vladd19 commited on
Commit
95f5049
Β·
verified Β·
1 Parent(s): ff312c1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -18
app.py CHANGED
@@ -20,8 +20,6 @@ from langchain_core.messages import HumanMessage, SystemMessage
20
  from langchain_core.tools import tool
21
  from langchain_groq import ChatGroq
22
  from langchain_community.tools import DuckDuckGoSearchRun
23
- from langchain_community.tools.wikipedia.tool import WikipediaQueryRun
24
- from langchain_community.utilities.wikipedia import WikipediaAPIWrapper
25
  from langgraph.graph import END, StateGraph
26
 
27
 
@@ -119,7 +117,6 @@ def _is_image(ct: str, data: bytes) -> bool:
119
  return True
120
  if data.startswith(b"GIF87a") or data.startswith(b"GIF89a"):
121
  return True
122
- # RIFF can also be WAV, so verify WEBP signature.
123
  if data[:4] == b"RIFF" and data[8:12] == b"WEBP":
124
  return True
125
  return False
@@ -144,6 +141,11 @@ def _is_audio_or_video(ct: str, path: str) -> bool:
144
  return ct.startswith("audio/") or ct.startswith("video/") or ext in AUDIO_VIDEO_EXTS
145
 
146
 
 
 
 
 
 
147
  def detect_local_file_kind(task_id: str) -> tuple[str, str | None]:
148
  local_path = get_task_file(task_id)
149
  if not local_path:
@@ -347,11 +349,6 @@ def run_python_file(path: Path, timeout_seconds: int = 8) -> str:
347
  return f"ERROR: Code execution failed: {type(e).__name__}: {e}"
348
 
349
  web_search_tool = DuckDuckGoSearchRun(name="web_search")
350
- wikipedia_tool = WikipediaQueryRun(
351
- name="wikipedia",
352
- api_wrapper=WikipediaAPIWrapper(top_k_results=3, doc_content_chars_max=3000),
353
- )
354
-
355
 
356
  def safe_tool_run(tool_obj: Any, query: str, limit: int = 6000) -> str:
357
  try:
@@ -398,6 +395,15 @@ def is_bad_answer(answer: str) -> bool:
398
  "not enough information",
399
  "unable to answer",
400
  "no answer",
 
 
 
 
 
 
 
 
 
401
  ]
402
  return any(m in a for m in bad_markers)
403
 
@@ -408,7 +414,7 @@ def reversed_english_question(question: str) -> bool:
408
  return sum(1 for m in markers if m in rev) >= 2
409
 
410
 
411
- def maybe_solve_directly_with_python(question: str) -> str | None:
412
  q = question.strip()
413
 
414
  if reversed_english_question(q):
@@ -465,6 +471,11 @@ def last_nonempty_line(text: str) -> str:
465
  return lines[-1] if lines else ""
466
 
467
 
 
 
 
 
 
468
  class AgentState(TypedDict):
469
  question: str
470
  task_id: str
@@ -558,6 +569,8 @@ class BasicAgent:
558
  route = "solve_direct"
559
  elif direct_question(question):
560
  route = "solve_direct"
 
 
561
  else:
562
  route = "solve_research"
563
 
@@ -655,7 +668,7 @@ class BasicAgent:
655
  file_kind = state.get("file_kind", "none")
656
  local_path = state.get("local_path")
657
 
658
- shortcut = maybe_solve_directly_with_python(question)
659
  if shortcut is not None:
660
  return {"context": "Solved by deterministic Python shortcut.", "raw_answer": shortcut}
661
 
@@ -678,29 +691,60 @@ class BasicAgent:
678
  print(f"[research query] {query}")
679
 
680
  web_results = safe_tool_run(web_search_tool, query, limit=5000)
681
- wiki_results = safe_tool_run(wikipedia_tool, query, limit=5000)
682
 
683
  print(f"[web len] {len(web_results)}")
684
- print(f"[wiki len] {len(wiki_results)}")
685
  print(f"[web preview] {repr(web_results[:500])}")
686
- print(f"[wiki preview] {repr(wiki_results[:500])}")
687
 
688
  context = truncate_text(
689
- f"Search query:\n{query}\n\n"
690
- f"Web search results:\n{web_results}\n\n"
691
- f"Wikipedia results:\n{wiki_results}",
692
  MAX_SEARCH_CONTEXT_CHARS,
693
  )
694
 
695
  raw_answer = self.answer_from_context(
696
  question=question,
697
  context=context,
698
- context_label="Web/Wikipedia research results",
699
  llm=self.research_llm,
700
  )
701
 
702
  print(f"[research raw_answer] {repr(raw_answer[:500])}")
703
  return {"context": context, "raw_answer": raw_answer}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
 
705
  def verify_answer(self, state: AgentState) -> dict[str, Any]:
706
  question = state.get("question", "")
@@ -909,7 +953,7 @@ with gr.Blocks() as demo:
909
  """
910
  **Architecture:** `classify_task β†’ route_by_type β†’ solve_* β†’ verify_answer β†’ final_cleaner`.
911
 
912
- Local files are routed deterministically by Python. Web/Wikipedia are called only inside `solve_research`, without automatic LLM tool-calling.
913
  """
