forked from lightningpixel/modly
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
68 lines (56 loc) · 2.29 KB
/
Copy pathmain.py
File metadata and controls
68 lines (56 loc) · 2.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"""
Modly FastAPI backend.
Runs locally within the Electron app to provide AI inference endpoints.
"""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi import HTTPException
from services.stdio_utf8 import ensure_utf8_stdio
ensure_utf8_stdio() # must run before any print/logging hits the pipe
from routers import generation, model, optimize, status, settings, extensions, export, workflow_runs, agent
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: initialize the registry (instantiates all adapters)
from services.generator_registry import generator_registry
generator_registry.initialize()
yield
# Shutdown: unload all models
generator_registry.unload_all()
class _StatusFilter(logging.Filter):
def filter(self, record):
return "/generate/status/" not in record.getMessage()
logging.getLogger("uvicorn.access").addFilter(_StatusFilter())
app = FastAPI(
title="Modly API",
version="0.4.2",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
# drei's SplatLoader reads Content-Length to size its buffers; cross-origin
# JS can only see it when the server explicitly exposes the header.
expose_headers=["Content-Length"],
)
app.include_router(status.router)
app.include_router(settings.router)
app.include_router(model.router, prefix="/model")
app.include_router(generation.router, prefix="/generate")
app.include_router(optimize.router, prefix="/optimize")
app.include_router(extensions.router, prefix="/extensions")
app.include_router(export.router, prefix="/export")
app.include_router(workflow_runs.router, prefix="/workflow-runs")
app.include_router(agent.router)
# Serve generated files from workspace — dynamic so path changes take effect immediately
@app.get("/workspace/{full_path:path}")
async def serve_workspace_file(full_path: str):
import services.generator_registry as reg
file_path = reg.WORKSPACE_DIR / full_path
if not file_path.exists() or not file_path.is_file():
raise HTTPException(status_code=404, detail="File not found")
return FileResponse(str(file_path))