Spaces:
Running
Running
<html lang="tr"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Hugging Face API ile Çelişki Tespiti</title> | |
<style> | |
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; margin: 2em; background-color: #f9fafb; color: #111827; } | |
.container { max-width: 900px; margin: 0 auto; background-color: white; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } | |
h1 { color: #374151; } | |
button { background-color: #3b82f6; color: white; border: none; padding: 10px 15px; border-radius: 5px; cursor: pointer; font-size: 16px; margin: 5px; } | |
button:hover { background-color: #2563eb; } | |
button:disabled { background-color: #9ca3af; cursor: not-allowed; } | |
input[type="text"], input[type="password"] { width: 100%; padding: 10px; border: 1px solid #d1d5db; border-radius: 5px; font-size: 14px; margin: 5px 0; box-sizing: border-box; } | |
#status { margin: 1em 0; padding: 1em; background-color: #eef2ff; border: 1px solid #c7d2fe; border-radius: 5px; display: none; } | |
.result-item { border: 1px solid #e5e7eb; padding: 15px; margin-top: 15px; border-radius: 5px; } | |
.result-item p { margin: 0.5em 0; } | |
.similarity-score { font-weight: bold; color: #ef4444; } | |
.api-section { background-color: #f8fafc; padding: 20px; border-radius: 8px; margin-bottom: 20px; border: 2px solid #e2e8f0; } | |
.info-box { background-color: #dbeafe; padding: 15px; border-radius: 5px; margin: 10px 0; border-left: 4px solid #3b82f6; } | |
.model-select { margin: 10px 0; } | |
select { padding: 8px; border: 1px solid #d1d5db; border-radius: 5px; font-size: 14px; width: 100%; } | |
.progress-bar { background-color: #e5e7eb; height: 20px; border-radius: 10px; overflow: hidden; margin: 10px 0; } | |
.progress-bar-fill { background-color: #3b82f6; height: 100%; transition: width 0.3s ease; } | |
.warning-box { background-color: #fef3c7; padding: 15px; border-radius: 5px; margin: 10px 0; border-left: 4px solid #f59e0b; } | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>🔍 Profesyonel Çelişki Tespiti</h1> | |
<p>Hugging Face API kullanarak güçlü dil modelleriyle çelişki analizi yapın.</p> | |
<div class="api-section"> | |
<h3>🔑 API Yapılandırması</h3> | |
<div class="info-box"> | |
<strong>Bilgi:</strong> Hugging Face API anahtarınızı <a href="https://huggingface.co/settings/tokens" target="_blank">buradan</a> alabilirsiniz. | |
Ücretsiz seviyede günde sınırlı sayıda istek atabilirsiniz. | |
</div> | |
<label for="api-key">Hugging Face API Anahtarı:</label> | |
<input type="password" id="api-key" placeholder="hf_xxxxxxxxxxxxxxxxxxxxxxxxx"> | |
<div class="model-select"> | |
<label for="model-select">Model Seçimi:</label> | |
<select id="model-select"> | |
<option value="facebook/bart-large-mnli" selected>Facebook BART-Large-MNLI (Çelişki Tespiti - Önerilen)</option> | |
<option value="roberta-large-mnli">RoBERTa-Large-MNLI (Yüksek Performans)</option> | |
<option value="microsoft/deberta-v3-large-mnli">DeBERTa-v3-Large-MNLI (En İyi)</option> | |
<option value="MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli">DeBERTa-v3-base-MNLI (Hızlı)</option> | |
</select> | |
</div> | |
</div> | |
<div> | |
<input type="file" id="file-input" accept=".txt"> | |
<button id="analyze-button">🔍 API ile Analiz Et</button> | |
</div> | |
<div id="status"></div> | |
<div class="progress-bar" id="progress-container" style="display: none;"> | |
<div class="progress-bar-fill" id="progress-bar"></div> | |
</div> | |
<div id="results"></div> | |
</div> | |
<script> | |
const fileInput = document.getElementById('file-input'); | |
const analyzeButton = document.getElementById('analyze-button'); | |
const statusDiv = document.getElementById('status'); | |
const resultsDiv = document.getElementById('results'); | |
const apiKeyInput = document.getElementById('api-key'); | |
const modelSelect = document.getElementById('model-select'); | |
const progressContainer = document.getElementById('progress-container'); | |
const progressBar = document.getElementById('progress-bar'); | |
let totalComparisons = 0; | |
let completedComparisons = 0; | |
// Progress bar güncelleme | |
function updateProgress() { | |
if (totalComparisons > 0) { | |
const percentage = (completedComparisons / totalComparisons) * 100; | |
progressBar.style.width = percentage + '%'; | |
} | |
} | |
// Hugging Face NLI API ile çelişki tespiti | |
async function analyzeContradictionWithNLI(sentence1, sentence2, apiKey, modelName) { | |
const inputText = `${sentence1} [SEP] ${sentence2}`; | |
const response = await fetch(`https://api-inference.huggingface.co/models/${modelName}`, { | |
method: 'POST', | |
headers: { | |
'Authorization': `Bearer ${apiKey}`, | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
inputs: inputText, | |
parameters: { | |
candidate_labels: ["contradiction", "entailment", "neutral"] | |
} | |
}) | |
}); | |
if (!response.ok) { | |
if (response.status === 503) { | |
// Model loading, retry after delay | |
statusDiv.textContent = 'Model yükleniyor, lütfen bekleyin...'; | |
await new Promise(resolve => setTimeout(resolve, 3000)); | |
return await analyzeContradictionWithNLI(sentence1, sentence2, apiKey, modelName); | |
} | |
// Hata detayını almak için response text'ini oku | |
let errorText = ''; | |
try { | |
errorText = await response.text(); | |
} catch (e) { | |
errorText = response.statusText; | |
} | |
throw new Error(`API Error: ${response.status} - ${errorText}`); | |
} | |
const result = await response.json(); | |
// API'den dönen format kontrol et | |
if (result.error) { | |
throw new Error(`API Error: ${result.error}`); | |
} | |
return result; | |
} | |
// Rate limiting için delay | |
async function delay(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
statusDiv.style.display = 'block'; | |
statusDiv.textContent = 'Sistem hazır. API anahtarınızı girin ve dosya seçip analiz edin.'; | |
analyzeButton.addEventListener('click', async () => { | |
const apiKey = apiKeyInput.value.trim(); | |
if (!apiKey) { | |
alert("Lütfen Hugging Face API anahtarınızı girin."); | |
return; | |
} | |
if (!fileInput.files || fileInput.files.length === 0) { | |
alert("Lütfen bir dosya seçin."); | |
return; | |
} | |
const file = fileInput.files[0]; | |
const text = await file.text(); | |
const selectedModel = modelSelect.value; | |
statusDiv.style.display = 'block'; | |
statusDiv.textContent = 'Analiz başladı... Metin cümlelere ayrılıyor.'; | |
resultsDiv.innerHTML = ''; | |
progressContainer.style.display = 'block'; | |
progressBar.style.width = '0%'; | |
analyzeButton.disabled = true; | |
try { | |
// Metni cümlelere ayır | |
let sentences = text.match(/[^.!?]+[.!?]+/g) || []; | |
if (sentences.length < 2) { | |
statusDiv.textContent = 'Analiz için en az 2 cümle bulunmalıdır.'; | |
analyzeButton.disabled = false; | |
return; | |
} | |
// Kısa cümleleri filtrele ve temizle | |
sentences = sentences | |
.map(s => s.trim()) | |
.filter(s => s.length > 20) // Minimum 20 karakter | |
.filter(s => s.split(' ').length > 3); // Minimum 3 kelime | |
// Çok fazla cümle varsa sınırla | |
const maxSentences = 50; // API rate limit için daha düşük | |
if (sentences.length > maxSentences) { | |
sentences = sentences.slice(0, maxSentences); | |
statusDiv.innerHTML = `<div class="warning-box">Performans ve API limitleri için analiz ${maxSentences} cümle ile sınırlandırıldı.</div>`; | |
await new Promise(resolve => setTimeout(resolve, 2000)); | |
} | |
statusDiv.textContent = `Toplam ${sentences.length} cümle bulundu. ${selectedModel} modeli ile çelişki analizi başlıyor...`; | |
const potentialContradictions = []; | |
totalComparisons = (sentences.length * (sentences.length - 1)) / 2; | |
completedComparisons = 0; | |
// Her cümleyi diğerleriyle karşılaştır | |
for (let i = 0; i < sentences.length; i++) { | |
for (let j = i + 1; j < sentences.length; j++) { | |
try { | |
const sentence1 = sentences[i]; | |
const sentence2 = sentences[j]; | |
// Çok benzer başlangıçları atla | |
if (sentence1.substring(0, 15) === sentence2.substring(0, 15)) { | |
completedComparisons++; | |
updateProgress(); | |
continue; | |
} | |
statusDiv.textContent = `Çelişki analizi: ${completedComparisons + 1}/${totalComparisons} - Cümle ${i + 1} vs ${j + 1}`; | |
// API çağrısı | |
const result = await analyzeContradictionWithNLI(sentence1, sentence2, apiKey, selectedModel); | |
completedComparisons++; | |
updateProgress(); | |
// Sonucu işle | |
let contradictionScore = 0; | |
console.log('API Response:', result); | |
if (result.labels && result.scores) { | |
// Zero-shot classification format | |
const contradictionIndex = result.labels.findIndex(label => | |
label.toLowerCase().includes('contradiction') | |
); | |
if (contradictionIndex !== -1) { | |
contradictionScore = result.scores[contradictionIndex]; | |
} | |
} else if (Array.isArray(result)) { | |
// Array format - classification result | |
const contradictionResult = result.find(r => | |
r.label && r.label.toLowerCase().includes('contradiction') | |
); | |
contradictionScore = contradictionResult?.score || 0; | |
} else if (result.sequence && result.labels) { | |
// Sequence classification format | |
const contradictionIndex = result.labels.findIndex(label => | |
label.toLowerCase().includes('contradiction') | |
); | |
if (contradictionIndex !== -1) { | |
contradictionScore = result.scores[contradictionIndex]; | |
} | |
} | |
console.log(`Analiz: "${sentence1.substring(0, 30)}..." vs "${sentence2.substring(0, 30)}..." - Çelişki: ${(contradictionScore * 100).toFixed(1)}%`); | |
// Çelişki eşiği - daha düşük bir eşik deneyelim | |
if (contradictionScore > 0.4) { // %40'dan yüksek çelişki skoru | |
potentialContradictions.push({ | |
sentence1: sentence1, | |
sentence2: sentence2, | |
contradictionScore: contradictionScore | |
}); | |
console.log(`✓ Çelişki bulundu! Skor: ${(contradictionScore * 100).toFixed(1)}%`); | |
} | |
// Rate limiting - her 5 istek arasında kısa bekleme | |
if (completedComparisons % 5 === 0) { | |
await delay(500); | |
} | |
} catch (error) { | |
console.warn(`Cümle ${i}-${j} analiz edilirken hata:`, error); | |
completedComparisons++; | |
updateProgress(); | |
if (error.message.includes('rate limit') || error.message.includes('429')) { | |
statusDiv.textContent = 'API rate limit aşıldı, 10 saniye bekleniyor...'; | |
await delay(10000); | |
} else { | |
await delay(1000); // Genel hata durumunda kısa bekleme | |
} | |
continue; | |
} | |
} | |
} | |
progressContainer.style.display = 'none'; | |
// Sonuçları göster | |
if (potentialContradictions.length > 20) { | |
potentialContradictions.sort((a, b) => b.contradictionScore - a.contradictionScore); | |
const limitedContradictions = potentialContradictions.slice(0, 20); | |
statusDiv.style.display = 'none'; | |
renderResults(limitedContradictions, potentialContradictions.length, selectedModel); | |
} else { | |
statusDiv.style.display = 'none'; | |
renderResults(potentialContradictions, null, selectedModel); | |
} | |
} catch (error) { | |
progressContainer.style.display = 'none'; | |
statusDiv.textContent = `Analiz sırasında hata: ${error.message}`; | |
console.error('Detaylı hata:', error); | |
if (error.message.includes('401') || error.message.includes('Unauthorized')) { | |
statusDiv.innerHTML = ` | |
<div class="warning-box"> | |
<strong>API Anahtarı Hatası:</strong><br> | |
• API anahtarınızı kontrol edin<br> | |
• Hugging Face hesabınızın aktif olduğundan emin olun<br> | |
• API anahtarının "read" yetkisi olduğundan emin olun | |
</div> | |
`; | |
} else if (error.message.includes('rate limit') || error.message.includes('429')) { | |
statusDiv.innerHTML = ` | |
<div class="warning-box"> | |
<strong>Rate Limit Aşıldı:</strong><br> | |
• Çok fazla istek gönderildi<br> | |
• Birkaç dakika bekleyip tekrar deneyin<br> | |
• Daha kısa bir metin kullanmayı deneyin | |
</div> | |
`; | |
} | |
} finally { | |
analyzeButton.disabled = false; | |
} | |
}); | |
function renderResults(results, totalFound, modelName) { | |
if (results.length === 0) { | |
let message = '<div style="text-align: center; padding: 20px;">'; | |
message += '<h3>🎉 Analiz Tamamlandı</h3>'; | |
message += '<p>Belirlenen eşik değerinde (%40) potansiyel çelişki bulunamadı.</p>'; | |
message += `<div style="background-color: #f3f4f6; padding: 15px; border-radius: 5px; margin-top: 15px;"> | |
<h4>${modelName} Modeli Sonucu</h4> | |
<p>Bu model özellikle çelişki tespiti için optimize edilmiştir.</p> | |
<p>%40'dan yüksek çelişki skoru aranan eşik değeridir.</p> | |
<p>Sonuç: Metninizde güçlü çelişkiler tespit edilmemiştir.</p> | |
</div>`; | |
message += '</div>'; | |
resultsDiv.innerHTML = message; | |
return; | |
} | |
let headerText = `<h3>🚨 ${results.length} adet potansiyel çelişki bulundu:</h3>`; | |
if (totalFound && totalFound > results.length) { | |
headerText = `<h3>🚨 Toplam ${totalFound} çelişki bulundu - En güçlü ${results.length} tanesi gösteriliyor:</h3>`; | |
} | |
headerText += `<p style="color: #6b7280; margin-bottom: 20px;">Model: <strong>${modelName}</strong> | Eşik: <strong>%40</strong></p>`; | |
resultsDiv.innerHTML = headerText; | |
// Sonuçları çelişki skoruna göre sırala | |
results.sort((a, b) => b.contradictionScore - a.contradictionScore); | |
results.forEach((item, index) => { | |
const div = document.createElement('div'); | |
div.className = 'result-item'; | |
let severityColor = '#ef4444'; | |
let severityText = 'Yüksek'; | |
let bgColor = '#fef2f2'; | |
if (item.contradictionScore > 0.9) { | |
severityColor = '#dc2626'; | |
severityText = 'Çok Yüksek'; | |
bgColor = '#fecaca'; | |
} else if (item.contradictionScore > 0.8) { | |
severityColor = '#ef4444'; | |
severityText = 'Yüksek'; | |
bgColor = '#fef2f2'; | |
} else if (item.contradictionScore > 0.5) { | |
severityColor = '#f59e0b'; | |
severityText = 'Orta-Yüksek'; | |
bgColor = '#fef3c7'; | |
} else if (item.contradictionScore > 0.4) { | |
severityColor = '#eab308'; | |
severityText = 'Orta'; | |
bgColor = '#fefce8'; | |
} | |
div.style.backgroundColor = bgColor; | |
div.innerHTML = ` | |
<p><strong>Çelişki #${index + 1}</strong></p> | |
<p><strong>Çelişki Skoru: <span style="color: ${severityColor}; font-weight: bold;">${(item.contradictionScore * 100).toFixed(1)}%</span> (${severityText} Seviye)</strong></p> | |
<p><em>🔴 İfade 1:</em> "${item.sentence1.trim()}"</p> | |
<p><em>🔴 İfade 2:</em> "${item.sentence2.trim()}"</p> | |
`; | |
resultsDiv.appendChild(div); | |
}); | |
// Özet bilgi | |
const summaryDiv = document.createElement('div'); | |
summaryDiv.style.cssText = 'background-color: #f3f4f6; padding: 20px; border-radius: 8px; margin-top: 20px; border-left: 4px solid #3b82f6;'; | |
summaryDiv.innerHTML = ` | |
<h4>📊 Analiz Özeti</h4> | |
<p><strong>Kullanılan Model:</strong> ${modelName}</p> | |
<p><strong>Toplam Çelişki:</strong> ${totalFound || results.length}</p> | |
<p><strong>Gösterilen:</strong> ${results.length}</p> | |
<p><strong>En Yüksek Skor:</strong> ${(results[0].contradictionScore * 100).toFixed(1)}%</p> | |
<p style="margin-top: 15px; color: #6b7280; font-size: 14px;"> | |
<em>Not: Çelişki skoru %40'ın üzerindeki cümle çiftleri potansiyel çelişki olarak değerlendirilmiştir.</em> | |
</p> | |
`; | |
resultsDiv.appendChild(summaryDiv); | |
} | |
</script> | |
</body> | |
</html> |