Carry OCR and missing-source warnings into analysis readiness

This commit is contained in:
2026-09-06 09:45:33 +03:00
parent 49965a2688
commit f073438922
12 changed files with 75 additions and 21 deletions
+3 -2
View File
@@ -59,12 +59,13 @@ export const AiSpecAnalyzerModal = () => {
try {
setProgress('Belge metni çıkarılıyor…');
const { extractText } = await import('../services/pdfText');
const { text, usedPages, pageCount } = await extractText(file);
const reading = await extractText(file);
const { text, usedPages, pageCount } = reading;
if (!text || text.length < 40) {
throw new Error('Belgeden metin çıkarılamadı. Taranmış (görüntü) PDF olabilir — metin tabanlı bir dosya deneyin.');
}
setProgress(`${usedPages}/${pageCount} sayfa okundu, ${derin ? 'derin analiz üretiliyor (1-2 dk sürebilir)…' : 'model analiz ediyor…'}`);
const r = await analyzeSpecPdfWithGemini({ text, fileName: file.name, tender: activeTenderDetail, mode: derin ? 'derin' : undefined });
const r = await analyzeSpecPdfWithGemini({ text, fileName: file.name, extraction:{ocr:reading.ocr,pageCount,usedPages,complete:reading.complete,fileName:file.name}, tender: activeTenderDetail, mode: derin ? 'derin' : undefined });
if (typeof r?.bidAnalysis?.recommendedBid === 'number') setCustomBid(r.bidAnalysis.recommendedBid);
confetti({ particleCount: 80, spread: 70 });
} catch (e) {
+1 -1
View File
@@ -245,7 +245,7 @@ export const BidPackageBuilder = ({ results, tender: selectedTender }) => {
{kaynakGecerlilik.status === 'conflict' && <p role="alert" className="text-red-700">Kaynaklarda farklı süreler var. Güncel resmi dokümanı belirleyip analizi yenileyin; çelişki çözülmeden çıktı alınamaz.</p>}
{[...new Set(kaynakGecerlilik.evidence.map(e=>e.quote))].map(quote=><blockquote key={quote}>{quote}</blockquote>)}
</div>}
{analizEksik && <p role="alert" className="text-xs text-red-700">Analiz kısmi: kaynak veya kalem listesi eksik. Tam dokümanı ve resmi cetveli kontrol ederek analizi tamamlayın.</p>}
{analizEksik && <p role="alert" className="text-xs text-red-700">Analiz kısmi: kaynak, OCR veya kalem bilgisi kontrol gerektiriyor. {(effectiveResults.sourceReview.issues || []).join(' ')} Tam ve doğrulanabilir kaynakla analizi tamamlayın.</p>}
{/* Sizden beklenen bilgiler */}
{eksikler.length > 0 && (
<div className="bg-amber-50 border border-amber-300 rounded-xl p-3.5 flex gap-2.5">
+14 -7
View File
@@ -120,10 +120,11 @@ export const TenderDocuments = ({ tender }) => {
setBusy('belge'); setError(null);
try {
if (!okunabilirMi(b.ad)) throw new Error('Bu dosya türünden metin çıkarılamıyor (PDF, DOCX, XLSX, ZIP ve TXT destekleniyor).');
const metin = await belgeMetni(b);
const reading = await inspectStoredDocument(b);
const metin = reading.text;
if (!metin || metin.length < 100) throw new Error('Belgeden analiz için yeterli metin çıkarılamadı (taranmış PDF olabilir).');
setIsAiSpecAnalyzerOpen(true);
await analyzeSpecPdfWithGemini({ text: metin, fileName: b.ad, tender, mode: mod });
await analyzeSpecPdfWithGemini({ text: metin, fileName: b.ad, extraction:{ocr:reading.ocr,pageCount:reading.pageCount,usedPages:reading.usedPages,complete:reading.complete,fileName:b.ad}, tender, mode: mod });
} catch (e) {
setError(e.message);
} finally { setBusy(null); }
@@ -188,6 +189,7 @@ export const TenderDocuments = ({ tender }) => {
const tumEvrakiTopla = async () => {
const parcalar = [];
const atlanan = [];
const extraction = [];
if (ekapIhalesi) {
setIlerleme('EKAP ilan metni alınıyor…');
@@ -198,28 +200,32 @@ export const TenderDocuments = ({ tender }) => {
}
} catch {
atlanan.push('EKAP ilan metni (alınamadı)');
extraction.push({fileName:'EKAP ilan metni',complete:false});
}
}
for (const b of belgeler) {
if (!okunabilirMi(b.ad)) { atlanan.push(`${b.ad} (metin çıkarılamıyor)`); continue; }
if (!okunabilirMi(b.ad)) { atlanan.push(`${b.ad} (metin çıkarılamıyor)`); extraction.push({fileName:b.ad,complete:false}); continue; }
setIlerleme(`${b.ad} okunuyor…`);
try {
const t = await belgeMetni(b);
const reading = await inspectStoredDocument(b);
const t = reading.text;
extraction.push({ocr:reading.ocr,pageCount:reading.pageCount,usedPages:reading.usedPages,complete:reading.complete,fileName:b.ad});
if (t && t.length >= 200) parcalar.push(`===== BELGE: ${b.ad} =====\n${t}`);
else atlanan.push(`${b.ad} (yeterli metin yok — taranmış olabilir)`);
else { atlanan.push(`${b.ad} (yeterli metin yok — taranmış olabilir)`); extraction.push({fileName:b.ad,complete:false}); }
} catch (e) {
atlanan.push(`${b.ad} (${e.message})`);
extraction.push({fileName:b.ad,complete:false});
}
}
return { metin: parcalar.join('\n\n'), parcaSayisi: parcalar.length, atlanan };
return { metin: parcalar.join('\n\n'), parcaSayisi: parcalar.length, atlanan, extraction };
};
const derinAnalizEt = async () => {
setBusy('derin'); setError(null); setBilgi(null);
try {
const { metin, parcaSayisi, atlanan } = await tumEvrakiTopla();
const { metin, parcaSayisi, atlanan, extraction } = await tumEvrakiTopla();
if (!metin || metin.length < 200) {
throw new Error('Derin analiz için yeterli metin toplanamadı. EKAP dokümanını indirip PDF olarak yükleyin.');
}
@@ -228,6 +234,7 @@ export const TenderDocuments = ({ tender }) => {
setIsAiSpecAnalyzerOpen(true);
await analyzeSpecPdfWithGemini({
text: metin,
extraction,
fileName: `${ikn || 'ihale'} — ${parcaSayisi} evrak birlikte`,
tender,
mode: 'derin',