"""Tab 3 - Processing: Instructions/Notes editieren, KI-Zusammenfassung anstoßen. Ausgegraut, solange kein Transkript existiert (siehe MainWindow-Tab-Aktivierungslogik). """ from __future__ import annotations import logging from PySide6.QtCore import Signal from PySide6.QtWidgets import QHBoxLayout, QLabel, QMessageBox, QPushButton, QTextEdit, QVBoxLayout, QWidget from notarius.gui.controller import AppController from notarius.gui.format_utils import format_duration, format_timestamp from notarius.keyring_store import get_api_key from notarius.models.recording import Recording from notarius.summarization.worker import SummarizationWorker logger = logging.getLogger(__name__) class ProcessingTab(QWidget): # MainWindow öffnet daraufhin automatisch Tab 4 und prüft die Tab-Aktivierung neu. summarization_finished = Signal() def __init__(self, controller: AppController, parent: QWidget | None = None) -> None: super().__init__(parent) self._controller = controller self._recording: Recording | None = None self._worker = SummarizationWorker() self._header_label = QLabel() self._header_label.setWordWrap(True) self._notes_edit = QTextEdit() self._notes_edit.setPlaceholderText( "Zusatzinfos für die KI: Zuordnung SPEAKER_00 -> Name, Projektkontext, " "Teilnehmer, Kanal, Datum, ..." ) self._notes_save_button = QPushButton("Save") self._notes_save_button.clicked.connect(self._on_notes_save_clicked) self._summarize_button = QPushButton("Summarize") self._summarize_button.clicked.connect(self._on_summarize_clicked) self._status_label = QLabel("idle") action_row = QHBoxLayout() action_row.addWidget(self._summarize_button) action_row.addWidget(self._status_label) action_row.addStretch(1) layout = QVBoxLayout(self) layout.addWidget(self._header_label) layout.addWidget(QLabel("Instructions and Notes")) layout.addWidget(self._notes_edit, stretch=1) layout.addWidget(self._notes_save_button) layout.addLayout(action_row) self.set_recording(None) def set_recording(self, recording: Recording | None) -> None: self._recording = recording has_recording = recording is not None self.setEnabled(has_recording) if not has_recording: return self._header_label.setText( f"Titel: {recording.meta.title}
" f"Aufzeichnungszeitpunkt: {format_timestamp(recording.meta.created_at)}
" f"Länge: {format_duration(recording.meta.duration_seconds)}
" f"Sprecher: {', '.join(recording.meta.speakers) or '-'}" ) if recording.prompt_notes_path.exists(): self._notes_edit.setPlainText(recording.prompt_notes_path.read_text(encoding="utf-8")) else: self._notes_edit.clear() self._status_label.setText("ready" if recording.has_summary else "idle") self._summarize_button.setText("Summarize") self._summarize_button.setEnabled(True) def _on_notes_save_clicked(self) -> None: if self._recording is None: return self._recording.prompt_notes_path.write_text(self._notes_edit.toPlainText(), encoding="utf-8") def _on_summarize_clicked(self) -> None: if self._worker.is_running: self._worker.cancel() return if self._recording is None: return api_key = get_api_key() if not api_key: QMessageBox.information( self, "Kein API-Key", "Bitte zuerst in Tab 5 (Settings) einen Anthropic-API-Key hinterlegen." ) return if self._recording.has_summary: answer = QMessageBox.question( self, "Summary überschreiben?", "Es existiert bereits eine Summary. Überschreiben?" ) if answer != QMessageBox.StandardButton.Yes: return transcript_markdown = self._recording.transcript_path.read_text(encoding="utf-8") notes = self._notes_edit.toPlainText() self._summarize_button.setText("Stop") self._status_label.setText("processing") self._worker.start( api_key, self._controller.config.claude_model, transcript_markdown, notes, self._on_summary_ok, self._on_summary_error, self._on_summary_cancelled, ) def _on_summary_ok(self, summary_markdown: str) -> None: if self._recording is None: return self._recording.summary_path.write_text(summary_markdown, encoding="utf-8") self._summarize_button.setText("Summarize") self._status_label.setText("ready") self.summarization_finished.emit() def _on_summary_error(self, error_message: str) -> None: self._summarize_button.setText("Summarize") self._status_label.setText("error") QMessageBox.critical(self, "Zusammenfassung fehlgeschlagen", error_message) def _on_summary_cancelled(self) -> None: self._summarize_button.setText("Summarize") self._status_label.setText("idle")