selim-ba commited on
Commit
8ec467d
·
verified ·
1 Parent(s): 0577dc3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -111
app.py CHANGED
@@ -8,9 +8,11 @@ from typing import TypedDict
8
  import string
9
 
10
 
11
- ###
12
-
13
  import wikipedia
 
 
14
 
15
  # (Keep Constants as is)
16
  # --- Constants ---
@@ -27,60 +29,43 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
27
  # print(f"Agent returning fixed answer: {fixed_answer}")
28
  # return fixed_answer
29
 
 
 
30
  class SuperSmartAgent:
31
  def __init__(self):
32
  self.graph = self._build_graph()
33
 
34
  def _build_graph(self):
35
- ############## NODES ###################
36
  def score_text(text):
37
- # Count alphanumeric characters
38
  alnum_count = sum(c.isalnum() for c in text)
39
- # Count spaces
40
  space_count = text.count(' ')
41
- # Count punctuation marks
42
  punctuation_count = sum(c in string.punctuation for c in text)
43
- # Check if text ends with sentence punctuation (., !, ?)
44
  ends_properly = text[-1] in '.!?'
45
-
46
- # Simple heuristic score: alnum + spaces + bonus if ends properly
47
  score = alnum_count + space_count
48
  if ends_properly:
49
- score += 5 # give bonus if text ends with punctuation
50
-
51
  return score
52
 
53
  def check_reversed(state):
54
  question = state["question"]
55
  reversed_candidate = question[::-1]
56
-
57
  original_score = score_text(question)
58
  reversed_score = score_text(reversed_candidate)
59
-
60
- print(f"Original text score: {original_score}")
61
- print(f"Reversed text score: {reversed_score}")
62
-
63
  if reversed_score > original_score:
64
- print("Detected reversed text. Marking as reversed.")
65
  state["is_reversed"] = True
66
  else:
67
- print("No reversal detected.")
68
  state["is_reversed"] = False
69
  return state
70
-
71
  def fix_question(state):
72
  if state.get("is_reversed", False):
73
- print(f"Fixing question by reversing: {state['question']}")
74
  state["question"] = state["question"][::-1]
75
- print(f"Fixed question: {state['question']}")
76
  return state
77
 
78
  def check_riddle_or_trick(state):
79
- print(f"Checking riddle/trick keywords in question: {state['question']}")
80
  q = state["question"].lower()
81
  keywords = ["opposite of", "if you understand", "riddle", "trick question", "what comes next", "i speak without"]
82
  state["is_riddle"] = any(kw in q for kw in keywords)
83
- print(f"is_riddle: {state['is_riddle']}")
84
  return state
85
 
86
  def solve_riddle(state):
@@ -97,16 +82,13 @@ class SuperSmartAgent:
97
  else:
98
  state["response"] = "Could not solve riddle."
99
  return state
100
-
101
  def check_python_suitability(state):
102
  question = state["question"].lower()
103
  patterns = ["sum", "average", "count", "sort", "generate", "regex", "convert"]
104
- if any(word in question for word in patterns):
105
- state["is_python"] = True
106
- else:
107
- state["is_python"] = False
108
  return state
109
-
110
  def generate_code(state):
111
  q = state["question"].lower()
112
  if "sum" in q:
@@ -118,84 +100,23 @@ class SuperSmartAgent:
118
  else:
119
  state["response"] = "# Code generation not implemented for this case."
120
  return state
121
-
122
  def fallback(state):
123
- print(f"Fallback triggered. Final question state: {state['question']}")
124
  state["response"] = "This question doesn't require Python or is unclear."
125
  return state
126
 
