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.
139 lines
4.3 KiB
139 lines
4.3 KiB
package echomeet
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
|
|
"yunyan/comm"
|
|
"yunyan/modules"
|
|
|
|
"yunyan/lego/core"
|
|
)
|
|
|
|
func NewModule() core.IModule {
|
|
m := new(Echomeet)
|
|
return m
|
|
}
|
|
|
|
type Echomeet struct {
|
|
modules.ModuleBase
|
|
options *Options
|
|
api *apiComp
|
|
model *modelComp
|
|
cache *modelCacheComp
|
|
tasks *tasksComp
|
|
providers *providersComp
|
|
analyze comm.IAnalyze
|
|
|
|
service core.IService
|
|
mem comm.IMemory // 同进程的 memory 模块(会议纪要 → 待办抽取),惰性取
|
|
memOnce sync.Once
|
|
}
|
|
|
|
func (this *Echomeet) GetType() core.M_Modules {
|
|
return comm.ModuleEchomeet
|
|
}
|
|
func (this *Echomeet) NewOptions() (options core.IModuleOptions) {
|
|
return new(Options)
|
|
}
|
|
func (this *Echomeet) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) {
|
|
this.options = options.(*Options)
|
|
this.service = service
|
|
if err = this.ModuleBase.Init(service, module, options); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// memoryModule 惰性取同进程的 memory 模块(会议纪要 → 待办抽取用)。
|
|
//
|
|
// 惰性而不是 Start 里取:模块 Start 顺序由 home/main.go 的 lego.Run 参数序决定,
|
|
// echomeet 排在 memory 前面,Start 阶段去拿会拿到一个还没 Start 完的实例。
|
|
// 这里只在真正要用时取一次,缓存住。
|
|
func (this *Echomeet) memoryModule() comm.IMemory {
|
|
this.memOnce.Do(func() {
|
|
if m, e := this.service.GetModule(comm.ModuleMemory); e == nil {
|
|
if mm, ok := m.(comm.IMemory); ok {
|
|
this.mem = mm
|
|
}
|
|
}
|
|
if this.mem == nil {
|
|
this.Warnf("未取到 memory 模块,会议待办抽取不可用(本服务可能没装载它)")
|
|
}
|
|
})
|
|
return this.mem
|
|
}
|
|
|
|
func (this *Echomeet) Start() (err error) {
|
|
if err = this.ModuleBase.Start(); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// MeetCapabilities 实现 comm.IEchomeet:把编排快照里的语言/总结模型汇总给同进程的其他模块
|
|
// (user 的 v3 配置下发)。读内存快照,不查库;echomeet_getcapabilities 接口用的是同一份数据。
|
|
func (this *Echomeet) MeetCapabilities() (c comm.MeetCapabilities) {
|
|
if this.providers == nil {
|
|
return
|
|
}
|
|
c.TranscribeLanguages, c.TranscribeAnyLanguage = this.providers.TranscribeLanguages()
|
|
c.TranslateLanguages, c.TranslateAnyLanguage = this.providers.TranslateLanguages()
|
|
clientChoice, items := this.providers.SummaryServices()
|
|
c.SummaryClientChoice = clientChoice
|
|
c.SummaryServices = make([]comm.MeetSummaryService, 0, len(items))
|
|
for _, it := range items {
|
|
c.SummaryServices = append(c.SummaryServices, comm.MeetSummaryService{
|
|
SvcId: it.SvcId, Name: it.Name, IsDefault: it.IsDefault,
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
// ChatLLM 用后台编排选出的总结模型跑一次对话(实现 comm.IEchomeet)。
|
|
//
|
|
// 开给其它模块用(memory 的周报生成、会议待办抽取),目的是让它们也走同一套编排选路,
|
|
// 不必各自 import sys/doubao 把服务商写死。svcId 传空按编排取默认;
|
|
// 返回实际用到的 svcId 便于排障时对齐「这条是谁生成的」。
|
|
func (this *Echomeet) ChatLLM(ctx context.Context, svcId, systemPrompt, userContent string) (string, string, error) {
|
|
if this.providers == nil {
|
|
return "", "", errors.New("echomeet providers 未就绪")
|
|
}
|
|
if strings.TrimSpace(userContent) == "" {
|
|
// 空内容送给大模型只会换回一个语焉不详的 400(通义/豆包都直接报
|
|
// InternalError.Algo.InvalidParameter),在这里挡掉更好排查。
|
|
return "", "", errors.New("userContent 为空")
|
|
}
|
|
usedSvcId := svcId
|
|
var (
|
|
s Summarizer
|
|
e error
|
|
)
|
|
if usedSvcId == "" {
|
|
usedSvcId, s, e = this.providers.PickLLM("")
|
|
} else {
|
|
s, e = this.providers.GetSummarizer(usedSvcId)
|
|
}
|
|
if e != nil {
|
|
return "", usedSvcId, e
|
|
}
|
|
msgs := make([]ChatMessage, 0, 2)
|
|
if systemPrompt != "" {
|
|
msgs = append(msgs, ChatMessage{Role: "system", Content: systemPrompt})
|
|
}
|
|
msgs = append(msgs, ChatMessage{Role: "user", Content: userContent})
|
|
text, err := s.Chat(ctx, msgs)
|
|
return text, usedSvcId, err
|
|
}
|
|
|
|
func (this *Echomeet) OnInstallComp() {
|
|
this.ModuleBase.OnInstallComp()
|
|
this.api = this.RegisterComp(new(apiComp)).(*apiComp)
|
|
this.model = this.RegisterComp(new(modelComp)).(*modelComp)
|
|
this.cache = this.RegisterComp(new(modelCacheComp)).(*modelCacheComp)
|
|
this.providers = this.RegisterComp(new(providersComp)).(*providersComp)
|
|
this.tasks = this.RegisterComp(new(tasksComp)).(*tasksComp)
|
|
}
|
|
|