package websearch import ( "fmt" "strings" ) type ProviderType string const ( ProviderBrave ProviderType = "brave" ProviderBing ProviderType = "bing" ProviderDuckDuckGo ProviderType = "duckduckgo" ProviderSearXNG ProviderType = "searxng" ProviderCustom ProviderType = "custom" ) type Provider struct { ID string `json:"id"` Name string `json:"name"` Type ProviderType `json:"type"` APIKey string `json:"api_key,omitempty"` BaseURL string `json:"base_url,omitempty"` QueryParam string `json:"query_param,omitempty"` AuthHeader string `json:"auth_header,omitempty"` ResultsPath string `json:"results_path,omitempty"` TitleField string `json:"title_field,omitempty"` URLField string `json:"url_field,omitempty"` DescField string `json:"description_field,omitempty"` } type Settings struct { DefaultProviderID string `json:"default_provider_id"` Providers []Provider `json:"providers"` } func ResolveProvider(settings Settings) (Provider, error) { providerID := strings.TrimSpace(settings.DefaultProviderID) if providerID != "" { for _, p := range settings.Providers { if p.ID == providerID && providerConfigured(p) { return p, nil } } } for _, p := range settings.Providers { if providerConfigured(p) { return p, nil } } return Provider{}, fmt.Errorf("no search provider configured") } func providerConfigured(p Provider) bool { switch p.Type { case ProviderBrave, ProviderBing: return strings.TrimSpace(p.APIKey) != "" case ProviderDuckDuckGo: return true case ProviderSearXNG: return strings.TrimSpace(p.BaseURL) != "" case ProviderCustom: return strings.TrimSpace(p.BaseURL) != "" && strings.TrimSpace(p.ResultsPath) != "" && strings.TrimSpace(p.TitleField) != "" && strings.TrimSpace(p.URLField) != "" default: return strings.TrimSpace(string(p.Type)) != "" && strings.TrimSpace(p.APIKey) != "" } } func queryParamName(provider Provider) string { if name := strings.TrimSpace(provider.QueryParam); name != "" { return name } return "q" }