appQQQ commited on
Commit
8178bce
·
verified ·
1 Parent(s): 16f2099

chore: upload app/llm/factory.py

Browse files
Files changed (1) hide show
  1. app/llm/factory.py +104 -0
app/llm/factory.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """LLM 工厂: 根据 settings.llm_provider 选择 provider.
2
+
3
+ 新增 provider 的步骤:
4
+ 1. 在 base.py 实现一个新类 (或复用 OpenAICompatibleLLM)
5
+ 2. 在本文件 _PROVIDERS 加一行
6
+ 3. 在 .env.example 暴露新 env
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from functools import lru_cache
12
+
13
+ from app.config import settings
14
+ from app.core.errors import LLMUnavailableError
15
+ from app.llm.base import AbstractLLM
16
+ from app.llm.minimax import OpenAICompatibleLLM
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def _build_minimax() -> OpenAICompatibleLLM:
22
+ key = settings.minimax_api_key.get_secret_value()
23
+ if not key:
24
+ raise LLMUnavailableError(
25
+ "MINIMAX_API_KEY is empty. Set it in .env or HF Space secrets.",
26
+ code="llm_api_key_missing",
27
+ )
28
+ return OpenAICompatibleLLM(
29
+ api_key=key,
30
+ base_url=settings.minimax_base_url,
31
+ model=settings.minimax_model,
32
+ provider_name="minimax",
33
+ )
34
+
35
+
36
+ def _build_openai() -> OpenAICompatibleLLM:
37
+ key = settings.openai_api_key.get_secret_value()
38
+ if not key:
39
+ raise LLMUnavailableError(
40
+ "OPENAI_API_KEY is empty.",
41
+ code="llm_api_key_missing",
42
+ )
43
+ return OpenAICompatibleLLM(
44
+ api_key=key,
45
+ base_url="https://api.openai.com/v1",
46
+ # 允许用 env 覆盖 model (openai_model), 没设则用 gpt-4o-mini
47
+ model=getattr(settings, "openai_model", "gpt-4o-mini"),
48
+ provider_name="openai",
49
+ )
50
+
51
+
52
+ def _build_qwen() -> OpenAICompatibleLLM:
53
+ key = settings.qwen_api_key.get_secret_value()
54
+ if not key:
55
+ raise LLMUnavailableError(
56
+ "QWEN_API_KEY is empty.",
57
+ code="llm_api_key_missing",
58
+ )
59
+ return OpenAICompatibleLLM(
60
+ api_key=key,
61
+ # 阿里百炼 OpenAI 兼容端点
62
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
63
+ model=getattr(settings, "qwen_model", "qwen-max"),
64
+ provider_name="qwen",
65
+ )
66
+
67
+
68
+ def _build_anthropic() -> AbstractLLM:
69
+ """占位: Anthropic SDK 原生协议, 暂未实现, 留 hook."""
70
+ raise NotImplementedError(
71
+ "Anthropic provider not yet implemented. "
72
+ "Use openai-compatible via OpenRouter or implement anthropic.AsyncAnthropic wrapper."
73
+ )
74
+
75
+
76
+ _PROVIDERS = {
77
+ "minimax": _build_minimax,
78
+ "openai": _build_openai,
79
+ "qwen": _build_qwen,
80
+ "anthropic": _build_anthropic,
81
+ }
82
+
83
+
84
+ @lru_cache(maxsize=1)
85
+ def get_llm() -> AbstractLLM:
86
+ """单例 LLM. 在 lifespan 中调用 + 缓存."""
87
+ builder = _PROVIDERS.get(settings.llm_provider)
88
+ if builder is None:
89
+ raise LLMUnavailableError(
90
+ f"Unknown llm_provider: {settings.llm_provider}",
91
+ code="llm_provider_unknown",
92
+ )
93
+ logger.info("Initializing LLM provider: %s", settings.llm_provider)
94
+ return builder()
95
+
96
+
97
+ async def close_llm() -> None:
98
+ """关闭 LLM 客户端. lifespan shutdown 时调用."""
99
+ try:
100
+ llm = get_llm()
101
+ except Exception: # noqa: BLE001
102
+ return
103
+ await llm.aclose()
104
+ get_llm.cache_clear()