ใ……ใ…Žใ…‡
Add CodeWeaver Gradio app
515f392
import logging
import os
import time
from typing import List
import requests
from tavily import TavilyClient # type: ignore[import]
from src.agent.state import SearchResult
logger = logging.getLogger(__name__)
def search_stackoverflow(query: str, limit: int = 3) -> List[SearchResult]:
"""Stack Overflow์—์„œ ๊ด€๋ จ ์งˆ๋ฌธ์„ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
Args:
query: ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ
limit: ๋ฐ˜ํ™˜ํ•  ์ตœ๋Œ€ ๊ฒฐ๊ณผ ์ˆ˜
Returns:
SearchResult ๋ฆฌ์ŠคํŠธ (์‹คํŒจ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ)
"""
if not query.strip():
logger.warning("Stack Overflow ๊ฒ€์ƒ‰: ๋นˆ ์ฟผ๋ฆฌ")
return []
try:
url = "https://api.stackexchange.com/2.3/search/advanced"
params = {
"q": query,
"order": "desc",
"sort": "votes",
"site": "stackoverflow",
"pagesize": limit,
"filter": "withbody",
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
items = data.get("items", [])
results = []
max_score = max((item.get("score", 0) for item in items), default=1)
for item in items:
title = item.get("title", "")
body = item.get("body", "")[:500] # ๋ณธ๋ฌธ ์ผ๋ถ€๋งŒ ํฌํ•จ
content = f"{title}\n\n{body}"
score = item.get("score", 0)
# ์ •๊ทœํ™”: 0-1 ๋ฒ”์œ„๋กœ ๋ณ€ํ™˜
relevance = min(score / max(max_score, 1), 1.0) if max_score > 0 else 0.5
results.append(
SearchResult(
source="Stack Overflow",
content=content,
url=item.get("link"),
relevance_score=relevance,
)
)
logger.info("Stack Overflow ๊ฒ€์ƒ‰ ์„ฑ๊ณต: %d๊ฐœ ๊ฒฐ๊ณผ", len(results))
# Rate limit ์ค€์ˆ˜
time.sleep(1)
return results
except Exception as e:
logger.error("Stack Overflow ๊ฒ€์ƒ‰ ์‹คํŒจ: %s", e, exc_info=True)
return []
def search_github(query: str, limit: int = 3) -> List[SearchResult]:
"""GitHub์—์„œ ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
Args:
query: ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ
limit: ๋ฐ˜ํ™˜ํ•  ์ตœ๋Œ€ ๊ฒฐ๊ณผ ์ˆ˜
Returns:
SearchResult ๋ฆฌ์ŠคํŠธ (์‹คํŒจ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ)
"""
if not query.strip():
logger.warning("GitHub ๊ฒ€์ƒ‰: ๋นˆ ์ฟผ๋ฆฌ")
return []
try:
url = "https://api.github.com/search/code"
# Python ์ฝ”๋“œ๋กœ ์ œํ•œ (์–ธ์–ด ๊ฐ์ง€ ๋กœ์ง์€ ์ถ”ํ›„ ํ™•์žฅ ๊ฐ€๋Šฅ)
search_query = f"{query} language:python"
params = {
"q": search_query,
"sort": "indexed",
"per_page": limit,
}
headers = {
"Accept": "application/vnd.github.v3+json",
}
# GitHub ํ† ํฐ์ด ์žˆ์œผ๋ฉด Authorization ํ—ค๋” ์ถ”๊ฐ€
github_token = os.getenv("GITHUB_TOKEN")
if github_token:
headers["Authorization"] = f"token {github_token}"
logger.debug("GitHub ํ† ํฐ ์‚ฌ์šฉ (์ธ์ฆ๋œ ์š”์ฒญ)")
else:
logger.warning(
"GITHUB_TOKEN์ด ์„ค์ •๋˜์ง€ ์•Š์Œ - rate limit ์ œํ•œ์  (60 req/hr). "
"ํ† ํฐ ์„ค์ • ์‹œ 5,000 req/hr๋กœ ์ฆ๊ฐ€"
)
response = requests.get(url, params=params, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
items = data.get("items", [])
results = []
for item in items:
repo_name = item.get("repository", {}).get("full_name", "unknown")
path = item.get("path", "")
content = f"Repository: {repo_name}\nFile: {path}"
results.append(
SearchResult(
source="GitHub",
content=content,
url=item.get("html_url"),
relevance_score=0.8, # GitHub ๊ฒฐ๊ณผ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋†’์€ ๊ด€๋ จ๋„
)
)
logger.info("GitHub ๊ฒ€์ƒ‰ ์„ฑ๊ณต: %d๊ฐœ ๊ฒฐ๊ณผ", len(results))
# Rate limit ์ค€์ˆ˜
time.sleep(1)
return results
except requests.exceptions.HTTPError as e:
if e.response.status_code == 403:
logger.warning("GitHub API rate limit ์ดˆ๊ณผ")
else:
logger.error("GitHub ๊ฒ€์ƒ‰ HTTP ์—๋Ÿฌ: %s", e, exc_info=True)
return []
except Exception as e:
logger.error("GitHub ๊ฒ€์ƒ‰ ์‹คํŒจ: %s", e, exc_info=True)
return []
def search_official_docs(query: str, limit: int = 3) -> List[SearchResult]:
"""Tavily API๋ฅผ ์‚ฌ์šฉํ•ด ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
Args:
query: ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ
limit: ๋ฐ˜ํ™˜ํ•  ์ตœ๋Œ€ ๊ฒฐ๊ณผ ์ˆ˜
Returns:
SearchResult ๋ฆฌ์ŠคํŠธ (์‹คํŒจ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ)
"""
if not query.strip():
logger.warning("Official Docs ๊ฒ€์ƒ‰: ๋นˆ ์ฟผ๋ฆฌ")
return []
api_key = os.getenv("TAVILY_API_KEY")
if not api_key:
logger.error("TAVILY_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
return []
try:
client = TavilyClient(api_key=api_key)
response = client.search(
query=query,
search_depth="basic",
max_results=limit,
include_domains=[
"docs.python.org",
"docs.oracle.com",
"spring.io/guides",
"developer.mozilla.org",
"reactjs.org/docs",
],
)
results = []
for item in response.get("results", []):
content = item.get("content", "")
url = item.get("url", "")
score = item.get("score", 0.5) # Tavily๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ด€๋ จ๋„ ์ ์ˆ˜
results.append(
SearchResult(
source="Official Docs",
content=content,
url=url,
relevance_score=score,
)
)
logger.info("Tavily ๊ฒ€์ƒ‰ ์„ฑ๊ณต: %d๊ฐœ ๊ฒฐ๊ณผ", len(results))
return results
except Exception as e:
logger.error("Tavily ๊ฒ€์ƒ‰ ์‹คํŒจ: %s", e, exc_info=True)
return []