bluenevus commited on
Commit
70571a9
·
1 Parent(s): ff68296

Update app.py via AI Editor

Browse files
Files changed (1) hide show
  1. app.py +48 -4
app.py CHANGED
@@ -160,6 +160,16 @@ def save_virtual_board_as_docx(board_text, base_filename):
160
  memf.seek(0)
161
  return memf.read()
162
 
 
 
 
 
 
 
 
 
 
 
163
  def process_document(action, selected_filename=None, chat_input=None, rfp_decoded_bytes=None, selected_proposal_filename=None):
164
  global generated_response
165
 
@@ -336,7 +346,39 @@ def process_document(action, selected_filename=None, chat_input=None, rfp_decode
336
  return result, None, None, None, None
337
 
338
  elif action == 'loe':
339
- return "LOE estimation not implemented yet.", None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  return "Action not implemented yet.", None, None, None, None
341
 
342
  def get_documents_list(docdict, shreddedict):
@@ -379,7 +421,10 @@ def get_proposals_list(proposaldict):
379
  for filename in proposaldict:
380
  file_content = proposaldict[filename]
381
  try:
382
- docx_bytes = save_proposal_as_docx(file_content, filename)
 
 
 
383
  b64 = base64.b64encode(docx_bytes).decode('utf-8')
384
  mime = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
385
  except Exception:
@@ -743,9 +788,8 @@ def master_callback(
743
  output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
744
  elif triggered_id == "loe-action-btn":
745
  action_name = "loe"
746
- selected_bytes = uploaded_documents_bytes.get(doc_value, None)
747
  result, _, _, generated_filename, generated_docx_bytes = process_document(
748
- action_name, doc_value, chat_input, selected_bytes, None
749
  )
750
  output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
751
  finally:
 
160
  memf.seek(0)
161
  return memf.read()
162
 
163
+ def save_loe_as_docx(loe_text, proposal_filename):
164
+ doc = Document()
165
+ doc.add_heading(f"Level of Effort for {proposal_filename}", 0)
166
+ for line in loe_text.split('\n'):
167
+ doc.add_paragraph(line)
168
+ memf = io.BytesIO()
169
+ doc.save(memf)
170
+ memf.seek(0)
171
+ return memf.read()
172
+
173
  def process_document(action, selected_filename=None, chat_input=None, rfp_decoded_bytes=None, selected_proposal_filename=None):
174
  global generated_response
175
 
 
346
  return result, None, None, None, None
347
 
348
  elif action == 'loe':
349
+ # LOE estimation implementation
350
+ if not selected_proposal_filename or selected_proposal_filename not in proposals:
351
+ logging.warning("No proposal document selected for LOE estimation.")
352
+ return "No proposal document selected for LOE estimation.", None, None, None, None
353
+ proposal_text = proposals[selected_proposal_filename]
354
+ proposal_base_name = os.path.splitext(selected_proposal_filename)[0]
355
+ prompt = (
356
+ "You are a federal proposal cost and level of effort estimator. "
357
+ "Analyze the following proposal response which is structured to map to a government RFP, PWS, or SOW. "
358
+ "For each PWS task or requirement referenced in the proposal, estimate the labor categories and a conservative, overestimated number of hours for each labor category required to accomplish that task. "
359
+ "Include a management reserve to ensure the estimate is not underestimated. "
360
+ "Return ONLY a markdown table (NO comments, NO intro, NO outro, NO summary) with the following columns: "
361
+ "| PWS Task Number | Brief Task Description | Labor Category | Estimated Hours (including management reserve) | "
362
+ "For each task, if more than one labor category is needed, list each category on its own row under the same task. "
363
+ "Be sure to break down by detailed task, not just high level sections. "
364
+ "Be detailed and thorough in your estimation and make sure to overestimate hours to ensure sufficient coverage. "
365
+ "If the proposal references any assumed task number or section, use it in the table. "
366
+ "Return ONLY the markdown table, no other text, no intro, no outro.\n\n"
367
+ )
368
+ if chat_input:
369
+ prompt += f"User additional instructions: {chat_input}\n"
370
+ prompt += f"\n---\nProposal Document ({selected_proposal_filename}):\n{proposal_text}\n"
371
+ result = gemini_generate_content(prompt, file_id=None, chat_input=chat_input)
372
+ if result and not result.startswith("Error"):
373
+ loe_docx_name = f"{proposal_base_name}_loe.docx"
374
+ proposals[loe_docx_name] = result
375
+ proposals_fileid[loe_docx_name] = None
376
+ docx_bytes = save_loe_as_docx(result, proposal_base_name)
377
+ logging.info(f"LOE generated and saved as {loe_docx_name}")
378
+ return result, None, None, loe_docx_name, docx_bytes
379
+ else:
380
+ return result, None, None, None, None
381
+
382
  return "Action not implemented yet.", None, None, None, None
383
 
384
  def get_documents_list(docdict, shreddedict):
 
421
  for filename in proposaldict:
422
  file_content = proposaldict[filename]
423
  try:
424
+ if filename.lower().endswith('_loe.docx'):
425
+ docx_bytes = save_loe_as_docx(file_content, filename)
426
+ else:
427
+ docx_bytes = save_proposal_as_docx(file_content, filename)
428
  b64 = base64.b64encode(docx_bytes).decode('utf-8')
429
  mime = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
430
  except Exception:
 
788
  output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
789
  elif triggered_id == "loe-action-btn":
790
  action_name = "loe"
 
791
  result, _, _, generated_filename, generated_docx_bytes = process_document(
792
+ action_name, None, chat_input, None, proposal_value
793
  )
794
  output_data_upload = dcc.Markdown(result, style={"whiteSpace": "pre-wrap", "wordWrap": "break-word"})
795
  finally: