Spaces:
Paused
Paused
Update app.py via AI Editor
Browse files
app.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
|
2 |
import base64
|
3 |
import io
|
4 |
import dash
|
@@ -138,7 +138,7 @@ def process_document(action, selected_filename=None, chat_input=None):
|
|
138 |
|
139 |
doc_content = None
|
140 |
doc_fileid = None
|
141 |
-
if action in ["shred", "
|
142 |
if selected_filename and selected_filename in uploaded_documents:
|
143 |
doc_content = uploaded_documents[selected_filename]
|
144 |
doc_fileid = uploaded_documents_fileid.get(selected_filename)
|
@@ -189,42 +189,6 @@ def process_document(action, selected_filename=None, chat_input=None):
|
|
189 |
uploaded_documents[result_holder["docx_name"]] = result_holder["text"]
|
190 |
return result_holder["text"], None, result_holder["docx_name"], result_holder["text"]
|
191 |
|
192 |
-
elif action == 'generate':
|
193 |
-
if not shredded_document:
|
194 |
-
logging.warning("No shredded document found when generating response.")
|
195 |
-
return "Shredded document not available.", None, None, None
|
196 |
-
prompt = (
|
197 |
-
"Create a highly detailed proposal response based on the following PWS requirements. "
|
198 |
-
"Be compliant and compelling. Focus on describing the approach, steps, workflow, people, processes, and technology. "
|
199 |
-
"Refer to research that validates the approach and cite sources with measurable outcomes. Return only the proposal response in markdown and nothing else, no comments, no intro, no outro, just the proposal.\n"
|
200 |
-
)
|
201 |
-
if chat_input:
|
202 |
-
prompt += f"User additional instructions: {chat_input}\n"
|
203 |
-
prompt += f"\nFile Name: {selected_filename}\n\n{shredded_document}"
|
204 |
-
result_holder = {"text": None, "docx_name": None}
|
205 |
-
def thread_generate():
|
206 |
-
global generated_response
|
207 |
-
generated_response = ""
|
208 |
-
try:
|
209 |
-
logging.info("Starting Gemini generate_content for generation.")
|
210 |
-
result = gemini_generate_content(prompt, file_id=doc_fileid, chat_input=chat_input)
|
211 |
-
generated_response = result
|
212 |
-
logging.info("Proposal response generated successfully.")
|
213 |
-
docx_bytes = save_proposal_as_docx(result, selected_filename)
|
214 |
-
generated_docx_name = f"{os.path.splitext(selected_filename)[0]}_proposal.docx"
|
215 |
-
generated_documents[generated_docx_name] = docx_bytes
|
216 |
-
result_holder["text"] = result
|
217 |
-
result_holder["docx_name"] = generated_docx_name
|
218 |
-
except Exception as e:
|
219 |
-
generated_response = f"Error during generation: {e}"
|
220 |
-
logging.error("Error in thread_generate: %s", e)
|
221 |
-
result_holder["text"] = generated_response
|
222 |
-
generated_response = "Generating response..."
|
223 |
-
t = Thread(target=thread_generate)
|
224 |
-
t.start()
|
225 |
-
t.join()
|
226 |
-
return result_holder["text"], None, result_holder["docx_name"], result_holder["text"]
|
227 |
-
|
228 |
elif action == 'proposal':
|
229 |
if not doc_content:
|
230 |
logging.warning("No RFP/SOW/PWS/RFI document selected for proposal action.")
|
@@ -331,17 +295,23 @@ def get_generated_doc_list(docdict):
|
|
331 |
)
|
332 |
return dbc.ListGroup(doc_list, flush=True)
|
333 |
|
334 |
-
def
|
335 |
-
|
336 |
-
return
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
|
346 |
app.layout = dbc.Container([
|
347 |
dcc.Store(id='shred-store', data={'text': None, 'docx_name': None}),
|
@@ -351,6 +321,7 @@ app.layout = dbc.Container([
|
|
351 |
dbc.Card([
|
352 |
dbc.CardHeader(html.H5("RFP/SOW/PWS/RFI")),
|
353 |
dbc.CardBody([
|
|
|
354 |
html.Div(get_uploaded_doc_list(uploaded_documents), id='uploaded-doc-list'),
|
355 |
dcc.Dropdown(
|
356 |
id='select-document-dropdown',
|
@@ -377,7 +348,7 @@ app.layout = dbc.Container([
|
|
377 |
},
|
378 |
multiple=False
|
379 |
),
|
380 |
-
html.Hr(),
|
381 |
html.H6("Shredded Requirements"),
|
382 |
html.Div(get_shredded_doc_list(shredded_documents), id='shredded-doc-list')
|
383 |
])
|
@@ -386,6 +357,7 @@ app.layout = dbc.Container([
|
|
386 |
dbc.Card([
|
387 |
dbc.CardHeader(html.H5("Proposal")),
|
388 |
dbc.CardBody([
|
|
|
389 |
html.Div(get_uploaded_proposal_list(uploaded_proposals), id='uploaded-proposal-list'),
|
390 |
dcc.Dropdown(
|
391 |
id='select-proposal-dropdown',
|
@@ -418,7 +390,6 @@ app.layout = dbc.Container([
|
|
418 |
dbc.Card([
|
419 |
dbc.CardHeader(html.H5("Generated Documents")),
|
420 |
dbc.CardBody([
|
421 |
-
html.Div(get_generated_doc_list(generated_documents), id='generated-doc-list'),
|
422 |
dcc.Dropdown(
|
423 |
id='select-generated-dropdown',
|
424 |
options=[{'label': fn, 'value': fn} for fn in generated_documents.keys()],
|
@@ -426,6 +397,9 @@ app.layout = dbc.Container([
|
|
426 |
value=next(iter(generated_documents), None),
|
427 |
style={"marginBottom": "10px"}
|
428 |
),
|
|
|
|
|
|
|
429 |
])
|
430 |
], className="mb-3")
|
431 |
], style={'minWidth': '260px', 'width':'30vw','maxWidth':'30vw'}, width=3),
|
@@ -468,6 +442,7 @@ app.layout = dbc.Container([
|
|
468 |
Output('generated-doc-list', 'children'),
|
469 |
Output('select-generated-dropdown', 'options'),
|
470 |
Output('select-generated-dropdown', 'value'),
|
|
|
471 |
[
|
472 |
Input('shred-action-btn', 'n_clicks'),
|
473 |
Input('proposal-action-btn', 'n_clicks'),
|
@@ -620,6 +595,7 @@ def master_callback(
|
|
620 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
621 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
622 |
generated_doc_value = select_generated_value if select_generated_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
|
|
623 |
|
624 |
output_data_upload = html.Div("No action taken yet.", style={"wordWrap": "break-word"})
|
625 |
|
@@ -634,11 +610,13 @@ def master_callback(
|
|
634 |
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
635 |
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
636 |
output_data_upload = dcc.Markdown(shred_text, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
|
|
637 |
return (
|
638 |
shred_store, proposal_store, output_data_upload,
|
639 |
uploaded_doc_list, doc_options, doc_value,
|
640 |
shredded_doc_list_items,
|
641 |
-
generated_doc_list, generated_doc_options, generated_doc_value
|
|
|
642 |
)
|
643 |
|
644 |
if triggered_id == 'proposal-action-btn':
|
@@ -650,58 +628,51 @@ def master_callback(
|
|
650 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
651 |
new_generated_doc_value = proposal_docx_name if proposal_docx_name in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
652 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
|
|
653 |
logging.info(f"Generated proposal docx saved: {proposal_docx_name}")
|
|
|
|
|
654 |
output_data_upload = dcc.Markdown(proposal_text, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
655 |
return (
|
656 |
shred_store, proposal_store, output_data_upload,
|
657 |
uploaded_doc_list, doc_options, doc_value,
|
658 |
shredded_doc_list_items,
|
659 |
-
generated_doc_list, generated_doc_options, new_generated_doc_value
|
|
|
660 |
)
|
661 |
|
662 |
if triggered_id == 'select-generated-dropdown':
|
663 |
-
|
664 |
-
if not sel_gen or sel_gen not in generated_documents:
|
665 |
-
output_data_upload = html.Div("No generated document selected.", style={"wordWrap": "break-word"})
|
666 |
-
else:
|
667 |
-
docx_bytes = generated_documents[sel_gen]
|
668 |
-
b64 = base64.b64encode(docx_bytes).decode('utf-8')
|
669 |
-
download_link = html.A(
|
670 |
-
f"Download {sel_gen}",
|
671 |
-
href=f"data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,{b64}",
|
672 |
-
download=sel_gen,
|
673 |
-
target="_blank",
|
674 |
-
style={"wordWrap": "break-word"}
|
675 |
-
)
|
676 |
-
output_data_upload = html.Div([
|
677 |
-
html.Div(download_link, style={"marginBottom": "15px"}),
|
678 |
-
html.Div("Preview not available for docx. Download to view.", style={"wordWrap": "break-word"})
|
679 |
-
])
|
680 |
return (
|
681 |
shred_store, proposal_store, output_data_upload,
|
682 |
uploaded_doc_list, doc_options, doc_value,
|
683 |
shredded_doc_list_items,
|
684 |
-
generated_doc_list, generated_doc_options, generated_doc_value
|
|
|
685 |
)
|
686 |
|
687 |
if upload_triggered:
|
688 |
doc_value = doc_value if doc_value in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
689 |
generated_doc_value = generated_doc_value if generated_doc_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
|
|
690 |
output_data_upload = html.Div("Upload/Delete completed.", style={"wordWrap": "break-word"})
|
691 |
return (
|
692 |
shred_store, proposal_store, output_data_upload,
|
693 |
uploaded_doc_list, doc_options, doc_value,
|
694 |
shredded_doc_list_items,
|
695 |
-
generated_doc_list, generated_doc_options, generated_doc_value
|
|
|
696 |
)
|
697 |
|
698 |
doc_value = doc_value if doc_value in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
699 |
generated_doc_value = generated_doc_value if generated_doc_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
|
|
700 |
return (
|
701 |
shred_store, proposal_store, output_data_upload,
|
702 |
uploaded_doc_list, doc_options, doc_value,
|
703 |
shredded_doc_list_items,
|
704 |
-
generated_doc_list, generated_doc_options, generated_doc_value
|
|
|
705 |
)
|
706 |
|
707 |
if __name__ == '__main__':
|
|
|
1 |
+
import os
|
2 |
import base64
|
3 |
import io
|
4 |
import dash
|
|
|
138 |
|
139 |
doc_content = None
|
140 |
doc_fileid = None
|
141 |
+
if action in ["shred", "proposal"]:
|
142 |
if selected_filename and selected_filename in uploaded_documents:
|
143 |
doc_content = uploaded_documents[selected_filename]
|
144 |
doc_fileid = uploaded_documents_fileid.get(selected_filename)
|
|
|
189 |
uploaded_documents[result_holder["docx_name"]] = result_holder["text"]
|
190 |
return result_holder["text"], None, result_holder["docx_name"], result_holder["text"]
|
191 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
elif action == 'proposal':
|
193 |
if not doc_content:
|
194 |
logging.warning("No RFP/SOW/PWS/RFI document selected for proposal action.")
|
|
|
295 |
)
|
296 |
return dbc.ListGroup(doc_list, flush=True)
|
297 |
|
298 |
+
def get_generated_rfp_download_section(selected_value):
|
299 |
+
if not selected_value or selected_value not in generated_documents:
|
300 |
+
return html.Div("No generated document selected.", style={"wordWrap": "break-word"})
|
301 |
+
docx_bytes = generated_documents[selected_value]
|
302 |
+
b64 = base64.b64encode(docx_bytes).decode('utf-8')
|
303 |
+
download_link = html.A(
|
304 |
+
f"Download {selected_value}",
|
305 |
+
href=f"data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,{b64}",
|
306 |
+
download=selected_value,
|
307 |
+
target="_blank",
|
308 |
+
style={"wordWrap": "break-word"}
|
309 |
+
)
|
310 |
+
return html.Div([
|
311 |
+
html.H6("RFP/SOW/PWS/RFI", style={"marginTop": "10px"}),
|
312 |
+
html.Div(download_link, style={"marginBottom": "15px"}),
|
313 |
+
html.Div("Preview not available for docx. Download to view.", style={"wordWrap": "break-word"})
|
314 |
+
])
|
315 |
|
316 |
app.layout = dbc.Container([
|
317 |
dcc.Store(id='shred-store', data={'text': None, 'docx_name': None}),
|
|
|
321 |
dbc.Card([
|
322 |
dbc.CardHeader(html.H5("RFP/SOW/PWS/RFI")),
|
323 |
dbc.CardBody([
|
324 |
+
html.H6("Uploaded Documents"),
|
325 |
html.Div(get_uploaded_doc_list(uploaded_documents), id='uploaded-doc-list'),
|
326 |
dcc.Dropdown(
|
327 |
id='select-document-dropdown',
|
|
|
348 |
},
|
349 |
multiple=False
|
350 |
),
|
351 |
+
html.Hr(style={"marginTop": "20px", "marginBottom": "10px"}),
|
352 |
html.H6("Shredded Requirements"),
|
353 |
html.Div(get_shredded_doc_list(shredded_documents), id='shredded-doc-list')
|
354 |
])
|
|
|
357 |
dbc.Card([
|
358 |
dbc.CardHeader(html.H5("Proposal")),
|
359 |
dbc.CardBody([
|
360 |
+
html.H6("Uploaded Documents"),
|
361 |
html.Div(get_uploaded_proposal_list(uploaded_proposals), id='uploaded-proposal-list'),
|
362 |
dcc.Dropdown(
|
363 |
id='select-proposal-dropdown',
|
|
|
390 |
dbc.Card([
|
391 |
dbc.CardHeader(html.H5("Generated Documents")),
|
392 |
dbc.CardBody([
|
|
|
393 |
dcc.Dropdown(
|
394 |
id='select-generated-dropdown',
|
395 |
options=[{'label': fn, 'value': fn} for fn in generated_documents.keys()],
|
|
|
397 |
value=next(iter(generated_documents), None),
|
398 |
style={"marginBottom": "10px"}
|
399 |
),
|
400 |
+
html.Div(id='generated-rfp-section'),
|
401 |
+
html.Hr(style={"marginTop": "20px", "marginBottom": "10px"}),
|
402 |
+
html.Div(get_generated_doc_list(generated_documents), id='generated-doc-list'),
|
403 |
])
|
404 |
], className="mb-3")
|
405 |
], style={'minWidth': '260px', 'width':'30vw','maxWidth':'30vw'}, width=3),
|
|
|
442 |
Output('generated-doc-list', 'children'),
|
443 |
Output('select-generated-dropdown', 'options'),
|
444 |
Output('select-generated-dropdown', 'value'),
|
445 |
+
Output('generated-rfp-section', 'children'),
|
446 |
[
|
447 |
Input('shred-action-btn', 'n_clicks'),
|
448 |
Input('proposal-action-btn', 'n_clicks'),
|
|
|
595 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
596 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
597 |
generated_doc_value = select_generated_value if select_generated_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
598 |
+
generated_rfp_section = get_generated_rfp_download_section(generated_doc_value)
|
599 |
|
600 |
output_data_upload = html.Div("No action taken yet.", style={"wordWrap": "break-word"})
|
601 |
|
|
|
610 |
uploaded_doc_list = get_uploaded_doc_list(uploaded_documents)
|
611 |
shredded_doc_list_items = get_shredded_doc_list(shredded_documents)
|
612 |
output_data_upload = dcc.Markdown(shred_text, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
613 |
+
generated_rfp_section = get_generated_rfp_download_section(generated_doc_value)
|
614 |
return (
|
615 |
shred_store, proposal_store, output_data_upload,
|
616 |
uploaded_doc_list, doc_options, doc_value,
|
617 |
shredded_doc_list_items,
|
618 |
+
generated_doc_list, generated_doc_options, generated_doc_value,
|
619 |
+
generated_rfp_section
|
620 |
)
|
621 |
|
622 |
if triggered_id == 'proposal-action-btn':
|
|
|
628 |
generated_doc_options = [{'label': fn, 'value': fn} for fn in generated_documents.keys()]
|
629 |
new_generated_doc_value = proposal_docx_name if proposal_docx_name in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
630 |
generated_doc_list = get_generated_doc_list(generated_documents)
|
631 |
+
generated_rfp_section = get_generated_rfp_download_section(new_generated_doc_value)
|
632 |
logging.info(f"Generated proposal docx saved: {proposal_docx_name}")
|
633 |
+
else:
|
634 |
+
generated_rfp_section = get_generated_rfp_download_section(generated_doc_value)
|
635 |
output_data_upload = dcc.Markdown(proposal_text, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
636 |
return (
|
637 |
shred_store, proposal_store, output_data_upload,
|
638 |
uploaded_doc_list, doc_options, doc_value,
|
639 |
shredded_doc_list_items,
|
640 |
+
generated_doc_list, generated_doc_options, new_generated_doc_value,
|
641 |
+
generated_rfp_section
|
642 |
)
|
643 |
|
644 |
if triggered_id == 'select-generated-dropdown':
|
645 |
+
generated_rfp_section = get_generated_rfp_download_section(select_generated_value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
646 |
return (
|
647 |
shred_store, proposal_store, output_data_upload,
|
648 |
uploaded_doc_list, doc_options, doc_value,
|
649 |
shredded_doc_list_items,
|
650 |
+
generated_doc_list, generated_doc_options, generated_doc_value,
|
651 |
+
generated_rfp_section
|
652 |
)
|
653 |
|
654 |
if upload_triggered:
|
655 |
doc_value = doc_value if doc_value in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
656 |
generated_doc_value = generated_doc_value if generated_doc_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
657 |
+
generated_rfp_section = get_generated_rfp_download_section(generated_doc_value)
|
658 |
output_data_upload = html.Div("Upload/Delete completed.", style={"wordWrap": "break-word"})
|
659 |
return (
|
660 |
shred_store, proposal_store, output_data_upload,
|
661 |
uploaded_doc_list, doc_options, doc_value,
|
662 |
shredded_doc_list_items,
|
663 |
+
generated_doc_list, generated_doc_options, generated_doc_value,
|
664 |
+
generated_rfp_section
|
665 |
)
|
666 |
|
667 |
doc_value = doc_value if doc_value in uploaded_documents else (next(iter(uploaded_documents), None) if uploaded_documents else None)
|
668 |
generated_doc_value = generated_doc_value if generated_doc_value in generated_documents else (next(iter(generated_documents), None) if generated_documents else None)
|
669 |
+
generated_rfp_section = get_generated_rfp_download_section(generated_doc_value)
|
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 |
+
generated_rfp_section
|
676 |
)
|
677 |
|
678 |
if __name__ == '__main__':
|