bluenevus commited on
Commit
586d074
·
verified ·
1 Parent(s): ba33407

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -155
app.py CHANGED
@@ -12,6 +12,7 @@ import os
12
  import logging
13
  import threading
14
  from huggingface_hub import HfApi
 
15
 
16
  # Configure logging
17
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -19,6 +20,7 @@ logger = logging.getLogger(__name__)
19
 
20
  # Initialize Dash app
21
  app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
 
22
 
23
  # Hugging Face API setup
24
  hf_api = HfApi()
@@ -27,149 +29,7 @@ hf_api = HfApi()
27
  GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
28
  GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
29
 
30
- def is_ui_file(filename):
31
- 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']
32
- return any(filename.endswith(ext) for ext in ui_extensions)
33
-
34
- def get_file_contents(git_provider, repo_url, exclude_folders):
35
- file_contents = []
36
- logger.info(f"Fetching files from {git_provider} repository: {repo_url}")
37
- exclude_folders = [folder.strip() for folder in exclude_folders.split(',') if folder.strip()]
38
- if git_provider == "GitHub":
39
- g = Github(GITHUB_TOKEN)
40
- repo = g.get_repo(repo_url)
41
- contents = repo.get_contents("")
42
- while contents:
43
- file_content = contents.pop(0)
44
- if file_content.type == "dir":
45
- if not any(file_content.path.startswith(folder) for folder in exclude_folders):
46
- contents.extend(repo.get_contents(file_content.path))
47
- elif is_ui_file(file_content.name) and not any(file_content.path.startswith(folder) for folder in exclude_folders):
48
- logger.info(f"Found UI file: {file_content.path}")
49
- file_contents.append((file_content.path, file_content.decoded_content.decode('utf-8', errors='ignore')))
50
- elif git_provider == "GitLab":
51
- gl = gitlab.Gitlab(url='https://gitlab.com', private_token=GITHUB_TOKEN)
52
- project = gl.projects.get(repo_url)
53
- items = project.repository_tree(recursive=True)
54
- for item in items:
55
- if item['type'] == 'blob' and is_ui_file(item['name']) and not any(item['path'].startswith(folder) for folder in exclude_folders):
56
- logger.info(f"Found UI file: {item['path']}")
57
- file_content = project.files.get(item['path'], ref='main')
58
- file_contents.append((item['path'], file_content.decode().decode('utf-8', errors='ignore')))
59
- elif git_provider == "Gitea":
60
- base_url = "https://gitea.com/api/v1"
61
- headers = {"Authorization": f"token {GITHUB_TOKEN}"}
62
- def recursive_get_contents(path=""):
63
- response = requests.get(f"{base_url}/repos/{repo_url}/contents/{path}", headers=headers)
64
- response.raise_for_status()
65
- for item in response.json():
66
- if item['type'] == 'file' and is_ui_file(item['name']) and not any(item['path'].startswith(folder) for folder in exclude_folders):
67
- logger.info(f"Found UI file: {item['path']}")
68
- file_content = requests.get(item['download_url']).text
69
- file_contents.append((item['path'], file_content))
70
- elif item['type'] == 'dir' and not any(item['path'].startswith(folder) for folder in exclude_folders):
71
- recursive_get_contents(item['path'])
72
- recursive_get_contents()
73
- else:
74
- raise ValueError("Unsupported Git provider")
75
- logger.info(f"Total UI files found: {len(file_contents)}")
76
- return file_contents
77
-
78
- def generate_guide_section(file_path, file_content, guide_type):
79
- logger.info(f"Generating {guide_type} section for file: {file_path}")
80
- genai.configure(api_key=GEMINI_API_KEY)
81
- model = genai.GenerativeModel('gemini-2.0-flash-lite')
82
-
83
- if guide_type == "User Guide":
84
- prompt = f"""Based on the following UI-related code file, generate a section for a user guide:
85
-
86
- File: {file_path}
87
- Content:
88
- {file_content}
89
-
90
- Please focus on:
91
- 1. The specific features and functionality this UI component provides to the end users
92
- 2. Step-by-step instructions on how to use these features
93
- 3. Any user interactions or inputs required
94
- 4. Expected outcomes or results for the user
95
-
96
- Important formatting instructions:
97
- - 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
98
- - Use clear section titles
99
- - Follow this numbering heirarchy (1.0, 1.1, 1.2), (2.0, 2.1, 2.2), (3.0, 3.1, 3.2)
100
- - Explain the purpose and benefit of each feature for non-technical users
101
- - This is an end user manual, not a system administration manual so focus on the end user components
102
- """
103
- else: # Administration Guide
104
- prompt = f"""Based on the following UI-related code file, generate a section for an System guide:
105
-
106
- File: {file_path}
107
- Content:
108
- {file_content}
109
-
110
- Please focus on explaining what that component is and does:
111
- 1. Any configuration options or settings related to this UI component
112
- 2. Security considerations or access control related to this feature
113
- 3. How to monitor or troubleshoot issues with this component
114
- 4. Best practices for managing and maintaining this part of the system
115
-
116
- Important formatting instructions:
117
- - 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
118
- - Use clear section titles
119
- - Use clear section titles that has the name of the file in parenthesis
120
- - Follow this numbering heirarchy (1.0, 1.1, 1.2), (2.0, 2.1, 2.2), (3.0, 3.1, 3.2)
121
- - Explain the purpose and implications of each component
122
- """
123
-
124
- response = model.generate_content(prompt)
125
- logger.info(f"Generated {guide_type} section for {file_path}")
126
- return response.text
127
-
128
- def generate_guide(git_provider, repo_url, guide_type, exclude_folders):
129
- try:
130
- logger.info(f"Starting guide generation for {repo_url}")
131
- file_contents = get_file_contents(git_provider, repo_url, exclude_folders)
132
-
133
- guide_sections = []
134
- for file_path, content in file_contents:
135
- section = generate_guide_section(file_path, content, guide_type)
136
- guide_sections.append(section)
137
- logger.info(f"Added section for {file_path}")
138
-
139
- full_guide = f"# {guide_type}\n\n" + "\n\n".join(guide_sections)
140
-
141
- logger.info("Creating DOCX file")
142
- doc = docx.Document()
143
- doc.add_heading(guide_type, 0)
144
-
145
- for line in full_guide.split('\n'):
146
- line = line.strip()
147
- if line.startswith('# '):
148
- doc.add_heading(line[2:], level=1)
149
- elif line.startswith('## '):
150
- doc.add_heading(line[3:], level=2)
151
- elif line.startswith('Step'):
152
- doc.add_paragraph(line, style='List Number')
153
- else:
154
- doc.add_paragraph(line)
155
-
156
- with tempfile.NamedTemporaryFile(delete=False, suffix='.docx') as temp_docx:
157
- doc.save(temp_docx.name)
158
- docx_path = temp_docx.name
159
- logger.info(f"DOCX file saved: {docx_path}")
160
-
161
- logger.info("Creating Markdown file")
162
- with tempfile.NamedTemporaryFile(delete=False, suffix='.md', mode='w', encoding='utf-8') as temp_md:
163
- temp_md.write(full_guide)
164
- md_path = temp_md.name
165
- logger.info(f"Markdown file saved: {md_path}")
166
-
167
- logger.info("Guide generation completed successfully")
168
- return full_guide, docx_path, md_path
169
-
170
- except Exception as e:
171
- logger.error(f"An error occurred: {str(e)}", exc_info=True)
172
- return f"An error occurred: {str(e)}", None, None
173
 
