bluenevus's picture
Update app.py
8db037e verified
raw
history blame
9 kB
import gradio as gr
import google.generativeai as genai
from github import Github
import gitlab
import requests
import tempfile
import docx
import os
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def is_ui_file(filename):
ui_extensions = ['.erb', '.haml', '.slim', '.php', '.aspx', '.jsp', '.ftl', '.twig', '.mustache', '.handlebars', '.ejs', '.pug', '.blade.php', '.xhtml', '.fxml', '.tsx', '.jsx', '.vue', '.html', '.cshtml', '.razor', '.xaml', '.jsx']
return any(filename.endswith(ext) for ext in ui_extensions)
def get_file_contents(git_provider, repo_url, personal_access_token, exclude_folders):
file_contents = []
logger.info(f"Fetching files from {git_provider} repository: {repo_url}")
exclude_folders = [folder.strip() for folder in exclude_folders.split(',') if folder.strip()]
if git_provider == "GitHub":
g = Github(personal_access_token)
repo = g.get_repo(repo_url)
contents = repo.get_contents("")
while contents:
file_content = contents.pop(0)
if file_content.type == "dir":
if not any(file_content.path.startswith(folder) for folder in exclude_folders):
contents.extend(repo.get_contents(file_content.path))
elif is_ui_file(file_content.name) and not any(file_content.path.startswith(folder) for folder in exclude_folders):
logger.info(f"Found UI file: {file_content.path}")
file_contents.append((file_content.path, file_content.decoded_content.decode('utf-8', errors='ignore')))
elif git_provider == "GitLab":
gl = gitlab.Gitlab(url='https://gitlab.com', private_token=personal_access_token)
project = gl.projects.get(repo_url)
items = project.repository_tree(recursive=True)
for item in items:
if item['type'] == 'blob' and is_ui_file(item['name']) and not any(item['path'].startswith(folder) for folder in exclude_folders):
logger.info(f"Found UI file: {item['path']}")
file_content = project.files.get(item['path'], ref='main')
file_contents.append((item['path'], file_content.decode().decode('utf-8', errors='ignore')))
elif git_provider == "Gitea":
base_url = "https://gitea.com/api/v1"
headers = {"Authorization": f"token {personal_access_token}"}
def recursive_get_contents(path=""):
response = requests.get(f"{base_url}/repos/{repo_url}/contents/{path}", headers=headers)
response.raise_for_status()
for item in response.json():
if item['type'] == 'file' and is_ui_file(item['name']) and not any(item['path'].startswith(folder) for folder in exclude_folders):
logger.info(f"Found UI file: {item['path']}")
file_content = requests.get(item['download_url']).text
file_contents.append((item['path'], file_content))
elif item['type'] == 'dir' and not any(item['path'].startswith(folder) for folder in exclude_folders):
recursive_get_contents(item['path'])
recursive_get_contents()
else:
raise ValueError("Unsupported Git provider")
logger.info(f"Total UI files found: {len(file_contents)}")
return file_contents
def generate_guide_section(file_path, file_content, guide_type, gemini_api_key):
logger.info(f"Generating {guide_type} section for file: {file_path}")
genai.configure(api_key=gemini_api_key)
model = genai.GenerativeModel('gemini-2.0-flash-lite')
if guide_type == "User Guide":
prompt = f"""Based on the following UI-related code file, generate a section for a user guide:
File: {file_path}
Content:
{file_content}
Please focus on:
1. The specific features and functionality this UI component provides to the end users
2. Step-by-step instructions on how to use these features
3. Any user interactions or inputs required
4. Expected outcomes or results for the user
Important formatting instructions:
- The output should be in plain text no markdown for example do not use * or ** or # or ##. Instead use numbers like 1., 2. for bullets
- Use clear section titles
- Follow this numbering heirarchy (1.0, 1.1, 1.2), (2.0, 2.1, 2.2), (3.0, 3.1, 3.2)
- Explain the purpose and benefit of each feature for non-technical users
- This is an end user manual, not a system administration manual so focus on the end user components
"""
else: # Administration Guide
prompt = f"""Based on the following UI-related code file, generate a section for an System guide:
File: {file_path}
Content:
{file_content}
Please focus on explaining what that component is and does:
1. Any configuration options or settings related to this UI component
2. Security considerations or access control related to this feature
3. How to monitor or troubleshoot issues with this component
4. Best practices for managing and maintaining this part of the system
Important formatting instructions:
- The output should be in plain text no markdown for example for example do not use * or ** or # or ##. Instead use numbers like 1., 2. for bullets
- Use clear section titles
- Use clear section titles that has the name of the file in parenthesis
- Follow this numbering heirarchy (1.0, 1.1, 1.2), (2.0, 2.1, 2.2), (3.0, 3.1, 3.2)
- Explain the purpose and implications of each component
"""
response = model.generate_content(prompt)
logger.info(f"Generated {guide_type} section for {file_path}")
return response.text
def generate_guide(git_provider, repo_url, personal_access_token, gemini_api_key, guide_type, exclude_folders):
try:
logger.info(f"Starting guide generation for {repo_url}")
file_contents = get_file_contents(git_provider, repo_url, personal_access_token, exclude_folders)
guide_sections = []
for file_path, content in file_contents:
section = generate_guide_section(file_path, content, guide_type, gemini_api_key)
guide_sections.append(section)
logger.info(f"Added section for {file_path}")
full_guide = f"# {guide_type}\n\n" + "\n\n".join(guide_sections)
logger.info("Creating DOCX file")
doc = docx.Document()
doc.add_heading(guide_type, 0)
for line in full_guide.split('\n'):
line = line.strip()
if line.startswith('# '):
doc.add_heading(line[2:], level=1)
elif line.startswith('## '):
doc.add_heading(line[3:], level=2)
elif line.startswith('Step'):
doc.add_paragraph(line, style='List Number')
else:
doc.add_paragraph(line)
with tempfile.NamedTemporaryFile(delete=False, suffix='.docx') as temp_docx:
doc.save(temp_docx.name)
docx_path = temp_docx.name
logger.info(f"DOCX file saved: {docx_path}")
logger.info("Creating Markdown file")
with tempfile.NamedTemporaryFile(delete=False, suffix='.md', mode='w', encoding='utf-8') as temp_md:
temp_md.write(full_guide)
md_path = temp_md.name
logger.info(f"Markdown file saved: {md_path}")
logger.info("Guide generation completed successfully")
return full_guide, docx_path, md_path
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return f"An error occurred: {str(e)}", None, None
iface = gr.Interface(
fn=generate_guide,
inputs=[
gr.Dropdown(
choices=["GitHub", "GitLab", "Gitea"],
label="Git Provider"
),
gr.Textbox(label="Repository URL", placeholder="owner/repo"),
gr.Textbox(label="Personal Access Token", type="password"),
gr.Textbox(label="Gemini API Key", type="password"),
gr.Radio(["User Guide", "Administration Guide"], label="Guide Type"),
gr.Textbox(label="Exclude Folders", placeholder="folder1, folder2, folder3")
],
outputs=[
gr.Textbox(label="Generated Guide"),
gr.File(label="Download Guide (DOCX)"),
gr.File(label="Download Guide (Markdown)")
],
title="Automated Guide Generator",
description="Generate a user guide or administration guide based on the UI-related code in a Git repository using Gemini AI. Select a Git provider, enter repository details, choose the guide type, and let AI create a comprehensive guide.",
allow_flagging="never",
theme="default",
analytics_enabled=False,
)
if __name__ == "__main__":
iface.launch()