mohammedelfeky-ai commited on
Commit
0b40803
·
verified ·
1 Parent(s): d9e8945

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -44
app.py CHANGED
@@ -1,25 +1,26 @@
1
- from smolagents import CodeAgent, DuckDuckGoSearchTool, load_tool, tool, LiteLLMModel
2
  import datetime
3
- import requests # Not used in the provided snippet directly, but often a common import
4
- import pytz # Used in the commented-out example tool
5
  import yaml
6
  import os
7
  import tempfile
8
- from tools.final_answer import FinalAnswerTool # Assuming this exists in ./tools/final_answer.py
9
- from tools.visit_webpage import VisitWebpageTool # Assuming this exists in ./tools/visit_webpage.py
10
- from tools.web_search import DuckDuckGoSearchTool
11
-
12
- import gradio as gr
13
- import json # Not used directly in the provided snippet, but can be common
14
-
15
  from typing import Dict, List, Optional, Union, Any
16
- import re # Added for regex in Gradio UI if not already globally available
17
 
18
- from smolagents.tools import Tool as SmolToolBase # Renamed to avoid conflict with @tool decorator
19
- from smolagents.agent_types import AgentAudio, AgentImage, AgentText # For GradioUI output handling
 
 
 
 
 
 
 
20
 
21
- from Gradio_UI import GradioUI # This will import the class from your modified file
 
22
 
 
23
 
24
  @tool
25
  def create_document(text: str, format: str = "docx") -> str:
@@ -30,7 +31,7 @@ def create_document(text: str, format: str = "docx") -> str:
30
  """
31
  try:
32
  temp_dir = tempfile.mkdtemp()
33
- file_name = "generated_document" # Consistent filename
34
 
35
  if format.lower() == "txt":
36
  path = os.path.join(temp_dir, f"{file_name}.txt")
@@ -75,17 +76,14 @@ def create_document(text: str, format: str = "docx") -> str:
75
  f"Please install it (e.g., 'pip install docx2pdf'). "
76
  f"Document saved as DOCX instead at: {docx_path}")
77
  print(err_msg)
78
- return err_msg # Or return docx_path with a note
79
  except Exception as e_pdf:
80
  err_msg = f"Error converting DOCX to PDF: {str(e_pdf)}. Document saved as DOCX at: {docx_path}"
81
  print(err_msg)
82
- return err_msg # Or return docx_path
83
-
84
  return docx_path
85
-
86
  else:
87
  return f"Error: Unsupported format '{format}'. Supported formats are 'docx', 'pdf', 'txt'."
88
-
89
  except Exception as e:
90
  print(f"General error in create_document: {str(e)}")
91
  return f"Error creating document: {str(e)}"
@@ -110,40 +108,120 @@ def get_file_download_link(file_path: str) -> str:
110
  msg = f"File '{os.path.basename(file_path)}' is ready for download (type: {mime_type})."
111
  print(f"get_file_download_link: {msg}")
112
  return msg
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  final_answer = FinalAnswerTool()
115
- web_search=DuckDuckGoSearchTool()
116
- visit_webpage=VisitWebpageTool()
117
 
118
- # Load image generation tool from Hub
119
  try:
120
- image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) # More likely correct
121
- # Common alternative: "agents-course/text-to-image" (uses a smaller SD model)
122
- # image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
123
  print(f"Successfully loaded image generation tool. Name: {getattr(image_generation_tool, 'name', 'N/A')}")
124
  except Exception as e:
125
- print(f"Error loading image generation tool: {e}")
126
- print("Image generation will not be available.")
127
- image_generation_tool = None # Set to None if loading fails
128
 
129
  # --- Configure LLM Model ---
130
- # Ensure GEMINI_KEY is set in your environment variables
131
  if not os.getenv("GEMINI_KEY"):
132
- print("CRITICAL: GEMINI_KEY environment variable not set. The LLM will not work.")
133
  # exit(1) # Or handle gracefully
134
 
135
  model = LiteLLMModel(
136
- model_id="gemini/gemini-1.5-flash-latest", # Using a common and capable Gemini model
137
  api_key=os.getenv("GEMINI_KEY"),
138
- max_tokens=4096, # Max output tokens for the LLM
139
- temperature=0.6 # Slightly lower temperature for more factual tool use
140
  )
141
 
142
  # --- Load Prompts ---
143
  prompts_file = "prompts.yaml"
144
  if not os.path.exists(prompts_file):
145
  print(f"Warning: '{prompts_file}' not found. Using default agent prompts.")
146
- prompt_templates = None # Agent will use its defaults
147
  else:
148
  with open(prompts_file, 'r') as stream:
149
  prompt_templates = yaml.safe_load(stream)
@@ -153,8 +231,9 @@ agent_tools = [
153
  final_answer,
154
  web_search,
155
  visit_webpage,
156
- create_document, # This is a @tool decorated function, so it's directly usable
157
- get_file_download_link, # Also a @tool decorated function
 
158
  ]
159
 
160
  if image_generation_tool:
@@ -165,16 +244,18 @@ else:
165
  agent = CodeAgent(
166
  model=model,
167
  tools=agent_tools,
168
- max_steps=10, # Max iterations for the agent
169
- verbosity_level=1, # Set to 1 or higher to populate interaction_logs for GradioUI
170
  prompt_templates=prompt_templates
171
  )
172
 
173
  # --- Main Application Entry Point ---
174
  if __name__ == "__main__":
 
 
 
 
175
  print("Starting Gradio UI...")
176
- # Initialize GradioUI with the agent
177
- # The GradioUI class should be imported from your modified Gradio_UI.py
178
- # Ensure Gradio_UI.py is in the same directory or python path
179
- ui = GradioUI(agent, file_upload_folder="uploaded_files") # Enable file uploads
180
- ui.launch() # share=False is default and safer for Spaces
 
1
+ from smolagents import CodeAgent, load_tool, tool, LiteLLMModel
2
  import datetime
3
+ import pytz
 
4
  import yaml
5
  import os
6
  import tempfile
7
+ import re
 
 
 
 
 
 
8
  from typing import Dict, List, Optional, Union, Any
 
9
 
10
+ # --- Tool Specific Imports ---
11
+ from newsapi import NewsApiClient # For News Tool
12
+
13
+ # --- Assuming your tools are structured like this ---
14
+ # If these are classes, they should be instantiated.
15
+ # If they are @tool decorated functions, they are used directly.
16
+ from tools.final_answer import FinalAnswerTool
17
+ from tools.visit_webpage import VisitWebpageTool
18
+ from tools.web_search import DuckDuckGoSearchTool
19
 
20
+ # --- Gradio UI ---
21
+ # from Gradio_UI import GradioUI # Assuming Gradio_UI.py is in the same directory
22
 
23
+ # --- @tool Decorated Functions (Custom Tools) ---
24
 
25
  @tool
26
  def create_document(text: str, format: str = "docx") -> str:
 
31
  """
