');
} catch { /* yazılamazsa da yönlendirme çalışır */ }
}
try {
const r = await fetch(`/api/documents/url?ikn=${encodeURIComponent(ikn)}`);
const d = await r.json();
if (!d.success) throw new Error(d.error);
setEkapUrl(d.url);
setBilgi({ dokumanSayisi: d.dokumanSayisi, ekapSekme: sekme ? 'acildi' : 'engellendi' });
if (sekme) sekme.location.href = d.url;
} catch (e) {
if (sekme) { try { sekme.close(); } catch { /* yoksay */ } }
setError(e.message);
} finally { setBusy(null); }
};
const ilanMetniGetir = async () => {
assertCurrent();
const r = await fetch(`/api/documents/ilan?ikn=${encodeURIComponent(ikn)}`, {
signal:readLifetime.current.signal,
headers: { Authorization: `Bearer ${sessionToken.current}` },
});
const d = await r.json();
assertCurrent();
if (!d.success) throw new Error(d.error);
return d;
};
const ilaniAnalizEt = async () => {
setBusy('analiz'); setError(null);
try {
const d = await ilanMetniGetir();
if (!d.metin || d.metin.length < 100) throw new Error('İlan metni analiz için yeterli değil.');
setBilgi({ karakter: d.metin.length, ilanSayisi: d.ilanSayisi, okasSayisi: d.okasSayisi });
assertCurrent();
setIsAiSpecAnalyzerOpen(true);
await analyzeSpecPdfWithGemini({ text: d.metin, fileName: `${d.ikn} — EKAP ilan metni`, tender });
} catch (e) {
setError(e.message);
} finally { setBusy(null); }
};
/**
* Derin analiz — teknik şartname ve diğer evrakın tamamını TEK metinde
* birleştirip gönderir: EKAP ilan metni + bu ihaleye yüklenmiş her belge.
* Böylece model şartnameyi ilanla ve eklerle çapraz okuyabiliyor.
*/
const tumEvrakiTopla = async () => {
const parcalar = [];
const atlanan = [];
const extraction = [];
if (ekapIhalesi) {
setIlerleme('EKAP ilan metni alınıyor…');
try {
const d = await ilanMetniGetir();
if (d.metin && d.metin.length >= 100) {
parcalar.push(`===== EKAP İLAN METNİ (${d.ikn}) =====\n${d.metin}`);
}
} catch {
assertCurrent();
atlanan.push('EKAP ilan metni (alınamadı)');
extraction.push({fileName:'EKAP ilan metni',complete:false});
}
}
for (const b of belgeler) {
assertCurrent();
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 reading = await inspectStoredDocument(b,{signal:readLifetime.current.signal});
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)`); extraction.push({fileName:b.ad,complete:false}); }
} catch (e) {
assertCurrent();
atlanan.push(`${b.ad} (${e.message})`);
extraction.push({fileName:b.ad,complete:false});
}
}
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, 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.');
}
setBilgi({ derin: { parcaSayisi, karakter: metin.length, atlanan } });
setIlerleme('');
assertCurrent();
setIsAiSpecAnalyzerOpen(true);
await analyzeSpecPdfWithGemini({
text: metin,
extraction,
fileName: `${ikn || 'ihale'} — ${parcaSayisi} evrak birlikte`,
tender,
mode: 'derin',
});
} catch (e) {
setError(e.message);
} finally { setBusy(null); setIlerleme(''); }
};
return (
İhale Dokümanları
{!ekapIhalesi ? (
Bu kayıt EKAP İKN formatında değil; doküman bağlantısı yalnızca EKAP ihaleleri için üretilebilir.
{tender?.kaynakUrl && (
<> İlanın kaynağını{' '}
buradan açabilirsiniz
.
>
)}
) : (
<>
İhale dokümanları EKAP üzerinde tutulur. Aşağıdaki bağlantı sizi doğrudan bu ihalenin
EKAP doküman sayfasına götürür; EKAP önce kısa bir güvenlik doğrulaması (resim seçme)
ister, ardından şartname ve ekleri listelenir. İlan metnini ise analiz için buradan çekebilirsiniz.
{ekapUrl && (
{bilgi?.ekapSekme === 'engellendi'
? <>Tarayıcınız yeni sekmeyi engelledi. >
: <>EKAP doküman sayfası yeni sekmede açıldı. Açılmadıysa: >}
EKAP doküman sayfasını aç
{' '}· Bağlantı bir süre sonra geçerliliğini yitirebilir; açılmazsa düğmeye yeniden basın.
)}
{bilgi && !bilgi.derin && (
{bilgi.dokumanSayisi > 0 && <>EKAP'ta {bilgi.dokumanSayisi} doküman kayıtlı. >}
{bilgi.karakter != null && <>{bilgi.ilanSayisi} ilan · {bilgi.okasSayisi} kalem · {bilgi.karakter.toLocaleString('tr-TR')} karakter metin analize gönderildi. >}
{bilgi.yuklendi && (
<>
{bilgi.yuklendi} yüklendi ve bu ihaleye bağlandı.
{bilgi.kalemHata && Kalem aktarımı tamamlanamadı: {bilgi.kalemHata}. Dosya kaydı korunmuştur.}
{bilgi.kalem
? <> Teklif cetvelinden {bilgi.kalem} kalem otomatik çıkarıldı; bu ihale artık kalemleriyle listeleniyor.>
: <> Bu dosyadan teklif cetveli kalemi çıkarılamadı.>}
>
)}
)}
>
)}
{/* EKAP dokümanı kullanıcının tarayıcısına iniyor; sunucu tarafından
alınamıyor. İndirilen dosya buraya yüklenip ihaleye bağlanır. */}
EKAP dokümanı kendi oturumunuz üzerinden bilgisayarınıza iner — biz sunucudan
alamıyoruz. İnen dosyayı buraya yükleyin; bu ihaleye bağlanır ve AI ile analiz edebilirsiniz.
EKAP ilan metni ve bu ihaleye yüklediğiniz tüm evrak birlikte okunur;
elenme sebepleri, gözden kaçan ince detaylar, belge kontrol listesi, kritik tarihler ve
teklife kadar adım adım yol haritası çıkarılır.
{bilgi?.derin ? (
{bilgi.derin.parcaSayisi} kaynak · {bilgi.derin.karakter.toLocaleString('tr-TR')} karakter analize gönderildi.