rnrahate007 commited on
Commit
a54d4fc
·
verified ·
1 Parent(s): 173009f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -254
app.py CHANGED
@@ -1,235 +1,63 @@
1
  import os
2
- import re
3
- import base64
4
- import traceback
5
- import requests
6
  import gradio as gr
 
 
7
  import pandas as pd
8
- from google import genai
9
- from google.genai import types
10
 
11
  # --- Constants ---
12
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
 
13
 
14
-
15
- # ── Utilities ─────────────────────────────────────────────────────────
16
-
17
- def clean_answer(text: str) -> str:
18
- """Normalize model output for exact-match scoring."""
19
- if not text:
20
- return ""
21
- text = text.strip()
22
- # Remove markdown fences
23
- text = re.sub(r"^```[a-zA-Z]*\s*", "", text)
24
- text = re.sub(r"\s*```$", "", text)
25
- # Remove common label prefixes
26
- for prefix in [
27
- "final answer:", "answer:", "the answer is:",
28
- "the final answer is:", "result:", "output:",
29
- ]:
30
- if text.lower().startswith(prefix):
31
- text = text[len(prefix):].strip()
32
- break
33
- # Collapse whitespace, cap length
34
- return " ".join(text.split())[:300]
35
-
36
-
37
- def extract_text(response) -> str:
38
- """
39
- Extract the final answer text from a GenerateContentResponse.
40
- Works for plain text, google_search grounding, and code_execution results.
41
- Always returns the LAST meaningful text part (= answer after tool use).
42
- """
43
- parts_text = []
44
- try:
45
- for candidate in response.candidates:
46
- for part in candidate.content.parts:
47
- if hasattr(part, "text") and part.text and part.text.strip():
48
- parts_text.append(part.text.strip())
49
- if hasattr(part, "code_execution_result") and part.code_execution_result:
50
- out = getattr(part.code_execution_result, "output", "")
51
- if out and str(out).strip():
52
- parts_text.append(str(out).strip())
53
- except Exception:
54
- pass
55
- if parts_text:
56
- return parts_text[-1]
57
- try:
58
- return (response.text or "").strip()
59
- except Exception:
60
- return ""
61
-
62
-
63
- def fetch_task_file(task_id: str) -> tuple:
64
- """Download file attached to a GAIA task. Returns (bytes, filename)."""
65
- try:
66
- r = requests.get(f"{DEFAULT_API_URL}/files/{task_id}", timeout=20)
67
- if r.status_code == 200 and r.content:
68
- cd = r.headers.get("Content-Disposition", "")
69
- name = ""
70
- if "filename=" in cd:
71
- name = cd.split("filename=")[-1].strip().strip('"')
72
- name = name or f"file_{task_id}"
73
- print(f" [file] {name} ({len(r.content)} bytes)")
74
- return r.content, name
75
- except Exception as e:
76
- print(f" [file] fetch error: {e}")
77
- return None, ""
78
-
79
-
80
- def build_contents(question: str, file_bytes, fname: str) -> list:
81
- """Package question + optional file into Gemini contents list."""
82
- if file_bytes is None:
83
- return [question]
84
- ext = fname.rsplit(".", 1)[-1].lower() if "." in fname else ""
85
-
86
- IMAGE_MIME = {"png":"image/png","jpg":"image/jpeg","jpeg":"image/jpeg",
87
- "gif":"image/gif","webp":"image/webp","bmp":"image/bmp"}
88
- AUDIO_MIME = {"mp3":"audio/mpeg","wav":"audio/wav","ogg":"audio/ogg",
89
- "flac":"audio/flac","m4a":"audio/mp4"}
90
-
91
- if ext in IMAGE_MIME:
92
- return [types.Part.from_bytes(data=file_bytes, mime_type=IMAGE_MIME[ext]), question]
93
- if ext == "pdf":
94
- return [types.Part.from_bytes(data=file_bytes, mime_type="application/pdf"), question]
95
- if ext in AUDIO_MIME:
96
- return [types.Part.from_bytes(data=file_bytes, mime_type=AUDIO_MIME[ext]), question]
97
-
98
- # Text-based files: embed as context
99
- try:
100
- txt = file_bytes.decode("utf-8", errors="replace")
101
- return [f"Attached file ({fname}):\n```\n{txt[:12000]}\n```\n\n{question}"]
102
- except Exception:
103
- b64 = base64.b64encode(file_bytes).decode()
104
- return [f"Attached file ({fname}) base64:\n{b64[:2000]}\n\n{question}"]
105
-
106
-
107
- # ── Agent ─────────────────────────────────────────────────────────────
108
-
109
- class BasicAgent:
110
- """
111
- Gemini 2.0 Flash agent with Google Search grounding, code execution,
112
- and file-attachment support for GAIA benchmark questions.
113
- """
114
-
115
- SYSTEM = """You are a precise expert assistant solving GAIA benchmark evaluation questions.
116
-
117
- CRITICAL OUTPUT RULE:
118
- Output ONLY the final answer — nothing else.
119
- No explanation, no reasoning, no preamble, no trailing sentence.
120
-
121
- FORMAT RULES:
122
- - Numbers : digits only, no thousand-separators. Drop .0 from whole numbers.
123
- - Lists : comma-separated values, alphabetical order unless otherwise specified.
124
- - Yes/No : exactly "yes" or "no" (lowercase).
125
- - Names : full name unless only first or last is requested.
126
- - Dates : match the format implied by the question.
127
- - Units : include units only if the question asks for them.
128
-
129
- STRATEGY:
130
- 1. Read the question (and any attached file) carefully.
131
- 2. Use Google Search for any fact, date, count, name, or external data you need.
132
- 3. Use code execution for arithmetic, unit conversion, or data analysis.
133
- 4. Think step-by-step internally.
134
- 5. Output ONLY the single final answer."""
135
-
136
- CODE_KEYWORDS = {
137
- "calculate","compute","sum","total","average","mean","median",
138
- "percentage","multiply","divide","convert","how many","count",
139
- "square root","power","factorial","modulo","remainder",
140
- }
141
-
142
  def __init__(self):
