Browse Source
线上表现:文本翻译 / 同传 / 面对面全部报「未配置机器翻译服务」, 而后台 EAIMAR 下 mt_alibaba / mt_azure / mt_volcano 三家都启用着、凭据也都填了。 根因:resolveTranslator 挑选时没有任何优先级,谁先从 postgres 返回就用谁, 这次挑中了 mt_volcano,而服务端只实现了阿里一家,于是落进「provider 不是 alibaba 就返回 nil」的分支。错误信息指向「没配置」,会把人引去后台反复检查 明明填好的凭据;而且它取决于数据库返回顺序,可能自己好、也可能自己坏。 - 新增 mtProviderPriority 白名单:只在真正接了的 provider 里挑,并给出稳定优先级。 - 挑选抽成纯函数 pickMTSvc(可脱离 postgres 测),被跳过的未接入服务打一条点名 warn。 - 缓存命中不再硬编码返回 "alibaba",改为记住实际 provider。 - model_translate_test.go 5 个用例:未接入的要跳过、全不可用返回 nil、 停用/非 MT 类别不参与、应用行优先、provider 大小写归一。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>main
2 changed files with 170 additions and 20 deletions
@ -0,0 +1,86 @@ |
|||
package user |
|||
|
|||
import ( |
|||
"strings" |
|||
"testing" |
|||
|
|||
"yunyan/comm" |
|||
) |
|||
|
|||
func mtSvc(app, id, provider string, enable bool) *comm.ThirdSvcConfig { |
|||
return &comm.ThirdSvcConfig{ |
|||
AppName: app, |
|||
Id: id, |
|||
Provider: provider, |
|||
Categories: "3", // comm.SvcCatMT
|
|||
Enable: enable, |
|||
} |
|||
} |
|||
|
|||
// 后台同时启用了三家 MT,只有阿里是服务端真接了的:必须挑阿里,
|
|||
// 而不是看 postgres 先返回谁。2026-09-14 线上翻译整体报「未配置机器翻译服务」
|
|||
// 就是因为没这条规则、随手挑中了 mt_volcano。
|
|||
func TestPickMTSvcSkipsUnimplementedProviders(t *testing.T) { |
|||
// 顺序刻意把没接入的排在最前,模拟库的返回顺序不利的情况
|
|||
svcs := []*comm.ThirdSvcConfig{ |
|||
mtSvc("EAIMAR", "mt_volcano", "volcano", true), |
|||
mtSvc("EAIMAR", "mt_azure", "azure", true), |
|||
mtSvc("EAIMAR", "mt_alibaba", "alibaba", true), |
|||
} |
|||
picked, skipped := pickMTSvc(svcs, "EAIMAR") |
|||
if picked == nil || picked.Id != "mt_alibaba" { |
|||
t.Fatalf("应挑中 mt_alibaba,实际 %v", pickedIdOf(picked)) |
|||
} |
|||
if len(skipped) != 2 || !strings.Contains(strings.Join(skipped, ","), "mt_volcano") { |
|||
t.Fatalf("未接入的两家应记进 skipped 供日志排查,实际 %v", skipped) |
|||
} |
|||
} |
|||
|
|||
// 全都没接入时返回 nil(调用方回 TranslateNotConfigured),
|
|||
// 并且把跳过的列出来——否则「配了却报未配置」无从查起。
|
|||
func TestPickMTSvcAllUnimplemented(t *testing.T) { |
|||
svcs := []*comm.ThirdSvcConfig{ |
|||
mtSvc("EAIMAR", "mt_volcano", "volcano", true), |
|||
mtSvc("EAIMAR", "mt_azure", "azure", true), |
|||
} |
|||
picked, skipped := pickMTSvc(svcs, "EAIMAR") |
|||
if picked != nil { |
|||
t.Fatalf("没有接得上的服务时应返回 nil,实际 %v", picked.Id) |
|||
} |
|||
if len(skipped) != 2 { |
|||
t.Fatalf("skipped 应含两家,实际 %v", skipped) |
|||
} |
|||
} |
|||
|
|||
// 停用的、类别不含 MT 的,一律不参与。
|
|||
func TestPickMTSvcIgnoresDisabledAndOtherCategories(t *testing.T) { |
|||
other := mtSvc("EAIMAR", "stt_azure", "alibaba", true) |
|||
other.Categories = "1" // STT
|
|||
svcs := []*comm.ThirdSvcConfig{ |
|||
mtSvc("EAIMAR", "mt_alibaba", "alibaba", false), // 停用
|
|||
other, |
|||
} |
|||
if picked, _ := pickMTSvc(svcs, "EAIMAR"); picked != nil { |
|||
t.Fatalf("停用/非 MT 类别不应被选中,实际 %v", picked.Id) |
|||
} |
|||
} |
|||
|
|||
// 本应用的行优先于全局行(作用域归一后全局行已不再产生,这条守存量数据)。
|
|||
func TestPickMTSvcPrefersAppScope(t *testing.T) { |
|||
svcs := []*comm.ThirdSvcConfig{ |
|||
mtSvc("", "mt_alibaba", "alibaba", true), |
|||
mtSvc("EAIMAR", "mt_alibaba", "alibaba", true), |
|||
} |
|||
picked, _ := pickMTSvc(svcs, "EAIMAR") |
|||
if picked == nil || picked.AppName != "EAIMAR" { |
|||
t.Fatalf("应优先取本应用的行,实际 %v", picked) |
|||
} |
|||
} |
|||
|
|||
// provider 是人手填的,大小写/空格不该影响匹配。
|
|||
func TestPickMTSvcNormalizesProvider(t *testing.T) { |
|||
svcs := []*comm.ThirdSvcConfig{mtSvc("EAIMAR", "mt_alibaba", " Alibaba ", true)} |
|||
if picked, _ := pickMTSvc(svcs, "EAIMAR"); picked == nil { |
|||
t.Fatal("provider 大小写/空白不应影响匹配") |
|||
} |
|||
} |
|||
Loading…
Reference in new issue