from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager import os from sqlalchemy import inspect, text from .db import Base, engine from .routers import assistants, voices, workflows, history, knowledge, llm, asr, tools def _ensure_assistant_columns() -> None: """Best-effort SQLite schema evolution for assistant flags.""" inspector = inspect(engine) if "assistants" not in inspector.get_table_names(): return columns = {col["name"] for col in inspector.get_columns("assistants")} alter_statements = [] if "generated_opener_enabled" not in columns: alter_statements.append( "ALTER TABLE assistants ADD COLUMN generated_opener_enabled BOOLEAN DEFAULT 0" ) if "bot_cannot_be_interrupted" not in columns: alter_statements.append( "ALTER TABLE assistants ADD COLUMN bot_cannot_be_interrupted BOOLEAN DEFAULT 0" ) if not alter_statements: return with engine.begin() as conn: for stmt in alter_statements: conn.execute(text(stmt)) @asynccontextmanager async def lifespan(app: FastAPI): # 启动时创建表 Base.metadata.create_all(bind=engine) _ensure_assistant_columns() yield app = FastAPI( title="AI VideoAssistant API", description="Backend API for AI VideoAssistant", version="1.0.0", lifespan=lifespan ) # CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 路由 app.include_router(assistants.router, prefix="/api") app.include_router(voices.router, prefix="/api") app.include_router(workflows.router, prefix="/api") app.include_router(history.router, prefix="/api") app.include_router(knowledge.router, prefix="/api") app.include_router(llm.router, prefix="/api") app.include_router(asr.router, prefix="/api") app.include_router(tools.router, prefix="/api") @app.get("/") def root(): return {"message": "AI VideoAssistant API", "version": "1.0.0"} @app.get("/health") def health(): return {"status": "ok"}