pmeyhoefer commited on
Commit
0cf07a2
·
verified ·
1 Parent(s): d2c7a1d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -143
app.py CHANGED
@@ -3,20 +3,20 @@ import gradio as gr
3
  import requests
4
  import pandas as pd
5
  import re
 
6
  from datetime import datetime
7
- import time
8
  import tempfile
9
  import atexit
10
  import sys # Für sys.exit bei Importfehlern
11
 
12
- # --- Smol Agents und HF Imports (angepasst an Beispiel) ---
13
  try:
14
  from smolagents import CodeAgent, tool, HfApiModel
15
  print("Successfully imported CodeAgent, tool, HfApiModel from 'smolagents'")
16
  except ImportError as e:
17
  print(f"Error importing from smolagents: {e}")
18
  print("Please ensure 'smolagents[huggingface]' is listed correctly in requirements.txt")
19
- sys.exit(f"Fatal Error: Could not import smolagents components. Check requirements.txt and rebuild/restart the Space. Original error: {e}")
20
 
21
  from huggingface_hub import HfApi
22
 
@@ -43,216 +43,159 @@ try:
43
  PDF_READER_AVAILABLE = True
44
  except ImportError:
45
  PDF_READER_AVAILABLE = False
46
- print("WARNUNG: PyPDF2 nicht installiert. PDF-Lesefunktion ist deaktiviert.")
47
 
48
- # --- Konstanten ---
49
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
50
  HF_MODEL_ID = os.getenv("HF_MODEL_ID", "meta-llama/Meta-Llama-3-8B-Instruct")
51
-
52
- # --- Globale Variablen ---
53
  search_client = None
54
  agent_instance = None
55
 
56
  temp_files_to_clean = set()
57
 
58
  def cleanup_temp_files():
59
- print("Cleaning up temporary files...")
60
- for file_path in list(temp_files_to_clean):
61
  try:
62
- if os.path.exists(file_path):
63
- os.remove(file_path)
64
- print(f"Removed temporary file: {file_path}")
65
- temp_files_to_clean.discard(file_path)
66
- except Exception as e:
67
- print(f"Error removing temporary file {file_path}: {e}")
68
-
69
  atexit.register(cleanup_temp_files)
70
 
71
- # --- Tool Definitionen ---
72
  @tool
73
  def search_web(query: str, max_results: int = 3) -> str:
74
  """
75
- Sucht im Web nach der angegebenen Query und gibt eine Zusammenfassung der obersten Ergebnisse zurück.
76
- Args:
77
- query (str): Der Suchbegriff.
78
- max_results (int): Maximale Anzahl an Ergebnissen (Standard 3).
79
- Returns:
80
- str: Konsolidierte Ergebnisliste oder Fehlermeldung.
81
  """
82
- print(f"Tool: search_web(query='{query}', max_results={max_results})")
83
  if not search_client:
84
- return "Search tool is not available/configured."
85
  try:
86
  if USE_TAVILY and isinstance(search_client, TavilyClient):
87
- response = search_client.search(query=query, search_depth="basic", max_results=max_results)
88
- context = response.get('results', [])
89
- if not context:
90
- return "No search results found."
91
- return "\n".join(
92
- [f"URL: {c['url']}\nContent: {c['content'][:500]}..." for c in context]
93
- )
94
  elif USE_DUCKDUCKGO and isinstance(search_client, DDGS):
95
  results = search_client.text(query, max_results=max_results)
96
- if not results:
97
- return "No search results found."
98
- return "\n".join(
99
- [f"Title: {r['title']}\nURL: {r['href']}\nSnippet: {r['body'][:500]}..." for r in results]
100
- )
101
- else:
102
- return "No compatible search client configured or available."
103
  except Exception as e:
104
- print(f"Search API Error ({type(e).__name__}): {e}")
105
  return f"Error during search: {e}"
 
106
 
107
  @tool
108
  def download_task_file(task_id: str) -> str:
109
- """
110
- Lädt eine Datei vom Evaluation-Server für die gegebene Task ID herunter.
111
- Args:
112
- task_id (str): Eindeutige Kennung der Aufgabe.
113
- Returns:
114
- str: Lokaler Pfad der heruntergeladenen Datei oder Fehlermeldung.
115
- """
116
- print(f"Tool: download_task_file(task_id='{task_id}')")
117
- file_url = f"{DEFAULT_API_URL}/files/{task_id}"
118
  try:
