bluenevus's picture
Update app.py
785cb50 verified
raw
history blame
9.76 kB
import dash
from dash import dcc, html, Input, Output, State
import dash_bootstrap_components as dbc
from datetime import datetime, timedelta
import google.generativeai as genai
from github import Github, GithubException
import gitlab
import docx
import tempfile
import requests
import os
import threading
import io
# Initialize the Dash app
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Hugging Face variables
HF_GEMINI_API_KEY = os.environ.get('HF_GEMINI_API_KEY')
HF_GITHUB_TOKEN = os.environ.get('HF_GITHUB_TOKEN')
# Global variable to store generated files
generated_file = None
def generate_release_notes(git_provider, repo_url, start_date, end_date, folder_location):
global generated_file
try:
start_date = datetime.strptime(start_date, "%Y-%m-%d")
end_date = datetime.strptime(end_date, "%Y-%m-%d")
if git_provider == "GitHub":
g = Github(HF_GITHUB_TOKEN)
repo = g.get_repo(repo_url)
commits = list(repo.get_commits(since=start_date, until=end_date))
commit_messages = [commit.commit.message for commit in commits]
elif git_provider == "GitLab":
gl = gitlab.Gitlab(url='https://gitlab.com', private_token=HF_GITHUB_TOKEN)
project = gl.projects.get(repo_url)
commits = project.commits.list(since=start_date.isoformat(), until=end_date.isoformat())
commit_messages = [commit.message for commit in commits]
elif git_provider == "Gitea":
base_url = "https://gitea.com/api/v1"
headers = {"Authorization": f"token {HF_GITHUB_TOKEN}"}
response = requests.get(f"{base_url}/repos/{repo_url}/commits", headers=headers, params={
"since": start_date.isoformat(),
"until": end_date.isoformat()
})
response.raise_for_status()
commits = response.json()
commit_messages = [commit['commit']['message'] for commit in commits]
else:
return "Unsupported Git provider", None
commit_text = "\n".join(commit_messages)
if not commit_text:
return "No commits found in the specified date range.", None
genai.configure(api_key=HF_GEMINI_API_KEY)
model = genai.GenerativeModel('gemini-2.0-flash-lite')
prompt = f"""Based on the following commit messages, generate comprehensive release notes:
{commit_text}
Please organize the release notes into sections such as:
1. New Features
2. Bug Fixes
3. Improvements
4. Breaking Changes (if any)
Provide a concise summary for each item. Do not include any links, but keep issue numbers if present.
Important formatting instructions:
- The output should be plain text without any markdown or "-" for post processing
- Use section titles followed by a colon (e.g., "New Features:")
- Start each item on a new line
- Be sure to briefly explain the why and benefits of the change for average users that are non-technical
"""
response = model.generate_content(prompt)
release_notes = response.text
# Create Markdown file
markdown_content = "# Release Notes\n\n"
for line in release_notes.split('\n'):
line = line.strip()
if line.endswith(':'):
markdown_content += f"\n## {line}\n\n"
elif line:
markdown_content += f"- {line}\n"
# Generate file name based on the current date
file_name = f"{datetime.now().strftime('%m-%d-%Y')}.md"
# Store the generated file content
generated_file = io.BytesIO(markdown_content.encode())
generated_file.seek(0)
# Update SUMMARY.md
summary_url = "https://github.com/MicroHealthLLC/maiko-assistant/blob/main/documentation%2Freleases%2FSUMMARY.md"
update_summary(summary_url, file_name)
return release_notes, file_name
except Exception as e:
return f"An error occurred: {str(e)}", None
def update_summary(summary_url, new_file_name):
try:
g = Github(HF_GITHUB_TOKEN)
repo = g.get_repo("MicroHealthLLC/maiko-assistant")
summary_content = repo.get_contents("documentation/releases/SUMMARY.md").decoded_content.decode()
# Add new file to the top of the Releases section
new_entry = f"{datetime.now().strftime('%b %d, %Y')}\n"
updated_content = summary_content.replace("Releases\n", f"Releases\n{new_entry}")
# Create a new branch for the PR
base_branch = repo.default_branch
new_branch = f"update-summary-{datetime.now().strftime('%Y%m%d%H%M%S')}"
ref = repo.get_git_ref(f"heads/{base_branch}")
repo.create_git_ref(ref=f"refs/heads/{new_branch}", sha=ref.object.sha)
# Update SUMMARY.md in the new branch
repo.update_file(
"documentation/releases/SUMMARY.md",
f"Update SUMMARY.md with new release notes {new_file_name}",
updated_content,
repo.get_contents("documentation/releases/SUMMARY.md").sha,
branch=new_branch
)
# Create a pull request
pr = repo.create_pull(
title=f"Update SUMMARY.md with new release notes {new_file_name}",
body="Automatically generated PR to update SUMMARY.md with new release notes.",
head=new_branch,
base=base_branch
)
return f"Pull request created: {pr.html_url}"
except Exception as e:
return f"Error updating SUMMARY.md: {str(e)}"
# App layout
app.layout = dbc.Container([
html.H1("Automated Release Notes Generator", className="mb-4"),
dbc.Card([
dbc.CardBody([
dbc.Form([
dbc.Row([
dbc.Col([
dcc.Dropdown(
id='git-provider',
options=[
{'label': 'GitHub', 'value': 'GitHub'},
{'label': 'GitLab', 'value': 'GitLab'},
{'label': 'Gitea', 'value': 'Gitea'}
],
placeholder="Select Git Provider"
)
], width=12, className="mb-3"),
]),
dbc.Row([
dbc.Col([
dbc.Input(id='repo-url', placeholder="Repository URL (owner/repo)", type="text")
], width=12, className="mb-3"),
]),
dbc.Row([
dbc.Col([
dbc.Input(id='start-date', placeholder="Start Date (YYYY-MM-DD)", type="text")
], width=12, className="mb-3"),
]),
dbc.Row([
dbc.Col([
dbc.Input(id='end-date', placeholder="End Date (YYYY-MM-DD)", type="text")
], width=12, className="mb-3"),
]),
dbc.Row([
dbc.Col([
dbc.Input(id='folder-location', placeholder="Folder Location", type="text")
], width=12, className="mb-3"),
]),
dbc.Row([
dbc.Col([
dbc.Button("Generate Release Notes", id="generate-button", color="primary", className="mr-2"),
dbc.Button("Download Markdown", id="download-button", color="secondary", className="mr-2", disabled=True),
dbc.Button("Create PR", id="pr-button", color="info", disabled=True)
], width=12, className="mb-3"),
]),
]),
])
], className="mb-4"),
dbc.Card([
dbc.CardBody([
html.H4("Generated Release Notes"),
html.Pre(id="output-notes", style={"white-space": "pre-wrap"})
])
]),
dcc.Download(id="download-markdown")
])
@app.callback(
[Output("output-notes", "children"),
Output("download-button", "disabled"),
Output("pr-button", "disabled")],
[Input("generate-button", "n_clicks")],
[State("git-provider", "value"),
State("repo-url", "value"),
State("start-date", "value"),
State("end-date", "value"),
State("folder-location", "value")]
)
def update_output(n_clicks, git_provider, repo_url, start_date, end_date, folder_location):
if n_clicks is None:
return "", True, True
notes, file_name = generate_release_notes(git_provider, repo_url, start_date, end_date, folder_location)
return notes, False, False
@app.callback(
Output("download-markdown", "data"),
Input("download-button", "n_clicks"),
prevent_initial_call=True
)
def download_markdown(n_clicks):
if n_clicks is None:
return dash.no_update
global generated_file
if generated_file is None:
return dash.no_update
return dcc.send_bytes(generated_file.getvalue(), f"release_notes_{datetime.now().strftime('%Y%m%d%H%M%S')}.md")
@app.callback(
Output("pr-button", "children"),
Input("pr-button", "n_clicks"),
[State("folder-location", "value")],
prevent_initial_call=True
)
def create_pr(n_clicks, folder_location):
if n_clicks is None:
return dash.no_update
# Implement PR creation logic here
# For now, we'll just return a placeholder message
return "PR Created"
if __name__ == '__main__':
print("Starting the Dash application...")
app.run(debug=True, host='0.0.0.0', port=7860)
print("Dash application has finished running.")