CognxSafeTrack
chore: execute Sprint 38 technical debt resolution (Type Safety, Zod validation, Vitest, Mock LLM extracted)
d9879cf | import axios from 'axios'; | |
| export interface SearchResult { | |
| title: string; | |
| snippet: string; | |
| link: string; | |
| } | |
| export class SearchService { | |
| private apiKey: string | undefined; | |
| constructor() { | |
| this.apiKey = process.env.SERPER_API_KEY; | |
| } | |
| /** | |
| * Performs a Google Search using Serper.dev API. | |
| */ | |
| async search(query: string): Promise<SearchResult[]> { | |
| if (!this.apiKey) { | |
| console.warn('[SEARCH_SERVICE] No SERPER_API_KEY found. Returning mock results.'); | |
| return [ | |
| { | |
| title: `Données pour ${query}`, | |
| snippet: "Le marché local est en croissance de 10-15% par an. La population cible est estimée à plusieurs milliers de personnes dans cette zone.", | |
| link: "https://xamle.sn" | |
| } | |
| ]; | |
| } | |
| try { | |
| const response = await axios.post('https://google.serper.dev/search', { | |
| q: query, | |
| gl: 'sn', // Search in Senegal | |
| hl: 'fr' // Language French | |
| }, { | |
| headers: { | |
| 'X-API-KEY': this.apiKey, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| const results = response.data.organic || []; | |
| return results.slice(0, 3).map((r: any) => ({ | |
| title: r.title, | |
| snippet: r.snippet, | |
| link: r.link | |
| })); | |
| } catch (err: unknown) { | |
| console.error('[SEARCH_SERVICE] Search failed:', (err instanceof Error ? (err instanceof Error ? err.message : String(err)) : String(err))); | |
| return []; | |
| } | |
| } | |
| } | |
| export const searchService = new SearchService(); | |