celiski-analizi / index.html
MEO1's picture
Update index.html
fa0d552 verified
<!DOCTYPE html>
<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>