119
- response = requests.get(file_url, stream=True, timeout=30)
120
- response.raise_for_status()
121
- content_type = response.headers.get('content-type', '').lower()
122
- suffix = ".tmp"
123
- if 'pdf' in content_type: suffix = ".pdf"
124
- elif 'png' in content_type: suffix = ".png"
125
- elif 'jpeg' in content_type or 'jpg' in content_type: suffix = ".jpg"
126
- elif 'csv' in content_type: suffix = ".csv"
127
- temp_dir = tempfile.gettempdir()
128
- safe_id = re.sub(r'[^\w\-]+', '_', task_id)
129
- timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")
130
- path = os.path.join(temp_dir, f"gaia_task_{safe_id}_{timestamp}{suffix}")
131
  with open(path, 'wb') as f:
132
- for chunk in response.iter_content(8192):
133
- f.write(chunk)
134
  temp_files_to_clean.add(path)
135
  return path
136
- except requests.exceptions.HTTPError as e:
137
- if e.response.status_code == 404:
138
- return "Error: No file found for this task ID."
139
- return f"Error: Failed to download file (HTTP {e.response.status_code})."
140
  except Exception as e:
141
- return f"Error: Unexpected error during file download: {e}"
142
 
143
  @tool
144
  def read_file_content(file_path: str) -> str:
145
- """
146
- Liest den Text einer heruntergeladenen Datei (PDF oder Text).
147
- Args:
148
- file_path (str): Absoluter Pfad zur Datei.
149
- Returns:
150
- str: Extrahierter Text oder Fehlermeldung.
151
- """
152
- print(f"Tool: read_file_content(file_path='{file_path}')")
153
- if not os.path.isabs(file_path) or not file_path.startswith(tempfile.gettempdir()):
154
- return "Error: Invalid file path provided."
155
- if not os.path.exists(file_path):
156
- return f"Error: File not found '{file_path}'."
157
  try:
158
- if file_path.lower().endswith('.pdf'):
159
- if not PDF_READER_AVAILABLE:
160
- return "Error: PyPDF2 not installed."
161
- text = ""
162
  with open(file_path, 'rb') as f:
163
- reader = PyPDF2.PdfReader(f)
164
- for p in reader.pages:
165
- text += p.extract_text() or ''
166
- if len(text) > 7000:
167
- text = text[:7000] + "\n... (truncated)"
168
- break
169
- return f"Content of '{os.path.basename(file_path)}':\n{text}"
170
  else:
171
- with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
172
- content = f.read(7000)
173
- return f"Content of '{os.path.basename(file_path)}':\n{content}"
174
  except Exception as e:
175
- return f"Error: Failed to read file: {e}"
176
 
177
- # --- Agent Initialisierung ---
178
  def initialize_agent():
179
  global search_client, agent_instance
180
  if search_client is None:
181
  if USE_TAVILY:
182
- key = os.getenv("TAVILY_API_KEY")
183
- if key:
184
- try: search_client = TavilyClient(api_key=key)
185
- except: search_client = False
186
- else:
187
- search_client = False
188
  elif USE_DUCKDUCKGO:
189
- try: search_client = DDGS()
190
- except: search_client = False
191
  else:
192
  search_client = False
193
- token = os.getenv("HUGGINGFACE_TOKEN")
194
  if not token:
195
- raise ValueError("HUGGINGFACE_TOKEN Secret nicht gefunden!")
196
  hf_model = HfApiModel()
197
  tools = [search_web, download_task_file, read_file_content]
198
- if search_client is False:
199
- tools = [t for t in tools if t != search_web]
200
  agent_instance = CodeAgent(tools=tools, model=hf_model)
201
 
202
- # --- Hauptfunktion run_and_submit_all ---
203
  def run_and_submit_all(profile, progress=gr.Progress(track_tqdm=True)):
204
- if not profile:
205
- return "Bitte zuerst mit Hugging Face einloggen.", None
206
- username = profile.username if hasattr(profile, 'username') else profile['username']
207
- api_url = DEFAULT_API_URL
 
 
 
208
  try:
209
  initialize_agent()
210
  except Exception as e:
211
- return f"Fehler bei der Agent-Initialisierung: {e}", None
212
- questions = requests.get(f"{api_url}/questions", timeout=30).json()
213
- answers_log = []
214
- payload = []
215
- for item in progress.tqdm(questions, desc="Bearbeite Fragen"):
216
- task_id = item.get("task_id")
217
- question = item.get("question")
218
- if not task_id or question is None:
219
- continue
220
- prompt = f"... Task {task_id}: {question}"
221
  try:
222
- resp = agent_instance.run(prompt=prompt)
223
- ans = re.sub(r"^(Answer:|Final Answer:)", "", resp or "").strip()
224
  except Exception as e:
225
  ans = f"ERROR: {e}"
226
- answers_log.append({"Task ID": task_id, "Question": question, "Submitted Answer": ans})
227
- payload.append({"task_id": task_id, "submitted_answer": ans})
228
- df = pd.DataFrame(answers_log)
229
- submission = {"username": username, "agent_code": "...", "answers": payload}
 
 
230
  try:
