{% extends "base.html" %} {% block title %}ZOP Kaszubia - Panel Admina - Norda Biznes Partner{% endblock %} {% block extra_css %} {% endblock %} {% block content %}
Panel zarządzania bazą wiedzy
gemini-2.5-flash-lite
Multi-source search: Brave API, RSS (trojmiasto.pl, Dziennik Bałtycki), Google News, gov.pl
Brak newsów{% if status_filter != 'all' %} o tym statusie{% endif %}.
| Nazwa | Typ | Status | Region |
|---|---|---|---|
|
{{ project.name }}
{{ project.slug }} |
{{ project.project_type or '-' }} | {% if project.status == 'planned' %}Planowany{% elif project.status == 'in_progress' %}W realizacji{% else %}{{ project.status }}{% endif %} | {{ project.region or '-' }} |
Brak projektów.
Odświeżam stronę za 2 sekundy...
`; // Auto-reload after showing results setTimeout(() => location.reload(), 2000); } else { resultIcon.textContent = '✗'; resultIcon.className = 'modal-icon error'; resultTitle.textContent = 'Wystąpił błąd'; resultStats.innerHTML = `${data.error}
`; btn.disabled = false; btn.querySelector('.stat-label').textContent = 'AI: Oceń ponownie'; } } catch (error) { clearInterval(progressInterval); document.getElementById('aiEvalProgress').style.display = 'none'; document.getElementById('aiEvalResult').style.display = 'block'; const resultIcon = document.getElementById('aiResultIcon'); const resultTitle = document.getElementById('aiResultTitle'); const resultStats = document.getElementById('aiResultStats'); resultIcon.textContent = '✗'; resultIcon.className = 'modal-icon error'; // Check if timeout if (error.name === 'AbortError') { resultTitle.textContent = 'Przekroczono limit czasu'; resultStats.innerHTML = `
Przetwarzanie trwało zbyt długo (>3 min).
Spróbuj ponownie lub sprawdź logi serwera.
${error.message}
`; } btn.disabled = false; btn.querySelector('.stat-label').textContent = 'AI: Oceń ponownie'; } } // Re-evaluate items missing scores (upgrade to 1-5 stars) async function reevaluateScores() { const btn = document.getElementById('aiRescoreBtn'); if (!btn) return; // Show modal for re-evaluation document.getElementById('aiEvalModal').classList.add('active'); document.getElementById('aiEvalConfirm').style.display = 'none'; document.getElementById('aiEvalProgress').style.display = 'block'; document.getElementById('aiEvalResult').style.display = 'none'; const progressBar = document.getElementById('aiProgressFill'); const progressStatus = document.getElementById('aiProgressStatus'); btn.disabled = true; btn.querySelector('.stat-label').textContent = 'AI pracuje...'; // Simulated progress for better UX let progress = 0; let startTime = Date.now(); const progressInterval = setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); if (progress < 90) { progress += Math.random() * 3; progressBar.style.width = Math.min(progress, 90) + '%'; } progressStatus.textContent = `AI dodaje gwiazdki... (${elapsed}s)`; }, 500); try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 180000); const response = await fetch('/admin/zopk/news/reevaluate-scores', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken }, body: JSON.stringify({ limit: 30 }), signal: controller.signal }); clearTimeout(timeoutId); clearInterval(progressInterval); const data = await response.json(); progressBar.style.width = '100%'; document.getElementById('aiEvalProgress').style.display = 'none'; document.getElementById('aiEvalResult').style.display = 'block'; const resultIcon = document.getElementById('aiResultIcon'); const resultTitle = document.getElementById('aiResultTitle'); const resultStats = document.getElementById('aiResultStats'); if (data.success) { resultIcon.textContent = '⭐'; resultIcon.className = 'modal-icon success'; resultTitle.textContent = 'Gwiazdki dodane!'; resultStats.innerHTML = `${data.message}
`; setTimeout(() => location.reload(), 2000); } else { resultIcon.textContent = '✗'; resultIcon.className = 'modal-icon error'; resultTitle.textContent = 'Wystąpił błąd'; resultStats.innerHTML = `${data.error}
`; btn.disabled = false; btn.querySelector('.stat-label').textContent = 'AI: Spróbuj ponownie'; } } catch (error) { clearInterval(progressInterval); document.getElementById('aiEvalProgress').style.display = 'none'; document.getElementById('aiEvalResult').style.display = 'block'; const resultIcon = document.getElementById('aiResultIcon'); const resultTitle = document.getElementById('aiResultTitle'); const resultStats = document.getElementById('aiResultStats'); resultIcon.textContent = '✗'; resultIcon.className = 'modal-icon error'; resultTitle.textContent = 'Błąd połączenia'; resultStats.innerHTML = `${error.message}
`; btn.disabled = false; btn.querySelector('.stat-label').textContent = 'AI: Spróbuj ponownie'; } } // Re-evaluate low score news (1-2★) with key topics (Via Pomerania, NORDA, etc.) async function reevaluateLowScores() { const btn = document.getElementById('aiReevalLowBtn'); if (!btn) return; // Show modal for re-evaluation document.getElementById('aiEvalModal').classList.add('active'); document.getElementById('aiEvalConfirm').style.display = 'none'; document.getElementById('aiEvalProgress').style.display = 'block'; document.getElementById('aiEvalResult').style.display = 'none'; const progressBar = document.getElementById('aiProgressFill'); const progressStatus = document.getElementById('aiProgressStatus'); btn.disabled = true; btn.querySelector('.stat-label').textContent = 'Re-ewaluacja...'; // Simulated progress for better UX let progress = 0; let startTime = Date.now(); const progressInterval = setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); if (progress < 90) { progress += Math.random() * 3; progressBar.style.width = Math.min(progress, 90) + '%'; } progressStatus.textContent = `Re-ewaluacja newsów z Via Pomerania, NORDA... (${elapsed}s)`; }, 500); try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 180000); const response = await fetch('/admin/zopk/news/reevaluate-low-scores', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken }, body: JSON.stringify({ limit: 50 }), signal: controller.signal }); clearTimeout(timeoutId); clearInterval(progressInterval); const data = await response.json(); progressBar.style.width = '100%'; document.getElementById('aiEvalProgress').style.display = 'none'; document.getElementById('aiEvalResult').style.display = 'block'; const resultIcon = document.getElementById('aiResultIcon'); const resultTitle = document.getElementById('aiResultTitle'); const resultStats = document.getElementById('aiResultStats'); if (data.success) { resultIcon.textContent = '🔄'; resultIcon.className = 'modal-icon success'; resultTitle.textContent = 'Re-ewaluacja zakończona!'; // Build details list if available let detailsHtml = ''; if (data.details && data.details.length > 0) { detailsHtml = `${data.message}
${detailsHtml} `; if (data.upgraded > 0 || data.downgraded > 0) { setTimeout(() => location.reload(), 3000); } } else { resultIcon.textContent = '✗'; resultIcon.className = 'modal-icon error'; resultTitle.textContent = 'Wystąpił błąd'; resultStats.innerHTML = `${data.error}
`; btn.disabled = false; btn.querySelector('.stat-label').textContent = 'Re-ewaluuj niskie oceny'; } } catch (error) { clearInterval(progressInterval); document.getElementById('aiEvalProgress').style.display = 'none'; document.getElementById('aiEvalResult').style.display = 'block'; const resultIcon = document.getElementById('aiResultIcon'); const resultTitle = document.getElementById('aiResultTitle'); const resultStats = document.getElementById('aiResultStats'); resultIcon.textContent = '✗'; resultIcon.className = 'modal-icon error'; resultTitle.textContent = 'Błąd połączenia'; resultStats.innerHTML = `${error.message}
`; btn.disabled = false; btn.querySelector('.stat-label').textContent = 'Re-ewaluuj niskie oceny'; } } // Close modal on click outside document.getElementById('aiEvalModal').addEventListener('click', function(e) { if (e.target === this) { closeAiEvalModal(); } }); // Source names mapping for progress display const SOURCE_NAMES = { 'brave': '🔍 Brave Search API', 'trojmiasto': '📰 trojmiasto.pl', 'dziennik_baltycki': '📰 Dziennik Bałtycki', 'gov_mon': '🏛️ Ministerstwo Obrony Narodowej', 'gov_przemysl': '🏛️ Min. Rozwoju i Technologii', 'google_news_zopk': '📡 Google News (ZOP Kaszubia)', 'google_news_offshore': '📡 Google News (offshore)', 'google_news_nuclear': '📡 Google News (elektrownia jądrowa)', 'google_news_samsonowicz': '📡 Google News (Samsonowicz)', 'google_news_kongsberg': '📡 Google News (Kongsberg)', // New local media sources 'google_news_norda_fm': '📻 Norda FM', 'google_news_ttm': '📺 Twoja Telewizja Morska', 'google_news_nadmorski24': '📰 Nadmorski24.pl', 'google_news_samsonowicz_fb': '👤 Facebook (Samsonowicz)', 'google_news_norda': '📡 Google News (Norda Biznes)', 'google_news_spoko': '📡 Google News (Spoko Gospodarcze)' }; const ALL_SOURCES = Object.keys(SOURCE_NAMES); async function searchNews() { const btn = document.getElementById('searchBtn'); const progressContainer = document.getElementById('progressContainer'); const progressBar = document.getElementById('progressBar'); const progressStatus = document.getElementById('progressStatus'); const progressPercent = document.getElementById('progressPercent'); const progressPhases = document.getElementById('progressPhases'); const progressSteps = document.getElementById('progressSteps'); const resultsContainer = document.getElementById('searchResultsContainer'); const resultsSummary = document.getElementById('searchResultsSummary'); const autoApprovedSection = document.getElementById('autoApprovedSection'); const autoApprovedList = document.getElementById('autoApprovedList'); const query = document.getElementById('searchQuery').value; // Process phases definition const PHASES = [ { id: 'search', icon: '🔍', label: 'Wyszukiwanie' }, { id: 'filter', icon: '🚫', label: 'Filtrowanie' }, { id: 'ai', icon: '🤖', label: 'Analiza AI' }, { id: 'save', icon: '💾', label: 'Zapisywanie' } ]; // Reset UI btn.disabled = true; btn.textContent = 'Szukam...'; resultsContainer.style.display = 'none'; autoApprovedSection.style.display = 'none'; progressContainer.classList.add('active'); progressBar.style.width = '0%'; progressBar.style.background = ''; // Reset color progressPercent.textContent = '0%'; // Build progress phases UI progressPhases.innerHTML = PHASES.map(phase => `