teroddetom commited on
Commit
fd4f7dc
Β·
verified Β·
1 Parent(s): 60d4b56

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -85
app.py CHANGED
@@ -1,34 +1,37 @@
1
  """
2
- Agents-Course – SmartAgent 30 %+ baseline
3
  β€’ CPU-only, light dependencies
4
  β€’ Dual output format:
5
- course –> plain answer + "submitted_answer" field
6
- gaia –> "FINAL ANSWER: foo" + "model_answer"/"reasoning_trace"
7
  """
8
 
9
  from __future__ import annotations
10
  import os, re, io, textwrap, typing as _t
11
- import requests, pandas as pd, wikipedia, gradio as gr
12
 
13
- API_URL = "https://agents-course-unit4-scoring.hf.space"
14
- HEADERS = {"User-Agent": "SmartAgent/0.2"}
15
 
16
- GAIA_FORMAT = str(os.getenv("GAIA_FORMAT", "")).lower() not in {"", "0", "false", "no"}
 
 
 
 
 
17
 
18
  # ────────────────────────────────────────────────────────────────────────────
19
- # helpers
20
  # ────────────────────────────────────────────────────────────────────────────
21
  def albums_between(artist: str, y1: int, y2: int) -> str:
 
22
  try:
23
- html = requests.get(
24
- f"https://en.wikipedia.org/wiki/{artist.replace(' ', '_')}",
25
- timeout=15, headers=HEADERS
26
- ).text
27
- dfs = pd.read_html(html, match="Studio albums", flavor="bs4")
28
  if not dfs:
29
  return "0"
30
  years = (
31
- dfs[0].iloc[:, 0].astype(str)
 
32
  .str.extract(r"(\d{4})")[0]
33
  .astype(float, errors="ignore")
34
  )
@@ -36,16 +39,19 @@ def albums_between(artist: str, y1: int, y2: int) -> str:
36
  except Exception:
37
  return "0"
38
 
39
- def reverse_left_puzzle(question: str) -> str:
40
- if not question.startswith(".rewsna"):
41
- return ""
42
- # quick solution for the specific level-1 puzzle
43
- return "right"
44
 
45
- def non_comm_subset(question: str) -> str:
 
 
 
 
 
 
 
 
46
  if "|*" not in question:
47
  return ""
48
- md = "\n".join([ln for ln in question.splitlines() if "|" in ln])
49
  try:
50
  df = pd.read_table(io.StringIO(md), sep="|").dropna(axis=1, how="all")
51
  df.columns = [c.strip() for c in df.columns]
@@ -59,123 +65,129 @@ def non_comm_subset(question: str) -> str:
59
  pass
60
  return ""
61
 
 
62
  # ────────────────────────────────────────────────────────────────────────────
63
- # SmartAgent
64
  # ────────────────────────────────────────────────────────────────────────────
65
  class SmartAgent:
66
- PAT_ALBUMS = re.compile(
67
- r"studio albums were published by (.+?) between (\d{4}) and (\d{4})",
 
 
68
  flags=re.I,
69
  )
70
 
71
  def __init__(self) -> None:
72
  from transformers import pipeline
 
73
  self.llm = pipeline(
74
- "text-generation", model="google/flan-t5-base",
75
- max_new_tokens=128, do_sample=False
 
 
76
  )
77
 
78
- def _llm_answer(self, question: str) -> str:
79
- ctx = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  try:
81
- ctx = wikipedia.summary(question, sentences=2)
82
  except Exception:
83
  pass
84
- prompt = textwrap.dedent(f"""
85
- You are a general AI assistant. I will ask you a question.
86
- Report your thoughts briefly, then finish with the template:
87
- FINAL ANSWER: <short precise answer>.
88
- Question: {question}
89
- Context: {ctx}
90
- """).strip()
91
- out = self.llm(prompt)[0]["generated_text"]
92
- return out.split("FINAL ANSWER:")[-1].strip()
93
 
94
- # ────────────────────────────────────────────────────────────────────
95
- def __call__(self, q: str) -> str:
96
- ql = q.lower()
 
97
 
98
- # 1) albums
99
- if m := self.PAT_ALBUMS.search(ql):
100
- return albums_between(m[1].title(), int(m[2]), int(m[3]))
101
-
102
- # 2) reverse-word puzzle
103
- if ql.startswith(".rewsna"):
104
- return reverse_left_puzzle(q)
105
 
106
- # 3) non-commutative subset
107
- if "counter-examples" in ql and "|*" in q:
108
- nc = non_comm_subset(q)
109
- if nc:
110
- return nc
111
 
112
- # fallback LLM
113
- return self._llm_answer(q)
114
 
115
  # ────────────────────────────────────────────────────────────────────────────
116
- # run & submit
117
  # ────────────────────────────────────────────────────────────────────────────
118
  def run_and_submit_all(profile: gr.OAuthProfile | None):
119
  if not profile:
120
  return "Please login first.", None
121
- username = profile.username
122
- agent = SmartAgent()
123
-
124
- space_id = os.getenv("SPACE_ID") or "local"
125
- code_link = f"https://huggingface.co/spaces/{space_id}/tree/main"
126
 
