Require real draft evidence for offer audit findings

This commit is contained in:
2026-09-06 10:09:12 +03:00
parent ecc031a822
commit 0b3bb8223f
5 changed files with 74 additions and 12 deletions
+3 -10
View File
@@ -1,3 +1,4 @@
import { qualifyOfferAudit } from './offer-audit.mjs';
import { documentContent } from './document-content.mjs';
// Teklif asistanı — İhaleAB'den taşınan üç AI özelliği, ihaleist'in mevcut
// analyzeSpec zinciri (yedekli sağlayıcılar) üzerinde:
@@ -101,17 +102,9 @@ export async function teklifDenetle({ ikn, taslak, gereklilikler, tender, chain,
const { text: metin } = await ihaleMetni(ikn, text, tender?.aciklama).catch(() => ({ text: '' }));
const liste = gereklilikMetni(tender, gereklilikler, metin);
if (!liste.length) throw new Error('Gereklilik listesi yok — önce derin analiz çalıştırın veya dokümanı yükleyin.');
const sistem = `Sen kamu ihalelerinde teklif dosyası denetçisisin. Gereklilik listesi ve teklif TASLAĞI verilecek. Her gereklilik için taslağı kontrol et. "karsilaniyor" yalnızca taslakta açık karşılığı varsa (alıntıyı 'kanit'e aynen kopyala); değinilmiyorsa "eksik"; kısmen/belirsizse "belirsiz". Sayı üretme. Yalnızca JSON: {"ozet":"2-3 cümle","maddeler":[{"gereklilik":"","durum":"karsilaniyor"|"eksik"|"belirsiz","kanit":"veya null","oneri":"veya null"}]} — maddeleri verilen sırada döndür.`;
const sistem = `Sen kamu ihalelerinde teklif dosyası denetçisisin. Gereklilik listesi ve teklif TASLAĞI verilecek. Her gereklilik için taslağı kontrol et. "karsilaniyor" yalnızca taslakta açık karşılığı varsa (alıntıyı 'kanit'e aynen kopyala); değinilmiyorsa "eksik"; kısmen/belirsizse "belirsiz". Sayı üretme. Yalnızca JSON: {"ozet":"2-3 cümle","maddeler":[{"gereklilik":"","durum":"karsilaniyor"|"eksik"|"belirsiz","kanit":"veya null","oneri":"veya null"}]} — maddeleri verilen sırada döndür; gereklilik alanına verilen gereklilik metnini değiştirmeden aynen kopyala.`;
const out = await analyzeSpec({ text: `GEREKLİLİKLER:\n${liste.map((g, i) => `${i + 1}. ${g}`).join('\n')}\n\nTEKLİF TASLAĞI:\n${t}\n\nYalnızca JSON döndür.`, tender, chain, systemOverride: sistem, mode: 'derin' });
const ham = Array.isArray(out?.result?.maddeler) ? out.result.maddeler : [];
const DUR = new Set(['karsilaniyor', 'eksik', 'belirsiz']);
const maddeler = liste.map((g, i) => {
const m = ham[i] ?? {};
return { gereklilik: g, durum: DUR.has(m.durum) ? m.durum : 'belirsiz', kanit: m.kanit ? String(m.kanit).slice(0, 400) : null, oneri: m.oneri ? String(m.oneri).slice(0, 400) : null };
});
const ok = maddeler.filter((m) => m.durum === 'karsilaniyor').length;
const yarim = maddeler.filter((m) => m.durum === 'belirsiz').length;
return { ozet: String(out?.result?.ozet ?? '').slice(0, 800), maddeler, uyum_yuzde: Math.round(((ok + yarim * 0.5) / maddeler.length) * 100), eksikler: maddeler.filter((m) => m.durum === 'eksik').map((m) => m.gereklilik) };
return qualifyOfferAudit(out?.result, liste, t);
}
const BOLUMLER = {