picpocket2 / app.py
chawin.chen
init
7a6cb13
import os
import time
from contextlib import asynccontextmanager
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from cleanup_scheduler import start_cleanup_scheduler, stop_cleanup_scheduler
from config import (
logger,
OUTPUT_DIR,
DEEPFACE_AVAILABLE,
DLIB_AVAILABLE,
MODELS_PATH,
IMAGES_DIR,
YOLO_AVAILABLE,
ENABLE_LOGGING,
HUGGINGFACE_SYNC_ENABLED,
)
from database import close_mysql_pool, init_mysql_pool
from utils import ensure_bos_resources, ensure_huggingface_models
logger.info("Starting to import api_routes module...")
if HUGGINGFACE_SYNC_ENABLED:
try:
t_hf_start = time.perf_counter()
if not ensure_huggingface_models():
raise RuntimeError("无法从 HuggingFace 同步模型,请检查配置与网络")
hf_time = time.perf_counter() - t_hf_start
logger.info("HuggingFace 模型同步完成,用时 %.3fs", hf_time)
except Exception as exc:
logger.error(f"HuggingFace model preparation failed: {exc}")
raise
else:
logger.info("已关闭 HuggingFace 模型同步开关,跳过启动阶段的同步步骤")
try:
t_bos_start = time.perf_counter()
if not ensure_bos_resources():
raise RuntimeError("无法从 BOS 同步模型与数据,请检查凭证与网络")
bos_time = time.perf_counter() - t_bos_start
logger.info(f"BOS resources synchronized successfully, time: {bos_time:.3f}s")
except Exception as exc:
logger.error(f"BOS resource preparation failed: {exc}")
raise
try:
t_start = time.perf_counter()
from api_routes import api_router, extract_chinese_celeb_dataset_sync
import_time = time.perf_counter() - t_start
logger.info(f"api_routes module imported successfully, time: {import_time:.3f}s")
except Exception as e:
import_time = time.perf_counter() - t_start
logger.error(f"api_routes module import failed, time: {import_time:.3f}s, error: {e}")
raise
try:
t_extract_start = time.perf_counter()
extract_result = extract_chinese_celeb_dataset_sync()
extract_time = time.perf_counter() - t_extract_start
logger.info(
"Chinese celeb dataset extracted successfully, time: %.3fs, target: %s",
extract_time,
extract_result.get("target_dir"),
)
except Exception as exc:
logger.error(f"Failed to extract Chinese celeb dataset automatically: {exc}")
raise
@asynccontextmanager
async def lifespan(app: FastAPI):
start_time = time.perf_counter()
logger.info("FaceScore service starting...")
logger.info(f"Output directory: {OUTPUT_DIR}")
logger.info(f"DeepFace available: {DEEPFACE_AVAILABLE}")
logger.info(f"YOLO available: {YOLO_AVAILABLE}")
logger.info(f"MediaPipe available: {DLIB_AVAILABLE}")
logger.info(f"Archive directory: {IMAGES_DIR}")
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 初始化数据库连接池
try:
await init_mysql_pool()
logger.info("MySQL 连接池初始化完成")
except Exception as exc:
logger.error(f"初始化 MySQL 连接池失败: {exc}")
raise
# 启动图片清理定时任务
logger.info("Starting image cleanup scheduled task...")
try:
start_cleanup_scheduler()
logger.info("Image cleanup scheduled task started successfully")
except Exception as e:
logger.error(f"Failed to start image cleanup scheduled task: {e}")
# 记录启动完成时间
total_startup_time = time.perf_counter() - start_time
logger.info(f"FaceScore service startup completed, total time: {total_startup_time:.3f}s")
yield
# 应用关闭时停止定时任务
logger.info("Stopping image cleanup scheduled task...")
try:
stop_cleanup_scheduler()
logger.info("Image cleanup scheduled task stopped")
except Exception as e:
logger.error(f"Failed to stop image cleanup scheduled task: {e}")
# 关闭数据库连接池
try:
await close_mysql_pool()
except Exception as exc:
logger.warning(f"关闭 MySQL 连接池失败: {exc}")
# 创建 FastAPI 应用
app = FastAPI(
title="Enhanced FaceScore 服务",
description="支持多模型的人脸分析REST API服务,包含五官评分功能。支持混合模式:HowCuteAmI(颜值+性别)+ DeepFace(年龄+情绪)",
version="3.0.0",
docs_url="/cp_docs",
redoc_url="/cp_redoc",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# 注册路由
app.include_router(api_router)
# 添加根路径处理
@app.get("/")
async def root():
return "UP"
if __name__ == "__main__":
import uvicorn
if not os.path.exists(MODELS_PATH):
logger.critical(
"Warning: 'models' directory not found. Please ensure it exists and contains model files."
)
logger.critical(
"Exiting application as FaceAnalyzer cannot be initialized without models."
)
exit(1)
# 根据日志开关配置 Uvicorn 日志
if ENABLE_LOGGING:
uvicorn.run(app, host="0.0.0.0", port=8080, reload=False)
else:
# 禁用 Uvicorn 的访问日志和错误日志
uvicorn.run(
app,
host="0.0.0.0",
port=8080,
reload=False,
access_log=False, # 禁用访问日志
log_level="critical" # 只显示严重错误
)