231
- r = requests.post(f"{api_url}/submit", json=submission, timeout=180)
232
  r.raise_for_status()
233
- res = r.json()
234
- status = f"Erfolg! Score: {res.get('score', 0):.2f}%"
235
  except Exception as e:
236
- status = f"Fehler bei der Submission: {e}"
237
  cleanup_temp_files()
238
  return status, df
239
 
240
- # --- Gradio Interface ---
241
  with gr.Blocks() as demo:
242
  gr.Markdown("# Smol CodeAgent Evaluation Runner")
243
  gr.Markdown("Bitte einloggen und dann auf Ausführen klicken.")
244
- with gr.Row():
245
- login_button = gr.LoginButton()
246
- run_button = gr.Button("Run Evaluation & Submit All Answers")
247
- status_output = gr.Textbox(label="Status", lines=5)
248
- results_table = gr.DataFrame(label="Ergebnisse")
249
 
250
- run_button.click(
251
  fn=run_and_submit_all,
252
- inputs=[login_button],
253
- outputs=[status_output, results_table],
254
  api_name="run_evaluation_smol_codeagent"
255
  )
256
 
257
- if __name__ == "__main__":
258
  demo.queue().launch(debug=False, share=False)
 
3
  import requests
4
  import pandas as pd
5
  import re
6
+ import json
7
  from datetime import datetime
 
8
  import tempfile
9
  import atexit
10
  import sys # Für sys.exit bei Importfehlern
11
 
12
+ # --- Smol Agents und HF Imports ---
13
  try:
14
  from smolagents import CodeAgent, tool, HfApiModel
15
  print("Successfully imported CodeAgent, tool, HfApiModel from 'smolagents'")
16
  except ImportError as e:
17
  print(f"Error importing from smolagents: {e}")
18
  print("Please ensure 'smolagents[huggingface]' is listed correctly in requirements.txt")
19
+ sys.exit(f"Fatal Error: Could not import smolagents components. Original error: {e}")
20
 
21
  from huggingface_hub import HfApi
22
 
 
43
  PDF_READER_AVAILABLE = True
44
  except ImportError:
45
  PDF_READER_AVAILABLE = False
46
+ print("WARNUNG: PyPDF2 nicht installiert. PDF-Lesefunktion deaktiviert.")
47
 
48
+ # --- Konstanten & Globals ---
49
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
50
  HF_MODEL_ID = os.getenv("HF_MODEL_ID", "meta-llama/Meta-Llama-3-8B-Instruct")
 
 
51
  search_client = None
52
  agent_instance = None
53
 
54
  temp_files_to_clean = set()
55
 
56
  def cleanup_temp_files():
57
+ for path in list(temp_files_to_clean):
 
58
  try:
59
+ if os.path.exists(path): os.remove(path)
60
+ except OSError:
61
+ pass
62
+ temp_files_to_clean.discard(path)
 
 
 
63
  atexit.register(cleanup_temp_files)
64
 
65
+ # --- Tool Definitions ---
66
  @tool
67
  def search_web(query: str, max_results: int = 3) -> str:
68
  """
69
+ Websuche via Tavily oder DuckDuckGo.
 
 
 
 
 
70
  """
 
71
  if not search_client:
72
+ return "Search tool not configured."
73
  try:
74
  if USE_TAVILY and isinstance(search_client, TavilyClient):
75
+ res = search_client.search(query=query, search_depth="basic", max_results=max_results)
76
+ items = res.get('results', [])
77
+ return "\n".join([f"URL: {i['url']}\n{ i['content'][:200] }..." for i in items])
 
 
 
 
78
  elif USE_DUCKDUCKGO and isinstance(search_client, DDGS):
79
  results = search_client.text(query, max_results=max_results)
80
+ return "\n".join([f"Title: {r['title']}\nURL: {r['href']}\n{r['body'][:200]}..." for r in results])
 
 
 
 
 
 
81
  except Exception as e:
 
82
  return f"Error during search: {e}"
83
+ return "No results."
84
 
85
  @tool
86
  def download_task_file(task_id: str) -> str:
87
+ """Download einer Datei zur Task ID vom Server."""
88
+ url = f"{DEFAULT_API_URL}/files/{task_id}"
 
 
 
 
 
 
 
89
  try:
90
+ r = requests.get(url, stream=True, timeout=30)
91
+ r.raise_for_status()
92
+ ct = r.headers.get('content-type', '')
93
+ suffix = '.pdf' if 'pdf' in ct else '.tmp'
94
+ tmp = tempfile.gettempdir()
95
+ name = f"task_{task_id}_{datetime.now().strftime('%Y%m%d%H%M%S')}{suffix}"
96
+ path = os.path.join(tmp, name)
 
 
 
 
 
97
  with open(path, 'wb') as f:
98
+ for chunk in r.iter_content(8192): f.write(chunk)
 
