wt002 commited on
Commit
d7c7507
·
verified ·
1 Parent(s): cd40d80

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +12 -339
app.py CHANGED
@@ -1,360 +1,33 @@
1
  import os
2
  import gradio as gr
3
  from dotenv import load_dotenv
 
4
  import requests
5
  import pandas as pd
6
- import base64
7
- import mimetypes
8
- import tempfile
9
- from smolagents import CodeAgent, OpenAIServerModel, tool
10
- from dotenv import load_dotenv
11
- from openai import OpenAI
12
- from markdownify import markdownify
13
- from requests.exceptions import RequestException
14
-
15
- from typing import Optional, List
16
- from langchain_core.tools import BaseTool, tool
17
- #from langchain_community.tools import DuckDuckGoSearchResults
18
- #from langchain_experimental.tools import PythonREPLTool
19
- import requests
20
- from bs4 import BeautifulSoup
21
- import markdownify
22
- import pandas as pd
23
- from io import BytesIO
24
- #import pytesseract
25
- from PIL import Image
26
- from youtube_transcript_api import YouTubeTranscriptApi
27
- import re
28
 
29
- # Load environment variables
30
  load_dotenv()
31
 
 
32
  # --- Constants ---
33
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
34
 
35
- # Initialize the OpenAI model using environment variable for API key
36
- model = OpenAIServerModel(
37
- model_id="o4-mini-2025-04-16",
38
- api_base="https://api.openai.com/v1",
39
- api_key=os.getenv("openai"),
40
- )
41
-
42
- # Initialize OpenAI client
43
- openAiClient = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
44
-
45
- @tool
46
- def arvix_search(query: str) -> str:
47
- """Search Arxiv for a query and return maximum 3 result.
48
-
49
- Args:
50
- query: The search query."""
51
- search_docs = ArxivLoader(query=query, load_max_docs=3).load()
52
- formatted_search_docs = "\n\n---\n\n".join(
53
- [
54
- f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content[:1000]}\n</Document>'
55
- for doc in search_docs
56
- ])
57
- return {"arvix_results": formatted_search_docs}
58
-
59
-
60
- @tool
61
- def analyze_image(image_url: str) -> str:
62
- """
63
- Analyze an image using OpenAI's vision model and return a description.
64
-
65
- Args:
66
- image_url: URL of the image to analyze
67
-
68
- Returns:
69
- A detailed description of the image
70
- """
71
- api_key = os.getenv("OPENAI_API_KEY")
72
- if not api_key:
73
- return "Error: OpenAI API key not set in environment variables"
74
-
75
- # Download the image
76
- try:
77
- response = requests.get(image_url)
78
- response.raise_for_status()
79
- image_data = response.content
80
- base64_image = base64.b64encode(image_data).decode('utf-8')
81
- except Exception as e:
82
- return f"Error downloading image: {str(e)}"
83
-
84
- # Call OpenAI API
85
- api_url = "https://api.openai.com/v1/chat/completions"
86
- headers = {
87
- "Content-Type": "application/json",
88
- "Authorization": f"Bearer {api_key}"
89
- }
90
-
91
- payload = {
92
- "model": "gpt-4.1-2025-04-14",
93
- "messages": [
94
- {
95
- "role": "user",
96
- "content": [
97
- {
98
- "type": "text",
99
- "text": "Describe this image in detail. Include any text, objects, people, actions, and overall context."
100
- },
101
- {
102
- "type": "image_url",
103
- "image_url": {
104
- "url": f"data:image/jpeg;base64,{base64_image}"
105
- }
106
- }
107
- ]
108
- }
109
- ],
110
- "max_tokens": 500
111
- }
112
-
113
- try:
114
- response = requests.post(api_url, headers=headers, json=payload)
115
- response.raise_for_status()
116
- data = response.json()
117
-
118
- if "choices" in data and len(data["choices"]) > 0:
119
- return data["choices"][0]["message"]["content"]
120
- else:
121
- return "No description generated"
122
- except Exception as e:
123
- return f"Error analyzing image: {str(e)}"
124
-
125
- @tool
126
- def analyze_sound(audio_url: str) -> str:
127
- """
128
- Transcribe an audio file using OpenAI's Whisper model.
129
-
130
- Args:
131
- audio_url: the url of the audio
132
-
133
- Returns:
134
- A transcription of the audio content
135
- """
136
- api_key = os.getenv("OPENAI_API_KEY")
137
- if not api_key:
138
- return "Error: OpenAI API key not set in environment variables"
139
-
140
- # Download the audio file
141
- try:
142
- response = requests.get(audio_url)
143
- response.raise_for_status()
144
-
145
- import tempfile
146
- with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
147
- temp_file.write(response.content)
148
- temp_file_path = temp_file.name
149
-
150
- audio_file= open(temp_file_path, "rb")
151
-
152
- except Exception as e:
153
- return f"Error downloading audio: {str(e)}"
154
-
155
- try:
156
- transcription = openAiClient.audio.transcriptions.create(
157
- model="gpt-4o-transcribe",
158
- file=audio_file
159
- )
160
- return transcription.text
161
- except Exception as e:
162
- return f"Error transcribing audio: {str(e)}"
163
-
164
- @tool
165
- def analyze_excel(excel_url: str) -> str:
166
- """
167
- Process an Excel file and convert it to a text-based format.
168
-
169
- Args:
170
- excel_url: URL of the Excel file to analyze
171
-
172
- Returns:
173
- A text representation of the Excel data
174
- """
175
- try:
176
- # Download the Excel file
177
- response = requests.get(excel_url)
178
- response.raise_for_status()
179
-
180
- # Save to a temporary file
181
- with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as temp_file:
182
- temp_file.write(response.content)
183
- temp_file_path = temp_file.name
184
-
185
- # Read the Excel file
186
- df = pd.read_excel(temp_file_path)
187
-
188
- # Convert to a text representation
189
- result = []
190
-
191
- # Add sheet information
192
- result.append(f"Excel file with {len(df)} rows and {len(df.columns)} columns")
193
-
194
- # Add column names
195
- result.append("\nColumns:")
196
- for i, col in enumerate(df.columns, 1):
197
- result.append(f"{i}. {col}")
198
-
199
- # Add data summary
200
- result.append("\nData Summary:")
201
- result.append(df.describe().to_string())
202
-
203
- # Add first few rows as a sample
204
- result.append("\nFirst 5 rows:")
205
- result.append(df.head().to_string())
206
-
207
- # Clean up
208
- os.unlink(temp_file_path)
209
-
210
- return "\n".join(result)
211
- except Exception as e:
212
- return f"Error processing Excel file: {str(e)}"
213
-
214
- @tool
215
- def analyze_text(text_url: str) -> str:
216
- """
217
- Process a text file and return its contents.
218
-
219
- Args:
220
- text_url: URL of the text file to analyze
221
-
222
- Returns:
223
- The contents of the text file
224
- """
225
- try:
226
- # Download the text file
227
- response = requests.get(text_url)
228
- response.raise_for_status()
229
-
230
- # Get the text content
231
- text_content = response.text
232
-
233
- # For very long files, truncate with a note
234
- if len(text_content) > 10000:
235
- return f"Text file content (truncated to first 10000 characters):\n\n{text_content[:10000]}\n\n... [content truncated]"
236
-
237
- return f"Text file content:\n\n{text_content}"
238
- except Exception as e:
239
- return f"Error processing text file: {str(e)}"
240
-
241
- @tool
242
- def transcribe_youtube(youtube_url: str) -> str:
243
- """
244
- Extract the transcript from a YouTube video.
245
-
246
- Args:
247
- youtube_url: URL of the YouTube video
248
-
249
- Returns:
250
- The transcript of the video
251
- """
252
- try:
253
- # Extract video ID from URL
254
- import re
255
- video_id_match = re.search(r'(?:v=|\/)([0-9A-Za-z_-]{11}).*', youtube_url)
256
- if not video_id_match:
257
- return "Error: Invalid YouTube URL"
258
-
259
- video_id = video_id_match.group(1)
260
-
261
- # Use youtube_transcript_api to get the transcript
262
- from youtube_transcript_api import YouTubeTranscriptApi
263
-
264
- try:
265
- transcript_list = YouTubeTranscriptApi.get_transcript(video_id)
266
-
267
- # Combine all transcript segments into a single text
268
- full_transcript = ""
269
- for segment in transcript_list:
270
- full_transcript += segment['text'] + " "
271
-
272
- return f"YouTube Video Transcript:\n\n{full_transcript.strip()}"
273
- except Exception as e:
274
- return f"Error extracting transcript: {str(e)}"
275
- except Exception as e:
276
- return f"Error processing YouTube video: {str(e)}"
277
-
278
-
279
- @tool
280
- def process_file(task_id: str, file_name: str) -> str:
281
- """
282
- Fetch and process a file based on task_id and file_name.
283
- For images, it will analyze them and return a description of the image.
284
- For audio files, it will transcribe them.
285
- For Excel files, it will convert them to a text format.
286
- For text files, it will return the file contents.
287
- Other file types can be ignored for this tool.
288
-
289
- Args:
290
- task_id: The task ID to fetch the file for
291
- file_name: The name of the file to process
292
-
293
- Returns:
294
- A description or transcription of the file content
295
- """
296
- if not task_id or not file_name:
297
- return "Error: task_id and file_name are required"
298
-
299
- # Construct the file URL
300
- file_url = f"{DEFAULT_API_URL}/files/{task_id}"
301
-
302
- try:
303
- # Fetch the file
304
- response = requests.get(file_url)
305
- response.raise_for_status()
306
-
307
- # Determine file type
308
- mime_type, _ = mimetypes.guess_type(file_name)
309
-
310
- # Process based on file type
311
- if mime_type and mime_type.startswith('image/'):
312
- # For images, use the analyze_image tool
313
- return analyze_image(file_url)
314
- elif file_name.lower().endswith('.mp3') or (mime_type and mime_type.startswith('audio/')):
315
- # For audio files, use the analyze_sound tool
316
- return analyze_sound(file_url)
317
- elif file_name.lower().endswith('.xlsx') or (mime_type and mime_type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'):
318
- # For Excel files, use the analyze_excel tool
319
- return analyze_excel(file_url)
320
- elif file_name.lower().endswith(('.txt', '.py', '.js', '.html', '.css', '.json', '.md')) or (mime_type and mime_type.startswith('text/')):
321
- # For text files, use the analyze_text tool
322
- return analyze_text(file_url)
323
- else:
324
- # For other file types, return basic information
325
- return f"File '{file_name}' of type '{mime_type or 'unknown'}' was fetched successfully. Content processing not implemented for this file type."
326
- except Exception as e:
327
- return f"Error processing file: {str(e)}"
328
-
329
 
330
  class BasicAgent:
331
- """
332
- A simple agent that uses smolagents.CodeAgent with multiple specialized tools:
333
- - Tavily search tool for web searches
334
- - Image analysis tool for processing images
335
- - Audio transcription tool for processing sound files
336
- - Excel analysis tool for processing spreadsheet data
337
- - Text file analysis tool for processing code and text files
338
- - YouTube transcription tool for processing video content
339
- - File processing tool for handling various file types
340
-
341
- The CodeAgent is instantiated once and reused for each question to reduce overhead.
342
- """
343
  def __init__(self):
344
  print("BasicAgent initialized.")
345
- # Reuse a single CodeAgent instance for all queries
346
- self.agent = CodeAgent(tools=[arvix_search,
347
- analyze_image,
348
- analyze_sound,
349
- analyze_excel,
350
- analyze_text,
351
- transcribe_youtube,
352
- process_file], model=model)
353
 
354
  def __call__(self, question: str) -> str:
355
  print(f"Agent received question (first 50 chars): {question[:50]}...")
356
- return self.agent.run(question)
357
-
 
 
 
358
 
359
 
360
  def run_and_submit_all( profile: gr.OAuthProfile | None):
 
1
  import os
2
  import gradio as gr
3
  from dotenv import load_dotenv
4
+ import inspect
5
  import requests
6
  import pandas as pd
7
+ from langchain_core.messages import HumanMessage
8
+ from agent import build_graph
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
 
10
  load_dotenv()
11
 
12
+ # (Keep Constants as is)
13
  # --- Constants ---
14
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
 
16
+ # --- Basic Agent Definition ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  class BasicAgent:
19
+ """A langgraph agent."""
 
 
 
 
 
 
 
 
 
 
 
20
  def __init__(self):
21
  print("BasicAgent initialized.")
22
+ self.graph = build_graph()
 
 
 
 
 
 
 
23
 
24
  def __call__(self, question: str) -> str:
25
  print(f"Agent received question (first 50 chars): {question[:50]}...")
26
+ # Wrap the question in a HumanMessage from langchain_core
27
+ messages = [HumanMessage(content=question)]
28
+ messages = self.graph.invoke({"messages": messages})
29
+ answer = messages['messages'][-1].content
30
+ return answer[14:]
31
 
32
 
33
  def run_and_submit_all( profile: gr.OAuthProfile | None):