import gradio as gr from datetime import datetime, timedelta import google.generativeai as genai from github import Github, GithubException import docx import re def remove_links_keep_issue_numbers(text): return re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', text) def strip_markdown(text): # Remove headers text = re.sub(r'^#+\s*', '', text, flags=re.MULTILINE) # Remove bold/italic without removing adjacent characters text = re.sub(r'(\*{1,2})([^\*]+)\1', r'\2', text) # Remove inline code without removing adjacent characters text = re.sub(r'`([^`]+)`', r'\1', text) # Remove blockquotes text = re.sub(r'^\s*>\s*', '', text, flags=re.MULTILINE) return text.strip() def markdown_to_docx(doc, markdown_text): lines = markdown_text.split('\n') for line in lines: stripped_line = strip_markdown(line) if line.lstrip().startswith('# '): doc.add_heading(stripped_line, level=1) elif line.lstrip().startswith('## '): doc.add_heading(stripped_line, level=2) elif line.lstrip().startswith('### '): doc.add_heading(stripped_line, level=3) elif line.strip().startswith('- ') or line.strip().startswith('* '): doc.add_paragraph(stripped_line.strip()[2:], style='List Bullet') elif re.match(r'^\d+\.', line.strip()): doc.add_paragraph(stripped_line.strip(), style='List Number') else: doc.add_paragraph(stripped_line) def generate_release_notes(github_url, github_token, gemini_api_key, start_date, end_date): try: g = Github(github_token) repo = g.get_repo(github_url) start_date = datetime.strptime(start_date, "%Y-%m-%d") end_date = datetime.strptime(end_date, "%Y-%m-%d") commits = list(repo.get_commits(since=start_date, until=end_date)) commit_messages = [commit.commit.message for commit in commits] commit_text = "\n".join(commit_messages) if not commit_text: return "No commits found in the specified date range.", None genai.configure(api_key=gemini_api_key) model = genai.GenerativeModel('gemini-2.5-pro-preview-03-25') 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.""" response = model.generate_content(prompt) release_notes = remove_links_keep_issue_numbers(response.text) doc = docx.Document() doc.add_heading('Release Notes', 0) markdown_to_docx(doc, release_notes) temp_file = "release_notes.docx" doc.save(temp_file) return release_notes, temp_file except GithubException as e: if e.status == 401: return "Error: Invalid GitHub token or insufficient permissions.", None elif e.status == 404: return f"Error: Repository not found. Please check the GitHub URL. Attempted to access: {github_url}", None else: return f"GitHub API error: {str(e)}", None except Exception as e: return f"An error occurred: {str(e)}", None default_end_date = datetime.now() default_start_date = default_end_date - timedelta(days=30) iface = gr.Interface( fn=generate_release_notes, inputs=[ gr.Textbox(label="GitHub Repository Name", placeholder="MicroHealthLLC/maiko-assistant"), gr.Textbox(label="GitHub Personal Access Token", type="password"), gr.Textbox(label="Gemini API Key", type="password"), gr.Textbox( label="Start Date", placeholder="YYYY-MM-DD", value=default_start_date.strftime("%Y-%m-%d"), ), gr.Textbox( label="End Date", placeholder="YYYY-MM-DD", value=default_end_date.strftime("%Y-%m-%d"), ) ], outputs=[ gr.Textbox(label="Generated Release Notes"), gr.File(label="Download Release Notes") ], title="Automated Release Notes Generator", description="Generate release notes based on GitHub commits using Gemini AI. Enter start and end dates (YYYY-MM-DD) to define the time range for commits.", allow_flagging="never", theme="default", analytics_enabled=False, ) iface.launch()