initial commit
This commit is contained in:
86
services/geminiService.ts
Normal file
86
services/geminiService.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
import { GoogleGenAI, Type } from "@google/genai";
|
||||
|
||||
const ai = new GoogleGenAI({ apiKey: process.env.API_KEY });
|
||||
|
||||
export interface DetailedSearchResult {
|
||||
title: string;
|
||||
uri: string;
|
||||
lat?: number;
|
||||
lng?: number;
|
||||
}
|
||||
|
||||
export const geminiService = {
|
||||
async searchNearbyWiFi(query: string, location: { lat: number, lng: number }) {
|
||||
try {
|
||||
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 || "";
|
||||
console.log("Stage 1 원문 결과:", rawText);
|
||||
|
||||
if (!rawText) {
|
||||
return { text: "검색 결과를 가져오지 못했습니다.", results: [] };
|
||||
}
|
||||
|
||||
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 || "[]");
|
||||
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: [] };
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user