From f86effd63cf2a81ead3c45fcb007e42fe9f65297 Mon Sep 17 00:00:00 2001 From: zqc <835569504@qq.com> Date: Thu, 8 Jan 2026 10:32:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=B7=AF=E5=BE=84=EF=BC=8C?= =?UTF-8?q?=E4=BB=8Esrc=E6=94=BE=E5=88=B0=E6=A0=B9=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 23 ++ {src => algorithm}/__init__.py | 0 .../face_recognition_algorithm.py | 0 {src/api => api}/dependencies.py | 0 {src/api => api}/errors.py | 0 {src/api => api}/routes/algorithm_router.py | 0 {src/api => api}/routes/face_features.py | 0 {src/algorithm => biz}/__init__.py | 0 {src/biz => biz}/base_face_biz.py | 0 {src/biz => biz}/video_check_biz.py | 0 {src/biz => biz}/video_face_biz.py | 0 config.yaml | 4 + {src/database => database}/base.py | 0 {src/database => database}/connection.py | 0 docker-compose.yml | 14 ++ face_database.pkl | Bin 0 -> 9435 bytes src/main.py => main.py | 0 {src/models => models}/face_feature.py | 0 {src/models => models}/sur_config.py | 0 {src/models => models}/sur_person.py | 0 {src/models => models}/video_check_task.py | 0 ...nnx_yolo11n.py => npu_yolo_onnx_yolo11n.py | 0 .../face_feature_repository.py | 0 .../sur_config_repository.py | 0 .../sur_person_repository.py | 0 .../video_check_repository.py | 0 requirements.txt | 10 + {src/rtsp => rtsp}/service.py | 0 ...vice_ws_1217.py => rtsp_service_ws_1217.py | 0 src/run.py => run.py | 0 {src/schemas => schemas}/face_feature.py | 0 .../face_feature_service.py | 0 src/app.py | 219 ------------------ src/biz/__init__.py | 0 src/config.py | 103 -------- src/utils/logger.py | 88 ------- ...n_3.py => video_face_recognition_cann_3.py | 0 37 files changed, 51 insertions(+), 410 deletions(-) create mode 100644 Dockerfile rename {src => algorithm}/__init__.py (100%) rename {src/algorithm => algorithm}/face_recognition_algorithm.py (100%) rename {src/api => api}/dependencies.py (100%) rename {src/api => api}/errors.py (100%) rename {src/api => api}/routes/algorithm_router.py (100%) rename {src/api => api}/routes/face_features.py (100%) rename {src/algorithm => biz}/__init__.py (100%) rename {src/biz => biz}/base_face_biz.py (100%) rename {src/biz => biz}/video_check_biz.py (100%) rename {src/biz => biz}/video_face_biz.py (100%) create mode 100644 config.yaml rename {src/database => database}/base.py (100%) rename {src/database => database}/connection.py (100%) create mode 100644 docker-compose.yml create mode 100644 face_database.pkl rename src/main.py => main.py (100%) rename {src/models => models}/face_feature.py (100%) rename {src/models => models}/sur_config.py (100%) rename {src/models => models}/sur_person.py (100%) rename {src/models => models}/video_check_task.py (100%) rename src/npu_yolo_onnx_yolo11n.py => npu_yolo_onnx_yolo11n.py (100%) rename {src/repositories => repositories}/face_feature_repository.py (100%) rename {src/repositories => repositories}/sur_config_repository.py (100%) rename {src/repositories => repositories}/sur_person_repository.py (100%) rename {src/repositories => repositories}/video_check_repository.py (100%) create mode 100644 requirements.txt rename {src/rtsp => rtsp}/service.py (100%) rename src/rtsp_service_ws_1217.py => rtsp_service_ws_1217.py (100%) rename src/run.py => run.py (100%) rename {src/schemas => schemas}/face_feature.py (100%) rename {src/services => services}/face_feature_service.py (100%) delete mode 100644 src/app.py delete mode 100644 src/biz/__init__.py delete mode 100644 src/config.py delete mode 100644 src/utils/logger.py rename src/video_face_recognition_cann_3.py => video_face_recognition_cann_3.py (100%) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..05cdaba --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.10-slim + +# 设置工作目录 +WORKDIR /app + +# 复制依赖文件 +COPY requirements.txt . + +# 安装依赖 +RUN pip install --no-cache-dir -r requirements.txt + +# 复制应用代码 +COPY src/ . + +# 暴露端口 +EXPOSE 8000 + +# 设置环境变量 +ENV PYTHONPATH=/app +ENV DEBUG=True + +# 启动命令 +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/src/__init__.py b/algorithm/__init__.py similarity index 100% rename from src/__init__.py rename to algorithm/__init__.py diff --git a/src/algorithm/face_recognition_algorithm.py b/algorithm/face_recognition_algorithm.py similarity index 100% rename from src/algorithm/face_recognition_algorithm.py rename to algorithm/face_recognition_algorithm.py diff --git a/src/api/dependencies.py b/api/dependencies.py similarity index 100% rename from src/api/dependencies.py rename to api/dependencies.py diff --git a/src/api/errors.py b/api/errors.py similarity index 100% rename from src/api/errors.py rename to api/errors.py diff --git a/src/api/routes/algorithm_router.py b/api/routes/algorithm_router.py similarity index 100% rename from src/api/routes/algorithm_router.py rename to api/routes/algorithm_router.py diff --git a/src/api/routes/face_features.py b/api/routes/face_features.py similarity index 100% rename from src/api/routes/face_features.py rename to api/routes/face_features.py diff --git a/src/algorithm/__init__.py b/biz/__init__.py similarity index 100% rename from src/algorithm/__init__.py rename to biz/__init__.py diff --git a/src/biz/base_face_biz.py b/biz/base_face_biz.py similarity index 100% rename from src/biz/base_face_biz.py rename to biz/base_face_biz.py diff --git a/src/biz/video_check_biz.py b/biz/video_check_biz.py similarity index 100% rename from src/biz/video_check_biz.py rename to biz/video_check_biz.py diff --git a/src/biz/video_face_biz.py b/biz/video_face_biz.py similarity index 100% rename from src/biz/video_face_biz.py rename to biz/video_face_biz.py diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..0f1df34 --- /dev/null +++ b/config.yaml @@ -0,0 +1,4 @@ +cameras: + - id: 1 + name: "Entrance" + rtsp_url: "rtsp://8.130.165.33:8554/test" \ No newline at end of file diff --git a/src/database/base.py b/database/base.py similarity index 100% rename from src/database/base.py rename to database/base.py diff --git a/src/database/connection.py b/database/connection.py similarity index 100% rename from src/database/connection.py rename to database/connection.py diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9f01746 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.8' + +services: + face-recognition: + build: . + ports: + - "8000:8000" + environment: + - DEBUG=True + - DATABASE_URL=postgresql://username:password@host:port/database + restart: unless-stopped + volumes: + - ./src/videos:/app/videos + - ./src/face_database.pkl:/app/face_database.pkl \ No newline at end of file diff --git a/face_database.pkl b/face_database.pkl new file mode 100644 index 0000000000000000000000000000000000000000..ebe707e356aa74d3a777d7d4cba8371581019190 GIT binary patch literal 9435 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 VBNw*$Ki?<~A1VINORHB8_#X)@N7euU literal 0 HcmV?d00001 diff --git a/src/main.py b/main.py similarity index 100% rename from src/main.py rename to main.py diff --git a/src/models/face_feature.py b/models/face_feature.py similarity index 100% rename from src/models/face_feature.py rename to models/face_feature.py diff --git a/src/models/sur_config.py b/models/sur_config.py similarity index 100% rename from src/models/sur_config.py rename to models/sur_config.py diff --git a/src/models/sur_person.py b/models/sur_person.py similarity index 100% rename from src/models/sur_person.py rename to models/sur_person.py diff --git a/src/models/video_check_task.py b/models/video_check_task.py similarity index 100% rename from src/models/video_check_task.py rename to models/video_check_task.py diff --git a/src/npu_yolo_onnx_yolo11n.py b/npu_yolo_onnx_yolo11n.py similarity index 100% rename from src/npu_yolo_onnx_yolo11n.py rename to npu_yolo_onnx_yolo11n.py diff --git a/src/repositories/face_feature_repository.py b/repositories/face_feature_repository.py similarity index 100% rename from src/repositories/face_feature_repository.py rename to repositories/face_feature_repository.py diff --git a/src/repositories/sur_config_repository.py b/repositories/sur_config_repository.py similarity index 100% rename from src/repositories/sur_config_repository.py rename to repositories/sur_config_repository.py diff --git a/src/repositories/sur_person_repository.py b/repositories/sur_person_repository.py similarity index 100% rename from src/repositories/sur_person_repository.py rename to repositories/sur_person_repository.py diff --git a/src/repositories/video_check_repository.py b/repositories/video_check_repository.py similarity index 100% rename from src/repositories/video_check_repository.py rename to repositories/video_check_repository.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d8dbf3f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +insightface==0.7.3 +numpy==2.3.5 +onnxruntime_gpu==1.23.2 +opencv_contrib_python==4.12.0.88 +opencv_python_headless==4.12.0.88 +setuptools==75.6.0 +setuptools==80.9.0 +sympy==1.13.1 +sympy==1.14.0 +torch==2.5.1+cu121 diff --git a/src/rtsp/service.py b/rtsp/service.py similarity index 100% rename from src/rtsp/service.py rename to rtsp/service.py diff --git a/src/rtsp_service_ws_1217.py b/rtsp_service_ws_1217.py similarity index 100% rename from src/rtsp_service_ws_1217.py rename to rtsp_service_ws_1217.py diff --git a/src/run.py b/run.py similarity index 100% rename from src/run.py rename to run.py diff --git a/src/schemas/face_feature.py b/schemas/face_feature.py similarity index 100% rename from src/schemas/face_feature.py rename to schemas/face_feature.py diff --git a/src/services/face_feature_service.py b/services/face_feature_service.py similarity index 100% rename from src/services/face_feature_service.py rename to services/face_feature_service.py diff --git a/src/app.py b/src/app.py deleted file mode 100644 index 17377d3..0000000 --- a/src/app.py +++ /dev/null @@ -1,219 +0,0 @@ -""" -FastAPI主应用 -将原来的main.py重命名为app.py -""" - -import time -from contextlib import asynccontextmanager -from fastapi import FastAPI, Request -from fastapi.exceptions import RequestValidationError -from fastapi.middleware.cors import CORSMiddleware -from fastapi.middleware.trustedhost import TrustedHostMiddleware -from fastapi.responses import JSONResponse -from fastapi.openapi.docs import ( - get_swagger_ui_html, - get_swagger_ui_oauth2_redirect_html, - get_redoc_html, -) -from fastapi.staticfiles import StaticFiles - -from api.routes import face_features -from api.routes.algorithm_router import router as algorithm_router, sync_videofacebiz_params, sync_videofacebiz_blacklist -from api.errors import ( - APIError, - validation_exception_handler, - api_error_handler, - generic_exception_handler -) -from config import settings -from database.connection import init_database -from database.connection import db_manager -from rtsp.service import rtsp_server - - -# 生命周期管理 -@asynccontextmanager -async def lifespan(app: FastAPI): - """ - 应用生命周期管理 - - - 启动时:初始化数据库 - - 关闭时:清理资源 - """ - # 启动时 - print("🚀 start algorithm service...") - print(f"📊 db: {settings.DATABASE_NAME}") - print(f"🔧 debug mode: {settings.DEBUG}") - - # 初始化数据库 - init_database() - - # 数据库健康检查 - if db_manager.health_check(): - print("✅ 数据库连接正常") - else: - print("❌ 数据库连接失败") - - # 启动 RTSP 服务(如果启用) - if settings.RTSP_ENABLED: - print("📹 启动 RTSP 服务...") - rtsp_server.start() - # 将 RTSP 服务实例保存到应用状态 - app.state.rtsp_server = rtsp_server - - # 自动同步VideoFaceBiz参数和黑名单 - print("🔄 自动同步VideoFaceBiz参数和黑名单...") - try: - params_updated = sync_videofacebiz_params() - blacklist_loaded = sync_videofacebiz_blacklist() - print(f"✅ 自动同步完成 - 参数更新: {params_updated}个, 黑名单加载: {blacklist_loaded}个") - except Exception as e: - print(f"⚠️ 自动同步失败: {e}") - else: - print("⚠️ RTSP 服务未启用") - - yield - - # 关闭时 - print("🛑 algorithm service stopped...") - - # 停止 RTSP 服务 - if settings.RTSP_ENABLED: - print("🛑 停止 RTSP 服务...") - rtsp_server.stop() - - db_manager.close() - - -# 创建FastAPI应用 -app = FastAPI( - title=settings.PROJECT_NAME, - version=settings.PROJECT_VERSION, - description=settings.PROJECT_DESCRIPTION, - openapi_url=f"{settings.API_V1_PREFIX}/openapi.json", - docs_url=None, # 自定义docs - redoc_url=None, # 自定义redoc - lifespan=lifespan -) - - -# 自定义API文档页面 -@app.get("/docs", include_in_schema=False) -async def custom_swagger_ui_html(): - return get_swagger_ui_html( - openapi_url=app.openapi_url, - title=f"{app.title} - Swagger UI", - oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, - swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", - swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", - ) - - -@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) -async def swagger_ui_redirect(): - return get_swagger_ui_oauth2_redirect_html() - - -@app.get("/redoc", include_in_schema=False) -async def redoc_html(): - return get_redoc_html( - openapi_url=app.openapi_url, - title=f"{app.title} - ReDoc", - redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js", - ) - - -# 中间件配置 -app.add_middleware( - CORSMiddleware, - allow_origins=settings.BACKEND_CORS_ORIGINS, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -app.add_middleware( - TrustedHostMiddleware, - allowed_hosts=["*"] if settings.DEBUG else ["localhost", "127.0.0.1", "0.0.0.0"] -) - - -# 请求计时中间件 -@app.middleware("http") -async def add_process_time_header(request: Request, call_next): - """ - 添加请求处理时间头 - """ - start_time = time.time() - response = await call_next(request) - process_time = time.time() - start_time - response.headers["X-Process-Time"] = str(process_time) - return response - - -# 异常处理器 -app.add_exception_handler(RequestValidationError, validation_exception_handler) -app.add_exception_handler(APIError, api_error_handler) -app.add_exception_handler(Exception, generic_exception_handler) - - -# 根路由 -@app.get("/") -async def root(): - """ - 根路径 - """ - return { - "message": "algorithm service", - "version": settings.PROJECT_VERSION, - "docs": "/docs", - "api_prefix": settings.API_V1_PREFIX - } - - -@app.get("/health") -async def health_check(): - """ - 健康检查端点 - """ - # 检查数据库连接 - db_healthy = db_manager.health_check() - - return { - "status": "healthy" if db_healthy else "unhealthy", - "database": "connected" if db_healthy else "disconnected", - "timestamp": time.time() - } - - -# 注册API路由 -app.include_router( - face_features.router, - prefix=settings.API_V1_PREFIX -) - -app.include_router( - algorithm_router, - prefix=settings.API_V1_PREFIX -) - - -# 自定义404处理器 -@app.exception_handler(404) -async def not_found_handler(request: Request, exc): - """ - 自定义404错误处理器 - """ - return JSONResponse( - status_code=404, - content={ - "error": { - "code": "NOT_FOUND", - "message": f"请求的资源不存在: {request.url.path}" - } - } - ) - - -# 导出应用实例 -__all__ = ["app"] \ No newline at end of file diff --git a/src/biz/__init__.py b/src/biz/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/config.py b/src/config.py deleted file mode 100644 index 48a4bb6..0000000 --- a/src/config.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -数据库配置模块 -使用pydantic进行配置验证和管理 -""" - -from typing import Optional, List -from pydantic_settings import BaseSettings -from functools import lru_cache -from pydantic import PostgresDsn, field_validator -from pydantic_core.core_schema import FieldValidationInfo - - -class Settings(BaseSettings): - """应用配置类""" - - RTSP_ENABLED: bool = True - - # API配置 - API_V1_PREFIX: str = "/api/v1" - PROJECT_NAME: str = "algorithm-service" - PROJECT_VERSION: str = "1.0.0" - PROJECT_DESCRIPTION: str = "algorithm-service" - BACKEND_CORS_ORIGINS: List[str] = ["http://localhost:3000", "http://localhost:8000"] - - - # 数据库配置 - DATABASE_HOST: str = "localhost" - DATABASE_PORT: int = 5432 - DATABASE_USER: str = "postgres" - DATABASE_PASSWORD: str = "yipai123" - DATABASE_NAME: str = "pmms" - DATABASE_SCHEMA: str = "public" - - # 连接池配置 - DATABASE_POOL_SIZE: int = 10 - DATABASE_MAX_OVERFLOW: int = 20 - DATABASE_POOL_RECYCLE: int = 3600 # 连接回收时间(秒) - DATABASE_ECHO: bool = False # SQL日志,生产环境设为False - - # 应用配置 - APP_NAME: str = "SurFaceFeature API" - APP_VERSION: str = "1.0.0" - DEBUG: bool = False - - # 日志配置 - LOG_LEVEL: str = "INFO" - LOG_FILE: Optional[str] = None - - # 异步配置 - ASYNC_MODE: bool = False - - # 资源文件夹配置 - FACE_REGISTER_IMAGE_RESOURCE_DIR: str = "D:/ruoyi/uploadPath/face" - VIDEO_RESOURCE_DIR: str = "D:/ruoyi/uploadPath/video" - FACE_CAL_FEATURE_TIMEOUT_HOURS: int = 10 - FACE_MODEL_VERSION: int = 0 #insight_face_buffalo_l - FACE_USE_GPU: bool = True - FACE_USE_NPU: bool = False - SUR_CONFIG_TYPE_FACE: int = 0 - SUR_CONFIG_SCOPE_GLOBAL: int = 0 - - # JWT配置(预留) - SECRET_KEY: str = "your-secret-key-here-change-in-production" - ALGORITHM: str = "HS256" - ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 - - @property - def DATABASE_URL(self) -> str: - """构建数据库连接URL""" - return f"postgresql://{self.DATABASE_USER}:{self.DATABASE_PASSWORD}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}" - - @property - def ASYNC_DATABASE_URL(self) -> str: - """构建异步数据库连接URL""" - return f"postgresql+asyncpg://{self.DATABASE_USER}:{self.DATABASE_PASSWORD}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}" - - @field_validator("DATABASE_POOL_SIZE") - def validate_pool_size(cls, v): - """验证连接池大小""" - if v < 1: - raise ValueError("DATABASE_POOL_SIZE must be at least 1") - if v > 100: - raise ValueError("DATABASE_POOL_SIZE cannot exceed 100") - return v - - class Config: - env_file = ".env" - env_file_encoding = "utf-8" - case_sensitive = False - extra = "ignore" - - -@lru_cache() -def get_settings() -> Settings: - """ - 获取配置单例 - 使用lru_cache避免重复加载.env文件 - """ - return Settings() - - -# 导出配置实例 -settings = get_settings() \ No newline at end of file diff --git a/src/utils/logger.py b/src/utils/logger.py deleted file mode 100644 index 5ae9da3..0000000 --- a/src/utils/logger.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -日志配置模块 -""" - -import logging -import sys -from typing import Optional -from logging.handlers import RotatingFileHandler - -from config import settings - - -def setup_logger( - name: str, - level: Optional[str] = None, - log_file: Optional[str] = None -) -> logging.Logger: - """ - 配置和获取logger - - Args: - name: logger名称 - level: 日志级别 - log_file: 日志文件路径 - - Returns: - 配置好的logger实例 - """ - # 获取日志级别 - if level is None: - level = settings.LOG_LEVEL - - log_level = getattr(logging, level.upper(), logging.INFO) - - # 创建logger - logger = logging.getLogger(name) - logger.setLevel(log_level) - - # 避免重复添加handler - if logger.handlers: - return logger - - # 创建formatter - formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' - ) - - # 控制台handler - console_handler = logging.StreamHandler(sys.stdout) - console_handler.setLevel(log_level) - console_handler.setFormatter(formatter) - logger.addHandler(console_handler) - - # 文件handler(如果配置了日志文件) - if log_file or settings.LOG_FILE: - file_path = log_file or settings.LOG_FILE - try: - file_handler = RotatingFileHandler( - file_path, - maxBytes=10 * 1024 * 1024, # 10MB - backupCount=5, - encoding='utf-8' - ) - file_handler.setLevel(log_level) - file_handler.setFormatter(formatter) - logger.addHandler(file_handler) - except Exception as e: - logger.warning(f"Failed to create log file handler: {e}") - - return logger - - -# 创建根logger -root_logger = setup_logger("sur_face_feature") - - -def get_logger(name: str) -> logging.Logger: - """ - 获取指定名称的logger - - Args: - name: logger名称 - - Returns: - logger实例 - """ - return setup_logger(name) \ No newline at end of file diff --git a/src/video_face_recognition_cann_3.py b/video_face_recognition_cann_3.py similarity index 100% rename from src/video_face_recognition_cann_3.py rename to video_face_recognition_cann_3.py