脕lvaro Valenzuela Valdes commited on
Commit
f80a9d9
1 Parent(s): b3251c0

Fix false positive on questions and make Q&A generation conditional

Browse files
backend/app/services/agents.py CHANGED
@@ -95,8 +95,7 @@ async def run_full_analysis(tender: Tender, company_profile: CompanyProfile, doc
95
  f" - Propuesta de Valor Diferenciadora (por qu茅 elegirnos)\n"
96
  f" - Cronograma estimado\n"
97
  f" - Conclusi贸n Profesional\n"
98
- f"10. requirement_responses: Genera exactamente una lista de 22 pares de {{question, answer}} respondiendo a los requisitos reales y preguntas de mercado de la licitaci贸n.\n"
99
- f" Si la licitaci贸n es 'Software de Gesti贸n Municipalidad de Monte Patria', incluye preguntas sobre: integraci贸n, servidores, migraci贸n, soporte 24/7, remuneraciones, firma electr贸nica, tiempos de respuesta, usuarios ilimitados, workflow, capacitaci贸n, motor BD, ISO 27001, respaldos, reportes, etc. hasta completar las 22.\n"
100
  f"11. report_markdown: Un reporte general para consumo interno.\n"
101
  f"Responde 脷NICAMENTE con el JSON plano. No incluyas explicaciones fuera del JSON."
102
  )
 
95
  f" - Propuesta de Valor Diferenciadora (por qu茅 elegirnos)\n"
96
  f" - Cronograma estimado\n"
97
  f" - Conclusi贸n Profesional\n"
98
+ f"10. requirement_responses: " + (f"Genera exactamente {tender_details.get('metadata', {}).get('question_count', 0)} pares de {{question, answer}} basados en las preguntas reales del mercado. " if tender_details and tender_details.get('metadata', {}).get('question_count', 0) > 0 else "Genera solo 3 preguntas y respuestas basadas en requisitos hipot茅ticos/claves ya que no hay preguntas de mercado activas. ") + "\n"
 
99
  f"11. report_markdown: Un reporte general para consumo interno.\n"
100
  f"Responde 脷NICAMENTE con el JSON plano. No incluyas explicaciones fuera del JSON."
101
  )
backend/app/services/tender_detail_extractor.py CHANGED
@@ -79,10 +79,17 @@ async def extract_tender_detail_tabs(tender_code: str, qs_param: Optional[str] =
79
  result["metadata"]["has_technical_docs"] = "grvTecnico" in html or html.count("T茅cnico") > 0
80
  result["metadata"]["has_economic_docs"] = "grvEconomico" in html or html.count("Econ贸mico") > 0
81
 
82
- # Count questions/responses if mentioned
83
- questions_match = re.search(r'Preguntas.*?(\d+)', html, re.IGNORECASE)
84
  if questions_match:
85
  result["metadata"]["question_count"] = int(questions_match.group(1))
 
 
 
 
 
 
 
86
 
87
  # Extract adjudication info
88
  if "adjudic" in html.lower():
 
79
  result["metadata"]["has_technical_docs"] = "grvTecnico" in html or html.count("T茅cnico") > 0
80
  result["metadata"]["has_economic_docs"] = "grvEconomico" in html or html.count("Econ贸mico") > 0
81
 
82
+ # Count questions/responses (more specific regex for the questions tab label)
83
+ questions_match = re.search(r'id="[^"]*PreguntasLicitacion"[^>]*>.*?(\d+)', html, re.IGNORECASE)
84
  if questions_match:
85
  result["metadata"]["question_count"] = int(questions_match.group(1))
86
+ else:
87
+ # Fallback to general label if specific ID not found
88
+ questions_match = re.search(r'Preguntas y Respuestas.*?(\d+)', html, re.IGNORECASE)
89
+ if questions_match:
90
+ result["metadata"]["question_count"] = int(questions_match.group(1))
91
+ else:
92
+ result["metadata"]["question_count"] = 0
93
 
94
  # Extract adjudication info
95
  if "adjudic" in html.lower():
frontend/components/AgentAnalysis.tsx CHANGED
@@ -703,16 +703,18 @@ export default function AgentAnalysis({ tender, companyProfile, analysis, onAnal
703
  {/* Requirement Q&A Section */}
704
  {activeAnalysis.requirement_responses && activeAnalysis.requirement_responses.length > 0 && (
705
  <div className="mt-12 space-y-6">
706
- <div className="flex items-center justify-between border-b border-white/5 pb-4">
707
  <div className="flex items-center gap-3">
708
  <span className="text-2xl">馃搵</span>
709
- <h4 className="text-[10px] sm:text-[11px] font-bold uppercase tracking-widest text-purple-400">Actual Market Questions ({activeAnalysis.requirement_responses.length})</h4>
 
 
710
  </div>
711
- <div className="flex items-center gap-2 px-3 py-1 rounded-full bg-green-500/10 border border-green-500/20">
712
- <span className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
713
- <span className="text-[9px] font-bold text-green-400 uppercase tracking-tighter">Synced with Portal</span>
714
- </div>
715
- </div>
 
716
  <div className="grid gap-4 max-h-[600px] overflow-y-auto pr-4 custom-scrollbar">
717
  {activeAnalysis.requirement_responses.map((item, i) => (
718
  <div key={i} className="rounded-2xl bg-white/[0.03] border border-white/5 p-4 sm:p-6 hover:border-purple-500/30 transition-all group">
 
703
  {/* Requirement Q&A Section */}
704
  {activeAnalysis.requirement_responses && activeAnalysis.requirement_responses.length > 0 && (
705
  <div className="mt-12 space-y-6">
 
706
  <div className="flex items-center gap-3">
707
  <span className="text-2xl">馃搵</span>
708
+ <h4 className="text-[10px] sm:text-[11px] font-bold uppercase tracking-widest text-purple-400">
709
+ {activeAnalysis.requirement_responses.length > 3 ? `Actual Market Questions (${activeAnalysis.requirement_responses.length})` : "Intelligence Requirement Response"}
710
+ </h4>
711
  </div>
712
+ {activeAnalysis.requirement_responses.length > 3 && (
713
+ <div className="flex items-center gap-2 px-3 py-1 rounded-full bg-green-500/10 border border-green-500/20">
714
+ <span className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
715
+ <span className="text-[9px] font-bold text-green-400 uppercase tracking-tighter">Synced with Portal</span>
716
+ </div>
717
+ )}
718
  <div className="grid gap-4 max-h-[600px] overflow-y-auto pr-4 custom-scrollbar">
719
  {activeAnalysis.requirement_responses.map((item, i) => (
720
  <div key={i} className="rounded-2xl bg-white/[0.03] border border-white/5 p-4 sm:p-6 hover:border-purple-500/30 transition-all group">