Spaces:
Paused
Paused
Update app.py via AI Editor
Browse files
app.py
CHANGED
|
@@ -161,6 +161,7 @@ def gemini_generate_content(prompt, file_id=None, chat_input=None, file_ids=None
|
|
| 161 |
content_list.extend(files)
|
| 162 |
content_list.append("\n\n")
|
| 163 |
content_list.append(prompt)
|
|
|
|
| 164 |
model = genai.GenerativeModel(GEMINI_MODEL)
|
| 165 |
response = model.generate_content(
|
| 166 |
contents=content_list,
|
|
@@ -169,6 +170,7 @@ def gemini_generate_content(prompt, file_id=None, chat_input=None, file_ids=None
|
|
| 169 |
)
|
| 170 |
)
|
| 171 |
result = response.text if hasattr(response, "text") else str(response)
|
|
|
|
| 172 |
return result
|
| 173 |
except Exception as e:
|
| 174 |
logging.error("Error during Gemini generate_content: %s", e)
|
|
@@ -260,17 +262,16 @@ def save_loe_as_docx(loe_text, proposal_filename):
|
|
| 260 |
def process_document(sess_data, action, selected_filename=None, chat_input=None, rfp_decoded_bytes=None, selected_proposal_filename=None):
|
| 261 |
doc_content = None
|
| 262 |
doc_fileid = None
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
doc_fileid = None
|
| 274 |
|
| 275 |
if action == 'shred':
|
| 276 |
if not doc_content:
|
|
@@ -281,6 +282,7 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 281 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 282 |
prompt += f"\nFile Name: {selected_filename}\n\n"
|
| 283 |
prompt += doc_content
|
|
|
|
| 284 |
result = gemini_generate_content(prompt, file_id=doc_fileid, chat_input=chat_input)
|
| 285 |
if result and not result.startswith("Error"):
|
| 286 |
xlsx_bytes = save_markdown_as_xlsx(result, selected_filename)
|
|
@@ -292,18 +294,16 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 292 |
return result, None, None, None, None
|
| 293 |
|
| 294 |
elif action == 'compliance':
|
| 295 |
-
if not
|
| 296 |
return "No proposal document selected for compliance.", None, None, None, None
|
| 297 |
-
if not
|
| 298 |
return "No RFP/SOW/PWS/RFI document selected for compliance.", None, None, None, None
|
| 299 |
|
| 300 |
-
|
| 301 |
-
proposal_text = sess_data["proposals"][selected_proposal_filename]
|
| 302 |
-
logging.info(f"Compliance check: comparing proposal [{selected_proposal_filename}] to RFP [{selected_filename}]")
|
| 303 |
prompt = read_prompt_file('compliance')
|
| 304 |
-
prompt += f"\n---\nRFP/SOW/PWS/RFI ({selected_filename}):\n{
|
| 305 |
prompt += "---\nGenerated Proposal Document:\n"
|
| 306 |
-
prompt += f"{
|
| 307 |
result = gemini_generate_content(prompt, file_id=None, chat_input=None)
|
| 308 |
if result and not result.startswith("Error"):
|
| 309 |
xlsx_bytes = save_markdown_as_xlsx(result, selected_filename)
|
|
@@ -315,18 +315,16 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 315 |
return result, None, None, None, None
|
| 316 |
|
| 317 |
elif action == 'virtual_board':
|
| 318 |
-
if not
|
| 319 |
return "No proposal document selected for evaluation board.", None, None, None, None
|
| 320 |
-
if not
|
| 321 |
return "No RFP/SOW/PWS/RFI document selected for evaluation board.", None, None, None, None
|
| 322 |
|
| 323 |
-
|
| 324 |
-
proposal_text = sess_data["proposals"][selected_proposal_filename]
|
| 325 |
-
logging.info(f"Evaluation Board: extracting criteria from RFP [{selected_filename}], evaluating proposal [{selected_proposal_filename}]")
|
| 326 |
prompt = read_prompt_file('virtual_board')
|
| 327 |
-
prompt += f"\n---\nRFP/SOW/PWS/RFI ({selected_filename}):\n{
|
| 328 |
prompt += "---\nProposal Document:\n"
|
| 329 |
-
prompt += f"{
|
| 330 |
result = gemini_generate_content(prompt, file_id=None, chat_input=None)
|
| 331 |
if result and not result.startswith("Error"):
|
| 332 |
xlsx_bytes = save_markdown_as_xlsx(result, selected_filename)
|
|
@@ -342,7 +340,7 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 342 |
logging.warning("No RFP/SOW/PWS/RFI document selected for proposal action.")
|
| 343 |
return "No RFP/SOW/PWS/RFI document selected.", None, None, None, None
|
| 344 |
rfp_filename = selected_filename
|
| 345 |
-
rfp_fileid =
|
| 346 |
if not rfp_fileid and rfp_filename in sess_data["uploaded_documents_bytes"]:
|
| 347 |
try:
|
| 348 |
fileid = upload_to_gemini_file(sess_data["uploaded_documents_bytes"][rfp_filename], rfp_filename)
|
|
@@ -356,6 +354,7 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 356 |
if chat_input:
|
| 357 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 358 |
prompt += f"\n---\nRFP/SOW/PWS/RFI ({rfp_filename}):\n{doc_content}\n"
|
|
|
|
| 359 |
result = gemini_generate_content(prompt, file_id=rfp_fileid, chat_input=chat_input)
|
| 360 |
sess_data["generated_response"] = result
|
| 361 |
if result and not result.startswith("Error"):
|
|
@@ -368,20 +367,20 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 368 |
return result, None, None, None, None
|
| 369 |
|
| 370 |
elif action == 'recover':
|
| 371 |
-
if not
|
| 372 |
logging.error("No proposal document selected for recovery.")
|
| 373 |
return "No proposal document selected for recovery.", None, None, None, None
|
| 374 |
-
if not
|
| 375 |
logging.error("No compliance check or shredded requirements document selected for recovery.")
|
| 376 |
return "No compliance check or shredded requirements document selected for recovery.", None, None, None, None
|
| 377 |
|
| 378 |
-
findings_content =
|
| 379 |
-
proposal_text = sess_data["proposals"][selected_proposal_filename]
|
| 380 |
prompt = read_prompt_file('recover')
|
| 381 |
if chat_input:
|
| 382 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 383 |
prompt += f"\n---\nFindings and Recommendations Table ({selected_filename}):\n{findings_content}\n"
|
| 384 |
-
prompt += f"\n---\nOriginal Proposal Document ({selected_proposal_filename}):\n{
|
|
|
|
| 385 |
result = gemini_generate_content(prompt, file_id=None, chat_input=chat_input)
|
| 386 |
if result and not result.startswith("Error"):
|
| 387 |
base_name = os.path.splitext(selected_proposal_filename)[0]
|
|
@@ -396,15 +395,15 @@ def process_document(sess_data, action, selected_filename=None, chat_input=None,
|
|
| 396 |
return result, None, None, None, None
|
| 397 |
|
| 398 |
elif action == 'loe':
|
| 399 |
-
if not
|
| 400 |
logging.warning("No proposal document selected for LOE estimation.")
|
| 401 |
return "No proposal document selected for LOE estimation.", None, None, None, None
|
| 402 |
-
proposal_text = sess_data["proposals"][selected_proposal_filename]
|
| 403 |
proposal_base_name = os.path.splitext(selected_proposal_filename)[0]
|
| 404 |
prompt = read_prompt_file('loe')
|
| 405 |
if chat_input:
|
| 406 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 407 |
-
prompt += f"\n---\nProposal Document ({selected_proposal_filename}):\n{
|
|
|
|
| 408 |
result = gemini_generate_content(prompt, file_id=None, chat_input=chat_input)
|
| 409 |
if result and not result.startswith("Error"):
|
| 410 |
loe_xlsx_name = f"{proposal_base_name}_loe.xlsx"
|
|
@@ -838,20 +837,19 @@ def master_callback(
|
|
| 838 |
elif triggered_id == "compliance-action-btn":
|
| 839 |
action_name = "compliance"
|
| 840 |
result, generated_filename, generated_xlsx_bytes, _, _ = process_document(
|
| 841 |
-
sess_data, action_name, doc_value, chat_input,
|
| 842 |
)
|
| 843 |
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 844 |
elif triggered_id == "board-action-btn":
|
| 845 |
action_name = "virtual_board"
|
| 846 |
result, generated_filename, generated_xlsx_bytes, _, _ = process_document(
|
| 847 |
-
sess_data, action_name, doc_value, chat_input,
|
| 848 |
)
|
| 849 |
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 850 |
elif triggered_id == "proposal-action-btn":
|
| 851 |
action_name = "proposal"
|
| 852 |
-
selected_bytes = sess_data["uploaded_documents_bytes"].get(doc_value, None)
|
| 853 |
result, _, _, generated_filename, generated_docx_bytes = process_document(
|
| 854 |
-
sess_data, action_name, doc_value, chat_input,
|
| 855 |
)
|
| 856 |
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 857 |
elif triggered_id == "recover-action-btn":
|
|
|
|
| 161 |
content_list.extend(files)
|
| 162 |
content_list.append("\n\n")
|
| 163 |
content_list.append(prompt)
|
| 164 |
+
logging.info(f"Prompt sent to Gemini: {prompt[:500]}...") # log first 500 chars
|
| 165 |
model = genai.GenerativeModel(GEMINI_MODEL)
|
| 166 |
response = model.generate_content(
|
| 167 |
contents=content_list,
|
|
|
|
| 170 |
)
|
| 171 |
)
|
| 172 |
result = response.text if hasattr(response, "text") else str(response)
|
| 173 |
+
logging.info(f"Gemini response (first 500 chars): {str(result)[:500]}...")
|
| 174 |
return result
|
| 175 |
except Exception as e:
|
| 176 |
logging.error("Error during Gemini generate_content: %s", e)
|
|
|
|
| 262 |
def process_document(sess_data, action, selected_filename=None, chat_input=None, rfp_decoded_bytes=None, selected_proposal_filename=None):
|
| 263 |
doc_content = None
|
| 264 |
doc_fileid = None
|
| 265 |
+
proposal_content = None
|
| 266 |
+
proposal_fileid = None
|
| 267 |
+
|
| 268 |
+
# Always find document and proposal content if possible
|
| 269 |
+
if selected_filename and selected_filename in sess_data["uploaded_documents"]:
|
| 270 |
+
doc_content = sess_data["uploaded_documents"][selected_filename]
|
| 271 |
+
doc_fileid = sess_data["uploaded_documents_fileid"].get(selected_filename)
|
| 272 |
+
if selected_proposal_filename and selected_proposal_filename in sess_data["proposals"]:
|
| 273 |
+
proposal_content = sess_data["proposals"][selected_proposal_filename]
|
| 274 |
+
proposal_fileid = sess_data["proposals_fileid"].get(selected_proposal_filename)
|
|
|
|
| 275 |
|
| 276 |
if action == 'shred':
|
| 277 |
if not doc_content:
|
|
|
|
| 282 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 283 |
prompt += f"\nFile Name: {selected_filename}\n\n"
|
| 284 |
prompt += doc_content
|
| 285 |
+
logging.info(f"[SHRED] Sending document {selected_filename} to Gemini for shredding.")
|
| 286 |
result = gemini_generate_content(prompt, file_id=doc_fileid, chat_input=chat_input)
|
| 287 |
if result and not result.startswith("Error"):
|
| 288 |
xlsx_bytes = save_markdown_as_xlsx(result, selected_filename)
|
|
|
|
| 294 |
return result, None, None, None, None
|
| 295 |
|
| 296 |
elif action == 'compliance':
|
| 297 |
+
if not proposal_content:
|
| 298 |
return "No proposal document selected for compliance.", None, None, None, None
|
| 299 |
+
if not doc_content:
|
| 300 |
return "No RFP/SOW/PWS/RFI document selected for compliance.", None, None, None, None
|
| 301 |
|
| 302 |
+
logging.info(f"[COMPLIANCE] Comparing proposal [{selected_proposal_filename}] to RFP [{selected_filename}]")
|
|
|
|
|
|
|
| 303 |
prompt = read_prompt_file('compliance')
|
| 304 |
+
prompt += f"\n---\nRFP/SOW/PWS/RFI ({selected_filename}):\n{doc_content}\n"
|
| 305 |
prompt += "---\nGenerated Proposal Document:\n"
|
| 306 |
+
prompt += f"{proposal_content}\n"
|
| 307 |
result = gemini_generate_content(prompt, file_id=None, chat_input=None)
|
| 308 |
if result and not result.startswith("Error"):
|
| 309 |
xlsx_bytes = save_markdown_as_xlsx(result, selected_filename)
|
|
|
|
| 315 |
return result, None, None, None, None
|
| 316 |
|
| 317 |
elif action == 'virtual_board':
|
| 318 |
+
if not proposal_content:
|
| 319 |
return "No proposal document selected for evaluation board.", None, None, None, None
|
| 320 |
+
if not doc_content:
|
| 321 |
return "No RFP/SOW/PWS/RFI document selected for evaluation board.", None, None, None, None
|
| 322 |
|
| 323 |
+
logging.info(f"[VIRTUAL_BOARD] Evaluating proposal [{selected_proposal_filename}] against RFP [{selected_filename}]")
|
|
|
|
|
|
|
| 324 |
prompt = read_prompt_file('virtual_board')
|
| 325 |
+
prompt += f"\n---\nRFP/SOW/PWS/RFI ({selected_filename}):\n{doc_content}\n"
|
| 326 |
prompt += "---\nProposal Document:\n"
|
| 327 |
+
prompt += f"{proposal_content}\n"
|
| 328 |
result = gemini_generate_content(prompt, file_id=None, chat_input=None)
|
| 329 |
if result and not result.startswith("Error"):
|
| 330 |
xlsx_bytes = save_markdown_as_xlsx(result, selected_filename)
|
|
|
|
| 340 |
logging.warning("No RFP/SOW/PWS/RFI document selected for proposal action.")
|
| 341 |
return "No RFP/SOW/PWS/RFI document selected.", None, None, None, None
|
| 342 |
rfp_filename = selected_filename
|
| 343 |
+
rfp_fileid = doc_fileid
|
| 344 |
if not rfp_fileid and rfp_filename in sess_data["uploaded_documents_bytes"]:
|
| 345 |
try:
|
| 346 |
fileid = upload_to_gemini_file(sess_data["uploaded_documents_bytes"][rfp_filename], rfp_filename)
|
|
|
|
| 354 |
if chat_input:
|
| 355 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 356 |
prompt += f"\n---\nRFP/SOW/PWS/RFI ({rfp_filename}):\n{doc_content}\n"
|
| 357 |
+
logging.info(f"[PROPOSAL] Sending document {rfp_filename} to Gemini for proposal generation.")
|
| 358 |
result = gemini_generate_content(prompt, file_id=rfp_fileid, chat_input=chat_input)
|
| 359 |
sess_data["generated_response"] = result
|
| 360 |
if result and not result.startswith("Error"):
|
|
|
|
| 367 |
return result, None, None, None, None
|
| 368 |
|
| 369 |
elif action == 'recover':
|
| 370 |
+
if not proposal_content:
|
| 371 |
logging.error("No proposal document selected for recovery.")
|
| 372 |
return "No proposal document selected for recovery.", None, None, None, None
|
| 373 |
+
if not doc_content:
|
| 374 |
logging.error("No compliance check or shredded requirements document selected for recovery.")
|
| 375 |
return "No compliance check or shredded requirements document selected for recovery.", None, None, None, None
|
| 376 |
|
| 377 |
+
findings_content = doc_content
|
|
|
|
| 378 |
prompt = read_prompt_file('recover')
|
| 379 |
if chat_input:
|
| 380 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 381 |
prompt += f"\n---\nFindings and Recommendations Table ({selected_filename}):\n{findings_content}\n"
|
| 382 |
+
prompt += f"\n---\nOriginal Proposal Document ({selected_proposal_filename}):\n{proposal_content}\n"
|
| 383 |
+
logging.info(f"[RECOVER] Recovering proposal {selected_proposal_filename} using findings from {selected_filename}.")
|
| 384 |
result = gemini_generate_content(prompt, file_id=None, chat_input=chat_input)
|
| 385 |
if result and not result.startswith("Error"):
|
| 386 |
base_name = os.path.splitext(selected_proposal_filename)[0]
|
|
|
|
| 395 |
return result, None, None, None, None
|
| 396 |
|
| 397 |
elif action == 'loe':
|
| 398 |
+
if not proposal_content:
|
| 399 |
logging.warning("No proposal document selected for LOE estimation.")
|
| 400 |
return "No proposal document selected for LOE estimation.", None, None, None, None
|
|
|
|
| 401 |
proposal_base_name = os.path.splitext(selected_proposal_filename)[0]
|
| 402 |
prompt = read_prompt_file('loe')
|
| 403 |
if chat_input:
|
| 404 |
prompt += f"\nUser additional instructions: {chat_input}\n"
|
| 405 |
+
prompt += f"\n---\nProposal Document ({selected_proposal_filename}):\n{proposal_content}\n"
|
| 406 |
+
logging.info(f"[LOE] Calculating LOE for proposal {selected_proposal_filename}.")
|
| 407 |
result = gemini_generate_content(prompt, file_id=None, chat_input=chat_input)
|
| 408 |
if result and not result.startswith("Error"):
|
| 409 |
loe_xlsx_name = f"{proposal_base_name}_loe.xlsx"
|
|
|
|
| 837 |
elif triggered_id == "compliance-action-btn":
|
| 838 |
action_name = "compliance"
|
| 839 |
result, generated_filename, generated_xlsx_bytes, _, _ = process_document(
|
| 840 |
+
sess_data, action_name, doc_value, chat_input, None, proposal_value
|
| 841 |
)
|
| 842 |
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 843 |
elif triggered_id == "board-action-btn":
|
| 844 |
action_name = "virtual_board"
|
| 845 |
result, generated_filename, generated_xlsx_bytes, _, _ = process_document(
|
| 846 |
+
sess_data, action_name, doc_value, chat_input, None, proposal_value
|
| 847 |
)
|
| 848 |
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 849 |
elif triggered_id == "proposal-action-btn":
|
| 850 |
action_name = "proposal"
|
|
|
|
| 851 |
result, _, _, generated_filename, generated_docx_bytes = process_document(
|
| 852 |
+
sess_data, action_name, doc_value, chat_input, None, None
|
| 853 |
)
|
| 854 |
output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
|
| 855 |
elif triggered_id == "recover-action-btn":
|