127
- ###################
128
- def general_reasoning_qa(state):
129
- question = state["question"]
130
-
131
- # Step 1: Search Wikipedia for relevant pages
132
- search_results = wikipedia.search(question)
133
- relevant_pages = search_results[:3] # get top 3 pages
134
-
135
- context = ""
136
- for title in relevant_pages:
137
- try:
138
- page = wikipedia.page(title)
139
- context += page.content + "\n"
140
- except:
141
- continue
142
-
143
- if not context:
144
- state["response"] = "Sorry, I couldn’t find enough information."
145
- return state
146
-
147
- # Step 2: Process the context to extract relevant information
148
- # This is a simplified approach; in practice, you'd use more sophisticated NLP techniques
149
- # For example, you can look for numerical data, dates, names, etc., in the context
150
-
151
- # Example: Extract numbers and names from the context
152
- import re
153
- numbers = re.findall(r'\d+', context)
154
- names = re.findall(r'\b[A-Z][a-z]+ [A-Z][a-z]+\b', context) # Simplified pattern for names
155
-
156
- # Step 3: Generate an answer based on the processed context
157
- # This is a placeholder; in practice, you'd need a more sophisticated method
158
- if "How many" in question:
159
- if numbers:
160
- # Assume the first number is relevant (this is a very simplistic approach)
161
- state["response"] = f"The answer is {numbers[0]}."
162
- else:
163
- state["response"] = "I couldn't find a numerical answer in the context."
164
- elif "who" in question.lower() or "what" in question.lower():
165
- if names:
166
- # Assume the first name is relevant (this is a very simplistic approach)
167
- state["response"] = f"The answer is {names[0]}."
168
- else:
169
- state["response"] = "I couldn't find a relevant name in the context."
170
- else:
171
- # Fallback to returning a summary if no specific pattern matches
172
- try:
173
- page = wikipedia.page(relevant_pages[0])
174
- summary = page.summary
175
- state["response"] = summary
176
- except Exception as e:
177
- state["response"] = f"Error fetching Wikipedia content: {e}"
178
-
179
- return state
180
-
181
-
182
-
183
  def check_reasoning_needed(state):
184
  q = state["question"].lower()
185
- # very rough heuristic — refine as needed
186
  needs_reasoning = any(word in q for word in ["whose", "only", "first", "after", "before", "no longer", "not", "but", "except"])
187
  state["needs_reasoning"] = needs_reasoning
188
  return state
189
-
190
 
191
  def check_wikipedia_suitability(state):
192
  q = state["question"].lower()
193
- # Simple heuristic: if it's a "who is", "what is", or named entity
194
  triggers = ["wikipedia","Wikipedia","who is", "what is", "when did", "where is", "tell me about", "How many"]
195
  state["is_wiki"] = any(trigger in q for trigger in triggers)
196
- print(f"is_wiki: {state['is_wiki']}")
197
  return state
198
-
199
  def search_wikipedia(state):
200
  question = state["question"]
201
  try:
@@ -203,7 +124,7 @@ class SuperSmartAgent:
203
  if not page_titles:
204
  state["response"] = "No relevant Wikipedia article found."
205
  return state
206
-
207
  page = wikipedia.page(page_titles[0])
208
  summary = page.summary
209
  state["response"] = summary
@@ -211,8 +132,65 @@ class SuperSmartAgent:
211
  state["response"] = f"Error fetching Wikipedia content: {e}"
212
  return state
213
 
214
- ##################
215
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  class AgentState(TypedDict, total=False):
217
  question: str
218
  is_reversed: bool
@@ -220,10 +198,8 @@ class SuperSmartAgent:
220
  is_riddle: bool
221
  use_tool: str
222
  response: str
223
-
224
- builder = StateGraph(AgentState)
225
-
226
 
 
227
  # --- Nodes ---
228
  builder.add_node("check_reversed", check_reversed)
229
  builder.add_node("fix_question", fix_question)
@@ -236,34 +212,33 @@ class SuperSmartAgent:
236
  builder.add_node("check_python_suitability", check_python_suitability)
237
  builder.add_node("generate_code", generate_code)
238
  builder.add_node("fallback", fallback)
239
-
240
  # Entry
241
  builder.set_entry_point("check_reversed")
242
-
243
  # Edges
244
  builder.add_edge("check_reversed", "fix_question")
245
  builder.add_edge("fix_question", "check_riddle_or_trick")
246
-
247
  builder.add_conditional_edges(
248
  "check_riddle_or_trick",
249
  lambda s: "solve_riddle" if s.get("is_riddle") else "check_wikipedia_suitability"
250
  )
251
-
252
  builder.add_conditional_edges(
253
  "check_wikipedia_suitability",
254
  lambda s: "search_wikipedia" if s.get("is_wiki") else "check_reasoning_needed"
255
  )
256
-
257
  builder.add_conditional_edges(
258
  "check_reasoning_needed",
259
  lambda s: "general_reasoning_qa" if s.get("needs_reasoning") else "check_python_suitability"
260
  )
261
-
262
  builder.add_conditional_edges(
263
  "check_python_suitability",
264
  lambda s: "generate_code" if s.get("is_python") else "fallback"
265
  )