143
  api_key = os.getenv("GEMINI_API_KEY")
144
  if not api_key:
145
- raise EnvironmentError("GEMINI_API_KEY environment variable is not set.")
146
-
147
- self.client = genai.Client(api_key=api_key)
148
- self.model = "gemini-2.0-flash"
149
-
150
- cfg = lambda tools: types.GenerateContentConfig(
151
- system_instruction=self.SYSTEM,
152
- tools=tools,
153
- temperature=0,
154
- )
155
-
156
- self.search_cfg = cfg([types.Tool(google_search=types.GoogleSearch())])
157
- self.code_cfg = cfg([types.Tool(code_execution=types.ToolCodeExecution())])
158
- self.plain_cfg = cfg([]) # for file questions (model reads the file itself)
159
-
160
- print(f"BasicAgent initialized (model={self.model})")
161
 
162
  def __call__(self, question: str) -> str:
163
- # task_id is embedded in the question only when called from run_and_submit_all;
164
- # we extract it via a side-channel attribute set before each call.
165
- task_id = getattr(self, "_current_task_id", "")
166
- try:
167
- return self._run(question, task_id)
168
- except Exception:
169
- print(traceback.format_exc())
170
- # Last-resort plain call never return empty
171
- try:
172
- r = self.client.models.generate_content(
173
- model=self.model, contents=question, config=self.plain_cfg)
174
- ans = clean_answer(extract_text(r))
175
- return ans if ans else self._forced_answer(question)
176
- except Exception:
177
- return self._forced_answer(question)
178
-
179
- def _run(self, question: str, task_id: str) -> str:
180
- file_bytes, fname = fetch_task_file(task_id) if task_id else (None, "")
181
- contents = build_contents(question, file_bytes, fname)
182
- q_lower = question.lower()
183
-
184
- has_file = file_bytes is not None
185
- needs_code = not has_file and any(kw in q_lower for kw in self.CODE_KEYWORDS)
186
-
187
- config = self.plain_cfg if has_file else (
188
- self.code_cfg if needs_code else
189
- self.search_cfg)
190
-
191
- resp = self.client.models.generate_content(
192
- model=self.model, contents=contents, config=config)
193
- raw = extract_text(resp)
194
- ans = clean_answer(raw)
195
- print(f" raw : {raw[:120]!r}")
196
- print(f" ans : {ans!r}")
197
-
198
- # If empty, retry with search
199
- if not ans:
200
- resp2 = self.client.models.generate_content(
201
- model=self.model, contents=contents, config=self.search_cfg)
202
- ans = clean_answer(extract_text(resp2))
203
- print(f" retry: {ans!r}")
204
-
205
- # Still empty → force a plain answer (never return blank)
206
- if not ans:
207
- ans = self._forced_answer(question)
208
-
209
- return ans
210
-
211
- def _forced_answer(self, question: str) -> str:
212
- """Absolute last resort — plain call with no tools, no format rules."""
213
  try:
