You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
8.7 KiB
218 lines
8.7 KiB
package echomeet
|
|
|
|
import (
|
|
"context"
|
|
"yunyan/comm"
|
|
"yunyan/lego/core"
|
|
"yunyan/lego/core/cbase"
|
|
"yunyan/pb"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// providersComp 服务聚合组件:
|
|
// - Init 阶段按 echomeet 模块配置初始化字节/阿里/Google/微软四套单元服务(转写+翻译+总结),
|
|
// 并把它们组合成「按服务商成套」的 provider 集合;
|
|
// - 运行期把转写/翻译/总结三类能力按 ServiceType 路由到同一服务商的 provider。
|
|
type providersComp struct {
|
|
cbase.ModuleCompBase
|
|
module *Echomeet
|
|
|
|
transcribers map[pb.TranscribeService]Transcriber
|
|
translators map[pb.TranscribeService]Translator
|
|
summarizers map[pb.TranscribeService]Summarizer
|
|
|
|
// 会议记录服务配置(DB 驱动,启动时从 yaml seed 进应用业务库,改配置重启生效)。
|
|
// 识别/翻译各维护一份按优先级排序的启用清单,识别叠加「支持语言」过滤。见 svcconfig.go。
|
|
svcLoaded bool
|
|
asrOrder []*comm.EchoSvcConfig // 识别:enabled,priority 升序
|
|
mtOrder []*comm.EchoSvcConfig // 翻译:enabled,priority 升序
|
|
llmOrder []*comm.EchoSvcConfig // 总结:enabled,priority 升序(第一个为默认)
|
|
summarizersById map[string]Summarizer // 总结模型实例,key=条目 id(客户端按 id 选择)
|
|
}
|
|
|
|
// 任务状态常量,对齐底层 sys 包
|
|
const (
|
|
StatusRunning = "RUNNING"
|
|
StatusSuccess = "SUCCESS"
|
|
StatusFailed = "FAILED"
|
|
)
|
|
|
|
// SubmitRequest 转写提交请求
|
|
type SubmitRequest struct {
|
|
Uid string
|
|
AudioURL string
|
|
Language string // BCP-47
|
|
EnableSpeaker bool
|
|
Seconds int32
|
|
SizeBytes int64
|
|
CallbackURL string
|
|
CallbackData string
|
|
}
|
|
|
|
// SubmitResult 转写提交结果。Done=true 时同步完成(仅 ByteDance flash),直接取 Contexts;
|
|
// 否则需要后续调用 Query 拉取异步结果。
|
|
type SubmitResult struct {
|
|
Done bool
|
|
TaskID string
|
|
LogID string
|
|
Contexts []*pb.ContextStruct
|
|
}
|
|
|
|
// QueryResult 转写查询结果
|
|
type QueryResult struct {
|
|
Status string
|
|
Contexts []*pb.ContextStruct
|
|
}
|
|
|
|
// ChatMessage 对齐 sys/doubao / sys/google/gemini 的统一消息结构。
|
|
// Images 为可选的图片 url 列表(多模态总结用):非空时该条消息以「文本 + 图片」的多模态形式
|
|
// 发给模型;为空时退化为纯文本,行为与以前一致。要求所配模型支持视觉输入。
|
|
type ChatMessage struct {
|
|
Role string
|
|
Content string
|
|
Images []string
|
|
}
|
|
|
|
// Transcriber 转写 provider 接口
|
|
type Transcriber interface {
|
|
Name() pb.TranscribeService
|
|
SupportsLanguage(bcp47 string) bool
|
|
Submit(ctx context.Context, req SubmitRequest) (*SubmitResult, error)
|
|
Query(ctx context.Context, taskID, logID string) (*QueryResult, error)
|
|
}
|
|
|
|
// Translator 翻译 provider 接口
|
|
type Translator interface {
|
|
Name() pb.TranscribeService
|
|
Translate(ctx context.Context, from, to string, texts []string) ([]string, error)
|
|
}
|
|
|
|
// Summarizer AI 总结 provider 接口
|
|
type Summarizer interface {
|
|
Name() pb.TranscribeService
|
|
Chat(ctx context.Context, messages []ChatMessage) (string, error)
|
|
}
|
|
|
|
// ==================== 组件生命周期 ====================
|
|
|
|
func (this *providersComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) {
|
|
this.ModuleCompBase.Init(service, module, comp, options)
|
|
this.module = module.(*Echomeet)
|
|
opt := options.(*Options)
|
|
|
|
// 按服务商成套初始化:每套各自完成转写/翻译/总结三个单元服务的装配。
|
|
bdTranscriber, bdTranslator, bdSummarizer := newByteDanceProviders(opt.ByteDance)
|
|
aliTranscriber, aliTranslator, aliSummarizer := newAliProviders(opt.Ali)
|
|
ggTranscriber, ggTranslator, ggSummarizer := newGoogleProviders(opt.Google)
|
|
msTranscriber, msTranslator, msSummarizer := newMicrosoftProviders(opt.Microsoft)
|
|
|
|
this.transcribers = map[pb.TranscribeService]Transcriber{
|
|
pb.TranscribeService_TranscribeService_ByteDance: bdTranscriber,
|
|
pb.TranscribeService_TranscribeService_Ali: aliTranscriber,
|
|
pb.TranscribeService_TranscribeService_Google: ggTranscriber,
|
|
pb.TranscribeService_TranscribeService_Microsoft: msTranscriber,
|
|
}
|
|
this.translators = map[pb.TranscribeService]Translator{
|
|
pb.TranscribeService_TranscribeService_ByteDance: bdTranslator,
|
|
pb.TranscribeService_TranscribeService_Ali: aliTranslator,
|
|
pb.TranscribeService_TranscribeService_Google: ggTranslator,
|
|
pb.TranscribeService_TranscribeService_Microsoft: msTranslator,
|
|
}
|
|
this.summarizers = map[pb.TranscribeService]Summarizer{
|
|
pb.TranscribeService_TranscribeService_ByteDance: bdSummarizer,
|
|
pb.TranscribeService_TranscribeService_Ali: aliSummarizer,
|
|
pb.TranscribeService_TranscribeService_Google: ggSummarizer,
|
|
pb.TranscribeService_TranscribeService_Microsoft: msSummarizer,
|
|
}
|
|
this.module.Infof("echomeet providers 初始化完成 DefaultService=%s", opt.DefaultService)
|
|
|
|
// 会议记录服务配置:从 yaml seed 进应用业务库(幂等),并加载识别/翻译的优先级清单。
|
|
// best-effort:失败不阻断启动,选择逻辑会回退到旧的 ResolveServiceType。
|
|
this.loadOrSeedSvcConfig(opt)
|
|
return
|
|
}
|
|
|
|
// ==================== 服务商解析 ====================
|
|
|
|
// parseServiceType 把配置里的服务商名称解析为枚举;空 / auto / 未识别返回 Auto。
|
|
func parseServiceType(s string) pb.TranscribeService {
|
|
switch strings.ToLower(strings.TrimSpace(s)) {
|
|
case "bytedance", "byte", "字节":
|
|
return pb.TranscribeService_TranscribeService_ByteDance
|
|
case "ali", "aliyun", "阿里", "阿里云":
|
|
return pb.TranscribeService_TranscribeService_Ali
|
|
case "google", "谷歌":
|
|
return pb.TranscribeService_TranscribeService_Google
|
|
case "microsoft", "azure", "微软":
|
|
return pb.TranscribeService_TranscribeService_Microsoft
|
|
default:
|
|
return pb.TranscribeService_TranscribeService_Auto
|
|
}
|
|
}
|
|
|
|
// ResolveServiceType 解析本次会议最终使用的服务商。优先级:
|
|
// 1. 请求显式指定 ServiceType → 直接采用(覆盖配置);
|
|
// 2. 模块配置 DefaultService 指定了服务商 → 采用配置;
|
|
// 3. 默认模式(以前的方案):按源语言自动路由——字节支持该语言走字节,否则走阿里。
|
|
//
|
|
// 解析结果一旦确定,会议撰写、翻译、总结三步都走同一服务商。
|
|
func (this *providersComp) ResolveServiceType(svcType pb.TranscribeService, language string) pb.TranscribeService {
|
|
if svcType != pb.TranscribeService_TranscribeService_Auto && svcType != pb.TranscribeService_TranscribeService_Unknown {
|
|
return svcType
|
|
}
|
|
if d := parseServiceType(this.module.options.DefaultService); d != pb.TranscribeService_TranscribeService_Auto {
|
|
return d
|
|
}
|
|
if _, ok := toByteDanceLang(language); ok {
|
|
return pb.TranscribeService_TranscribeService_ByteDance
|
|
}
|
|
return pb.TranscribeService_TranscribeService_Ali
|
|
}
|
|
|
|
// ==================== 工厂方法 ====================
|
|
|
|
// GetTranscriber 取转写 provider;svcType=Auto/Unknown 时先 ResolveServiceType。
|
|
func (this *providersComp) GetTranscriber(svcType pb.TranscribeService, language string) (Transcriber, error) {
|
|
resolved := this.ResolveServiceType(svcType, language)
|
|
if p, ok := this.transcribers[resolved]; ok && p != nil {
|
|
return p, nil
|
|
}
|
|
return nil, fmt.Errorf("transcriber not registered: service=%s", ServiceTypeName(resolved))
|
|
}
|
|
|
|
// GetTranslator 取翻译 provider;与转写同服务商,svcType=Auto/Unknown 时先 ResolveServiceType。
|
|
func (this *providersComp) GetTranslator(svcType pb.TranscribeService, language string) (Translator, error) {
|
|
resolved := this.ResolveServiceType(svcType, language)
|
|
if p, ok := this.translators[resolved]; ok && p != nil {
|
|
return p, nil
|
|
}
|
|
return nil, fmt.Errorf("translator not registered: service=%s", ServiceTypeName(resolved))
|
|
}
|
|
|
|
// GetSummarizer 取总结 provider;与转写同服务商,svcType=Auto/Unknown 时先 ResolveServiceType。
|
|
func (this *providersComp) GetSummarizer(svcType pb.TranscribeService, language string) (Summarizer, error) {
|
|
resolved := this.ResolveServiceType(svcType, language)
|
|
if p, ok := this.summarizers[resolved]; ok && p != nil {
|
|
return p, nil
|
|
}
|
|
return nil, fmt.Errorf("summarizer not registered: service=%s", ServiceTypeName(resolved))
|
|
}
|
|
|
|
// ServiceTypeName 返回服务类型的友好名称,便于日志输出
|
|
func ServiceTypeName(svcType pb.TranscribeService) string {
|
|
switch svcType {
|
|
case pb.TranscribeService_TranscribeService_ByteDance:
|
|
return "ByteDance"
|
|
case pb.TranscribeService_TranscribeService_Ali:
|
|
return "Ali"
|
|
case pb.TranscribeService_TranscribeService_Auto:
|
|
return "Auto"
|
|
case pb.TranscribeService_TranscribeService_Google:
|
|
return "Google"
|
|
case pb.TranscribeService_TranscribeService_Microsoft:
|
|
return "Microsoft"
|
|
default:
|
|
return fmt.Sprintf("Unknown(%d)", int32(svcType))
|
|
}
|
|
}
|
|
|