leofltt commited on
Commit
7bb9df1
·
1 Parent(s): 4489283

one more try

Browse files
Files changed (2) hide show
  1. app.py +72 -154
  2. requirements.txt +7 -15
app.py CHANGED
@@ -2,169 +2,89 @@ import os
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
5
- from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
6
- from transformers import AutoProcessor, AutoModelForVision2Seq
7
- from dotenv import load_dotenv
8
- from typing import Optional, Dict, Any
9
- from PIL import Image
10
- import yt_dlp
11
  import torch
12
- import re
13
- from io import BytesIO
 
14
 
15
  # (Keep Constants as is)
16
  # --- Constants ---
17
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
18
 
19
 
20
- # --- Basic Agent Definition ---
21
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
22
- class BasicAgent:
23
  def __init__(self):
24
- print("BasicAgent initialized.")
25
- load_dotenv()
26
-
27
- # Initialize model and tokenizer using Qwen
28
- model_name = "Qwen/Qwen-7B-Chat" # Changed to Qwen
 
 
 
 
 
 
 
29
 
30
- # Configure quantization
31
- quantization_config = BitsAndBytesConfig(
32
- load_in_8bit=True, bnb_4bit_compute_dtype=torch.float16
 
 
 
 
 
 
33
  )
34
 
35
- self.tokenizer = AutoTokenizer.from_pretrained(
36
- model_name, trust_remote_code=True # Required for Qwen
37
- )
38
- self.model = AutoModelForCausalLM.from_pretrained(
39
- model_name,
 
40
  device_map="auto",
41
- quantization_config=quantization_config,
42
- trust_remote_code=True,
43
- )
44
-
45
- # Initialize vision model
46
- vision_model_name = "microsoft/kosmos-2-patch14-224"
47
- self.vision_processor = AutoProcessor.from_pretrained(vision_model_name)
48
- self.vision_model = AutoModelForVision2Seq.from_pretrained(
49
- vision_model_name, device_map="auto", trust_remote_code=True
50
  )
51
-
52
- print("Agent initialized with multimodal capabilities.")
53
-
54
- def generate_text(self, prompt: str) -> str:
55
- inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
56
- outputs = self.model.generate(
57
- **inputs, max_new_tokens=512, temperature=0.1, do_sample=True
58
- )
59
- return self.tokenizer.decode(outputs[0], skip_special_tokens=True)
60
-
61
- def analyze_image(self, image_url: str) -> str:
62
- try:
63
- response = requests.get(image_url)
64
- image = Image.open(BytesIO(response.content))
65
- inputs = self.vision_processor(images=image, return_tensors="pt")
66
- outputs = self.vision_model.generate(
67
- pixel_values=inputs["pixel_values"], max_length=128, num_beams=5
68
- )
69
- return self.vision_processor.batch_decode(
70
- outputs, skip_special_tokens=True
71
- )[0]
72
- except Exception as e:
73
- print(f"Error analyzing image: {e}")
74
- return "Error analyzing image"
75
-
76
- def analyze_video(self, video_url: str) -> str:
77
- try:
78
- # Extract video info using yt-dlp
79
- ydl_opts = {
80
- "format": "worst", # Lowest quality to save bandwidth
81
- "extract_flat": True,
82
- "quiet": True,
83
- }
84
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
85
- info = ydl.extract_info(video_url, download=False)
86
-
87
- # Extract relevant information
88
- title = info.get("title", "")
89
- description = info.get("description", "")
90
- duration = info.get("duration", 0)
91
-
92
- # Create prompt for the LLM
93
- video_context = f"""
94
- Video Title: {title}
95
- Duration: {duration} seconds
96
- Description: {description}
97
- """
98
-
99
- return self.generate_response(video_context)
100
- except Exception as e:
101
- print(f"Error analyzing video: {e}")
102
- return "Error analyzing video"
103
-
104
- def analyze_data(self, df: pd.DataFrame, question: str) -> str:
105
- try:
106
- prompt = f"""Analyze this DataFrame:
107
- Columns: {', '.join(df.columns)}
108
- Sample: {df.head().to_string()}
109
- Question: {question}
110
- Provide only the numerical answer or specific value."""
111
-
112
- return self.generate_response(prompt)
113
- except Exception as e:
114
- print(f"Error analyzing data: {e}")
115
- return "Error analyzing data"
116
-
117
- def generate_response(self, prompt: str) -> str:
118
- try:
119
- response = self.llm.complete(prompt)
120
- return response.text.strip()
121
- except Exception as e:
122
- print(f"Error generating response: {e}")
123
- return "Error generating response"
124
 
