fix(translate): 调整优先级为 zhipu→spark(智谱第一,星火第二)

This commit is contained in:
Mavis
2026-06-11 09:28:03 +08:00
parent 3f183d14db
commit 2e0e5ea80c

View File

@@ -1,8 +1,8 @@
"""翻译服务门面:配额检查 + 缓存 + 引擎选择 + 月度计数。
引擎链路(优先级降序):
1. spark(主,Lite 免费;spark_api_password 配了才用)
2. zhipu(第二序位,GLM-4-Flash 免费;zhipu_api_key 配了才用)
1. zhipu(主,GLM-4-Flash 免费;zhipu_api_key 配了才用)
2. spark(第二序位,Lite 免费;spark_api_password 配了才用)
3. tencent TMT(第三级,按月配额;快满时主动切走)
4. tencent_maas(备用,OpenAI 兼容,无配额;主失败/TMT 配额耗尽时启用)
5. agnes(第四级,通用 LLM 做翻译;MaaS 不可用时启用 — 质量次之但够用)
@@ -12,8 +12,9 @@
- TMT 是按月计费的(腾讯云后台可能计费口径是请求字节,我们 redis 累加的是字符数,
差异约 2-3x);用户从腾讯云后台看"已用 2M"时,我们 redis 显示约 80 万字符
- 用户决策:以腾讯云后台数字为准,快满时降级
- spark / zhipu 都是免费模型,默认优先;不可用时降级到 tencent(继续吃配额)。
- zhipu / spark 都是免费模型,默认优先;不可用时降级到 tencent(继续吃配额)。
想要完全绕开 tencent,把 TENCENTCLOUD_SECRET_ID 留空即可。
- 智谱放第一是因为它家 GLM-4-Flash 翻译质量比星火 Lite 更稳,星火降为二级
"""
from __future__ import annotations
@@ -58,18 +59,8 @@ class TranslationService:
# 串行:1 个并发;避免触发腾讯 TMT 限速
self._sem = asyncio.Semaphore(1)
def _spark_translator(self) -> BaseTranslator | None:
"""主引擎:星火 Spark(Lite 免费)。配了 spark_api_password 才启用。"""
if self._spark is None and settings.spark_api_password:
try:
self._spark = SparkTranslator()
except Exception as e:
logger.warning("spark init failed: %s", e)
self._spark = None
return self._spark
def _zhipu_translator(self) -> BaseTranslator | None:
"""第二序位引擎:智谱 GLM(免费)。配了 zhipu_api_key 才启用。"""
"""引擎:智谱 GLM(免费)。配了 zhipu_api_key 才启用。"""
if self._zhipu is None and settings.zhipu_api_key:
try:
self._zhipu = ZhipuTranslator()
@@ -78,6 +69,16 @@ class TranslationService:
self._zhipu = None
return self._zhipu
def _spark_translator(self) -> BaseTranslator | None:
"""第二序位引擎:星火 Spark(Lite 免费)。配了 spark_api_password 才启用。"""
if self._spark is None and settings.spark_api_password:
try:
self._spark = SparkTranslator()
except Exception as e:
logger.warning("spark init failed: %s", e)
self._spark = None
return self._spark
def _primary(self) -> BaseTranslator | None:
"""第三级:腾讯 TMT(初始化失败返回 None 表示不可用)。"""
if self._tencent is None:
@@ -168,12 +169,12 @@ class TranslationService:
return TranslationResult(text=cached, engine="cache", chars=chars, cached=True)
# 2) 选引擎
# 优先级:spark → zhipu → tencent(配额)→ maas → agnes → local
# 优先级:zhipu → spark → tencent(配额)→ maas → agnes → local
engine: BaseTranslator | None = None
if self._spark_translator() is not None:
engine = self._spark_translator()
elif self._zhipu_translator() is not None:
if self._zhipu_translator() is not None:
engine = self._zhipu_translator()
elif self._spark_translator() is not None:
engine = self._spark_translator()
elif await self.can_use_tencent(chars):
engine = self._primary()
if engine is None:
@@ -204,17 +205,17 @@ class TranslationService:
res = await engine.translate(text, source=source, target=target)
except Exception as e:
logger.exception("translate failed with %s: %s", engine.name, e)
# 失败时按 zhipu → tencent → maas → local 顺序找一个不同的 fallback
# spark / zhipu 失败时也要走 tencent(继续吃配额,因优先级只是降低不是禁用)
# 失败时按 spark → tencent → maas → local 顺序找一个不同的 fallback
# zhipu / spark 失败时也要走 tencent(继续吃配额,因优先级只是降低不是禁用)
fb: BaseTranslator | None = None
if engine.name == "spark":
if self._zhipu_translator() is not None:
fb = self._zhipu_translator()
if engine.name == "zhipu":
if self._spark_translator() is not None:
fb = self._spark_translator()
if fb is None and await self.can_use_tencent(chars):
fb = self._primary()
if fb is None:
fb = self._maas() if engine.name != "tencent_maas" else None
elif engine.name == "zhipu":
elif engine.name == "spark":
if await self.can_use_tencent(chars):
fb = self._primary()
if fb is None: