This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/tools/search/provider.go
2026-02-25 23:56:27 +00:00

104 lines
2.6 KiB
Go

package search
import (
"context"
"fmt"
"log"
"sync"
)
// SearchResult represents a single web search result.
type SearchResult struct {
Title string `json:"title"`
URL string `json:"url"`
Snippet string `json:"snippet"`
}
// Provider is the interface for web search backends.
type Provider interface {
// Search performs a web search and returns up to maxResults results.
Search(ctx context.Context, query string, maxResults int) ([]SearchResult, error)
// Name returns the provider identifier (e.g. "duckduckgo", "searxng").
Name() string
}
// ── Provider Registry ───────────────────────
var (
mu sync.RWMutex
providers = map[string]Provider{}
active string
)
// RegisterProvider adds a search provider to the registry.
func RegisterProvider(p Provider) {
mu.Lock()
defer mu.Unlock()
providers[p.Name()] = p
log.Printf("🔍 Registered search provider: %s", p.Name())
}
// SetActive sets the active search provider by name.
func SetActive(name string) error {
mu.Lock()
defer mu.Unlock()
if _, ok := providers[name]; !ok {
return fmt.Errorf("unknown search provider: %s", name)
}
active = name
log.Printf("🔍 Active search provider: %s", name)
return nil
}
// Active returns the currently active provider, or nil if none configured.
func Active() Provider {
mu.RLock()
defer mu.RUnlock()
if active == "" {
return nil
}
return providers[active]
}
// Available returns the names of all registered providers.
func Available() []string {
mu.RLock()
defer mu.RUnlock()
names := make([]string, 0, len(providers))
for name := range providers {
names = append(names, name)
}
return names
}
// Config holds the persisted search configuration.
type Config struct {
Provider string `json:"provider"` // "duckduckgo" or "searxng"
Endpoint string `json:"endpoint"` // SearXNG endpoint URL
APIKey string `json:"api_key"` // SearXNG API key (optional)
MaxResults int `json:"max_results"` // default results per search
}
// DefaultConfig returns the default search config (DuckDuckGo, no key needed).
func DefaultConfig() Config {
return Config{Provider: "duckduckgo", MaxResults: 5}
}
// ApplyConfig applies a Config to the active provider registry.
// Called on startup and when admin saves settings.
func ApplyConfig(cfg Config) error {
if cfg.Provider == "" {
cfg.Provider = "duckduckgo"
}
// Configure SearXNG if selected
mu.RLock()
if sxng, ok := providers["searxng"].(*SearXNG); ok {
sxng.Configure(cfg.Endpoint, cfg.APIKey)
}
mu.RUnlock()
return SetActive(cfg.Provider)
}