- Implement adapters for NewsAPI, GNews, NewsData, Serper Web Search, and Brave Search. - Add unified fetchNews aggregator with URL deduplication. - Wire OpenAI-compatible Kimi client for bias classification, ranking, summarization, and topic extraction. - Add AI analysis prompts, response parsing, and fallback logic. - Build ranker combining AI score, source credibility, and recency. - Create admin Discover page and API for manual news discovery.
43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
import { FetchNewsOptions, RawArticle } from '../types';
|
|
import { getActiveKey } from '@/lib/api-keys';
|
|
|
|
export async function fetchWebSearch(options: FetchNewsOptions): Promise<RawArticle[]> {
|
|
const apiKey = await getActiveKey('WEBSEARCH');
|
|
if (!apiKey) {
|
|
console.warn('Web search key not configured');
|
|
return [];
|
|
}
|
|
|
|
const res = await fetch('https://google.serper.dev/search', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-API-KEY': apiKey,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
q: options.query,
|
|
num: Math.min(options.maxResults || 10, 20),
|
|
tbs: options.from ? `cdr:1,cd_min:${options.from.toISOString().split('T')[0]}` : undefined,
|
|
}),
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const text = await res.text();
|
|
throw new Error(`Web search error ${res.status}: ${text}`);
|
|
}
|
|
|
|
const data = await res.json();
|
|
|
|
return (data.news || data.organic || []).map((item: Record<string, unknown>) => ({
|
|
title: String(item.title || ''),
|
|
url: String(item.link || item.url || ''),
|
|
sourceName: String(item.source || 'Web Search'),
|
|
sourceApiCode: 'websearch',
|
|
publishedAt: item.date ? new Date(String(item.date)) : undefined,
|
|
description: item.snippet ? String(item.snippet) : undefined,
|
|
content: undefined,
|
|
imageUrl: item.imageUrl ? String(item.imageUrl) : undefined,
|
|
raw: item,
|
|
}));
|
|
}
|