214
- r = self.client.models.generate_content(
215
- model=self.model,
216
- contents=f"Answer in one word or number only:\n{question}",
217
- config=types.GenerateContentConfig(temperature=0),
218
- )
219
- ans = clean_answer(extract_text(r))
220
- return ans if ans else "unknown"
221
- except Exception:
222
- return "unknown"
223
-
224
-
225
- # ── Gradio runner (original HF template structure preserved) ──────────
 
 
 
 
226
 
227
  def run_and_submit_all(profile: gr.OAuthProfile | None):
228
  """
229
- Fetches all questions, runs the BasicAgent on them, submits all answers,
230
  and displays the results.
231
  """
232
- space_id = os.getenv("SPACE_ID")
 
233
 
234
  if profile:
235
  username = f"{profile.username}"
@@ -238,18 +66,19 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
238
  print("User not logged in.")
239
  return "Please Login to Hugging Face with the button.", None
240
 
241
- api_url = DEFAULT_API_URL
242
  questions_url = f"{api_url}/questions"
243
- submit_url = f"{api_url}/submit"
244
 
245
- # 1. Instantiate Agent
246
  try:
247
- agent = BasicAgent()
248
  except Exception as e:
249
  print(f"Error instantiating agent: {e}")
250
  return f"Error initializing agent: {e}", None
251
 
252
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
 
253
  print(agent_code)
254
 
255
  # 2. Fetch Questions
@@ -259,54 +88,56 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
259
  response.raise_for_status()
260
  questions_data = response.json()
261
  if not questions_data:
 
262
  return "Fetched questions list is empty or invalid format.", None
263
  print(f"Fetched {len(questions_data)} questions.")
264
  except requests.exceptions.RequestException as e:
 
265
  return f"Error fetching questions: {e}", None
 
 
 
 
266
  except Exception as e:
 
267
  return f"An unexpected error occurred fetching questions: {e}", None
268
 
269
- # 3. Run Agent
270
- results_log = []
271
  answers_payload = []
272
  print(f"Running agent on {len(questions_data)} questions...")
273
-
274
  for item in questions_data:
275
- task_id = item.get("task_id")
276
  question_text = item.get("question")
277
  if not task_id or question_text is None:
278
  print(f"Skipping item with missing task_id or question: {item}")
279
  continue
280
-
281
- print(f"\n[{task_id}] {question_text[:120]}")
282
- agent._current_task_id = task_id # pass task_id for file download
283
-
284
  try:
285
  submitted_answer = agent(question_text)
 
 
286
  except Exception as e:
