Bandook01 commited on
Commit
da372f7
·
1 Parent(s): c3640c8
Files changed (1) hide show
  1. app.py +76 -73
app.py CHANGED
@@ -1,30 +1,31 @@
 
 
 
 
 
1
  import os
2
  import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
6
- from tools import ReverseTextTool, RunPythonFileTool, download_server, wiki_tool,YoutubeTranscript
7
- import os
8
- from dotenv import load_dotenv
9
- from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
10
- from llama_index.core.agent.workflow import AgentWorkflow, ToolCallResult, AgentStream
11
- from llama_index.core.workflow import Context
12
- from llama_index.core.agent.workflow import FunctionAgent
13
- from llama_index.core.tools.tool_spec.load_and_search import (
14
- LoadAndSearchToolSpec,
15
  )
16
  from smolagents import DuckDuckGoSearchTool
17
- from llama_index.core.agent.workflow import AgentWorkflow
18
- from llama_index.core.tools import FunctionTool
19
-
20
-
21
 
 
 
 
22
 
23
- # (Keep Constants as is)
24
- # --- Constants ---
25
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
26
 
27
- # System prompt for the agent
28
  SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question.
29
  Report your thoughts, and finish your answer with just the answer — no prefixes like "FINAL ANSWER:".
30
  Your answer should be a number OR as few words as possible OR a comma-separated list of numbers and/or strings.
@@ -46,65 +47,75 @@ Tool Use Guidelines:
46
  10. Due to context length limits, keep browser-based tasks (e.g., searches) as short and efficient as possible.
47
  """
48
 
49
-
50
- # --- Basic Agent Definition ---
51
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
52
  class BasicAgent:
53
- def __init__(self):
54
- # Ensure environmental variable is set
 
55
  hf_api_key = os.getenv("HF_API_KEY")
56
  if not hf_api_key:
57
  raise RuntimeError("HF_API_KEY not set in environment variables.")
58
 
59
- # Initialize LLM with api_key parameter
60
- llm = HuggingFaceInferenceAPI(
61
  model_name="Qwen/Qwen2.5-Coder-32B-Instruct",
62
- token = hf_api_key,
 
63
  )
64
 
65
- # Create agent with function-calling-compatible LLM
66
- self.agent = AgentWorkflow.from_tools_or_functions(
67
- tools_or_functions=[
68
- ReverseTextTool,
69
- RunPythonFileTool,
70
- download_server,
71
- wiki_tool,
72
- YoutubeTranscript,
73
- DuckDuckGoSearchTool,
74
- ],
75
- llm=llm,
 
 
 
 
 
76
  system_prompt=SYSTEM_PROMPT,
77
  )
78
  print("✅ BasicAgent initialized.")
79
 
 
80
  async def answer_once(self, prompt: str) -> str:
81
- """Run the agent in a blank context so tokens never pile up."""
82
- # Safety: trim monster inputs
83
- # prompt = prompt[:32000] # 2 k tokens head-room
84
- ctx = Context(self.agent) # no prior messages
85
- resp = await self.agent.run(user_msg=prompt, ctx=ctx)
86
- # run() sometimes returns dict, sometimes str
87
- return resp if isinstance(resp, str) else resp.get("response", str(resp))
88
 
 
 
 
 
 
89
  async def __call__(self, input_text: str):
90
- # Use run() within async context
91
- return await self.agent.run(input_text)
92
 
93
  async def run(self, input_text: str):
94
- return await self.agent.run(input_text)
95
 
96
  async def stream(self, input_text: str):
97
- async for chunk in self.agent.stream(input_text):
 
98
  yield chunk.delta
99
 
 
 
 
100
  async def run_and_submit_all(profile: gr.OAuthProfile | None):
101
  """
