""" 全局共享依赖: - 认证:get_current_user / get_optional_user - Port DI factory:get_sms_sender / get_llm_provider / get_tts_provider / ... """ from functools import lru_cache from typing import Optional from fastapi import Depends from sqlalchemy.ext.asyncio import AsyncSession from app.core.config import settings from app.core.eval_judge_spec import EvalJudgeLlmSpec, EvalJudgeProvider from app.core.runtime_constants import asr_defaults, llm_defaults, misc_defaults, tts_defaults from app.features.memoir.constants import memoir from app.ports.asr import ASRProvider from app.ports.embedding import EmbeddingProvider from app.ports.image_gen import ImageGenerator from app.ports.llm import LLMProvider from app.ports.sms import SmsSender from app.ports.storage import ObjectStorage from app.ports.tts import TTSProvider # ── Port DI factories ─────────────────────────────────────── @lru_cache def get_sms_sender() -> SmsSender: from app.adapters.sms.tencent import TencentSmsSender return TencentSmsSender( secret_id=settings.tencent_secret_id, secret_key=settings.tencent_secret_key, sdk_app_id=settings.tencent_sms_sdk_app_id, sign_name=settings.tencent_sms_sign_name, template_id=settings.tencent_sms_template_id, template_param_count=misc_defaults.tencent_sms_template_param_count, ) @lru_cache def get_llm_provider() -> LLMProvider: from app.adapters.llm.deepseek import DeepSeekLLMProvider api_key = settings.deepseek_api_key or "" base_url = llm_defaults.deepseek_base_url or "" model = llm_defaults.deepseek_model or "deepseek-v4-flash" return DeepSeekLLMProvider( api_key=api_key, base_url=base_url, model=model, temperature=llm_defaults.temperature, extra_body={ "thinking": { "type": "enabled" if llm_defaults.deepseek_thinking_enabled else "disabled" } }, ) @lru_cache def get_llm_provider_fast() -> LLMProvider: """快档位:与默认共用密钥与 base_url,仅模型名可单独配置。""" fast = (llm_defaults.fast_model or "").strip() if not fast: return get_llm_provider() from app.adapters.llm.deepseek import DeepSeekLLMProvider api_key = settings.deepseek_api_key or "" base_url = llm_defaults.deepseek_base_url or "" return DeepSeekLLMProvider( api_key=api_key, base_url=base_url, model=fast, temperature=llm_defaults.temperature, extra_body={ "thinking": { "type": "enabled" if llm_defaults.deepseek_thinking_enabled else "disabled" } }, ) @lru_cache def get_tts_provider() -> TTSProvider: if tts_defaults.provider == "tencent": from app.adapters.tts.tencent_tts import TencentTTSProvider return TencentTTSProvider( secret_id=settings.tencent_secret_id, secret_key=settings.tencent_secret_key, voice_type=tts_defaults.voice_type, codec=tts_defaults.codec, voice_type_en=tts_defaults.voice_type_en, ) from app.adapters.tts.openai_tts import OpenAITTSProvider return OpenAITTSProvider(api_key="") @lru_cache def get_asr_provider() -> ASRProvider: from app.adapters.asr.tencent_asr import TencentASRProvider return TencentASRProvider( secret_id=settings.tencent_secret_id, secret_key=settings.tencent_secret_key, app_id=settings.tencent_app_id, engine_type=asr_defaults.engine_type, request_timeout_seconds=asr_defaults.request_timeout_seconds, ) @lru_cache def get_image_generator() -> ImageGenerator: from app.adapters.image_gen.liblib import LiblibImageGenerator return LiblibImageGenerator( access_key=settings.liblib_access_key, secret_key=settings.liblib_secret_key, base_url=misc_defaults.liblib_base_url, template_uuid=settings.liblib_template_uuid, poll_interval=memoir.image_poll_interval, max_attempts=memoir.image_max_attempts, ) @lru_cache def get_object_storage() -> ObjectStorage: from app.adapters.storage.tencent_cos import TencentCosStorage return TencentCosStorage( secret_id=settings.tencent_secret_id, secret_key=settings.tencent_secret_key, region=misc_defaults.tencent_cos_region, bucket=settings.tencent_cos_bucket, base_url=settings.tencent_cos_base_url, token="", ) @lru_cache def get_embedding_provider() -> EmbeddingProvider: from app.adapters.embedding.zhipu import ZhipuEmbeddingProvider return ZhipuEmbeddingProvider( api_key=settings.zhipu_api_key, base_url=llm_defaults.embedding_base_url or None, model=llm_defaults.embedding_model, ) # Re-export auth deps for backward compatibility from app.core.auth_deps import get_current_user, get_optional_user # noqa: F401 # ── Eval judge ─────────────────────────────────────────────── def build_eval_judge_llm_spec( provider: EvalJudgeProvider = "zhipu", judge_model: str | None = None, ) -> EvalJudgeLlmSpec | None: """按供应商装配 ChatOpenAI;密钥缺失时返回 None(llm 为 None)。""" from app.adapters.llm.deepseek_eval_judge import build_deepseek_eval_judge_spec from app.adapters.llm.zhipu_eval_judge import build_zhipu_eval_judge_spec if provider == "deepseek": return build_deepseek_eval_judge_spec(judge_model) return build_zhipu_eval_judge_spec(judge_model) def get_eval_judge_langchain_llm(): """兼容:等价于智谱供应商下的 `build_eval_judge_llm_spec(\"zhipu\", None).llm`。""" spec = build_eval_judge_llm_spec("zhipu", None) return spec.llm if spec else None