import { GoogleGenAI } from "@google/genai"; const ai = new GoogleGenAI({ apiKey: process.env.API_KEY }); export interface GeoResult { street: string; number: string; city: string; state: string; zip: string; description: string; mapLink?: string; } export const searchLocationWithGemini = async (query: string): Promise => { if (!query || query.length < 3) return []; try { // Attempt to get user location for better context let userLocation: { latitude: number; longitude: number } | undefined; try { const position = await new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject, { timeout: 2000 }); }); userLocation = { latitude: position.coords.latitude, longitude: position.coords.longitude }; } catch (e) { // Ignore geolocation errors, proceed without it } const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: `Find the specific address details for the location query: "${query}". You MUST return the address components in the following format (one per line): Description: [A concise formatted address] Street: [Street Name] Number: [Street Number, if available] City: [City Name] State: [State Code, e.g., SP, RJ] Zip: [Postal Code] If a specific component is not found, leave it empty after the colon.`, config: { tools: [{ googleMaps: {} }], toolConfig: userLocation ? { retrievalConfig: { latLng: { latitude: userLocation.latitude, longitude: userLocation.longitude } } } : undefined } }); const text = response.text || ""; // Helper parser const parseField = (key: string) => { const regex = new RegExp(`${key}:\\s*(.*)`, 'i'); const match = text.match(regex); return match ? match[1].trim() : ''; }; // Extract Google Maps URI from grounding metadata let mapUri = ''; const chunks = response.candidates?.[0]?.groundingMetadata?.groundingChunks || []; // Look for the Web URI in the chunks (Google Maps grounding often returns this) for (const chunk of chunks) { if (chunk.web?.uri && (chunk.web.uri.includes('google.com/maps') || chunk.web.uri.includes('maps.google.com'))) { mapUri = chunk.web.uri; break; } } const result: GeoResult = { street: parseField('Street'), number: parseField('Number'), city: parseField('City'), state: parseField('State'), zip: parseField('Zip'), description: parseField('Description') || text.split('\n')[0], // Fallback to first line mapLink: mapUri }; // Filter out bad results (empty city/state usually means it failed to identify a place) if (!result.city && !result.street) return []; return [result]; } catch (error) { console.error("Gemini Search Error:", error); return []; } };