mrhenu commited on
Commit
bfd7e4d
·
verified ·
1 Parent(s): 4868771

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -105
app.py CHANGED
@@ -1,9 +1,5 @@
1
- """Full Hugging Face Spaces app.py for GAIA agent includes image analysis tool.
2
- Copypaste this file as‑is to your Space.
3
- Requires:
4
- - openai>=1.7.0 (for vision)
5
- - langchain, langchain-community, langgraph, gradio, pandas, requests, tavily-python, youtube-transcript-api
6
- - PILLOW (installed automatically with Gradio)
7
  """
8
 
9
  import os
@@ -14,7 +10,6 @@ import operator
14
  from typing import Sequence, Annotated, TypedDict
15
 
16
  from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
17
- from langchain.agents import AgentExecutor
18
  from langchain_experimental.tools import PythonREPLTool
19
  from langchain_community.tools.tavily_search import TavilySearchResults
20
  from langchain_community.tools.youtube.search import YouTubeSearchTool
@@ -22,83 +17,47 @@ from langchain_openai import ChatOpenAI
22
  from langgraph.graph import StateGraph
23
  from langgraph.prebuilt import ToolNode, tools_condition
24
 
25
- # ------------------------ Vision Tool --------------------------------------
26
-
27
- from langchain_core.tools import tool
28
-
29
- @tool("image_analysis", return_direct=True)
30
- def image_analysis(image_path: str, prompt: str) -> str:
31
- """Analyze an image located at `image_path` according to `prompt`.
32
- Example call from LLM: image_analysis{"image_path": "/mnt/data/cat.png", "prompt": "How many cats?"}
33
- Returns a textual answer.
34
- """
35
- import openai
36
- from PIL import Image
37
-
38
- if not os.path.exists(image_path):
39
- return "Image path not found."
40
-
41
- # Read image bytes
42
- with open(image_path, "rb") as f:
43
- img_bytes = f.read()
44
-
45
- client = openai.OpenAI()
46
- completion = client.chat.completions.create(
47
- model="gpt-4o-mini", # vision‑capable
48
- messages=[
49
- {
50
- "role": "user",
51
- "content": [
52
- {"type": "image", "image": img_bytes},
53
- {"type": "text", "text": prompt},
54
- ],
55
- }
56
- ],
57
- )
58
- return completion.choices[0].message.content.strip()
59
-
60
- # --------------------- LangGraph Agent -------------------------------------
61
 
62
  class AgentState(TypedDict):
63
  messages: Annotated[Sequence[BaseMessage], operator.add]
64
 
65
  SYSTEM_PROMPT = (
66
- "You are a general AI assistant. I will ask you a question. Report your thoughts, "
67
- "and finish your answer with the template:\nFINAL ANSWER: [YOUR FINAL ANSWER].\n\n"
68
- "YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.\n"
69
- "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.\n"
70
- "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.\n"
71
- "If you are asked for a comma separated list, apply the above rules depending on whether the element to be put in the list is a number or a string."
 
 
 
 
72
  )
73
 
74
 
75
- def create_langgraph_agent() -> AgentExecutor:
76
- print("Initializing LangGraph GAIA agent…")
77
-
78
  llm = ChatOpenAI(model="gpt-4o", temperature=0)
79
 
80
- # Base tools
81
  tools = [
82
  TavilySearchResults(max_results=3),
83
  PythonREPLTool(),
84
  YouTubeSearchTool(),
85
- image_analysis,
86
  ]
87
 
88
- # Optional FileManagement tools
89
  try:
90
  from langchain_community.agent_toolkits.file_management.toolkit import FileManagementToolkit
91
  tools.extend(FileManagementToolkit(root_dir=".").get_tools())
92
- print("FileManagement tools loaded.")
93
- except Exception as e:
94
- print("FileManagement toolkit unavailable:", e)
95
 
96
  llm_with_tools = llm.bind_tools(tools)
97
 
98
  def agent_node(state: AgentState):
99
- full_msgs = [SystemMessage(content=SYSTEM_PROMPT)] + list(state["messages"])
100
- response = llm_with_tools.invoke(full_msgs)
101
- return {"messages": [response]}
102
 
103
  graph = StateGraph(AgentState)
104
  graph.add_node("agent", agent_node)
@@ -107,85 +66,77 @@ def create_langgraph_agent() -> AgentExecutor:
107
  graph.add_conditional_edges("agent", tools_condition)
108
  graph.add_edge("tools", "agent")
109
 
110
- executor = graph.compile()
111
- print("LangGraph agent compiled.")
112
- return executor
113
 
114
- # --------------------- Helper to run one question ---------------------------
115
 
116
- def run_agent(agent_executor, question: str) -> str:
117
- print("New question:", question)
118
  try:
