Files
speech/app/main.py
du5t ac49bfc7f9 Cut over OIDC redirect to speech.du5t.xyz
NPM proxy host + Let's Encrypt cert for speech.du5t.xyz are live, so
flip the session cookie to https_only=True (the redirect_uri and
Authentik provider config changes live outside this repo, in
/srv/asr/env/asr.env and the Authentik provider record).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 17:53:05 +09:00

62 lines
2.1 KiB
Python

from __future__ import annotations
from pathlib import Path
from typing import Any, Dict
from fastapi import Depends, FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from asr.config import ensure_runtime_dirs
from asr.router import router as asr_router
from asr.router import ws_router as asr_ws_router
from core.auth import SESSION_SECRET_KEY, require_login
from core.auth import router as auth_router
from tts.router import router as tts_router
app = FastAPI(title="Speech Gateway", docs_url="/docs", redoc_url="/redoc")
app.add_middleware(
SessionMiddleware,
secret_key=SESSION_SECRET_KEY,
same_site="lax",
https_only=True, # speech.du5t.xyz는 NPM에서 TLS 종료 후 내부로 포워딩됨
max_age=14 * 24 * 3600,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
UI_DIR = Path("/app/ui")
app.include_router(auth_router, prefix="/auth", tags=["auth"])
app.include_router(asr_router, prefix="/asr", tags=["asr"], dependencies=[Depends(require_login)])
app.include_router(asr_ws_router, prefix="/asr", tags=["asr"]) # 인증은 핸들러 내부에서 세션으로 직접 체크
app.include_router(tts_router, prefix="/tts", tags=["tts"], dependencies=[Depends(require_login)])
@app.on_event("startup")
def startup() -> None:
ensure_runtime_dirs()
if UI_DIR.exists():
app.mount("/ui", StaticFiles(directory=str(UI_DIR), html=True), name="ui")
app.mount("/assets", StaticFiles(directory=str(UI_DIR / "assets")), name="assets")
@app.get("/health")
def health() -> Dict[str, Any]:
return {"status": "ok", "ui_installed": UI_DIR.exists(), "api": "/docs"}
@app.get("/", response_class=HTMLResponse, dependencies=[Depends(require_login)])
def root() -> Any:
index = UI_DIR / "index.html"
if index.exists():
return FileResponse(index)
return JSONResponse({"status": "ok", "message": "UI not installed", "api": "/docs"})