dawid-lorek commited on
Commit
448bb86
·
verified ·
1 Parent(s): 4910a87

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -174
app.py CHANGED
@@ -1,160 +1,109 @@
1
- import requests
2
  import os
3
  import gradio as gr
 
4
  import pandas as pd
5
- import time
6
- import re
7
- import json
8
- import wikipedia
9
- import speech_recognition as sr
10
- from pydub import AudioSegment
11
- from langchain_openai import ChatOpenAI
12
- from langchain.agents import AgentExecutor, create_react_agent
13
- from langchain.memory import ConversationSummaryMemory
14
- from langchain.tools import Tool
15
- from langchain.tools.python.tool import PythonREPLTool
16
- from langchain_community.document_loaders import WikipediaLoader
17
- from langchain.prompts import PromptTemplate
18
 
 
19
  # --- Constants ---
20
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
21
 
22
- # === TOOL: python_repl ===
23
- repl_tool = PythonREPLTool(
24
- name="python_repl",
25
- description="A Python REPL for calculations and parsing. Input must be valid Python code, use print() to output results."
26
- )
27
 
28
- # === TOOL: file_saver ===
29
- def download_and_save_file(args: dict) -> str:
30
- try:
31
- if isinstance(args, str):
32
- args = json.loads(args)
33
- url = args.get("url")
34
- local_filename = args.get("local_filename")
35
- if not url or not local_filename:
36
- return "Error: Both 'url' and 'local_filename' must be provided."
37
- response = requests.get(url, stream=True, timeout=30)
 
 
 
 
 
38
  response.raise_for_status()
39
- os.makedirs(os.path.dirname(local_filename) or '.', exist_ok=True)
40
- with open(local_filename, 'wb') as f:
41
- for chunk in response.iter_content(chunk_size=8192):
42
- f.write(chunk)
43
- return f"File downloaded successfully to {local_filename}"
44
- except Exception as e:
45
- return f"Error downloading file: {e}"
46
 
47
- file_saver_tool = Tool(
48
- name="file_saver",
49
- description="Downloads a file from a URL and saves it as the given local filename. Input: JSON with 'url' and 'local_filename'.",
50
- func=download_and_save_file,
51
- )
 
 
52
 
53
- # === TOOL: audio_transcriber_tool ===
54
- def transcribe_audio_from_path(local_audio_path: str, language: str = "en-US") -> str:
55
- r = sr.Recognizer()
56
- temp_wav_path = "temp_audio_to_transcribe.wav"
57
- transcribed_text = ""
58
- try:
59
- if local_audio_path.startswith("http://") or local_audio_path.startswith("https://"):
60
- return "Error: Only local file paths allowed. Use 'file_saver' first."
61
- if not os.path.exists(local_audio_path):
62
- return f"Error: File not found: '{local_audio_path}'."
63
- audio = AudioSegment.from_file(local_audio_path)
64
- audio.export(temp_wav_path, format="wav")
65
- with sr.AudioFile(temp_wav_path) as source:
66
- audio_listened = r.record(source)
67
- try:
68
- transcribed_text = r.recognize_google(audio_listened, language=language)
69
- except sr.UnknownValueError:
70
- return "Could not understand audio."
71
- except sr.RequestError as e:
72
- return f"Could not request results from Google Speech Recognition; {e}"
73
- except Exception as e:
74
- return f"Error: {e}"
75
- finally:
76
- if os.path.exists(temp_wav_path):
77
- os.remove(temp_wav_path)
78
- return transcribed_text.strip()
79
-
80
- audio_transcriber_tool = Tool(
81
- name="audio_transcriber_tool",
82
- description="Transcribes audio from a local file path to text. Input: path to audio file (e.g., 'myfile.mp3'). Use 'file_saver' to download first. Optionally set language.",
83
- func=transcribe_audio_from_path,
84
- )
85
 