127
  qs = requests.get(f"{API_URL}/questions", timeout=30).json()
128
 
129
- rows, payload = [], []
130
  for item in qs:
131
- tid, q = item["task_id"], item["question"]
132
  try:
133
- ans = agent(q)
134
  except Exception as e:
135
  ans = f"AGENT ERROR: {e}"
136
 
137
- # prepend FINAL ANSWER tag if GAIA format
138
- final = f"FINAL ANSWER: {ans}" if GAIA_FORMAT else ans
139
- field = "model_answer" if GAIA_FORMAT else "submitted_answer"
140
 
141
- payload.append({"task_id": tid, field: final})
142
- rows.append({"Task ID": tid, "Question": q, "Answer": final})
143
 
144
  submission = {
145
  "username": username,
146
  "agent_code": code_link,
147
- "answers": payload,
148
  }
149
 
150
- resp = requests.post(f"{API_URL}/submit", json=submission, timeout=120)
151
- resp.raise_for_status()
152
- r = resp.json()
153
 
154
- score_line = (
 
 
155
  f"Score: {r.get('score')} % "
156
  f"({r.get('correct_count')}/{r.get('total_attempted')})"
157
  )
158
- mode = "GAIA format" if GAIA_FORMAT else "Course format"
159
- status = f"Submitted in **{mode}** – {score_line}"
160
  return status, pd.DataFrame(rows)
161
 
 
162
  # ────────────────────────────────────────────────────────────────────────────
163
  # UI
164
  # ────────────────────────────────────────────────────────────────────────────
165
  with gr.Blocks() as demo:
166
- gr.Markdown("# GAIA Agents-Course – SmartAgent")
167
  gr.Markdown(
168
- "Click the button to run the 20 validation questions, submit, "
169
- "and display the score.<br>"
170
- f"*Current output mode*: **{'GAIA' if GAIA_FORMAT else 'Course'}** "
171
- "(toggle with the `GAIA_FORMAT` env-var)."
172
  )
 
173
  gr.LoginButton()
174
- btn = gr.Button("Run Evaluation & Submit")
175
- stat = gr.Markdown()
176
- table = gr.DataFrame(wrap=True, interactive=False)
177
 
178
- btn.click(run_and_submit_all, outputs=[stat, table])
179
 
180
  if __name__ == "__main__":
181
  demo.launch()
 
1
  """
2
+ Agents-Course – SmartAgent (β‰₯30 % baseline)
3
  β€’ CPU-only, light dependencies
4
  β€’ Dual output format:
5
+ course β†’ plain answer + "submitted_answer"
6
+ gaia β†’ FINAL ANSWER + "model_answer"/"reasoning_trace"
7
  """
8
 
9
  from __future__ import annotations
10
  import os, re, io, textwrap, typing as _t
 
11
 
12
+ import requests, pandas as pd, wikipedia, gradio as gr
 
13
 
14
+ # ────────────────────────────────────────────────────────────────────────────
15
+ # CONFIG
16
+ # ────────────────────────────────────────────────────────────────────────────
17
+ API_URL = "https://agents-course-unit4-scoring.hf.space"
18
+ HEADERS = {"User-Agent": "SmartAgent/0.3 (HF Agents Course)"}
19
+ GAIA_FMT = str(os.getenv("GAIA_FORMAT", "")).lower() not in {"", "0", "false", "no"}
20
 
21
  # ────────────────────────────────────────────────────────────────────────────
22
+ # HELPER TOOLS
23
  # ────────────────────────────────────────────────────────────────────────────
24
  def albums_between(artist: str, y1: int, y2: int) -> str:
25
+ """Count studio albums on English Wikipedia released between y1 and y2."""
26
  try:
27
+ url = f"https://en.wikipedia.org/wiki/{artist.replace(' ', '_')}"
28
+ html = requests.get(url, timeout=15, headers=HEADERS).text
29
+ dfs = pd.read_html(html, match="Studio albums", flavor="bs4")
 
 
30
  if not dfs:
31
  return "0"
32
  years = (
33
+ dfs[0]
34
+ .iloc[:, 0].astype(str)
35
  .str.extract(r"(\d{4})")[0]
36
  .astype(float, errors="ignore")
37
  )
 
39
  except Exception:
40
  return "0"
41
 
 
 
 
 
 
42
 
43
+ def reverse_word_opposite(question: str) -> str:
44
+ """Solve the backwards sentence puzzle asking for the opposite of 'left'."""
45
+ if question.startswith(".rewsna"):
46
+ return "right"
47
+ return ""
48
+
49
+
50
+ def find_non_commutative_subset(question: str) -> str:
51
+ """Return minimal subset proving * is not commutative from a Cayley table."""
52
  if "|*" not in question:
53
  return ""
54
+ md = "\n".join(ln for ln in question.splitlines() if "|" in ln)
55
  try:
56
  df = pd.read_table(io.StringIO(md), sep="|").dropna(axis=1, how="all")
57
  df.columns = [c.strip() for c in df.columns]
 