125
  def __call__(self, question: str) -> str:
126
- print(f"Agent received question: {question[:50]}...")
127
 
128
- try:
129
- # Check for data analysis task
130
- if "```python" in question:
131
- data_start = question.find("```python")
132
- data_end = question.find("```", data_start + 8)
133
- data_code = question[data_start + 8 : data_end].strip()
134
- local_vars = {}
135
- exec(data_code, {"pd": pd}, local_vars)
136
- df = local_vars.get("df")
137
- actual_question = question[data_end + 3 :].strip()
138
- return self.analyze_data(df, actual_question)
139
 
140
- # Check for video analysis task
141
- video_pattern = r"https?://(?:www\.)?youtube\.com/\S+"
142
- video_match = re.search(video_pattern, question)
143
- if video_match:
144
- return self.analyze_video(video_match.group(0))
145
 
146
- # Check for image analysis task
147
- image_pattern = r"https?://\S+\.(?:jpg|jpeg|png|gif)"
148
- image_match = re.search(image_pattern, question)
149
- if image_match:
150
- return self.analyze_image(image_match.group(0))
151
 
152
- # General question
153
- return self.generate_text(question)
 
 
 
 
 
 
 
 
154
 
155
- except Exception as e:
156
- print(f"Error processing question: {e}")
157
- return "Error occurred while processing the question"
158
 
159
 
160
  def run_and_submit_all(profile: gr.OAuthProfile | None):
161
  """
162
- Fetches all questions, runs the BasicAgent on them, submits all answers,
163
  and displays the results.
164
  """
165
  # --- Determine HF Space Runtime URL and Repo URL ---
166
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
167
-
168
  if profile:
169
  username = f"{profile.username}"
170
  print(f"User logged in: {username}")
@@ -176,13 +96,14 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
176
  questions_url = f"{api_url}/questions"
177
  submit_url = f"{api_url}/submit"
178
 
179
- # 1. Instantiate Agent ( modify this part to create your agent)
180
  try:
181
- agent = BasicAgent()
182
  except Exception as e:
183
  print(f"Error instantiating agent: {e}")
184
  return f"Error initializing agent: {e}", None
185
- # 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)
 
186
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
187
  print(agent_code)
188
 
@@ -217,16 +138,21 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
217
  if not task_id or question_text is None:
218
  print(f"Skipping item with missing task_id or question: {item}")
219
  continue
 
220
  try:
221
  submitted_answer = agent(question_text)
 
 
 
 
222
  answers_payload.append(
223
- {"task_id": task_id, "submitted_answer": submitted_answer}
224
  )
225
  results_log.append(
226
  {
227
  "Task ID": task_id,
228
  "Question": question_text,
229
- "Submitted Answer": submitted_answer,
230
  }
231
  )
232
  except Exception as e:
@@ -298,30 +224,24 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
298
 
299
  # --- Build Gradio Interface using Blocks ---
300
  with gr.Blocks() as demo:
301
- gr.Markdown("# Basic Agent Evaluation Runner")
302
  gr.Markdown(
303
  """
304
  **Instructions:**
305
-
306
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
307
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
308
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
309
-
310
  ---
311
  **Disclaimers:**
312
- 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).
313
- 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.
314
  """
315
  )
316
-
317
  gr.LoginButton()
