package echomeet import ( "context" "yunyan/lego/sys/log" "yunyan/pb" "yunyan/sys/microsoft/speech" "yunyan/sys/microsoft/translate" "yunyan/sys/openai" "fmt" ) // newMicrosoftProviders 初始化微软系单元服务(转写=Azure Speech、翻译=Azure Translator、 // 总结=Azure OpenAI 兼容端点),返回组合后的转写/翻译/总结三个 provider。 func newMicrosoftProviders(opt ProviderOptions) (Transcriber, Translator, Summarizer) { if err := speech.OnInit(opt.Transcribe); err != nil { log.Errorf("echomeet: init microsoft speech failed: %v", err) } if err := translate.OnInit(opt.Translate); err != nil { log.Errorf("echomeet: init microsoft translate failed: %v", err) } sys, err := openai.NewSys( openai.SetBaseURL(opt.Summary.BaseURL), openai.SetToken(opt.Summary.Token), openai.SetModel(opt.Summary.Model), openai.SetMaxfunccall(1), ) if err != nil { log.Errorf("echomeet: init microsoft(azure openai) summarizer failed: %v", err) } return µsoftTranscriber{}, µsoftTranslator{}, µsoftSummarizer{sys: sys} } // Azure Speech Batch Transcription type microsoftTranscriber struct{} func (this *microsoftTranscriber) Name() pb.TranscribeService { return pb.TranscribeService_TranscribeService_Microsoft } // Azure Speech 支持的语种较广,原生使用 BCP-47 locale,不做白名单限制; // 不支持时由 Azure 直接返回错误,统一在 Submit 失败路径处理。 func (this *microsoftTranscriber) SupportsLanguage(_ string) bool { return true } func (this *microsoftTranscriber) Submit(_ context.Context, req SubmitRequest) (*SubmitResult, error) { taskID, err := speech.CreateTask(req.AudioURL, req.Language, req.EnableSpeaker, req.CallbackURL) if err != nil { return nil, fmt.Errorf("microsoft speech create task: %w", err) } return &SubmitResult{TaskID: taskID}, nil } func (this *microsoftTranscriber) Query(_ context.Context, taskID, _ string) (*QueryResult, error) { status, contexts, err := speech.QueryTask(taskID) switch status { case speech.StatusSuccess: 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 speech.StatusRunning: return &QueryResult{Status: StatusRunning}, nil default: return &QueryResult{Status: StatusFailed}, fmt.Errorf("microsoft speech query failed: %w", err) } } // Azure Translator type microsoftTranslator struct{} func (this *microsoftTranslator) Name() pb.TranscribeService { return pb.TranscribeService_TranscribeService_Microsoft } func (this *microsoftTranslator) Translate(ctx context.Context, from, to string, texts []string) ([]string, error) { return translate.Translate(ctx, toMicrosoftTranslateLang(from), toMicrosoftTranslateLang(to), texts) } // Azure OpenAI 总结(OpenAI 兼容端点) type microsoftSummarizer struct { sys openai.ISys } func (this *microsoftSummarizer) Name() pb.TranscribeService { return pb.TranscribeService_TranscribeService_Microsoft } func (this *microsoftSummarizer) Chat(ctx context.Context, messages []ChatMessage) (string, error) { if this.sys == nil { return "", fmt.Errorf("microsoft summarizer not initialized") } msgs := make([]openai.ChatReq, 0, len(messages)) for _, m := range messages { msgs = append(msgs, openai.ChatReq{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("microsoft(azure openai) chat: empty response") } return resp.Content, nil }