diff --git a/GitAccess.py b/GitAccess.py index 0d256bc..9b21bd8 100644 --- a/GitAccess.py +++ b/GitAccess.py @@ -1,15 +1,15 @@ """ title: GitAccess -author: ErrorRExorY/CptExorY +author: ErrorRExorY/CptExorY, SeveighTech, Josetseph author_url: https://pascal-frerks.de git_url: https://github.com/WhyWaitServices/open-webui-gitaccess.git description: This Tool allows the LLM to connect to one GitHub Repo to fetch its contents to ask it about it and use it to have your model always have the current state of the project required_open_webui_version: 0.6.0 -version: 0.1.0 +version: 0.2.0 licence: MIT """ -from typing import Any, Optional, Callable, Awaitable +from typing import Any, Optional, Callable, Awaitable, List, Dict from pydantic import BaseModel, Field, ValidationError import os import requests @@ -77,9 +77,9 @@ class Valves(BaseModel): description="GitHub Personal Access Token (needs repo access)", json_schema_extra={"secret": True}, ) - repo_url: str = Field( - default=os.getenv("GITHUB_REPO_URL", ""), - description="Default GitHub repository to access (in the format 'username/repo')", + owner: str = Field( + default="", + description="GitHub owner to access", ) class UserValves(BaseModel): @@ -95,13 +95,20 @@ class UserValves(BaseModel): default=5000, description="Maximum character length for file contents when truncation is enabled", ) + max_items: int = Field( + default=5, + description="Maximum number of issues, pull requests, etc. to retrieve per state (open/closed).", + ) + max_comments: int = Field( + default=5, + description="Maximum number of comments to retrieve for issues and pull requests.", + ) def __init__(self): try: self.valves = self.Valves() except ValidationError as e: raise ValueError(f"Configuration error in Valves: {e}") - self.user_valves = self.UserValves() self.filter = Filter() self.pipe = RepositoryPipe() @@ -125,11 +132,9 @@ async def _fetch_directory_contents( }, } ) - response = requests.get(api_url, headers=headers) if response.status_code != 200: return f"Error fetching from {api_url}: {response.status_code} - {response.text}" - items = response.json() result = [] file_count = 0 @@ -201,7 +206,6 @@ async def _fetch_directory_contents( "detail": item, } ) - if __event_emitter__: await __event_emitter__( { @@ -213,50 +217,106 @@ async def _fetch_directory_contents( }, } ) - return result + async def _fetch_github_data( + self, + api_url: str, + headers: dict, + data_type: str, + max_items: int, + __event_emitter__: Optional[Callable[[Any], Awaitable[None]]] = None, + ) -> list: + """Fetches data from the GitHub API and returns a list of dictionaries.""" + try: + response = requests.get(api_url, headers=headers) + response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx) + data = response.json() + if not isinstance(data, list): + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"No {data_type} found", + "done": True, + "hidden": False, + }, + } + ) + return [] + # Limit the number of items + limited_data = data[:max_items] + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Found {len(limited_data)} {data_type}", + "done": True, + "hidden": False, + }, + } + ) + return limited_data + except requests.exceptions.RequestException as e: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Error fetching {data_type}: {e}", + "done": True, + "hidden": False, + }, + } + ) + return [] + async def fetch_repo_content( - self, __event_emitter__: Optional[Callable[[Any], Awaitable[None]]] = None + self, + repo_name: str, + __event_emitter__: Optional[Callable[[Any], Awaitable[None]]] = None, ): - if not self.valves.access_token or not self.valves.repo_url: - msg = "Access token or repo URL is not properly configured." + """Fetches the content of a specified repository within the configured owner. + :param repo_name: The name of the repository to fetch. + """ + owner = self.valves.owner + if not self.valves.access_token or not owner: + msg = "Access token or owner is not properly configured." if __event_emitter__: await __event_emitter__( {"type": "error", "data": {"description": msg, "done": True}} ) return msg - headers = { "Authorization": f"token {self.valves.access_token}", "Accept": "application/vnd.github.v3+json", } - - if "/" not in self.valves.repo_url or len(self.valves.repo_url.split("/")) != 2: - msg = "The repo_url is not in the expected 'username/repo' format." + repo_url = f"{owner}/{repo_name}" + repo_api_url = f"https://api.github.com/repos/{repo_url}/contents" + try: + requests.get(repo_api_url, headers=headers).raise_for_status() + except requests.exceptions.RequestException as e: + msg = f"Error accessing repository {repo_url}: {e}" if __event_emitter__: await __event_emitter__( {"type": "error", "data": {"description": msg, "done": True}} ) return msg - - repo_api_url = f"https://api.github.com/repos/{self.valves.repo_url}/contents" - if __event_emitter__: await __event_emitter__( { "type": "status", "data": { - "description": "Fetching repository contents...", + "description": f"Fetching repository contents from {repo_name}...", "done": False, }, } ) - contents = await self._fetch_directory_contents( repo_api_url, headers, __event_emitter__ ) - if __event_emitter__: await __event_emitter__( { @@ -268,12 +328,9 @@ async def fetch_repo_content( }, } ) - messages_wrapper = {"messages": contents} self.filter.outlet(messages_wrapper) - if contents: - repo_name = self.valves.repo_url.split("/")[1] for item in contents: if item.get("type") == "file": file_name = item.get("name", "Unknown") @@ -284,28 +341,385 @@ async def fetch_repo_content( f"Repo: {repo_name}, File: {file_name}", file_url, ) - return messages_wrapper.get("messages") + async def _find_repositories( + self, partial_name: str, __event_emitter__=None + ) -> List[str]: + """ + Finds repositories in the owner that match the partial name. + """ + owner = self.valves.owner + access_token = self.valves.access_token + if not owner or not access_token: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Missing owner or access token", + "done": True, + "hidden": False, + }, + } + ) + return [] + headers = { + "Authorization": f"token {access_token}", + "Accept": "application/vnd.github.v3+json", + } + + # Determine the API URL based on whether it's a user or org + try: + # Try to get org info - if it fails, assume it's a user + user_api_url = f"https://api.github.com/orgs/{owner}" + response = requests.get(user_api_url, headers=headers) + response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx) + api_url = f"https://api.github.com/orgs/{owner}/repos" # It's an org + except requests.exceptions.RequestException: + # If the user API call fails, assume it's an organization + api_url = f"https://api.github.com/users/{owner}/repos" # It's a user + + try: + response = requests.get(api_url, headers=headers) + response.raise_for_status() + repos = response.json() + matching_repos = [ + repo["name"] + for repo in repos + if partial_name.lower() in repo["name"].lower() + ] + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Found {len(matching_repos)} repos matching '{partial_name}'", + "done": True, + "hidden": False, + }, + } + ) + return matching_repos + except requests.exceptions.RequestException as e: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Error fetching repos: {e}", + "done": True, + "hidden": False, + }, + } + ) + return [] + + async def _fetch_issues_and_pulls( + self, repo_name: str, state: str, __event_emitter__=None + ) -> List[Dict[str, Any]]: + """Fetches issues and pull requests from a repository.""" + owner = self.valves.owner + access_token = self.valves.access_token + max_items = ( + self.user_valves.max_items + ) # max_items is per state (open and closed) + if not owner or not access_token: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Missing owner or access token", + "done": True, + "hidden": False, + }, + } + ) + return [] + headers = { + "Authorization": f"token {access_token}", + "Accept": "application/vnd.github.v3+json", + } + repo_url = f"{owner}/{repo_name}" + issues_api_url = f"https://api.github.com/repos/{repo_url}/issues?state={state}" + pulls_api_url = f"https://api.github.com/repos/{repo_url}/pulls?state={state}" + all_items = [] + try: + # Fetch issues + issues = await self._fetch_github_data( + issues_api_url, + headers, + f"issues (state: {state})", + max_items, + __event_emitter__, + ) + for issue in issues: + issue_number = issue.get("number") + if issue_number: + issue_comments = await self._fetch_issue_comments( + repo_name, issue_number, headers, __event_emitter__ + ) + issue["comments_content"] = issue_comments + issue["type"] = "issue" # Add a type identifier + all_items.append(issue) + # Fetch pull requests + pulls = await self._fetch_github_data( + pulls_api_url, + headers, + f"pull requests (state: {state})", + max_items, + __event_emitter__, + ) + for pull in pulls: + pull_number = pull.get("number") + if pull_number: + pull_comments = await self._fetch_pull_request_comments( + repo_name, pull_number, headers, __event_emitter__ + ) + pull["comments_content"] = pull_comments + pull["type"] = "pull" # Add a type identifier + all_items.append(pull) + except requests.exceptions.RequestException as e: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Error fetching issues/pulls: {e}", + "done": True, + "hidden": False, + }, + } + ) + return [] + return all_items + + async def _fetch_issue_comments( + self, + repo_name: str, + issue_number: int, + headers: dict, + __event_emitter__=None, + ) -> List[Dict[str, Any]]: + """Fetches comments for a specific issue.""" + owner = self.valves.owner + max_comments = self.user_valves.max_comments + if not owner or not self.valves.access_token: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": "Missing owner or access token", + "done": True, + "hidden": False, + }, + } + ) + return [] + comments_api_url = f"https://api.github.com/repos/{owner}/{repo_name}/issues/{issue_number}/comments" + try: + response = requests.get(comments_api_url, headers=headers) + response.raise_for_status() + comments = response.json() + limited_comments = comments[:max_comments] + # Debug: Print the fetched comments + print(f"Fetched issue comments for issue #{issue_number}: {comments}") + return limited_comments + except Exception as e: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Error fetching issue comments: {e}", + "done": True, + "hidden": False, + }, + } + ) + return [] + + async def _fetch_pull_request_comments( + self, + repo_name: str, + pull_number: int, + headers: dict, + __event_emitter__=None, + ) -> List[Dict[str, Any]]: + """Fetches comments for a specific pull request.""" + owner = self.valves.owner + max_comments = self.user_valves.max_comments + if not owner or not self.valves.access_token: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": "Missing owner or access token", + "done": True, + "hidden": False, + }, + } + ) + return [] + comments_api_url = f"https://api.github.com/repos/{owner}/{repo_name}/pulls/{pull_number}/comments" + try: + response = requests.get(comments_api_url, headers=headers) + response.raise_for_status() + comments = response.json() + limited_comments = comments[:max_comments] + # Debug: Print the fetched comments + print(f"Fetched pull request comments for PR #{pull_number}: {comments}") + return limited_comments + except Exception as e: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Error fetching pull request comments: {e}", + "done": True, + "hidden": False, + }, + } + ) + return [] + + async def _fetch_pull_request_file_changes( + self, repo_name: str, pull_number: int, __event_emitter__=None + ) -> List[Dict[str, Any]]: + """Fetches file changes for a specific pull request.""" + owner = self.valves.owner + access_token = self.valves.access_token + if not owner or not access_token: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": "Missing owner or access token", + "done": True, + "hidden": False, + }, + } + ) + return [] + headers = { + "Authorization": f"token {access_token}", + "Accept": "application/vnd.github.v3+json", + } + files_api_url = f"https://api.github.com/repos/{owner}/{repo_name}/pulls/{pull_number}/files" + try: + files = await self._fetch_github_data( + files_api_url, + headers, + "pull request file changes", + self.user_valves.max_items, + __event_emitter__, + ) + return files + except Exception as e: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Error fetching pull request file changes: {e}", + "done": True, + "hidden": False, + }, + } + ) + return [] + async def analyze_repository( self, + repo_name: str, + include_files: bool = True, + include_commits: bool = False, # disabled as default because of rate limits and time user: dict = {}, __event_emitter__: Optional[Callable[[Any], Awaitable[None]]] = None, ): + """Analyzes the content of a specified repository. It fetches all relevant data and lets the LLM handle specific queries. + :param repo_name: The name of the repository to analyze OR a partial name to search for. + :param include_files: Whether to include file contents in the analysis. + :param include_commits: Whether to include recent commits in the analysis. + """ try: + owner = self.valves.owner + if not owner: + return "owner not configured." + headers = { + "Authorization": f"token {self.valves.access_token}", + "Accept": "application/vnd.github.v3+json", + } + max_items = self.user_valves.max_items + # First, check if the repo_name is a partial name + matching_repos = await self._find_repositories(repo_name, __event_emitter__) + if not matching_repos: + return ( + f"No repositories found matching '{repo_name}' in owner '{owner}'." + ) + elif len(matching_repos) > 1: + output = f"Multiple repositories found matching '{repo_name}':\n" + for r in matching_repos: + output += f"- {r}\n" + output += "Please specify the exact repository name to analyze." + return output # <---- Just return the list + else: + repo_name = matching_repos[ + 0 + ] # Use the full name of the matched repository + repo_url = f"{owner}/{repo_name}" + output = f"Analysis of {repo_url}:\n" if __event_emitter__: await __event_emitter__( { "type": "status", "data": { - "description": "Starting repository analysis...", + "description": f"Starting repository analysis for {repo_name}...", "done": False, }, } ) - - content = await self.fetch_repo_content(__event_emitter__) - + # Fetch repository files + repository_data = {"files": [], "issues": [], "pulls": [], "commits": []} + if include_files: + if __event_emitter__: + await __event_emitter__( + { + "type": "status", + "data": { + "description": f"Fetching repository files...", + "done": False, + }, + } + ) + file_contents = await self.fetch_repo_content( + repo_name, __event_emitter__ + ) + if isinstance(file_contents, str) and file_contents.startswith("Error"): + return file_contents # Propagate the error message + repository_data["files"] = file_contents + # Fetch issues and pull requests (all states) + for state in ["open", "closed"]: + items = await self._fetch_issues_and_pulls( + repo_name, state, __event_emitter__ + ) + for item in items: + if item.get("type") == "issue": + repository_data["issues"].append(item) + elif item.get("type") == "pull": + repository_data["pulls"].append(item) + # Fetch commits + if include_commits: + commits_api_url = f"https://api.github.com/repos/{repo_url}/commits" + commits = await self._fetch_github_data( + commits_api_url, headers, "commits", max_items, __event_emitter__ + ) + repository_data["commits"] = commits if __event_emitter__: await __event_emitter__( { @@ -317,8 +731,7 @@ async def analyze_repository( }, } ) - - return f"Repository contents:\n{content}" + return repository_data except Exception as e: error_msg = f"An error occurred: {e}" if __event_emitter__: diff --git a/README.de.md b/README.de.md index 9f9616b..a11f6e3 100644 --- a/README.de.md +++ b/README.de.md @@ -1,76 +1,98 @@ -# GitAccess +**# GitAccess** ![GitAccess Logo](https://i.imgur.com/1PxbyHA.png) -**GitAccess** ist ein Tool, das es ermöglicht, LLM-Modelle mit einem GitHub-Repository zu verbinden, um dessen Inhalte abzurufen. So kannst du das Modell über den aktuellen Stand des Projekts befragen und stets auf dem neuesten Stand bleiben. +**GitAccess** ist ein Tool, das es LLM-Modellen ermöglicht, sich mit GitHub-Repositories innerhalb eines bestimmten Accounts oder einer Organisation zu verbinden, um deren Inhalte, Issues, Pull Requests und mehr abzurufen. So kannst du das Modell über den aktuellen Stand eines Projekts befragen und stets auf dem neuesten Stand bleiben. -## 📦 Beschreibung +**## 📦 Beschreibung** -- **Autor**: ErrorRExorY/CptExorY -- **Website**: [pascal-frerks.de](https://pascal-frerks.de) -- **GitHub Repo**: [GitAccess auf GitHub](https://github.com/WhyWaitServices/open-webui-gitaccess.git) -- **Erforderliche OpenWebUI-Version**: 0.6.0 -- **Version**: 0.1.0 -- **Lizenz**: MIT +* **Autoren:** ErrorRExorY/CptExorY, [SeveighTech](https://seveightech.com)), [Josetseph](https://github.com/josetseph)) +* **Autoren Website:** [pascal-frerks.de](https://pascal-frerks.de) +* **GitHub Repository:** [GitAccess auf GitHub](https://github.com/WhyWaitServices/open-webui-gitaccess.git) +* **Erforderliche OpenWebUI-Version:** 0.6.0 +* **Version:** 0.2.0 (Aktualisiert von SeveighTech) +* **Lizenz:** MIT -## 🚀 Installation +**Wichtige Aktualisierungen von SeveighTech (Version 0.2.0):** + +* Unterstützung für das Abrufen von Issues, Pull Requests, Kommentaren und Dateiänderungen in Pull Requests hinzugefügt. +* Repository-Suche nach Teilnamen implementiert. +* Konfigurierbare Limits für die Anzahl der abgerufenen Elemente und Kommentare eingeführt. +* Verbesserte Fehlerbehandlung und Statusaktualisierungen. + +**## 🚀 Installation** Um GitAccess in deiner selbst gehosteten OpenWebUI-Instanz zu installieren, kannst du den folgenden Schritten folgen: -### Über den Marktplatz -1. Öffne deine OpenWebUI Instanz. -2. Gehe zum [Marktplatz](https://openwebui.com/t/cptexory/gitaccess "Marktplatz"). -3. Füge den Link zu GitAccess hinzu: (https://github.com/WhyWaitServices/open-webui-gitaccess.git). +**### Über den Marktplatz** + +1. Öffne deine OpenWebUI Instanz. +2. Gehe zum [Marktplatz](https://openwebui.com/t/cptexory/gitaccess "Marktplatz"). +3. Füge den Link zu GitAccess hinzu: `https://github.com/WhyWaitServices/open-webui-gitaccess.git`. + +**### Manuelle Installation** -### Manuelle Installation -1. Kopiere den Code aus der `GitCccess.py` Datei heraus. -2. Füge den kopierten Code zu deiner OpenWebUI-Instanz hinzu, indem du unter Arbeitsbereich>Werkzeuge ein neues Tool erstellst. -3. Füge den kopierten Code aus der `GitAccess.py` Datei im großen Eingabefeld ein und veregib einen Namen und eine Beschreibung. -4. Speichere das Tool. +1. Kopiere den Code aus der `GitAccess.py` Datei. +2. Füge den kopierten Code zu deiner OpenWebUI-Instanz hinzu, indem du unter Arbeitsbereich > Werkzeuge ein neues Tool erstellst. +3. Füge den kopierten Code aus der `GitAccess.py` Datei im großen Eingabefeld ein und vergib einen Namen und eine Beschreibung. +4. Speichere das Tool. -## ⚙️ Konfiguration +**## ⚙️ Konfiguration** -### Environment Variables (Valves) +**### Umgebungsvariablen (Valves)** -- **Zugang zu den Valves**: Die Umgebungsvariablen für das Tool werden in der OpenWebUI gesetzt. Klicke auf den Zahnrad-Button, wenn du das Tool öffnest, um die Valves zu konfigurieren. - - **GITHUB_ACCESS_TOKEN**: Ein persönlicher Zugriffstoken von GitHub, das die erforderlichen Zugriffsrechte auf das Repository hat. - - **GITHUB_REPO_URL**: Die URL des GitHub-Repositories, das im Format `username/repo` angegeben werden muss. +* **Zugang zu den Valves:** Die Umgebungsvariablen für das Tool werden in der OpenWebUI gesetzt. Klicke auf den Zahnrad-Button, wenn du das Tool öffnest, um die Valves zu konfigurieren. -### UserValves +* **access_token:** Ein persönlicher Zugriffstoken von GitHub, das die erforderlichen Zugriffsrechte auf das Repository hat. +* **owner:** Der Name des GitHub-Accounts/der Organisation (z.B. `SeveighTech`). -- **Setzen der UserValves**: Wenn du das Tool in einem Chat oder Modell aktiviert hast, kannst du die UserValves über den „Controls“-Button (oben rechts, direkt links neben dem Profilbild) setzen. Ein Sheet wird geöffnet, wo du die UserValves des Tools konfigurieren kannst. +**### UserValves** -## 🛠️ Nutzung +* **Setzen der UserValves:** Wenn du das Tool in einem Chat oder Modell aktiviert hast, kannst du die UserValves über den „Controls“-Button (oben rechts, direkt links neben dem Profilbild) setzen. Ein Sheet wird geöffnet, wo du die UserValves des Tools konfigurieren kannst. + +* **max_files:** Maximale Anzahl von Dateien pro Verzeichnis, die abgerufen werden sollen. +* **truncate_content:** Ob große Dateien zur besseren Lesbarkeit gekürzt werden sollen. +* **max_content_length:** Maximale Zeichenlänge für Dateiinhalte, wenn die Kürzung aktiviert ist. +* **max_items:** Maximale Anzahl von Issues, Pull Requests usw., die pro Status (offen/geschlossen) abgerufen werden sollen. +* **max_comments:** Maximale Anzahl von Kommentaren, die für Issues und Pull Requests abgerufen werden sollen. + +**## 🛠️ Nutzung** Nach der Installation kannst du GitAccess wie folgt nutzen: -1. Stelle sicher, dass du richtig konfiguriert bist (Zugangstoken und Repo-URL). -2. Starte das Tool in deiner OpenWebUI-Instanz. -3. Verwende einfache Prompts wie: - - „Was ist der Inhalt meines GitHub-Repos?“ - - „Gib mir den Inhalt zweier Dateien in Codeblöcken aus.“ +1. Stelle sicher, dass du richtig konfiguriert bist (Zugriffstoken und Owner). +2. Starte das Tool in deiner OpenWebUI-Instanz. +3. Verwende einfache Prompts wie: + +* "Was sind die Pull Requests, Pull Request Kommentare und die Pull Request Dateiänderungen im `{repository_name}` Repository?" +* "Erzähl mir mehr über das `{repository_name}` Repository." +* "Gib mir alle Kommentare zu jedem Issue im `{repository_name}` Repository." +* "Gibt es irgendwelche Issues oder Pull Requests im Repository: `{repository_name}`" +* "Kannst du mir mehr Details über PR #{PR_number}: "{PR_title}" Pull Request im `{repository_name}` Repository geben?" Die Antwort könnte wie folgt aussehen: -![Example Screenshot](https://i.imgur.com/tPMQwyf.png) +![Example Screenshot](https://i.imgur.com/1PxbyHA.png) Der Status der Aktionen wird in der Benutzeroberfläche durch Statusmeldungen angezeigt. -## 🤖 Funktionen +**## 🤖 Funktionen** -- **Repository Inhalten abrufen**: Lese die Struktur und die Dateien eines angegebenen GitHub-Repositories. -- **Dynamische Filter**: Unterscheidung zwischen Verzeichnissen und Dateien, um die gewünschten Daten effizient abzurufen. -- **Ereignis-Emitter**: Echtzeit-Feedback über die Progression der Abfragen und andere Aktionen. +* **Repository Inhalte abrufen:** Lese die Struktur und die Dateien eines angegebenen GitHub-Repositories. +* **Dynamische Filter:** Unterscheidung zwischen Verzeichnissen und Dateien, um die gewünschten Daten effizient abzurufen. +* **Ereignis-Emitter:** Echtzeit-Feedback über die Progression der Abfragen und andere Aktionen. +* **Issue- und Pull Request-Analyse:** Abrufen und Analysieren von Issues, Pull Requests und zugehörigen Kommentaren. +* **Repository-Suche:** Finden von Repositories anhand von Teilnamen innerhalb des konfigurierten Owners. -## 📋 Lizenz +**## 📋 Lizenz** Dieses Projekt steht unter der MIT Lizenz. Weitere Informationen findest du in der [LICENSE](LICENSE) Datei. -## 🤝 Mitwirken +**## 🤝 Mitwirken** Beiträge sind willkommen! Bitte öffne ein Issue oder eine Pull-Request, um Anregungen zu teilen oder Verbesserungen vorzuschlagen. -## 📞 Kontakt +**## 📞 Kontakt** -Bei Fragen oder Feedback kannst du mich unter [contact@example.com](mailto:contact@example.com) kontaktieren. +Bei Fragen oder Feedback kannst du ein Issue eröffnen. Vielen Dank, dass du GitAccess nutzt! \ No newline at end of file diff --git a/README.md b/README.md index f09c06a..3345baa 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,74 @@ # GitAccess + ![GitAccess Logo](https://i.imgur.com/1PxbyHA.png) -**GitAccess** is a tool that enables LLM models to connect to a GitHub repository to fetch its contents. This way, you can query the model about the current state of the project and always stay up to date. +**GitAccess** is a tool that enables LLM models to connect to GitHub repositories within a specified account or organization to fetch their contents, issues, pull requests, and more. This allows you to query the model about the current state of a project and stay up-to-date. ## 📦 Description -- **Author**: ErrorRExorY/CptExorY -- **Website**: [pascal-frerks.de](https://pascal-frerks.de) -- **GitHub Repo**: [GitAccess on GitHub](https://github.com/WhyWaitServices/open-webui-gitaccess.git) -- **Required OpenWebUI Version**: 0.6.0 -- **Version**: 0.1.0 -- **License**: MIT + +* **Authors:** ErrorRExorY/CptExorY, [SeveighTech](https://seveightech.com)), [Josetseph](https://github.com/josetseph)) +* **Author Website:** [pascal-frerks.de](https://pascal-frerks.de) +* **GitHub Repository:** [GitAccess on GitHub](https://github.com/WhyWaitServices/open-webui-gitaccess.git) +* **Required OpenWebUI Version:** 0.6.0 +* **Version:** 0.2.0 (Updated by SeveighTech) +* **License:** MIT + +**Key Updates by SeveighTech (Version 0.2.0):** + +* Added support for fetching issues, pull requests, comments, and file changes in pull requests. +* Implemented repository search by partial name. +* Introduced configurable limits for the number of items and comments fetched. +* Improved error handling and status updates. ## 🚀 Installation + To install GitAccess in your self-hosted OpenWebUI instance, you can follow these steps: ### Via the Marketplace -1. Open your OpenWebUI instance. -2. Go to the [Marketplace](https://openwebui.com/t/cptexory/gitaccess "Marketplace"). -3. Add the link to GitAccess: `https://github.com/WhyWaitServices/open-webui-gitaccess.git`. + +1. Open your OpenWebUI instance. +2. Go to the [Marketplace](https://openwebui.com/t/cptexory/gitaccess "Marketplace"). +3. Add the link to GitAccess: `https://github.com/WhyWaitServices/open-webui-gitaccess.git`. ### Manual Installation -1. Copy the code from the `GitAccess.py` file. -2. Add the copied code to your OpenWebUI instance by creating a new tool under Workspace > Tools. -3. Paste the copied code from the `GitAccess.py` file into the large input field and assign a name and a description. -4. Save the tool. -## ⚙️ Configuration +1. Copy the code from the `GitAccess.py` file. +2. Add the copied code to your OpenWebUI instance by creating a new tool under Workspace > Tools. +3. Paste the copied code from the `GitAccess.py` file into the large input field and assign a name and a description. +4. Save the tool. + +## ⚙️ Configuration + ### Environment Variables (Valves) -- **Accessing the Valves**: The environment variables for the tool are set within OpenWebUI. Click the gear button when you open the tool to configure the valves. - - **GITHUB_ACCESS_TOKEN**: A personal access token from GitHub that has the necessary permissions to access the repository. - - **GITHUB_REPO_URL**: The URL of the GitHub repository, which should be specified in the format `username/repo`. + +* **Accessing the Valves:** The environment variables for the tool are set within OpenWebUI. Click the gear button when you open the tool to configure the valves. + + * **access_token:** A personal access token from GitHub that has the necessary permissions to access the repository. + * **owner:** The name of the GitHub account/organization (e.g., `SeveighTech`). ### UserValves -- **Setting UserValves**: If you have activated the tool in a chat or model, you can set the UserValves using the "Controls" button (located at the top right, directly left of the profile picture). A sheet will open where you can configure the UserValves of the tool. + +* **Setting UserValves:** If you have activated the tool in a chat or model, you can set the UserValves using the "Controls" button (located at the top right, directly left of the profile picture). A sheet will open where you can configure the UserValves of the tool. + + * **max_files:** Maximum number of files per directory to fetch. + * **truncate_content:** Whether to truncate large files for better readability. + * **max_content_length:** Maximum character length for file contents when truncation is enabled. + * **max_items:** Maximum number of issues, pull requests, etc., to retrieve per state (open/closed). + * **max_comments:** Maximum number of comments to retrieve for issues and pull requests. ## 🛠️ Usage + After installation, you can use GitAccess as follows: -1. Ensure that you are correctly configured (access token and repo URL). -2. Launch the tool in your OpenWebUI instance. -3. Use simple prompts like: - - "What is the content of my GitHub repo?" - - "Show me the content of two files in code blocks." +1. Ensure that you are correctly configured (access token and owner). +2. Launch the tool in your OpenWebUI instance. +3. Use simple prompts like: + + * "What are the pull requests, pull request comments, and the pull request file changes on the `{repository_name}` repository?" + * "Tell me more about the `{repository_name}` repository." + * "Give me all the comments on each issue on the `{repository_name}` repository." + * "Are there any issues or pull requests in the repository: `{repository_name}`" + * "Get all the information about all the pull requests on the `{repository_name}` repository. Using *only* that information, tell me which comments are on pull request number `{PR_number}`. Do *not* use the tool again." The response might look like this: ![Example Screenshot](https://i.imgur.com/tPMQwyf.png) @@ -49,17 +76,23 @@ The response might look like this: The status of actions will be displayed in the user interface through status messages. ## 🤖 Features -- **Fetching Repository Contents**: Read the structure and files of a specified GitHub repository. -- **Dynamic Filters**: Distinguish between directories and files to efficiently retrieve the desired data. -- **Event Emitter**: Real-time feedback on the progression of queries and other actions. + +* **Fetching Repository Contents:** Read the structure and files of a specified GitHub repository. +* **Dynamic Filters:** Distinguish between directories and files to efficiently retrieve the desired data. +* **Event Emitter:** Real-time feedback on the progression of queries and other actions. +* **Issue and Pull Request Analysis:** Fetch and analyze issues, pull requests, and associated comments. +* **Repository Search:** Find repositories by partial name within the configured owner. ## 📋 License + This project is licensed under the MIT License. For more information, please refer to the [LICENSE](LICENSE) file. ## 🤝 Contributing + Contributions are welcome! Please open an issue or a pull request to share suggestions or propose improvements. ## 📞 Contact -For questions or feedback, you can contact me at [contact@example.com](mailto:contact@example.com). + +For questions or feedback, feel free to leave an issue. Thank you for using GitAccess! \ No newline at end of file