refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构

- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/
- 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层
- 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构
- 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations)
- 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image
- 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
fawney19
2026-04-03 16:26:16 +08:00
parent 8f26e1a31f
commit 1d9c77522a
868 changed files with 1735 additions and 2433 deletions

View File

@@ -0,0 +1,101 @@
from __future__ import annotations
from typing import Any
from sqlalchemy.orm import Session
from src.models.database import ApiKey
from src.services.orchestration.error_classifier import ErrorClassifier
from src.services.scheduling.aware_scheduler import ProviderCandidate, get_cache_aware_scheduler
from src.services.system.config import SystemConfigService
from .recorder import CandidateRecorder
from .resolver import CandidateResolver
from .schema import CandidateKey
class CandidateService:
"""
CandidateService (Facade).
Phase2 note: this is introduced as a new domain entrypoint. Legacy orchestrators
still exist and will be migrated gradually to use this service.
"""
def __init__(self, db: Session, redis_client: Any | None = None) -> None:
self.db = db
self.redis = redis_client
self._cache_scheduler = None
self._resolver: CandidateResolver | None = None
self._error_classifier: ErrorClassifier | None = None
self._recorder = CandidateRecorder(db)
async def _ensure_initialized(self) -> None:
if self._cache_scheduler is not None:
return
priority_mode = SystemConfigService.get_config(
self.db,
"provider_priority_mode",
"provider",
)
scheduling_mode = SystemConfigService.get_config(
self.db,
"scheduling_mode",
"cache_affinity",
)
self._cache_scheduler = await get_cache_aware_scheduler(
self.redis,
priority_mode=priority_mode,
scheduling_mode=scheduling_mode,
)
self._resolver = CandidateResolver(db=self.db, cache_scheduler=self._cache_scheduler)
self._error_classifier = ErrorClassifier(db=self.db, cache_scheduler=self._cache_scheduler)
async def resolve(
self,
*,
api_format: str,
model_name: str,
affinity_key: str,
user_api_key: ApiKey | None = None,
request_id: str | None = None,
is_stream: bool = False,
capability_requirements: dict[str, bool] | None = None,
preferred_key_ids: list[str] | None = None,
) -> tuple[list[ProviderCandidate], str]:
await self._ensure_initialized()
assert self._resolver is not None
return await self._resolver.fetch_candidates(
api_format=api_format,
model_name=model_name,
affinity_key=affinity_key,
user_api_key=user_api_key,
request_id=request_id,
is_stream=is_stream,
capability_requirements=capability_requirements,
preferred_key_ids=preferred_key_ids,
)
def create_candidate_records(
self,
*,
candidates: list[ProviderCandidate],
request_id: str,
user_api_key: ApiKey,
required_capabilities: dict[str, bool] | None = None,
expand_retries: bool = True,
) -> dict[tuple[int, int], str]:
# CandidateResolver.create_candidate_records is currently the canonical implementation
assert self._resolver is not None, "Call resolve() once before create_candidate_records()"
return self._resolver.create_candidate_records(
all_candidates=candidates,
request_id=request_id,
user_id=str(user_api_key.user_id),
user_api_key=user_api_key,
required_capabilities=required_capabilities,
expand_retries=expand_retries,
)
def get_candidate_keys(self, request_id: str) -> list["CandidateKey"]:
return self._recorder.get_candidate_keys(request_id)