/** * 巡樓網路搜尋 — 委派至 lib/search(Brave Search API)。 * * 允許的搜尋來源(全專案): * 1. Threads API(lib/threads-api / lib/search) * 2. Brave Search API(lib/search) * 3. 瀏覽器爬蟲(lib/threads-browser) * * 以下 provider 已移除,不得再接入: * SerpAPI, Google Search API, Google Custom Search, Bing Search API, * Serper, Tavily, Exa, DuckDuckGo wrapper, SearXNG, 其他第三方 SERP。 */ import { detectLegacySearchEnvKeys, executeBraveSearch, getSearchConfig, LEGACY_SEARCH_ENV_KEYS, } from "@/lib/search"; export type SearchProvider = "brave"; export { detectLegacySearchEnvKeys, LEGACY_SEARCH_ENV_KEYS }; export interface WebSearchResult { title: string; snippet: string; link: string; provider: SearchProvider; } const PROVIDER_LABELS: Record = { brave: "Brave Search", }; export function getProviderLabel(provider: SearchProvider): string { return PROVIDER_LABELS[provider]; } function toWebResults( results: Array<{ title: string; snippet: string; url: string }> ): WebSearchResult[] { return results.map((item) => ({ title: item.title, snippet: item.snippet, link: item.url, provider: "brave" as const, })); } export interface BraveWebSearchOptions { limit?: number; /** 巡邏模式:檢查 high priority + 每日額度(預設依 context) */ patrolMode?: boolean; priority?: "high" | "medium" | "low"; /** 僅保留 threads.com 結果 */ threadsOnly?: boolean; } /** Brave Search API(需 BRAVE_SEARCH_API_KEY) */ export async function searchBrave( query: string, limit = 5, options?: BraveWebSearchOptions ): Promise { const cfg = getSearchConfig().brave; if (!cfg.enabled || !cfg.apiKey) return []; const patrolMode = options?.patrolMode ?? true; const executed = await executeBraveSearch({ keyword: query, query, limit, priority: options?.priority ?? (patrolMode ? "high" : undefined), patrolMode, threadsOnly: options?.threadsOnly ?? true, }); if (executed.status === "skipped" && executed.skipReason !== "cache_hit") { return []; } return toWebResults(executed.results); } /** 單一查詢(Brave) */ export async function searchWeb( query: string, limit = 5, options?: BraveWebSearchOptions ): Promise<{ results: WebSearchResult[]; provider: SearchProvider; providerLabel: string; }> { const results = await searchBrave(query, limit, options); return { results, provider: "brave", providerLabel: results.length > 0 ? PROVIDER_LABELS.brave : "無搜尋結果", }; } /** 網路搜尋入口(僅 Brave) */ export async function searchWebThorough( query: string, limit = 6, options?: BraveWebSearchOptions ): Promise<{ results: WebSearchResult[]; provider: SearchProvider; providerLabel: string; sources: SearchProvider[]; }> { const results = await searchBrave(query, limit, options); return { results, provider: "brave", sources: results.length > 0 ? ["brave"] : [], providerLabel: results.length > 0 ? PROVIDER_LABELS.brave : "無搜尋結果", }; } export function isBraveSearchConfigured(): boolean { const cfg = getSearchConfig().brave; return cfg.enabled && !!cfg.apiKey; }