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'; const tl = (n) => (typeof n === 'number' && isFinite(n) ? '₺' + n.toLocaleString('tr-TR') : '—'); export const AiSpecAnalyzerModal = () => { const { isAiSpecAnalyzerOpen, setIsAiSpecAnalyzerOpen, analyzeSpecPdfWithGemini, aiAnalysisResults, 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); useEffect(() => { if (isAiSpecAnalyzerOpen && aiCfg === null) getAiConfig().then(setAiCfg); }, [isAiSpecAnalyzerOpen, aiCfg]); if (!isAiSpecAnalyzerOpen) return null; const results = aiAnalysisResults; const bid = results?.bidAnalysis || {}; const runAnalysis = async (text, fileName) => { setError(null); setIsAnalyzing(true); setSelectedFile(fileName); try { setProgress('Model analiz ediyor…'); const r = await analyzeSpecPdfWithGemini({ text, fileName, tender: activeTenderDetail }); 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 { text, usedPages, pageCount } = await extractText(file); 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, model analiz ediyor…`); const r = await analyzeSpecPdfWithGemini({ text, fileName: file.name, tender: activeTenderDetail }); 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.
Analiz tamamlanamadı
{error}
{selectedFile}
{results.summary || 'Özet üretilemedi.'}
{results.fileName &&Kaynak: {results.fileName}
}{bid.notes}
}Belgede cezai hüküm/risk tespit edilemedi.
)} {(results.risksAndPenalties || []).map((risk, idx) => ({risk.text}
Analiz yapay zeka tarafından üretilmiştir; teklif kararı öncesi şartnamenin aslını doğrulayın.