fix: Job-Polling vor Redirect statt sofortigem Antrag-nicht-gefunden
Vorher: Klick 'Analysieren' -> POST /api/analyze-drucksache -> sofort
window.location.href = '/antrag/{ds}' -> aber Job laeuft noch im Hintergrund
-> Detail-Seite zeigt 'Antrag nicht gefunden'.
Jetzt:
- already_checked -> sofortiger Redirect
- skipped (nicht abstimmbar) -> Hinweistext im Form
- queued -> Polling auf /status/{job_id} alle 2s, max 3 Min
- completed -> Redirect zur Detail-Seite
- failed/rejected -> Fehlermeldung mit Grund
Anwendung in v2/screens/landtag_suche.html + v2/screens/neu.html.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c38bca615d
commit
38bffb23fa
@ -292,9 +292,40 @@ async function lsAnalyse(btn, drucksache, bundesland) {
|
||||
}
|
||||
var data = await resp.json();
|
||||
var ds = data.drucksache || drucksache;
|
||||
// Backend gibt {job_id, drucksache} zurück (Queue) — nicht direkt redirecten,
|
||||
// sondern auf /antrag/{ds} gehen, dort wird dann ggf. der Polling-Status sichtbar
|
||||
|
||||
// Falls bereits bewertet oder skipped: direkt redirecten
|
||||
if (data.status === 'already_checked') {
|
||||
window.location.href = '/antrag/' + encodeURIComponent(ds);
|
||||
return;
|
||||
}
|
||||
if (data.status === 'skipped') {
|
||||
btn.textContent = 'Übersprungen';
|
||||
btn.title = 'Typ "' + (data.typ || 'unbekannt') + '" ist nicht abstimmbar';
|
||||
return;
|
||||
}
|
||||
|
||||
// Sonst Job-Polling bis fertig, dann redirect
|
||||
btn.textContent = 'Analysiere…';
|
||||
var jobId = data.job_id;
|
||||
if (!jobId) { window.location.href = '/antrag/' + encodeURIComponent(ds); return; }
|
||||
|
||||
var attempts = 0;
|
||||
var maxAttempts = 90; // 90 × 2s = 3 min
|
||||
while (attempts < maxAttempts) {
|
||||
await new Promise(function (r) { setTimeout(r, 2000); });
|
||||
attempts++;
|
||||
var st = await fetch('/status/' + jobId).then(function (r) { return r.json(); }).catch(function () { return null; });
|
||||
if (!st) continue;
|
||||
if (st.status === 'completed') {
|
||||
window.location.href = '/antrag/' + encodeURIComponent(ds);
|
||||
return;
|
||||
}
|
||||
if (st.status === 'failed' || st.status === 'rejected') {
|
||||
throw new Error('Analyse fehlgeschlagen: ' + (st.error || 'unbekannt'));
|
||||
}
|
||||
btn.textContent = 'Analysiere… (' + (st.status || '...') + ')';
|
||||
}
|
||||
throw new Error('Analyse-Timeout (>3 min)');
|
||||
} catch (err) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Fehler';
|
||||
|
||||
@ -154,16 +154,56 @@ async function startAnalyse(e) {
|
||||
if (model) fd.append('model', model);
|
||||
|
||||
const resp = await fetch('/api/analyze-drucksache', { method: 'POST', body: fd });
|
||||
if (resp.status === 401 || resp.status === 403) {
|
||||
progEl.style.display = 'none';
|
||||
errEl.style.display = '';
|
||||
errEl.textContent = 'Sitzung abgelaufen — bitte erneut anmelden.';
|
||||
btn.disabled = false;
|
||||
if (typeof window.v2AuthModalOpen === 'function') window.v2AuthModalOpen();
|
||||
return;
|
||||
}
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json().catch(() => ({ detail: resp.statusText }));
|
||||
throw new Error(err.detail || ('HTTP ' + resp.status));
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
// Redirect to result page
|
||||
const ds = data.drucksache || drucksache;
|
||||
progText.textContent = 'Analyse abgeschlossen. Weiterleitung …';
|
||||
setTimeout(() => { window.location.href = '/antrag/' + encodeURIComponent(ds); }, 600);
|
||||
|
||||
if (data.status === 'already_checked') {
|
||||
progText.textContent = 'Bereits bewertet. Weiterleitung …';
|
||||
setTimeout(() => { window.location.href = '/antrag/' + encodeURIComponent(ds); }, 400);
|
||||
return;
|
||||
}
|
||||
if (data.status === 'skipped') {
|
||||
progEl.style.display = 'none';
|
||||
errEl.style.display = '';
|
||||
errEl.textContent = 'Antrag-Typ "' + (data.typ || 'unbekannt') + '" ist nicht abstimmbar — keine GWÖ-Bewertung sinnvoll.';
|
||||
btn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Job-Polling bis Abschluss, dann redirect
|
||||
const jobId = data.job_id;
|
||||
if (!jobId) { window.location.href = '/antrag/' + encodeURIComponent(ds); return; }
|
||||
let attempts = 0;
|
||||
const maxAttempts = 90;
|
||||
while (attempts < maxAttempts) {
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
attempts++;
|
||||
const st = await fetch('/status/' + jobId).then(r => r.json()).catch(() => null);
|
||||
if (!st) continue;
|
||||
progText.textContent = 'Analyse läuft … (' + (st.status || '?') + ', ~' + (attempts * 2) + 's)';
|
||||
if (st.status === 'completed') {
|
||||
progText.textContent = 'Fertig. Weiterleitung …';
|
||||
setTimeout(() => { window.location.href = '/antrag/' + encodeURIComponent(ds); }, 400);
|
||||
return;
|
||||
}
|
||||
if (st.status === 'failed' || st.status === 'rejected') {
|
||||
throw new Error('Analyse fehlgeschlagen: ' + (st.error || 'unbekannt'));
|
||||
}
|
||||
}
|
||||
throw new Error('Analyse-Timeout (>3 min)');
|
||||
|
||||
} catch (err) {
|
||||
progEl.style.display = 'none';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user