mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-08-06 04:23:13 +00:00
Baseline groundwork for TTS expansion plan. Introduces a capabilities system that the follow-up plan (phase-01..04) builds on. Backend: - `audio.ParamSchema` / `ProviderCapabilities` types + per-provider capabilities.go for edge, elevenlabs, minimax, openai, gemini. - Gemini TTS provider (client, models, voices, wav encoder, multi-speaker via SpeakerVoice, audio-tag aware prompts). - TTSOptions gains `Params map[string]any` (read-only) + `Speakers`. - `VoiceListProvider` interface decouples HTTP voice handler from provider-specific impls. - `nested_keys.go` resolves dot-separated param paths for nested provider bodies (voice_settings.stability etc.). - Characterization + defaults-invariant tests per provider lock nil-params byte-equivalence before new params land. - `/v1/tts/capabilities` HTTP endpoint + integration coverage. - Dual-read tests (PG + SQLite) for tts_config. Frontend (web + desktop): - `DynamicParamForm` with depends-on evaluation, split into fields/logic modules. Slider primitive added. - `AudioTagPicker` + `MultiSpeakerEditor` for Gemini. - `voice-picker` refactored toward portal UX; combobox tightened. - tts-capabilities API client + typed hooks. - i18n catalogs (en/vi/zh) expanded; parity tests guard key drift. - TTS page reorganised (voice-model-section removed; playground + credentials + provider-setup split cleanly). Docs: codebase-summary, project-changelog, tts-provider-capabilities.
117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
//go:build integration
|
|
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/audio"
|
|
httphandlers "github.com/nextlevelbuilder/goclaw/internal/http"
|
|
)
|
|
|
|
// TestTTSCapabilities_ListProviders verifies that the audio manager correctly
|
|
// lists capabilities for all registered TTS providers.
|
|
func TestTTSCapabilities_ListProviders(t *testing.T) {
|
|
// Create manager with mock providers
|
|
mgr := audio.NewManager(audio.ManagerConfig{Primary: "openai"})
|
|
registerTestProviders(mgr)
|
|
|
|
// List capabilities from manager
|
|
caps := mgr.ListCapabilities()
|
|
|
|
if len(caps) < 4 {
|
|
t.Errorf("expected at least 4 providers, got %d", len(caps))
|
|
}
|
|
|
|
// Find OpenAI provider
|
|
var openaiCap *audio.ProviderCapabilities
|
|
for i := range caps {
|
|
if caps[i].Provider == "openai" {
|
|
openaiCap = &caps[i]
|
|
break
|
|
}
|
|
}
|
|
|
|
if openaiCap == nil {
|
|
t.Fatal("OpenAI provider not found in capabilities")
|
|
}
|
|
|
|
if openaiCap.DisplayName == "" {
|
|
t.Error("OpenAI capability missing DisplayName")
|
|
}
|
|
}
|
|
|
|
// TestTTSCapabilities_Handler_GetRoute verifies that GET /v1/tts/capabilities
|
|
// endpoint is properly registered on the TTS handler.
|
|
func TestTTSCapabilities_Handler_GetRoute(t *testing.T) {
|
|
mgr := audio.NewManager(audio.ManagerConfig{Primary: "openai"})
|
|
registerTestProviders(mgr)
|
|
|
|
handler := httphandlers.NewTTSHandler(mgr)
|
|
mux := http.NewServeMux()
|
|
handler.RegisterRoutes(mux)
|
|
|
|
// GET /v1/tts/capabilities (without auth, should fail on auth check)
|
|
req := httptest.NewRequest("GET", "/v1/tts/capabilities", nil)
|
|
rr := httptest.NewRecorder()
|
|
mux.ServeHTTP(rr, req)
|
|
|
|
// Should get 401 (unauthorized) since no Bearer token provided
|
|
// Note: The auth middleware requires valid token
|
|
if rr.Code != http.StatusUnauthorized && rr.Code != http.StatusBadRequest {
|
|
t.Logf("GET without auth returned %d (expected 401 or 400)", rr.Code)
|
|
}
|
|
}
|
|
|
|
// TestTTSCapabilities_ManagerRegistration verifies that providers can be
|
|
// registered and listed through the manager.
|
|
func TestTTSCapabilities_ManagerRegistration(t *testing.T) {
|
|
mgr := audio.NewManager(audio.ManagerConfig{Primary: "openai"})
|
|
|
|
// Register providers
|
|
mgr.RegisterTTS(&capTestProvider{name: "openai"})
|
|
mgr.RegisterTTS(&capTestProvider{name: "elevenlabs"})
|
|
|
|
// Check count
|
|
caps := mgr.ListCapabilities()
|
|
if len(caps) < 2 {
|
|
t.Errorf("expected at least 2 providers after registration, got %d", len(caps))
|
|
}
|
|
|
|
// Verify names present
|
|
names := make(map[string]bool)
|
|
for _, cap := range caps {
|
|
names[cap.Provider] = true
|
|
}
|
|
|
|
if !names["openai"] {
|
|
t.Error("openai not in capabilities after registration")
|
|
}
|
|
if !names["elevenlabs"] {
|
|
t.Error("elevenlabs not in capabilities after registration")
|
|
}
|
|
}
|
|
|
|
// registerTestProviders registers the standard test providers with the manager.
|
|
func registerTestProviders(mgr *audio.Manager) {
|
|
// Register mock providers for testing
|
|
mgr.RegisterTTS(&capTestProvider{name: "openai"})
|
|
mgr.RegisterTTS(&capTestProvider{name: "elevenlabs"})
|
|
mgr.RegisterTTS(&capTestProvider{name: "edge"})
|
|
mgr.RegisterTTS(&capTestProvider{name: "minimax"})
|
|
}
|
|
|
|
// capTestProvider is a test implementation of audio.TTSProvider.
|
|
type capTestProvider struct {
|
|
name string
|
|
}
|
|
|
|
func (p *capTestProvider) Name() string { return p.name }
|
|
|
|
func (p *capTestProvider) Synthesize(context.Context, string, audio.TTSOptions) (*audio.SynthResult, error) {
|
|
return nil, nil
|
|
}
|