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":
|