99
  temp_files_to_clean.add(path)
100
  return path
 
 
 
 
101
  except Exception as e:
102
+ return f"Error: {e}"
103
 
104
  @tool
105
  def read_file_content(file_path: str) -> str:
106
+ """Liest Text aus einer heruntergeladenen Datei."""
107
+ if not file_path.startswith(tempfile.gettempdir()):
108
+ return "Error: Invalid path."
 
 
 
 
 
 
 
 
 
109
  try:
110
+ if file_path.endswith('.pdf'):
111
+ if not PDF_READER_AVAILABLE: return "Error: PyPDF2 fehlt."
112
+ txt = ''
 
113
  with open(file_path, 'rb') as f:
114
+ rdr = PyPDF2.PdfReader(f)
115
+ for p in rdr.pages:
116
+ txt += p.extract_text() or ''
117
+ if len(txt) > 5000: break
118
+ return txt
 
 
119
  else:
120
+ return open(file_path, 'r', encoding='utf-8', errors='ignore').read(5000)
 
 
121
  except Exception as e:
122
+ return f"Error: {e}"
123
 
124
+ # --- Agent Setup ---
125
  def initialize_agent():
126
  global search_client, agent_instance
127
  if search_client is None:
128
  if USE_TAVILY:
129
+ key = os.getenv('TAVILY_API_KEY')
130
+ search_client = TavilyClient(api_key=key) if key else False
 
 
 
 
131
  elif USE_DUCKDUCKGO:
132
+ search_client = DDGS()
 
133
  else:
134
  search_client = False
135
+ token = os.getenv('HUGGINGFACE_TOKEN')
136
  if not token:
137
+ raise ValueError("HUGGINGFACE_TOKEN fehlt.")
138
  hf_model = HfApiModel()
139
  tools = [search_web, download_task_file, read_file_content]
140
+ if not search_client: tools = [t for t in tools if t != search_web]
 
141
  agent_instance = CodeAgent(tools=tools, model=hf_model)
142
 
143
+ # --- Hauptfunktion ---
144
  def run_and_submit_all(profile, progress=gr.Progress(track_tqdm=True)):
145
+ # Profil parsen (evtl. JSON-String)
146
+ if isinstance(profile, str):
147
+ try: profile = json.loads(profile)
148
+ except: return "Ungültiges Profilformat.", None
149
+ if not profile or 'username' not in profile:
150
+ return "Bitte zuerst einloggen.", None
151
+ username = profile['username']
152
  try:
153
  initialize_agent()
154
  except Exception as e:
155
+ return f"Init-Error: {e}", None
156
+
157
+ # Fragen holen
158
+ questions = requests.get(f"{DEFAULT_API_URL}/questions").json()
159
+ logs, payload = [], []
160
+ for item in progress.tqdm(questions, desc="Bearbeite" ):
161
+ tid, q = item.get('task_id'), item.get('question')
162
+ if not tid or not q: continue
163
+ prompt = f"Task {tid}: {q}"
 
164
  try:
165
+ res = agent_instance.run(prompt=prompt)
166
+ ans = re.sub(r"^(Answer:|Final Answer:)", "", res or "").strip()
167
  except Exception as e:
168
  ans = f"ERROR: {e}"
169
+ logs.append({'Task ID': tid, 'Question': q, 'Submitted Answer': ans})
170
+ payload.append({'task_id': tid, 'submitted_answer': ans})
171
+ df = pd.DataFrame(logs)
172
+
173
+ # Submission
174
+ sub = {'username': username, 'agent_code': '...', 'answers': payload}
175
  try:
176
+ r = requests.post(f"{DEFAULT_API_URL}/submit", json=sub, timeout=180)
177
  r.raise_for_status()
178
+ status = f"Erfolg: {r.json().get('score',0):.2f}%"
 
179
  except Exception as e:
180
+ status = f"Submit-Error: {e}"
181
  cleanup_temp_files()
182
  return status, df
183
 
184
+ # --- Gradio UI ---
185
  with gr.Blocks() as demo:
186
  gr.Markdown("# Smol CodeAgent Evaluation Runner")
187
  gr.Markdown("Bitte einloggen und dann auf Ausführen klicken.")
188
+ with gr.Row(): login_btn = gr.LoginButton()
189
+ run_btn = gr.Button("Run Evaluation & Submit All Answers")
190
+ out_status = gr.Textbox(label="Status", lines=5)
191
+ out_table = gr.DataFrame(label="Ergebnisse")
 
192
 
193
+ run_btn.click(
194
  fn=run_and_submit_all,
195
+ inputs=[login_btn],
196
+ outputs=[out_status, out_table],
197
  api_name="run_evaluation_smol_codeagent"
198
  )
199
 
200
+ if __name__ == '__main__':
201
  demo.queue().launch(debug=False, share=False)