| import { SearchSummary, SearchResult } from "../types.js"; |
| import { searchDuckDuckGo } from "./duckduckgo.js"; |
| import { rankResults } from "./rank.js"; |
| import { extractReadable } from "./extract.js"; |
| import { getCached, setCached } from "./cache.js"; |
|
|
| export async function searchWeb(query: string): Promise<SearchSummary> { |
| const cached = getCached(query); |
| if (cached) return cached; |
|
|
| const raw = await searchDuckDuckGo(query, 8); |
| const ranked = rankResults(query, raw); |
| const top = ranked.slice(0, 5); |
|
|
| const contentResults: Array<{ |
| url: string; |
| title: string; |
| content: string; |
| }> = []; |
|
|
| await Promise.all( |
| top.map(async (item) => { |
| try { |
| const article = await extractReadable(item.url); |
| if (article.content) { |
| contentResults.push({ |
| url: item.url, |
| title: article.title || item.title, |
| content: article.content |
| }); |
| } |
| } catch { |
| |
| } |
| }) |
| ); |
|
|
| const summary: SearchSummary = { |
| query, |
| results: top.map((r, idx) => ({ |
| title: r.title, |
| url: r.url, |
| snippet: r.snippet, |
| score: r.score + (top.length - idx) * 0.01 |
| })), |
| topContent: contentResults |
| }; |
|
|
| setCached(query, summary); |
| return summary; |
| }
|
|
|