318
-
319
  run_button = gr.Button("Run Evaluation & Submit All Answers")
320
-
321
  status_output = gr.Textbox(
322
  label="Run Status / Submission Result", lines=5, interactive=False
323
  )
324
- # Removed max_rows=10 from DataFrame constructor
325
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
326
 
327
  run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
@@ -331,7 +251,6 @@ if __name__ == "__main__":
331
  # Check for SPACE_HOST and SPACE_ID at startup for information
332
  space_host_startup = os.getenv("SPACE_HOST")
333
  space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
334
-
335
  if space_host_startup:
336
  print(f"✅ SPACE_HOST found: {space_host_startup}")
337
  print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
@@ -350,6 +269,5 @@ if __name__ == "__main__":
350
  )
351
 
352
  print("-" * (60 + len(" App Starting ")) + "\n")
353
-
354
- print("Launching Gradio Interface for Basic Agent Evaluation...")
355
  demo.launch(debug=True, share=False)
 
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
 
 
 
 
 
 
5
  import torch
6
+ from llama_index.llms.huggingface import HuggingFaceLLM
7
+ from llama_index.core import ChatPromptTemplate
8
+ from llama_index.core.llms import ChatMessage
9
 
10
  # (Keep Constants as is)
11
  # --- Constants ---
12
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
13
 
14
 
15
+ # --- LlamaIndex Agent Definition ---
16
+ # ----- THIS IS THE MODIFIED AGENT USING LLAMA-INDEX ------
17
+ class LlamaIndexAgent:
18
  def __init__(self):
19
+ print("Initializing LlamaIndexAgent...")
20
+
21
+ # Define the system prompt as requested by the user
22
+ system_prompt = """
23
+ You are a helpful assistant tasked with answering questions.
24
+ Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER].
25
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
26
+ 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.
27
+ 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.
28
+ 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.
29
+ Your answer should only start with "FINAL ANSWER: ", then follows with the answer.
30
+ """
31
 
32
+ # Using a fixed user and assistant message for the prompt template
33
+ self.chat_prompt_template = ChatPromptTemplate(
34
+ message_templates=[
35
+ ChatMessage(
36
+ role="system",
37
+ content=system_prompt,
38
+ ),
39
+ ChatMessage(role="user", content="{question}"),
40
+ ]
41
  )
42
 
43
+ # Load the model. Using a smaller, free model that can run on CPU
44
+ # Using quantization to reduce memory footprint
45
+ self.llm = HuggingFaceLLM(
46
+ model_name="HuggingFaceH4/zephyr-7b-beta",
47
+ tokenizer_name="HuggingFaceH4/zephyr-7b-beta",
48
+ query_wrapper_prompt=self.chat_prompt_template,
49
  device_map="auto",
50
+ model_kwargs={"torch_dtype": torch.float16, "load_in_8bit": True},
 
 
 
 
 
 
 
 
51
  )