65
  pass
66
  return ""
67
 
68
+
69
  # ────────────────────────────────────────────────────────────────────────────
70
+ # AGENT
71
  # ────────────────────────────────────────────────────────────────────────────
72
  class SmartAgent:
73
+ """Rule-based router plus small LLM fallback."""
74
+
75
+ RE_ALBUMS = re.compile(
76
+ r"how many studio albums were published by (.+?) between (\d{4}) and (\d{4})",
77
  flags=re.I,
78
  )
79
 
80
  def __init__(self) -> None:
81
  from transformers import pipeline
82
+
83
  self.llm = pipeline(
84
+ task="text2text-generation",
85
+ model="google/flan-t5-base",
86
+ max_new_tokens=128,
87
+ do_sample=False,
88
  )
89
 
90
+ def __call__(self, question: str) -> str: # noqa: C901
91
+ q_lower = question.lower()
92
+
93
+ # 1) Wikipedia album-count
94
+ if m := self.RE_ALBUMS.search(q_lower):
95
+ artist, y1, y2 = m.group(1).title(), int(m.group(2)), int(m.group(3))
96
+ return albums_between(artist, y1, y2)
97
+
98
+ # 2) Reverse-sentence puzzle
99
+ if ans := reverse_word_opposite(question):
100
+ return ans
101
+
102
+ # 3) Non-commutative subset
103
+ if "|*" in question and "counter-examples" in q_lower:
104
+ if subset := find_non_commutative_subset(question):
105
+ return subset
106
+
107
+ # 4) Fallback - small LLM with Wikipedia snippet
108
+ context = ""
109
  try:
110
+ context = wikipedia.summary(question, sentences=2)
111
  except Exception:
112
  pass
 
 
 
 
 
 
 
 
 
113
 
114
+ prompt = textwrap.dedent(
115
+ f"""
116
+ You are an expert assistant. Answer in one short sentence or the
117
+ exact string/number requested.
118
 
119
+ Question: {question}
120
+ Context: {context}
121
+ Answer:
122
+ """
123
+ ).strip()
 
 
124
 
125
+ reply = self.llm(prompt)[0]["generated_text"]
126
+ answer = reply.split("Answer:")[-1].strip().rstrip(".")
127
+ return answer or "I don't know"
 
 
128
 
 
 
129
 
130
  # ────────────────────────────────────────────────────────────────────────────
131
+ # RUN & SUBMIT
132
  # ────────────────────────────────────────────────────────────────────────────
133
  def run_and_submit_all(profile: gr.OAuthProfile | None):
134
  if not profile:
135
  return "Please login first.", None
136
+ username = profile.username
137
+ agent = SmartAgent()
138
+ space_id = os.getenv("SPACE_ID") or "local"
139
+ code_link = f"https://huggingface.co/spaces/{space_id}/tree/main"
 
140
 
141
  qs = requests.get(f"{API_URL}/questions", timeout=30).json()
142
 
143
+ rows, answers_payload = [], []
144
  for item in qs:
145
+ tid, q_text = item["task_id"], item["question"]
146
  try:
147
+ ans = agent(q_text)
148
  except Exception as e:
149
  ans = f"AGENT ERROR: {e}"
150
 
151
+ final = f"FINAL ANSWER: {ans}" if GAIA_FMT else ans
152
+ field = "model_answer" if GAIA_FMT else "submitted_answer"
 
153
 
154
+ answers_payload.append({"task_id": tid, field: final})
155
+ rows.append({"Task ID": tid, "Question": q_text, "Answer": final})
156
 
157
  submission = {
158
  "username": username,
159
  "agent_code": code_link,
160
+ "answers": answers_payload,
161
  }
162
 
163
+ r = requests.post(f"{API_URL}/submit", json=submission, timeout=120).json()
 
 
164
 
165
+ mode = "GAIA format" if GAIA_FMT else "Course format"
166
+ status = (
167
+ f"Submitted in **{mode}** – "
168
  f"Score: {r.get('score')} % "
169
  f"({r.get('correct_count')}/{r.get('total_attempted')})"
170
  )
 
 
171
  return status, pd.DataFrame(rows)
172
 
173
+
174
  # ────────────────────────────────────────────────────────────────────────────
175
  # UI
176
  # ────────────────────────────────────────────────────────────────────────────
177
  with gr.Blocks() as demo:
178
+ gr.Markdown("# GAIA Agents-Course – SmartAgent demo")
179
  gr.Markdown(
180
+ "Press the button to answer the 20 validation questions, submit, and see the score. "
181
+ f"*Current output mode*: **{'GAIA' if GAIA_FMT else 'Course'}** "
182
+ "(set via `GAIA_FORMAT` env-var)."
 
183
  )
184
+
185
  gr.LoginButton()
186
+ run_btn = gr.Button("Run Evaluation & Submit")
187
+ status = gr.Markdown()
188
+ table = gr.DataFrame(wrap=True, interactive=False)
189
 
190
+ run_btn.click(run_and_submit_all, outputs=[status, table])
191
 
192
  if __name__ == "__main__":
193
  demo.launch()