init
This commit is contained in:
104
services/search_service.py
Normal file
104
services/search_service.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from typing import List, Optional
|
||||
from models.debate import SearchResult, SearchEvidence
|
||||
|
||||
|
||||
class SearchService:
|
||||
"""
|
||||
Tavily web search wrapper for debate research.
|
||||
"""
|
||||
|
||||
def __init__(self, api_key: str):
|
||||
from tavily import TavilyClient
|
||||
self.client = TavilyClient(api_key=api_key)
|
||||
|
||||
def search(self, query: str, max_results: int = 5) -> List[SearchResult]:
|
||||
"""
|
||||
Perform a web search using Tavily and return structured results.
|
||||
"""
|
||||
try:
|
||||
response = self.client.search(
|
||||
query=query,
|
||||
max_results=max_results,
|
||||
search_depth="basic"
|
||||
)
|
||||
results = []
|
||||
for item in response.get("results", []):
|
||||
results.append(SearchResult(
|
||||
title=item.get("title", ""),
|
||||
url=item.get("url", ""),
|
||||
snippet=item.get("content", "")[:500], # Truncate to avoid token bloat
|
||||
score=item.get("score")
|
||||
))
|
||||
return results
|
||||
except Exception as e:
|
||||
print(f"Tavily search error: {e}")
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def format_results_for_context(evidence: SearchEvidence) -> str:
|
||||
"""
|
||||
Format search results into a string suitable for injecting into the LLM context.
|
||||
"""
|
||||
if not evidence or not evidence.results:
|
||||
return ""
|
||||
lines = [f"\n[网络搜索结果] 搜索词: \"{evidence.query}\""]
|
||||
for i, r in enumerate(evidence.results, 1):
|
||||
lines.append(f" {i}. {r.title}")
|
||||
lines.append(f" {r.snippet}")
|
||||
lines.append(f" 来源: {r.url}")
|
||||
lines.append("[搜索结果结束]\n")
|
||||
return "\n".join(lines)
|
||||
|
||||
@staticmethod
|
||||
def generate_search_query(topic: str, last_opponent_argument: Optional[str] = None) -> str:
|
||||
"""
|
||||
Generate a search query from the debate topic and the opponent's last argument.
|
||||
"""
|
||||
if last_opponent_argument:
|
||||
# Extract key phrases from the opponent's argument (first ~100 chars)
|
||||
snippet = last_opponent_argument[:100].strip()
|
||||
return f"{topic} {snippet}"
|
||||
return topic
|
||||
|
||||
@staticmethod
|
||||
def get_tool_definition() -> dict:
|
||||
"""
|
||||
Return the web_search tool definition for function calling.
|
||||
"""
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "web_search",
|
||||
"description": "Search the web for current information relevant to the debate topic. Use this to find facts, statistics, or recent news that support your argument.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The search query to look up"
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_tool_definition_anthropic() -> dict:
|
||||
"""
|
||||
Return the web_search tool definition in Anthropic format.
|
||||
"""
|
||||
return {
|
||||
"name": "web_search",
|
||||
"description": "Search the web for current information relevant to the debate topic. Use this to find facts, statistics, or recent news that support your argument.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The search query to look up"
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user