266
-
267
  # Ends
268
  builder.add_edge("solve_riddle", END)
269
  builder.add_edge("search_wikipedia", END)
@@ -271,20 +246,16 @@ class SuperSmartAgent:
271
  builder.add_edge("generate_code", END)
272
  builder.add_edge("fallback", END)
273
 
274
-
275
-
276
-
277
-
278
  graph = builder.compile()
279
  return graph
280
-
281
  def __call__(self, question: str) -> str:
282
- # use self.graph to process the question
283
  state = {"question": question}
284
  result = self.graph.invoke(state)
285
  return result.get("response", "No answer generated.")
286
 
287
 
 
288
  ########################################
289
  def run_and_submit_all( profile: gr.OAuthProfile | None):
290
  """
 
8
  import string
9
 
10
 
11
+ from transformers import pipeline
12
+ import re
13
  import wikipedia
14
+ import wikipediaapi
15
+
16
 
17
  # (Keep Constants as is)
18
  # --- Constants ---
 
29
  # print(f"Agent returning fixed answer: {fixed_answer}")
30
  # return fixed_answer
31
 
32
+
33
+
34
  class SuperSmartAgent:
35
  def __init__(self):
36
  self.graph = self._build_graph()
37
 
38
  def _build_graph(self):
 
39
  def score_text(text):
 
40
  alnum_count = sum(c.isalnum() for c in text)
 
41
  space_count = text.count(' ')
 
42
  punctuation_count = sum(c in string.punctuation for c in text)
 
43
  ends_properly = text[-1] in '.!?'
 
 
44
  score = alnum_count + space_count
45
  if ends_properly:
46
+ score += 5
 
47
  return score
48
 
49
  def check_reversed(state):
50
  question = state["question"]
51
  reversed_candidate = question[::-1]
 
52
  original_score = score_text(question)
53
  reversed_score = score_text(reversed_candidate)
 
 
 
 
54
  if reversed_score > original_score:
 
55
  state["is_reversed"] = True
56
  else:
 
57
  state["is_reversed"] = False
58
  return state
59
+
60
  def fix_question(state):
61
  if state.get("is_reversed", False):
 
62
  state["question"] = state["question"][::-1]
 
63
  return state
64
 
65
  def check_riddle_or_trick(state):
 
66
  q = state["question"].lower()
67
  keywords = ["opposite of", "if you understand", "riddle", "trick question", "what comes next", "i speak without"]
68
  state["is_riddle"] = any(kw in q for kw in keywords)
 
69
  return state
70
 
71
  def solve_riddle(state):
 
82
  else:
83
  state["response"] = "Could not solve riddle."
84
  return state
85
+
86
  def check_python_suitability(state):
87
  question = state["question"].lower()
88
  patterns = ["sum", "average", "count", "sort", "generate", "regex", "convert"]
89
+ state["is_python"] = any(word in question for word in patterns)
 
 
 
90
  return state
91
+
92
  def generate_code(state):
93
  q = state["question"].lower()
94
  if "sum" in q:
 
100
  else:
101
  state["response"] = "# Code generation not implemented for this case."
102
  return state
103
+
104
  def fallback(state):
 
105
  state["response"] = "This question doesn't require Python or is unclear."
106
  return state
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  def check_reasoning_needed(state):
109
  q = state["question"].lower()
 
110
  needs_reasoning = any(word in q for word in ["whose", "only", "first", "after", "before", "no longer", "not", "but", "except"])
111
  state["needs_reasoning"] = needs_reasoning
112
  return state
 
113
 
114
  def check_wikipedia_suitability(state):
115
  q = state["question"].lower()
 
116
  triggers = ["wikipedia","Wikipedia","who is", "what is", "when did", "where is", "tell me about", "How many"]
117
  state["is_wiki"] = any(trigger in q for trigger in triggers)
 
118
  return state
119
+
120
  def search_wikipedia(state):
121
  question = state["question"]
122
  try:
 
124
  if not page_titles:
125
  state["response"] = "No relevant Wikipedia article found."
126
  return state
127
+
128
  page = wikipedia.page(page_titles[0])
129
  summary = page.summary
130
  state["response"] = summary
 
132
  state["response"] = f"Error fetching Wikipedia content: {e}"
133
  return state
134
 
135
+ def preprocess_context(context):
136
+ context = re.sub(r'\[\d+\]', '', context) # Remove citations
137
+ context = re.sub(r'\s+', ' ', context).strip() # Clean whitespace
138
+ return context
139
+
140
+ def validate_answer(question, answer):
141
+ if "how many" in question.lower():
142
+ if not re.search(r'\d+', answer):
143
+ return False
144
+ return True
145
+
146
+ def general_reasoning_qa(state):
147
+ question = state["question"]
148
+
149
+ # Step 1: Search Wikipedia and gather context
150
+ context = ""
151
+ try:
152
+ wiki_wiki = wikipediaapi.Wikipedia('en')
153
+ search_results = wiki_wiki.search(question, results=3) # get top 3 pages
154
+
155
+ for title in search_results:
156
+ page = wiki_wiki.page(title)
157
+ if page.exists():
158
+ context += page.text + "\n"
159
+ except Exception as e:
160
+ state["response"] = f"Error fetching Wikipedia content: {e}"
161
+ return state
162
+
163
+ if not context:
164
+ state["response"] = "Sorry, I couldn’t find enough information."
165
+ return state
166
+
167
+ context = preprocess_context(context)
168
+
169
+ # Step 2: Use a pre-trained QA model to generate the answer
170
+ try:
171
+ qa_pipeline = pipeline("question-answering")
172
+ result = qa_pipeline(question=question, context=context)
173
+ answer = result['answer']
174
+
175
+ if validate_answer(question, answer):
176
+ state["response"] = answer
177
+ else:
178
+ # Fallback: return a summary if the answer is not validated
179
+ try:
180
+ page_titles = wikipedia.search(question)
181
+ if page_titles:
182
+ page = wikipedia.page(page_titles[0])
183
+ summary = page.summary
184
+ state["response"] = summary
185
+ else:
186
+ state["response"] = "No relevant Wikipedia article found."
187
+ except Exception as e:
188
+ state["response"] = f"Error fetching Wikipedia content: {e}"
189
+ except Exception as e:
190
+ state["response"] = f"Error generating answer: {e}"
191
+
192
+ return state
193
+
194
  class AgentState(TypedDict, total=False):
195
  question: str
196
  is_reversed: bool
 
198
  is_riddle: bool
199
  use_tool: str
200
  response: str
 
 
 
201
 
202
+ builder = StateGraph(AgentState)
203
  # --- Nodes ---
204
  builder.add_node("check_reversed", check_reversed)
205
  builder.add_node("fix_question", fix_question)
 
212
  builder.add_node("check_python_suitability", check_python_suitability)
213
  builder.add_node("generate_code", generate_code)
214
  builder.add_node("fallback", fallback)
215
+
216
  # Entry
217
  builder.set_entry_point("check_reversed")
 
218
  # Edges
219
  builder.add_edge("check_reversed", "fix_question")
220
  builder.add_edge("fix_question", "check_riddle_or_trick")
221
+
222
  builder.add_conditional_edges(
223
  "check_riddle_or_trick",
224
  lambda s: "solve_riddle" if s.get("is_riddle") else "check_wikipedia_suitability"
225
  )
226
+
227
  builder.add_conditional_edges(
228
  "check_wikipedia_suitability",
229
  lambda s: "search_wikipedia" if s.get("is_wiki") else "check_reasoning_needed"
230
  )
231
+
232
  builder.add_conditional_edges(
233
  "check_reasoning_needed",
234
  lambda s: "general_reasoning_qa" if s.get("needs_reasoning") else "check_python_suitability"
235
  )
236
+
237
  builder.add_conditional_edges(
238
  "check_python_suitability",
239
  lambda s: "generate_code" if s.get("is_python") else "fallback"
240
  )
241
+
242
  # Ends
243
  builder.add_edge("solve_riddle", END)
244
  builder.add_edge("search_wikipedia", END)
 
246
  builder.add_edge("generate_code", END)
247
  builder.add_edge("fallback", END)
248
 
 
 
 
 
249
  graph = builder.compile()
250
  return graph
251
+
252
  def __call__(self, question: str) -> str:
 
253
  state = {"question": question}
254
  result = self.graph.invoke(state)
255
  return result.get("response", "No answer generated.")
256
 
257
 
258
+
259
  ########################################
260
  def run_and_submit_all( profile: gr.OAuthProfile | None):
261
  """