914
  )
915
 
 
20
  from langchain_core.tools import tool
21
  from langchain_groq import ChatGroq
22
  from langchain_community.tools import DuckDuckGoSearchRun
 
 
23
  from langgraph.graph import END, StateGraph
24
 
25
 
 
117
  return True
118
  if data.startswith(b"GIF87a") or data.startswith(b"GIF89a"):
119
  return True
 
120
  if data[:4] == b"RIFF" and data[8:12] == b"WEBP":
121
  return True
122
  return False
 
141
  return ct.startswith("audio/") or ct.startswith("video/") or ext in AUDIO_VIDEO_EXTS
142
 
143
 
144
+ def is_youtube_question(question: str) -> bool:
145
+ q = question.lower()
146
+ return "youtube.com/watch" in q or "youtu.be/" in q
147
+
148
+
149
  def detect_local_file_kind(task_id: str) -> tuple[str, str | None]:
150
  local_path = get_task_file(task_id)
151
  if not local_path:
 
349
  return f"ERROR: Code execution failed: {type(e).__name__}: {e}"
350
 
351
  web_search_tool = DuckDuckGoSearchRun(name="web_search")
 
 
 
 
 
352
 
353
  def safe_tool_run(tool_obj: Any, query: str, limit: int = 6000) -> str:
354
  try:
 
395
  "not enough information",
396
  "unable to answer",
397
  "no answer",
398
+ "no answer found",
399
+ "i could not find",
400
+ "could not find",
401
+ "not found",
402
+ "not in the search results",
403
+ "this answer is not",
404
+ "unknown",
405
+ "insufficient information",
406
+ "cannot determine",
407
  ]
408
  return any(m in a for m in bad_markers)
409
 
 
414
  return sum(1 for m in markers if m in rev) >= 2
415
 
416
 
417
+ def solve_directly_with_python(question: str) -> str | None:
418
  q = question.strip()
419
 
420
  if reversed_english_question(q):
 
471
  return lines[-1] if lines else ""
472
 
473
 
474
+ def extract_youtube_id(question: str) -> str | None:
475
+ m = re.search(r"(?:v=|youtu\.be/)([A-Za-z0-9_-]{11})", question)
476
+ return m.group(1) if m else None
477
+
478
+
479
  class AgentState(TypedDict):
480
  question: str
481
  task_id: str
 
569
  route = "solve_direct"
570
  elif direct_question(question):
571
  route = "solve_direct"
572
+ elif is_youtube_question(question):
573
+ route = "solve_youtube"
574
  else:
575
  route = "solve_research"
576
 
 
668
  file_kind = state.get("file_kind", "none")
669
  local_path = state.get("local_path")
670
 
671
+ shortcut = solve_directly_with_python(question)
672
  if shortcut is not None:
673
  return {"context": "Solved by deterministic Python shortcut.", "raw_answer": shortcut}
674
 
 
691
  print(f"[research query] {query}")
692
 
693
  web_results = safe_tool_run(web_search_tool, query, limit=5000)
 
694
 
695
  print(f"[web len] {len(web_results)}")
 
696
  print(f"[web preview] {repr(web_results[:500])}")
 
697
 
698
  context = truncate_text(
699
+ f"Search query:\n{query}\n\n",
700
+ f"Web search results:\n{web_results}\n\n",
 
701
  MAX_SEARCH_CONTEXT_CHARS,
702
  )
703
 
704
  raw_answer = self.answer_from_context(
705
  question=question,
706
  context=context,
707
+ context_label="Web research results",
708
  llm=self.research_llm,
709
  )
710
 
711
  print(f"[research raw_answer] {repr(raw_answer[:500])}")
712
  return {"context": context, "raw_answer": raw_answer}
713
+
714
+ def solve_youtube(self, state: AgentState) -> dict:
715
+ question = state["question"]
716
+ video_id = extract_youtube_id(question)
717
+
718
+ queries = []
719
+
720
+ if video_id:
721
+ queries += [
722
+ f'"{video_id}" transcript',
723
+ f'"{video_id}" subtitles',
724
+ f'"{video_id}" "{question[:80]}"',
725
+ ]
726
+
727
+ queries.append(question)
728
+
729
+ parts = []
730
+
731
+ for query in queries:
732
+ result = safe_tool_run(web_search_tool, query, limit=5000)
733
+ parts.append(f"Query: {query}\nResults:\n{result}")
734
+
735
+ context = "\n\n---\n\n".join(parts)[:16000]
736
+
737
+ raw_answer = self.answer_from_context(
738
+ question=question,
739
+ context=context,
740
+ context_label="YouTube/web transcript search results",
741
+ llm=self.research_llm,
742
+ )
743
+
744
+ return {
745
+ "context": context,
746
+ "raw_answer": raw_answer,
747
+ }
748
 
749
  def verify_answer(self, state: AgentState) -> dict[str, Any]:
750
  question = state.get("question", "")
 
953
  """
954
  **Architecture:** `classify_task β†’ route_by_type β†’ solve_* β†’ verify_answer β†’ final_cleaner`.
955
 
956
+ Local files are routed deterministically by Python. Web are called only inside `solve_research`, without automatic LLM tool-calling.
957
  """
958
  )
959