diff --git a/community/github-analyzer/app.py b/community/github-analyzer/app.py new file mode 100644 index 0000000..8e77054 --- /dev/null +++ b/community/github-analyzer/app.py @@ -0,0 +1,21 @@ +from flask import Flask, render_template, request, jsonify +from tuneai_integration import analyze_github_profile + +app = Flask(__name__) + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/chat', methods=['POST']) +def chat(): + user_input = request.json.get("message") + tuneAI_response = analyze_github_profile(user_input) + # tuneAI_response = "okay broooo" + # For simplicity, echoing user input (replace this with any processing logic you need) + bot_response = f"{tuneAI_response}" + return jsonify({"response": bot_response}) + +if __name__ == "__main__": + # app.run(debug=True) + app.run(port=7788) diff --git a/community/github-analyzer/demo.gif b/community/github-analyzer/demo.gif new file mode 100644 index 0000000..ac57211 Binary files /dev/null and b/community/github-analyzer/demo.gif differ diff --git a/community/github-analyzer/readme.md b/community/github-analyzer/readme.md new file mode 100644 index 0000000..4c2a01f --- /dev/null +++ b/community/github-analyzer/readme.md @@ -0,0 +1,47 @@ +# GitHubGPT 🤖 + +## Overview + +GitHubGPT is your github analyser tool that utilizes the power of the TuneAI API and analyze any GitHub profiles. It provides users with insights and information about specific GitHub users based on their username queries. The application combines a user-friendly interface with the capabilities of a conversational AI, making it easy to interact with GitHub data. + +## Questions to test with githubGPT + +- Should I hire `sayak9495` for python role? +- What is the most reviewed repo by `abhishekmishragithub`? +- Tell me top 3 language used by `palnabarun` + +## How It Works + +1. **User Input**: Users can enter a GitHub username or a query that includes the username. +2. **Processing**: The application extracts the username and sends a request to the TuneAI API for analysis. +3. **Response Handling**: The response is processed and displayed in a user-friendly format. +4. **Continuous Interaction**: Users can ask follow-up questions or provide new queries. + +## Demo + +![](https://raw.githubusercontent.com/Sayak9495/cookbook/refs/heads/main/community/github-analyzer/demo.gif) + +## Usage + +To run GitHubGPT locally using `pyenv`, follow these steps: + +1. **Clone the repository**: + ```bash + git clone https://github.com/sayak9495/cookbook.git + ``` +2. **Move to GithubGPT**: + ```bash + cd cookbook/community/github-analyzer + ``` +3. **Install Requirements.TXT**: + ```bash + python3 install -r requirements.txt + ``` +4. **Run**: + ```bash + python3 app.py + ``` +5. **Note**: + ```bash + Add os-env variables for the required key + ``` diff --git a/community/github-analyzer/requirements.txt b/community/github-analyzer/requirements.txt new file mode 100644 index 0000000..97b12ef --- /dev/null +++ b/community/github-analyzer/requirements.txt @@ -0,0 +1,122 @@ +alembic==1.13.2 +androguard==4.1.2 +-e git+https://github.com/mitmproxy/android-unpinner.git@7968f0b9cd9e93e84f38faba63b118b8b48aff72#egg=android_unpinner +apkInspector==1.3.1 +asn1crypto==1.5.1 +asttokens==2.4.1 +banal==1.0.6 +beautifulsoup4==4.12.3 +boto3==1.34.10 +botocore==1.34.10 +bs4==0.0.2 +certifi==2022.9.24 +charset-normalizer==2.1.1 +cli_helpers==2.3.1 +click==7.1.2 +colorama==0.4.6 +colour==0.1.5 +config==0.5.1 +configobj==5.0.8 +configparser==5.3.0 +contourpy==1.2.1 +cycler==0.12.1 +Cython==3.0.10 +dataset==1.6.2 +decorator==5.1.1 +delegator.py==0.1.1 +distlib==0.3.6 +dnspython==1.16.0 +executing==2.0.1 +filelock==3.8.0 +Flask==1.1.2 +Flask-CKEditor==0.4.4.1 +Flask-WTF==0.14.3 +fonttools==4.53.0 +frida==16.4.10 +frida-tools==12.5.0 +glcontext==2.5.0 +gunicorn==20.0.4 +idna==3.4 +ipython==8.25.0 +isosurfaces==0.1.2 +itsdangerous==1.1.0 +jedi==0.19.1 +Jinja2==2.11.3 +jmespath==1.0.1 +kiwisolver==1.4.5 +litecli==1.11.0 +loguru==0.7.2 +lxml==5.3.0 +Mako==1.3.5 +-e git+https://github.com/3b1b/manim.git@88c7e9d2c96be1ea729b089c06cabb1bd3b2c187#egg=manimgl +ManimPango==0.4.4 +mapbox-earcut==1.0.1 +markdown-it-py==3.0.0 +MarkupSafe==1.1.1 +matplotlib==3.9.0 +matplotlib-inline==0.1.7 +matplotlib-venn==0.11.10 +mdurl==0.1.2 +moderngl==5.10.0 +moderngl-window==2.4.6 +mpmath==1.3.0 +multipledispatch==1.0.0 +mutf8==1.0.6 +mysql-connector==2.2.9 +networkx==3.3 +numpy==1.26.4 +objection==1.11.0 +oscrypto==1.3.0 +packaging==24.0 +parso==0.8.4 +pbr==5.11.0 +pexpect==4.9.0 +pillow==10.3.0 +platformdirs==2.5.4 +prompt_toolkit==3.0.45 +ptyprocess==0.7.0 +pure-eval==0.2.2 +pydot==3.0.1 +pydub==0.25.1 +pygame==2.5.2 +pyglet==2.0.15 +Pygments==2.18.0 +pymongo==3.11.0 +pyobjc-core==10.3 +pyobjc-framework-Cocoa==10.3 +PyOpenGL==3.1.7 +pyparsing==3.1.2 +pyperclip==1.8.2 +pyrr==0.10.3 +python-dateutil==2.8.2 +PyYAML==6.0.1 +requests==2.28.1 +rich==13.7.1 +rich-click==1.8.3 +s3transfer==0.10.0 +scipy==1.13.1 +screeninfo==0.8.1 +semver==2.13.0 +six==1.16.0 +skia-pathops==0.8.0.post1 +soupsieve==2.5 +sql==2022.4.0 +SQLAlchemy==1.4.53 +sqlparse==0.5.1 +stack-data==0.6.3 +stevedore==4.1.1 +svgelements==1.9.6 +sympy==1.12.1 +tabulate==0.9.0 +tqdm==4.66.4 +traitlets==5.14.3 +typing_extensions==4.12.0 +urllib3==1.26.12 +validators==0.28.3 +venny4py==1.0.2 +virtualenv==20.16.7 +virtualenv-clone==0.5.7 +virtualenvwrapper==4.8.4 +wcwidth==0.2.13 +Werkzeug==1.0.1 +WTForms==2.3.1 diff --git a/community/github-analyzer/templates/index.html b/community/github-analyzer/templates/index.html new file mode 100644 index 0000000..e42aac3 --- /dev/null +++ b/community/github-analyzer/templates/index.html @@ -0,0 +1,179 @@ + + + + + + GithubGPT 🦾 + + + +
+
GithubGPT 🤖
+
+
+ + +
+ + + + + diff --git a/community/github-analyzer/tuneai_integration.py b/community/github-analyzer/tuneai_integration.py new file mode 100644 index 0000000..a6cda5d --- /dev/null +++ b/community/github-analyzer/tuneai_integration.py @@ -0,0 +1,181 @@ +import requests +import json +import os + +# Replace this with your actual GitHub API token +GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "") +TUNEAI_TOKEN = os.environ.get("TUNEAI_TOKEN", "") + +# Common headers for the API requests +headers = { + "Authorization": f"Bearer {GITHUB_TOKEN}", + "Accept": "application/vnd.github+json" +} + +# Function to fetch repositories for a GitHub user +def get_repositories(user): + url = f"https://api.github.com/users/{user}/repos" + response = requests.get(url, headers=headers) + if response.status_code == 200: + return response.json() + else: + raise Exception(f"Error fetching repositories for user {user}: {response.status_code}") + +# Function to get languages used in a repository +def get_repo_languages(user, repo_name): + url = f"https://api.github.com/repos/{user}/{repo_name}/languages" + response = requests.get(url, headers=headers) + if response.status_code == 200: + return response.json() # Returns a dictionary of languages with their corresponding LOC + else: + raise Exception(f"Error fetching languages for repository {repo_name}: {response.status_code}") + +session_user = "" +cache = {} +# Function to get dynamic GitHub data for the user +def get_github_data(user): + if user in cache: + print(f"Fetching data for {user} from cache...") + return cache[user] + + repos = get_repositories(user) + languagesLOC = {} + repositoryDetails = [] + + # Iterate through repositories to fetch relevant details + for repo in repos: + repo_name = repo['name'] + repo_languages = get_repo_languages(user, repo_name) + + # Aggregate languages and their LOC + for language, loc in repo_languages.items(): + loc_key = f"{language.lower()}LOC" + if loc_key in languagesLOC: + languagesLOC[loc_key] += loc + else: + languagesLOC[loc_key] = loc + + # Prepare repository details structure + repo_details = { + "name": repo_name, + "languages": list(repo_languages.keys()), + "stars": repo['stargazers_count'], + "forks": repo['forks_count'], + "description": repo.get('description', 'No description'), + "commits": repo.get('size', 0), # GitHub API doesn't provide commit count directly + "lastUpdate": repo['updated_at'][:10] # Extract date portion of timestamp + } + repositoryDetails.append(repo_details) + + # Calculate repository stats + repositoryStats = { + "numberOfRepos": len(repos), + "numberOfOpenSourceRepos": len([r for r in repos if not r['private']]), + "numberOfCommits": sum([r.get('size', 0) for r in repos]), # Approximation based on repo size + "numberOfReviews": 0 # This information is not available via API without digging deeper + } + + # Construct GitHub data in the required format + github_data = { + "username": user, + "languagesLOC": languagesLOC, + "repositoryStats": repositoryStats, + "repositoryDetails": repositoryDetails + } + + cache[user] = github_data + return github_data + + +# Function to analyze GitHub profile using TuneAI API +def analyze_github_profile(user_query): + global session_user + uname = extract_github_uname(user_query).strip() # Stripping whitespaces + print("***********", repr(uname)) # Checking for quotes in the output + # Remove enclosing quotes if present + if uname.startswith('"') and uname.endswith('"'): + uname = uname[1:-1].strip() + + print("User-Name=[", uname,"] Len=[", len(uname), "] SessionUser=[", session_user, "] Len=[",len(session_user),"]") + if (not uname and not session_user) or (len(uname)>2 and len(uname)<5): + return "github username not entered. Please provide the github username with whole query" + elif uname and not session_user: + session_user = uname + elif len(session_user) != 0 and len(uname) != 0 and uname != session_user: + # for switching ctx of user + session_user = uname + else: + uname = session_user + + print("User-Name=[", uname,"] Len=[", len(uname), "] SessionUser=[", session_user, "] Len=[",len(session_user),"]") + + github_data = get_github_data(uname) + # print(json.dumps(github_data, indent=4)) + # Sample prompt to be sent to TuneAI + prompt_content = f"You are an extremely experienced developer, a CTO who has given a task to access github-details about a user, being such a senior person in coding industry answer the query: '{user_query}'. Do not over-explain your answer, be brief, short and humane in your response. And always give the response in markdown format\n\n```json\n{json.dumps(github_data, indent=4)}\n```" + + # API request payload + payload = { + "temperature": 0.8, + "messages": [ + { + "role": "system", + "content": prompt_content + } + ], + "model": "sayak9495/githubGPT-pycon", + "stream": False, + "max_tokens": 1200 + } + + # API headers including Authorization token + headers = { + "Authorization": f"{TUNEAI_TOKEN}", # Replace with your actual API key + "Content-Type": "application/json" + } + + # Send the API request + response = requests.post('https://proxy.tune.app/chat/completions', headers=headers, json=payload) + + # Parse and return the response + if response.status_code == 200: + response_json = response.json() + # Extract the assistant's response + return response_json['choices'][0]['message']['content'].replace("*", "") + else: + return f"Error: Unable to get a valid response. Status code {response.status_code}" + + +def extract_github_uname(user_query): + prompt_content = f"extract plausible github username from this user-query '{user_query}'. Only return the github username, if not found then return empty string." + + # API request payload + payload = { + "temperature": 0.8, + "messages": [ + { + "role": "system", + "content": prompt_content + } + ], + "model": "openai/gpt-4o-mini", + "stream": False, + "max_tokens": 1200 + } + + # API headers including Authorization token + headers = { + "Authorization": "sk-tune-LOMAwgqNkU3irH7iCBccSfnrpNlosle862e", # Replace with your actual API key + "Content-Type": "application/json" + } + + # Send the API request + response = requests.post('https://proxy.tune.app/chat/completions', headers=headers, json=payload) + + # Parse and return the response + if response.status_code == 200: + response_json = response.json() + # Extract the assistant's response + return response_json['choices'][0]['message']['content'].replace("*", "") + else: + return f""