174
  # App layout
175
  app.layout = dbc.Container([
@@ -227,23 +87,32 @@ app.layout = dbc.Container([
227
  dbc.Card([
228
  dbc.CardBody([
229
  html.H4("Generated Guide", className="card-title"),
230
- html.Div(id="generated-guide", style={"whiteSpace": "pre-wrap"}),
231
  html.Div([
232
  dbc.Button("Download DOCX", id="download-docx", color="secondary", className="me-2"),
233
  dbc.Button("Download Markdown", id="download-md", color="secondary"),
234
- ], className="mt-3")
 
 
235
  ])
236
  ], className="mt-4"),
237
  color="primary",
238
  ),
239
- ], width=12)
 
 
 
 
 
 
 
 
240
  ])
241
  ], fluid=True)
242
 
243
  @app.callback(
244
  [Output("generated-guide", "children"),
245
- Output("download-docx", "href"),
246
- Output("download-md", "href")],
247
  [Input("generate-button", "n_clicks")],
248
  [State("git-provider", "value"),
249
  State("repo-url", "value"),
@@ -263,13 +132,27 @@ def update_output(n_clicks, git_provider, repo_url, guide_type, exclude_folders)
263
  thread.start()
264
  thread.join()
265
 
266
- if docx_path and md_path:
267
- docx_url = f"/download?path={docx_path}"
268
- md_url = f"/download?path={md_path}"
269
- else:
270
- docx_url = md_url = "#"
271
-
272
- return guide_text, docx_url, md_url
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
 
274
  if __name__ == '__main__':
275
  print("Starting the Dash application...")
 
12
  import logging
13
  import threading
14
  from huggingface_hub import HfApi
15
+ from flask import send_file
16
 
17
  # Configure logging
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
20
 
21
  # Initialize Dash app
22
  app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
23
+ server = app.server # Expose the Flask server
24
 
25
  # Hugging Face API setup
26
  hf_api = HfApi()
 
29
  GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
30
  GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
31
 
32
+ # ... (rest of the functions remain unchanged)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  # App layout
35
  app.layout = dbc.Container([
 
87
  dbc.Card([
88
  dbc.CardBody([
89
  html.H4("Generated Guide", className="card-title"),
 
90
  html.Div([
91
  dbc.Button("Download DOCX", id="download-docx", color="secondary", className="me-2"),
92
  dbc.Button("Download Markdown", id="download-md", color="secondary"),
93
+ ], className="mt-3"),
94
+ dcc.Download(id="download-docx-file"),
95
+ dcc.Download(id="download-md-file"),
96
  ])
97
  ], className="mt-4"),
98
  color="primary",
99
  ),
100
+ ], width=6),
101
+ dbc.Col([
102
+ dbc.Card([
103
+ dbc.CardBody([
104
+ html.H4("Preview", className="card-title"),
105
+ html.Div(id="generated-guide", style={"whiteSpace": "pre-wrap", "height": "400px", "overflowY": "auto"}),
106
+ ])
107
+ ], className="mt-4"),
108
+ ], width=6),
109
  ])
