import dash from dash import dcc, html, Input, Output, State, callback import dash_bootstrap_components as dbc from dash.exceptions import PreventUpdate import google.generativeai as genai from github import Github import gitlab import requests import tempfile import docx import os import logging import threading import base64 # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) # Helper functions (is_ui_file, get_file_contents, generate_guide_section, generate_guide) # ... (Keep these functions as they are in the original code) app.layout = dbc.Container([ html.H1("Automated Guide Generator", className="my-4"), html.P("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."), dbc.Card([ dbc.CardBody([ dcc.Dropdown( id='git-provider', options=[ {'label': 'GitHub', 'value': 'GitHub'}, {'label': 'GitLab', 'value': 'GitLab'}, {'label': 'Gitea', 'value': 'Gitea'} ], placeholder="Select Git Provider" ), dbc.Input(id='repo-url', placeholder="Repository URL (owner/repo)", type="text", className="mt-3"), dcc.RadioItems( id='guide-type', options=[ {'label': 'User Guide', 'value': 'User Guide'}, {'label': 'Administration Guide', 'value': 'Administration Guide'} ], className="mt-3" ), dbc.Input(id='exclude-folders', placeholder="Exclude Folders (comma-separated)", type="text", className="mt-3"), dbc.Button("Generate Guide", id="generate-button", color="primary", className="mt-3"), ]) ], className="mb-4"), dbc.Spinner( dcc.Loading( id="loading-output", children=[ html.Div(id="output-area"), dcc.Download(id="download-docx"), dcc.Download(id="download-md") ], type="default", ) ), dcc.Store(id='guide-store'), ]) @app.callback( Output('guide-store', 'data'), Output('output-area', 'children'), Input('generate-button', 'n_clicks'), State('git-provider', 'value'), State('repo-url', 'value'), State('guide-type', 'value'), State('exclude-folders', 'value'), prevent_initial_call=True ) def generate_guide_callback(n_clicks, git_provider, repo_url, guide_type, exclude_folders): if not all([git_provider, repo_url, guide_type]): raise PreventUpdate def generate_guide_thread(): try: guide_text, docx_path, md_path = generate_guide( git_provider, repo_url, "", "", guide_type, exclude_folders ) with open(docx_path, 'rb') as docx_file, open(md_path, 'rb') as md_file: docx_content = base64.b64encode(docx_file.read()).decode('utf-8') md_content = base64.b64encode(md_file.read()).decode('utf-8') os.unlink(docx_path) os.unlink(md_path) return { 'guide_text': guide_text, 'docx_content': docx_content, 'md_content': md_content } except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) return {'error': str(e)} thread = threading.Thread(target=generate_guide_thread) thread.start() thread.join() result = thread.result() if hasattr(thread, 'result') else None if result and 'error' not in result: output = [ html.H3("Generated Guide"), html.Pre(result['guide_text']), dbc.Button("Download DOCX", id="btn-download-docx", color="secondary", className="me-2"), dbc.Button("Download Markdown", id="btn-download-md", color="secondary") ] return result, output else: error_message = result['error'] if result and 'error' in result else "An unknown error occurred" return None, html.Div(f"Error: {error_message}", style={'color': 'red'}) @app.callback( Output("download-docx", "data"), Input("btn-download-docx", "n_clicks"), State('guide-store', 'data'), prevent_initial_call=True ) def download_docx(n_clicks, data): if data and 'docx_content' in data: return dict(content=data['docx_content'], filename="guide.docx", base64=True) raise PreventUpdate @app.callback( Output("download-md", "data"), Input("btn-download-md", "n_clicks"), State('guide-store', 'data'), prevent_initial_call=True ) def download_md(n_clicks, data): if data and 'md_content' in data: return dict(content=data['md_content'], filename="guide.md", base64=True) raise PreventUpdate 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.")