package search import "fmt" // Engine 一个可插拔的搜索引擎源。 // // 各源(SearXNG、搜狗 HTTP、真实浏览器、付费 SerpApi 等)通过实现该接口接入聚合 Client, // 由 search_config.json 声明启用顺序与参数,替代此前写死在 Client.Search 里的硬编码回退链。 type Engine interface { // Name 引擎唯一标识(与 search_config.json 中 engines 的 key 对应)。 Name() string // Search 执行一次搜索。失败或无结果时返回 (nil, err),由聚合 Client 降级到下一引擎。 Search(query string) ([]Result, error) } // searxngEngine 基于 SearXNG /search?format=json 的引擎。 type searxngEngine struct { client *SearXNGClient } func (e *searxngEngine) Name() string { return "searxng" } func (e *searxngEngine) Search(q string) ([]Result, error) { return e.client.searchSearXNG(q) } // sogouEngine 基于搜狗 HTTP 抓取的引擎。 type sogouEngine struct { client *SogouClient } func (e *sogouEngine) Name() string { return "sogou" } func (e *sogouEngine) Search(q string) ([]Result, error) { return e.client.Search(q) } // browserEngine 基于真实浏览器(Playwright + 系统 Chrome)的引擎。 type browserEngine struct { searcher *BrowserSearcher } func (e *browserEngine) Name() string { return "browser" } func (e *browserEngine) Search(q string) ([]Result, error) { return e.searcher.Search(q) } // serpapiEngine 基于付费 SerpApi 的引擎。 type serpapiEngine struct { client *SerpApiClient } func (e *serpapiEngine) Name() string { return "serpapi" } func (e *serpapiEngine) Search(q string) ([]Result, error) { return e.client.Search(q) } // dtsAIEngine 基于阿里云 DTS-AI WebSearch 的引擎。 type dtsAIEngine struct { client *DtsAIClient } func (e *dtsAIEngine) Name() string { return "dtsai" } func (e *dtsAIEngine) Search(q string) ([]Result, error) { return e.client.Search(q) } // engineFromConfig 根据一条 EngineConfig 构建对应引擎;type 未知返回 error。 func engineFromConfig(name string, ec EngineConfig) (Engine, error) { switch ec.Type { case "searxng": return &searxngEngine{client: NewSearXNGClient(ec.BaseURL)}, nil case "sogou": return &sogouEngine{client: NewSogouClient()}, nil case "browser": return &browserEngine{searcher: GetBrowserSearcher()}, nil case "serpapi": return &serpapiEngine{client: NewSerpApiClient(ec.APIKeyEnv)}, nil case "dtsai": return &dtsAIEngine{client: NewDtsAIClient(ec.APIKeyEnv, ec.Region, ec.BaseURL, ec.MaxResults, ec.TimeoutSec)}, nil default: return nil, fmt.Errorf("未知搜索引擎类型 %q(引擎 %q)", ec.Type, name) } }