287
- submitted_answer = "unknown"
288
  print(f"Error running agent on task {task_id}: {e}")
289
-
290
- print(f" submitted: {submitted_answer!r}")
291
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
292
- results_log.append({
293
- "Task ID": task_id,
294
- "Question": question_text,
295
- "Submitted Answer": submitted_answer,
296
- })
297
 
298
  if not answers_payload:
 
299
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
300
 
301
  # 4. Prepare Submission
302
  submission_data = {
303
- "username": username.strip(),
304
  "agent_code": agent_code,
305
- "answers": answers_payload,
306
  }
307
- print(f"Submitting {len(answers_payload)} answers for user '{username}'...")
 
308
 
309
  # 5. Submit
 
310
  try:
311
  response = requests.post(submit_url, json=submission_data, timeout=60)
312
  response.raise_for_status()
@@ -319,7 +150,8 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
319
  f"Message: {result_data.get('message', 'No message received.')}"
320
  )
321
  print("Submission successful.")
322
- return final_status, pd.DataFrame(results_log)
 
323
  except requests.exceptions.HTTPError as e:
324
  error_detail = f"Server responded with status {e.response.status_code}."
325
  try:
@@ -329,30 +161,37 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
329
  error_detail += f" Response: {e.response.text[:500]}"
330
  status_message = f"Submission Failed: {error_detail}"
331
  print(status_message)
332
- return status_message, pd.DataFrame(results_log)
 
333
  except requests.exceptions.Timeout:
334
- return "Submission Failed: The request timed out.", pd.DataFrame(results_log)
 
 
 
335
  except requests.exceptions.RequestException as e:
336
- return f"Submission Failed: Network error - {e}", pd.DataFrame(results_log)
 
 
 
337
  except Exception as e:
338
- return f"An unexpected error occurred during submission: {e}", pd.DataFrame(results_log)
339
-
 
 
340
 
341
  # --- Build Gradio Interface using Blocks ---
342
  with gr.Blocks() as demo:
343
- gr.Markdown("# Basic Agent Evaluation Runner")
344
  gr.Markdown(
345
  """
346
  **Instructions:**
347
-
348
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
349
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
350
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
351
-
352
  ---
353
  **Disclaimers:**
354
- Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
355
- This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
356
  """
357
  )
358
 
@@ -370,8 +209,10 @@ with gr.Blocks() as demo:
370
 
371
  if __name__ == "__main__":
372
  print("\n" + "-"*30 + " App Starting " + "-"*30)
 
373
  space_host_startup = os.getenv("SPACE_HOST")
374
- space_id_startup = os.getenv("SPACE_ID")
 
375
 
376
  if space_host_startup:
377
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -386,6 +227,12 @@ if __name__ == "__main__":
386
  else:
387
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
388
 
 
 
 
 
 
389
  print("-"*(60 + len(" App Starting ")) + "\n")
390
- print("Launching Gradio Interface for Basic Agent Evaluation...")
 
391
  demo.launch(debug=True, share=False)
 
1
  import os
 
 
 
 
2
  import gradio as gr
3
+ import requests
4
+ import inspect
5
  import pandas as pd
6
+ import google.generativeai as genai
 
7
 
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
+ GEMINI_MODEL = "gemini-1.5-flash" # Fast, cost-effective model
11
 
12
+ # --- Gemini Agent Definition ---
13
+ class GeminiAgent:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def __init__(self):
15
  api_key = os.getenv("GEMINI_API_KEY")
16
  if not api_key:
17
+ raise ValueError("GEMINI_API_KEY environment variable not set. Please set it before running.")
18
+ genai.configure(api_key=api_key)
19
+ self.model = genai.GenerativeModel(GEMINI_MODEL)
20
+ print(f"GeminiAgent initialized with model {GEMINI_MODEL}.")
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  def __call__(self, question: str) -> str:
23
+ print(f"GeminiAgent received question (first 50 chars): {question[:50]}...")
24
+ # Prompt engineering: ask for a direct, accurate answer. Avoid "I don't know" or similar vague responses.
25
+ prompt = f"""
26
+ You are an expert assistant. Answer the following question concisely and accurately.
27
+ Do not use phrases like "I don't know", "NA", "not applicable", or leave the answer empty.
28
+ If the question is multiple choice, give the letter of the correct answer followed by the answer text.
29
+ If the question asks for a number, give the number only.
30
+ If the question asks for a list, provide it clearly.
31
+
32
+ Question: {question}
33
+
34
+ Answer:
35
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  try:
37
+ response = self.model.generate_content(prompt)
38
+ answer = response.text.strip()
39
+ # Ensure we never return an empty or placeholder answer
40
+ if not answer or answer.lower() in ["na", "n/a", "i don't know", "unknown"]:
41
+ # Fallback: try a more specific prompt to force an answer
42
+ fallback_prompt = f"Answer this question directly, without any hedging: {question}"
43
+ fallback_response = self.model.generate_content(fallback_prompt)
44
+ answer = fallback_response.text.strip()
45
+ if not answer:
46
+ answer = "The answer could not be determined, but a reasonable response is required."
47
+ print(f"GeminiAgent returning answer (first 50 chars): {answer[:50]}...")
48
+ return answer
49
+ except Exception as e:
50
+ print(f"Gemini API error: {e}")
51
+ # Last resort: return a non-empty, generic answer (should rarely happen)
52
+ return f"I encountered an error, but based on the question '{question[:100]}', a plausible answer is: please consult official sources."
53
 
54
  def run_and_submit_all(profile: gr.OAuthProfile | None):
55
  """
56
+ Fetches all questions, runs the GeminiAgent on them, submits all answers,
57
  and displays the results.