102
- Fetches all questions, runs the BasicAgent on them, submits all answers,
103
- and displays the results.
104
  """
105
- # --- Determine HF Space Runtime URL and Repo URL ---
106
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
107
-
108
  if profile:
109
  username = f"{profile.username}"
110
  print(f"User logged in: {username}")
@@ -112,45 +123,36 @@ async def run_and_submit_all(profile: gr.OAuthProfile | None):
112
  print("User not logged in.")
113
  return "Please Login to Hugging Face with the button.", None
114
 
115
- api_url = DEFAULT_API_URL
116
  questions_url = f"{api_url}/questions"
117
- submit_url = f"{api_url}/submit"
118
 
119
- # 1. Instantiate Agent ( modify this part to create your agent)
120
  try:
121
  agent = BasicAgent()
122
  except Exception as e:
123
  print(f"Error instantiating agent: {e}")
124
  return f"Error initializing agent: {e}", None
125
- # 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)
126
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
127
  print(agent_code)
128
 
129
- # 2. Fetch Questions
130
  print(f"Fetching questions from: {questions_url}")
131
  try:
132
- response = requests.get(questions_url, timeout=15)
133
- response.raise_for_status()
134
- questions_data = response.json()
135
  if not questions_data:
136
- print("Fetched questions list is empty.")
137
  return "Fetched questions list is empty or invalid format.", None
138
  print(f"Fetched {len(questions_data)} questions.")
139
- except requests.exceptions.RequestException as e:
140
- print(f"Error fetching questions: {e}")
141
- return f"Error fetching questions: {e}", None
142
- except requests.exceptions.JSONDecodeError as e:
143
- print(f"Error decoding JSON response from questions endpoint: {e}")
144
- print(f"Response text: {response.text[:500]}")
145
- return f"Error decoding server response for questions: {e}", None
146
  except Exception as e:
147
- print(f"An unexpected error occurred fetching questions: {e}")
148
- return f"An unexpected error occurred fetching questions: {e}", None
149
 
150
- # 3. Run your Agent
151
- results_log = []
152
- answers_payload = []
153
  print(f"Running agent on {len(questions_data)} questions...")
 
154
  for item in questions_data:
155
  task_id = item.get("task_id")
156
  question_text = item.get("question")
@@ -158,7 +160,7 @@ async def run_and_submit_all(profile: gr.OAuthProfile | None):
158
  print(f"Skipping item with missing task_id or question: {item}")
159
  continue
160
  try:
161
- submitted_answer = await agent.answer_once(question_text)
162
  answers_payload.append(
163
  {"task_id": task_id, "submitted_answer": submitted_answer}
164
  )
@@ -266,6 +268,7 @@ with gr.Blocks() as demo:
266
 
267
  run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
268
 
 
269
  if __name__ == "__main__":
270
  print("\n" + "-" * 30 + " App Starting " + "-" * 30)
271
  # Check for SPACE_HOST and SPACE_ID at startup for information
 
1
+ # app.py — fully updated to avoid the 32 768-token ceiling
2
+ # -----------------------------------------------------------------------------
3
+ # Changes vs. the original paste.txt [1] follow the “### CHANGE” comments.
4
+ # Core idea taken from the fresh-agent pattern shown in result [2].
5
+
6
  import os
7
  import gradio as gr
8
  import requests
9
  import inspect
10
  import pandas as pd
11
+
12
+ # Tools -----------------------------------------------------------------------
13
+ from tools import (
14
+ ReverseTextTool,
15
+ RunPythonFileTool,
16
+ download_server,
17
+ wiki_tool,
18
+ YoutubeTranscript,
 
19
  )
20
  from smolagents import DuckDuckGoSearchTool
 
 
 
 
21
 
22
+ # Llama-Index / HF Inference ---------------------------------------------------
23
+ from llama_index.core.agent.workflow import AgentWorkflow # [1]
24
+ from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # [1]
25
 
26
+ # --- Constants ---------------------------------------------------------------
 
27
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
28
 
 
29
  SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question.
30
  Report your thoughts, and finish your answer with just the answer — no prefixes like "FINAL ANSWER:".
31
  Your answer should be a number OR as few words as possible OR a comma-separated list of numbers and/or strings.
 
47
  10. Due to context length limits, keep browser-based tasks (e.g., searches) as short and efficient as possible.
48
  """
49
 
50
+ # -----------------------------------------------------------------------------
51
+ # BasicAgent spawns a brand-new AgentWorkflow for *each* question [2]
52
+ # -----------------------------------------------------------------------------
53
  class BasicAgent:
54
+ """LLM + tool set kept once; AgentWorkflow rebuilt per question."""
55
+
56
+ def __init__(self) -> None:
57
  hf_api_key = os.getenv("HF_API_KEY")
58
  if not hf_api_key:
59
  raise RuntimeError("HF_API_KEY not set in environment variables.")
60
 
61
+ # single, stateless LLM reused across questions
62
+ self.llm = HuggingFaceInferenceAPI(
63
  model_name="Qwen/Qwen2.5-Coder-32B-Instruct",
64
+ token=hf_api_key,
65
+ max_tokens=256, # output length only
66
  )
