Spaces:
Paused
Paused
Update app.py via AI Editor
Browse files
app.py
CHANGED
@@ -336,28 +336,49 @@ app.layout = dbc.Container([
|
|
336 |
Output('generated-doc-list', 'children'),
|
337 |
Output('select-generated-dropdown', 'options'),
|
338 |
Output('select-generated-dropdown', 'value'),
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
350 |
prevent_initial_call=True
|
351 |
)
|
352 |
-
def
|
353 |
rfp_content, rfp_filename, rfp_delete_clicks, selected_doc,
|
354 |
proposal_content, proposal_filename, proposal_delete_clicks, selected_proposal,
|
355 |
-
generated_delete_clicks, selected_generated, generated_options
|
|
|
|
|
|
|
356 |
):
|
357 |
ctx = callback_context
|
358 |
-
|
359 |
|
360 |
-
|
|
|
|
|
|
|
|
|
361 |
content_type, content_string = rfp_content.split(',')
|
362 |
decoded = base64.b64decode(content_string)
|
363 |
text = decode_document(decoded)
|
@@ -366,8 +387,10 @@ def update_uploaded_docs(
|
|
366 |
logging.info(f"Document uploaded: {rfp_filename}")
|
367 |
else:
|
368 |
logging.error(f"Failed to decode uploaded document: {rfp_filename}")
|
|
|
369 |
|
370 |
-
|
|
|
371 |
content_type, content_string = proposal_content.split(',')
|
372 |
decoded = base64.b64decode(content_string)
|
373 |
text = decode_document(decoded)
|
@@ -376,8 +399,10 @@ def update_uploaded_docs(
|
|
376 |
logging.info(f"Proposal uploaded: {proposal_filename}")
|
377 |
else:
|
378 |
logging.error(f"Failed to decode uploaded proposal: {proposal_filename}")
|
|
|
379 |
|
380 |
-
|
|
|
381 |
for i, n_click in enumerate(rfp_delete_clicks):
|
382 |
if n_click:
|
383 |
btn_id = ctx.inputs_list[2][i]['id']
|
@@ -387,8 +412,11 @@ def update_uploaded_docs(
|
|
387 |
logging.info(f"Document deleted: {del_filename}")
|
388 |
if selected_doc == del_filename:
|
389 |
selected_doc = next(iter(uploaded_documents), None)
|
|
|
390 |
break
|
391 |
-
|
|
|
|
|
392 |
for i, n_click in enumerate(proposal_delete_clicks):
|
393 |
if n_click:
|
394 |
btn_id = ctx.inputs_list[6][i]['id']
|
@@ -398,8 +426,11 @@ def update_uploaded_docs(
|
|
398 |
logging.info(f"Proposal deleted: {del_filename}")
|
399 |
if selected_proposal == del_filename:
|
400 |
selected_proposal = next(iter(uploaded_proposals), None)
|
|
|
401 |
break
|
402 |
-
|
|
|
|
|
403 |
for i, n_click in enumerate(generated_delete_clicks):
|
404 |
if n_click:
|
405 |
btn_id = ctx.inputs_list[10][i]['id']
|
@@ -409,6 +440,7 @@ def update_uploaded_docs(
|
|
409 |
logging.info(f"Generated doc deleted: {del_filename}")
|
410 |
if selected_generated == del_filename:
|
411 |
selected_generated = next(iter(generated_documents), None)
|
|
|
412 |
break
|
413 |
|
414 |
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
@@ -417,60 +449,25 @@ def update_uploaded_docs(
|
|
417 |
proposal_value = selected_proposal if selected_proposal in uploaded_proposals else (next(iter(uploaded_proposals), None) if uploaded_proposals else None)
|
418 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
419 |
generated_doc_value = selected_generated if selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
420 |
-
return (
|
421 |
-
get_uploaded_doc_list(uploaded_documents),
|
422 |
-
doc_options,
|
423 |
-
doc_value,
|
424 |
-
proposal_options,
|
425 |
-
proposal_value,
|
426 |
-
get_uploaded_proposal_list(uploaded_proposals),
|
427 |
-
get_generated_doc_list(generated_documents),
|
428 |
-
generated_doc_options,
|
429 |
-
generated_doc_value
|
430 |
-
)
|
431 |
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
Output('select-generated-dropdown', 'options'),
|
436 |
-
Output('select-generated-dropdown', 'value'),
|
437 |
-
[
|
438 |
-
Input('shred-action-btn', 'n_clicks'),
|
439 |
-
Input('generate-action-btn', 'n_clicks'),
|
440 |
-
Input('compliance-action-btn', 'n_clicks'),
|
441 |
-
Input('recover-action-btn', 'n_clicks'),
|
442 |
-
Input('board-action-btn', 'n_clicks'),
|
443 |
-
Input('loe-action-btn', 'n_clicks'),
|
444 |
-
Input('select-generated-dropdown', 'value'),
|
445 |
-
],
|
446 |
-
State('chat-input', 'value'),
|
447 |
-
State('select-document-dropdown', 'value'),
|
448 |
-
State('select-proposal-dropdown', 'value'),
|
449 |
-
State('select-generated-dropdown', 'value'),
|
450 |
-
prevent_initial_call=True
|
451 |
-
)
|
452 |
-
def handle_all_actions(
|
453 |
-
shred_clicks, generate_clicks, compliance_clicks, recover_clicks, board_clicks, loe_clicks, selected_generated_dropdown,
|
454 |
-
chat_input, selected_filename, selected_proposal, selected_generated
|
455 |
-
):
|
456 |
-
ctx = callback_context
|
457 |
-
if not ctx.triggered:
|
458 |
-
logging.info("No action triggered yet.")
|
459 |
-
return html.Div("No action taken yet.", style={"wordWrap": "break-word"}), get_generated_doc_list(generated_documents), [{'label': fn, 'value': fn} for fn in generated_documents.keys()], selected_generated
|
460 |
|
461 |
-
|
|
|
|
|
|
|
462 |
'shred-action-btn', 'generate-action-btn', 'compliance-action-btn',
|
463 |
'recover-action-btn', 'board-action-btn', 'loe-action-btn'
|
464 |
]
|
465 |
-
triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]
|
466 |
-
logging.info(f"Trigger: {triggered_id}")
|
467 |
|
468 |
-
#
|
469 |
-
if triggered_id in
|
470 |
result = ""
|
471 |
generated_docx_bytes = None
|
472 |
generated_docx_name = None
|
473 |
-
new_selected_generated =
|
474 |
|
475 |
if triggered_id == 'shred-action-btn':
|
476 |
result, generated_docx_bytes, generated_docx_name = process_document('shred', selected_filename, chat_input)
|
@@ -492,31 +489,51 @@ def handle_all_actions(
|
|
492 |
result = "Action not implemented yet."
|
493 |
|
494 |
if isinstance(result, str) and result.strip().startswith("Error"):
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
|
|
|
|
|
|
|
|
|
|
499 |
|
500 |
-
#
|
501 |
-
|
502 |
sel_gen = selected_generated_dropdown
|
503 |
if not sel_gen or sel_gen not in generated_documents:
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
html.Div(
|
516 |
-
|
517 |
-
|
|
|
|
|
|
|
|
|
518 |
|
519 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
|
521 |
if __name__ == '__main__':
|
522 |
print("Starting the Dash application...")
|
|
|
336 |
Output('generated-doc-list', 'children'),
|
337 |
Output('select-generated-dropdown', 'options'),
|
338 |
Output('select-generated-dropdown', 'value'),
|
339 |
+
Output('output-data-upload', 'children'),
|
340 |
+
[
|
341 |
+
Input('upload-document', 'contents'),
|
342 |
+
State('upload-document', 'filename'),
|
343 |
+
Input({'type': 'delete-doc-btn', 'index': dash.ALL, 'group': 'rfp'}, 'n_clicks'),
|
344 |
+
State('select-document-dropdown', 'value'),
|
345 |
+
Input('upload-proposal', 'contents'),
|
346 |
+
State('upload-proposal', 'filename'),
|
347 |
+
Input({'type': 'delete-proposal-btn', 'index': dash.ALL, 'group': 'proposal'}, 'n_clicks'),
|
348 |
+
State('select-proposal-dropdown', 'value'),
|
349 |
+
Input({'type': 'delete-generated-btn', 'index': dash.ALL, 'group': 'generated'}, 'n_clicks'),
|
350 |
+
State('select-generated-dropdown', 'value'),
|
351 |
+
State('select-generated-dropdown', 'options'),
|
352 |
+
Input('shred-action-btn', 'n_clicks'),
|
353 |
+
Input('generate-action-btn', 'n_clicks'),
|
354 |
+
Input('compliance-action-btn', 'n_clicks'),
|
355 |
+
Input('recover-action-btn', 'n_clicks'),
|
356 |
+
Input('board-action-btn', 'n_clicks'),
|
357 |
+
Input('loe-action-btn', 'n_clicks'),
|
358 |
+
Input('select-generated-dropdown', 'value'),
|
359 |
+
State('chat-input', 'value'),
|
360 |
+
State('select-document-dropdown', 'value'),
|
361 |
+
State('select-proposal-dropdown', 'value'),
|
362 |
+
State('select-generated-dropdown', 'value'),
|
363 |
+
],
|
364 |
prevent_initial_call=True
|
365 |
)
|
366 |
+
def master_callback(
|
367 |
rfp_content, rfp_filename, rfp_delete_clicks, selected_doc,
|
368 |
proposal_content, proposal_filename, proposal_delete_clicks, selected_proposal,
|
369 |
+
generated_delete_clicks, selected_generated, generated_options,
|
370 |
+
shred_clicks, generate_clicks, compliance_clicks, recover_clicks, board_clicks, loe_clicks,
|
371 |
+
selected_generated_dropdown,
|
372 |
+
chat_input, selected_filename, selected_proposal_dropdown, selected_generated_dropdown_state
|
373 |
):
|
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)
|
384 |
text = decode_document(decoded)
|
|
|
387 |
logging.info(f"Document uploaded: {rfp_filename}")
|
388 |
else:
|
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)
|
396 |
text = decode_document(decoded)
|
|
|
399 |
logging.info(f"Proposal uploaded: {proposal_filename}")
|
400 |
else:
|
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:
|
408 |
btn_id = ctx.inputs_list[2][i]['id']
|
|
|
412 |
logging.info(f"Document deleted: {del_filename}")
|
413 |
if selected_doc == del_filename:
|
414 |
selected_doc = next(iter(uploaded_documents), None)
|
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:
|
422 |
btn_id = ctx.inputs_list[6][i]['id']
|
|
|
426 |
logging.info(f"Proposal deleted: {del_filename}")
|
427 |
if selected_proposal == del_filename:
|
428 |
selected_proposal = next(iter(uploaded_proposals), None)
|
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:
|
436 |
btn_id = ctx.inputs_list[10][i]['id']
|
|
|
440 |
logging.info(f"Generated doc deleted: {del_filename}")
|
441 |
if selected_generated == del_filename:
|
442 |
selected_generated = next(iter(generated_documents), None)
|
443 |
+
upload_triggered = True
|
444 |
break
|
445 |
|
446 |
doc_options = [{'label': fn, 'value': fn} for fn in uploaded_documents.keys()]
|
|
|
449 |
proposal_value = selected_proposal if selected_proposal in uploaded_proposals else (next(iter(uploaded_proposals), None) if uploaded_proposals else None)
|
450 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
451 |
generated_doc_value = selected_generated if selected_generated in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
452 |
|
453 |
+
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
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 = [
|
461 |
'shred-action-btn', 'generate-action-btn', 'compliance-action-btn',
|
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
|
469 |
generated_docx_name = None
|
470 |
+
new_selected_generated = generated_doc_value
|
471 |
|
472 |
if triggered_id == 'shred-action-btn':
|
473 |
result, generated_docx_bytes, generated_docx_name = process_document('shred', selected_filename, chat_input)
|
|
|
489 |
result = "Action not implemented yet."
|
490 |
|
491 |
if isinstance(result, str) and result.strip().startswith("Error"):
|
492 |
+
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
493 |
+
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):
|
494 |
+
output_data_upload = html.Div(result, style={"wordWrap": "break-word"})
|
495 |
+
else:
|
496 |
+
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
497 |
+
|
498 |
+
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
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:
|
506 |
+
output_data_upload = html.Div("No generated document selected.", style={"wordWrap": "break-word"})
|
507 |
+
else:
|
508 |
+
docx_bytes = generated_documents[sel_gen]
|
509 |
+
b64 = base64.b64encode(docx_bytes).decode('utf-8')
|
510 |
+
download_link = html.A(
|
511 |
+
f"Download {sel_gen}",
|
512 |
+
href=f"data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,{b64}",
|
513 |
+
download=sel_gen,
|
514 |
+
target="_blank",
|
515 |
+
style={"wordWrap": "break-word"}
|
516 |
+
)
|
517 |
+
output_data_upload = html.Div([
|
518 |
+
html.Div(download_link, style={"marginBottom": "15px"}),
|
519 |
+
html.Div("Preview not available for docx. Download to view.", style={"wordWrap": "break-word"})
|
520 |
+
])
|
521 |
+
|
522 |
+
elif upload_triggered:
|
523 |
+
output_data_upload = html.Div("Upload/Delete completed.", style={"wordWrap": "break-word"})
|
524 |
|
525 |
+
return (
|
526 |
+
uploaded_doc_list,
|
527 |
+
doc_options,
|
528 |
+
doc_value,
|
529 |
+
proposal_options,
|
530 |
+
proposal_value,
|
531 |
+
uploaded_proposal_list,
|
532 |
+
generated_doc_list,
|
533 |
+
generated_doc_options,
|
534 |
+
generated_doc_value,
|
535 |
+
output_data_upload
|
536 |
+
)
|
537 |
|
538 |
if __name__ == '__main__':
|
539 |
print("Starting the Dash application...")
|