mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 10:15:48 +00:00
Add Transcribe() method to Manager with STT provider dispatch and channel-specific overrides. Implements channelSTTOverrides map, WithChannel context propagation, RegisterChannelSTT registration, and resolveSTTChain fallback logic. Includes manager-level unit tests.
147 lines
4.2 KiB
Go
147 lines
4.2 KiB
Go
package audio
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// mockSTT is a test STTProvider that either returns a fixed result or error.
|
|
type mockSTT struct {
|
|
name string
|
|
result *TranscriptResult
|
|
err error
|
|
}
|
|
|
|
func (m *mockSTT) Name() string { return m.name }
|
|
func (m *mockSTT) Transcribe(_ context.Context, _ STTInput, _ STTOptions) (*TranscriptResult, error) {
|
|
return m.result, m.err
|
|
}
|
|
|
|
func newTestManager() *Manager {
|
|
return NewManager(ManagerConfig{})
|
|
}
|
|
|
|
// Case 1: chain ["elevenlabs","proxy"] — Scribe succeeds, result.Provider="elevenlabs".
|
|
func TestManager_Transcribe_ChainSuccessFirst(t *testing.T) {
|
|
m := newTestManager()
|
|
m.RegisterSTT(&mockSTT{
|
|
name: "elevenlabs",
|
|
result: &TranscriptResult{Text: "hello", Provider: "elevenlabs"},
|
|
})
|
|
m.RegisterSTT(&mockSTT{
|
|
name: "proxy",
|
|
result: &TranscriptResult{Text: "world", Provider: "proxy"},
|
|
})
|
|
m.SetSTTChain([]string{"elevenlabs", "proxy"})
|
|
|
|
res, err := m.Transcribe(context.Background(), STTInput{}, STTOptions{})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if res.Provider != "elevenlabs" {
|
|
t.Errorf("expected provider 'elevenlabs', got %q", res.Provider)
|
|
}
|
|
if res.Text != "hello" {
|
|
t.Errorf("expected text 'hello', got %q", res.Text)
|
|
}
|
|
}
|
|
|
|
// Case 2: Scribe fails → proxy succeeds → result.Provider="proxy".
|
|
func TestManager_Transcribe_FallsToProxy(t *testing.T) {
|
|
m := newTestManager()
|
|
m.RegisterSTT(&mockSTT{
|
|
name: "elevenlabs",
|
|
err: errors.New("scribe 500"),
|
|
})
|
|
m.RegisterSTT(&mockSTT{
|
|
name: "proxy",
|
|
result: &TranscriptResult{Text: "fallback", Provider: "proxy"},
|
|
})
|
|
m.SetSTTChain([]string{"elevenlabs", "proxy"})
|
|
|
|
res, err := m.Transcribe(context.Background(), STTInput{}, STTOptions{})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if res.Provider != "proxy" {
|
|
t.Errorf("expected provider 'proxy', got %q", res.Provider)
|
|
}
|
|
}
|
|
|
|
// Case 3: both fail → ErrAllSTTProvidersFailed.
|
|
func TestManager_Transcribe_AllFail(t *testing.T) {
|
|
m := newTestManager()
|
|
m.RegisterSTT(&mockSTT{name: "elevenlabs", err: errors.New("scribe error")})
|
|
m.RegisterSTT(&mockSTT{name: "proxy", err: errors.New("proxy error")})
|
|
m.SetSTTChain([]string{"elevenlabs", "proxy"})
|
|
|
|
_, err := m.Transcribe(context.Background(), STTInput{}, STTOptions{})
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if !errors.Is(err, ErrAllSTTProvidersFailed) {
|
|
t.Errorf("expected ErrAllSTTProvidersFailed, got: %v", err)
|
|
}
|
|
}
|
|
|
|
// Case 4: empty chain → error.
|
|
func TestManager_Transcribe_EmptyChain(t *testing.T) {
|
|
m := newTestManager()
|
|
m.SetSTTChain([]string{})
|
|
|
|
_, err := m.Transcribe(context.Background(), STTInput{}, STTOptions{})
|
|
if err == nil {
|
|
t.Fatal("expected error for empty chain, got nil")
|
|
}
|
|
if !errors.Is(err, ErrAllSTTProvidersFailed) {
|
|
t.Errorf("expected ErrAllSTTProvidersFailed, got: %v", err)
|
|
}
|
|
}
|
|
|
|
// Case 5: unknown provider in chain is skipped with warn; known one succeeds.
|
|
func TestManager_Transcribe_UnknownSkipped(t *testing.T) {
|
|
m := newTestManager()
|
|
m.RegisterSTT(&mockSTT{
|
|
name: "proxy",
|
|
result: &TranscriptResult{Text: "ok", Provider: "proxy"},
|
|
})
|
|
m.SetSTTChain([]string{"unknown_provider", "proxy"})
|
|
|
|
res, err := m.Transcribe(context.Background(), STTInput{}, STTOptions{})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if res.Provider != "proxy" {
|
|
t.Errorf("expected provider 'proxy', got %q", res.Provider)
|
|
}
|
|
}
|
|
|
|
// Case 6: channel override wins over tenant chain.
|
|
func TestManager_Transcribe_ChannelOverrideWins(t *testing.T) {
|
|
m := newTestManager()
|
|
|
|
// Register tenant-level provider.
|
|
m.RegisterSTT(&mockSTT{
|
|
name: "elevenlabs",
|
|
result: &TranscriptResult{Text: "tenant", Provider: "elevenlabs"},
|
|
})
|
|
m.SetSTTChain([]string{"elevenlabs"})
|
|
|
|
// Register channel-scoped proxy that wins for "telegram".
|
|
channelProxy := &mockSTT{
|
|
name: "proxy",
|
|
result: &TranscriptResult{Text: "channel-override", Provider: "proxy"},
|
|
}
|
|
m.RegisterChannelSTT("telegram", channelProxy)
|
|
|
|
ctx := WithChannel(context.Background(), "telegram")
|
|
res, err := m.Transcribe(ctx, STTInput{}, STTOptions{})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if res.Text != "channel-override" {
|
|
t.Errorf("expected channel override result, got %q", res.Text)
|
|
}
|
|
}
|