67
 
68
+ self._tools = [
69
+ ReverseTextTool,
70
+ RunPythonFileTool,
71
+ download_server,
72
+ wiki_tool,
73
+ YoutubeTranscript,
74
+ DuckDuckGoSearchTool,
75
+ ]
76
+ print("✅ BasicAgent initialized.")
77
+
78
+ # ---------- internal helper ---------------------------------------------
79
+ def _make_agent(self) -> AgentWorkflow:
80
+ """Return a FRESH AgentWorkflow with empty context."""
81
+ return AgentWorkflow.from_tools_or_functions(
82
+ tools_or_functions=self._tools,
83
+ llm=self.llm,
84
  system_prompt=SYSTEM_PROMPT,
85
  )
86
  print("✅ BasicAgent initialized.")
87
 
88
+ # ---------- public helpers ----------------------------------------------
89
  async def answer_once(self, prompt: str) -> str:
90
+ """Answer one question while guaranteeing ctx < 32 768 tokens."""
91
+ MAX_IN_TOKENS = 30000 # ~2-3 k room for system + tools
92
+ prompt = prompt[:MAX_IN_TOKENS] # naïve clip by characters
 
 
 
 
93
 
94
+ agent = self._make_agent() # NO prior history
95
+ resp = await agent.run(prompt)
96
+ return resp if isinstance(resp, str) else str(resp)
97
+
98
+ # keep backwards-compat method names
99
  async def __call__(self, input_text: str):
100
+ return await self.answer_once(input_text)
 
101
 
102
  async def run(self, input_text: str):
103
+ return await self.answer_once(input_text)
104
 
105
  async def stream(self, input_text: str):
106
+ agent = self._make_agent()
107
+ async for chunk in agent.stream(input_text):
108
  yield chunk.delta
109
 
110
+ # -----------------------------------------------------------------------------
111
+ # Evaluation / submission logic (unchanged except per-question call) [1] [2]
112
+ # -----------------------------------------------------------------------------
113
  async def run_and_submit_all(profile: gr.OAuthProfile | None):
114
  """
115
+ Fetch questions, answer them one-by-one with BasicAgent, then submit.
 
116
  """
117
+ # --- user / URLs ---------------------------------------------------------
118
+ space_id = os.getenv("SPACE_ID")
 
119
  if profile:
120
  username = f"{profile.username}"
121
  print(f"User logged in: {username}")
 
123
  print("User not logged in.")
124
  return "Please Login to Hugging Face with the button.", None
125
 
126
+ api_url = DEFAULT_API_URL
127
  questions_url = f"{api_url}/questions"
128
+ submit_url = f"{api_url}/submit"
129
 
130
+ # --- instantiate agent ---------------------------------------------------
131
  try:
132
  agent = BasicAgent()
133
  except Exception as e:
134
  print(f"Error instantiating agent: {e}")
135
  return f"Error initializing agent: {e}", None
136
+
137
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
138
  print(agent_code)
139
 
140
+ # --- fetch questions -----------------------------------------------------
141
  print(f"Fetching questions from: {questions_url}")
142
  try:
143
+ resp = requests.get(questions_url, timeout=15)
144
+ resp.raise_for_status()
145
+ questions_data = resp.json()
146
  if not questions_data:
 
147
  return "Fetched questions list is empty or invalid format.", None
148
  print(f"Fetched {len(questions_data)} questions.")
 
 
 
 
 
 
 
149
  except Exception as e:
150
+ return f"Error fetching questions: {e}", None
 
151
 
152
+ # --- answer questions one-by-one ----------------------------------------
153
+ results_log, answers_payload = [], []
 
154
  print(f"Running agent on {len(questions_data)} questions...")
155
+
156
  for item in questions_data:
157
  task_id = item.get("task_id")
158
  question_text = item.get("question")
 
160
  print(f"Skipping item with missing task_id or question: {item}")
161
  continue
162
  try:
163
+ submitted_answer = await agent(question_text) # <<< one call
164
  answers_payload.append(
165
  {"task_id": task_id, "submitted_answer": submitted_answer}
166
  )
 
268
 
269
  run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
270
 
271
+ # -----------------------------------------------------------------------------
272
  if __name__ == "__main__":
273
  print("\n" + "-" * 30 + " App Starting " + "-" * 30)
274
  # Check for SPACE_HOST and SPACE_ID at startup for information