From 916bf83529520dd015db1bb3b9ac7749096487a9 Mon Sep 17 00:00:00 2001 From: Srijito354 Date: Sat, 6 Dec 2025 16:13:32 +0530 Subject: [PATCH 1/3] Add PR Analyzer module with PR seeker, classifier, prioritizer --- toasty/pr_analyzer/.gitignore | 1 + toasty/pr_analyzer/PR_prioritizer.py | 46 ++++++++++++++++++++++++ toasty/pr_analyzer/PR_seeker.py | 38 ++++++++++++++++++++ toasty/pr_analyzer/README.md | 3 ++ toasty/pr_analyzer/__init__.py | 0 toasty/pr_analyzer/priority_generator.py | 40 +++++++++++++++++++++ toasty/pr_analyzer/testing_class.py | 16 +++++++++ 7 files changed, 144 insertions(+) create mode 100644 toasty/pr_analyzer/.gitignore create mode 100644 toasty/pr_analyzer/PR_prioritizer.py create mode 100644 toasty/pr_analyzer/PR_seeker.py create mode 100644 toasty/pr_analyzer/README.md create mode 100644 toasty/pr_analyzer/__init__.py create mode 100644 toasty/pr_analyzer/priority_generator.py create mode 100644 toasty/pr_analyzer/testing_class.py diff --git a/toasty/pr_analyzer/.gitignore b/toasty/pr_analyzer/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/toasty/pr_analyzer/.gitignore @@ -0,0 +1 @@ +.env diff --git a/toasty/pr_analyzer/PR_prioritizer.py b/toasty/pr_analyzer/PR_prioritizer.py new file mode 100644 index 0000000..4b6ff8a --- /dev/null +++ b/toasty/pr_analyzer/PR_prioritizer.py @@ -0,0 +1,46 @@ +import os +from github import Github +from sarvamai import SarvamAI +from PR_seeker import Seeker +from priority_generator import Generator + + +seeker = Seeker() +generator = Generator() +client = SarvamAI(api_subscription_key=os.getenv("SARVAM_API_KEY")) + +# Priority segregation. +high = ["Bug Fix", "Performance Improvement", "Security Fix"] +mid = ["Feature Addition", "Refactoring", "Testing"] +low = ["Documentation Update", "Others"] + +gh_link = input("Enter repo link: ").strip() +# Converting repo links to a 'owner/repo' format, without requiring the maintainer to format it themselves, thus reducing the cognitive load needed (to an extent). +new_gh_link = gh_link +if new_gh_link.startswith("https://github.com/"): + new_gh_link = new_gh_link.replace("https://github.com/", "") +''' +elif new_gh_link.startswith("http://github.com/"): + new_gh_link = new_gh_link.replace("http://github.com/", "") +''' +new_gh_link = new_gh_link.rstrip('/') + +if new_gh_link.endswith('.git'): + new_gh_link = new_gh_link[:-4] + +print(new_gh_link) + +response = '' +store_lst = seeker.forward(new_gh_link) +for i in range(len(store_lst)): + title = store_lst[i]['Title'] + body = store_lst[i]['Body'] + + response = generator.forward(title, body).strip() + + if response in high: + print(response, ": high") + elif response in mid: + print(response, ": medium") + elif response in low: + print(response, ": low") \ No newline at end of file diff --git a/toasty/pr_analyzer/PR_seeker.py b/toasty/pr_analyzer/PR_seeker.py new file mode 100644 index 0000000..e7ecb29 --- /dev/null +++ b/toasty/pr_analyzer/PR_seeker.py @@ -0,0 +1,38 @@ +from github import Github +import os + +class Seeker: + def __init__(self): + self.PERSONAL_TOKEN = os.getenv('PERSONAL_TOKEN') + self.store_dict = {} + self.store_list = [] + self.do_not_include = """ +--- + +💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).""" + + #self.f = open("Output.txt", "w") + def forward(self, repository:str): + g = Github(self.PERSONAL_TOKEN) + repo = g.get_repo(repository) + pulls = repo.get_pulls(state='all') + store_list = [] + for pr in pulls: + if pr != self.do_not_include: + store_dict = {} + store_dict['Title'] = pr.title + store_dict['Body'] = pr.body + store_list.append(store_dict) + #self.f.writelines(store_list) + return store_list + +''' +seeker_obj = Seeker() +lst_store = [] +lst_store = seeker_obj.forward("OWASP-BLT/Toasty") +#print("Title: ", lst_store[3]['Title'], "\n\n") +#print("Body: ", lst_store[3]['Body']) + +print(lst_store[3]['Title'], "\n\n") +print(lst_store[3]['Body']) +''' \ No newline at end of file diff --git a/toasty/pr_analyzer/README.md b/toasty/pr_analyzer/README.md new file mode 100644 index 0000000..b2ae72e --- /dev/null +++ b/toasty/pr_analyzer/README.md @@ -0,0 +1,3 @@ +# PR (Pull Request) analyzer. + +This module retrieves PRs from GitHub, classifies them using Sarvam-M API, and generates priority categories (High, Medium, and Low) for project managers. diff --git a/toasty/pr_analyzer/__init__.py b/toasty/pr_analyzer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/toasty/pr_analyzer/priority_generator.py b/toasty/pr_analyzer/priority_generator.py new file mode 100644 index 0000000..1969254 --- /dev/null +++ b/toasty/pr_analyzer/priority_generator.py @@ -0,0 +1,40 @@ +from sarvamai import SarvamAI +from PR_seeker import Seeker +#from dotenv import load_dotenv +import os + +#load_dotenv() +client = SarvamAI(api_subscription_key=os.getenv("SARVAM_API_KEY")) + +class Generator: + def __init__(self): + self.client = client + self.categories = ["Bug Fix", "Feature Addition", "Documentation Update", + "Performance Improvement", "Refactoring", "Testing", "Others"] + + def forward(self, pr_title: str, pr_body: str): + pr_content = f"Title: {pr_title}\nBody: {pr_body}" + + response = self.client.chat.completions( + messages=[ + {'role': 'system', 'content': f'You are a Pull Request (PR) analyzer. You classify them into the following categories: {", ".join(self.categories)}. Classify the PR into exactly ONE of these categories: {", ".join(self.categories)}. Output ONLY the category label, with no explanation or additional text.'}, + {"role": "user", "content": pr_content} + ], + temperature=0.5, + top_p=1, + max_tokens=1000, + ) + + return response.choices[0].message.content +''' +generator = Generator() +seeker = Seeker() +response = '' +store_lst = seeker.forward('OWASP-BLT/Toasty') +for i in range(len(store_lst)): + title = store_lst[i]['Title'] + body = store_lst[i]['Body'] + + response = generator.forward(title, body) + print(response) +''' \ No newline at end of file diff --git a/toasty/pr_analyzer/testing_class.py b/toasty/pr_analyzer/testing_class.py new file mode 100644 index 0000000..65e8acc --- /dev/null +++ b/toasty/pr_analyzer/testing_class.py @@ -0,0 +1,16 @@ +class Add: + def __init__(self, c): + self.c = c + def forward(self, a, b): + c = a+b + return c + +class test: + def __init__(self): + self.add = Add(0) + def forward(self, a, b): + c = self.add.forward(a, b) + return c + +t = test() +print(t.forward(10, 12)) \ No newline at end of file From 18e86d3c3f278d6c3644424a89ce7ddc72aa7212 Mon Sep 17 00:00:00 2001 From: Srijito354 Date: Sat, 6 Dec 2025 16:24:52 +0530 Subject: [PATCH 2/3] Remove commented out code --- toasty/pr_analyzer/PR_seeker.py | 13 +------------ toasty/pr_analyzer/priority_generator.py | 14 +------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/toasty/pr_analyzer/PR_seeker.py b/toasty/pr_analyzer/PR_seeker.py index e7ecb29..f4561c5 100644 --- a/toasty/pr_analyzer/PR_seeker.py +++ b/toasty/pr_analyzer/PR_seeker.py @@ -24,15 +24,4 @@ def forward(self, repository:str): store_dict['Body'] = pr.body store_list.append(store_dict) #self.f.writelines(store_list) - return store_list - -''' -seeker_obj = Seeker() -lst_store = [] -lst_store = seeker_obj.forward("OWASP-BLT/Toasty") -#print("Title: ", lst_store[3]['Title'], "\n\n") -#print("Body: ", lst_store[3]['Body']) - -print(lst_store[3]['Title'], "\n\n") -print(lst_store[3]['Body']) -''' \ No newline at end of file + return store_list \ No newline at end of file diff --git a/toasty/pr_analyzer/priority_generator.py b/toasty/pr_analyzer/priority_generator.py index 1969254..860a47b 100644 --- a/toasty/pr_analyzer/priority_generator.py +++ b/toasty/pr_analyzer/priority_generator.py @@ -25,16 +25,4 @@ def forward(self, pr_title: str, pr_body: str): max_tokens=1000, ) - return response.choices[0].message.content -''' -generator = Generator() -seeker = Seeker() -response = '' -store_lst = seeker.forward('OWASP-BLT/Toasty') -for i in range(len(store_lst)): - title = store_lst[i]['Title'] - body = store_lst[i]['Body'] - - response = generator.forward(title, body) - print(response) -''' \ No newline at end of file + return response.choices[0].message.content \ No newline at end of file From e5cf95608b55f58b985c1d8779b2bf01bd62a24e Mon Sep 17 00:00:00 2001 From: Srijito354 Date: Sat, 6 Dec 2025 16:40:08 +0530 Subject: [PATCH 3/3] Add requirements.txt for easier identification and installation of dependencies --- toasty/pr_analyzer/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 toasty/pr_analyzer/requirements.txt diff --git a/toasty/pr_analyzer/requirements.txt b/toasty/pr_analyzer/requirements.txt new file mode 100644 index 0000000..752b87c --- /dev/null +++ b/toasty/pr_analyzer/requirements.txt @@ -0,0 +1,2 @@ +github +sarvamai \ No newline at end of file