bluenevus commited on
Commit
9f4cd2a
·
1 Parent(s): 263b12d

Update app.py via AI Editor

Browse files
Files changed (1) hide show
  1. app.py +84 -38
app.py CHANGED
@@ -3,22 +3,25 @@ import io
3
  import os
4
  import pandas as pd
5
  from docx import Document
6
- from io import BytesIO
7
  import dash
8
  import dash_bootstrap_components as dbc
9
  from dash import html, dcc, Input, Output, State, callback_context
10
- import google.generativeai as genai
11
  from docx.shared import Pt
12
  from docx.enum.style import WD_STYLE_TYPE
13
  from PyPDF2 import PdfReader
14
- from io import StringIO
 
 
 
 
 
15
 
16
  # Initialize Dash app
17
  app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
18
 
19
- # Configure Gemini AI
20
- genai.configure(api_key=os.environ["GEMINI_API_KEY"])
21
- model = genai.GenerativeModel('gemini-2.5-pro-preview-03-25')
22
 
23
  # Global variables
24
  uploaded_files = {}
@@ -44,6 +47,9 @@ app.layout = dbc.Container([
44
  dbc.Row([
45
  dbc.Col([
46
  html.H4("Proposal Documents", className="mt-3 mb-4"),
 
 
 
47
  dcc.Upload(
48
  id='upload-document',
49
  children=html.Div([
@@ -75,6 +81,9 @@ app.layout = dbc.Container([
75
  ])
76
  ], width=3),
77
  dbc.Col([
 
 
 
78
  html.Div(id='status-bar', className="alert alert-info", style={'marginBottom': '20px'}),
79
  dcc.Loading(
80
  id="loading-indicator",
@@ -107,7 +116,7 @@ app.layout = dbc.Container([
107
  id="chat-loading",
108
  type="dot",
109
  children=[
110
- dbc.Input(id="chat-input", type="text", placeholder="Chat with AI to update document...", className="mb-2"),
111
  dbc.Button("Send", id="btn-send-chat", color="primary", className="mb-3"),
112
  html.Div(id="chat-output")
113
  ]
@@ -128,11 +137,14 @@ def process_document(contents, filename):
128
  pdf = PdfReader(BytesIO(decoded))
129
  text = ""
130
  for page in pdf.pages:
131
- text += page.extract_text()
 
 
132
  return text
133
  else:
134
  return f"Unsupported file format: {filename}. Please upload a PDF or DOCX file."
135
  except Exception as e:
 
136
  return f"Error processing document: {str(e)}"
137
 
138
  @app.callback(
@@ -155,7 +167,8 @@ def update_output(list_of_contents, list_of_names, existing_files):
155
  ]))
156
  if existing_files is None:
157
  existing_files = []
158
- shredded_document = None # Reset shredded document when new files are uploaded
 
159
  return existing_files + new_files, "Document uploaded. Please click 'Shred' to proceed."
160
  return existing_files, "Please upload a document and click 'Shred' to begin."
161
 
@@ -173,7 +186,8 @@ def remove_file(n_clicks, existing_files):
173
  raise dash.exceptions.PreventUpdate
174
  removed_file = ctx.triggered[0]['prop_id'].split(',')[0].split(':')[-1].strip('}')
175
  uploaded_files.pop(removed_file, None)
176
- shredded_document = None # Reset shredded document when a file is removed
 
177
  return [file for file in existing_files if file['props']['children'][1]['props']['children'] != removed_file], "Document removed. Please upload a document and click 'Shred' to begin."
178
 
179
  def generate_document(document_type, file_contents):
@@ -207,8 +221,23 @@ to be sure we address them.
207
  Now, generate the {document_type}:
208
  """
209
 
210
- response = model.generate_content(prompt)
211
- return response.text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  @app.callback(
214
  Output('document-preview', 'children'),
@@ -239,7 +268,7 @@ def generate_document_preview(*args):
239
  shredded_document = generate_document(document_type, file_contents)
240
  return dcc.Markdown(shredded_document), f"{document_type} generated", "Document shredded. You can now proceed with other operations.", {'display': 'none'}
241
  except Exception as e:
242
- print(f"Error generating document: {str(e)}")
243
  return html.Div(f"Error generating document: {str(e)}"), "Error", "An error occurred while shredding the document.", {'display': 'none'}
244
 
245
  if shredded_document is None:
@@ -262,9 +291,10 @@ def generate_document_preview(*args):
262
  if document_type == "Pink Review":
263
  pink_review_document = current_document
264
 
 
265
  return dcc.Markdown(current_document), f"{document_type} generated", f"{document_type} document generated successfully.", {'display': 'none'}
266
  except Exception as e:
267
- print(f"Error generating document: {str(e)}")
268
  return html.Div(f"Error generating document: {str(e)}"), "Error", "An error occurred while generating the document.", {'display': 'none'}
269
 
270
  @app.callback(
@@ -274,6 +304,7 @@ def generate_document_preview(*args):
274
  )
275
  def update_pink_review_filename(contents, filename):
276
  if contents is not None:
 
277
  return filename
278
  return ""
279
 
@@ -298,11 +329,24 @@ Instructions:
298
  3. Incorporate the requested changes seamlessly.
299
  Now, provide the updated {document_type}:
300
  """
301
-
302
- response = model.generate_content(prompt)
303
- current_document = response.text
304
-
305
- return f"Document updated based on: {chat_input}", dcc.Markdown(current_document)
 
 
 
 
 
 
 
 
 
 
 
 
 
306
 
307
  @app.callback(
308
  Output("download-document", "data"),
@@ -315,27 +359,29 @@ def download_document(n_clicks):
315
  raise dash.exceptions.PreventUpdate
316
 
317
  if document_type == "LOE":
318
- # Create a pandas DataFrame for LOE
319
- df = pd.read_csv(StringIO(current_document))
320
-
321
- # Save the DataFrame to an Excel file
322
- output = BytesIO()
323
- with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
324
- df.to_excel(writer, sheet_name='LOE', index=False)
325
-
326
- return dcc.send_bytes(output.getvalue(), f"{document_type}.xlsx")
 
327
  else:
328
- # Create an in-memory Word document
329
- doc = Document()
330
- doc.add_paragraph(current_document)
331
-
332
- # Save the document to a BytesIO object
333
- output = BytesIO()
334
- doc.save(output)
335
-
336
- return dcc.send_bytes(output.getvalue(), f"{document_type}.docx")
 
337
 
338
  if __name__ == '__main__':
339
  print("Starting the Dash application...")
340
- app.run(debug=False, host='0.0.0.0', port=7860)
341
  print("Dash application has finished running.")
 
3
  import os
4
  import pandas as pd
5
  from docx import Document
6
+ from io import BytesIO, StringIO
7
  import dash
8
  import dash_bootstrap_components as dbc
9
  from dash import html, dcc, Input, Output, State, callback_context
 
10
  from docx.shared import Pt
11
  from docx.enum.style import WD_STYLE_TYPE
12
  from PyPDF2 import PdfReader
13
+ import openai
14
+ import logging
15
+ import threading
16
+
17
+ # Logging configuration
18
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
19
 
20
  # Initialize Dash app
21
  app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
22
 
23
+ # Configure OpenAI
24
+ openai.api_key = os.environ.get("OPENAI_API_KEY", "")
 
25
 
26
  # Global variables
27
  uploaded_files = {}
 
47
  dbc.Row([
48
  dbc.Col([
49
  html.H4("Proposal Documents", className="mt-3 mb-4"),
50
+ html.Div([
51
+ html.Div(className="blinking-dot", style={'margin':'0 auto','width':'16px','height':'16px'}),
52
+ ], style={'textAlign':'center', 'marginBottom':'10px'}),
53
  dcc.Upload(
54
  id='upload-document',
55
  children=html.Div([
 
81
  ])
82
  ], width=3),
83
  dbc.Col([
84
+ html.Div([
85
+ html.Div(className="blinking-dot", style={'margin':'0 auto','width':'16px','height':'16px'}),
86
+ ], style={'textAlign':'center', 'marginBottom':'10px'}),
87
  html.Div(id='status-bar', className="alert alert-info", style={'marginBottom': '20px'}),
88
  dcc.Loading(
89
  id="loading-indicator",
 
116
  id="chat-loading",
117
  type="dot",
118
  children=[
119
+ dbc.Input(id="chat-input", type="text", placeholder="Chat with AI to update document...", className="mb-2", style={'whiteSpace':'pre-wrap'}),
120
  dbc.Button("Send", id="btn-send-chat", color="primary", className="mb-3"),
121
  html.Div(id="chat-output")
122
  ]
 
137
  pdf = PdfReader(BytesIO(decoded))
138
  text = ""
139
  for page in pdf.pages:
140
+ page_text = page.extract_text()
141
+ if page_text:
142
+ text += page_text
143
  return text
144
  else:
145
  return f"Unsupported file format: {filename}. Please upload a PDF or DOCX file."
146
  except Exception as e:
147
+ logging.error(f"Error processing document: {str(e)}")
148
  return f"Error processing document: {str(e)}"
149
 
150
  @app.callback(
 
167
  ]))
168
  if existing_files is None:
169
  existing_files = []
170
+ shredded_document = None
171
+ logging.info("Documents uploaded and file list updated.")
172
  return existing_files + new_files, "Document uploaded. Please click 'Shred' to proceed."
173
  return existing_files, "Please upload a document and click 'Shred' to begin."
174
 
 
186
  raise dash.exceptions.PreventUpdate
187
  removed_file = ctx.triggered[0]['prop_id'].split(',')[0].split(':')[-1].strip('}')
188
  uploaded_files.pop(removed_file, None)
189
+ shredded_document = None
190
+ logging.info(f"Removed file: {removed_file}")
191
  return [file for file in existing_files if file['props']['children'][1]['props']['children'] != removed_file], "Document removed. Please upload a document and click 'Shred' to begin."
192
 
193
  def generate_document(document_type, file_contents):
 
221
  Now, generate the {document_type}:
222
  """
223
 
224
+ logging.info(f"Generating document for type: {document_type}")
225
+ try:
226
+ response = openai.ChatCompletion.create(
227
+ model="gpt-4-1106-preview",
228
+ messages=[
229
+ {"role": "system", "content": "You are a helpful, expert government proposal writer."},
230
+ {"role": "user", "content": prompt}
231
+ ],
232
+ max_tokens=4096,
233
+ temperature=0.25,
234
+ )
235
+ generated_text = response['choices'][0]['message']['content']
236
+ logging.info("Document generated successfully.")
237
+ return generated_text
238
+ except Exception as e:
239
+ logging.error(f"Error generating document: {str(e)}")
240
+ raise
241
 
242
  @app.callback(
243
  Output('document-preview', 'children'),
 
268
  shredded_document = generate_document(document_type, file_contents)
269
  return dcc.Markdown(shredded_document), f"{document_type} generated", "Document shredded. You can now proceed with other operations.", {'display': 'none'}
270
  except Exception as e:
271
+ logging.error(f"Error generating document: {str(e)}")
272
  return html.Div(f"Error generating document: {str(e)}"), "Error", "An error occurred while shredding the document.", {'display': 'none'}
273
 
274
  if shredded_document is None:
 
291
  if document_type == "Pink Review":
292
  pink_review_document = current_document
293
 
294
+ logging.info(f"{document_type} document generated successfully.")
295
  return dcc.Markdown(current_document), f"{document_type} generated", f"{document_type} document generated successfully.", {'display': 'none'}
296
  except Exception as e:
297
+ logging.error(f"Error generating document: {str(e)}")
298
  return html.Div(f"Error generating document: {str(e)}"), "Error", "An error occurred while generating the document.", {'display': 'none'}
299
 
300
  @app.callback(
 
304
  )
305
  def update_pink_review_filename(contents, filename):
306
  if contents is not None:
307
+ logging.info(f"Pink Review file uploaded: {filename}")
308
  return filename
309
  return ""
310
 
 
329
  3. Incorporate the requested changes seamlessly.
330
  Now, provide the updated {document_type}:
331
  """
332
+
333
+ logging.info(f"Updating document via chat for {document_type} instruction: {chat_input}")
334
+ try:
335
+ response = openai.ChatCompletion.create(
336
+ model="gpt-4-1106-preview",
337
+ messages=[
338
+ {"role": "system", "content": "You are a helpful, expert government proposal writer."},
339
+ {"role": "user", "content": prompt}
340
+ ],
341
+ max_tokens=4096,
342
+ temperature=0.2,
343
+ )
344
+ current_document = response['choices'][0]['message']['content']
345
+ logging.info("Document updated via chat successfully.")
346
+ return f"Document updated based on: {chat_input}", dcc.Markdown(current_document)
347
+ except Exception as e:
348
+ logging.error(f"Error updating document via chat: {str(e)}")
349
+ return f"Error updating document: {str(e)}", html.Div(f"Error updating document: {str(e)}")
350
 
351
  @app.callback(
352
  Output("download-document", "data"),
 
359
  raise dash.exceptions.PreventUpdate
360
 
361
  if document_type == "LOE":
362
+ try:
363
+ df = pd.read_csv(StringIO(current_document))
364
+ output = BytesIO()
365
+ with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
366
+ df.to_excel(writer, sheet_name='LOE', index=False)
367
+ logging.info("LOE document downloaded as Excel.")
368
+ return dcc.send_bytes(output.getvalue(), f"{document_type}.xlsx")
369
+ except Exception as e:
370
+ logging.error(f"Error downloading LOE document: {str(e)}")
371
+ return dcc.send_string(f"Error downloading LOE: {str(e)}", f"{document_type}_error.txt")
372
  else:
373
+ try:
374
+ doc = Document()
375
+ doc.add_paragraph(current_document)
376
+ output = BytesIO()
377
+ doc.save(output)
378
+ logging.info("Document downloaded as Word.")
379
+ return dcc.send_bytes(output.getvalue(), f"{document_type}.docx")
380
+ except Exception as e:
381
+ logging.error(f"Error downloading document: {str(e)}")
382
+ return dcc.send_string(f"Error downloading document: {str(e)}", f"{document_type}_error.txt")
383
 
384
  if __name__ == '__main__':
385
  print("Starting the Dash application...")
386
+ app.run(debug=True, host='0.0.0.0', port=7860, threaded=True)
387
  print("Dash application has finished running.")