Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
BASE_URL=http://192.168.178.21
BASE_URL=http://192.168.0.17
WWW_PORT=8989
API_PORT=8988
SEMVER=0.2.1
25 changes: 24 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
bun-debug.log*

# Dependency directories
node_modules

# Build output
dist
dist-ssr
*.local
Expand All @@ -23,4 +27,23 @@ dist-ssr
*.sln
*.sw?

.venv
# Virtual Environments
.venv
venv/

# Python
__pycache__
*.pyc

# Lock files
package-lock.json
yarn.lock
pnpm-lock.yaml
bun.lock

# Backend
/backend/__pycache__/
/backend/app/uploads/
/backend/data/
/backend/*.db
/backend/uploads/
3 changes: 2 additions & 1 deletion backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir uv && \
uv pip install --system -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
54 changes: 42 additions & 12 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@
import shutil
import sqlite3
from fastapi import (
BackgroundTasks,
Depends,
FastAPI,
UploadFile,
File,
Form,
HTTPException,
Query,
)
from fastapi.responses import FileResponse
from starlette.middleware.cors import CORSMiddleware
import json
from pathlib import Path
from typing import Optional, List, Dict, Any, Union
from pydantic import BaseModel
import requests

DB_PATH = os.getenv("DB_PATH", "data.db")
UPLOAD_DIR = Path(os.getenv("FILE_STORAGE", "./app/uploads"))
Expand All @@ -33,7 +31,7 @@ class FolderData(BaseModel):
app = FastAPI(title="STLVault API")
app.add_middleware(
CORSMiddleware,
allow_origins=WEBUI_URL,
allow_origins=["*"], # Allow all origins for development, or use [WEBUI_URL] for production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
Expand Down Expand Up @@ -208,7 +206,11 @@ def upload_model(
tags: Optional[str] = Form(None),
):
mid = str(uuid.uuid4())
ext = os.path.splitext(file.filename)[1] or ".stl"

# Ensure that file.filename is a string before passing it to os.path.splitext, providing a default value if it is None
filename_str = file.filename or ".stl"
ext = os.path.splitext(filename_str)[1] or ".stl"

filename = f"{mid}{ext}"
path = os.path.join(UPLOAD_DIR, filename)
size = save_upload_file(file, path)
Expand Down Expand Up @@ -378,16 +380,26 @@ def import_model(payload: dict):
url = payload.get("url")
folderId = payload.get("folderId", "1")
mid = str(uuid.uuid4())
ext = os.path.splitext(url.split("?")[0])[1] or ".stl"

# check if url is not None before calling split on it and provide a default extension if it is None
if url:
ext = os.path.splitext(url.split("?")[0])[1] or ".stl"
else:
ext = ".stl"

filename = f"{mid}{ext}"
path = os.path.join(UPLOAD_DIR, filename)

# Check if url is not None before calling requests.get(url, ...)
try:
r = requests.get(url, timeout=10)
r.raise_for_status()
with open(path, "wb") as fh:
fh.write(r.content)
size = os.path.getsize(path)
if url is not None:
r = requests.get(url, timeout=10)
r.raise_for_status()
with open(path, "wb") as fh:
fh.write(r.content)
size = os.path.getsize(path)
else:
raise ValueError("URL is None")
except Exception:
# create empty valid binary STL (80 byte header + 4 byte count)
header = bytes(80)
Expand Down Expand Up @@ -447,7 +459,8 @@ def replace_model_file(
except Exception:
pass

ext = os.path.splitext(file.filename)[1] or ".stl"
filename_str = file.filename or ".stl"
ext = os.path.splitext(filename_str)[1] or ".stl"
filename = f"{model_id}{ext}"
path = os.path.join(UPLOAD_DIR, filename)
size = save_upload_file(file, path)
Expand All @@ -469,3 +482,20 @@ def storage_stats():
used += os.path.getsize(os.path.join(UPLOAD_DIR, fname))
total = 5 * 1024 * 1024 * 1024
return {"used": used, "total": total}


if __name__ == "__main__":
import uvicorn

# Ensure upload directory exists
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)

port = int(os.getenv("PORT", "8080"))

uvicorn.run(
"app:app",
host="0.0.0.0",
port=port,
reload=True,
log_level="info"
)
12 changes: 9 additions & 3 deletions backend/run.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail

# Install dependencies (recommended inside a venv)
# Check if uv is installed, install if missing
if ! command -v uv &> /dev/null; then
echo "uv not found, installing..."
pip install uv
fi

# Install dependencies using uv (much faster than pip)
if [ ! -f .venv/bin/activate ]; then
python3 -m venv .venv || true
uv venv .venv
fi
. .venv/bin/activate
pip install -r requirements.txt
uv pip install -r requirements.txt

# Run uvicorn
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
Loading