File size: 4,718 Bytes
22a3c56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""Main application entry point"""
import uvicorn
from fastapi import FastAPI
from fastapi.responses import FileResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from pathlib import Path

# Import modules
from .core.config import config
from .core.database import Database
from .services.token_manager import TokenManager
from .services.proxy_manager import ProxyManager
from .services.load_balancer import LoadBalancer
from .services.sora_client import SoraClient
from .services.generation_handler import GenerationHandler
from .api import routes as api_routes
from .api import admin as admin_routes

# Initialize FastAPI app
app = FastAPI(
    title="Sora2API",
    description="OpenAI compatible API for Sora",
    version="1.0.0"
)

# CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Initialize components
db = Database()
token_manager = TokenManager(db)
proxy_manager = ProxyManager(db)
load_balancer = LoadBalancer(token_manager)
sora_client = SoraClient(proxy_manager)
generation_handler = GenerationHandler(sora_client, token_manager, load_balancer, db, proxy_manager)

# Set dependencies for route modules
api_routes.set_generation_handler(generation_handler)
admin_routes.set_dependencies(token_manager, proxy_manager, db, generation_handler)

# Include routers
app.include_router(api_routes.router)
app.include_router(admin_routes.router)

# Static files
static_dir = Path(__file__).parent.parent / "static"
static_dir.mkdir(exist_ok=True)
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")

# Cache files (tmp directory)
tmp_dir = Path(__file__).parent.parent / "tmp"
tmp_dir.mkdir(exist_ok=True)
app.mount("/tmp", StaticFiles(directory=str(tmp_dir)), name="tmp")

# Frontend routes
@app.get("/", response_class=HTMLResponse)
async def root():
    """Redirect to login page"""
    return """
    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="refresh" content="0; url=/login">
    </head>
    <body>
        <p>Redirecting to login...</p>
    </body>
    </html>
    """

@app.get("/login", response_class=FileResponse)
async def login_page():
    """Serve login page"""
    return FileResponse(str(static_dir / "login.html"))

@app.get("/manage", response_class=FileResponse)
async def manage_page():
    """Serve management page"""
    return FileResponse(str(static_dir / "manage.html"))

@app.on_event("startup")
async def startup_event():
    """Initialize database on startup"""
    # Get config from setting.toml
    config_dict = config.get_raw_config()

    # Check if database exists
    is_first_startup = not db.db_exists()

    # Initialize database tables
    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 credentials from database
    admin_config = await db.get_admin_config()
    config.set_admin_username_from_db(admin_config.admin_username)
    config.set_admin_password_from_db(admin_config.admin_password)

    # 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)

    # Load token refresh configuration from database
    token_refresh_config = await db.get_token_refresh_config()
    config.set_at_auto_refresh_enabled(token_refresh_config.at_auto_refresh_enabled)

    # Start file cache cleanup task
    await generation_handler.file_cache.start_cleanup_task()

@app.on_event("shutdown")
async def shutdown_event():
    """Cleanup on shutdown"""
    await generation_handler.file_cache.stop_cleanup_task()

if __name__ == "__main__":
    uvicorn.run(
        "src.main:app",
        host=config.server_host,
        port=config.server_port,
        reload=False
    )