86
- # === TOOL: wikipedia_search_tool2 ===
87
- def wiki_search(query: str) -> str:
88
- search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
89
- formatted_search_docs = "\n\n---\n\n".join(
90
- [
91
- f'<Document source="{doc.metadata.get("source", "")}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
92
- for doc in search_docs
93
- ])
94
- return formatted_search_docs
95
-
96
- wikipedia_search_tool2 = Tool(
97
- name="wikipedia_search_tool2",
98
- description="Search Wikipedia for a query and return up to 2 results. Input: query string.",
99
- func=wiki_search,
100
- )
101
 
102
- # === PROMPT ===
103
- prompt = PromptTemplate(
104
- input_variables=["input", "agent_scratchpad", "chat_history", "tool_names"],
105
- template="""
106
- You are a smart and helpful AI Agent/Assistant that excels at fact-based reasoning. You are allowed and encouraged to use one or more tools as needed to answer complex questions and perform tasks.
107
- STRICT FINAL ANSWER RULES:
108
- - Final Answer must be a number, a few words, or a comma-separated list, as requested.
109
- - No units or extra punctuation unless asked.
110
- Your response must start with 'Thought:' and finish with 'Final Answer:'.
111
- You have access to the following tools:
112
- {tools}
113
- Use this format:
114
- Thought: [thinking]
115
- Action: [tool_name]
116
- Action Input: [input]
117
- Observation: [result]
118
- ...
119
- Thought: [done]
120
- Final Answer: [concise answer]
121
-
122
- {chat_history}
123
- New input: {input}
124
- ---
125
- {agent_scratchpad}
126
- """
127
  )
128
 
129
- # === AGENT ===
130
- class BasicAgent:
131
- def __init__(
132
- self,
133
- agent,
134
- tools,
135
- verbose=False,
136
- handle_parsing_errors=True,
137
- max_iterations=9,
138
- memory=None
139
- ):
140
- self.agent_obj = AgentExecutor(
141
- agent=agent,
142
- tools=tools,
143
- verbose=verbose,
144
- handle_parsing_errors=handle_parsing_errors,
145
- max_iterations=max_iterations,
146
- memory=memory
147
- )
148
 
149
- def __call__(self, question: str) -> str:
150
- result = self.agent_obj.invoke(
151
- {"input": question},
152
- config={"configurable": {"session_id": "test-session"}},
153
- )
154
- return result['output']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
- def run_and_submit_all(profile: gr.OAuthProfile | None):
157
- space_id = os.getenv("SPACE_ID")
158
  if profile:
159
  username= f"{profile.username}"
160
  print(f"User logged in: {username}")
@@ -166,30 +115,17 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
166
  questions_url = f"{api_url}/questions"
167
  submit_url = f"{api_url}/submit"
168
 
169
- openai_api_key = os.getenv("OPENAI_API_KEY")
170
- if not openai_api_key:
171
- print("OpenAI API key not found in environment variables.")
172
- return "OpenAI API key not found. Please set OPENAI_API_KEY environment variable.", None
173
- print(f"Using OpenAI API key: {openai_api_key[:4]}... (truncated for security)")
174
-
175
- llm_client = ChatOpenAI(model='gpt-4o', temperature=0, api_key=openai_api_key)
176
-
177
- summary_memory = ConversationSummaryMemory(llm=llm_client, memory_key="chat_history")
178
-
179
- summary_react_agent = create_react_agent(
180
- llm=llm_client,
181
- tools=[repl_tool, file_saver_tool, audio_transcriber_tool, wikipedia_search_tool2],
182
- prompt=prompt
183
- )
184
-
185
  try:
186
- agent = BasicAgent(summary_react_agent, [repl_tool, file_saver_tool, audio_transcriber_tool, wikipedia_search_tool2], True, True, 30, summary_memory)
187
  except Exception as e:
188
  print(f"Error instantiating agent: {e}")
189
  return f"Error initializing agent: {e}", None
 
190
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
191
  print(agent_code)
192
 
 
193
  print(f"Fetching questions from: {questions_url}")
194
  try:
195
  response = requests.get(questions_url, timeout=15)
@@ -210,23 +146,27 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
210
  print(f"An unexpected error occurred fetching questions: {e}")
