OwenPowell commited on
Commit
00a3c1e
·
verified ·
1 Parent(s): 0b64296

Delete main.py

Browse files
Files changed (1) hide show
  1. main.py +0 -215
main.py DELETED
@@ -1,215 +0,0 @@
1
- """
2
- Grok2API 应用入口
3
-
4
- FastAPI 应用初始化和路由注册
5
- """
6
-
7
- from contextlib import asynccontextmanager
8
- import asyncio
9
- import os
10
- import platform
11
- import sys
12
- from pathlib import Path
13
-
14
- from dotenv import load_dotenv
15
-
16
- env_file = Path(__file__).parent / ".env"
17
- if env_file.exists():
18
- load_dotenv(env_file)
19
-
20
- from fastapi import FastAPI, Request
21
- from fastapi.middleware.cors import CORSMiddleware
22
- from fastapi import Depends
23
-
24
- from app.core.auth import verify_api_key
25
- from app.core.config import get_config
26
- from app.core.logger import logger, setup_logging
27
- from app.core.exceptions import register_exception_handlers
28
- from app.core.response_middleware import ResponseLoggerMiddleware
29
- from app.api.v1.chat import router as chat_router
30
- from app.api.v1.image import router as image_router
31
- from app.api.v1.files import router as files_router
32
- from app.api.v1.models import router as models_router
33
- from app.api.v1.uploads import router as uploads_router
34
- from app.services.token import get_scheduler
35
-
36
-
37
- # 初始化日志
38
- setup_logging(
39
- level=os.getenv("LOG_LEVEL", "INFO"),
40
- json_console=False,
41
- file_logging=True,
42
- )
43
-
44
-
45
- @asynccontextmanager
46
- async def lifespan(app: FastAPI):
47
- """应用生命周期管理"""
48
-
49
- # 0. 兼容迁移:保留旧版 data 目录中的配置/缓存等数据
50
- from app.core.legacy_migration import migrate_legacy_cache_dirs, migrate_legacy_account_settings
51
-
52
- await asyncio.to_thread(migrate_legacy_cache_dirs)
53
-
54
- # 1. 加载配置(内部会自动合并 defaults + 兼容 setting.toml)
55
- from app.core.config import config
56
-
57
- await config.load()
58
-
59
- # 1.1 Old account post-migration settings (TOS + BirthDate + NSFW), best-effort
60
- async def _run_legacy_account_migration():
61
- try:
62
- await migrate_legacy_account_settings(concurrency=10)
63
- except Exception as e:
64
- logger.warning(f"Legacy account migration failed: {e}")
65
-
66
- asyncio.create_task(_run_legacy_account_migration())
67
-
68
- # 2. 启动服务显示
69
- logger.info("Starting Grok2API...")
70
- logger.info(f"Platform: {platform.system()} {platform.release()}")
71
- logger.info(f"Python: {sys.version.split()[0]}")
72
-
73
- # 3. 启动 Token 刷新调度器
74
- refresh_enabled = get_config("token.auto_refresh", True)
75
- if refresh_enabled:
76
- interval = get_config("token.refresh_interval_hours", 8)
77
- scheduler = get_scheduler(interval)
78
- scheduler.start()
79
-
80
- logger.info("Application startup complete.")
81
- yield
82
-
83
- # 关闭
84
- logger.info("Shutting down Grok2API...")
85
-
86
- # Best-effort: stop auto-register to avoid blocking shutdown on background threads.
87
- try:
88
- from app.services.register import get_auto_register_manager
89
-
90
- await get_auto_register_manager().stop_job()
91
- except Exception:
92
- pass
93
-
94
- from app.core.storage import StorageFactory
95
-
96
- if StorageFactory._instance:
97
- await StorageFactory._instance.close()
98
-
99
- if refresh_enabled:
100
- scheduler = get_scheduler()
101
- scheduler.stop()
102
-
103
-
104
- def create_app() -> FastAPI:
105
- """创建 FastAPI 应用"""
106
- app = FastAPI(
107
- title="Grok2API",
108
- lifespan=lifespan,
109
- )
110
-
111
- @app.get("/health")
112
- async def health():
113
- return {"status": "healthy", "service": "Grok2API", "runtime": "python-fastapi"}
114
-
115
- # CORS 配置
116
- app.add_middleware(
117
- CORSMiddleware,
118
- allow_origins=["*"],
119
- allow_credentials=True,
120
- allow_methods=["*"],
121
- allow_headers=["*"],
122
- )
123
-
124
- # 请求日志和 ID 中间件
125
- app.add_middleware(ResponseLoggerMiddleware)
126
-
127
- # 注册异常处理器
128
- register_exception_handlers(app)
129
-
130
- # 注册路由
131
- app.include_router(chat_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
132
- app.include_router(image_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
133
- app.include_router(models_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
134
- app.include_router(uploads_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
135
- app.include_router(files_router, prefix="/v1/files")
136
-
137
- # 静态文件服务
138
- #
139
- # NOTE: Starlette/StaticFiles serves JS as `application/javascript` without a charset.
140
- # Some browsers/OS locales may then mis-decode UTF-8 and display `????` for Chinese text.
141
- # Force `charset=utf-8` for JS to avoid mojibake across environments (local/docker).
142
- from fastapi.staticfiles import StaticFiles
143
-
144
- static_dir = Path(__file__).parent / "app" / "static"
145
- if static_dir.exists():
146
- class _UTF8StaticFiles(StaticFiles):
147
- async def get_response(self, path: str, scope): # type: ignore[override]
148
- resp = await super().get_response(path, scope)
149
-
150
- # Starlette uses `mimetypes` which may vary across OS/distros.
151
- # Ensure UTF-8 decoding for text-like assets to avoid mojibake (`????`) on some locales.
152
- ctype = (resp.headers.get("content-type", "") or "").strip()
153
- ctype_l = ctype.lower()
154
- if "charset=" in ctype_l:
155
- return resp
156
-
157
- base = ctype.split(";", 1)[0].strip().lower()
158
- is_text = base.startswith("text/")
159
- is_js = base in ("application/javascript", "text/javascript")
160
- is_json = base == "application/json"
161
- is_css = base == "text/css"
162
-
163
- # Some servers might respond with empty content-type for 304 etc; fall back by extension.
164
- if not base:
165
- ext = Path(path).suffix.lower()
166
- if ext in (".js", ".mjs"):
167
- resp.headers["content-type"] = "application/javascript; charset=utf-8"
168
- elif ext == ".css":
169
- resp.headers["content-type"] = "text/css; charset=utf-8"
170
- elif ext in (".html", ".htm"):
171
- resp.headers["content-type"] = "text/html; charset=utf-8"
172
- return resp
173
-
174
- if is_text or is_js or is_json or is_css:
175
- resp.headers["content-type"] = f"{base}; charset=utf-8"
176
- return resp
177
-
178
- app.mount("/static", _UTF8StaticFiles(directory=static_dir), name="static")
179
-
180
- # 注册管理路由
181
- from app.api.v1.admin import router as admin_router
182
-
183
- app.include_router(admin_router)
184
-
185
- return app
186
-
187
-
188
- app = create_app()
189
-
190
-
191
- if __name__ == "__main__":
192
- import uvicorn
193
-
194
- host = os.getenv("SERVER_HOST", "0.0.0.0")
195
- port = int(os.getenv("SERVER_PORT", "8000"))
196
- workers = int(os.getenv("SERVER_WORKERS", "1"))
197
-
198
- # 平台检查
199
- is_windows = platform.system() == "Windows"
200
-
201
- # 自动降级
202
- if is_windows and workers > 1:
203
- logger.warning(
204
- f"Windows platform detected. Multiple workers ({workers}) is not supported. "
205
- "Using single worker instead.",
206
- )
207
- workers = 1
208
-
209
- uvicorn.run(
210
- "main:app",
211
- host=host,
212
- port=port,
213
- workers=workers,
214
- log_level=os.getenv("LOG_LEVEL", "INFO").lower(),
215
- )