119
- result = agent_executor.invoke(
120
  {"messages": [HumanMessage(content=question)]},
121
  config={"recursion_limit": 15},
122
  )
123
- answer_raw = result["messages"][-1].content
124
- return answer_raw.split("FINAL ANSWER:")[-1].strip() if "FINAL ANSWER:" in answer_raw else answer_raw
125
- except Exception as err:
126
- print("Execution error:", err)
127
- return f"Error: {err}"
128
 
129
- # --------------------- Evaluation / Submission ----------------------------
130
 
131
  def run_and_submit_all(profile: gr.OAuthProfile | None):
132
- space_id = os.getenv("SPACE_ID")
133
  if not profile:
134
- return "Please login via the button.", None
135
 
136
- if not (os.getenv("TAVILY_API_KEY") and os.getenv("OPENAI_API_KEY")):
137
- return "Missing API keys (TAVILY / OPENAI)", None
 
138
 
139
  try:
140
  agent_exec = create_langgraph_agent()
141
  except Exception as e:
142
- return f"Error initializing agent: {e}", None
143
 
144
- QUESTIONS_URL = "https://agents-course-unit4-scoring.hf.space/questions"
145
- SUBMIT_URL = "https://agents-course-unit4-scoring.hf.space/submit"
146
 
147
  try:
148
- q_resp = requests.get(QUESTIONS_URL, timeout=20)
149
- q_resp.raise_for_status()
150
- questions = q_resp.json()
151
  except Exception as e:
152
- return f"Error fetching questions: {e}", None
153
 
154
  answers = []
155
- for item in questions:
156
- tid, qtext = item.get("task_id"), item.get("question")
157
- if tid and qtext:
158
- answers.append({"task_id": tid, "submitted_answer": run_agent(agent_exec, qtext)})
 
 
159
 
160
  payload = {
161
- "username": profile.username.strip(),
162
- "agent_code": f"https://huggingface.co/spaces/{space_id}/tree/main",
163
  "answers": answers,
164
  }
165
 
166
  try:
167
- s_resp = requests.post(SUBMIT_URL, json=payload, timeout=240)
168
- s_resp.raise_for_status()
169
- r = s_resp.json()
170
  status = (
171
- f"Submission Successful!\nUser: {r.get('username')}\n"
172
- f"Score: {r.get('score', 'N/A')}% ({r.get('correct_count', '?')}/{r.get('total_attempted', '?')})\n"
173
- f"Message: {r.get('message', 'No message')}"
174
  )
175
  return status, pd.DataFrame(answers)
176
  except Exception as e:
177
- return f"Error submitting answers: {e}", pd.DataFrame(answers)
178
 
179
- # ------------------------ Gradio UI ---------------------------------------
180
 
181
  with gr.Blocks() as demo:
182
- gr.Markdown("# GAIA Agent Evaluation Runner (Visionenabled)")
183
  gr.LoginButton()
184
- run_btn = gr.Button("Run & Submit All Answers")
185
- status_out = gr.Textbox(label="Run Status", lines=5, interactive=False)
186
- table_out = gr.DataFrame(label="Questions / Answers", wrap=True)
187
-
188
- run_btn.click(fn=run_and_submit_all, outputs=[status_out, table_out])
189
 
190
  if __name__ == "__main__":
191
  demo.launch()
 
1
+ """Full app.py with improved Excel-handling guidelines for GAIA agent.
2
+ Copy/paste into your Hugging Face Space.
 
 
 
 
3
  """
4
 
5
  import os
 
10
  from typing import Sequence, Annotated, TypedDict
11
 
12
  from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
 
13
  from langchain_experimental.tools import PythonREPLTool
14
  from langchain_community.tools.tavily_search import TavilySearchResults
15
  from langchain_community.tools.youtube.search import YouTubeSearchTool
 
17
  from langgraph.graph import StateGraph
18
  from langgraph.prebuilt import ToolNode, tools_condition
19
 
20
+ # ----------------------- Agent Definition ----------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  class AgentState(TypedDict):
23
  messages: Annotated[Sequence[BaseMessage], operator.add]
24
 
25
  SYSTEM_PROMPT = (
26
+ "You are a GAIA evaluation agent. For each question, think step‑by‑step, but only output the final answer with the template:\n"
27
+ "FINAL ANSWER: [YOUR FINAL ANSWER]\n\n"
28
+ "Formatting rules: Your FINAL ANSWER must be a single number, a single short string, or a commaseparated list, as the task dictates. No extra words.\n\n"
29
+ "**IMPORTANT TOOL USAGE**:\n"
30
+ " You have a PythonREPL tool with pandas pre‑installed. If the task references an Excel / CSV file path (e.g. .xlsx, .xls, .csv), do the following:\n"
31
+ " 1. Call PythonREPL and load the file with `pd.read_excel(<path>)` or `pd.read_csv(<path>)`.\n"
32
+ " 2. Use pandas operations (sum, mean, filtering etc.) to compute the required value.\n"
33
+ " 3. Return the numeric/string result in the FINAL ANSWER template.\n\n"
34
+ "• Use TavilySearchResults for web look‑ups, YouTubeSearchTool for video queries.\n"
35
+ "• If the task involves code execution or math, use PythonREPL.\n"
36
  )