211
  return f"An unexpected error occurred fetching questions: {e}", None
212
 
 
213
  results_log = []
214
  answers_payload = []
215
  print(f"Running agent on {len(questions_data)} questions...")
216
  for item in questions_data:
217
  task_id = item.get("task_id")
218
  question_text = item.get("question")
 
219
  file_name = item.get("file_name")
220
- full_question_for_agent = question_text
221
- if file_name:
222
- attachment_url = f"https://agents-course-unit4-scoring.hf.space/files/{task_id}"
223
- full_question_for_agent += f"\n\nAttachment '{file_name}' available at EXACT URL: {attachment_url}"
224
- print(f"Running agent on task {task_id}: {full_question_for_agent}",flush=True)
225
  try:
226
- submitted_answer = agent(full_question_for_agent)
 
 
 
 
 
227
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
228
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
229
- time.sleep(1)
230
  except Exception as e:
231
  print(f"Error running agent on task {task_id}: {e}")
232
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
@@ -235,10 +175,12 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
235
  print("Agent did not produce any answers to submit.")
236
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
237
 
 
238
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
239
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
240
  print(status_update)
241
 
 
242
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
243
  try:
244
  response = requests.post(submit_url, json=submission_data, timeout=60)
@@ -252,31 +194,60 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
252
  f"Message: {result_data.get('message', 'No message received.')}"
253
  )
254
  print("Submission successful.")
255
- cleaned_final_status = re.sub(r'[^\x20-\x7E\n\r\t]+', '', final_status)
256
- cleaned_final_status = cleaned_final_status.strip()
257
  results_df = pd.DataFrame(results_log)
258
- return cleaned_final_status, results_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  except Exception as e:
260
- status_message = f"Submission Failed: {e}"
261
  print(status_message)
262
  results_df = pd.DataFrame(results_log)
263
  return status_message, results_df
264
 
265
- # --- Gradio Interface ---
 
266
  with gr.Blocks() as demo:
267
  gr.Markdown("# Basic Agent Evaluation Runner")
268
  gr.Markdown(
269
  """
270
  **Instructions:**
271
- 1. Clone this space and modify the code as needed.
272
- 2. Log in to your Hugging Face account below.
273
- 3. Click 'Run Evaluation & Submit All Answers' to see your score!
 
 
 
 
274
  """
275
  )
 
276
  gr.LoginButton()
 
277
  run_button = gr.Button("Run Evaluation & Submit All Answers")
 
278
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
279
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
 
