Skip to content

Commit 3fa76bd

Browse files
committed
feat: Implement Perplexity API call in research_topic
1 parent 137e712 commit 3fa76bd

File tree

1 file changed

+69
-5
lines changed

1 file changed

+69
-5
lines changed

sonar-use-cases/research_finder/research_finder.py

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,77 @@ def _load_system_prompt(self, prompt_path: Path) -> str:
7777
return (
7878
"You are an AI research assistant. Your task is to research the user's query, "
7979
"provide a concise summary, and list the sources used."
80-
)
80+
)
8181

8282
def research_topic(self, query: str, model: str = DEFAULT_MODEL) -> Dict[str, Any]:
83-
"""Placeholder for research function."""
84-
print(f"Researching (placeholder): '{query}' using model '{model}'...")
85-
# TODO: Implement actual API call here
86-
return {"summary": "Placeholder summary", "sources": ["placeholder source"], "raw_response": ""}
83+
"""
84+
Research a given topic or question using the Perplexity API.
85+
"""
86+
if not query or not query.strip():
87+
return {"error": "Input query is empty. Cannot perform research."}
88+
89+
headers = {
90+
"accept": "application/json",
91+
"content-type": "application/json",
92+
"Authorization": f"Bearer {self.api_key}"
93+
}
94+
95+
data = {
96+
"model": model,
97+
"messages": [
98+
{"role": "system", "content": self.system_prompt},
99+
{"role": "user", "content": query}
100+
]
101+
# Consider adding other parameters like temperature, max_tokens if needed
102+
}
103+
104+
try:
105+
# Increased timeout for potentially longer research tasks
106+
response = requests.post(self.API_URL, headers=headers, json=data, timeout=90)
107+
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
108+
result = response.json()
109+
110+
if "choices" in result and result["choices"] and "message" in result["choices"][0]:
111+
content = result["choices"][0]["message"]["content"]
112+
# Basic parsing attempt (can be improved)
113+
summary = content # Default to full content
114+
sources_list = result.get("citations", []) # Use structured citations if available
115+
116+
# Simple text parsing if no structured citations and "Sources:" marker exists
117+
if not sources_list and "Sources:" in content:
118+
try:
119+
parts = content.split("Sources:", 1)
120+
summary = parts[0].strip()
121+
sources_text = parts[1].strip()
122+
sources_list = [s.strip().lstrip('- ') for s in sources_text.split('\n') if s.strip()]
123+
except Exception:
124+
summary = content # Revert if parsing fails
125+
sources_list = []
126+
127+
return {
128+
"summary": summary,
129+
"sources": sources_list,
130+
"raw_response": content
131+
}
132+
else:
133+
error_msg = "Unexpected API response format."
134+
if "error" in result:
135+
error_msg += f" API Error: {result['error'].get('message', 'Unknown error')}"
136+
return {"error": error_msg, "raw_response": result}
137+
138+
except RequestException as e:
139+
error_message = f"API request failed: {str(e)}"
140+
if e.response is not None:
141+
try:
142+
error_details = e.response.json()
143+
error_message += f" - {error_details.get('error', {}).get('message', e.response.text)}"
144+
except json.JSONDecodeError:
145+
error_message += f" - Status Code: {e.response.status_code}"
146+
return {"error": error_message}
147+
except json.JSONDecodeError:
148+
return {"error": "Failed to parse API response as JSON", "raw_response": response.text if 'response' in locals() else 'No response object'}
149+
except Exception as e:
150+
return {"error": f"An unexpected error occurred: {str(e)}"}
87151

88152

89153
def display_results(results: Dict[str, Any]):

0 commit comments

Comments
 (0)