export interface SerperVideoResult { title: string; link: string; snippet?: string; date?: string; duration?: string; channel?: string; } export interface SerperVideoResponse { searchParameters: any; videos: SerperVideoResult[]; } export interface SerperWebResult { title: string; link: string; snippet: string; date?: string; sitelinks?: any[]; position: number; } export interface SerperWebResponse { searchParameters: any; organic: SerperWebResult[]; } export class SerperClient { private apiKey: string; constructor(apiKey?: string) { const key = apiKey || process.env.SERPER_API_KEY; if (!key) { console.warn("⚠️ SERPER_API_KEY is not defined. SerperClient will fail."); } this.apiKey = key || ""; } /** * Performs a video search via Serper (Google Video Search). * Great for finding relevant YouTube videos. */ async searchVideos( query: string, num: number = 5, ): Promise { if (!this.apiKey) { console.error("❌ SERPER_API_KEY missing - cannot execute search."); return []; } try { console.log(`🔍 [Serper] Searching videos for: "${query}"`); const response = await fetch("https://google.serper.dev/videos", { method: "POST", headers: { "X-API-KEY": this.apiKey, "Content-Type": "application/json", }, body: JSON.stringify({ q: query, num: num, gl: "de", // Germany for localized results hl: "de", // German language }), }); if (!response.ok) { console.error( `❌ [Serper] API Error: ${response.status} ${response.statusText}`, ); const text = await response.text(); console.error(text); return []; } const data = (await response.json()) as SerperVideoResponse; return data.videos || []; } catch (e) { console.error("❌ [Serper] Request failed", e); return []; } } /** * Performs a standard web search via Serper. * Crucial for B2B competitor analysis and context gathering. */ async searchWeb(query: string, num: number = 5): Promise { if (!this.apiKey) { console.error("❌ SERPER_API_KEY missing - cannot execute web search."); return []; } try { console.log(`🔍 [Serper] Web Search for Competitor Insights: "${query}"`); const response = await fetch("https://google.serper.dev/search", { method: "POST", headers: { "X-API-KEY": this.apiKey, "Content-Type": "application/json", }, body: JSON.stringify({ q: query, num: num, gl: "de", // Germany for localized results hl: "de", // German language }), }); if (!response.ok) { console.error( `❌ [Serper] API Error: ${response.status} ${response.statusText}`, ); const text = await response.text(); console.error(text); return []; } const data = (await response.json()) as SerperWebResponse; return data.organic || []; } catch (e) { console.error("❌ [Serper] Web Request failed", e); return []; } } }