Files
WifiShare/services/geminiService.ts
2026-02-06 16:19:54 +09:00

90 lines
3.4 KiB
TypeScript

import { GoogleGenAI, Type } from "@google/genai";
const apiKey = import.meta.env.VITE_GEMINI_API_KEY || process.env.GEMINI_API_KEY || process.env.API_KEY || '';
if (!apiKey) console.error("API Key is missing!");
const isDebug = import.meta.env.DEV;
const ai = new GoogleGenAI({ apiKey });
export interface DetailedSearchResult {
title: string;
uri: string;
lat?: number;
lng?: number;
}
export const geminiService = {
async searchNearbyWiFi(query: string, location: { lat: number, lng: number }) {
try {
if (isDebug) console.log("Stage 1: 정보 검색 시작...");
// Stage 1: Google Search/Maps Grounding을 통해 원시 데이터 확보
const searchResponse = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: `내 위치(위도: ${location.lat}, 경도: ${location.lng}) 주변에서 "${query}" 장소들을 찾아주세요.
각 장소의 이름, 주소, 그리고 가능한 경우 위도와 경도 정보를 상세히 포함해서 답변해 주세요.`,
config: {
tools: [{ googleSearch: {} }, { googleMaps: {} }],
toolConfig: {
retrievalConfig: {
latLng: {
latitude: location.lat,
longitude: location.lng
}
}
}
},
});
const rawText = searchResponse.text || "";
if (isDebug) console.log("Stage 1 원문 결과:", rawText);
if (!rawText) {
return { text: "검색 결과를 가져오지 못했습니다.", results: [] };
}
if (isDebug) console.log("Stage 2: 데이터 구조화 추출 시작...");
// Stage 2: 획득한 텍스트에서 JSON 형태로 좌표 및 정보 정밀 추출
const parseResponse = await ai.models.generateContent({
model: "gemini-3-flash-preview",
contents: `다음은 주변 장소 검색 결과 텍스트입니다. 이 텍스트에서 언급된 모든 장소를 추출하여 JSON 배열로 응답해 주세요.
각 객체는 title, uri(구글맵 링크), lat(숫자), lng(숫자) 속성을 가져야 합니다.
좌표가 텍스트에 직접 없더라도 문맥상 추론 가능하거나 본문에 포함되어 있다면 반드시 숫자로 변환하세요.
텍스트:
${rawText}`,
config: {
responseMimeType: "application/json",
responseSchema: {
type: Type.ARRAY,
items: {
type: Type.OBJECT,
properties: {
title: { type: Type.STRING, description: "장소 이름" },
uri: { type: Type.STRING, description: "구글 맵 링크" },
lat: { type: Type.NUMBER, description: "위도 (Latitude)" },
lng: { type: Type.NUMBER, description: "경도 (Longitude)" },
},
required: ["title", "lat", "lng"]
}
}
}
});
let results: DetailedSearchResult[] = [];
try {
results = JSON.parse(parseResponse.text || "[]");
if (isDebug) console.log("Stage 2 추출 성공:", results);
} catch (e) {
console.error("JSON 파싱 실패:", e);
}
return { text: rawText, results };
} catch (error: any) {
console.error("Gemini 검색 에러:", error);
return { text: `에러: ${error.message}`, results: [] };
}
}
};