bluenevus commited on
Commit
3f743eb
·
1 Parent(s): 4dc0cab

Update app.py via AI Editor

Browse files
Files changed (1) hide show
  1. app.py +56 -15
app.py CHANGED
@@ -6,7 +6,6 @@ from dash import dcc, html, Input, Output, State, callback_context
6
  import dash_bootstrap_components as dbc
7
  import pandas as pd
8
  import anthropic
9
- from threading import Thread
10
  import logging
11
  from docx import Document
12
 
@@ -63,6 +62,19 @@ def anthropic_stream_generate(prompt):
63
  logging.error("Error during anthropic streaming request: %s", e)
64
  return f"Error during streaming: {e}"
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  def save_shredded_as_docx(shredded_text, rfp_filename):
67
  doc = Document()
68
  doc.add_heading(f"Shredded Requirements for {rfp_filename}", 0)
@@ -73,7 +85,7 @@ def save_shredded_as_docx(shredded_text, rfp_filename):
73
  memf.seek(0)
74
  return memf.read()
75
 
76
- def process_document(action, selected_filename=None, chat_input=None, selected_proposal=None):
77
  global shredded_document, generated_response
78
  logging.info(f"Process document called with action: {action}")
79
 
@@ -127,6 +139,7 @@ def process_document(action, selected_filename=None, chat_input=None, selected_p
127
  logging.error("Error in thread_shred: %s", e)
128
  result_holder["text"] = shredded_document
129
  shredded_document = "Shredding in progress..."
 
130
  t = Thread(target=thread_shred)
131
  t.start()
132
  t.join()
@@ -159,15 +172,52 @@ def process_document(action, selected_filename=None, chat_input=None, selected_p
159
  logging.error("Error in thread_generate: %s", e)
160
  result_holder["text"] = generated_response
161
  generated_response = "Generating response..."
 
162
  t = Thread(target=thread_generate)
163
  t.start()
164
  t.join()
165
  return result_holder["text"], None, None
166
 
167
  elif action == 'proposal':
168
- if not doc_content:
169
- return "No proposal document uploaded.", None, None
170
- return dcc.Markdown(doc_content, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"}), None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  elif action == 'compliance':
172
  return "Compliance checking not implemented yet.", None, None
173
  elif action == 'recover':
@@ -374,10 +424,8 @@ def master_callback(
374
  ctx = callback_context
375
  triggered_id = ctx.triggered[0]['prop_id'].split('.')[0] if ctx.triggered else None
376
 
377
- # Upload or delete document or proposal or generated document
378
  upload_triggered = False
379
 
380
- # Handle upload document
381
  if triggered_id == 'upload-document' and rfp_content is not None and rfp_filename:
382
  content_type, content_string = rfp_content.split(',')
383
  decoded = base64.b64decode(content_string)
@@ -389,7 +437,6 @@ def master_callback(
389
  logging.error(f"Failed to decode uploaded document: {rfp_filename}")
390
  upload_triggered = True
391
 
392
- # Handle upload proposal
393
  if triggered_id == 'upload-proposal' and proposal_content is not None and proposal_filename:
394
  content_type, content_string = proposal_content.split(',')
395
  decoded = base64.b64decode(content_string)
@@ -401,7 +448,6 @@ def master_callback(
401
  logging.error(f"Failed to decode uploaded proposal: {proposal_filename}")
402
  upload_triggered = True
403
 
404
- # Handle delete document
405
  if triggered_id and isinstance(ctx.inputs_list[2], list):
406
  for i, n_click in enumerate(rfp_delete_clicks):
407
  if n_click:
@@ -415,7 +461,6 @@ def master_callback(
415
  upload_triggered = True
416
  break
417
 
418
- # Handle delete proposal
419
  if triggered_id and isinstance(ctx.inputs_list[6], list):
420
  for i, n_click in enumerate(proposal_delete_clicks):
421
  if n_click:
@@ -429,7 +474,6 @@ def master_callback(
429
  upload_triggered = True
430
  break
431
 
432
- # Handle delete generated document
433
  if triggered_id and isinstance(ctx.inputs_list[10], list):
434
  for i, n_click in enumerate(generated_delete_clicks):
435
  if n_click:
@@ -454,7 +498,6 @@ def master_callback(
454
  uploaded_proposal_list = get_uploaded_proposal_list(uploaded_proposals)
455
  generated_doc_list = get_generated_doc_list(generated_documents)
456
 
457
- # Default output
458
  output_data_upload = html.Div("No action taken yet.", style={"wordWrap": "break-word"})
459
 
460
  action_buttons = [
@@ -462,7 +505,6 @@ def master_callback(
462
  'recover-action-btn', 'board-action-btn', 'loe-action-btn'
463
  ]
464
 
465
- # Handle action buttons
466
  if triggered_id in action_buttons:
467
  result = ""
468
  generated_docx_bytes = None
@@ -476,7 +518,7 @@ def master_callback(
476
  logging.info(f"Generated docx saved: {generated_docx_name}")
477
  new_selected_generated = generated_docx_name
478
  elif triggered_id == 'generate-action-btn':
479
- result, _, _ = process_document('generate', selected_filename, chat_input)
480
  elif triggered_id == 'compliance-action-btn':
481
  result, _, _ = process_document('compliance', selected_filename, chat_input)
482
  elif triggered_id == 'recover-action-btn':
@@ -499,7 +541,6 @@ def master_callback(
499
  generated_doc_value = new_selected_generated if new_selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
500
  generated_doc_list = get_generated_doc_list(generated_documents)
501
 
502
- # Handle select-generated-dropdown for download
503
  elif triggered_id == 'select-generated-dropdown':
504
  sel_gen = selected_generated_dropdown
505
  if not sel_gen or sel_gen not in generated_documents:
 
6
  import dash_bootstrap_components as dbc
7
  import pandas as pd
8
  import anthropic
 
9
  import logging
10
  from docx import Document
11
 
 
62
  logging.error("Error during anthropic streaming request: %s", e)
63
  return f"Error during streaming: {e}"
64
 
65
+ def anthropic_sync_generate(prompt):
66
+ try:
67
+ response = anthropic_client.messages.create(
68
+ model=CLAUDE3_SONNET_MODEL,
69
+ max_tokens=CLAUDE3_MAX_OUTPUT_TOKENS,
70
+ messages=[{"role": "user", "content": prompt}]
71
+ )
72
+ logging.info("Synchronous anthropic generation complete.")
73
+ return response.content[0].text if hasattr(response, "content") else ""
74
+ except Exception as e:
75
+ logging.error("Error during anthropic synchronous request: %s", e)
76
+ return f"Error during synchronous call: {e}"
77
+
78
  def save_shredded_as_docx(shredded_text, rfp_filename):
79
  doc = Document()
80
  doc.add_heading(f"Shredded Requirements for {rfp_filename}", 0)
 
85
  memf.seek(0)
86
  return memf.read()
87
 
88
+ def process_document(action, selected_filename=None, chat_input=None, selected_proposal=None, selected_generated=None):
89
  global shredded_document, generated_response
90
  logging.info(f"Process document called with action: {action}")
91
 
 
139
  logging.error("Error in thread_shred: %s", e)
140
  result_holder["text"] = shredded_document
141
  shredded_document = "Shredding in progress..."
142
+ from threading import Thread
143
  t = Thread(target=thread_shred)
144
  t.start()
145
  t.join()
 
172
  logging.error("Error in thread_generate: %s", e)
173
  result_holder["text"] = generated_response
174
  generated_response = "Generating response..."
175
+ from threading import Thread
176
  t = Thread(target=thread_generate)
177
  t.start()
178
  t.join()
179
  return result_holder["text"], None, None
180
 
181
  elif action == 'proposal':
182
+ rfp_content = None
183
+ generated_doc_content = None
184
+ rfp_filename = selected_filename
185
+ generated_docname = selected_generated
186
+ if not (selected_filename and selected_filename in uploaded_documents):
187
+ return "No RFP/SOW/PWS/RFI document selected.", None, None
188
+ if not (selected_generated and selected_generated in generated_documents):
189
+ return "No generated document selected.", None, None
190
+ rfp_content = uploaded_documents[selected_filename]
191
+ gen_bytes = generated_documents[selected_generated]
192
+ try:
193
+ # Try to read as docx, fallback to decode
194
+ try:
195
+ docx_stream = io.BytesIO(gen_bytes)
196
+ doc = Document(docx_stream)
197
+ generated_doc_content = "\n".join([para.text for para in doc.paragraphs])
198
+ except Exception as e:
199
+ try:
200
+ generated_doc_content = gen_bytes.decode('utf-8')
201
+ except Exception:
202
+ generated_doc_content = "<Unable to decode generated document.>"
203
+ except Exception as e:
204
+ generated_doc_content = "<Unable to read generated document.>"
205
+ logging.error(f"Failed to read generated document: {e}")
206
+
207
+ prompt = (
208
+ "Respond to the following RFP/SOW/PWS/RFI provided and focus on the Generated Document provided by creating a highly detailed proposal response that follows each section and subsection header and numbering. "
209
+ "The response to each section and subsection will be compliant and compelling, focusing on describing the approach, and how the labor category uses a specific industry standard process in a workflow described in steps, and how technology is used. "
210
+ "You must show innovation in the approach. Refer to research that validates the approach and cite sources with measurable outcome. "
211
+ "Be sure to respond in paragraph format, significantly limiting the use of bullets.\n"
212
+ )
213
+ if chat_input:
214
+ prompt += f"User additional instructions: {chat_input}\n"
215
+ prompt += f"\n---\nRFP/SOW/PWS/RFI ({rfp_filename}):\n{rfp_content}\n"
216
+ prompt += f"\n---\nGenerated Document ({generated_docname}):\n{generated_doc_content}\n"
217
+ logging.info("Sending proposal prompt to anthropic. This is a synchronous call.")
218
+ result = anthropic_sync_generate(prompt)
219
+ return result, None, None
220
+
221
  elif action == 'compliance':
222
  return "Compliance checking not implemented yet.", None, None
223
  elif action == 'recover':
 
424
  ctx = callback_context
425
  triggered_id = ctx.triggered[0]['prop_id'].split('.')[0] if ctx.triggered else None
426
 
 
427
  upload_triggered = False
428
 
 
429
  if triggered_id == 'upload-document' and rfp_content is not None and rfp_filename:
430
  content_type, content_string = rfp_content.split(',')
431
  decoded = base64.b64decode(content_string)
 
437
  logging.error(f"Failed to decode uploaded document: {rfp_filename}")
438
  upload_triggered = True
439
 
 
440
  if triggered_id == 'upload-proposal' and proposal_content is not None and proposal_filename:
441
  content_type, content_string = proposal_content.split(',')
442
  decoded = base64.b64decode(content_string)
 
448
  logging.error(f"Failed to decode uploaded proposal: {proposal_filename}")
449
  upload_triggered = True
450
 
 
451
  if triggered_id and isinstance(ctx.inputs_list[2], list):
452
  for i, n_click in enumerate(rfp_delete_clicks):
453
  if n_click:
 
461
  upload_triggered = True
462
  break
463
 
 
464
  if triggered_id and isinstance(ctx.inputs_list[6], list):
465
  for i, n_click in enumerate(proposal_delete_clicks):
466
  if n_click:
 
474
  upload_triggered = True
475
  break
476
 
 
477
  if triggered_id and isinstance(ctx.inputs_list[10], list):
478
  for i, n_click in enumerate(generated_delete_clicks):
479
  if n_click:
 
498
  uploaded_proposal_list = get_uploaded_proposal_list(uploaded_proposals)
499
  generated_doc_list = get_generated_doc_list(generated_documents)
500
 
 
501
  output_data_upload = html.Div("No action taken yet.", style={"wordWrap": "break-word"})
502
 
503
  action_buttons = [
 
505
  'recover-action-btn', 'board-action-btn', 'loe-action-btn'
506
  ]
507
 
 
508
  if triggered_id in action_buttons:
509
  result = ""
510
  generated_docx_bytes = None
 
518
  logging.info(f"Generated docx saved: {generated_docx_name}")
519
  new_selected_generated = generated_docx_name
520
  elif triggered_id == 'generate-action-btn':
521
+ result, _, _ = process_document('proposal', selected_filename, chat_input, selected_proposal_dropdown, selected_generated_dropdown_state)
522
  elif triggered_id == 'compliance-action-btn':
523
  result, _, _ = process_document('compliance', selected_filename, chat_input)
524
  elif triggered_id == 'recover-action-btn':
 
541
  generated_doc_value = new_selected_generated if new_selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
542
  generated_doc_list = get_generated_doc_list(generated_documents)
543
 
 
544
  elif triggered_id == 'select-generated-dropdown':
545
  sel_gen = selected_generated_dropdown
546
  if not sel_gen or sel_gen not in generated_documents: