refactor transcriber factory to use model metadata
- factory now looks up Model via provider.GetModel() - switches on model.AdapterType instead of provider name - uses model.Endpoint for adapter configuration - streaming models return clear error (not yet implemented) - empty model falls back to provider default - added tests for streaming and unknown model errors
This commit is contained in:
@@ -3,6 +3,7 @@ package transcriber
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/leonardotrapani/hyprvoice/internal/provider"
|
"github.com/leonardotrapani/hyprvoice/internal/provider"
|
||||||
"github.com/leonardotrapani/hyprvoice/internal/recording"
|
"github.com/leonardotrapani/hyprvoice/internal/recording"
|
||||||
@@ -29,52 +30,84 @@ type Config struct {
|
|||||||
Keywords []string
|
Keywords []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTranscriber creates a new simple transcriber
|
// mapConfigProviderToRegistryName maps config provider names to provider registry names
|
||||||
func NewTranscriber(config Config) (Transcriber, error) {
|
// Config uses names like "groq-transcription", "groq-translation", "mistral-transcription"
|
||||||
// Create the appropriate adapter
|
// Registry uses base names like "groq", "mistral"
|
||||||
var adapter BatchAdapter
|
func mapConfigProviderToRegistryName(configProvider string) string {
|
||||||
|
switch configProvider {
|
||||||
switch config.Provider {
|
case "groq-transcription", "groq-translation":
|
||||||
case "openai":
|
return "groq"
|
||||||
if config.APIKey == "" {
|
|
||||||
return nil, fmt.Errorf("OpenAI API key required")
|
|
||||||
}
|
|
||||||
adapter = NewOpenAIAdapterFromConfig(config)
|
|
||||||
|
|
||||||
case "groq-transcription":
|
|
||||||
if config.APIKey == "" {
|
|
||||||
return nil, fmt.Errorf("Groq API key required")
|
|
||||||
}
|
|
||||||
// use consolidated OpenAI adapter with Groq endpoint
|
|
||||||
endpoint := &provider.EndpointConfig{BaseURL: "https://api.groq.com/openai"}
|
|
||||||
adapter = NewOpenAIAdapter(endpoint, config.APIKey, config.Model, config.Language, config.Keywords, "groq")
|
|
||||||
|
|
||||||
case "groq-translation":
|
|
||||||
if config.APIKey == "" {
|
|
||||||
return nil, fmt.Errorf("Groq API key required")
|
|
||||||
}
|
|
||||||
adapter = NewGroqTranslationAdapter(config)
|
|
||||||
|
|
||||||
case "mistral-transcription":
|
case "mistral-transcription":
|
||||||
if config.APIKey == "" {
|
return "mistral"
|
||||||
return nil, fmt.Errorf("Mistral API key required")
|
|
||||||
}
|
|
||||||
// use consolidated OpenAI adapter with Mistral endpoint
|
|
||||||
endpoint := &provider.EndpointConfig{BaseURL: "https://api.mistral.ai"}
|
|
||||||
adapter = NewOpenAIAdapter(endpoint, config.APIKey, config.Model, config.Language, config.Keywords, "mistral")
|
|
||||||
|
|
||||||
case "elevenlabs":
|
|
||||||
if config.APIKey == "" {
|
|
||||||
return nil, fmt.Errorf("ElevenLabs API key required")
|
|
||||||
}
|
|
||||||
adapter = NewElevenLabsAdapterFromConfig(config)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported provider: %s", config.Provider)
|
return configProvider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTranscriber creates a new transcriber based on model metadata
|
||||||
|
func NewTranscriber(config Config) (Transcriber, error) {
|
||||||
|
if config.Provider == "" {
|
||||||
|
return nil, fmt.Errorf("provider is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create simple transcriber that collects all audio
|
// special case: groq-translation uses CreateTranslation API (different from transcription)
|
||||||
transcriber := NewSimpleTranscriber(config, adapter)
|
if config.Provider == "groq-translation" {
|
||||||
|
if config.APIKey == "" {
|
||||||
|
return nil, fmt.Errorf("Groq API key required")
|
||||||
|
}
|
||||||
|
adapter := NewGroqTranslationAdapter(config)
|
||||||
|
return NewSimpleTranscriber(config, adapter), nil
|
||||||
|
}
|
||||||
|
|
||||||
return transcriber, nil
|
// map config provider name to registry provider name
|
||||||
|
registryProvider := mapConfigProviderToRegistryName(config.Provider)
|
||||||
|
|
||||||
|
// lookup provider
|
||||||
|
p := provider.GetProvider(registryProvider)
|
||||||
|
if p == nil {
|
||||||
|
return nil, fmt.Errorf("unknown provider: %s", config.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check API key requirement
|
||||||
|
if p.RequiresAPIKey() && config.APIKey == "" {
|
||||||
|
return nil, fmt.Errorf("%s API key required", strings.Title(registryProvider))
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup model from provider
|
||||||
|
model, err := provider.GetModel(registryProvider, config.Model)
|
||||||
|
if err != nil {
|
||||||
|
// if model not found, try to use default model
|
||||||
|
if config.Model == "" {
|
||||||
|
defaultModel := p.DefaultModel(provider.Transcription)
|
||||||
|
if defaultModel != "" {
|
||||||
|
model, err = provider.GetModel(registryProvider, defaultModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil || model == nil {
|
||||||
|
return nil, fmt.Errorf("model not found: %s (provider: %s)", config.Model, config.Provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check model type
|
||||||
|
if model.Type != provider.Transcription {
|
||||||
|
return nil, fmt.Errorf("model %s is not a transcription model", config.Model)
|
||||||
|
}
|
||||||
|
|
||||||
|
// streaming models not supported yet
|
||||||
|
if model.Streaming {
|
||||||
|
return nil, fmt.Errorf("streaming model %s not supported yet (coming soon)", config.Model)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create adapter based on model.AdapterType
|
||||||
|
var adapter BatchAdapter
|
||||||
|
switch model.AdapterType {
|
||||||
|
case "openai":
|
||||||
|
adapter = NewOpenAIAdapter(model.Endpoint, config.APIKey, model.ID, config.Language, config.Keywords, registryProvider)
|
||||||
|
case "elevenlabs":
|
||||||
|
adapter = NewElevenLabsAdapter(model.Endpoint, config.APIKey, model.ID, config.Language)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported adapter type: %s", model.AdapterType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewSimpleTranscriber(config, adapter), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,14 +145,34 @@ func TestNewTranscriber(t *testing.T) {
|
|||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty model",
|
name: "empty model uses default",
|
||||||
config: Config{
|
config: Config{
|
||||||
Provider: "openai",
|
Provider: "openai",
|
||||||
APIKey: "test-key",
|
APIKey: "test-key",
|
||||||
Language: "en",
|
Language: "en",
|
||||||
Model: "",
|
Model: "",
|
||||||
},
|
},
|
||||||
wantErr: false, // Model validation is not implemented in NewTranscriber
|
wantErr: false, // uses default model when empty
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "streaming model returns error",
|
||||||
|
config: Config{
|
||||||
|
Provider: "elevenlabs",
|
||||||
|
APIKey: "test-key",
|
||||||
|
Language: "en",
|
||||||
|
Model: "scribe_v1-streaming",
|
||||||
|
},
|
||||||
|
wantErr: true, // streaming not yet supported
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown model returns error",
|
||||||
|
config: Config{
|
||||||
|
Provider: "openai",
|
||||||
|
APIKey: "test-key",
|
||||||
|
Language: "en",
|
||||||
|
Model: "nonexistent-model",
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,3 +134,15 @@ Started: Sun Feb 1 12:22:47 AM CET 2026
|
|||||||
- Updated factory to use `NewElevenLabsAdapterFromConfig`
|
- Updated factory to use `NewElevenLabsAdapterFromConfig`
|
||||||
- Updated tests for new constructor signature
|
- Updated tests for new constructor signature
|
||||||
- All tests passing, typecheck passes
|
- All tests passing, typecheck passes
|
||||||
|
|
||||||
|
### Task 15: Update transcriber factory to use Model metadata
|
||||||
|
- Refactored `NewTranscriber()` to look up Model via `provider.GetModel()`
|
||||||
|
- Added `mapConfigProviderToRegistryName()` to map config provider names (e.g., "groq-transcription") to registry names (e.g., "groq")
|
||||||
|
- Factory now switches on `model.AdapterType` instead of provider name
|
||||||
|
- Special case: "groq-translation" still uses dedicated `GroqTranslationAdapter` (uses CreateTranslation API)
|
||||||
|
- For "openai" adapter type: creates `OpenAIAdapter` with model's endpoint config
|
||||||
|
- For "elevenlabs" adapter type: creates `ElevenLabsAdapter` with model's endpoint config
|
||||||
|
- Streaming models return clear error: "streaming model %s not supported yet (coming soon)"
|
||||||
|
- Empty model now uses provider's default transcription model
|
||||||
|
- Added tests for streaming model rejection and unknown model error
|
||||||
|
- All tests passing, typecheck passes
|
||||||
|
|||||||
+1
-1
@@ -373,7 +373,7 @@
|
|||||||
"Streaming models return clear error until implemented",
|
"Streaming models return clear error until implemented",
|
||||||
"Typecheck passes"
|
"Typecheck passes"
|
||||||
],
|
],
|
||||||
"passes": false
|
"passes": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Update config.ToTranscriberConfig to work with new architecture",
|
"title": "Update config.ToTranscriberConfig to work with new architecture",
|
||||||
|
|||||||
Reference in New Issue
Block a user