32
  try:
33
  temp_dir = tempfile.mkdtemp()
34
+ file_name = "generated_document"
35
 
36
  if format.lower() == "txt":
37
  path = os.path.join(temp_dir, f"{file_name}.txt")
 
76
  f"Please install it (e.g., 'pip install docx2pdf'). "
77
  f"Document saved as DOCX instead at: {docx_path}")
78
  print(err_msg)
79
+ return err_msg
80
  except Exception as e_pdf:
81
  err_msg = f"Error converting DOCX to PDF: {str(e_pdf)}. Document saved as DOCX at: {docx_path}"
82
  print(err_msg)
83
+ return err_msg
 
84
  return docx_path
 
85
  else:
86
  return f"Error: Unsupported format '{format}'. Supported formats are 'docx', 'pdf', 'txt'."
 
87
  except Exception as e:
88
  print(f"General error in create_document: {str(e)}")
89
  return f"Error creating document: {str(e)}"
 
108
  msg = f"File '{os.path.basename(file_path)}' is ready for download (type: {mime_type})."
109
  print(f"get_file_download_link: {msg}")
110
  return msg
111
+
112
+ @tool
113
+ def get_latest_news(query: Optional[str] = None,
114
+ category: Optional[str] = None,
115
+ country: Optional[str] = "us",
116
+ language: Optional[str] = "en",
117
+ page_size: int = 5) -> str:
118
+ """
119
+ Fetches the latest news headlines.
120
+ You can specify a query, category, country, and language.
121
+
122
+ Args:
123
+ query: Keywords or a phrase to search for in the news articles. (e.g., "Tesla stock")
124
+ category: The category: business, entertainment, general, health, science, sports, technology.
125
+ country: The 2-letter ISO 3166-1 code of the country (e.g., 'us', 'gb'). Default 'us'.
126
+ language: The 2-letter ISO 639-1 code of the language (e.g., 'en', 'es'). Default 'en'.
127
+ page_size: Number of results (max 100, default 5).
128
+ """
129
+ api_key = os.getenv("NEWS_API_KEY")
130
+ if not api_key:
131
+ return "ERROR: News API key (NEWS_API_KEY) is not set in environment variables."
132
+
133
+ newsapi = NewsApiClient(api_key=api_key)
134
+ print(f"DEBUG NewsTool: query='{query}', category='{category}', country='{country}', lang='{language}', size={page_size}")
135
+
136
+ try:
137
+ if query:
138
+ print(f"Fetching news with query: '{query}'")
139
+ top_headlines = newsapi.get_everything(q=query,
140
+ language=language,
141
+ sort_by='publishedAt',
142
+ page_size=page_size)
143
+ elif category or country != "us": # If category or specific country (other than default for top-headlines)
144
+ print(f"Fetching top headlines for category: '{category}', country: '{country}'")
145
+ top_headlines = newsapi.get_top_headlines(q=None,
146
+ category=category,
147
+ language=language,
148
+ country=country,
149
+ page_size=page_size)
150
+ else: # Default top headlines for US/English if nothing specific is asked
151
+ print(f"Fetching default top headlines for country: '{country}', language: '{language}'")
152
+ top_headlines = newsapi.get_top_headlines(language=language,
153
+ country=country,
154
+ page_size=page_size)
155
 
