add runtime language-model compatibility check with fallback to auto-detect
This commit is contained in:
@@ -3,9 +3,12 @@ package transcriber
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leonardotrapani/hyprvoice/internal/language"
|
||||||
"github.com/leonardotrapani/hyprvoice/internal/models/whisper"
|
"github.com/leonardotrapani/hyprvoice/internal/models/whisper"
|
||||||
|
"github.com/leonardotrapani/hyprvoice/internal/notify"
|
||||||
"github.com/leonardotrapani/hyprvoice/internal/provider"
|
"github.com/leonardotrapani/hyprvoice/internal/provider"
|
||||||
"github.com/leonardotrapani/hyprvoice/internal/recording"
|
"github.com/leonardotrapani/hyprvoice/internal/recording"
|
||||||
)
|
)
|
||||||
@@ -95,6 +98,20 @@ func NewTranscriber(config Config) (Transcriber, error) {
|
|||||||
return nil, fmt.Errorf("model %s is not a transcription model", config.Model)
|
return nil, fmt.Errorf("model %s is not a transcription model", config.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runtime language-model compatibility check with fallback
|
||||||
|
// primary validation happens at config time (hard error), this is a safety net
|
||||||
|
if config.Language != "" && !model.SupportsLanguage(config.Language) {
|
||||||
|
langName := language.FromCode(config.Language).Name
|
||||||
|
log.Printf("warning: model %s does not support language %s, falling back to auto-detect", model.ID, langName)
|
||||||
|
|
||||||
|
// send desktop notification to alert user
|
||||||
|
notifier := notify.NewDesktop(nil)
|
||||||
|
notifier.Error(fmt.Sprintf("Model %s does not support %s. Using auto-detect.", model.Name, langName))
|
||||||
|
|
||||||
|
// override language to auto for this session
|
||||||
|
config.Language = ""
|
||||||
|
}
|
||||||
|
|
||||||
// streaming models use StreamingTranscriber
|
// streaming models use StreamingTranscriber
|
||||||
if model.Streaming {
|
if model.Streaming {
|
||||||
var streamingAdapter StreamingAdapter
|
var streamingAdapter StreamingAdapter
|
||||||
|
|||||||
@@ -994,3 +994,85 @@ func TestStreamingTranscriber_GetFinalTranscriptionSafe(t *testing.T) {
|
|||||||
t.Errorf("Stop() error = %v", err)
|
t.Errorf("Stop() error = %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewTranscriber_LanguageFallback(t *testing.T) {
|
||||||
|
// test that incompatible language falls back to auto-detect (no error)
|
||||||
|
// distil-whisper-large-v3-en only supports English
|
||||||
|
config := Config{
|
||||||
|
Provider: "groq-transcription",
|
||||||
|
APIKey: "test-key",
|
||||||
|
Language: "es", // Spanish not supported by English-only model
|
||||||
|
Model: "distil-whisper-large-v3-en",
|
||||||
|
}
|
||||||
|
|
||||||
|
// should succeed (fallback to auto), not error
|
||||||
|
transcriber, err := NewTranscriber(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewTranscriber() should fall back to auto, got error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if transcriber == nil {
|
||||||
|
t.Errorf("NewTranscriber() returned nil transcriber")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewTranscriber_AutoLanguageNoFallback(t *testing.T) {
|
||||||
|
// test that auto language never triggers warning/fallback
|
||||||
|
config := Config{
|
||||||
|
Provider: "groq-transcription",
|
||||||
|
APIKey: "test-key",
|
||||||
|
Language: "", // auto
|
||||||
|
Model: "distil-whisper-large-v3-en",
|
||||||
|
}
|
||||||
|
|
||||||
|
transcriber, err := NewTranscriber(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewTranscriber() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if transcriber == nil {
|
||||||
|
t.Errorf("NewTranscriber() returned nil transcriber")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewTranscriber_CompatibleLanguageNoFallback(t *testing.T) {
|
||||||
|
// test that compatible language works normally
|
||||||
|
config := Config{
|
||||||
|
Provider: "groq-transcription",
|
||||||
|
APIKey: "test-key",
|
||||||
|
Language: "en", // English supported by English-only model
|
||||||
|
Model: "distil-whisper-large-v3-en",
|
||||||
|
}
|
||||||
|
|
||||||
|
transcriber, err := NewTranscriber(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewTranscriber() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if transcriber == nil {
|
||||||
|
t.Errorf("NewTranscriber() returned nil transcriber")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewTranscriber_MultilingualModelAllLanguages(t *testing.T) {
|
||||||
|
// test that multilingual model accepts any language without fallback
|
||||||
|
config := Config{
|
||||||
|
Provider: "groq-transcription",
|
||||||
|
APIKey: "test-key",
|
||||||
|
Language: "es", // Spanish
|
||||||
|
Model: "whisper-large-v3", // multilingual
|
||||||
|
}
|
||||||
|
|
||||||
|
transcriber, err := NewTranscriber(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewTranscriber() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if transcriber == nil {
|
||||||
|
t.Errorf("NewTranscriber() returned nil transcriber")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -459,3 +459,13 @@ Started: Sun Feb 1 12:22:47 AM CET 2026
|
|||||||
- Removed old hardcoded `isValidLanguageCode()` function
|
- Removed old hardcoded `isValidLanguageCode()` function
|
||||||
- Updated tests: replaced TestIsValidLanguageCode with TestValidateModelLanguageCompatibility
|
- Updated tests: replaced TestIsValidLanguageCode with TestValidateModelLanguageCompatibility
|
||||||
- All tests passing, typecheck passes
|
- All tests passing, typecheck passes
|
||||||
|
|
||||||
|
### Task 42: Add runtime language-model compatibility check with fallback
|
||||||
|
- Updated `internal/transcriber/transcriber.go` NewTranscriber()
|
||||||
|
- Added runtime check after model lookup: `if config.Language != "" && !model.SupportsLanguage(config.Language)`
|
||||||
|
- Logs warning with model ID and language name
|
||||||
|
- Sends desktop notification via `notify.NewDesktop(nil).Error(...)` alerting user of fallback
|
||||||
|
- Overrides `config.Language = ""` (auto) for this transcription session
|
||||||
|
- This is a safety net for manually-edited configs; primary validation is at config-time (hard error)
|
||||||
|
- Added 4 tests: LanguageFallback, AutoLanguageNoFallback, CompatibleLanguageNoFallback, MultilingualModelAllLanguages
|
||||||
|
- All tests passing with -race flag, typecheck passes
|
||||||
+1
-1
@@ -992,7 +992,7 @@
|
|||||||
"NewTranscriber with compatible language works normally",
|
"NewTranscriber with compatible language works normally",
|
||||||
"Typecheck passes"
|
"Typecheck passes"
|
||||||
],
|
],
|
||||||
"passes": false
|
"passes": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Add DEEPGRAM_API_KEY env var support",
|
"title": "Add DEEPGRAM_API_KEY env var support",
|
||||||
|
|||||||
Reference in New Issue
Block a user