import React, { useState, useEffect } from 'react'; import { useApp } from '../context/AppContext'; import { Sparkles, Upload, FileText, CheckCircle2, AlertTriangle, X, Loader2, TrendingUp, Sliders, Info } from 'lucide-react'; import confetti from 'canvas-confetti'; import { getAiConfig } from '../services/ai'; import { DeepAnalysisReport } from './DeepAnalysisReport'; const tl = (n) => (typeof n === 'number' && isFinite(n) ? '₺' + n.toLocaleString('tr-TR') : '—'); export const AiSpecAnalyzerModal = () => { const { isAiSpecAnalyzerOpen, setIsAiSpecAnalyzerOpen, analyzeSpecPdfWithGemini, aiAnalysisResults, aiAnalyzing, activeAiModel, activeTenderDetail, } = useApp(); const [isAnalyzing, setIsAnalyzing] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const [error, setError] = useState(null); const [progress, setProgress] = useState(''); const [customBid, setCustomBid] = useState(null); const [aiCfg, setAiCfg] = useState(null); // Derin mod: ince detaylar, belge kontrol listesi ve yol haritası da üretilir. // Çıktısı standart şemanın üst kümesi olduğu için varsayılan açık. const [derin, setDerin] = useState(true); useEffect(() => { if (isAiSpecAnalyzerOpen && aiCfg === null) getAiConfig().then(setAiCfg); }, [isAiSpecAnalyzerOpen, aiCfg]); if (!isAiSpecAnalyzerOpen) return null; // Analiz doküman panelinden de başlatılabiliyor — o durumda isAnalyzing false // kalır, bu yüzden context'teki ortak sinyalle birleştiriyoruz. const mesgul = isAnalyzing || aiAnalyzing; const results = aiAnalysisResults; const bid = results?.bidAnalysis || {}; const runAnalysis = async (text, fileName) => { setError(null); setIsAnalyzing(true); setSelectedFile(fileName); try { setProgress(derin ? 'Derin analiz üretiliyor (1-2 dk sürebilir)…' : 'Model analiz ediyor…'); const r = await analyzeSpecPdfWithGemini({ text, fileName, tender: activeTenderDetail, mode: derin ? 'derin' : undefined }); if (typeof r?.bidAnalysis?.recommendedBid === 'number') setCustomBid(r.bidAnalysis.recommendedBid); confetti({ particleCount: 80, spread: 70 }); } catch (e) { setError(e.message); } finally { setIsAnalyzing(false); setProgress(''); } }; const handleFile = async (file) => { setError(null); setIsAnalyzing(true); setSelectedFile(file.name); try { setProgress('Belge metni çıkarılıyor…'); const { extractText } = await import('../services/pdfText'); 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, 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) { setError(e.message); } finally { setIsAnalyzing(false); setProgress(''); } }; // Açık ihalenin ilan metnini analiz et const analyzeCurrentTender = () => { const t = activeTenderDetail; const text = [t?.baslik, t?.kurum, t?.aciklama, ...(t?.yeterlikKriterleri || [])].filter(Boolean).join('\n'); if (!text || text.length < 40) { setError('Açık ihalenin ilan metni analiz için yeterli değil. Bir şartname dosyası yükleyin.'); return; } runAnalysis(text, `${t.ikn || 'ihale'} — ilan metni`); }; const modelEtiketi = aiCfg?.providers?.length ? aiCfg.providers.map((p) => p.label).join(' → ') : `${activeAiModel.label} (${activeAiModel.provider})`; return (
Şartname dosyanızı yükleyin; yeterlik, riskler ve teklif aralığı gerçek AI ile analiz edilsin.
AI henüz yapılandırılmamış. En kolayı: sunucuya tek bir{' '}
OPENROUTER_API_KEY ekleyin —
zincirdeki tüm modeller (GLM, DeepSeek, Gemini, Grok, GPT, Claude) bu tek anahtarla çalışır.
Dilerseniz tek tek sağlayıcı anahtarı da verebilirsiniz; doğrudan anahtar OpenRouter'ı ezer.
Model sırası Admin → AI Model Ayarları'ndan belirlenir.
Metin tabanlı .pdf veya .txt dosyası — belge tarayıcınızda okunur, yalnızca metni analiz için gönderilir.
{derin ? 'Elenme sebepleri, gözden kaçan ince detaylar, belge kontrol listesi, kritik tarihler ve teklife kadar adım adım yol haritası üretilir. Daha uzun sürer.' : 'Yalnızca özet, yeterlik kriterleri, riskler ve teklif aralığı üretilir. Daha hızlıdır.'}
Analiz tamamlanamadı
{error}
{selectedFile}
{results.summary || 'Özet üretilemedi.'}
{results.fileName &&Kaynak: {results.fileName}
}{bid.notes}
}Bu bölümde yapılandırılmış ceza/risk listesi yok. Bu, belgede risk bulunmadığı anlamına gelmez.
)} {(results.risksAndPenalties || []).map((risk, idx) => ({risk.text}
Analiz yapay zeka tarafından üretilmiştir; teklif kararı öncesi şartnamenin aslını doğrulayın.