Viele Änderungen

This commit is contained in:
RubenRWU
2026-04-07 15:08:56 +02:00
parent b4e78206ed
commit d1866508ca
12 changed files with 1130 additions and 422 deletions

View File

@@ -277,6 +277,36 @@ body {
.btn-send:not(:disabled):hover { background: #d8d8d8; }
.btn-send.success { background: var(--green); color: #000; }
.notice-stack {
position: fixed;
top: 18px;
right: 18px;
z-index: 300;
display: flex;
flex-direction: column;
gap: 10px;
width: min(420px, calc(100vw - 24px));
}
.notice {
padding: 14px 16px;
border-radius: var(--radius);
border: 1px solid var(--border2);
background: rgba(17,17,20,.96);
box-shadow: var(--shadow-lg);
color: var(--text);
line-height: 1.5;
animation: notice-in .18s ease;
}
.notice.info { border-color: #3f3f46; }
.notice.error { border-color: rgba(248,113,113,.55); }
@keyframes notice-in {
from { opacity: 0; transform: translateY(-6px); }
to { opacity: 1; transform: translateY(0); }
}
/* ═══════════════════════════════════════════
PROGRESS STEPS
═══════════════════════════════════════════ */
@@ -566,6 +596,8 @@ body {
</head>
<body>
<div class="notice-stack" id="noticeStack"></div>
<!-- ══════════════════════════════════════════
UPLOAD SCREEN
══════════════════════════════════════════ -->
@@ -670,7 +702,7 @@ body {
<div class="review-footer">
<input type="text" class="title-input" id="titleInput" placeholder="Meeting-Titel…">
<div class="email-chip-field" id="emailChipField">
<input class="email-chip-input" id="emailChipInput" placeholder="E-Mail, Enter oder ","">
<input class="email-chip-input" id="emailChipInput" placeholder="E-Mail, Enter oder ,">
</div>
<button class="btn btn-send" id="sendBtn">Senden</button>
</div>
@@ -795,6 +827,7 @@ const deleteModalSub = document.getElementById('deleteModalSub');
const deleteReplSel = document.getElementById('deleteReplSel');
const deleteCancelBtn = document.getElementById('deleteCancelBtn');
const deleteConfirmBtn= document.getElementById('deleteConfirmBtn');
const noticeStack = document.getElementById('noticeStack');
// ═══════════════════════════════════════════
// INIT
@@ -964,8 +997,8 @@ function updateTimer() {
// ═══════════════════════════════════════════
// NEW / RESET
// ═══════════════════════════════════════════
function resetApp() {
if (!confirm('Wirklich neu starten? Alle Daten gehen verloren.')) return;
function resetApp(requireConfirmation = true) {
if (requireConfirmation && !confirm('Wirklich neu starten? Alle Daten gehen verloren.')) return;
stopRecording();
clearAll();
state = { screen:'upload', inputMode:null, uploadedFileName:'', uploadedFileSize:0,
@@ -980,6 +1013,7 @@ function resetApp() {
transcribeBtn.disabled = true;
transcribeBtn.textContent = 'Transkribieren';
sendBtn.textContent = 'Senden';
sendBtn.classList.remove('success');
sendBtn.style.background = ''; sendBtn.style.color = '';
sendBtn.disabled = false;
[1,2,3].forEach(n => setStep(n, null));
@@ -997,6 +1031,14 @@ function setStep(n, s) {
if (s) el.classList.add(s);
}
function showNotice(message, kind = 'info', timeout = 6000) {
const notice = document.createElement('div');
notice.className = `notice ${kind}`;
notice.textContent = message;
noticeStack.appendChild(notice);
window.setTimeout(() => notice.remove(), timeout);
}
// ═══════════════════════════════════════════
// API
// ═══════════════════════════════════════════
@@ -1005,11 +1047,8 @@ async function api(url, init) {
if (!r.ok) throw new Error(await r.text());
return r.json();
}
const apiUpload = (blob, name) => { const fd=new FormData(); fd.append('file',blob,name); return api('/upload',{method:'POST',body:fd}); };
const apiTranscribe = id => api('/transcribe',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({file_id:id})});
const apiProcess = text => { const fd=new FormData(); fd.append('text',text); return api('/process',{method:'POST',body:fd}); };
const apiSummarize = (transcript, title) => { const fd=new FormData(); fd.append('transcript',transcript); fd.append('title',title); return api('/summarize',{method:'POST',body:fd}); };
const apiSend = (email,title,sum,tr) => { const fd=new FormData(); fd.append('email',email); fd.append('title',title); fd.append('summary',sum); fd.append('transcript',tr); return api('/send',{method:'POST',body:fd}); };
const apiTranscribe = (blob, name) => { const fd=new FormData(); fd.append('file',blob,name); return api('/transcribe',{method:'POST',body:fd}); };
const apiSend = (emails,title,tr) => { const fd=new FormData(); fd.append('emails',emails.join(',')); fd.append('title',title); fd.append('transcript',tr); return api('/send',{method:'POST',body:fd}); };
// ═══════════════════════════════════════════
// TRANSCRIBE FLOW
@@ -1019,27 +1058,28 @@ transcribeBtn.addEventListener('click', async () => {
transcribeBtn.textContent = 'Verarbeitung…';
try {
setStep(1,'active');
const up = await apiUpload(audioBlob, state.uploadedFileName || 'audio.webm');
const trPromise = apiTranscribe(audioBlob, state.uploadedFileName || 'audio.webm');
setStep(1,'completed');
setStep(2,'active');
const tr = await apiTranscribe(up.file_id);
const tr = await trPromise;
setStep(2,'completed');
setStep(3,'active');
const pr = await apiProcess(tr.transcription);
setStep(3,'completed');
state.segments = parseTranscript(pr.processed);
state.segments = parseTranscript(tr.transcription);
buildSpeakersFromSegments();
state.screen = 'review';
await saveState();
showReview();
} catch(err) {
console.error(err);
setStep(1,'error');
if (document.getElementById('step2').classList.contains('active')) setStep(2,'error');
else setStep(1,'error');
transcribeBtn.disabled = false;
transcribeBtn.textContent = 'Transkribieren';
showNotice('Die Transkription konnte nicht gestartet oder abgeschlossen werden.', 'error');
}
});
@@ -1287,19 +1327,16 @@ sendBtn.addEventListener('click', async () => {
const title = titleInput.value.trim() || 'Meeting';
try {
sendBtn.textContent = 'Zusammenfassung…';
const { summary } = await apiSummarize(transcript, title);
state.summary = summary; await saveState();
sendBtn.textContent = 'Senden…';
await Promise.all(emails.map(email => apiSend(email, title, summary, transcript)));
sendBtn.textContent = emails.length > 1 ? `Gesendet (${emails.length})` : 'Gesendet';
sendBtn.classList.add('success');
sendBtn.textContent = 'Wird gestartet…';
await apiSend(emails, title, transcript);
showNotice('Ihr Dokument wird jetzt bearbeitet und schon bald verschickt. Sie koennen direkt ein neues Meeting starten.');
resetApp(false);
} catch(err) {
console.error(err);
sendBtn.disabled = false;
sendBtn.classList.remove('success');
sendBtn.textContent = 'Fehler erneut versuchen';
showNotice('Der Versand konnte nicht gestartet werden. Bitte erneut versuchen.', 'error');
setTimeout(() => { sendBtn.textContent='Senden'; }, 3000);
}
});