add DocsURL field to Model struct for language support documentation

This commit is contained in:
leonardotrapani
2026-02-01 13:31:53 +01:00
parent 55257db725
commit 811ca71c08
10 changed files with 79 additions and 1 deletions
+6
View File
@@ -37,6 +37,8 @@ func (p *DeepgramProvider) Models() []Model {
"ro", "ru", "sk", "es", "sv", "th", "tr", "uk", "vi", "ro", "ru", "sk", "es", "sv", "th", "tr", "uk", "vi",
} }
docsURL := "https://developers.deepgram.com/docs/language"
return []Model{ return []Model{
{ {
ID: "nova-3", ID: "nova-3",
@@ -48,6 +50,7 @@ func (p *DeepgramProvider) Models() []Model {
AdapterType: "deepgram", AdapterType: "deepgram",
SupportedLanguages: nova3Langs, SupportedLanguages: nova3Langs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
DocsURL: docsURL,
}, },
{ {
ID: "nova-3-general", ID: "nova-3-general",
@@ -59,6 +62,7 @@ func (p *DeepgramProvider) Models() []Model {
AdapterType: "deepgram", AdapterType: "deepgram",
SupportedLanguages: nova3Langs, SupportedLanguages: nova3Langs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
DocsURL: docsURL,
}, },
{ {
ID: "nova-2", ID: "nova-2",
@@ -70,6 +74,7 @@ func (p *DeepgramProvider) Models() []Model {
AdapterType: "deepgram", AdapterType: "deepgram",
SupportedLanguages: nova2Langs, SupportedLanguages: nova2Langs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
DocsURL: docsURL,
}, },
{ {
ID: "nova-2-general", ID: "nova-2-general",
@@ -81,6 +86,7 @@ func (p *DeepgramProvider) Models() []Model {
AdapterType: "deepgram", AdapterType: "deepgram",
SupportedLanguages: nova2Langs, SupportedLanguages: nova2Langs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
DocsURL: docsURL,
}, },
} }
} }
+5
View File
@@ -26,6 +26,7 @@ func (p *ElevenLabsProvider) Models() []Model {
// ElevenLabs Scribe supports 90+ languages, including all 57 from our master list // ElevenLabs Scribe supports 90+ languages, including all 57 from our master list
// See: https://elevenlabs.io/speech-to-text // See: https://elevenlabs.io/speech-to-text
allLangs := language.AllLanguageCodes() allLangs := language.AllLanguageCodes()
docsURL := "https://elevenlabs.io/docs/capabilities/speech-to-text#supported-languages"
return []Model{ return []Model{
// batch models // batch models
@@ -39,6 +40,7 @@ func (p *ElevenLabsProvider) Models() []Model {
AdapterType: "elevenlabs", AdapterType: "elevenlabs",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.elevenlabs.io", Path: "/v1/speech-to-text"}, Endpoint: &EndpointConfig{BaseURL: "https://api.elevenlabs.io", Path: "/v1/speech-to-text"},
DocsURL: docsURL,
}, },
{ {
ID: "scribe_v2", ID: "scribe_v2",
@@ -50,6 +52,7 @@ func (p *ElevenLabsProvider) Models() []Model {
AdapterType: "elevenlabs", AdapterType: "elevenlabs",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.elevenlabs.io", Path: "/v1/speech-to-text"}, Endpoint: &EndpointConfig{BaseURL: "https://api.elevenlabs.io", Path: "/v1/speech-to-text"},
DocsURL: docsURL,
}, },
// streaming models // streaming models
{ {
@@ -62,6 +65,7 @@ func (p *ElevenLabsProvider) Models() []Model {
AdapterType: "elevenlabs-streaming", AdapterType: "elevenlabs-streaming",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.elevenlabs.io", Path: "/v1/speech-to-text/realtime"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.elevenlabs.io", Path: "/v1/speech-to-text/realtime"},
DocsURL: docsURL,
}, },
{ {
ID: "scribe_v2-streaming", ID: "scribe_v2-streaming",
@@ -73,6 +77,7 @@ func (p *ElevenLabsProvider) Models() []Model {
AdapterType: "elevenlabs-streaming", AdapterType: "elevenlabs-streaming",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.elevenlabs.io", Path: "/v1/speech-to-text/realtime"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.elevenlabs.io", Path: "/v1/speech-to-text/realtime"},
DocsURL: docsURL,
}, },
} }
} }
+4
View File
@@ -27,6 +27,7 @@ func (p *GroqProvider) IsLocal() bool {
func (p *GroqProvider) Models() []Model { func (p *GroqProvider) Models() []Model {
allLangs := language.AllLanguageCodes() allLangs := language.AllLanguageCodes()
docsURL := "https://console.groq.com/docs/speech-to-text#supported-languages"
return []Model{ return []Model{
// transcription models // transcription models
@@ -40,6 +41,7 @@ func (p *GroqProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.groq.com/openai", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.groq.com/openai", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
{ {
ID: "whisper-large-v3-turbo", ID: "whisper-large-v3-turbo",
@@ -51,6 +53,7 @@ func (p *GroqProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.groq.com/openai", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.groq.com/openai", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
{ {
ID: "distil-whisper-large-v3-en", ID: "distil-whisper-large-v3-en",
@@ -62,6 +65,7 @@ func (p *GroqProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: []string{"en"}, SupportedLanguages: []string{"en"},
Endpoint: &EndpointConfig{BaseURL: "https://api.groq.com/openai", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.groq.com/openai", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
// LLM models // LLM models
{ {
+3
View File
@@ -24,6 +24,7 @@ func (p *MistralProvider) IsLocal() bool {
func (p *MistralProvider) Models() []Model { func (p *MistralProvider) Models() []Model {
allLangs := language.AllLanguageCodes() allLangs := language.AllLanguageCodes()
docsURL := "https://docs.mistral.ai/capabilities/speech/"
return []Model{ return []Model{
{ {
@@ -36,6 +37,7 @@ func (p *MistralProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.mistral.ai", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.mistral.ai", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
{ {
ID: "voxtral-mini-2507", ID: "voxtral-mini-2507",
@@ -47,6 +49,7 @@ func (p *MistralProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.mistral.ai", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.mistral.ai", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
} }
} }
+1
View File
@@ -22,6 +22,7 @@ type Model struct {
SupportedLanguages []string // explicit list of supported language codes SupportedLanguages []string // explicit list of supported language codes
Endpoint *EndpointConfig // nil for local models Endpoint *EndpointConfig // nil for local models
LocalInfo *LocalModelInfo // nil for cloud models LocalInfo *LocalModelInfo // nil for cloud models
DocsURL string // URL to provider's language support documentation
} }
// EndpointConfig holds HTTP/WebSocket endpoint configuration // EndpointConfig holds HTTP/WebSocket endpoint configuration
+38
View File
@@ -296,6 +296,7 @@ func TestModel_AllFields(t *testing.T) {
Size: "100MB", Size: "100MB",
DownloadURL: "https://example.com/test.bin", DownloadURL: "https://example.com/test.bin",
}, },
DocsURL: "https://example.com/docs/languages",
} }
if model.ID != "test-model" { if model.ID != "test-model" {
@@ -328,4 +329,41 @@ func TestModel_AllFields(t *testing.T) {
if model.LocalInfo == nil { if model.LocalInfo == nil {
t.Error("LocalInfo should not be nil") t.Error("LocalInfo should not be nil")
} }
if model.DocsURL != "https://example.com/docs/languages" {
t.Errorf("DocsURL = %q, want 'https://example.com/docs/languages'", model.DocsURL)
}
}
func TestAllTranscriptionModels_HaveDocsURL(t *testing.T) {
// verify all transcription models have DocsURL set
providers := []string{"openai", "groq", "mistral", "elevenlabs", "deepgram", "whisper-cpp"}
expectedDocsURLs := map[string]string{
"openai": "https://platform.openai.com/docs/guides/speech-to-text#supported-languages",
"groq": "https://console.groq.com/docs/speech-to-text#supported-languages",
"mistral": "https://docs.mistral.ai/capabilities/speech/",
"elevenlabs": "https://elevenlabs.io/docs/capabilities/speech-to-text#supported-languages",
"deepgram": "https://developers.deepgram.com/docs/language",
"whisper-cpp": "https://github.com/openai/whisper#available-models-and-languages",
}
for _, pName := range providers {
p := GetProvider(pName)
if p == nil {
t.Errorf("GetProvider(%q) returned nil", pName)
continue
}
expectedURL := expectedDocsURLs[pName]
for _, m := range p.Models() {
if m.Type != Transcription {
continue
}
if m.DocsURL == "" {
t.Errorf("%s/%s: DocsURL is empty", pName, m.ID)
} else if m.DocsURL != expectedURL {
t.Errorf("%s/%s: DocsURL = %q, want %q", pName, m.ID, m.DocsURL, expectedURL)
}
}
}
} }
+6
View File
@@ -28,6 +28,8 @@ func (p *OpenAIProvider) IsLocal() bool {
func (p *OpenAIProvider) Models() []Model { func (p *OpenAIProvider) Models() []Model {
allLangs := language.AllLanguageCodes() allLangs := language.AllLanguageCodes()
docsURL := "https://platform.openai.com/docs/guides/speech-to-text#supported-languages"
return []Model{ return []Model{
// transcription models // transcription models
{ {
@@ -40,6 +42,7 @@ func (p *OpenAIProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.openai.com", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.openai.com", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
{ {
ID: "gpt-4o-transcribe", ID: "gpt-4o-transcribe",
@@ -51,6 +54,7 @@ func (p *OpenAIProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.openai.com", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.openai.com", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
{ {
ID: "gpt-4o-mini-transcribe", ID: "gpt-4o-mini-transcribe",
@@ -62,6 +66,7 @@ func (p *OpenAIProvider) Models() []Model {
AdapterType: "openai", AdapterType: "openai",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "https://api.openai.com", Path: "/v1/audio/transcriptions"}, Endpoint: &EndpointConfig{BaseURL: "https://api.openai.com", Path: "/v1/audio/transcriptions"},
DocsURL: docsURL,
}, },
{ {
ID: "gpt-4o-realtime-preview", ID: "gpt-4o-realtime-preview",
@@ -73,6 +78,7 @@ func (p *OpenAIProvider) Models() []Model {
AdapterType: "openai-realtime", AdapterType: "openai-realtime",
SupportedLanguages: allLangs, SupportedLanguages: allLangs,
Endpoint: &EndpointConfig{BaseURL: "wss://api.openai.com", Path: "/v1/realtime"}, Endpoint: &EndpointConfig{BaseURL: "wss://api.openai.com", Path: "/v1/realtime"},
DocsURL: docsURL,
}, },
// LLM models // LLM models
{ {
+2
View File
@@ -27,6 +27,7 @@ func (p *WhisperCppProvider) IsLocal() bool {
func (p *WhisperCppProvider) Models() []Model { func (p *WhisperCppProvider) Models() []Model {
allLangs := language.AllLanguageCodes() allLangs := language.AllLanguageCodes()
englishOnly := []string{"en"} englishOnly := []string{"en"}
docsURL := "https://github.com/openai/whisper#available-models-and-languages"
whisperModels := whisper.ListModels() whisperModels := whisper.ListModels()
result := make([]Model, 0, len(whisperModels)) result := make([]Model, 0, len(whisperModels))
@@ -54,6 +55,7 @@ func (p *WhisperCppProvider) Models() []Model {
Size: wm.Size, Size: wm.Size,
DownloadURL: whisper.GetDownloadURL(wm.ID), DownloadURL: whisper.GetDownloadURL(wm.ID),
}, },
DocsURL: docsURL,
}) })
} }
+13
View File
@@ -571,4 +571,17 @@ Started: Sun Feb 1 12:22:47 AM CET 2026
- Default selection skips headers to find first real model - Default selection skips headers to find first real model
- Providers with only one type (e.g., Groq=batch, Deepgram=streaming) show no headers - Providers with only one type (e.g., Groq=batch, Deepgram=streaming) show no headers
- Added unit tests: GroupsModels, NoHeadersForSingleType, OpenAI_GroupsCorrectly - Added unit tests: GroupsModels, NoHeadersForSingleType, OpenAI_GroupsCorrectly
- All tests passing, typecheck passes
### Task 9: Add docs URLs to provider models
- Added `DocsURL string` field to Model struct in internal/provider/model.go
- Updated all 6 providers to set DocsURL for transcription models:
- OpenAI: https://platform.openai.com/docs/guides/speech-to-text#supported-languages
- Groq: https://console.groq.com/docs/speech-to-text#supported-languages
- Mistral: https://docs.mistral.ai/capabilities/speech/
- ElevenLabs: https://elevenlabs.io/docs/capabilities/speech-to-text#supported-languages
- Deepgram: https://developers.deepgram.com/docs/language
- whisper-cpp: https://github.com/openai/whisper#available-models-and-languages
- LLM models don't have DocsURL (not needed - no language restrictions)
- Added TestAllTranscriptionModels_HaveDocsURL test verifying all transcription models have correct URLs
- All tests passing, typecheck passes - All tests passing, typecheck passes
+1 -1
View File
@@ -150,7 +150,7 @@
"URLs point to correct language support documentation", "URLs point to correct language support documentation",
"Typecheck passes" "Typecheck passes"
], ],
"passes": false "passes": true
}, },
{ {
"title": "Improve language-model compatibility error messages", "title": "Improve language-model compatibility error messages",