From 31dc984197490e31ed84d325877fc8457614f893 Mon Sep 17 00:00:00 2001 From: moosecrap Date: Fri, 24 Jul 2026 22:53:22 -0700 Subject: [PATCH] Documentation --- README.md | 6 ++++++ config.py | 2 +- tools/wikipedia.py | 26 ++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index faa8a4c..dc4995c 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,12 @@ Extracts AI generation parameters from PNG files. Returns the full-resolution image. * **Best for**: Final confirmation or deep visual analysis where every pixel counts. +### 🌐 `browse_wikipedia` +Allows the model to browse Wikipedia using its API. +* **Best for**: Quickly retrieving summaries, structural maps (ToC), or specific section content from Wikipedia without dumping the entire page. +* **Workflow**: Use `mode='summary'` (default) to get an overview and a Table of Contents. Use `mode='section'` with a linear index from the ToC to dive into specific details. +* **Features**: Returns raw Wikitext to save tokens, handles redirects, and automatically falls back to a search result list if a page is not found. + --- ## Installation & Requirements diff --git a/config.py b/config.py index 9866cf5..fbb731f 100644 --- a/config.py +++ b/config.py @@ -5,7 +5,7 @@ HOST = "127.0.0.1" PORT = 8000 LOG_LEVEL = "WARNING" # Options: "DEBUG", "INFO", "WARNING", "ERROR" LOG_FILE = "debug.log" -USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0" +USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0" # Stealth User-Agent to bypass Wikipedia's bot detection # --- Model Specific Token Tuning (Tuned for Gemma 4) --- # Patch size is typically (clip.vision.patch_size * n_merge) diff --git a/tools/wikipedia.py b/tools/wikipedia.py index 8d71e31..26c6736 100644 --- a/tools/wikipedia.py +++ b/tools/wikipedia.py @@ -10,11 +10,15 @@ import config API_URL = "https://en.wikipedia.org/w/api.php" def strip_html(text: str) -> str: - """Removes HTML tags from a string using regex.""" + """Removes HTML tags from a string using regex to provide clean text to the LLM.""" return re.sub(r'<[^>]*>', '', text) def _make_request(params: Dict[str, Any]) -> Dict[str, Any]: - """Synchronous helper to make the API request using urllib.""" + """ + Synchronous helper to make the API request using urllib. + urllib is used instead of httpx to avoid TLS/HTTP fingerprinting + that triggers 403 Forbidden responses from Wikipedia. + """ query_string = urllib.parse.urlencode(params) url = f"{API_URL}?{query_string}" @@ -27,6 +31,10 @@ def _make_request(params: Dict[str, Any]) -> Dict[str, Any]: return json.loads(response.read().decode('utf-8')) async def _search(title: str, limit: int = 5, fallback: bool = False) -> str: + """ + Searches Wikipedia for a title. + fallback=True: Used when a direct page request fails, providing 'Article not found' header. + """ params = { "action": "query", "list": "search", @@ -34,6 +42,7 @@ async def _search(title: str, limit: int = 5, fallback: bool = False) -> str: "format": "json", "srlimit": limit } + # Run synchronous urllib call in a thread to avoid blocking the event loop data = await asyncio.to_thread(_make_request, params) search_results = data.get("query", {}).get("search", []) @@ -49,11 +58,16 @@ async def _search(title: str, limit: int = 5, fallback: bool = False) -> str: for i, res in enumerate(search_results, 1): title_res = res.get("title") snippet = strip_html(res.get("snippet", "")) + # Brackets around title help the AI identify the exact string for subsequent calls lines.append(f"{i}. [{title_res}] - Snippet: {snippet}") return "\n".join(lines) async def _fetch_content(title: str, section_index: int) -> Optional[str]: + """ + Retrieves raw Wikitext for a specific section. + section_index=0 returns the lead section. + """ params = { "action": "query", "prop": "revisions", @@ -82,6 +96,9 @@ async def _fetch_content(title: str, section_index: int) -> Optional[str]: return revisions[0].get("*") async def _fetch_toc(title: str) -> Optional[str]: + """ + Retrieves the Table of Contents data and formats it hierarchically. + """ params = { "action": "parse", "page": title, @@ -111,6 +128,10 @@ async def _fetch_toc(title: str) -> Optional[str]: return "\n".join(lines) async def handle(args: Dict[str, Any]) -> Dict[str, Any]: + """ + Main handler for the browse_wikipedia tool. + Supports modes: summary, toc, section, and search. + """ title = args.get("title") if not title: raise ToolError("Missing required parameter: 'title'") @@ -122,6 +143,7 @@ async def handle(args: Dict[str, Any]) -> Dict[str, Any]: if mode == "search": result = await _search(title, search_limit, fallback=False) elif mode == "summary": + # Lead section + ToC is the default 'summary' to guide the AI's next steps content = await _fetch_content(title, 0) if content is None: result = await _search(title, search_limit, fallback=True)