280
  run_button.click(
281
  fn=run_and_submit_all,
282
  outputs=[status_output, results_table]
@@ -284,19 +255,24 @@ with gr.Blocks() as demo:
284
 
285
  if __name__ == "__main__":
286
  print("\n" + "-"*30 + " App Starting " + "-"*30)
 
287
  space_host_startup = os.getenv("SPACE_HOST")
288
- space_id_startup = os.getenv("SPACE_ID")
 
289
  if space_host_startup:
290
  print(f"✅ SPACE_HOST found: {space_host_startup}")
291
  print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
292
  else:
293
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
294
- if space_id_startup:
 
295
  print(f"✅ SPACE_ID found: {space_id_startup}")
296
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
297
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
298
  else:
299
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
 
300
  print("-"*(60 + len(" App Starting ")) + "\n")
 
301
  print("Launching Gradio Interface for Basic Agent Evaluation...")
302
  demo.launch(debug=True, share=False)
 
 
1
  import os
2
  import gradio as gr
3
+ import inspect
4
  import pandas as pd
5
+ import importlib
6
+ from importlib import resources
7
+ import requests
8
+ import yaml
9
+ import numpy as np
10
+ from smolagents import CodeAgent, DuckDuckGoSearchTool, VisitWebpageTool, WikipediaSearchTool, Tool, OpenAIServerModel, SpeechToTextTool
 
 
 
 
 
 
 
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
+ # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
 
 
 
18
 
19
+
20
+
21
+
22
+
23
+ class GetTaskFileTool(Tool):
24
+ name = "get_task_file_tool"
25
+ description = """This tool downloads the file content associated with the given task_id if exists. Returns absolute file path"""
26
+ inputs = {
27
+ "task_id": {"type": "string", "description": "Task id"},
28
+ "file_name": {"type": "string", "description": "File name"},
29
+ }
30
+ output_type = "string"
31
+
32
+ def forward(self, task_id: str, file_name: str) -> str:
33
+ response = requests.get(f"{DEFAULT_API_URL}/files/{task_id}", timeout=15)
34
  response.raise_for_status()
35
+ with open(file_name, 'wb') as file:
36
+ file.write(response.content)
37
+ return os.path.abspath(file_name)
 
 
 
 
38
 
39
+ class LoadXlsxFileTool(Tool):
40
+ name = "load_xlsx_file_tool"
41
+ description = """This tool loads xlsx file into pandas and returns it"""
42
+ inputs = {
43
+ "file_path": {"type": "string", "description": "File path"}
44
+ }
45
+ output_type = "object"
46
 
47
+ def forward(self, file_path: str) -> object:
48
+ return pd.read_excel(file_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ class LoadTextFileTool(Tool):
51
+ name = "load_text_file_tool"
52
+ description = """This tool loads any text file"""
53
+ inputs = {
54
+ "file_path": {"type": "string", "description": "File path"}
55
+ }
56
+ output_type = "string"
 
 
 
 
 
 
 
 
57
 
58
+ def forward(self, file_path: str) -> object:
59
+ with open(file_path, 'r', encoding='utf-8') as file:
60
+ return file.read()
61
+
62
+ prompts = yaml.safe_load(
63
+ resources.files("smolagents.prompts").joinpath("code_agent.yaml").read_text()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  )
65
 
66
+ prompts["system_prompt"] = ("You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings. If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise. If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise. If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string. "
67
+ + prompts["system_prompt"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ def init_agent():
70
+ gemini_model = OpenAIServerModel(
71
+ model_id="deepseek-ai/DeepSeek-R1-0528",
72
+ api_base="https://llm.chutes.ai/v1",
73
+ api_key=os.getenv("CHUTES_API_KEY"),
74
+ temperature=0.7
75
+ )
76
+ agent = CodeAgent(
77
+ tools=[
78
+ DuckDuckGoSearchTool(),
79
+ VisitWebpageTool(),
80
+ WikipediaSearchTool(),
81
+ GetTaskFileTool(),
82
+ SpeechToTextTool(),
83
+ LoadXlsxFileTool(),
84
+ LoadTextFileTool()
85
+ ],
86
+ model=gemini_model,
87
+ prompt_templates=prompts,
88
+ max_steps=15,
89
+ additional_authorized_imports = ["pandas"]
90
+ )
91
+ return agent
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
100
+ """
101
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
102
+ and displays the results.
103
+ """
104
+ # --- Determine HF Space Runtime URL and Repo URL ---
105
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
106
 
 
 
107
  if profile:
108
  username= f"{profile.username}"
109
  print(f"User logged in: {username}")
 
115
  questions_url = f"{api_url}/questions"
116
  submit_url = f"{api_url}/submit"
117
 
118
+ # 1. Instantiate Agent ( modify this part to create your agent)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  try:
120
+ agent = init_agent()
121
  except Exception as e:
122
  print(f"Error instantiating agent: {e}")
123
  return f"Error initializing agent: {e}", None
124
+ # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
125
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
126
  print(agent_code)
127
 
128
+ # 2. Fetch Questions
129
  print(f"Fetching questions from: {questions_url}")
130
  try:
131
  response = requests.get(questions_url, timeout=15)
 
146
  print(f"An unexpected error occurred fetching questions: {e}")
147
  return f"An unexpected error occurred fetching questions: {e}", None
148
 
149
+ # 3. Run your Agent
150
  results_log = []
151
  answers_payload = []
152
  print(f"Running agent on {len(questions_data)} questions...")
153
  for item in questions_data:
154
  task_id = item.get("task_id")
155
  question_text = item.get("question")
156
+ print(question_text)
157
  file_name = item.get("file_name")
158
+ if not task_id or question_text is None:
159
+ print(f"Skipping item with missing task_id or question: {item}")
160
+ continue
 
 
161
  try:
162
+ submitted_answer = agent.run(f"Task id: {task_id}. Task file: {file_name if file_name != '' else 'is absent'}. Task: " + question_text)
163
+ if isinstance(submitted_answer, (np.integer, np.floating)):
164
+ submitted_answer = submitted_answer.item() # Convert NumPy types to Python native types
165
+ elif isinstance(submitted_answer, list):
166
+ submitted_answer = [x.item() if isinstance(x, (np.integer, np.floating)) else x for x in submitted_answer]
167
+ submitted_answer = str(submitted_answer)
168
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
169
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
170
  except Exception as e:
171
  print(f"Error running agent on task {task_id}: {e}")
172
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
175
  print("Agent did not produce any answers to submit.")
176
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
177
 
178
+ # 4. Prepare Submission
179
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
180
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
181
  print(status_update)
182
 
183
+ # 5. Submit
184
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
185
  try:
186
  response = requests.post(submit_url, json=submission_data, timeout=60)
 
194
  f"Message: {result_data.get('message', 'No message received.')}"
195
  )
196
  print("Submission successful.")
 
 
197
  results_df = pd.DataFrame(results_log)
198
+ return final_status, results_df
199
+ except requests.exceptions.HTTPError as e:
200
+ error_detail = f"Server responded with status {e.response.status_code}."
201
+ try:
202
+ error_json = e.response.json()
203
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
204
+ except requests.exceptions.JSONDecodeError:
205
+ error_detail += f" Response: {e.response.text[:500]}"
206
+ status_message = f"Submission Failed: {error_detail}"
207
+ print(status_message)
208
+ results_df = pd.DataFrame(results_log)
209
+ return status_message, results_df
210
+ except requests.exceptions.Timeout:
211
+ status_message = "Submission Failed: The request timed out."
212
+ print(status_message)
213
+ results_df = pd.DataFrame(results_log)
214
+ return status_message, results_df
215
+ except requests.exceptions.RequestException as e:
216
+ status_message = f"Submission Failed: Network error - {e}"
217
+ print(status_message)
218
+ results_df = pd.DataFrame(results_log)
219
+ return status_message, results_df
220
  except Exception as e:
221
+ status_message = f"An unexpected error occurred during submission: {e}"
222
  print(status_message)
223
  results_df = pd.DataFrame(results_log)
224
  return status_message, results_df
225
 
226
+
227
+ # --- Build Gradio Interface using Blocks ---
228
  with gr.Blocks() as demo:
229
  gr.Markdown("# Basic Agent Evaluation Runner")
230
  gr.Markdown(
231
  """
232
  **Instructions:**
233
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
234
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
235
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
236
+ ---
237
+ **Disclaimers:**
238
+ 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).
239
+ 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.
240
  """
241
  )
242
+
243
  gr.LoginButton()
244
+
245
  run_button = gr.Button("Run Evaluation & Submit All Answers")
246
+
247
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
248
+ # Removed max_rows=10 from DataFrame constructor
249
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
250
+
251
  run_button.click(
252
  fn=run_and_submit_all,
253
  outputs=[status_output, results_table]
 
255
 
256
  if __name__ == "__main__":
257
  print("\n" + "-"*30 + " App Starting " + "-"*30)
258
+ # Check for SPACE_HOST and SPACE_ID at startup for information
259
  space_host_startup = os.getenv("SPACE_HOST")
260
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
261
+
262
  if space_host_startup:
263
  print(f"✅ SPACE_HOST found: {space_host_startup}")
264
  print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
265
  else:
266
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
267
+
268
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
269
  print(f"✅ SPACE_ID found: {space_id_startup}")
270
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
271
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
272
  else:
273
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
274
+
275
  print("-"*(60 + len(" App Starting ")) + "\n")
276
+
277
  print("Launching Gradio Interface for Basic Agent Evaluation...")
278
  demo.launch(debug=True, share=False)