Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -22,6 +22,9 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
|
| 22 |
RESULT_COLUMNS = ["Task ID", "Question", "Submitted Answer"]
|
| 23 |
HTTP_TIMEOUT = 45
|
| 24 |
MAX_EXTRACTED_CHARS = 35_000
|
|
|
|
|
|
|
|
|
|
| 25 |
DEFAULT_MAIN_MODEL = "groq/qwen/qwen3.6-27b"
|
| 26 |
DEFAULT_GROQ_REVIEW_MODEL = "groq/qwen/qwen3.6-27b"
|
| 27 |
TASK_FILE_CACHE = {}
|
|
@@ -248,8 +251,9 @@ class OpenWebPageTool(Tool):
|
|
| 248 |
description = (
|
| 249 |
"Opens and reads one exact HTTP/HTTPS page. Use it after web_search to "
|
| 250 |
"verify article text, tables, archives, papers, and linked sources. "
|
| 251 |
-
"It
|
| 252 |
-
"It is not a
|
|
|
|
| 253 |
)
|
| 254 |
inputs = {
|
| 255 |
"url": {
|
|
@@ -283,7 +287,7 @@ class OpenWebPageTool(Tool):
|
|
| 283 |
response = requests.get(
|
| 284 |
target,
|
| 285 |
headers=headers,
|
| 286 |
-
timeout=
|
| 287 |
allow_redirects=True,
|
| 288 |
)
|
| 289 |
response.raise_for_status()
|
|
@@ -300,10 +304,68 @@ class OpenWebPageTool(Tool):
|
|
| 300 |
|
| 301 |
text = response.text
|
| 302 |
if "html" in content_type:
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
return text or "The page was retrieved but contained no text."
|
| 308 |
except Exception as exc:
|
| 309 |
errors.append(f"{target}: {exc}")
|
|
@@ -489,7 +551,8 @@ class BasicAgent:
|
|
| 489 |
model_id=model_id,
|
| 490 |
api_key=groq_api_key,
|
| 491 |
temperature=0,
|
| 492 |
-
max_tokens=
|
|
|
|
| 493 |
)
|
| 494 |
self.hf_token = hf_token
|
| 495 |
self.model_id = model_id
|
|
@@ -721,6 +784,16 @@ include reasoning, explanations, labels, Markdown, citations, or the words
|
|
| 721 |
except ValueError:
|
| 722 |
pass
|
| 723 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 724 |
person_question = (
|
| 725 |
question_lower.startswith("who ")
|
| 726 |
or " who " in f" {question_lower} "
|
|
|
|
| 22 |
RESULT_COLUMNS = ["Task ID", "Question", "Submitted Answer"]
|
| 23 |
HTTP_TIMEOUT = 45
|
| 24 |
MAX_EXTRACTED_CHARS = 35_000
|
| 25 |
+
WEBPAGE_CONNECT_TIMEOUT = 8
|
| 26 |
+
WEBPAGE_READ_TIMEOUT = 20
|
| 27 |
+
MAX_WEBPAGE_CHARS = 8_000
|
| 28 |
DEFAULT_MAIN_MODEL = "groq/qwen/qwen3.6-27b"
|
| 29 |
DEFAULT_GROQ_REVIEW_MODEL = "groq/qwen/qwen3.6-27b"
|
| 30 |
TASK_FILE_CACHE = {}
|
|
|
|
| 251 |
description = (
|
| 252 |
"Opens and reads one exact HTTP/HTTPS page. Use it after web_search to "
|
| 253 |
"verify article text, tables, archives, papers, and linked sources. "
|
| 254 |
+
"It returns concise main-page content while preserving links near the "
|
| 255 |
+
"end, and retries blocked HTML through a text mirror. It is not a "
|
| 256 |
+
"binary-file downloader."
|
| 257 |
)
|
| 258 |
inputs = {
|
| 259 |
"url": {
|
|
|
|
| 287 |
response = requests.get(
|
| 288 |
target,
|
| 289 |
headers=headers,
|
| 290 |
+
timeout=(WEBPAGE_CONNECT_TIMEOUT, WEBPAGE_READ_TIMEOUT),
|
| 291 |
allow_redirects=True,
|
| 292 |
)
|
| 293 |
response.raise_for_status()
|
|
|
|
| 304 |
|
| 305 |
text = response.text
|
| 306 |
if "html" in content_type:
|
| 307 |
+
from bs4 import BeautifulSoup
|
| 308 |
+
from trafilatura import extract
|
| 309 |
+
from urllib.parse import urljoin
|
| 310 |
+
|
| 311 |
+
soup = BeautifulSoup(text, "html.parser")
|
| 312 |
+
for element in soup.select(
|
| 313 |
+
"script, style, noscript, nav, header, footer, form, "
|
| 314 |
+
"aside, iframe"
|
| 315 |
+
):
|
| 316 |
+
element.decompose()
|
| 317 |
+
main_content = (
|
| 318 |
+
soup.find("article")
|
| 319 |
+
or soup.find("main")
|
| 320 |
+
or soup.body
|
| 321 |
+
or soup
|
| 322 |
+
)
|
| 323 |
+
extracted = extract(
|
| 324 |
+
text,
|
| 325 |
+
url=target,
|
| 326 |
+
output_format="markdown",
|
| 327 |
+
include_comments=False,
|
| 328 |
+
include_tables=True,
|
| 329 |
+
include_links=True,
|
| 330 |
+
favor_recall=True,
|
| 331 |
+
)
|
| 332 |
+
text = (
|
| 333 |
+
extracted
|
| 334 |
+
if extracted and len(extracted.strip()) >= 200
|
| 335 |
+
else markdownify(str(main_content))
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
+
# Article extractors sometimes classify bibliography links
|
| 339 |
+
# as navigation. Append a compact link index so the agent
|
| 340 |
+
# can still open papers and primary sources cited at the end.
|
| 341 |
+
source_links = []
|
| 342 |
+
seen_links = set()
|
| 343 |
+
for anchor in main_content.find_all("a", href=True):
|
| 344 |
+
label = " ".join(anchor.get_text(" ", strip=True).split())
|
| 345 |
+
absolute_url = urljoin(target, anchor["href"])
|
| 346 |
+
if (
|
| 347 |
+
label
|
| 348 |
+
and absolute_url.startswith(("http://", "https://"))
|
| 349 |
+
and absolute_url not in seen_links
|
| 350 |
+
):
|
| 351 |
+
seen_links.add(absolute_url)
|
| 352 |
+
source_links.append(
|
| 353 |
+
f"- [{label[:160]}]({absolute_url})"
|
| 354 |
+
)
|
| 355 |
+
if source_links:
|
| 356 |
+
text += (
|
| 357 |
+
"\n\nSource links found on the page:\n"
|
| 358 |
+
+ "\n".join(source_links[-25:])
|
| 359 |
+
)
|
| 360 |
+
text = re.sub(r"\n{3,}", "\n\n", text).strip()
|
| 361 |
+
if len(text) > MAX_WEBPAGE_CHARS:
|
| 362 |
+
head_size = 5_000
|
| 363 |
+
tail_size = MAX_WEBPAGE_CHARS - head_size
|
| 364 |
+
text = (
|
| 365 |
+
text[:head_size]
|
| 366 |
+
+ "\n\n[page middle omitted to conserve tokens]\n\n"
|
| 367 |
+
+ text[-tail_size:]
|
| 368 |
+
)
|
| 369 |
return text or "The page was retrieved but contained no text."
|
| 370 |
except Exception as exc:
|
| 371 |
errors.append(f"{target}: {exc}")
|
|
|
|
| 551 |
model_id=model_id,
|
| 552 |
api_key=groq_api_key,
|
| 553 |
temperature=0,
|
| 554 |
+
max_tokens=1_200,
|
| 555 |
+
requests_per_minute=2,
|
| 556 |
)
|
| 557 |
self.hf_token = hf_token
|
| 558 |
self.model_id = model_id
|
|
|
|
| 784 |
except ValueError:
|
| 785 |
pass
|
| 786 |
|
| 787 |
+
if "award number" in question_lower or "grant number" in question_lower:
|
| 788 |
+
identifiers = re.findall(r"\b[A-Z0-9][A-Z0-9-]{5,}\b", text.upper())
|
| 789 |
+
identifiers = [
|
| 790 |
+
value
|
| 791 |
+
for value in identifiers
|
| 792 |
+
if re.search(r"[A-Z]", value) and re.search(r"\d", value)
|
| 793 |
+
]
|
| 794 |
+
if identifiers:
|
| 795 |
+
return identifiers[-1].strip(" .,:;\"'")
|
| 796 |
+
|
| 797 |
person_question = (
|
| 798 |
question_lower.startswith("who ")
|
| 799 |
or " who " in f" {question_lower} "
|