Spaces:
Paused
Paused
Update app.py via AI Editor
Browse files
app.py
CHANGED
@@ -26,6 +26,7 @@ CLAUDE3_MAX_OUTPUT_TOKENS = 64_000
|
|
26 |
uploaded_documents = {}
|
27 |
uploaded_proposals = {}
|
28 |
generated_documents = {}
|
|
|
29 |
shredded_document = None
|
30 |
generated_response = None
|
31 |
|
@@ -112,7 +113,7 @@ def process_document(action, selected_filename=None, chat_input=None, selected_p
|
|
112 |
if chat_input:
|
113 |
prompt += f"User additional instructions: {chat_input}\n"
|
114 |
prompt += f"\nFile Name: {selected_filename}\n\n{doc_content}"
|
115 |
-
|
116 |
result_holder = {"text": None, "docx_bytes": None, "docx_name": None}
|
117 |
def thread_shred():
|
118 |
global shredded_document
|
@@ -256,6 +257,28 @@ def get_uploaded_doc_list(docdict):
|
|
256 |
)
|
257 |
return dbc.ListGroup(doc_list, flush=True)
|
258 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
def get_uploaded_proposal_list(docdict):
|
260 |
if not docdict:
|
261 |
return html.Div("No proposal documents uploaded.", style={"wordWrap": "break-word"})
|
@@ -313,7 +336,10 @@ app.layout = dbc.Container([
|
|
313 |
'margin': '10px'
|
314 |
},
|
315 |
multiple=False
|
316 |
-
)
|
|
|
|
|
|
|
317 |
])
|
318 |
], className="mb-3"),
|
319 |
|
@@ -401,6 +427,7 @@ app.layout = dbc.Container([
|
|
401 |
Output('generated-doc-list', 'children'),
|
402 |
Output('select-generated-dropdown', 'options'),
|
403 |
Output('select-generated-dropdown', 'value'),
|
|
|
404 |
Output('output-data-upload', 'children'),
|
405 |
[
|
406 |
Input('upload-document', 'contents'),
|
@@ -414,6 +441,8 @@ app.layout = dbc.Container([
|
|
414 |
Input({'type': 'delete-generated-btn', 'index': dash.ALL, 'group': 'generated'}, 'n_clicks'),
|
415 |
State('select-generated-dropdown', 'value'),
|
416 |
State('select-generated-dropdown', 'options'),
|
|
|
|
|
417 |
Input('shred-action-btn', 'n_clicks'),
|
418 |
Input('proposal-action-btn', 'n_clicks'),
|
419 |
Input('compliance-action-btn', 'n_clicks'),
|
@@ -432,6 +461,7 @@ def master_callback(
|
|
432 |
rfp_content, rfp_filename, rfp_delete_clicks, selected_doc,
|
433 |
proposal_content, proposal_filename, proposal_delete_clicks, selected_proposal,
|
434 |
generated_delete_clicks, selected_generated, generated_options,
|
|
|
435 |
shred_clicks, proposal_clicks, compliance_clicks, recover_clicks, board_clicks, loe_clicks,
|
436 |
selected_generated_dropdown,
|
437 |
chat_input, selected_filename, selected_proposal_dropdown, selected_generated_dropdown_state
|
@@ -502,12 +532,24 @@ def master_callback(
|
|
502 |
upload_triggered = True
|
503 |
break
|
504 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
506 |
doc_value = selected_doc if selected_doc in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
507 |
proposal_options = [{'label': fn, 'value': fn} for fn in uploaded_proposals.keys()]
|
508 |
proposal_value = selected_proposal if selected_proposal in uploaded_proposals else (next(iter(uploaded_proposals), None) if uploaded_proposals else None)
|
509 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
510 |
generated_doc_value = selected_generated if selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
|
|
511 |
|
512 |
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
513 |
uploaded_proposal_list = get_uploaded_proposal_list(uploaded_proposals)
|
@@ -520,7 +562,6 @@ def master_callback(
|
|
520 |
'recover-action-btn', 'board-action-btn', 'loe-action-btn'
|
521 |
]
|
522 |
|
523 |
-
# Fix: When "Proposal" is clicked, trigger proposal streaming with correct dropdown doc selections
|
524 |
if triggered_id in action_buttons:
|
525 |
result = ""
|
526 |
generated_docx_bytes = None
|
@@ -528,14 +569,14 @@ def master_callback(
|
|
528 |
new_selected_generated = generated_doc_value
|
529 |
|
530 |
if triggered_id == 'shred-action-btn':
|
531 |
-
result,
|
532 |
-
if
|
533 |
-
|
534 |
-
logging.info(f"
|
535 |
-
|
|
|
536 |
|
537 |
elif triggered_id == 'proposal-action-btn':
|
538 |
-
# Use the currently selected doc and generated doc from dropdowns
|
539 |
rfp_doc = selected_filename
|
540 |
gen_doc = selected_generated_dropdown_state
|
541 |
logging.info(f"Starting proposal streaming with RFP: {rfp_doc}, Generated Doc: {gen_doc}")
|
@@ -550,28 +591,26 @@ def master_callback(
|
|
550 |
generated_documents[generated_docx_name] = generated_docx_bytes
|
551 |
logging.info(f"Generated proposal docx saved: {generated_docx_name}")
|
552 |
new_selected_generated = generated_docx_name
|
|
|
|
|
|
|
|
|
553 |
|
554 |
elif triggered_id == 'compliance-action-btn':
|
555 |
result, _, _ = process_document('compliance', selected_filename, chat_input)
|
|
|
556 |
elif triggered_id == 'recover-action-btn':
|
557 |
result, _, _ = process_document('recover', selected_filename, chat_input)
|
|
|
558 |
elif triggered_id == 'board-action-btn':
|
559 |
result, _, _ = process_document('board', selected_filename, chat_input)
|
|
|
560 |
elif triggered_id == 'loe-action-btn':
|
561 |
result, _, _ = process_document('loe', selected_filename, chat_input)
|
|
|
562 |
else:
|
563 |
result = "Action not implemented yet."
|
564 |
-
|
565 |
-
if isinstance(result, str) and result.strip().startswith("Error"):
|
566 |
-
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
567 |
-
elif isinstance(result, str) and ("not implemented" in result or "No document uploaded" in result or "Shredding in progress" in result or "Generating response" in result or "Shredded document not available" in result):
|
568 |
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
569 |
-
else:
|
570 |
-
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
571 |
-
|
572 |
-
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
573 |
-
generated_doc_value = new_selected_generated if new_selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
574 |
-
generated_doc_list = get_generated_doc_list(generated_documents)
|
575 |
|
576 |
elif triggered_id == 'select-generated-dropdown':
|
577 |
sel_gen = selected_generated_dropdown
|
@@ -605,6 +644,7 @@ def master_callback(
|
|
605 |
generated_doc_list,
|
606 |
generated_doc_options,
|
607 |
generated_doc_value,
|
|
|
608 |
output_data_upload
|
609 |
)
|
610 |
|
|
|
26 |
uploaded_documents = {}
|
27 |
uploaded_proposals = {}
|
28 |
generated_documents = {}
|
29 |
+
shredded_documents = {}
|
30 |
shredded_document = None
|
31 |
generated_response = None
|
32 |
|
|
|
113 |
if chat_input:
|
114 |
prompt += f"User additional instructions: {chat_input}\n"
|
115 |
prompt += f"\nFile Name: {selected_filename}\n\n{doc_content}"
|
116 |
+
|
117 |
result_holder = {"text": None, "docx_bytes": None, "docx_name": None}
|
118 |
def thread_shred():
|
119 |
global shredded_document
|
|
|
257 |
)
|
258 |
return dbc.ListGroup(doc_list, flush=True)
|
259 |
|
260 |
+
def get_shredded_doc_list(shreddict):
|
261 |
+
if not shreddict:
|
262 |
+
return html.Div("No shredded requirements yet.", style={"wordWrap": "break-word"})
|
263 |
+
doc_list = []
|
264 |
+
for filename in shreddict:
|
265 |
+
b64 = base64.b64encode(shreddict[filename]).decode('utf-8')
|
266 |
+
download_link = html.A(
|
267 |
+
f"Download {filename}",
|
268 |
+
href=f"data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,{b64}",
|
269 |
+
download=filename,
|
270 |
+
target="_blank",
|
271 |
+
style={"wordWrap": "break-word", "marginRight": "10px"}
|
272 |
+
)
|
273 |
+
doc_list.append(
|
274 |
+
dbc.ListGroupItem([
|
275 |
+
html.Span(filename, style={"wordWrap": "break-word", "marginRight": "10px"}),
|
276 |
+
download_link,
|
277 |
+
dbc.Button("Delete", id={'type': 'delete-shredded-btn', 'index': filename, 'group': 'shredded'}, size="sm", color="danger", className="float-end ms-2")
|
278 |
+
], className="d-flex justify-content-between align-items-center")
|
279 |
+
)
|
280 |
+
return dbc.ListGroup(doc_list, flush=True)
|
281 |
+
|
282 |
def get_uploaded_proposal_list(docdict):
|
283 |
if not docdict:
|
284 |
return html.Div("No proposal documents uploaded.", style={"wordWrap": "break-word"})
|
|
|
336 |
'margin': '10px'
|
337 |
},
|
338 |
multiple=False
|
339 |
+
),
|
340 |
+
html.Hr(),
|
341 |
+
html.H6("Shredded Requirements"),
|
342 |
+
html.Div(get_shredded_doc_list(shredded_documents), id='shredded-doc-list')
|
343 |
])
|
344 |
], className="mb-3"),
|
345 |
|
|
|
427 |
Output('generated-doc-list', 'children'),
|
428 |
Output('select-generated-dropdown', 'options'),
|
429 |
Output('select-generated-dropdown', 'value'),
|
430 |
+
Output('shredded-doc-list', 'children'),
|
431 |
Output('output-data-upload', 'children'),
|
432 |
[
|
433 |
Input('upload-document', 'contents'),
|
|
|
441 |
Input({'type': 'delete-generated-btn', 'index': dash.ALL, 'group': 'generated'}, 'n_clicks'),
|
442 |
State('select-generated-dropdown', 'value'),
|
443 |
State('select-generated-dropdown', 'options'),
|
444 |
+
Input({'type': 'delete-shredded-btn', 'index': dash.ALL, 'group': 'shredded'}, 'n_clicks'),
|
445 |
+
State('shredded-doc-list', 'children'),
|
446 |
Input('shred-action-btn', 'n_clicks'),
|
447 |
Input('proposal-action-btn', 'n_clicks'),
|
448 |
Input('compliance-action-btn', 'n_clicks'),
|
|
|
461 |
rfp_content, rfp_filename, rfp_delete_clicks, selected_doc,
|
462 |
proposal_content, proposal_filename, proposal_delete_clicks, selected_proposal,
|
463 |
generated_delete_clicks, selected_generated, generated_options,
|
464 |
+
shredded_delete_clicks, shredded_doc_children,
|
465 |
shred_clicks, proposal_clicks, compliance_clicks, recover_clicks, board_clicks, loe_clicks,
|
466 |
selected_generated_dropdown,
|
467 |
chat_input, selected_filename, selected_proposal_dropdown, selected_generated_dropdown_state
|
|
|
532 |
upload_triggered = True
|
533 |
break
|
534 |
|
535 |
+
if triggered_id and isinstance(ctx.inputs_list[12], list):
|
536 |
+
for i, n_click in enumerate(shredded_delete_clicks):
|
537 |
+
if n_click:
|
538 |
+
btn_id = ctx.inputs_list[12][i]['id']
|
539 |
+
del_filename = btn_id['index']
|
540 |
+
if del_filename in shredded_documents:
|
541 |
+
del shredded_documents[del_filename]
|
542 |
+
logging.info(f"Shredded doc deleted: {del_filename}")
|
543 |
+
upload_triggered = True
|
544 |
+
break
|
545 |
+
|
546 |
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
547 |
doc_value = selected_doc if selected_doc in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
548 |
proposal_options = [{'label': fn, 'value': fn} for fn in uploaded_proposals.keys()]
|
549 |
proposal_value = selected_proposal if selected_proposal in uploaded_proposals else (next(iter(uploaded_proposals), None) if uploaded_proposals else None)
|
550 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
551 |
generated_doc_value = selected_generated if selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
552 |
+
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
553 |
|
554 |
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
555 |
uploaded_proposal_list = get_uploaded_proposal_list(uploaded_proposals)
|
|
|
562 |
'recover-action-btn', 'board-action-btn', 'loe-action-btn'
|
563 |
]
|
564 |
|
|
|
565 |
if triggered_id in action_buttons:
|
566 |
result = ""
|
567 |
generated_docx_bytes = None
|
|
|
569 |
new_selected_generated = generated_doc_value
|
570 |
|
571 |
if triggered_id == 'shred-action-btn':
|
572 |
+
result, shredded_docx_bytes, shredded_docx_name = process_document('shred', selected_filename, chat_input)
|
573 |
+
if shredded_docx_bytes and shredded_docx_name:
|
574 |
+
shredded_documents[shredded_docx_name] = shredded_docx_bytes
|
575 |
+
logging.info(f"Shredded docx saved: {shredded_docx_name}")
|
576 |
+
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
577 |
+
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
578 |
|
579 |
elif triggered_id == 'proposal-action-btn':
|
|
|
580 |
rfp_doc = selected_filename
|
581 |
gen_doc = selected_generated_dropdown_state
|
582 |
logging.info(f"Starting proposal streaming with RFP: {rfp_doc}, Generated Doc: {gen_doc}")
|
|
|
591 |
generated_documents[generated_docx_name] = generated_docx_bytes
|
592 |
logging.info(f"Generated proposal docx saved: {generated_docx_name}")
|
593 |
new_selected_generated = generated_docx_name
|
594 |
+
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
595 |
+
generated_doc_value = new_selected_generated if new_selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
596 |
+
generated_doc_list = get_generated_doc_list(generated_documents)
|
597 |
+
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
598 |
|
599 |
elif triggered_id == 'compliance-action-btn':
|
600 |
result, _, _ = process_document('compliance', selected_filename, chat_input)
|
601 |
+
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
602 |
elif triggered_id == 'recover-action-btn':
|
603 |
result, _, _ = process_document('recover', selected_filename, chat_input)
|
604 |
+
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
605 |
elif triggered_id == 'board-action-btn':
|
606 |
result, _, _ = process_document('board', selected_filename, chat_input)
|
607 |
+
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
608 |
elif triggered_id == 'loe-action-btn':
|
609 |
result, _, _ = process_document('loe', selected_filename, chat_input)
|
610 |
+
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
611 |
else:
|
612 |
result = "Action not implemented yet."
|
|
|
|
|
|
|
|
|
613 |
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
|
|
|
|
|
|
|
|
|
|
|
|
614 |
|
615 |
elif triggered_id == 'select-generated-dropdown':
|
616 |
sel_gen = selected_generated_dropdown
|
|
|
644 |
generated_doc_list,
|
645 |
generated_doc_options,
|
646 |
generated_doc_value,
|
647 |
+
shredded_doc_list_items,
|
648 |
output_data_upload
|
649 |
)
|
650 |
|