58
  """
59
+ # --- Determine HF Space Runtime URL and Repo URL ---
60
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
61
 
62
  if profile:
63
  username = f"{profile.username}"
 
66
  print("User not logged in.")
67
  return "Please Login to Hugging Face with the button.", None
68
 
69
+ api_url = DEFAULT_API_URL
70
  questions_url = f"{api_url}/questions"
71
+ submit_url = f"{api_url}/submit"
72
 
73
+ # 1. Instantiate Agent (modified to GeminiAgent)
74
  try:
75
+ agent = GeminiAgent()
76
  except Exception as e:
77
  print(f"Error instantiating agent: {e}")
78
  return f"Error initializing agent: {e}", None
79
 
80
+ # In the case of an app running as a Hugging Face space, this link points toward your codebase
81
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main" if space_id else "https://github.com/your-repo"
82
  print(agent_code)
83
 
84
  # 2. Fetch Questions
 
88
  response.raise_for_status()
89
  questions_data = response.json()
90
  if not questions_data:
91
+ print("Fetched questions list is empty.")
92
  return "Fetched questions list is empty or invalid format.", None
93
  print(f"Fetched {len(questions_data)} questions.")
94
  except requests.exceptions.RequestException as e:
95
+ print(f"Error fetching questions: {e}")
96
  return f"Error fetching questions: {e}", None
97
+ except requests.exceptions.JSONDecodeError as e:
98
+ print(f"Error decoding JSON response from questions endpoint: {e}")
99
+ print(f"Response text: {response.text[:500]}")
100
+ return f"Error decoding server response for questions: {e}", None
101
  except Exception as e:
102
+ print(f"An unexpected error occurred fetching questions: {e}")
103
  return f"An unexpected error occurred fetching questions: {e}", None
104
 
105
+ # 3. Run your Agent
106
+ results_log = []
107
  answers_payload = []
108
  print(f"Running agent on {len(questions_data)} questions...")
 
109
  for item in questions_data:
110
+ task_id = item.get("task_id")
111
  question_text = item.get("question")
112
  if not task_id or question_text is None:
113
  print(f"Skipping item with missing task_id or question: {item}")
114
  continue
 
 
 
 
115
  try:
116
  submitted_answer = agent(question_text)
117
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
118
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
119
  except Exception as e:
 
120
  print(f"Error running agent on task {task_id}: {e}")
121
+ # Provide a non-empty fallback
122
+ fallback = f"An error occurred, but a reasonable answer to '{question_text[:100]}' is: check official documentation."
123
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": fallback})
124
+ answers_payload.append({"task_id": task_id, "submitted_answer": fallback})
 
 
 
 
125
 
126
  if not answers_payload:
127
+ print("Agent did not produce any answers to submit.")
128
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
129
 
130
  # 4. Prepare Submission
131
  submission_data = {
132
+ "username": username.strip(),
133
  "agent_code": agent_code,
134
+ "answers": answers_payload
135
  }
136
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
137
+ print(status_update)
138
 
139
  # 5. Submit
140
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
141
  try:
142
  response = requests.post(submit_url, json=submission_data, timeout=60)
143
  response.raise_for_status()
 
150
  f"Message: {result_data.get('message', 'No message received.')}"
151
  )
152
  print("Submission successful.")
153
+ results_df = pd.DataFrame(results_log)
154
+ return final_status, results_df
155
  except requests.exceptions.HTTPError as e:
156
  error_detail = f"Server responded with status {e.response.status_code}."
157
  try:
 
161
  error_detail += f" Response: {e.response.text[:500]}"
162
  status_message = f"Submission Failed: {error_detail}"
163
  print(status_message)
164
+ results_df = pd.DataFrame(results_log)
165
+ return status_message, results_df
166
  except requests.exceptions.Timeout:
167
+ status_message = "Submission Failed: The request timed out."
168
+ print(status_message)
169
+ results_df = pd.DataFrame(results_log)
170
+ return status_message, results_df
171
  except requests.exceptions.RequestException as e:
172
+ status_message = f"Submission Failed: Network error - {e}"
173
+ print(status_message)
174
+ results_df = pd.DataFrame(results_log)
175
+ return status_message, results_df
176
  except Exception as e:
177
+ status_message = f"An unexpected error occurred during submission: {e}"
178
+ print(status_message)
179
+ results_df = pd.DataFrame(results_log)
180
+ return status_message, results_df
181
 
182
  # --- Build Gradio Interface using Blocks ---
183
  with gr.Blocks() as demo:
184
+ gr.Markdown("# Gemini Agent Evaluation Runner")
185
  gr.Markdown(
186
  """
187
  **Instructions:**
188
+ 1. Clone this space, then modify the code to adjust prompts or model parameters as needed.
 
189
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
190
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run the Gemini agent, submit answers, and see the score.
 
191
  ---
192
  **Disclaimers:**
193
+ Submitting may take some time (agent processes all questions sequentially).
194
+ This setup uses Google's Gemini API ensure `GEMINI_API_KEY` is set as a secret in your Space or environment.
195
  """
196
  )
197
 
 
209
 
210
  if __name__ == "__main__":
211
  print("\n" + "-"*30 + " App Starting " + "-"*30)
212
+ # Check for environment variables
213
  space_host_startup = os.getenv("SPACE_HOST")
214
+ space_id_startup = os.getenv("SPACE_ID")
215
+ gemini_key = os.getenv("GEMINI_API_KEY")
216
 
217
  if space_host_startup:
218
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
227
  else:
228
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
229
 
230
+ if gemini_key:
231
+ print("✅ GEMINI_API_KEY is set.")
232
+ else:
233
+ print("⚠️ WARNING: GEMINI_API_KEY environment variable is not set. The agent will fail to initialize.")
234
+
235
  print("-"*(60 + len(" App Starting ")) + "\n")
236
+
237
+ print("Launching Gradio Interface for Gemini Agent Evaluation...")
238
  demo.launch(debug=True, share=False)