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.
 
 
 
 
 
 

136 lines
4.3 KiB

package echomeet
import (
"context"
"yunyan/lego/sys/log"
"yunyan/pb"
"yunyan/sys/bytedance/audomodel"
"yunyan/sys/bytedance/translate"
"yunyan/sys/doubao"
"fmt"
)
// newByteDanceProviders 初始化字节系单元服务(转写=audomodel、翻译=火山翻译、总结=豆包),
// 返回组合后的转写/翻译/总结三个 provider。
func newByteDanceProviders(opt ProviderOptions) (Transcriber, Translator, Summarizer) {
if err := audomodel.OnInit(opt.Transcribe); err != nil {
log.Errorf("echomeet: init bytedance audomodel failed: %v", err)
}
if err := translate.OnInit(opt.Translate); err != nil {
log.Errorf("echomeet: init bytedance translate failed: %v", err)
}
sys, err := doubao.NewSys(
doubao.SetApikey(opt.Summary.Apikey),
doubao.SetModel(opt.Summary.Model),
)
if err != nil {
log.Errorf("echomeet: init doubao summarizer failed: %v", err)
}
return &byteDanceTranscriber{}, &byteDanceTranslator{}, &doubaoSummarizer{sys: sys}
}
// 字节跳动转写:短音频 RecognizeFlash(同步) + 长音频 CreateTask+QueryTask(异步)
type byteDanceTranscriber struct{}
func (this *byteDanceTranscriber) Name() pb.TranscribeService {
return pb.TranscribeService_TranscribeService_ByteDance
}
func (this *byteDanceTranscriber) SupportsLanguage(bcp47 string) bool {
_, ok := toByteDanceLang(bcp47)
return ok
}
const (
byteDanceFlashMaxSeconds = 7200
byteDanceFlashMaxBytes = 1024 * 1024 * 100
)
func (this *byteDanceTranscriber) Submit(_ context.Context, req SubmitRequest) (*SubmitResult, error) {
lang, _ := toByteDanceLang(req.Language)
// 短音频走 flash 同步通道
if req.Seconds <= byteDanceFlashMaxSeconds && req.SizeBytes <= byteDanceFlashMaxBytes {
statusCode, _, contexts, err := audomodel.RecognizeFlash(req.Uid, req.AudioURL, req.EnableSpeaker, lang)
if err != nil {
return nil, fmt.Errorf("bytedance flash err: status=%s %w", statusCode, err)
}
out := make([]*pb.ContextStruct, 0, len(contexts))
for _, c := range contexts {
out = append(out, &pb.ContextStruct{
Content: c.Content,
Starttime: c.StartTime,
Endtime: c.EndTime,
Speaker: c.Speaker,
})
}
return &SubmitResult{Done: true, Contexts: out}, nil
}
// 长音频走异步 submit
taskID, logID, err := audomodel.CreateTask(req.Uid, req.AudioURL, req.EnableSpeaker, lang, req.CallbackURL, req.CallbackData)
if err != nil {
return nil, fmt.Errorf("bytedance create task: %w", err)
}
return &SubmitResult{TaskID: taskID, LogID: logID}, nil
}
func (this *byteDanceTranscriber) Query(_ context.Context, taskID, logID string) (*QueryResult, error) {
code, contexts, err := audomodel.QueryTask(taskID, logID)
switch code {
case "20000000":
if err != nil {
return &QueryResult{Status: StatusFailed}, err
}
out := make([]*pb.ContextStruct, 0, len(contexts))
for _, c := range contexts {
out = append(out, &pb.ContextStruct{
Content: c.Content,
Starttime: c.StartTime,
Endtime: c.EndTime,
Speaker: c.Speaker,
})
}
return &QueryResult{Status: StatusSuccess, Contexts: out}, nil
case "20000001", "20000002":
return &QueryResult{Status: StatusRunning}, nil
default:
return &QueryResult{Status: StatusFailed}, fmt.Errorf("bytedance query failed code=%s err=%v", code, err)
}
}
// 字节翻译
type byteDanceTranslator struct{}
func (this *byteDanceTranslator) Name() pb.TranscribeService {
return pb.TranscribeService_TranscribeService_ByteDance
}
func (this *byteDanceTranslator) Translate(ctx context.Context, from, to string, texts []string) ([]string, error) {
return translate.Translate(ctx, toByteDanceTranslateLang(from), toByteDanceTranslateLang(to), texts)
}
// 豆包总结
type doubaoSummarizer struct {
sys doubao.ISys
}
func (this *doubaoSummarizer) Name() pb.TranscribeService {
return pb.TranscribeService_TranscribeService_ByteDance
}
func (this *doubaoSummarizer) Chat(ctx context.Context, messages []ChatMessage) (string, error) {
if this.sys == nil {
return "", fmt.Errorf("doubao summarizer not initialized")
}
msgs := make([]doubao.Message, 0, len(messages))
for _, m := range messages {
msgs = append(msgs, doubao.Message{Role: m.Role, Content: m.Content, Images: m.Images})
}
resp, err := this.sys.Chat(ctx, msgs)
if err != nil {
return "", err
}
if resp == nil {
return "", fmt.Errorf("doubao chat: empty response")
}
return resp.Content, nil
}