From 76b01788869222f2883ffc9d5b8f4a3f9c574522 Mon Sep 17 00:00:00 2001 From: projectmoon Date: Sat, 30 Nov 2024 21:25:59 +0100 Subject: [PATCH] Gemini: Better handling of redirect results. --- CHANGELOG.md | 4 +++ gemini.py | 80 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e68576..de730ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -214,6 +214,10 @@ # Gemini Tool +**0.1.1:** + - Do not correct URLs when following redirects. + - Improve result handling. + **0.1.0:** - Handle redirects. diff --git a/gemini.py b/gemini.py index 174ded8..747df21 100644 --- a/gemini.py +++ b/gemini.py @@ -2,7 +2,7 @@ title: Gemini Protocol Tool author: projectmoon author_url: https://git.agnos.is/projectmoon/open-webui-filters -version: 0.1.0 +version: 0.1.1 license: AGPL-3.0+ required_open_webui_version: 0.4.3 requirements: ignition-gemini @@ -13,21 +13,32 @@ from ignition import RedirectResponse, SuccessResponse from pydantic import BaseModel, Field from typing import Optional -def instructions() -> str: - return ("Render all Gemini links as Markdown links. Examples:\n\n" - " - [gemini://example.com](gemini://example.com)\n" - " - [a gemini capsule](gemini://example.com)\n" - " - [my personal capsule](gemini://example.com/personal)\n\n" - "A Gemini link starts with => on the line, and then the URL follows:\n\n" - " - `=> /page A Gemini Page`: A relative link to `/page` titled `A Gemini Page`\n" - " - `=> gemini://example.com/place` An absolute link with no URL title \n\n" - "When rendering relative links, always make them absolute links.\n" - "If the link has a title, render the link title verbatim:\n" - " - `=> gemini://example.com My Page` becomes `[My Page](gemini://example.com)`\n" - " - `=> gemini://example.com` becomes `[gemini://example.com](gemini://example.com)`.\n" - " - `=> gemini://example.com 🐂 My Page` becomes `[🐂 My Page](gemini://example.com)`\n\n" - "The Gemtext content is below in the code block." - ) +def result_instructions(url: str, redirect: bool=False) -> str: + content_instructions = ( + "Report the content to the user and answer their question." + ) + + return ("# Gemini Content Fetch Result\n" + f"Content was successfully fetched for the URL: {url}\n" + ) + content_instructions + "\n\n" + +def instructions(url: str, redirect: bool=False) -> str: + return result_instructions(url, redirect) + ( + "Here are the instructions you must follow. " + "Render all Gemini links as Markdown links. Examples:\n\n" + " - [gemini://example.com](gemini://example.com)\n" + " - [a gemini capsule](gemini://example.com)\n" + " - [my personal capsule](gemini://example.com/personal)\n\n" + "A Gemini link starts with => on the line, and then the URL follows:\n\n" + " - `=> /page A Gemini Page`: A relative link to `/page` titled `A Gemini Page`\n" + " - `=> gemini://example.com/place` An absolute link with no URL title \n\n" + "When rendering relative links, always make them absolute links.\n" + "If the link has a title, render the link title verbatim:\n" + " - `=> gemini://example.com My Page` becomes `[My Page](gemini://example.com)`\n" + " - `=> gemini://example.com` becomes `[gemini://example.com](gemini://example.com)`.\n" + " - `=> gemini://example.com 🐂 My Page` becomes `[🐂 My Page](gemini://example.com)`\n\n" + "The Gemtext content is below in the code block." + ) def correct_url(url: str) -> str: if url.startswith("gemini://http://"): @@ -60,9 +71,13 @@ def correct_url(url: str) -> str: return url -def fetch(gemini_url: str, correct_urls: bool=False, prev_url: Optional[str]=None, redirects: int=0) -> str: +def fetch(gemini_url: str, correct_urls: bool=False, prev_url: Optional[str]=None, redirects: int=0) -> dict: if redirects > 5: - return f"Too many redirects (ended at {gemini_url})" + return { + "success": False, + content: f"Too many redirects (ended at {gemini_url})", + "redirected": prev_url is not None + } if correct_urls and not prev_url: corrected_url = correct_url(gemini_url) @@ -76,22 +91,30 @@ def fetch(gemini_url: str, correct_urls: bool=False, prev_url: Optional[str]=Non print(f"[Gemini] Fetching: {gemini_url} (redirected from {prev_url})") try: - response = ignition.request(gemini_url, raise_errors=True, referer=prev_url) if isinstance(response, SuccessResponse): - content = response.data() - return f"{instructions()}\n\n ```\n{content.strip()}\n```" + return { + "success": True, + "content": response.data().strip(), + "redirected": prev_url is not None + } elif isinstance(response, RedirectResponse): redirect_url = response.data() return fetch(redirect_url, correct_urls, gemini_url, redirects + 1) else: print(f"[Gemini] Unhandled {response.status} code for '{gemini_url}'") - return (f"Tell the user there was a {response.status} status code. " - f"Support for handling {response.status} is not implemented yet.") + message = (f"Tell the user there was a {response.status} status code. " + f"Support for handling {response.status} is not implemented yet.") + return { "success": False, content: message, "redirected": prev_url is not None } except Exception as e: print(f"[Gemini] error: {e}") - return f"Tell the user there was an error fetching the page: {e}" + message = f"Tell the user there was an error fetching the page: {e}" + return { + "success": False, + "content": message, + "redirected": prev_url is not None + } class Tools: class Valves(BaseModel): @@ -111,4 +134,11 @@ class Tools: :param gemini_url: The URL to fetch. The URL MUST begin with gemini://. :return: The fetched data as Markdown. """ - return fetch(gemini_url, correct_urls=self.valves.attempt_url_correction) + resp = fetch(gemini_url, correct_urls=self.valves.attempt_url_correction) + if resp["success"] == True: + result_instructions = instructions(gemini_url, redirect=resp["redirected"]) + stuff = f"{result_instructions}\n\n```\n{resp['content']}\n```" + print(stuff) + return stuff + else: + return resp["content"]