Files changed (1) hide show
  1. app.py +43 -0
app.py CHANGED
@@ -1,5 +1,6 @@
1
  # --- minimal dependencies ---
2
  import os, re, json, requests
 
3
  import gradio as gr
4
  import pandas as pd
5
  from huggingface_hub import InferenceClient # add to requirements.txt
@@ -7,6 +8,7 @@ from huggingface_hub import InferenceClient # add to requirements.txt
7
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
8
  YOUTUBE_RE = re.compile(r"https?://(?:www\.)?youtube\.com/watch\?v=[\w-]+")
9
  REV_INSTR_RX = re.compile(r'opposite of the word ["“]?([A-Za-z]+)["”]?', re.I)
 
10
 
11
  NUM_WORDS = {
12
  "zero":"0","one":"1","two":"2","three":"3","four":"4","five":"5",
@@ -230,6 +232,37 @@ class BasicAgent:
230
 
231
  return None
232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  # change the template call to pass task_id as second arg
234
  def __call__(self, question: str, task_id: str | None = None) -> str:
235
  ql = question.lower()
@@ -239,6 +272,16 @@ class BasicAgent:
239
  if rev_ans is not None:
240
  return rev_ans
241
 
 
 
 
 
 
 
 
 
 
 
242
  # 0) YouTube special-case: count distinct bird species from description
243
  m = YOUTUBE_RE.search(question)
244
  if m:
 
1
  # --- minimal dependencies ---
2
  import os, re, json, requests
3
+ import chess
4
  import gradio as gr
5
  import pandas as pd
6
  from huggingface_hub import InferenceClient # add to requirements.txt
 
8
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
9
  YOUTUBE_RE = re.compile(r"https?://(?:www\.)?youtube\.com/watch\?v=[\w-]+")
10
  REV_INSTR_RX = re.compile(r'opposite of the word ["“]?([A-Za-z]+)["”]?', re.I)
11
+ FEN_RX = re.compile(r"\bfen\b[:\s]*([rnbqkRNBQK1-8/]+\s+[bw]\s+[KQkq\-]+(?:\s+[a-h36\-]+){2}\s*\d*\s*\d*)", re.I)
12
 
13
  NUM_WORDS = {
14
  "zero":"0","one":"1","two":"2","three":"3","four":"4","five":"5",
 
232
 
233
  return None
234
 
235
+ def _extract_fen(self, text: str) -> str | None:
236
+ if not text:
237
+ return None
238
+ m = FEN_RX.search(text)
239
+ if m:
240
+ return " ".join(m.group(1).split()) # normalize whitespace
241
+ # fallback: sometimes file is just the fen line
242
+ t = text.strip()
243
+ if "/" in t and " w " in t or " b " in t:
244
+ return " ".join(t.split())
245
+ return None
246
+
247
+ def _solve_chess_mate_in_one(self, fen: str) -> str | None:
248
+ try:
249
+ board = chess.Board(fen)
250
+ except Exception:
251
+ return None
252
+ # It’s black’s turn per question; trust FEN side-to-move. If mismatch, flip.
253
+ # (Optional safety)
254
+ # if "black" in self._last_question.lower() and board.turn == chess.WHITE:
255
+ # return None
256
+
257
+ for mv in board.legal_moves:
258
+ board.push(mv)
259
+ is_mate = board.is_checkmate()
260
+ san = board.san(mv) # SAN before popping while board still in that state
261
+ board.pop()
262
+ if is_mate:
263
+ return san # e.g., "Qg2#"
264
+ return None
265
+
266
  # change the template call to pass task_id as second arg
267
  def __call__(self, question: str, task_id: str | None = None) -> str:
268
  ql = question.lower()
 
272
  if rev_ans is not None:
273
  return rev_ans
274
 
275
+
276
+ # CHESS fast-path
277
+ if ("chess" in ql or "algebraic notation" in ql or "diagram" in ql or "board" in ql) and task_id:
278
+ file_text = self._fetch_file_text(task_id)
279
+ fen = self._extract_fen(file_text or "")
280
+ if fen:
281
+ san = self._solve_chess_mate_in_one(fen)
282
+ if san:
283
+ return san
284
+
285
  # 0) YouTube special-case: count distinct bird species from description
286
  m = YOUTUBE_RE.search(question)
287
  if m: