Spaces:
Paused
Paused
Update app.py via AI Editor
Browse files
app.py
CHANGED
|
@@ -2,7 +2,7 @@ import os
|
|
| 2 |
import base64
|
| 3 |
import io
|
| 4 |
import dash
|
| 5 |
-
from dash import dcc, html, Input, Output, State, callback_context
|
| 6 |
import dash_bootstrap_components as dbc
|
| 7 |
import pandas as pd
|
| 8 |
import logging
|
|
@@ -153,7 +153,7 @@ def process_document(action, selected_filename=None, chat_input=None):
|
|
| 153 |
if action == 'shred':
|
| 154 |
if not doc_content:
|
| 155 |
logging.warning("No uploaded document found for shredding.")
|
| 156 |
-
return "No document uploaded.", None, None
|
| 157 |
prompt = (
|
| 158 |
"Analyze the following RFP/PWS/SOW/RFI and generate a requirements spreadsheet. "
|
| 159 |
"Identify requirements by action words like 'shall', 'will', 'perform', etc. Also analye the document and put a column for win theme for each requirement identified. Organize by PWS section and requirement. "
|
|
@@ -184,12 +184,20 @@ def process_document(action, selected_filename=None, chat_input=None):
|
|
| 184 |
t = Thread(target=thread_shred)
|
| 185 |
t.start()
|
| 186 |
t.join()
|
| 187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
|
| 189 |
elif action == 'generate':
|
| 190 |
if not shredded_document:
|
| 191 |
logging.warning("No shredded document found when generating response.")
|
| 192 |
-
return "Shredded document not available.", None, None
|
| 193 |
prompt = (
|
| 194 |
"Create a highly detailed proposal response based on the following PWS requirements. "
|
| 195 |
"Be compliant and compelling. Focus on describing the approach, steps, workflow, people, processes, and technology. "
|
|
@@ -220,12 +228,12 @@ def process_document(action, selected_filename=None, chat_input=None):
|
|
| 220 |
t = Thread(target=thread_generate)
|
| 221 |
t.start()
|
| 222 |
t.join()
|
| 223 |
-
return result_holder["text"], result_holder["docx_bytes"], result_holder["docx_name"]
|
| 224 |
|
| 225 |
elif action == 'proposal':
|
| 226 |
if not doc_content:
|
| 227 |
logging.warning("No RFP/SOW/PWS/RFI document selected for proposal action.")
|
| 228 |
-
return "No RFP/SOW/PWS/RFI document selected.", None, None
|
| 229 |
rfp_filename = selected_filename
|
| 230 |
rfp_fileid = uploaded_documents_fileid.get(selected_filename)
|
| 231 |
prompt = (
|
|
@@ -255,17 +263,17 @@ def process_document(action, selected_filename=None, chat_input=None):
|
|
| 255 |
t = Thread(target=thread_proposal)
|
| 256 |
t.start()
|
| 257 |
t.join()
|
| 258 |
-
return result_holder["text"], result_holder["docx_bytes"], result_holder["docx_name"]
|
| 259 |
|
| 260 |
elif action == 'compliance':
|
| 261 |
-
return "Compliance checking not implemented yet.", None, None
|
| 262 |
elif action == 'recover':
|
| 263 |
-
return "Recovery not implemented yet.", None, None
|
| 264 |
elif action == 'board':
|
| 265 |
-
return "Virtual board not implemented yet.", None, None
|
| 266 |
elif action == 'loe':
|
| 267 |
-
return "LOE estimation not implemented yet.", None, None
|
| 268 |
-
return "Action not implemented yet.", None, None
|
| 269 |
|
| 270 |
def get_uploaded_doc_list(docdict):
|
| 271 |
if not docdict:
|
|
@@ -329,6 +337,8 @@ def get_generated_doc_list(docdict):
|
|
| 329 |
return dbc.ListGroup(doc_list, flush=True)
|
| 330 |
|
| 331 |
app.layout = dbc.Container([
|
|
|
|
|
|
|
| 332 |
dbc.Row([
|
| 333 |
dbc.Col([
|
| 334 |
dbc.Card([
|
|
@@ -441,37 +451,31 @@ app.layout = dbc.Container([
|
|
| 441 |
], fluid=True)
|
| 442 |
|
| 443 |
@app.callback(
|
|
|
|
|
|
|
|
|
|
| 444 |
Output('uploaded-doc-list', 'children'),
|
| 445 |
Output('select-document-dropdown', 'options'),
|
| 446 |
Output('select-document-dropdown', 'value'),
|
| 447 |
-
Output('
|
| 448 |
-
Output('select-proposal-dropdown', 'value'),
|
| 449 |
-
Output('uploaded-proposal-list', 'children'),
|
| 450 |
Output('generated-doc-list', 'children'),
|
| 451 |
Output('select-generated-dropdown', 'options'),
|
| 452 |
Output('select-generated-dropdown', 'value'),
|
| 453 |
-
Output('shredded-doc-list', 'children'),
|
| 454 |
-
Output('output-data-upload', 'children'),
|
| 455 |
[
|
|
|
|
|
|
|
| 456 |
Input('upload-document', 'contents'),
|
| 457 |
State('upload-document', 'filename'),
|
| 458 |
-
Input({'type': 'delete-doc-btn', 'index':
|
| 459 |
State('select-document-dropdown', 'value'),
|
| 460 |
Input('upload-proposal', 'contents'),
|
| 461 |
State('upload-proposal', 'filename'),
|
| 462 |
-
Input({'type': 'delete-proposal-btn', 'index':
|
| 463 |
State('select-proposal-dropdown', 'value'),
|
| 464 |
-
Input({'type': 'delete-generated-btn', 'index':
|
| 465 |
State('select-generated-dropdown', 'value'),
|
| 466 |
-
|
| 467 |
-
Input({'type': 'delete-shredded-btn', 'index': dash.ALL, 'group': 'shredded'}, 'n_clicks'),
|
| 468 |
State('shredded-doc-list', 'children'),
|
| 469 |
-
Input('shred-action-btn', 'n_clicks'),
|
| 470 |
-
Input('proposal-action-btn', 'n_clicks'),
|
| 471 |
-
Input('compliance-action-btn', 'n_clicks'),
|
| 472 |
-
Input('recover-action-btn', 'n_clicks'),
|
| 473 |
-
Input('board-action-btn', 'n_clicks'),
|
| 474 |
-
Input('loe-action-btn', 'n_clicks'),
|
| 475 |
Input('select-generated-dropdown', 'value'),
|
| 476 |
State('chat-input', 'value'),
|
| 477 |
State('select-document-dropdown', 'value'),
|
|
@@ -481,12 +485,12 @@ app.layout = dbc.Container([
|
|
| 481 |
prevent_initial_call=True
|
| 482 |
)
|
| 483 |
def master_callback(
|
|
|
|
| 484 |
rfp_content, rfp_filename, rfp_delete_clicks, selected_doc,
|
| 485 |
proposal_content, proposal_filename, proposal_delete_clicks, selected_proposal,
|
| 486 |
-
generated_delete_clicks, selected_generated,
|
| 487 |
shredded_delete_clicks, shredded_doc_children,
|
| 488 |
-
|
| 489 |
-
selected_generated_dropdown,
|
| 490 |
chat_input, selected_filename, selected_proposal_dropdown, selected_generated_dropdown_state
|
| 491 |
):
|
| 492 |
ctx = callback_context
|
|
@@ -494,6 +498,10 @@ def master_callback(
|
|
| 494 |
|
| 495 |
upload_triggered = False
|
| 496 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
if triggered_id == 'upload-document' and rfp_content is not None and rfp_filename:
|
| 498 |
content_type, content_string = rfp_content.split(',')
|
| 499 |
decoded = base64.b64decode(content_string)
|
|
@@ -526,10 +534,10 @@ def master_callback(
|
|
| 526 |
logging.error(f"Failed to decode uploaded proposal: {proposal_filename}")
|
| 527 |
upload_triggered = True
|
| 528 |
|
| 529 |
-
if triggered_id and isinstance(ctx.inputs_list[
|
| 530 |
for i, n_click in enumerate(rfp_delete_clicks):
|
| 531 |
if n_click:
|
| 532 |
-
btn_id = ctx.inputs_list[
|
| 533 |
del_filename = btn_id['index']
|
| 534 |
if del_filename in uploaded_documents:
|
| 535 |
del uploaded_documents[del_filename]
|
|
@@ -545,10 +553,10 @@ def master_callback(
|
|
| 545 |
upload_triggered = True
|
| 546 |
break
|
| 547 |
|
| 548 |
-
if triggered_id and isinstance(ctx.inputs_list[
|
| 549 |
for i, n_click in enumerate(proposal_delete_clicks):
|
| 550 |
if n_click:
|
| 551 |
-
btn_id = ctx.inputs_list[
|
| 552 |
del_filename = btn_id['index']
|
| 553 |
if del_filename in uploaded_proposals:
|
| 554 |
del uploaded_proposals[del_filename]
|
|
@@ -590,72 +598,59 @@ def master_callback(
|
|
| 590 |
|
| 591 |
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
| 592 |
doc_value = selected_doc if selected_doc in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
| 593 |
-
proposal_options = [{'label': fn, 'value': fn} for fn in uploaded_proposals.keys()]
|
| 594 |
-
proposal_value = selected_proposal if selected_proposal in uploaded_proposals else (next(iter(uploaded_proposals), None) if uploaded_proposals else None)
|
| 595 |
-
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
| 596 |
-
generated_doc_value = selected_generated if selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
| 597 |
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
| 598 |
-
|
| 599 |
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
| 600 |
-
uploaded_proposal_list = get_uploaded_proposal_list(uploaded_proposals)
|
| 601 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
|
|
|
|
|
|
| 602 |
|
| 603 |
output_data_upload = html.Div("No action taken yet.", style={"wordWrap": "break-word"})
|
| 604 |
|
| 605 |
-
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
|
| 619 |
-
shredded_documents[shredded_docx_name] = shredded_docx_bytes
|
| 620 |
-
logging.info(f"Shredded docx saved: {shredded_docx_name}")
|
| 621 |
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
|
|
|
|
|
|
| 636 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
| 637 |
-
|
| 638 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
elif triggered_id == 'board-action-btn':
|
| 648 |
-
result, _, _ = process_document('board', selected_filename, chat_input)
|
| 649 |
-
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
| 650 |
-
elif triggered_id == 'loe-action-btn':
|
| 651 |
-
result, _, _ = process_document('loe', selected_filename, chat_input)
|
| 652 |
-
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
| 653 |
-
else:
|
| 654 |
-
result = "Action not implemented yet."
|
| 655 |
-
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
| 656 |
|
| 657 |
-
|
| 658 |
-
sel_gen =
|
| 659 |
if not sel_gen or sel_gen not in generated_documents:
|
| 660 |
output_data_upload = html.Div("No generated document selected.", style={"wordWrap": "break-word"})
|
| 661 |
else:
|
|
@@ -672,22 +667,27 @@ def master_callback(
|
|
| 672 |
html.Div(download_link, style={"marginBottom": "15px"}),
|
| 673 |
html.Div("Preview not available for docx. Download to view.", style={"wordWrap": "break-word"})
|
| 674 |
])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 675 |
|
| 676 |
-
|
| 677 |
output_data_upload = html.Div("Upload/Delete completed.", style={"wordWrap": "break-word"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 678 |
|
| 679 |
return (
|
| 680 |
-
|
| 681 |
-
doc_options,
|
| 682 |
-
doc_value,
|
| 683 |
-
proposal_options,
|
| 684 |
-
proposal_value,
|
| 685 |
-
uploaded_proposal_list,
|
| 686 |
-
generated_doc_list,
|
| 687 |
-
generated_doc_options,
|
| 688 |
-
generated_doc_value,
|
| 689 |
shredded_doc_list_items,
|
| 690 |
-
|
| 691 |
)
|
| 692 |
|
| 693 |
if __name__ == '__main__':
|
|
|
|
| 2 |
import base64
|
| 3 |
import io
|
| 4 |
import dash
|
| 5 |
+
from dash import dcc, html, Input, Output, State, callback_context, MATCH, ALL
|
| 6 |
import dash_bootstrap_components as dbc
|
| 7 |
import pandas as pd
|
| 8 |
import logging
|
|
|
|
| 153 |
if action == 'shred':
|
| 154 |
if not doc_content:
|
| 155 |
logging.warning("No uploaded document found for shredding.")
|
| 156 |
+
return "No document uploaded.", None, None, None
|
| 157 |
prompt = (
|
| 158 |
"Analyze the following RFP/PWS/SOW/RFI and generate a requirements spreadsheet. "
|
| 159 |
"Identify requirements by action words like 'shall', 'will', 'perform', etc. Also analye the document and put a column for win theme for each requirement identified. Organize by PWS section and requirement. "
|
|
|
|
| 184 |
t = Thread(target=thread_shred)
|
| 185 |
t.start()
|
| 186 |
t.join()
|
| 187 |
+
# Add the shredded docx to uploaded_documents as a new doc
|
| 188 |
+
if result_holder["docx_bytes"] and result_holder["docx_name"]:
|
| 189 |
+
docx_name = result_holder["docx_name"]
|
| 190 |
+
try:
|
| 191 |
+
# We'll store the text as the plain shredded text (not binary docx) in uploaded_documents
|
| 192 |
+
uploaded_documents[docx_name] = result_holder["text"]
|
| 193 |
+
except Exception as e:
|
| 194 |
+
logging.error(f"Error adding shredded docx to uploaded_documents: {e}")
|
| 195 |
+
return result_holder["text"], result_holder["docx_bytes"], result_holder["docx_name"], result_holder["text"]
|
| 196 |
|
| 197 |
elif action == 'generate':
|
| 198 |
if not shredded_document:
|
| 199 |
logging.warning("No shredded document found when generating response.")
|
| 200 |
+
return "Shredded document not available.", None, None, None
|
| 201 |
prompt = (
|
| 202 |
"Create a highly detailed proposal response based on the following PWS requirements. "
|
| 203 |
"Be compliant and compelling. Focus on describing the approach, steps, workflow, people, processes, and technology. "
|
|
|
|
| 228 |
t = Thread(target=thread_generate)
|
| 229 |
t.start()
|
| 230 |
t.join()
|
| 231 |
+
return result_holder["text"], result_holder["docx_bytes"], result_holder["docx_name"], result_holder["text"]
|
| 232 |
|
| 233 |
elif action == 'proposal':
|
| 234 |
if not doc_content:
|
| 235 |
logging.warning("No RFP/SOW/PWS/RFI document selected for proposal action.")
|
| 236 |
+
return "No RFP/SOW/PWS/RFI document selected.", None, None, None
|
| 237 |
rfp_filename = selected_filename
|
| 238 |
rfp_fileid = uploaded_documents_fileid.get(selected_filename)
|
| 239 |
prompt = (
|
|
|
|
| 263 |
t = Thread(target=thread_proposal)
|
| 264 |
t.start()
|
| 265 |
t.join()
|
| 266 |
+
return result_holder["text"], result_holder["docx_bytes"], result_holder["docx_name"], result_holder["text"]
|
| 267 |
|
| 268 |
elif action == 'compliance':
|
| 269 |
+
return "Compliance checking not implemented yet.", None, None, None
|
| 270 |
elif action == 'recover':
|
| 271 |
+
return "Recovery not implemented yet.", None, None, None
|
| 272 |
elif action == 'board':
|
| 273 |
+
return "Virtual board not implemented yet.", None, None, None
|
| 274 |
elif action == 'loe':
|
| 275 |
+
return "LOE estimation not implemented yet.", None, None, None
|
| 276 |
+
return "Action not implemented yet.", None, None, None
|
| 277 |
|
| 278 |
def get_uploaded_doc_list(docdict):
|
| 279 |
if not docdict:
|
|
|
|
| 337 |
return dbc.ListGroup(doc_list, flush=True)
|
| 338 |
|
| 339 |
app.layout = dbc.Container([
|
| 340 |
+
dcc.Store(id='shred-store', data={'text': None, 'docx_bytes': None, 'docx_name': None}),
|
| 341 |
+
dcc.Store(id='proposal-store', data={'text': None, 'docx_bytes': None, 'docx_name': None}),
|
| 342 |
dbc.Row([
|
| 343 |
dbc.Col([
|
| 344 |
dbc.Card([
|
|
|
|
| 451 |
], fluid=True)
|
| 452 |
|
| 453 |
@app.callback(
|
| 454 |
+
Output('shred-store', 'data'),
|
| 455 |
+
Output('proposal-store', 'data'),
|
| 456 |
+
Output('output-data-upload', 'children'),
|
| 457 |
Output('uploaded-doc-list', 'children'),
|
| 458 |
Output('select-document-dropdown', 'options'),
|
| 459 |
Output('select-document-dropdown', 'value'),
|
| 460 |
+
Output('shredded-doc-list', 'children'),
|
|
|
|
|
|
|
| 461 |
Output('generated-doc-list', 'children'),
|
| 462 |
Output('select-generated-dropdown', 'options'),
|
| 463 |
Output('select-generated-dropdown', 'value'),
|
|
|
|
|
|
|
| 464 |
[
|
| 465 |
+
Input('shred-action-btn', 'n_clicks'),
|
| 466 |
+
Input('proposal-action-btn', 'n_clicks'),
|
| 467 |
Input('upload-document', 'contents'),
|
| 468 |
State('upload-document', 'filename'),
|
| 469 |
+
Input({'type': 'delete-doc-btn', 'index': ALL, 'group': 'rfp'}, 'n_clicks'),
|
| 470 |
State('select-document-dropdown', 'value'),
|
| 471 |
Input('upload-proposal', 'contents'),
|
| 472 |
State('upload-proposal', 'filename'),
|
| 473 |
+
Input({'type': 'delete-proposal-btn', 'index': ALL, 'group': 'proposal'}, 'n_clicks'),
|
| 474 |
State('select-proposal-dropdown', 'value'),
|
| 475 |
+
Input({'type': 'delete-generated-btn', 'index': ALL, 'group': 'generated'}, 'n_clicks'),
|
| 476 |
State('select-generated-dropdown', 'value'),
|
| 477 |
+
Input({'type': 'delete-shredded-btn', 'index': ALL, 'group': 'shredded'}, 'n_clicks'),
|
|
|
|
| 478 |
State('shredded-doc-list', 'children'),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 479 |
Input('select-generated-dropdown', 'value'),
|
| 480 |
State('chat-input', 'value'),
|
| 481 |
State('select-document-dropdown', 'value'),
|
|
|
|
| 485 |
prevent_initial_call=True
|
| 486 |
)
|
| 487 |
def master_callback(
|
| 488 |
+
shred_clicks, proposal_clicks,
|
| 489 |
rfp_content, rfp_filename, rfp_delete_clicks, selected_doc,
|
| 490 |
proposal_content, proposal_filename, proposal_delete_clicks, selected_proposal,
|
| 491 |
+
generated_delete_clicks, selected_generated,
|
| 492 |
shredded_delete_clicks, shredded_doc_children,
|
| 493 |
+
select_generated_value,
|
|
|
|
| 494 |
chat_input, selected_filename, selected_proposal_dropdown, selected_generated_dropdown_state
|
| 495 |
):
|
| 496 |
ctx = callback_context
|
|
|
|
| 498 |
|
| 499 |
upload_triggered = False
|
| 500 |
|
| 501 |
+
shred_store = {'text': None, 'docx_bytes': None, 'docx_name': None}
|
| 502 |
+
proposal_store = {'text': None, 'docx_bytes': None, 'docx_name': None}
|
| 503 |
+
|
| 504 |
+
# Handle uploads and deletes
|
| 505 |
if triggered_id == 'upload-document' and rfp_content is not None and rfp_filename:
|
| 506 |
content_type, content_string = rfp_content.split(',')
|
| 507 |
decoded = base64.b64decode(content_string)
|
|
|
|
| 534 |
logging.error(f"Failed to decode uploaded proposal: {proposal_filename}")
|
| 535 |
upload_triggered = True
|
| 536 |
|
| 537 |
+
if triggered_id and isinstance(ctx.inputs_list[4], list):
|
| 538 |
for i, n_click in enumerate(rfp_delete_clicks):
|
| 539 |
if n_click:
|
| 540 |
+
btn_id = ctx.inputs_list[4][i]['id']
|
| 541 |
del_filename = btn_id['index']
|
| 542 |
if del_filename in uploaded_documents:
|
| 543 |
del uploaded_documents[del_filename]
|
|
|
|
| 553 |
upload_triggered = True
|
| 554 |
break
|
| 555 |
|
| 556 |
+
if triggered_id and isinstance(ctx.inputs_list[8], list):
|
| 557 |
for i, n_click in enumerate(proposal_delete_clicks):
|
| 558 |
if n_click:
|
| 559 |
+
btn_id = ctx.inputs_list[8][i]['id']
|
| 560 |
del_filename = btn_id['index']
|
| 561 |
if del_filename in uploaded_proposals:
|
| 562 |
del uploaded_proposals[del_filename]
|
|
|
|
| 598 |
|
| 599 |
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
| 600 |
doc_value = selected_doc if selected_doc in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 601 |
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
|
|
|
| 602 |
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
|
|
|
| 603 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
| 604 |
+
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
| 605 |
+
generated_doc_value = select_generated_value if select_generated_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
| 606 |
|
| 607 |
output_data_upload = html.Div("No action taken yet.", style={"wordWrap": "break-word"})
|
| 608 |
|
| 609 |
+
if triggered_id == 'shred-action-btn':
|
| 610 |
+
output_data_upload = dcc.Loading(type="default", children=html.Div("Shredding document...", style={"wordWrap": "break-word"}))
|
| 611 |
+
shred_text, shredded_docx_bytes, shredded_docx_name, shredded_text = process_document('shred', selected_filename, chat_input)
|
| 612 |
+
shred_store = {'text': shred_text, 'docx_bytes': shredded_docx_bytes, 'docx_name': shredded_docx_name}
|
| 613 |
+
|
| 614 |
+
if shredded_docx_bytes and shredded_docx_name:
|
| 615 |
+
shredded_documents[shredded_docx_name] = shredded_docx_bytes
|
| 616 |
+
logging.info(f"Shredded docx saved: {shredded_docx_name}")
|
| 617 |
+
# Add shredded docx to uploaded_documents as text so it appears as selectable
|
| 618 |
+
if shredded_docx_name not in uploaded_documents:
|
| 619 |
+
uploaded_documents[shredded_docx_name] = shredded_text
|
| 620 |
+
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
| 621 |
+
doc_value = shredded_docx_name
|
| 622 |
+
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
|
|
|
|
|
|
| 623 |
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
| 624 |
+
output_data_upload = dcc.Markdown(shred_text, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 625 |
+
|
| 626 |
+
return (
|
| 627 |
+
shred_store, proposal_store, output_data_upload,
|
| 628 |
+
uploaded_doc_list, doc_options, doc_value,
|
| 629 |
+
shredded_doc_list_items,
|
| 630 |
+
generated_doc_list, generated_doc_options, generated_doc_value
|
| 631 |
+
)
|
| 632 |
+
|
| 633 |
+
if triggered_id == 'proposal-action-btn':
|
| 634 |
+
output_data_upload = dcc.Loading(type="default", children=html.Div("Generating proposal...", style={"wordWrap": "break-word"}))
|
| 635 |
+
proposal_text, proposal_docx_bytes, proposal_docx_name, proposal_text_preview = process_document('proposal', selected_filename, chat_input)
|
| 636 |
+
proposal_store = {'text': proposal_text, 'docx_bytes': proposal_docx_bytes, 'docx_name': proposal_docx_name}
|
| 637 |
+
new_generated_doc_value = generated_doc_value
|
| 638 |
+
if proposal_docx_bytes and proposal_docx_name:
|
| 639 |
+
generated_documents[proposal_docx_name] = proposal_docx_bytes
|
| 640 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
| 641 |
+
new_generated_doc_value = proposal_docx_name
|
| 642 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
| 643 |
+
logging.info(f"Generated proposal docx saved: {proposal_docx_name}")
|
| 644 |
+
output_data_upload = dcc.Markdown(proposal_text, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 645 |
+
return (
|
| 646 |
+
shred_store, proposal_store, output_data_upload,
|
| 647 |
+
uploaded_doc_list, doc_options, doc_value,
|
| 648 |
+
shredded_doc_list_items,
|
| 649 |
+
generated_doc_list, generated_doc_options, new_generated_doc_value
|
| 650 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 651 |
|
| 652 |
+
if triggered_id == 'select-generated-dropdown':
|
| 653 |
+
sel_gen = select_generated_value
|
| 654 |
if not sel_gen or sel_gen not in generated_documents:
|
| 655 |
output_data_upload = html.Div("No generated document selected.", style={"wordWrap": "break-word"})
|
| 656 |
else:
|
|
|
|
| 667 |
html.Div(download_link, style={"marginBottom": "15px"}),
|
| 668 |
html.Div("Preview not available for docx. Download to view.", style={"wordWrap": "break-word"})
|
| 669 |
])
|
| 670 |
+
return (
|
| 671 |
+
shred_store, proposal_store, output_data_upload,
|
| 672 |
+
uploaded_doc_list, doc_options, doc_value,
|
| 673 |
+
shredded_doc_list_items,
|
| 674 |
+
generated_doc_list, generated_doc_options, generated_doc_value
|
| 675 |
+
)
|
| 676 |
|
| 677 |
+
if upload_triggered:
|
| 678 |
output_data_upload = html.Div("Upload/Delete completed.", style={"wordWrap": "break-word"})
|
| 679 |
+
return (
|
| 680 |
+
shred_store, proposal_store, output_data_upload,
|
| 681 |
+
uploaded_doc_list, doc_options, doc_value,
|
| 682 |
+
shredded_doc_list_items,
|
| 683 |
+
generated_doc_list, generated_doc_options, generated_doc_value
|
| 684 |
+
)
|
| 685 |
|
| 686 |
return (
|
| 687 |
+
shred_store, proposal_store, output_data_upload,
|
| 688 |
+
uploaded_doc_list, doc_options, doc_value,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 689 |
shredded_doc_list_items,
|
| 690 |
+
generated_doc_list, generated_doc_options, generated_doc_value
|
| 691 |
)
|
| 692 |
|
| 693 |
if __name__ == '__main__':
|