add deepgram provider with nova-3 and nova-2 streaming models
This commit is contained in:
@@ -0,0 +1,94 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
// DeepgramProvider implements Provider for Deepgram transcription services
|
||||||
|
type DeepgramProvider struct{}
|
||||||
|
|
||||||
|
func (p *DeepgramProvider) Name() string {
|
||||||
|
return "deepgram"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DeepgramProvider) RequiresAPIKey() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DeepgramProvider) ValidateAPIKey(key string) bool {
|
||||||
|
// Deepgram API keys are alphanumeric, just check non-empty
|
||||||
|
return len(key) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DeepgramProvider) IsLocal() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DeepgramProvider) Models() []Model {
|
||||||
|
// Nova-3 language support - maps to our 57 language list
|
||||||
|
// from https://developers.deepgram.com/docs/models-languages-overview
|
||||||
|
nova3Langs := []string{
|
||||||
|
"ar", "be", "bs", "bg", "ca", "hr", "cs", "da", "nl", "en", "et", "fi",
|
||||||
|
"fr", "de", "el", "hi", "hu", "id", "it", "ja", "kn", "ko", "lv", "lt",
|
||||||
|
"mk", "ms", "mr", "no", "pl", "pt", "ro", "ru", "sr", "sk", "sl", "es",
|
||||||
|
"sv", "tl", "ta", "tr", "uk", "vi",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nova-2 language support - subset of nova-3
|
||||||
|
nova2Langs := []string{
|
||||||
|
"bg", "ca", "zh", "cs", "da", "nl", "en", "et", "fi", "fr", "de", "el",
|
||||||
|
"hi", "hu", "id", "it", "ja", "ko", "lv", "lt", "ms", "no", "pl", "pt",
|
||||||
|
"ro", "ru", "sk", "es", "sv", "th", "tr", "uk", "vi",
|
||||||
|
}
|
||||||
|
|
||||||
|
return []Model{
|
||||||
|
{
|
||||||
|
ID: "nova-3",
|
||||||
|
Name: "Nova-3",
|
||||||
|
Description: "Best accuracy, 40+ languages, real-time",
|
||||||
|
Type: Transcription,
|
||||||
|
Streaming: true,
|
||||||
|
Local: false,
|
||||||
|
AdapterType: "deepgram",
|
||||||
|
SupportedLanguages: nova3Langs,
|
||||||
|
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nova-3-general",
|
||||||
|
Name: "Nova-3 General",
|
||||||
|
Description: "General purpose, same as nova-3",
|
||||||
|
Type: Transcription,
|
||||||
|
Streaming: true,
|
||||||
|
Local: false,
|
||||||
|
AdapterType: "deepgram",
|
||||||
|
SupportedLanguages: nova3Langs,
|
||||||
|
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nova-2",
|
||||||
|
Name: "Nova-2",
|
||||||
|
Description: "Fast, 30+ languages, filler words",
|
||||||
|
Type: Transcription,
|
||||||
|
Streaming: true,
|
||||||
|
Local: false,
|
||||||
|
AdapterType: "deepgram",
|
||||||
|
SupportedLanguages: nova2Langs,
|
||||||
|
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nova-2-general",
|
||||||
|
Name: "Nova-2 General",
|
||||||
|
Description: "General purpose, same as nova-2",
|
||||||
|
Type: Transcription,
|
||||||
|
Streaming: true,
|
||||||
|
Local: false,
|
||||||
|
AdapterType: "deepgram",
|
||||||
|
SupportedLanguages: nova2Langs,
|
||||||
|
Endpoint: &EndpointConfig{BaseURL: "wss://api.deepgram.com", Path: "/v1/listen"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DeepgramProvider) DefaultModel(t ModelType) string {
|
||||||
|
switch t {
|
||||||
|
case Transcription:
|
||||||
|
return "nova-3"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDeepgramProvider(t *testing.T) {
|
||||||
|
p := GetProvider("deepgram")
|
||||||
|
if p == nil {
|
||||||
|
t.Fatal("deepgram provider not registered")
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Name() != "deepgram" {
|
||||||
|
t.Errorf("Name() = %q, want %q", p.Name(), "deepgram")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.RequiresAPIKey() {
|
||||||
|
t.Error("RequiresAPIKey() should return true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.IsLocal() {
|
||||||
|
t.Error("IsLocal() should return false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeepgramProvider_Models(t *testing.T) {
|
||||||
|
p := &DeepgramProvider{}
|
||||||
|
models := p.Models()
|
||||||
|
|
||||||
|
if len(models) != 4 {
|
||||||
|
t.Errorf("Models() returned %d models, want 4", len(models))
|
||||||
|
}
|
||||||
|
|
||||||
|
// all models should be streaming
|
||||||
|
for _, m := range models {
|
||||||
|
if !m.Streaming {
|
||||||
|
t.Errorf("model %s should be streaming", m.ID)
|
||||||
|
}
|
||||||
|
if m.AdapterType != "deepgram" {
|
||||||
|
t.Errorf("model %s has AdapterType %q, want 'deepgram'", m.ID, m.AdapterType)
|
||||||
|
}
|
||||||
|
if m.Local {
|
||||||
|
t.Errorf("model %s should not be local", m.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeepgramProvider_Nova3Languages(t *testing.T) {
|
||||||
|
p := &DeepgramProvider{}
|
||||||
|
models := p.Models()
|
||||||
|
|
||||||
|
var nova3 *Model
|
||||||
|
for i := range models {
|
||||||
|
if models[i].ID == "nova-3" {
|
||||||
|
nova3 = &models[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nova3 == nil {
|
||||||
|
t.Fatal("nova-3 model not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nova-3 should support many languages from our list
|
||||||
|
supportedTests := []struct {
|
||||||
|
code string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"en", true},
|
||||||
|
{"es", true},
|
||||||
|
{"fr", true},
|
||||||
|
{"de", true},
|
||||||
|
{"ja", true},
|
||||||
|
{"", true}, // auto always supported
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range supportedTests {
|
||||||
|
got := nova3.SupportsLanguage(tt.code)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("nova-3.SupportsLanguage(%q) = %v, want %v", tt.code, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeepgramProvider_DefaultModel(t *testing.T) {
|
||||||
|
p := &DeepgramProvider{}
|
||||||
|
|
||||||
|
if got := p.DefaultModel(Transcription); got != "nova-3" {
|
||||||
|
t.Errorf("DefaultModel(Transcription) = %q, want 'nova-3'", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := p.DefaultModel(LLM); got != "" {
|
||||||
|
t.Errorf("DefaultModel(LLM) = %q, want empty (no LLM support)", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeepgramProvider_Endpoint(t *testing.T) {
|
||||||
|
p := &DeepgramProvider{}
|
||||||
|
models := p.Models()
|
||||||
|
|
||||||
|
for _, m := range models {
|
||||||
|
if m.Endpoint == nil {
|
||||||
|
t.Errorf("model %s has nil Endpoint", m.ID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m.Endpoint.BaseURL != "wss://api.deepgram.com" {
|
||||||
|
t.Errorf("model %s has BaseURL %q, want 'wss://api.deepgram.com'", m.ID, m.Endpoint.BaseURL)
|
||||||
|
}
|
||||||
|
if m.Endpoint.Path != "/v1/listen" {
|
||||||
|
t.Errorf("model %s has Path %q, want '/v1/listen'", m.ID, m.Endpoint.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ func init() {
|
|||||||
Register(&MistralProvider{})
|
Register(&MistralProvider{})
|
||||||
Register(&ElevenLabsProvider{})
|
Register(&ElevenLabsProvider{})
|
||||||
Register(&WhisperCppProvider{})
|
Register(&WhisperCppProvider{})
|
||||||
|
Register(&DeepgramProvider{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register adds a provider to the registry
|
// Register adds a provider to the registry
|
||||||
|
|||||||
@@ -335,3 +335,15 @@ Started: Sun Feb 1 12:22:47 AM CET 2026
|
|||||||
- After max retries exhausted, sends final error and closes channel
|
- After max retries exhausted, sends final error and closes channel
|
||||||
- Added tests: ReconnectOnReadError, ReconnectNotifiesClient, MaxRetriesExhausted, ReconnectExponentialBackoff
|
- Added tests: ReconnectOnReadError, ReconnectNotifiesClient, MaxRetriesExhausted, ReconnectExponentialBackoff
|
||||||
- All tests passing with -race flag, typecheck passes
|
- All tests passing with -race flag, typecheck passes
|
||||||
|
|
||||||
|
### Task 33: Create Deepgram Provider
|
||||||
|
- Created `internal/provider/deepgram.go` implementing Provider interface
|
||||||
|
- Researched Deepgram docs: Nova-3 and Nova-2 are main models, both streaming-only
|
||||||
|
- Models: nova-3, nova-3-general, nova-2, nova-2-general (all Streaming=true)
|
||||||
|
- Nova-3 supports 42 languages from our list (ar, be, bs, bg, ca, hr, cs, da, nl, en, et, fi, fr, de, el, hi, hu, id, it, ja, kn, ko, lv, lt, mk, ms, mr, no, pl, pt, ro, ru, sr, sk, sl, es, sv, tl, ta, tr, uk, vi)
|
||||||
|
- Nova-2 supports 33 languages (subset of nova-3)
|
||||||
|
- All models have AdapterType='deepgram', Endpoint.BaseURL='wss://api.deepgram.com'
|
||||||
|
- DefaultModel(Transcription) returns 'nova-3'
|
||||||
|
- Registered in provider.init()
|
||||||
|
- Comprehensive test file created: deepgram_test.go
|
||||||
|
- All tests passing, typecheck passes
|
||||||
+1
-1
@@ -783,7 +783,7 @@
|
|||||||
"RequiresAPIKey() returns true",
|
"RequiresAPIKey() returns true",
|
||||||
"Typecheck passes"
|
"Typecheck passes"
|
||||||
],
|
],
|
||||||
"passes": false
|
"passes": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Create Deepgram StreamingAdapter",
|
"title": "Create Deepgram StreamingAdapter",
|
||||||
|
|||||||
Reference in New Issue
Block a user