"""FastAPI application initialization""" from fastapi import FastAPI from fastapi.responses import HTMLResponse, FileResponse from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager from pathlib import Path from .core.config import config from .core.database import Database from .services.flow_client import FlowClient from .services.proxy_manager import ProxyManager from .services.token_manager import TokenManager from .services.load_balancer import LoadBalancer from .services.concurrency_manager import ConcurrencyManager from .services.generation_handler import GenerationHandler from .api import routes, admin @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan manager""" # Startup print("=" * 60) print("Flow2API Starting...") print("=" * 60) # Get config from setting.toml config_dict = config.get_raw_config() # Check if database exists (determine if first startup) is_first_startup = not db.db_exists() # Initialize database tables structure await db.init_db() # Handle database initialization based on startup type if is_first_startup: print("🎉 First startup detected. Initializing database and configuration from setting.toml...") await db.init_config_from_toml(config_dict, is_first_startup=True) print("✓ Database and configuration initialized successfully.") else: print("🔄 Existing database detected. Checking for missing tables and columns...") await db.check_and_migrate_db(config_dict) print("✓ Database migration check completed.") # Load admin config from database admin_config = await db.get_admin_config() if admin_config: config.set_admin_username_from_db(admin_config.username) config.set_admin_password_from_db(admin_config.password) config.api_key = admin_config.api_key # Load cache configuration from database cache_config = await db.get_cache_config() config.set_cache_enabled(cache_config.cache_enabled) config.set_cache_timeout(cache_config.cache_timeout) config.set_cache_base_url(cache_config.cache_base_url or "") # Load generation configuration from database generation_config = await db.get_generation_config() config.set_image_timeout(generation_config.image_timeout) config.set_video_timeout(generation_config.video_timeout) # Initialize concurrency manager tokens = await token_manager.get_all_tokens() await concurrency_manager.initialize(tokens) # Start file cache cleanup task await generation_handler.file_cache.start_cleanup_task() print(f"✓ Database initialized") print(f"✓ Total tokens: {len(tokens)}") print(f"✓ Cache: {'Enabled' if config.cache_enabled else 'Disabled'} (timeout: {config.cache_timeout}s)") print(f"✓ File cache cleanup task started") print(f"✓ Server running on http://{config.server_host}:{config.server_port}") print("=" * 60) yield # Shutdown print("Flow2API Shutting down...") # Stop file cache cleanup task await generation_handler.file_cache.stop_cleanup_task() print("✓ File cache cleanup task stopped") # Initialize components db = Database() proxy_manager = ProxyManager(db) flow_client = FlowClient(proxy_manager) token_manager = TokenManager(db, flow_client) concurrency_manager = ConcurrencyManager() load_balancer = LoadBalancer(token_manager, concurrency_manager) generation_handler = GenerationHandler( flow_client, token_manager, load_balancer, db, concurrency_manager, proxy_manager # 添加 proxy_manager 参数 ) # Set dependencies routes.set_generation_handler(generation_handler) admin.set_dependencies(token_manager, proxy_manager, db) # Create FastAPI app app = FastAPI( title="Flow2API", description="OpenAI-compatible API for Google VideoFX (Veo)", version="1.0.0", lifespan=lifespan ) # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(routes.router) app.include_router(admin.router) # Static files - serve tmp directory for cached files tmp_dir = Path(__file__).parent.parent / "tmp" tmp_dir.mkdir(exist_ok=True) app.mount("/tmp", StaticFiles(directory=str(tmp_dir)), name="tmp") # HTML routes for frontend static_path = Path(__file__).parent.parent / "static" @app.get("/", response_class=HTMLResponse) async def index(): """Redirect to login page""" login_file = static_path / "login.html" if login_file.exists(): return FileResponse(str(login_file)) return HTMLResponse(content="

Flow2API

Frontend not found

", status_code=404) @app.get("/login", response_class=HTMLResponse) async def login_page(): """Login page""" login_file = static_path / "login.html" if login_file.exists(): return FileResponse(str(login_file)) return HTMLResponse(content="

Login Page Not Found

", status_code=404) @app.get("/manage", response_class=HTMLResponse) async def manage_page(): """Management console page""" manage_file = static_path / "manage.html" if manage_file.exists(): return FileResponse(str(manage_file)) return HTMLResponse(content="

Management Page Not Found

", status_code=404)