1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
// Package provider defines capability-specific AI provider interfaces and
// provider-neutral registries for runtime selection.
package provider
import (
"context"
"errors"
"fmt"
"strings"
"sync"
)
const (
// Gemini is the canonical provider name for Google's Gemini backend.
Gemini = "gemini"
// OpenAI is the canonical provider name for OpenAI backends.
OpenAI = "openai"
)
// TextProvider generates text from prompts.
type TextProvider interface {
Name() string
IsAvailable() error
GenerateText(ctx context.Context, prompt string) (string, error)
}
// ImageProvider generates images from prompts.
type ImageProvider interface {
Name() string
IsAvailable() error
GenerateImage(ctx context.Context, prompt string, outputFile string) error
}
// TTSProvider generates audio from text.
type TTSProvider interface {
Name() string
IsAvailable() error
GenerateAudio(ctx context.Context, text string, outputFile string) error
}
// TextConfig exposes the configured text provider name.
type TextConfig interface {
TextProviderName() string
}
// ImageConfig exposes the configured image provider name.
type ImageConfig interface {
ImageProviderName() string
}
// TTSConfig exposes the configured TTS provider name.
type TTSConfig interface {
TTSProviderName() string
}
// Factory builds a provider implementation from configuration.
type Factory[T any, C any] func(C) (T, error)
// Registry resolves provider names to factories.
type Registry[T any, C any] struct {
mu sync.RWMutex
factories map[string]Factory[T, C]
}
// NewRegistry creates an empty provider registry.
func NewRegistry[T any, C any]() *Registry[T, C] {
return &Registry[T, C]{factories: make(map[string]Factory[T, C])}
}
// NewTextRegistry creates an empty text-provider registry.
func NewTextRegistry() *Registry[TextProvider, TextConfig] {
return NewRegistry[TextProvider, TextConfig]()
}
// NewImageRegistry creates an empty image-provider registry.
func NewImageRegistry() *Registry[ImageProvider, ImageConfig] {
return NewRegistry[ImageProvider, ImageConfig]()
}
// NewTTSRegistry creates an empty text-to-speech provider registry.
func NewTTSRegistry() *Registry[TTSProvider, TTSConfig] {
return NewRegistry[TTSProvider, TTSConfig]()
}
// Register associates name with a factory. Later registrations replace earlier ones.
func (r *Registry[T, C]) Register(name string, factory Factory[T, C]) {
if r == nil || factory == nil {
return
}
normalized := NormalizeName(name)
if normalized == "" {
return
}
r.mu.Lock()
defer r.mu.Unlock()
if r.factories == nil {
r.factories = make(map[string]Factory[T, C])
}
r.factories[normalized] = factory
}
// Resolve returns the factory registered for name.
func (r *Registry[T, C]) Resolve(name string) (Factory[T, C], bool) {
if r == nil {
return nil, false
}
r.mu.RLock()
defer r.mu.RUnlock()
factory, ok := r.factories[NormalizeName(name)]
return factory, ok
}
// Has reports whether a factory is registered for name.
func (r *Registry[T, C]) Has(name string) bool {
_, ok := r.Resolve(name)
return ok
}
// New constructs a provider for name using cfg.
func (r *Registry[T, C]) New(name string, cfg C) (T, error) {
var zero T
factory, ok := r.Resolve(name)
if !ok {
return zero, fmt.Errorf("%w: %s", ErrUnknownProvider, name)
}
return factory(cfg)
}
// NewFromConfig resolves the provider name from cfg and constructs it.
func (r *Registry[T, C]) NewFromConfig(cfg C, providerName func(C) string) (T, error) {
var zero T
if providerName == nil {
return zero, errors.New("provider name resolver is required")
}
return r.New(providerName(cfg), cfg)
}
// NormalizeName returns a canonical lower-case provider name.
func NormalizeName(name string) string {
return strings.ToLower(strings.TrimSpace(name))
}
// IsKnownName reports whether the name matches a supported provider family.
func IsKnownName(name string) bool {
switch NormalizeName(name) {
case Gemini, OpenAI:
return true
default:
return false
}
}
// ErrUnknownProvider indicates that a provider name does not map to a known backend.
var ErrUnknownProvider = errors.New("unknown provider")
|