feat: auto-create search/tts providers at startup with enable toggle

- Add `enable` column (default false) to search_providers and tts_providers tables
- Auto-create default entries for all provider types on startup (disabled by default)
- Add enable/disable Switch toggle in frontend for both search and TTS providers
- Show green status dot in sidebar for enabled providers, sort enabled first
- Filter bot settings dropdowns to only show enabled providers
This commit is contained in:
Acbox
2026-03-28 23:47:09 +08:00
parent c0057b5c54
commit 90ac222bc9
25 changed files with 420 additions and 63 deletions
+58
View File
@@ -405,6 +405,7 @@ func (s *Service) Create(ctx context.Context, req CreateRequest) (GetResponse, e
Name: strings.TrimSpace(req.Name),
Provider: string(req.Provider),
Config: configJSON,
Enable: false,
})
if err != nil {
return GetResponse{}, fmt.Errorf("create search provider: %w", err)
@@ -481,11 +482,16 @@ func (s *Service) Update(ctx context.Context, id string, req UpdateRequest) (Get
}
config = configJSON
}
enable := current.Enable
if req.Enable != nil {
enable = *req.Enable
}
updated, err := s.queries.UpdateSearchProvider(ctx, sqlc.UpdateSearchProviderParams{
ID: pgID,
Name: name,
Provider: provider,
Config: config,
Enable: enable,
})
if err != nil {
return GetResponse{}, fmt.Errorf("update search provider: %w", err)
@@ -513,11 +519,63 @@ func (s *Service) toGetResponse(row sqlc.SearchProvider) GetResponse {
Name: row.Name,
Provider: row.Provider,
Config: cfg,
Enable: row.Enable,
CreatedAt: row.CreatedAt.Time,
UpdatedAt: row.UpdatedAt.Time,
}
}
var defaultProviders = []struct {
Name ProviderName
DisplayName string
}{
{ProviderBrave, "Brave"},
{ProviderBing, "Bing"},
{ProviderGoogle, "Google"},
{ProviderTavily, "Tavily"},
{ProviderSogou, "Sogou"},
{ProviderSerper, "Serper"},
{ProviderSearXNG, "SearXNG"},
{ProviderJina, "Jina"},
{ProviderExa, "Exa"},
{ProviderBocha, "Bocha"},
{ProviderDuckDuckGo, "DuckDuckGo"},
{ProviderYandex, "Yandex"},
}
func (s *Service) EnsureDefaults(ctx context.Context) error {
rows, err := s.queries.ListSearchProviders(ctx)
if err != nil {
return fmt.Errorf("list search providers: %w", err)
}
existing := make(map[string]struct{}, len(rows))
for _, row := range rows {
existing[row.Provider] = struct{}{}
}
for _, dp := range defaultProviders {
if _, ok := existing[string(dp.Name)]; ok {
continue
}
_, err := s.queries.CreateSearchProvider(ctx, sqlc.CreateSearchProviderParams{
Name: dp.DisplayName,
Provider: string(dp.Name),
Config: []byte("{}"),
Enable: false,
})
if err != nil {
s.logger.Warn("failed to create default search provider",
slog.String("provider", string(dp.Name)),
slog.Any("error", err),
)
continue
}
s.logger.Info("created default search provider", slog.String("provider", string(dp.Name)))
}
return nil
}
func isValidProviderName(name ProviderName) bool {
switch name {
case ProviderBrave, ProviderBing, ProviderGoogle,
+2
View File
@@ -48,6 +48,7 @@ type UpdateRequest struct {
Name *string `json:"name,omitempty"`
Provider *ProviderName `json:"provider,omitempty"`
Config map[string]any `json:"config,omitempty"`
Enable *bool `json:"enable,omitempty"`
}
type GetResponse struct {
@@ -55,6 +56,7 @@ type GetResponse struct {
Name string `json:"name"`
Provider string `json:"provider"`
Config map[string]any `json:"config,omitempty"`
Enable bool `json:"enable"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}