Skip to content

Commit

Permalink
Refactor command handling and subscription logic, export commits in d…
Browse files Browse the repository at this point in the history
…aily progress, and enhance report generation with GPT-3.5
  • Loading branch information
DjangoPeng committed Jul 30, 2024
1 parent 8da7236 commit ba06231
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 104 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,7 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# User-defined
daily_progress/*

1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
requests
openai
74 changes: 74 additions & 0 deletions src/command_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# src/command_handler.py

import argparse

class CommandHandler:
def __init__(self, github_client, subscription_manager, report_generator):
self.github_client = github_client
self.subscription_manager = subscription_manager
self.report_generator = report_generator
self.parser = self.create_parser()

def create_parser(self):
parser = argparse.ArgumentParser(
description='GitHub Sentinel Command Line Interface',
formatter_class=argparse.RawTextHelpFormatter
)
subparsers = parser.add_subparsers(title='Commands', dest='command')

parser_add = subparsers.add_parser('add', help='Add a subscription')
parser_add.add_argument('repo', type=str, help='The repository to subscribe to (e.g., owner/repo)')
parser_add.set_defaults(func=self.add_subscription)

parser_remove = subparsers.add_parser('remove', help='Remove a subscription')
parser_remove.add_argument('repo', type=str, help='The repository to unsubscribe from (e.g., owner/repo)')
parser_remove.set_defaults(func=self.remove_subscription)

parser_list = subparsers.add_parser('list', help='List all subscriptions')
parser_list.set_defaults(func=self.list_subscriptions)

parser_fetch = subparsers.add_parser('fetch', help='Fetch updates immediately')
parser_fetch.set_defaults(func=self.fetch_updates)

parser_export = subparsers.add_parser('export', help='Export daily progress')
parser_export.add_argument('repo', type=str, help='The repository to export progress from (e.g., owner/repo)')
parser_export.set_defaults(func=self.export_daily_progress)

parser_generate = subparsers.add_parser('generate', help='Generate daily report from markdown file')
parser_generate.add_argument('file', type=str, help='The markdown file to generate report from')
parser_generate.set_defaults(func=self.generate_daily_report)

parser_help = subparsers.add_parser('help', help='Show help message')
parser_help.set_defaults(func=self.print_help)

return parser

def add_subscription(self, args):
self.subscription_manager.add_subscription(args.repo)
print(f"Added subscription for repository: {args.repo}")

def remove_subscription(self, args):
self.subscription_manager.remove_subscription(args.repo)
print(f"Removed subscription for repository: {args.repo}")

def list_subscriptions(self, args):
subscriptions = self.subscription_manager.list_subscriptions()
print("Current subscriptions:")
for sub in subscriptions:
print(f" - {sub}")

def fetch_updates(self, args):
updates = self.github_client.fetch_updates()
for update in updates:
print(update)

def export_daily_progress(self, args):
self.github_client.export_daily_progress(args.repo)
print(f"Exported daily progress for repository: {args.repo}")

def generate_daily_report(self, args):
self.report_generator.generate_daily_report(args.file)
print(f"Generated daily report from file: {args.file}")

def print_help(self, args=None):
self.parser.print_help()
2 changes: 1 addition & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ def load_config(self):
self.github_token = config.get('github_token')
self.notification_settings = config.get('notification_settings')
self.subscriptions_file = config.get('subscriptions_file')
self.update_interval = config.get('update_interval', 24 * 60 * 60) # Default to 24 hours
self.update_interval = config.get('update_interval', 24 * 60 * 60) # Default to 24 hours
57 changes: 48 additions & 9 deletions src/github_client.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,55 @@
# src/github_client.py

import requests
import datetime

class GitHubClient:
def __init__(self, token):
self.token = token

def fetch_updates(self, subscriptions):
headers = {
'Authorization': f'token {self.token}'
self.headers = {'Authorization': f'token {self.token}'}

def fetch_updates(self, repo):
# 获取特定 repo 的更新(commits, issues, pull requests)
updates = {
'commits': self.fetch_commits(repo),
'issues': self.fetch_issues(repo),
'pull_requests': self.fetch_pull_requests(repo)
}
updates = {}
for repo in subscriptions:
response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest', headers=headers)
if response.status_code == 200:
updates[repo] = response.json()
return updates

def fetch_commits(self, repo):
url = f'https://api.github.com/repos/{repo}/commits'
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()

def fetch_issues(self, repo):
url = f'https://api.github.com/repos/{repo}/issues'
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()

def fetch_pull_requests(self, repo):
url = f'https://api.github.com/repos/{repo}/pulls'
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()


def export_daily_progress(self, repo):
date_str = datetime.datetime.now().strftime('%Y-%m-%d')
issues = self.fetch_issues(repo)
pull_requests = self.fetch_pull_requests(repo)
filename = f'daily_progress/{repo.replace("/", "_")}_{date_str}.md'
with open(filename, 'w') as f:
f.write(f"# {repo} Daily Progress - {date_str}\n\n")
f.write("## Issues\n")
for issue in issues:
f.write(f"- {issue['title']} #{issue['number']}\n")
f.write("\n## Pull Requests\n")
for pr in pull_requests:
f.write(f"- {pr['title']} #{pr['number']}\n")

print(f"Exported daily progress to {filename}")

return filename
26 changes: 26 additions & 0 deletions src/llm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# src/llm.py

import os
from openai import OpenAI

class LLM:
def __init__(self):
self.client = OpenAI()

def generate_daily_report(self, markdown_content, dry_run=False):
prompt = f"以下是项目的最新进展,根据功能合并同类项,形成一份简报,至少包含:1)新增功能;2)主要改进;3)修复问题;:\n\n{markdown_content}"
if dry_run:
with open("daily_progress/prompt.txt", "w+") as f:
f.write(prompt)
return "DRY RUN"

print("Before call GPT")
response = self.client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": prompt}
]
)
print("After call GPT")
print(response)
return response.choices[0].message.content
93 changes: 23 additions & 70 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,30 @@
import argparse
# src/main.py

import threading
import shlex

from argparse import ArgumentError

from config import Config
from scheduler import Scheduler
from github_client import GitHubClient
from notifier import Notifier
from report_generator import ReportGenerator
from llm import LLM
from subscription_manager import SubscriptionManager
import threading
import shlex
from command_handler import CommandHandler

def run_scheduler(scheduler):
scheduler.start()

def add_subscription(args, subscription_manager):
subscription_manager.add_subscription(args.repo)
print(f"Added subscription: {args.repo}")

def remove_subscription(args, subscription_manager):
subscription_manager.remove_subscription(args.repo)
print(f"Removed subscription: {args.repo}")

def list_subscriptions(subscription_manager):
subscriptions = subscription_manager.get_subscriptions()
print("Current subscriptions:")
for sub in subscriptions:
print(f"- {sub}")

def fetch_updates(github_client, subscription_manager, report_generator):
subscriptions = subscription_manager.get_subscriptions()
updates = github_client.fetch_updates(subscriptions)
report = report_generator.generate(updates)
print("Updates fetched:")
print(report)

def print_help():
help_text = """
GitHub Sentinel Command Line Interface
Available commands:
add <repo> Add a subscription (e.g., owner/repo)
remove <repo> Remove a subscription (e.g., owner/repo)
list List all subscriptions
fetch Fetch updates immediately
help Show this help message
exit Exit the tool
quit Exit the tool
"""
print(help_text)

def main():
config = Config()
github_client = GitHubClient(config.github_token)
notifier = Notifier(config.notification_settings)
report_generator = ReportGenerator()
llm = LLM()
report_generator = ReportGenerator(llm)
subscription_manager = SubscriptionManager(config.subscriptions_file)
command_handler = CommandHandler(github_client, subscription_manager, report_generator)

scheduler = Scheduler(
github_client=github_client,
Expand All @@ -66,42 +38,23 @@ def main():
scheduler_thread.daemon = True
scheduler_thread.start()

parser = argparse.ArgumentParser(description='GitHub Sentinel Command Line Interface')
subparsers = parser.add_subparsers(title='Commands', dest='command')

parser_add = subparsers.add_parser('add', help='Add a subscription')
parser_add.add_argument('repo', type=str, help='The repository to subscribe to (e.g., owner/repo)')
parser_add.set_defaults(func=lambda args: add_subscription(args, subscription_manager))

parser_remove = subparsers.add_parser('remove', help='Remove a subscription')
parser_remove.add_argument('repo', type=str, help='The repository to unsubscribe from (e.g., owner/repo)')
parser_remove.set_defaults(func=lambda args: remove_subscription(args, subscription_manager))

parser_list = subparsers.add_parser('list', help='List all subscriptions')
parser_list.set_defaults(func=lambda args: list_subscriptions(subscription_manager))

parser_fetch = subparsers.add_parser('fetch', help='Fetch updates immediately')
parser_fetch.set_defaults(func=lambda args: fetch_updates(github_client, subscription_manager, report_generator))

parser_help = subparsers.add_parser('help', help='Show this help message')
parser_help.set_defaults(func=lambda args: print_help())

# Print help on startup
print_help()
parser = command_handler.parser
command_handler.print_help()

while True:
try:
user_input = input("GitHub Sentinel> ")
if user_input in ["exit", "quit"]:
print("Exiting GitHub Sentinel...")
if user_input in ['exit', 'quit']:
break
args = parser.parse_args(shlex.split(user_input))
if args.command is not None:
try:
args = parser.parse_args(shlex.split(user_input))
if args.command is None:
continue
args.func(args)
else:
parser.print_help()
except SystemExit as e:
print("Invalid command. Type 'help' to see the list of available commands.")
except Exception as e:
print(f"Error: {e}")
print(f"Unexpected error: {e}")

if __name__ == "__main__":
if __name__ == '__main__':
main()
44 changes: 34 additions & 10 deletions src/report_generator.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
# src/report_generator.py

import os
from datetime import date

class ReportGenerator:
def generate(self, updates):
report = "Latest Release Information:\n\n"
for repo, release in updates.items():
report += f"Repository: {repo}\n"
report += f"Latest Version: {release['tag_name']}\n"
report += f"Release Name: {release['name']}\n"
report += f"Published at: {release['published_at']}\n"
report += f"Release Notes:\n{release['body']}\n"
report += "-" * 40 + "\n"
return report
def __init__(self, llm):
self.llm = llm

def export_daily_progress(self, repo, updates):
file_path = f'daily_progress/{repo.replace("/", "_")}_{date.today()}.md'
with open(file_path, 'w') as file:
file.write(f"# Daily Progress for {repo} ({date.today()})\n\n")
file.write("## Commits\n")
for commit in updates['commits']:
file.write(f"- {commit}\n")
file.write("\n## Issues\n")
for issue in updates['issues']:
file.write(f"- {issue}\n")
file.write("\n## Pull Requests\n")
for pr in updates['pull_requests']:
file.write(f"- {pr}\n")
return file_path

def generate_daily_report(self, markdown_file_path):
with open(markdown_file_path, 'r') as file:
markdown_content = file.read()

report = self.llm.generate_daily_report(markdown_content)

report_file_path = os.path.splitext(markdown_file_path)[0] + "_report.md"
with open(report_file_path, 'w+') as report_file:
report_file.write(report)

print(f"Generated report saved to {report_file_path}")
22 changes: 12 additions & 10 deletions src/scheduler.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# src/scheduler.py

import time
import threading

class Scheduler:
def __init__(self, github_client, notifier, report_generator, subscription_manager, interval):
def __init__(self, github_client, notifier, report_generator, subscription_manager, interval=86400):
self.github_client = github_client
self.notifier = notifier
self.report_generator = report_generator
self.subscription_manager = subscription_manager
self.interval = interval

def start(self):
self.run()

def run(self):
while True:
self.run()
subscriptions = self.subscription_manager.get_subscriptions()
for repo in subscriptions:
updates = self.github_client.fetch_updates(repo)
markdown_file_path = self.report_generator.export_daily_progress(repo, updates)
self.report_generator.generate_daily_report(markdown_file_path)
time.sleep(self.interval)

def run(self):
subscriptions = self.subscription_manager.get_subscriptions()
updates = self.github_client.fetch_updates(subscriptions)
report = self.report_generator.generate(updates)
self.notifier.notify(report)
Loading

0 comments on commit ba06231

Please sign in to comment.