"""Gemini AI 유틸리티"""
import os
from typing import List, Dict
from google import genai
from google.genai import types
import re
import json
from typing import List, Dict, Union
# 환경 변수 설정
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/Users/yanghyojun/Downloads/mystic-subject-478505-r7-330480ad8816.json"
# Gemini AI 클라이언트 초기화
_genai_client = genai.Client(
vertexai=True,
project="mystic-subject-478505-r7",
location="global",
)
def generate_text(
prompt: str,
model: str = "gemini-2.0-flash-exp",
temperature: float = 0.3,
max_tokens: int = 1024
) -> str:
"""
Gemini AI를 사용하여 텍스트 생성
Args:
prompt: 입력 프롬프트
model: 사용할 모델 (기본: gemini-2.0-flash-exp)
temperature: 온도 설정 (0.0~1.0)
max_tokens: 최대 토큰 수
Returns:
생성된 텍스트
"""
contents = [
types.Content(
role="user",
parts=[types.Part(text=prompt)]
)
]
generate_content_config = types.GenerateContentConfig(
temperature=temperature,
top_p=0.95,
max_output_tokens=max_tokens,
)
response = _genai_client.models.generate_content(
model=model,
contents=contents,
config=generate_content_config,
)
return response.text.strip()
#
# def filter_official_docs(query: str, search_results: List[Dict[str, str]]) -> List[Dict[str, str]]:
# """
# AI를 사용하여 검색 결과에서 공식 문서 필터링
#
# Args:
# query: 원본 검색 질문
# search_results: 검색 결과 리스트
#
# Returns:
# 제일 공식문서같은 url
# """
# if not search_results:
# return []
#
# # 검색 결과를 텍스트로 포맷팅
# results_text = ""
# for idx, result in enumerate(search_results):
# results_text += f"\n[{idx}] 제목: {result['title']}\n"
# results_text += f"URL: {result['link']}\n"
# results_text += "---\n"
#
# # AI에게 공식문서 찾기 요청
# prompt = f"""다음은 "{query}"에 대한 검색 결과이다.
#
# {results_text}
#
# 위 검색 결과들 중에서 가장 알맞은 공식 문서(official documentation) 하나를 뽑으시오.
# 공식 문서의 특징:
# - 공식 웹사이트 도메인 (예: docs.python.org, react.dev, docs.microsoft.com 등)
# 출력 조건:
# - 단 하나의 결과만을 뽑아 title과 link를 아래 json형식에 맞춰 반환하시오.
# - 다른 추가 기호, 서식, 설명, 마크다운, ```, 이스케이프 문자(\, \n, \")을 절대 사용하지 마시오.
# - 아래 형식에 맞춰 순수한 JSON 객체만 출력하시오.
#
# 응답 형식:
# {{{{
# "title" : 제목,
# "link" : URL
# }}}}
#
# 만약 공식문서가 없다면 "없음" 반환하시오"""
#
# ai_response = generate_text(prompt)
#
# # AI 응답 파싱
# if "없음" in ai_response or not ai_response:
# return "결과 이상"
#
# return ai_response
def filter_official_docs(query: str, search_results: List[Dict[str, str]]) -> Dict[str, str]:
"""
AI를 사용하여 검색 결과에서 공식 문서 필터링
Args:
query: 검색 질문
search_results: 검색 결과 리스트
Returns:
공식 문서 정보 (title과 link) 또는 에러 메시지
"""
if not search_results:
return {"error": "검색 결과가 없습니다."}
results_text = ""
for idx, r in enumerate(search_results):
results_text += f"[{idx}] {r['title']}\n"
prompt = f"""다음은 "{query}"에 대한 검색 결과 제목 목록이다.
{results_text}
위 목록 중에서
- "{query}"에 가장 직접적으로 답이 되는
- 공식 문서로 보이는
- 단 하나의 결과 번호만 고르시오
출력 조건:
- 숫자 하나만 출력
- 다른 문자, 설명, 기호 출력 금지
- 예: 0
"""
ai_response = generate_text(prompt).strip()
# 숫자만 추출 (앞뒤 공백이나 다른 문자 제거)
match = re.search(r'\d+', ai_response)
if not match:
return {"error": "AI가 올바른 결과를 반환하지 않았습니다."}
idx = int(match.group())
if idx < 0 or idx >= len(search_results):
return {"error": f"잘못된 인덱스: {idx}"}
# title과 link만 반환
title = search_results[idx]["title"].strip()
link = search_results[idx]["link"].strip()
# link에서 역슬래시 제거
link = link.replace('\\', '')
return {
"title": title,
"link": link
}