sushilideaclan01's picture
change the
c4f9173
Raw
History Blame Contribute Delete
3.92 kB
"""
Product Showcase Studio — FastAPI backend.
Video pipeline aligned with python-backend (KIE Veo, image hosting, merge).
"""
from contextlib import asynccontextmanager
from pathlib import Path
import os
import shutil
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from api.video_generation import router as video_router
from api.seedance_generation import router as seedance_router
from api.image_service import router as image_router
from api.video_export import router as export_router
from api.showcase_prompts import router as showcase_router
from api.scraper_routes import router as scraper_router
from api.gpt_image_frames import router as gpt_image_router
from utils.env_load import load_app_env
from utils.public_url import get_public_base_url, get_server_port_str
from utils.storage import cleanup_old_files
load_app_env()
@asynccontextmanager
async def lifespan(app: FastAPI):
print("Starting Product Showcase API…")
os.makedirs("storage/images", exist_ok=True)
os.makedirs("storage/videos", exist_ok=True)
public = get_public_base_url()
print(f"Public URL for callbacks/hosted images: {public}")
if not os.getenv("KIE_API_KEY"):
if os.getenv("REPLICATE_API_TOKEN") or os.getenv("REPLICATE_API_KEY"):
print("Info: KIE_API_KEY not set — Seedance can use Replicate fallback when token is set.")
else:
print("Warning: KIE_API_KEY not set — KIE video generation will fail (set REPLICATE_API_TOKEN for Seedance fallback).")
if not os.getenv("OPENAI_API_KEY"):
print("Info: OPENAI_API_KEY not set — shot plan and GPT Image frames are unavailable.")
else:
print(f"GPT Image model for first frames: {os.getenv('GPT_IMAGE_MODEL', 'gpt-image-1.5')}")
yield
cleanup_old_files()
app = FastAPI(
title="Product Showcase API",
description="Cinematic product videos: shot planning + KIE Veo / Seedance 2 + export",
version="1.0.0",
lifespan=lifespan,
)
origins = [
"http://localhost:5173",
"http://127.0.0.1:5173",
"http://localhost:3000",
"http://127.0.0.1:3000",
]
extra = (os.getenv("CORS_ALLOWED_ORIGINS") or "").strip()
if extra:
origins = [o.strip().rstrip("/") for o in extra.split(",") if o.strip()]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(showcase_router, prefix="/api")
app.include_router(scraper_router, prefix="/api")
app.include_router(gpt_image_router, prefix="/api")
app.include_router(video_router, prefix="/api")
app.include_router(seedance_router, prefix="/api")
app.include_router(image_router, prefix="/api")
app.include_router(export_router, prefix="/api")
_REPO_ROOT = Path(__file__).resolve().parent.parent
_FRONTEND_DIST = _REPO_ROOT / "frontend" / "dist"
@app.get("/health")
def health():
return {
"status": "healthy",
"service": "product-showcase",
"kie_configured": bool(os.getenv("KIE_API_KEY")),
"replicate_configured": bool(
(os.getenv("REPLICATE_API_TOKEN") or os.getenv("REPLICATE_API_KEY") or "").strip()
),
"openai_configured": bool(os.getenv("OPENAI_API_KEY")),
"gpt_image_model": os.getenv("GPT_IMAGE_MODEL", "gpt-image-1.5"),
"ffmpeg_available": bool(shutil.which("ffmpeg")),
"ffprobe_available": bool(shutil.which("ffprobe")),
"public_base_url": get_public_base_url(),
"server_port": int(get_server_port_str()),
}
if _FRONTEND_DIST.is_dir():
app.mount(
"/",
StaticFiles(directory=str(_FRONTEND_DIST), html=True),
name="frontend",
)
if __name__ == "__main__":
import uvicorn
port = int(get_server_port_str())
uvicorn.run("main:app", host="0.0.0.0", port=port, reload=True)