Files
xiaoxia-saas/apps/api/app/dependencies.py
T
API文档维护Agent 312dad7497 feat: Phase 2 查重后端 API 实现
六边形架构分层实现:

Domain 层:
- DuplicationRecord / DuplicateSegment 实体
- 状态机生命周期 (pending→processing→completed/failed)

Ports 层:
- DuplicationRecordRepository Protocol

Adapters 层:
- SQLAlchemyDuplicationRecordRepository 完整实现
- DuplicationRecordModel / DuplicationSegmentModel ORM 模型

Application 层:
- UploadForDuplicationUseCase (上传查重)
- ListDuplicationRecordsUseCase (记录列表)
- GetDuplicationDetailUseCase (详情查询)
- DeleteDuplicationRecordUseCase (删除)
- RetryDuplicationUseCase (重新查重)

API 层:
- POST /api/v1/duplication/upload (上传视频查重)
- GET /api/v1/duplication/records (记录列表)
- GET /api/v1/duplication/records/{id} (详情含片段)
- DELETE /api/v1/duplication/records/{id} (删除)
- POST /api/v1/duplication/records/{id}/retry (重新查重)

Alembic 迁移:
- 011_add_duplication_tables.py (duplication_records + duplication_segments)

API 契约与前端 feat/phase2-duplication-ui (PR#75) 完全对齐。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-28 16:12:46 +08:00

171 lines
6.3 KiB
Python

"""Dependency injection providers for FastAPI endpoints.
All repository and service factories are defined here as FastAPI dependencies,
ensuring proper lifecycle management and testability.
"""
from __future__ import annotations
import redis
from typing import Generator
from app.config import settings
from fastapi import Depends
from sqlalchemy.orm import Session
from packages.adapters.redis import NoopSessionStore, SessionStore
from packages.adapters.smtp import EmailConfig, NoopEmailService, get_email_service
from packages.adapters.sqlalchemy_impl.asset_library_repository import (
SQLAlchemyAssetLibraryRepository,
)
from packages.adapters.sqlalchemy_impl.asset_repository import SQLAlchemyAssetRepository
from packages.adapters.sqlalchemy_impl.classification_job_repository import (
SQLAlchemyClassificationJobRepository,
)
from packages.adapters.sqlalchemy_impl.duplication_repository import (
SQLAlchemyDuplicationRecordRepository,
)
from packages.adapters.sqlalchemy_impl.generated_video_repository import (
SQLAlchemyGeneratedVideoRepository,
)
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
SQLAlchemyGenerationTaskRepository,
)
from packages.adapters.sqlalchemy_impl.title_library_repository import (
SQLAlchemyTitleLibraryRepository,
)
from packages.adapters.sqlalchemy_impl.voice_library_repository import (
SQLAlchemyVoiceLibraryRepository,
)
from packages.adapters.sqlalchemy_impl.ingest_job_repository import (
SQLAlchemyIngestJobRepository,
)
from packages.adapters.sqlalchemy_impl.project_repository import (
SQLAlchemyProjectRepository,
)
from packages.adapters.sqlalchemy_impl.session import build_session_factory
from packages.adapters.sqlalchemy_impl.user_repository import SQLAlchemyUserRepository
from packages.ports.asset_repository import AssetRepository
from packages.ports.asset_library_repository import AssetLibraryRepository
from packages.ports.user_repository import UserRepository
from packages.ports.classification_job_repository import ClassificationJobRepository
from packages.ports.duplication_repository import DuplicationRecordRepository
from packages.ports.generation_task_repository import GenerationTaskRepository
from packages.ports.title_library_repository import TitleLibraryRepository
from packages.ports.voice_library_repository import VoiceLibraryRepository
from packages.ports.generated_video_repository import GeneratedVideoRepository
from packages.ports.ingest_job_repository import IngestJobRepository
from packages.ports.project_repository import ProjectRepository
_engine, _SessionLocal = build_session_factory(settings.DATABASE_URL)
def get_db_session() -> Generator[Session, None, None]:
"""Provide a database session with automatic cleanup."""
session: Session = _SessionLocal()
try:
yield session
finally:
session.close()
def get_asset_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyAssetRepository:
"""Provide the SQLAlchemy asset repository implementation."""
return SQLAlchemyAssetRepository(session)
def get_asset_library_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyAssetLibraryRepository:
"""Provide the SQLAlchemy asset library repository implementation."""
return SQLAlchemyAssetLibraryRepository(session)
def get_ingest_job_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyIngestJobRepository:
"""Provide the SQLAlchemy ingest job repository implementation."""
return SQLAlchemyIngestJobRepository(session)
def get_classification_job_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyClassificationJobRepository:
"""Provide the SQLAlchemy classification job repository implementation."""
return SQLAlchemyClassificationJobRepository(session)
def get_generation_task_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyGenerationTaskRepository:
"""Provide the SQLAlchemy generation task repository implementation."""
return SQLAlchemyGenerationTaskRepository(session)
def get_generated_video_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyGeneratedVideoRepository:
"""Provide the SQLAlchemy generated video repository implementation."""
return SQLAlchemyGeneratedVideoRepository(session)
def get_duplication_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyDuplicationRecordRepository:
"""Provide the SQLAlchemy duplication record repository implementation."""
return SQLAlchemyDuplicationRecordRepository(session)
def get_project_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyProjectRepository:
"""Provide the SQLAlchemy project repository implementation."""
return SQLAlchemyProjectRepository(session)
def get_user_repository(
session: Session = Depends(get_db_session),
) -> UserRepository:
"""Provide the SQLAlchemy user repository implementation."""
return SQLAlchemyUserRepository(session)
def get_auth_session_store() -> SessionStore | NoopSessionStore:
"""Provide the session store based on configuration."""
if not settings.ENABLE_REDIS_SESSIONS:
return NoopSessionStore()
return SessionStore(redis_client=redis.from_url(settings.REDIS_URL, decode_responses=True))
def get_auth_email_service() -> NoopEmailService | EmailService:
"""Provide the email service based on configuration."""
if not settings.ENABLE_EMAIL_DELIVERY:
return NoopEmailService()
return get_email_service(
EmailConfig(
smtp_host=settings.SMTP_HOST,
smtp_port=settings.SMTP_PORT,
smtp_user=settings.SMTP_USER,
smtp_password=settings.SMTP_PASSWORD,
from_email=settings.SMTP_FROM_EMAIL,
from_name=settings.SMTP_FROM_NAME,
use_tls=settings.SMTP_USE_TLS,
),
enabled=True,
)
def get_title_library_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyTitleLibraryRepository:
"""Provide the SQLAlchemy title library repository implementation."""
return SQLAlchemyTitleLibraryRepository(session)
def get_voice_library_repository(
session: Session = Depends(get_db_session),
) -> SQLAlchemyVoiceLibraryRepository:
"""Provide the SQLAlchemy voice library repository implementation."""
return SQLAlchemyVoiceLibraryRepository(session)