Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -117,11 +117,7 @@ forecast_tool = FunctionTool.from_defaults(
|
|
117 |
# -----------------------------
|
118 |
|
119 |
def fetch_news_headlines() -> str:
|
120 |
-
"""Fetches the latest news from Google News RSS feed.
|
121 |
-
|
122 |
-
Returns:
|
123 |
-
A string containing the latest news articles from Google News, or an error message if the request fails.
|
124 |
-
"""
|
125 |
url = "https://news.google.com/rss"
|
126 |
|
127 |
try:
|
@@ -131,7 +127,7 @@ def fetch_news_headlines() -> str:
|
|
131 |
# Parse the XML content
|
132 |
root = ET.fromstring(response.content)
|
133 |
|
134 |
-
# Format the news articles into a readable string
|
135 |
formatted_news = []
|
136 |
for i, item in enumerate(root.findall('.//item')):
|
137 |
if i >= 5:
|
@@ -139,12 +135,10 @@ def fetch_news_headlines() -> str:
|
|
139 |
title = item.find('title').text if item.find('title') is not None else 'N/A'
|
140 |
link = item.find('link').text if item.find('link') is not None else 'N/A'
|
141 |
pub_date = item.find('pubDate').text if item.find('pubDate') is not None else 'N/A'
|
142 |
-
description = item.find('description').text if item.find('description') is not None else 'N/A'
|
143 |
|
144 |
-
|
|
|
145 |
formatted_news.append(f"Published: {pub_date}")
|
146 |
-
formatted_news.append(f"Link: {link}")
|
147 |
-
formatted_news.append(f"Description: {description}")
|
148 |
formatted_news.append("---")
|
149 |
|
150 |
return "\n".join(formatted_news) if formatted_news else "No news articles found."
|
@@ -163,14 +157,7 @@ google_rss_tool = FunctionTool.from_defaults(
|
|
163 |
# SERPER API
|
164 |
# -----------------------------
|
165 |
def fetch_news_topics(query: str) -> str:
|
166 |
-
"""Fetches news articles about a specific topic using the Serper API.
|
167 |
-
|
168 |
-
Args:
|
169 |
-
query: The topic to search for news about.
|
170 |
-
|
171 |
-
Returns:
|
172 |
-
A string containing the news articles found, or an error message if the request fails.
|
173 |
-
"""
|
174 |
url = "https://google.serper.dev/news"
|
175 |
|
176 |
payload = json.dumps({
|
@@ -188,15 +175,20 @@ def fetch_news_topics(query: str) -> str:
|
|
188 |
|
189 |
news_data = response.json()
|
190 |
|
191 |
-
# Format the news articles
|
192 |
formatted_news = []
|
193 |
for i, article in enumerate(news_data.get('news', [])):
|
194 |
if i >= 5:
|
195 |
break
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
|
|
|
|
|
|
|
|
|
|
200 |
formatted_news.append("---")
|
201 |
|
202 |
return "\n".join(formatted_news) if formatted_news else "No news articles found."
|
@@ -318,25 +310,56 @@ async def run_query(query: str):
|
|
318 |
# Start the handler
|
319 |
handler = web_agent.run(query, ctx=ctx)
|
320 |
|
321 |
-
#
|
322 |
async for event in handler.stream_events():
|
|
|
|
|
|
|
|
|
323 |
if isinstance(event, AgentStream):
|
324 |
-
# This is the text being generated
|
325 |
if hasattr(event, 'delta') and event.delta:
|
326 |
yield event.delta
|
327 |
|
328 |
-
# We can optionally add minimal annotations for tool calls and results
|
329 |
-
# But we'll keep it simple to avoid interfering with the agent's natural output
|
330 |
elif isinstance(event, ToolCall):
|
331 |
-
#
|
332 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
|
334 |
elif isinstance(event, ToolCallResult):
|
335 |
-
#
|
336 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
|
338 |
except Exception as e:
|
339 |
yield f"\n\n❌ Error: {str(e)}\n"
|
|
|
|
|
|
|
340 |
finally:
|
341 |
instrumentor.flush()
|
342 |
|
|
|
117 |
# -----------------------------
|
118 |
|
119 |
def fetch_news_headlines() -> str:
|
120 |
+
"""Fetches the latest news from Google News RSS feed."""
|
|
|
|
|
|
|
|
|
121 |
url = "https://news.google.com/rss"
|
122 |
|
123 |
try:
|
|
|
127 |
# Parse the XML content
|
128 |
root = ET.fromstring(response.content)
|
129 |
|
130 |
+
# Format the news articles into a readable string with clickable links
|
131 |
formatted_news = []
|
132 |
for i, item in enumerate(root.findall('.//item')):
|
133 |
if i >= 5:
|
|
|
135 |
title = item.find('title').text if item.find('title') is not None else 'N/A'
|
136 |
link = item.find('link').text if item.find('link') is not None else 'N/A'
|
137 |
pub_date = item.find('pubDate').text if item.find('pubDate') is not None else 'N/A'
|
|
|
138 |
|
139 |
+
# Make the title a clickable link using Markdown syntax
|
140 |
+
formatted_news.append(f"**[{title}]({link})**")
|
141 |
formatted_news.append(f"Published: {pub_date}")
|
|
|
|
|
142 |
formatted_news.append("---")
|
143 |
|
144 |
return "\n".join(formatted_news) if formatted_news else "No news articles found."
|
|
|
157 |
# SERPER API
|
158 |
# -----------------------------
|
159 |
def fetch_news_topics(query: str) -> str:
|
160 |
+
"""Fetches news articles about a specific topic using the Serper API."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
url = "https://google.serper.dev/news"
|
162 |
|
163 |
payload = json.dumps({
|
|
|
175 |
|
176 |
news_data = response.json()
|
177 |
|
178 |
+
# Format the news articles with clickable links
|
179 |
formatted_news = []
|
180 |
for i, article in enumerate(news_data.get('news', [])):
|
181 |
if i >= 5:
|
182 |
break
|
183 |
+
title = article.get('title', 'N/A')
|
184 |
+
link = article.get('link', 'N/A')
|
185 |
+
source = article.get('source', 'N/A')
|
186 |
+
snippet = article.get('snippet', 'N/A')
|
187 |
+
|
188 |
+
# Make the title a clickable link using Markdown syntax
|
189 |
+
formatted_news.append(f"**[{title}]({link})**")
|
190 |
+
formatted_news.append(f"Source: {source}")
|
191 |
+
formatted_news.append(f"Snippet: {snippet}")
|
192 |
formatted_news.append("---")
|
193 |
|
194 |
return "\n".join(formatted_news) if formatted_news else "No news articles found."
|
|
|
310 |
# Start the handler
|
311 |
handler = web_agent.run(query, ctx=ctx)
|
312 |
|
313 |
+
# Stream content
|
314 |
async for event in handler.stream_events():
|
315 |
+
# Add some debugging info to understand event structure
|
316 |
+
# print(f"Event type: {type(event)}")
|
317 |
+
# print(f"Event attrs: {dir(event)}")
|
318 |
+
|
319 |
if isinstance(event, AgentStream):
|
320 |
+
# This is the text being generated
|
321 |
if hasattr(event, 'delta') and event.delta:
|
322 |
yield event.delta
|
323 |
|
|
|
|
|
324 |
elif isinstance(event, ToolCall):
|
325 |
+
# Handle ToolCall differently - check available attributes
|
326 |
+
tool_name = "unknown tool"
|
327 |
+
|
328 |
+
# Try different possible attribute locations
|
329 |
+
if hasattr(event, 'name'):
|
330 |
+
tool_name = event.name
|
331 |
+
elif hasattr(event, 'function_name'):
|
332 |
+
tool_name = event.function_name
|
333 |
+
elif hasattr(event, 'tool_name'):
|
334 |
+
tool_name = event.tool_name
|
335 |
+
|
336 |
+
yield f"\n\n🔧 Using tool: {tool_name}...\n"
|
337 |
|
338 |
elif isinstance(event, ToolCallResult):
|
339 |
+
# Handle ToolCallResult - check available attributes
|
340 |
+
result = "Result not available"
|
341 |
+
|
342 |
+
# Try different possible attribute locations
|
343 |
+
if hasattr(event, 'result'):
|
344 |
+
result = event.result
|
345 |
+
elif hasattr(event, 'output'):
|
346 |
+
result = event.output
|
347 |
+
elif hasattr(event, 'data') and hasattr(event.data, 'get'):
|
348 |
+
result = event.data.get("result", "")
|
349 |
+
|
350 |
+
# Truncate long results for display
|
351 |
+
if isinstance(result, str) and len(result) > 200:
|
352 |
+
result_preview = result[:200] + "... (truncated)"
|
353 |
+
else:
|
354 |
+
result_preview = str(result)
|
355 |
+
|
356 |
+
yield f"\n📊 Got result from tool\n"
|
357 |
|
358 |
except Exception as e:
|
359 |
yield f"\n\n❌ Error: {str(e)}\n"
|
360 |
+
# For debugging:
|
361 |
+
import traceback
|
362 |
+
yield f"Traceback: {traceback.format_exc()}"
|
363 |
finally:
|
364 |
instrumentor.flush()
|
365 |
|