Initialer Push, Grundsätzlich funktioniert das Programm
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
"""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("<b>Instructions and Notes</b>"))
|
||||
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"<b>Titel:</b> {recording.meta.title}<br>"
|
||||
f"<b>Aufzeichnungszeitpunkt:</b> {format_timestamp(recording.meta.created_at)}<br>"
|
||||
f"<b>Länge:</b> {format_duration(recording.meta.duration_seconds)}<br>"
|
||||
f"<b>Sprecher:</b> {', '.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")
|
||||
Reference in New Issue
Block a user