37
 
38
 
39
+ def create_langgraph_agent():
 
 
40
  llm = ChatOpenAI(model="gpt-4o", temperature=0)
41
 
 
42
  tools = [
43
  TavilySearchResults(max_results=3),
44
  PythonREPLTool(),
45
  YouTubeSearchTool(),
 
46
  ]
47
 
48
+ # Optional FileManagement toolkit
49
  try:
50
  from langchain_community.agent_toolkits.file_management.toolkit import FileManagementToolkit
51
  tools.extend(FileManagementToolkit(root_dir=".").get_tools())
52
+ except Exception:
53
+ pass
 
54
 
55
  llm_with_tools = llm.bind_tools(tools)
56
 
57
  def agent_node(state: AgentState):
58
+ msgs = [SystemMessage(content=SYSTEM_PROMPT)] + list(state["messages"])
59
+ reply = llm_with_tools.invoke(msgs)
60
+ return {"messages": [reply]}
61
 
62
  graph = StateGraph(AgentState)
63
  graph.add_node("agent", agent_node)
 
66
  graph.add_conditional_edges("agent", tools_condition)
67
  graph.add_edge("tools", "agent")
68
 
69
+ return graph.compile()
 
 
70
 
71
+ # ------------------ Helper to run one question -----------------------------
72
 
73
+ def run_agent(agent_exec, question: str) -> str:
 
74
  try:
75
+ result = agent_exec.invoke(
76
  {"messages": [HumanMessage(content=question)]},
77
  config={"recursion_limit": 15},
78
  )
79
+ text = result["messages"][-1].content
80
+ return text.split("FINAL ANSWER:")[-1].strip() if "FINAL ANSWER:" in text else text
81
+ except Exception as e:
82
+ return f"Error: {e}"
 
83
 
84
+ # ------------------ Evaluation & Submission --------------------------------
85
 
86
  def run_and_submit_all(profile: gr.OAuthProfile | None):
 
87
  if not profile:
88
+ return "Please login first.", None
89
 
90
+ for key in ("OPENAI_API_KEY", "TAVILY_API_KEY"):
91
+ if not os.getenv(key):
92
+ return f"Missing {key} env var.", None
93
 
94
  try:
95
  agent_exec = create_langgraph_agent()
96
  except Exception as e:
97
+ return f"Init error: {e}", None
98
 
99
+ Q_URL = "https://agents-course-unit4-scoring.hf.space/questions"
100
+ S_URL = "https://agents-course-unit4-scoring.hf.space/submit"
101
 
102
  try:
103
+ questions = requests.get(Q_URL, timeout=20).json()
 
 
104
  except Exception as e:
105
+ return f"Fetch error: {e}", None
106
 
107
  answers = []
108
+ for q in questions:
109
+ if q.get("task_id") and q.get("question"):
110
+ answers.append({
111
+ "task_id": q["task_id"],
112
+ "submitted_answer": run_agent(agent_exec, q["question"]),
113
+ })
114
 
115
  payload = {
116
+ "username": profile.username,
117
+ "agent_code": "HF_Space_Link", # not required for scoring
118
  "answers": answers,
119
  }
120
 
121
  try:
122
+ res = requests.post(S_URL, json=payload, timeout=240).json()
 
 
123
  status = (
124
+ f"Score: {res.get('score', 'N/A')}% ({res.get('correct_count')}/" \
125
+ f"{res.get('total_attempted')})\nMessage: {res.get('message', '')}"
 
126
  )
127
  return status, pd.DataFrame(answers)
128
  except Exception as e:
129
+ return f"Submit error: {e}", pd.DataFrame(answers)
130
 
131
+ # ----------------------------- UI -----------------------------------------
132
 
133
  with gr.Blocks() as demo:
134
+ gr.Markdown("# GAIA Agent Runner – Excelaware")
135
  gr.LoginButton()
136
+ btn = gr.Button("Run & Submit")
137
+ out1 = gr.Textbox(label="Status", lines=4)
138
+ out2 = gr.DataFrame(label="Answers", wrap=True)
139
+ btn.click(fn=run_and_submit_all, outputs=[out1, out2])
 
140
 
141
  if __name__ == "__main__":
142
  demo.launch()