156
+ if top_headlines['status'] == 'ok':
157
+ articles = top_headlines['articles']
158
+ if not articles:
159
+ return "No news articles found for the given criteria."
160
+
161
+ formatted_news = "## Latest News:\n\n"
162
+ for i, article in enumerate(articles[:page_size]): # Ensure we respect page_size
163
+ title = article.get('title', 'N/A')
164
+ source_name = article.get('source', {}).get('name', 'N/A')
165
+ description = article.get('description', 'No description available.')
166
+ url = article.get('url', '#')
167
+ published_at_str = article.get('publishedAt', 'N/A')
168
+
169
+ published_at_formatted = published_at_str
170
+ try:
171
+ if published_at_str and published_at_str != 'N/A':
172
+ # Handle 'Z' for UTC timezone correctly
173
+ dt_object = datetime.datetime.fromisoformat(published_at_str.replace('Z', '+00:00'))
174
+ # Format to a more readable string, perhaps without timezone if it's always UTC from API
175
+ published_at_formatted = dt_object.strftime('%Y-%m-%d %H:%M') + " UTC"
176
+ except ValueError:
177
+ pass # Keep original string if parsing fails
178
+
179
+ formatted_news += (
180
+ f"{i+1}. **{title}**\n"
181
+ f" - Source: {source_name}\n"
182
+ f" - Published: {published_at_formatted}\n"
183
+ f" - Description: {description[:200] + '...' if description and len(description) > 200 else (description or '')}\n"
184
+ f" - URL: {url}\n\n"
185
+ )
186
+ return formatted_news.strip()
187
+ else:
188
+ err_msg = f"ERROR: Could not fetch news. API Response: {top_headlines.get('code')} - {top_headlines.get('message')}"
189
+ print(err_msg)
190
+ return err_msg
191
+
192
+ except Exception as e:
193
+ print(f"ERROR: Exception in get_latest_news: {str(e)}")
194
+ return f"ERROR: An exception occurred while fetching news: {str(e)}"
195
+
196
+ # --- Initialize Tools ---
197
  final_answer = FinalAnswerTool()
198
+ web_search = DuckDuckGoSearchTool() # Your custom tool from tools/web_search.py
199
+ visit_webpage = VisitWebpageTool()
200
 
 
201
  try:
202
+ image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
 
 
203
  print(f"Successfully loaded image generation tool. Name: {getattr(image_generation_tool, 'name', 'N/A')}")
204
  except Exception as e:
205
+ print(f"Error loading image generation tool: {e}. Image generation will not be available.")
206
+ image_generation_tool = None
 
207
 
208
  # --- Configure LLM Model ---
 
209
  if not os.getenv("GEMINI_KEY"):
210
+ print("CRITICAL: GEMINI_KEY environment variable not set. LLM will not work.")
211
  # exit(1) # Or handle gracefully
212
 
213
  model = LiteLLMModel(
214
+ model_id="gemini/gemini-1.5-flash-latest",
215
  api_key=os.getenv("GEMINI_KEY"),
216
+ max_tokens=4096,
217
+ temperature=0.6
218
  )
219
 
220
  # --- Load Prompts ---
221
  prompts_file = "prompts.yaml"
222
  if not os.path.exists(prompts_file):
223
  print(f"Warning: '{prompts_file}' not found. Using default agent prompts.")
224
+ prompt_templates = None
225
  else:
226
  with open(prompts_file, 'r') as stream:
227
  prompt_templates = yaml.safe_load(stream)
 
231
  final_answer,
232
  web_search,
233
  visit_webpage,
234
+ create_document,
235
+ get_file_download_link,
236
+ get_latest_news, # Added the new news tool
237
  ]
238
 
239
  if image_generation_tool:
 
244
  agent = CodeAgent(
245
  model=model,
246
  tools=agent_tools,
247
+ max_steps=10,
248
+ verbosity_level=1,
249
  prompt_templates=prompt_templates
250
  )
251
 
252
  # --- Main Application Entry Point ---
253
  if __name__ == "__main__":
254
+ # Ensure NEWS_API_KEY is set if you want the news tool to work
255
+ if not os.getenv("NEWS_API_KEY"):
256
+ print("Warning: NEWS_API_KEY environment variable not set. News tool will return an error.")
257
+
258
  print("Starting Gradio UI...")
259
+ from Gradio_UI import GradioUI # Assuming Gradio_UI.py is in the same directory
260
+ ui = GradioUI(agent) # Removed file_upload_folder argument to disable UI uploads
261
+ ui.launch()