Álvaro Valenzuela Valdes commited on
Commit
be04f48
·
1 Parent(s): a7c74bb

feat: Enhanced Compra Ágil detection and COT26 pattern matching

Browse files
backend/app/services/llm.py CHANGED
@@ -161,9 +161,9 @@ def generate_analysis(tender: Tender, company: CompanyProfile, document_text: st
161
 
162
  # Define Agent roles for separate calls
163
  agent_definitions = {
164
- "legal": "Experto Legal & Cumplimiento: Evalúa bases administrativas, multas y garantías.",
165
- "tech": "Ingeniero Técnico: Evalúa arquitectura, stack tecnológico y capacidad de ejecución.",
166
- "risk": "Estratega Comercial: Evalúa rentabilidad, competencia y riesgos de mercado."
167
  }
168
 
169
  for agent_id, role_desc in agent_definitions.items():
 
161
 
162
  # Define Agent roles for separate calls
163
  agent_definitions = {
164
+ "legal": "Experto Legal & Cumplimiento: Evalúa bases administrativas, multas y garantías. Pon especial atención a los ANEXOS de Sustentabilidad y Admisibilidad.",
165
+ "tech": "Ingeniero Técnico: Evalúa arquitectura, stack tecnológico y capacidad de ejecución. Considera si se requieren certificaciones ambientales.",
166
+ "risk": "Estratega Comercial: Evalúa rentabilidad, competencia y riesgos de mercado. Analiza el impacto de los criterios de evaluación ESG en el puntaje final."
167
  }
168
 
169
  for agent_id, role_desc in agent_definitions.items():
frontend/components/AgentAnalysis.tsx CHANGED
@@ -102,6 +102,9 @@ export default function AgentAnalysis({ tender, companyProfile, analysis, onAnal
102
  <div className="max-w-3xl">
103
  <div className="flex items-center gap-3 mb-4">
104
  <span className="rounded-full bg-purple-500/20 px-3 py-1 text-[10px] font-bold uppercase tracking-widest text-purple-300 border border-purple-500/30">Active Opportunity</span>
 
 
 
105
  <span className="text-xs text-slate-500 font-mono">{tender?.code}</span>
106
  </div>
107
  <h2 className="text-4xl font-bold text-white tracking-tight leading-tight mb-4">{tender?.name}</h2>
 
102
  <div className="max-w-3xl">
103
  <div className="flex items-center gap-3 mb-4">
104
  <span className="rounded-full bg-purple-500/20 px-3 py-1 text-[10px] font-bold uppercase tracking-widest text-purple-300 border border-purple-500/30">Active Opportunity</span>
105
+ {tender?.name.toLowerCase().includes('sustentable') || tender?.description?.toLowerCase().includes('ambiental') ? (
106
+ <span className="rounded-full bg-green-500/20 px-3 py-1 text-[10px] font-bold uppercase tracking-widest text-green-400 border border-green-500/30 animate-pulse">🌱 Sustainable / Compra Ágil</span>
107
+ ) : null}
108
  <span className="text-xs text-slate-500 font-mono">{tender?.code}</span>
109
  </div>
110
  <h2 className="text-4xl font-bold text-white tracking-tight leading-tight mb-4">{tender?.name}</h2>
frontend/components/TenderSearch.tsx CHANGED
@@ -33,6 +33,7 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
33
 
34
  const [showOnlyFollowed, setShowOnlyFollowed] = useState(forceShowFollowed);
35
  const [isLoading, setIsLoading] = useState(false);
 
36
  const itemsPerPage = 50;
37
 
38
  useEffect(() => {
@@ -92,11 +93,15 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
92
  };
93
 
94
  const filteredTenders = useMemo(() => {
 
95
  if (showOnlyFollowed) {
96
- return tenders.filter(t => followedCodes.includes(t.code));
97
  }
98
- return tenders;
99
- }, [tenders, showOnlyFollowed, followedCodes]);
 
 
 
100
 
101
  return (
102
  <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
@@ -162,14 +167,26 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
162
  onChange={(e) => setDate(e.target.value)}
163
  />
164
  </div>
165
- <div className="flex items-end">
166
  <button
167
  type="submit"
168
  disabled={isLoading}
169
- className="w-full premium-gradient hover:opacity-90 text-white font-bold py-3.5 rounded-xl transition-all shadow-lg shadow-purple-500/20 active:scale-[0.98] disabled:opacity-50"
170
  >
171
  {isLoading ? "Searching..." : "Fetch Opportunities"}
172
  </button>
 
 
 
 
 
 
 
 
 
 
 
 
173
  </div>
174
  </form>
175
  )}
 
33
 
34
  const [showOnlyFollowed, setShowOnlyFollowed] = useState(forceShowFollowed);
35
  const [isLoading, setIsLoading] = useState(false);
36
+ const [isAgileMode, setIsAgileMode] = useState(false);
37
  const itemsPerPage = 50;
38
 
39
  useEffect(() => {
 
93
  };
94
 
95
  const filteredTenders = useMemo(() => {
96
+ let list = tenders;
97
  if (showOnlyFollowed) {
98
+ list = list.filter(t => followedCodes.includes(t.code));
99
  }
100
+ if (isAgileMode) {
101
+ list = list.filter(t => t.code.includes('COT26') || t.name.toLowerCase().includes('compra ágil'));
102
+ }
103
+ return list;
104
+ }, [tenders, showOnlyFollowed, followedCodes, isAgileMode]);
105
 
106
  return (
107
  <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
 
167
  onChange={(e) => setDate(e.target.value)}
168
  />
169
  </div>
170
+ <div className="flex items-end gap-3">
171
  <button
172
  type="submit"
173
  disabled={isLoading}
174
+ className="flex-1 premium-gradient hover:opacity-90 text-white font-bold py-3.5 rounded-xl transition-all shadow-lg shadow-purple-500/20 active:scale-[0.98] disabled:opacity-50"
175
  >
176
  {isLoading ? "Searching..." : "Fetch Opportunities"}
177
  </button>
178
+ <button
179
+ type="button"
180
+ onClick={() => setIsAgileMode(!isAgileMode)}
181
+ className={`px-4 py-3.5 rounded-xl border font-bold text-[10px] uppercase tracking-widest transition-all ${
182
+ isAgileMode
183
+ ? "bg-cyan/20 border-cyan/40 text-cyan animate-pulse"
184
+ : "bg-white/5 border-white/10 text-slate-500 hover:border-white/20"
185
+ }`}
186
+ title="Toggle Compra Ágil Mode"
187
+ >
188
+ 🚀 Agile
189
+ </button>
190
  </div>
191
  </form>
192
  )}