110
  ], fluid=True)
111
 
112
  @app.callback(
113
  [Output("generated-guide", "children"),
114
+ Output("download-docx", "n_clicks"),
115
+ Output("download-md", "n_clicks")],
116
  [Input("generate-button", "n_clicks")],
117
  [State("git-provider", "value"),
118
  State("repo-url", "value"),
 
132
  thread.start()
133
  thread.join()
134
 
135
+ return guide_text, 0, 0 # Reset n_clicks for download buttons
136
+
137
+ @app.callback(
138
+ Output("download-docx-file", "data"),
139
+ Input("download-docx", "n_clicks"),
140
+ prevent_initial_call=True,
141
+ )
142
+ def download_docx(n_clicks):
143
+ if n_clicks is None:
144
+ raise PreventUpdate
145
+ return dcc.send_file(docx_path, filename="generated_guide.docx")
146
+
147
+ @app.callback(
148
+ Output("download-md-file", "data"),
149
+ Input("download-md", "n_clicks"),
150
+ prevent_initial_call=True,
151
+ )
152
+ def download_md(n_clicks):
153
+ if n_clicks is None:
154
+ raise PreventUpdate
155
+ return dcc.send_file(md_path, filename="generated_guide.md")
156
 
157
  if __name__ == '__main__':
158
  print("Starting the Dash application...")