52
+ print("LlamaIndexAgent initialized successfully.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  def __call__(self, question: str) -> str:
55
+ print(f"Agent received question (first 80 chars): {question[:80]}...")
56
 
57
+ # Format the messages
58
+ messages = self.chat_prompt_template.format_messages(question=question)
 
 
 
 
 
 
 
 
 
59
 
60
+ # Get the response from the LLM
61
+ response = self.llm.chat(messages)
 
 
 
62
 
63
+ # Extract the answer from the response
64
+ answer = response.message.content.strip()
 
 
 
65
 
66
+ # Ensure the answer starts with "FINAL ANSWER: "
67
+ if "FINAL ANSWER:" in answer:
68
+ final_answer = answer.split("FINAL ANSWER:")[-1].strip()
69
+ else:
70
+ # If the model fails to follow the template, we return its raw output
71
+ # as the answer, prefixed with the required string.
72
+ print(
73
+ f"Warning: Model did not use the 'FINAL ANSWER:' template. Raw output: {answer}"
74
+ )
75
+ final_answer = answer
76
 
77
+ print(f"Agent returning answer: {final_answer}")
78
+ return f"FINAL ANSWER: {final_answer}"
 
79
 
80
 
81
  def run_and_submit_all(profile: gr.OAuthProfile | None):
82
  """
83
+ Fetches all questions, runs the LlamaIndexAgent on them, submits all answers,
84
  and displays the results.
85
  """
86
  # --- Determine HF Space Runtime URL and Repo URL ---
87
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
 
88
  if profile:
89
  username = f"{profile.username}"
90
  print(f"User logged in: {username}")
 
96
  questions_url = f"{api_url}/questions"
97
  submit_url = f"{api_url}/submit"
98
 
99
+ # 1. Instantiate Agent (modify this part to create your agent)
100
  try:
101
+ agent = LlamaIndexAgent()
102
  except Exception as e:
103
  print(f"Error instantiating agent: {e}")
104
  return f"Error initializing agent: {e}", None
105
+
106
+ # In the case of an app running as a hugging Face space, this link points toward your codebase
107
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
108
  print(agent_code)
109
 
 
138
  if not task_id or question_text is None:
139
  print(f"Skipping item with missing task_id or question: {item}")
140
  continue
141
+
142
  try:
143
  submitted_answer = agent(question_text)
144
+ # The agent now returns the full "FINAL ANSWER: ..." string, so we extract the answer part for submission.
145
+ answer_for_submission = submitted_answer.replace(
146
+ "FINAL ANSWER:", ""
147
+ ).strip()
148
  answers_payload.append(
149
+ {"task_id": task_id, "submitted_answer": answer_for_submission}
150
  )
151
  results_log.append(
152
  {
153
  "Task ID": task_id,
154
  "Question": question_text,
155
+ "Submitted Answer": answer_for_submission,
156
  }
157
  )
158
  except Exception as e:
 
224
 
225
  # --- Build Gradio Interface using Blocks ---
226
  with gr.Blocks() as demo:
227
+ gr.Markdown("# LlamaIndex Agent Evaluation Runner for GAIA")
228
  gr.Markdown(
229
  """
230
  **Instructions:**
231
+ 1. This space is configured with a `LlamaIndexAgent` to answer the GAIA subset questions.
 
232
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
233
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run the agent, submit answers, and see the score.
 
234
  ---
235
  **Disclaimers:**
236
+ 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.
237
+ Model loading can also take a few minutes on the first run.
238
  """
239
  )
 
240
  gr.LoginButton()
 
241
  run_button = gr.Button("Run Evaluation & Submit All Answers")
 
242
  status_output = gr.Textbox(
243
  label="Run Status / Submission Result", lines=5, interactive=False
244
  )
 
245
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
246
 
247
  run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
 
251
  # Check for SPACE_HOST and SPACE_ID at startup for information
252
  space_host_startup = os.getenv("SPACE_HOST")
253
  space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
 
254
  if space_host_startup:
255
  print(f"✅ SPACE_HOST found: {space_host_startup}")
256
  print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
 
269
  )
270
 
271
  print("-" * (60 + len(" App Starting ")) + "\n")
272
+ print("Launching Gradio Interface for LlamaIndex Agent Evaluation...")
 
273
  demo.launch(debug=True, share=False)
requirements.txt CHANGED
@@ -1,16 +1,8 @@
1
- gradio~=4.44.0
2
- numpy<2.0.0
3
- requests==2.31.0
 
 
4
  transformers
5
- python-dotenv==1.0.0
6
- torch==2.2.0
7
- sentence-transformers==2.3.1
8
- nltk==3.8.1
9
- accelerate==0.27.2
10
- bitsandbytes==0.41.0
11
- yt-dlp
12
- Pillow==10.2.0
13
- pandas==2.1.4
14
- gradio[oauth]
15
- transformers_stream_generator
16
- einops
 
1
+ gradio
2
+ requests
3
+ pandas
4
+ llama-index
5
+ torch
6
  transformers
7
+ accelerate
8
+ bitsandbytes