Spaces:
Running
Running
Ship frontend
Browse files- Dockerfile +40 -35
- py_backend/app/main.py +28 -27
Dockerfile
CHANGED
|
@@ -1,35 +1,40 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
RUN
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
ENV
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
#
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ---------- Build frontend ----------
|
| 2 |
+
FROM node:20-alpine AS fe
|
| 3 |
+
WORKDIR /fe
|
| 4 |
+
COPY frontend/package*.json ./
|
| 5 |
+
RUN npm ci
|
| 6 |
+
COPY frontend/ .
|
| 7 |
+
RUN npm run build # produces /fe/dist
|
| 8 |
+
|
| 9 |
+
# ---------- Backend image ----------
|
| 10 |
+
FROM python:3.11-slim
|
| 11 |
+
|
| 12 |
+
RUN apt-get update && apt-get install -y \
|
| 13 |
+
build-essential gcc libpq-dev \
|
| 14 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 15 |
+
|
| 16 |
+
WORKDIR /app
|
| 17 |
+
|
| 18 |
+
# Install backend deps
|
| 19 |
+
COPY py_backend/requirements.txt /tmp/requirements.txt
|
| 20 |
+
RUN pip install --no-cache-dir -r /tmp/requirements.txt
|
| 21 |
+
|
| 22 |
+
# Copy backend code
|
| 23 |
+
COPY py_backend/ /app/
|
| 24 |
+
|
| 25 |
+
# Copy built frontend into the image (served by FastAPI)
|
| 26 |
+
COPY --from=fe /fe/dist /app/static
|
| 27 |
+
|
| 28 |
+
# Data dirs & sensible defaults (you can keep sqlite fallback if you want)
|
| 29 |
+
RUN mkdir -p /data/uploads && chmod -R 777 /data
|
| 30 |
+
ENV STORAGE_PROVIDER=local
|
| 31 |
+
ENV STORAGE_DIR=/data/uploads
|
| 32 |
+
ENV HF_HOME=/data/.cache/huggingface
|
| 33 |
+
|
| 34 |
+
# Spaces provides PORT; default to 7860 locally
|
| 35 |
+
ENV PORT=7860
|
| 36 |
+
EXPOSE 7860
|
| 37 |
+
|
| 38 |
+
# Start backend (serves API + static frontend)
|
| 39 |
+
CMD uvicorn app.main:app --host 0.0.0.0 --port $PORT
|
| 40 |
+
|
py_backend/app/main.py
CHANGED
|
@@ -1,51 +1,52 @@
|
|
| 1 |
-
|
|
|
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
-
from fastapi.
|
| 4 |
-
from
|
|
|
|
| 5 |
from app.config import settings
|
|
|
|
| 6 |
from app.routers.images import router as images_router
|
| 7 |
|
| 8 |
app = FastAPI(title="PromptAid Vision")
|
| 9 |
|
|
|
|
| 10 |
app.add_middleware(
|
| 11 |
CORSMiddleware,
|
| 12 |
allow_origins=[
|
| 13 |
"http://localhost:3000",
|
| 14 |
"http://localhost:5173",
|
| 15 |
-
"https://huggingface.co",
|
| 16 |
-
"https://*.hf.space",
|
| 17 |
-
"https://*.hf.space",
|
| 18 |
-
"*"
|
| 19 |
],
|
| 20 |
-
|
|
|
|
| 21 |
allow_methods=["*"],
|
| 22 |
allow_headers=["*"],
|
| 23 |
)
|
| 24 |
|
| 25 |
-
|
| 26 |
-
app.include_router(
|
| 27 |
-
app.include_router(
|
| 28 |
-
app.include_router(
|
| 29 |
-
app.include_router(
|
| 30 |
-
|
| 31 |
-
@app.get("/", include_in_schema=False, response_class=HTMLResponse)
|
| 32 |
-
async def root():
|
| 33 |
-
# simple page so HF health-check gets 200 OK
|
| 34 |
-
return """<!doctype html>
|
| 35 |
-
<title>PromptAid Vision</title>
|
| 36 |
-
<h1>PromptAid Vision API</h1>
|
| 37 |
-
<p>OK</p>
|
| 38 |
-
<p>See <a href="/docs">/docs</a> for the API.</p>
|
| 39 |
-
"""
|
| 40 |
|
|
|
|
| 41 |
@app.get("/health", include_in_schema=False, response_class=JSONResponse)
|
| 42 |
async def health():
|
| 43 |
return {"status": "ok"}
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
print("π PromptAid Vision API server ready")
|
| 46 |
print("π Available endpoints: /api/images, /api/captions, /api/metadata, /api/models")
|
| 47 |
print(f"π Environment: {settings.ENVIRONMENT}")
|
| 48 |
-
print("π CORS enabled for
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from fastapi import FastAPI, HTTPException
|
| 3 |
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
+
from fastapi.staticfiles import StaticFiles
|
| 5 |
+
from fastapi.responses import FileResponse, JSONResponse
|
| 6 |
+
|
| 7 |
from app.config import settings
|
| 8 |
+
from app.routers import upload, caption, metadata, models
|
| 9 |
from app.routers.images import router as images_router
|
| 10 |
|
| 11 |
app = FastAPI(title="PromptAid Vision")
|
| 12 |
|
| 13 |
+
# CORS: allow localhost dev and all *.hf.space
|
| 14 |
app.add_middleware(
|
| 15 |
CORSMiddleware,
|
| 16 |
allow_origins=[
|
| 17 |
"http://localhost:3000",
|
| 18 |
"http://localhost:5173",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
],
|
| 20 |
+
allow_origin_regex=r"https://.*\.hf\.space$", # Hugging Face subdomains
|
| 21 |
+
allow_credentials=False, # must be False if using "*" or regex
|
| 22 |
allow_methods=["*"],
|
| 23 |
allow_headers=["*"],
|
| 24 |
)
|
| 25 |
|
| 26 |
+
# ---- API routers (keep them under /api) ----
|
| 27 |
+
app.include_router(caption.router, prefix="/api", tags=["captions"])
|
| 28 |
+
app.include_router(metadata.router, prefix="/api", tags=["metadata"])
|
| 29 |
+
app.include_router(models.router, prefix="/api", tags=["models"])
|
| 30 |
+
app.include_router(upload.router, prefix="/api/images", tags=["images"])
|
| 31 |
+
app.include_router(images_router, prefix="/api/contribute", tags=["contribute"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
# Simple health endpoint for HF health checks
|
| 34 |
@app.get("/health", include_in_schema=False, response_class=JSONResponse)
|
| 35 |
async def health():
|
| 36 |
return {"status": "ok"}
|
| 37 |
|
| 38 |
+
# ---- Serve built frontend (Vite) ----
|
| 39 |
+
STATIC_DIR = os.path.join(os.path.dirname(__file__), "..", "static")
|
| 40 |
+
app.mount("/", StaticFiles(directory=STATIC_DIR, html=True), name="static")
|
| 41 |
+
|
| 42 |
+
# SPA fallback for client-side routes; don't intercept API or docs
|
| 43 |
+
@app.get("/{full_path:path}", include_in_schema=False)
|
| 44 |
+
def spa_fallback(full_path: str):
|
| 45 |
+
if full_path.startswith(("api", "docs", "redoc", "openapi")):
|
| 46 |
+
raise HTTPException(status_code=404, detail="Not Found")
|
| 47 |
+
return FileResponse(os.path.join(STATIC_DIR, "index.html"))
|
| 48 |
+
|
| 49 |
print("π PromptAid Vision API server ready")
|
| 50 |
print("π Available endpoints: /api/images, /api/captions, /api/metadata, /api/models")
|
| 51 |
print(f"π Environment: {settings.ENVIRONMENT}")
|
| 52 |
+
print("π CORS enabled for localhost and *.hf.space")
|
|
|
|
|
|
|
|
|