mirror of
https://github.com/chidiwilliams/buzz.git
synced 2024-06-03 00:12:14 +02:00
add transcript viewer (#686)
This commit is contained in:
parent
8ae8300afc
commit
ba522a58cd
|
@ -1,6 +1,6 @@
|
|||
# Adapted from https://github.com/zhiyiYo/Groove
|
||||
from abc import ABC
|
||||
from typing import TypeVar, Generic, Any, Type
|
||||
from typing import TypeVar, Generic, Any, Type, List
|
||||
|
||||
from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlRecord
|
||||
|
||||
|
@ -11,6 +11,7 @@ T = TypeVar("T", bound=Entity)
|
|||
|
||||
class DAO(ABC, Generic[T]):
|
||||
entity: Type[T]
|
||||
ignore_fields = []
|
||||
|
||||
def __init__(self, table: str, db: QSqlDatabase):
|
||||
self.db = db
|
||||
|
@ -18,15 +19,18 @@ class DAO(ABC, Generic[T]):
|
|||
|
||||
def insert(self, record: T):
|
||||
query = self._create_query()
|
||||
keys = record.__dict__.keys()
|
||||
fields = [
|
||||
field for field in record.__dict__.keys() if field not in self.ignore_fields
|
||||
]
|
||||
query.prepare(
|
||||
f"""
|
||||
INSERT INTO {self.table} ({", ".join(keys)})
|
||||
VALUES ({", ".join([f":{key}" for key in keys])})
|
||||
INSERT INTO {self.table} ({", ".join(fields)})
|
||||
VALUES ({", ".join([f":{key}" for key in fields])})
|
||||
"""
|
||||
)
|
||||
for key, value in record.__dict__.items():
|
||||
query.bindValue(f":{key}", value)
|
||||
for field in fields:
|
||||
query.bindValue(f":{field}", getattr(record, field))
|
||||
|
||||
if not query.exec():
|
||||
raise Exception(query.lastError().text())
|
||||
|
||||
|
@ -37,10 +41,8 @@ class DAO(ABC, Generic[T]):
|
|||
return self._execute(query)
|
||||
|
||||
def to_entity(self, record: QSqlRecord) -> T:
|
||||
entity = self.entity()
|
||||
for i in range(record.count()):
|
||||
setattr(entity, record.fieldName(i), record.value(i))
|
||||
return entity
|
||||
kwargs = {record.fieldName(i): record.value(i) for i in range(record.count())}
|
||||
return self.entity(**kwargs)
|
||||
|
||||
def _execute(self, query: QSqlQuery) -> T | None:
|
||||
if not query.exec():
|
||||
|
@ -49,5 +51,13 @@ class DAO(ABC, Generic[T]):
|
|||
return None
|
||||
return self.to_entity(query.record())
|
||||
|
||||
def _execute_all(self, query: QSqlQuery) -> List[T]:
|
||||
if not query.exec():
|
||||
raise Exception(query.lastError().text())
|
||||
entities = []
|
||||
while query.next():
|
||||
entities.append(self.to_entity(query.record()))
|
||||
return entities
|
||||
|
||||
def _create_query(self):
|
||||
return QSqlQuery(self.db)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from typing import List
|
||||
from uuid import UUID
|
||||
|
||||
from PyQt6.QtSql import QSqlDatabase
|
||||
|
||||
from buzz.db.dao.dao import DAO
|
||||
|
@ -6,6 +9,18 @@ from buzz.db.entity.transcription_segment import TranscriptionSegment
|
|||
|
||||
class TranscriptionSegmentDAO(DAO[TranscriptionSegment]):
|
||||
entity = TranscriptionSegment
|
||||
ignore_fields = ["id"]
|
||||
|
||||
def __init__(self, db: QSqlDatabase):
|
||||
super().__init__("transcription_segment", db)
|
||||
|
||||
def get_segments(self, transcription_id: UUID) -> List[TranscriptionSegment]:
|
||||
query = self._create_query()
|
||||
query.prepare(
|
||||
f"""
|
||||
SELECT * FROM {self.table}
|
||||
WHERE transcription_id = :transcription_id
|
||||
"""
|
||||
)
|
||||
query.bindValue(":transcription_id", str(transcription_id))
|
||||
return self._execute_all(query)
|
||||
|
|
|
@ -20,6 +20,13 @@ class Transcription(Entity):
|
|||
error_message: str | None = None
|
||||
file: str | None = None
|
||||
time_queued: str = datetime.datetime.now().isoformat()
|
||||
progress: float = 0.0
|
||||
time_ended: str | None = None
|
||||
time_started: str | None = None
|
||||
export_formats: str | None = None
|
||||
output_folder: str | None = None
|
||||
source: str | None = None
|
||||
url: str | None = None
|
||||
|
||||
@property
|
||||
def id_as_uuid(self):
|
||||
|
|
|
@ -9,3 +9,4 @@ class TranscriptionSegment(Entity):
|
|||
end_time: int
|
||||
text: str
|
||||
transcription_id: str
|
||||
id: int = -1
|
||||
|
|
|
@ -42,3 +42,6 @@ class TranscriptionService:
|
|||
transcription_id=str(id),
|
||||
)
|
||||
)
|
||||
|
||||
def get_transcription_segments(self, transcription_id: UUID):
|
||||
return self.transcription_segment_dao.get_segments(transcription_id)
|
||||
|
|
|
@ -7,8 +7,8 @@ APP_NAME = "Buzz"
|
|||
|
||||
|
||||
class Settings:
|
||||
def __init__(self):
|
||||
self.settings = QSettings(APP_NAME)
|
||||
def __init__(self, application=""):
|
||||
self.settings = QSettings(APP_NAME, application)
|
||||
self.settings.sync()
|
||||
|
||||
class Key(enum.Enum):
|
||||
|
|
|
@ -18,7 +18,9 @@ class Shortcut(str, enum.Enum):
|
|||
OPEN_IMPORT_URL_WINDOW = ("Ctrl+U", "Import URL")
|
||||
OPEN_PREFERENCES_WINDOW = ("Ctrl+,", "Open Preferences Window")
|
||||
|
||||
OPEN_TRANSCRIPT_EDITOR = ("Ctrl+E", "Open Transcript Viewer")
|
||||
VIEW_TRANSCRIPT_TEXT = ("Ctrl+E", "View Transcript Text")
|
||||
VIEW_TRANSCRIPT_TIMESTAMPS = ("Ctrl+T", "View Transcript Timestamps")
|
||||
|
||||
CLEAR_HISTORY = ("Ctrl+S", "Clear History")
|
||||
STOP_TRANSCRIPTION = ("Ctrl+X", "Cancel Transcription")
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import typing
|
||||
|
||||
from buzz.settings.settings import Settings
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
|
||||
|
||||
class ShortcutSettings:
|
||||
def __init__(self, settings: Settings):
|
||||
self.settings = settings
|
||||
|
||||
def load(self) -> typing.Dict[str, str]:
|
||||
shortcuts = Shortcut.get_default_shortcuts()
|
||||
custom_shortcuts: typing.Dict[str, str] = self.settings.value(
|
||||
Settings.Key.SHORTCUTS, {}
|
||||
)
|
||||
for shortcut_name in custom_shortcuts:
|
||||
shortcuts[shortcut_name] = custom_shortcuts[shortcut_name]
|
||||
return shortcuts
|
||||
|
||||
def save(self, shortcuts: typing.Dict[str, str]) -> None:
|
||||
self.settings.set_value(Settings.Key.SHORTCUTS, shortcuts)
|
24
buzz/settings/shortcuts.py
Normal file
24
buzz/settings/shortcuts.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
import typing
|
||||
|
||||
from buzz.settings.settings import Settings
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
|
||||
|
||||
class Shortcuts:
|
||||
def __init__(self, settings: Settings):
|
||||
self.settings = settings
|
||||
|
||||
def get(self, shortcut: Shortcut) -> str:
|
||||
custom_shortcuts = self.get_custom_shortcuts()
|
||||
return custom_shortcuts.get(shortcut.name, shortcut.sequence)
|
||||
|
||||
def set(self, shortcut: Shortcut, sequence: str) -> None:
|
||||
custom_shortcuts = self.get_custom_shortcuts()
|
||||
custom_shortcuts[shortcut.name] = sequence
|
||||
self.settings.set_value(Settings.Key.SHORTCUTS, custom_shortcuts)
|
||||
|
||||
def clear(self) -> None:
|
||||
self.settings.set_value(Settings.Key.SHORTCUTS, {})
|
||||
|
||||
def get_custom_shortcuts(self) -> typing.Dict[str, str]:
|
||||
return self.settings.value(Settings.Key.SHORTCUTS, {})
|
|
@ -102,6 +102,7 @@ class FileTranscriber(QObject):
|
|||
...
|
||||
|
||||
|
||||
# TODO: Move to transcription service
|
||||
def write_output(path: str, segments: List[Segment], output_format: OutputFormat):
|
||||
logging.debug(
|
||||
"Writing transcription output, path = %s, output format = %s, number of segments = %s",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import sys
|
||||
|
||||
from PyQt6.QtGui import QFont
|
||||
from PyQt6.QtWidgets import QApplication
|
||||
|
||||
from buzz.__version__ import VERSION
|
||||
|
@ -22,7 +23,7 @@ class Application(QApplication):
|
|||
self.setApplicationVersion(VERSION)
|
||||
|
||||
if sys.platform == "darwin":
|
||||
self.setStyle("Fusion")
|
||||
self.setFont(QFont("SF Pro", self.font().pointSize()))
|
||||
|
||||
db = setup_app_db()
|
||||
transcription_service = TranscriptionService(
|
||||
|
|
|
@ -74,6 +74,13 @@ class FileDownloadIcon(Icon):
|
|||
super().__init__(get_path("assets/file_download_black_24dp.svg"), parent)
|
||||
|
||||
|
||||
class VisibilityIcon(Icon):
|
||||
def __init__(self, parent: QWidget):
|
||||
super().__init__(
|
||||
get_path("assets/visibility_FILL0_wght700_GRAD0_opsz48.svg"), parent
|
||||
)
|
||||
|
||||
|
||||
BUZZ_ICON_PATH = get_path("assets/buzz.ico")
|
||||
BUZZ_LARGE_ICON_PATH = get_path("assets/buzz-icon-1024.png")
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from buzz.db.service.transcription_service import TranscriptionService
|
|||
from buzz.file_transcriber_queue_worker import FileTranscriberQueueWorker
|
||||
from buzz.locale import _
|
||||
from buzz.settings.settings import APP_NAME, Settings
|
||||
from buzz.settings.shortcut_settings import ShortcutSettings
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.store.keyring_store import set_password, Key
|
||||
from buzz.transcriber.transcriber import (
|
||||
FileTranscriptionTask,
|
||||
|
@ -59,8 +59,7 @@ class MainWindow(QMainWindow):
|
|||
|
||||
self.settings = Settings()
|
||||
|
||||
self.shortcut_settings = ShortcutSettings(settings=self.settings)
|
||||
self.shortcuts = self.shortcut_settings.load()
|
||||
self.shortcuts = Shortcuts(settings=self.settings)
|
||||
|
||||
self.transcription_service = transcription_service
|
||||
|
||||
|
@ -326,7 +325,11 @@ class MainWindow(QMainWindow):
|
|||
|
||||
def open_transcription_viewer(self, transcription: Transcription):
|
||||
transcription_viewer_widget = TranscriptionViewerWidget(
|
||||
transcription=transcription, parent=self, flags=Qt.WindowType.Window
|
||||
transcription=transcription,
|
||||
transcription_service=self.transcription_service,
|
||||
shortcuts=self.shortcuts,
|
||||
parent=self,
|
||||
flags=Qt.WindowType.Window,
|
||||
)
|
||||
transcription_viewer_widget.show()
|
||||
|
||||
|
@ -354,15 +357,12 @@ class MainWindow(QMainWindow):
|
|||
self.table_widget.refresh_row(task.uid)
|
||||
|
||||
def on_task_error(self, task: FileTranscriptionTask, error: str):
|
||||
logging.debug("FAILED!!!!")
|
||||
self.transcription_service.update_transcription_as_failed(task.uid, error)
|
||||
self.table_widget.refresh_row(task.uid)
|
||||
|
||||
def on_shortcuts_changed(self, shortcuts: dict):
|
||||
self.shortcuts = shortcuts
|
||||
self.menu_bar.set_shortcuts(shortcuts=self.shortcuts)
|
||||
self.toolbar.set_shortcuts(shortcuts=self.shortcuts)
|
||||
self.shortcut_settings.save(shortcuts=self.shortcuts)
|
||||
def on_shortcuts_changed(self):
|
||||
self.menu_bar.reset_shortcuts()
|
||||
self.toolbar.reset_shortcuts()
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self.save_geometry()
|
||||
|
@ -373,7 +373,6 @@ class MainWindow(QMainWindow):
|
|||
self.transcriber_worker.stop()
|
||||
self.transcriber_thread.quit()
|
||||
self.transcriber_thread.wait()
|
||||
self.shortcut_settings.save(shortcuts=self.shortcuts)
|
||||
super().closeEvent(event)
|
||||
|
||||
def save_geometry(self):
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
from typing import Dict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from PyQt6.QtCore import pyqtSignal, Qt
|
||||
from PyQt6.QtGui import QKeySequence
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
|
||||
from buzz.action import Action
|
||||
from buzz.locale import _
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.icon import Icon
|
||||
from buzz.widgets.icon import (
|
||||
RECORD_ICON_PATH,
|
||||
ADD_ICON_PATH,
|
||||
|
@ -12,9 +16,6 @@ from buzz.widgets.icon import (
|
|||
CANCEL_ICON_PATH,
|
||||
TRASH_ICON_PATH,
|
||||
)
|
||||
from buzz.locale import _
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
from buzz.widgets.icon import Icon
|
||||
from buzz.widgets.recording_transcriber_widget import RecordingTranscriberWidget
|
||||
from buzz.widgets.toolbar import ToolBar
|
||||
|
||||
|
@ -26,9 +27,11 @@ class MainWindowToolbar(ToolBar):
|
|||
ICON_LIGHT_THEME_BACKGROUND = "#555"
|
||||
ICON_DARK_THEME_BACKGROUND = "#AAA"
|
||||
|
||||
def __init__(self, shortcuts: Dict[str, str], parent: Optional[QWidget]):
|
||||
def __init__(self, shortcuts: Shortcuts, parent: Optional[QWidget]):
|
||||
super().__init__(parent)
|
||||
|
||||
self.shortcuts = shortcuts
|
||||
|
||||
self.record_action = Action(Icon(RECORD_ICON_PATH, self), _("Record"), self)
|
||||
self.record_action.triggered.connect(self.on_record_action_triggered)
|
||||
|
||||
|
@ -59,7 +62,7 @@ class MainWindowToolbar(ToolBar):
|
|||
self.clear_history_action_triggered = self.clear_history_action.triggered
|
||||
self.clear_history_action.setDisabled(True)
|
||||
|
||||
self.set_shortcuts(shortcuts)
|
||||
self.reset_shortcuts()
|
||||
|
||||
self.addAction(self.record_action)
|
||||
self.addSeparator()
|
||||
|
@ -74,21 +77,18 @@ class MainWindowToolbar(ToolBar):
|
|||
self.setMovable(False)
|
||||
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||
|
||||
def set_shortcuts(self, shortcuts: Dict[str, str]):
|
||||
def reset_shortcuts(self):
|
||||
self.record_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.OPEN_RECORD_WINDOW.name])
|
||||
QKeySequence.fromString(self.shortcuts.get(Shortcut.OPEN_RECORD_WINDOW))
|
||||
)
|
||||
self.new_transcription_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.OPEN_IMPORT_WINDOW.name])
|
||||
)
|
||||
self.open_transcript_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.OPEN_TRANSCRIPT_EDITOR.name])
|
||||
QKeySequence.fromString(self.shortcuts.get(Shortcut.OPEN_IMPORT_WINDOW))
|
||||
)
|
||||
self.stop_transcription_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.STOP_TRANSCRIPTION.name])
|
||||
QKeySequence.fromString(self.shortcuts.get(Shortcut.STOP_TRANSCRIPTION))
|
||||
)
|
||||
self.clear_history_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.CLEAR_HISTORY.name])
|
||||
QKeySequence.fromString(self.shortcuts.get(Shortcut.CLEAR_HISTORY))
|
||||
)
|
||||
|
||||
def on_record_action_triggered(self):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import webbrowser
|
||||
from typing import Dict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from PyQt6.QtGui import QAction, QKeySequence
|
||||
|
@ -8,6 +8,7 @@ from PyQt6.QtWidgets import QMenuBar, QWidget
|
|||
from buzz.locale import _
|
||||
from buzz.settings.settings import APP_NAME
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.about_dialog import AboutDialog
|
||||
from buzz.widgets.preferences_dialog.models.preferences import Preferences
|
||||
from buzz.widgets.preferences_dialog.preferences_dialog import (
|
||||
|
@ -18,14 +19,14 @@ from buzz.widgets.preferences_dialog.preferences_dialog import (
|
|||
class MenuBar(QMenuBar):
|
||||
import_action_triggered = pyqtSignal()
|
||||
import_url_action_triggered = pyqtSignal()
|
||||
shortcuts_changed = pyqtSignal(dict)
|
||||
shortcuts_changed = pyqtSignal()
|
||||
openai_api_key_changed = pyqtSignal(str)
|
||||
preferences_changed = pyqtSignal(Preferences)
|
||||
preferences_dialog: Optional[PreferencesDialog] = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
shortcuts: Dict[str, str],
|
||||
shortcuts: Shortcuts,
|
||||
preferences: Preferences,
|
||||
parent: Optional[QWidget] = None,
|
||||
):
|
||||
|
@ -49,7 +50,7 @@ class MenuBar(QMenuBar):
|
|||
help_action = QAction(f'{_("Help")}', self)
|
||||
help_action.triggered.connect(self.on_help_action_triggered)
|
||||
|
||||
self.set_shortcuts(shortcuts)
|
||||
self.reset_shortcuts()
|
||||
|
||||
file_menu = self.addMenu(_("File"))
|
||||
file_menu.addAction(self.import_action)
|
||||
|
@ -86,15 +87,15 @@ class MenuBar(QMenuBar):
|
|||
def on_help_action_triggered(self):
|
||||
webbrowser.open("https://chidiwilliams.github.io/buzz/docs")
|
||||
|
||||
def set_shortcuts(self, shortcuts: Dict[str, str]):
|
||||
self.shortcuts = shortcuts
|
||||
|
||||
def reset_shortcuts(self):
|
||||
self.import_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.OPEN_IMPORT_WINDOW.name])
|
||||
QKeySequence.fromString(self.shortcuts.get(Shortcut.OPEN_IMPORT_WINDOW))
|
||||
)
|
||||
self.import_url_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.OPEN_IMPORT_URL_WINDOW.name])
|
||||
QKeySequence.fromString(self.shortcuts.get(Shortcut.OPEN_IMPORT_URL_WINDOW))
|
||||
)
|
||||
self.preferences_action.setShortcut(
|
||||
QKeySequence.fromString(shortcuts[Shortcut.OPEN_PREFERENCES_WINDOW.name])
|
||||
QKeySequence.fromString(
|
||||
self.shortcuts.get(Shortcut.OPEN_PREFERENCES_WINDOW)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ from PyQt6.QtCore import pyqtSignal
|
|||
from PyQt6.QtWidgets import QWidget, QLineEdit
|
||||
|
||||
from buzz.assets import get_path
|
||||
from buzz.widgets.icon import Icon
|
||||
from buzz.widgets.icon import Icon, VisibilityIcon
|
||||
from buzz.widgets.line_edit import LineEdit
|
||||
|
||||
|
||||
|
@ -16,9 +16,7 @@ class OpenAIAPIKeyLineEdit(LineEdit):
|
|||
|
||||
self.key = key
|
||||
|
||||
self.visible_on_icon = Icon(
|
||||
get_path("assets/visibility_FILL0_wght700_GRAD0_opsz48.svg"), self
|
||||
)
|
||||
self.visible_on_icon = VisibilityIcon(self)
|
||||
self.visible_off_icon = Icon(
|
||||
get_path("assets/visibility_off_FILL0_wght700_GRAD0_opsz48.svg"), self
|
||||
)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import copy
|
||||
from typing import Dict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from PyQt6.QtWidgets import QDialog, QWidget, QVBoxLayout, QTabWidget, QDialogButtonBox
|
||||
|
||||
from buzz.locale import _
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.preferences_dialog.folder_watch_preferences_widget import (
|
||||
FolderWatchPreferencesWidget,
|
||||
)
|
||||
|
@ -24,15 +25,14 @@ from buzz.widgets.preferences_dialog.shortcuts_editor_preferences_widget import
|
|||
|
||||
|
||||
class PreferencesDialog(QDialog):
|
||||
shortcuts_changed = pyqtSignal(dict)
|
||||
shortcuts_changed = pyqtSignal()
|
||||
openai_api_key_changed = pyqtSignal(str)
|
||||
folder_watch_config_changed = pyqtSignal(FolderWatchPreferences)
|
||||
preferences_changed = pyqtSignal(Preferences)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
# TODO: move shortcuts and default export file name into preferences
|
||||
shortcuts: Dict[str, str],
|
||||
shortcuts: Shortcuts,
|
||||
preferences: Preferences,
|
||||
parent: Optional[QWidget] = None,
|
||||
) -> None:
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
from typing import Optional, Dict
|
||||
from typing import Optional
|
||||
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from PyQt6.QtGui import QKeySequence
|
||||
from PyQt6.QtWidgets import QWidget, QFormLayout, QPushButton
|
||||
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.sequence_edit import SequenceEdit
|
||||
|
||||
|
||||
class ShortcutsEditorPreferencesWidget(QWidget):
|
||||
shortcuts_changed = pyqtSignal(dict)
|
||||
shortcuts_changed = pyqtSignal()
|
||||
|
||||
def __init__(self, shortcuts: Dict[str, str], parent: Optional[QWidget] = None):
|
||||
def __init__(self, shortcuts: Shortcuts, parent: Optional[QWidget] = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.shortcuts = shortcuts
|
||||
|
||||
self.layout = QFormLayout(self)
|
||||
for shortcut in Shortcut:
|
||||
sequence_edit = SequenceEdit(shortcuts.get(shortcut.name, ""), self)
|
||||
sequence_edit = SequenceEdit(shortcuts.get(shortcut), self)
|
||||
sequence_edit.keySequenceChanged.connect(
|
||||
self.get_key_sequence_changed(shortcut.name)
|
||||
self.get_key_sequence_changed(shortcut)
|
||||
)
|
||||
self.layout.addRow(shortcut.description, sequence_edit)
|
||||
|
||||
|
@ -31,21 +32,21 @@ class ShortcutsEditorPreferencesWidget(QWidget):
|
|||
|
||||
self.layout.addWidget(reset_to_defaults_button)
|
||||
|
||||
def get_key_sequence_changed(self, shortcut_name: str):
|
||||
def get_key_sequence_changed(self, shortcut: Shortcut):
|
||||
def key_sequence_changed(sequence: QKeySequence):
|
||||
self.shortcuts[shortcut_name] = sequence.toString()
|
||||
self.shortcuts_changed.emit(self.shortcuts)
|
||||
self.shortcuts.set(shortcut, sequence.toString())
|
||||
self.shortcuts_changed.emit()
|
||||
|
||||
return key_sequence_changed
|
||||
|
||||
def reset_to_defaults(self):
|
||||
self.shortcuts = Shortcut.get_default_shortcuts()
|
||||
self.shortcuts.clear()
|
||||
|
||||
for i, shortcut in enumerate(Shortcut):
|
||||
sequence_edit = self.layout.itemAt(
|
||||
i, QFormLayout.ItemRole.FieldRole
|
||||
).widget()
|
||||
assert isinstance(sequence_edit, SequenceEdit)
|
||||
sequence_edit.setKeySequence(QKeySequence(self.shortcuts[shortcut.name]))
|
||||
sequence_edit.setKeySequence(QKeySequence(self.shortcuts.get(shortcut)))
|
||||
|
||||
self.shortcuts_changed.emit(self.shortcuts)
|
||||
self.shortcuts_changed.emit()
|
||||
|
|
|
@ -14,9 +14,10 @@ class ToolBar(QToolBar):
|
|||
self.setStyleSheet("QToolButton{margin: 6px 3px;}")
|
||||
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||
|
||||
def addAction(self, action: QtGui.QAction) -> None:
|
||||
super().addAction(action)
|
||||
def addAction(self, *args):
|
||||
action = super().addAction(*args)
|
||||
self.fix_spacing_on_mac()
|
||||
return action
|
||||
|
||||
def addActions(self, actions: typing.Iterable[QtGui.QAction]) -> None:
|
||||
super().addActions(actions)
|
||||
|
|
|
@ -187,6 +187,9 @@ class TranscriptionTasksTableWidget(QTableView):
|
|||
self.verticalHeader().hide()
|
||||
self.setAlternatingRowColors(True)
|
||||
|
||||
# Show date added before date completed
|
||||
self.horizontalHeader().swapSections(11, 12)
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
menu = QMenu(self)
|
||||
for definition in column_definitions:
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
from PyQt6.QtCore import pyqtSignal
|
||||
from PyQt6.QtGui import QAction
|
||||
from PyQt6.QtWidgets import QPushButton, QWidget, QMenu
|
||||
|
||||
from buzz.transcriber.transcriber import (
|
||||
OutputFormat,
|
||||
)
|
||||
from buzz.widgets.icon import FileDownloadIcon
|
||||
|
||||
|
||||
class ExportTranscriptionButton(QPushButton):
|
||||
on_export_triggered = pyqtSignal(OutputFormat)
|
||||
|
||||
def __init__(self, parent: QWidget):
|
||||
super().__init__(parent)
|
||||
|
||||
export_button_menu = QMenu()
|
||||
actions = [
|
||||
QAction(text=output_format.value.upper(), parent=self)
|
||||
for output_format in OutputFormat
|
||||
]
|
||||
export_button_menu.addActions(actions)
|
||||
export_button_menu.triggered.connect(self.on_menu_triggered)
|
||||
|
||||
self.setMenu(export_button_menu)
|
||||
self.setIcon(FileDownloadIcon(self))
|
||||
|
||||
def on_menu_triggered(self, action: QAction):
|
||||
output_format = OutputFormat[action.text()]
|
||||
self.on_export_triggered.emit(output_format)
|
|
@ -0,0 +1,61 @@
|
|||
from PyQt6.QtGui import QAction
|
||||
from PyQt6.QtWidgets import QWidget, QMenu, QFileDialog
|
||||
|
||||
from buzz.db.entity.transcription import Transcription
|
||||
from buzz.db.service.transcription_service import TranscriptionService
|
||||
from buzz.locale import _
|
||||
from buzz.transcriber.file_transcriber import write_output
|
||||
from buzz.transcriber.transcriber import (
|
||||
OutputFormat,
|
||||
Segment,
|
||||
)
|
||||
|
||||
|
||||
class ExportTranscriptionMenu(QMenu):
|
||||
def __init__(
|
||||
self,
|
||||
transcription: Transcription,
|
||||
transcription_service: TranscriptionService,
|
||||
parent: QWidget | None = None,
|
||||
):
|
||||
super().__init__(parent)
|
||||
|
||||
self.transcription = transcription
|
||||
self.transcription_service = transcription_service
|
||||
|
||||
actions = [
|
||||
QAction(text=output_format.value.upper(), parent=self)
|
||||
for output_format in OutputFormat
|
||||
]
|
||||
self.addActions(actions)
|
||||
self.triggered.connect(self.on_menu_triggered)
|
||||
|
||||
def on_menu_triggered(self, action: QAction):
|
||||
output_format = OutputFormat[action.text()]
|
||||
|
||||
default_path = self.transcription.get_output_file_path(
|
||||
output_format=output_format
|
||||
)
|
||||
|
||||
(output_file_path, nil) = QFileDialog.getSaveFileName(
|
||||
self,
|
||||
_("Save File"),
|
||||
default_path,
|
||||
_("Text files") + f" (*.{output_format.value})",
|
||||
)
|
||||
|
||||
if output_file_path == "":
|
||||
return
|
||||
|
||||
segments = [
|
||||
Segment(start=segment.start_time, end=segment.end_time, text=segment.text)
|
||||
for segment in self.transcription_service.get_transcription_segments(
|
||||
transcription_id=self.transcription.id_as_uuid
|
||||
)
|
||||
]
|
||||
|
||||
write_output(
|
||||
path=output_file_path,
|
||||
segments=segments,
|
||||
output_format=output_format,
|
||||
)
|
|
@ -90,6 +90,8 @@ class TranscriptionSegmentsEditorWidget(QTableView):
|
|||
self.selectionModel().selectionChanged.connect(self.on_selection_changed)
|
||||
model.select()
|
||||
|
||||
# Show start before end
|
||||
self.horizontalHeader().swapSections(1, 2)
|
||||
self.resizeColumnsToContents()
|
||||
|
||||
def on_selection_changed(
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
from typing import Optional
|
||||
|
||||
from PyQt6.QtCore import pyqtSignal, Qt
|
||||
from PyQt6.QtGui import QKeySequence
|
||||
from PyQt6.QtWidgets import QToolButton, QWidget, QMenu
|
||||
|
||||
from buzz.locale import _
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.icon import VisibilityIcon
|
||||
|
||||
|
||||
class TranscriptionViewModeToolButton(QToolButton):
|
||||
view_mode_changed = pyqtSignal(bool) # is_timestamps?
|
||||
|
||||
def __init__(self, shortcuts: Shortcuts, parent: Optional[QWidget] = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setText("View")
|
||||
self.setIcon(VisibilityIcon(self))
|
||||
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||
self.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
||||
|
||||
menu = QMenu(self)
|
||||
|
||||
menu.addAction(
|
||||
_("Text"),
|
||||
QKeySequence(shortcuts.get(Shortcut.VIEW_TRANSCRIPT_TEXT)),
|
||||
lambda: self.view_mode_changed.emit(False),
|
||||
)
|
||||
|
||||
menu.addAction(
|
||||
_("Timestamps"),
|
||||
QKeySequence(shortcuts.get(Shortcut.VIEW_TRANSCRIPT_TIMESTAMPS)),
|
||||
lambda: self.view_mode_changed.emit(True),
|
||||
)
|
||||
self.setMenu(menu)
|
|
@ -3,28 +3,35 @@ from typing import Optional
|
|||
from uuid import UUID
|
||||
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QFont
|
||||
from PyQt6.QtMultimedia import QMediaPlayer
|
||||
from PyQt6.QtSql import QSqlRecord
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget,
|
||||
QHBoxLayout,
|
||||
QVBoxLayout,
|
||||
QToolButton,
|
||||
QLabel,
|
||||
QGridLayout,
|
||||
QFileDialog,
|
||||
)
|
||||
|
||||
from buzz.db.entity.transcription import Transcription
|
||||
from buzz.locale import _
|
||||
from buzz.db.service.transcription_service import TranscriptionService
|
||||
from buzz.paths import file_path_as_title
|
||||
from buzz.transcriber.file_transcriber import write_output
|
||||
from buzz.transcriber.transcriber import OutputFormat, Segment
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.audio_player import AudioPlayer
|
||||
from buzz.widgets.transcription_viewer.export_transcription_button import (
|
||||
ExportTranscriptionButton,
|
||||
from buzz.widgets.icon import (
|
||||
FileDownloadIcon,
|
||||
)
|
||||
from buzz.widgets.text_display_box import TextDisplayBox
|
||||
from buzz.widgets.toolbar import ToolBar
|
||||
from buzz.widgets.transcription_viewer.export_transcription_menu import (
|
||||
ExportTranscriptionMenu,
|
||||
)
|
||||
from buzz.widgets.transcription_viewer.transcription_segments_editor_widget import (
|
||||
TranscriptionSegmentsEditorWidget,
|
||||
)
|
||||
from buzz.widgets.transcription_viewer.transcription_view_mode_tool_button import (
|
||||
TranscriptionViewModeToolButton,
|
||||
)
|
||||
|
||||
|
||||
class TranscriptionViewerWidget(QWidget):
|
||||
|
@ -33,22 +40,31 @@ class TranscriptionViewerWidget(QWidget):
|
|||
def __init__(
|
||||
self,
|
||||
transcription: Transcription,
|
||||
transcription_service: TranscriptionService,
|
||||
shortcuts: Shortcuts,
|
||||
parent: Optional["QWidget"] = None,
|
||||
flags: Qt.WindowType = Qt.WindowType.Widget,
|
||||
) -> None:
|
||||
super().__init__(parent, flags)
|
||||
self.transcription = transcription
|
||||
self.transcription_service = transcription_service
|
||||
|
||||
self.setMinimumWidth(800)
|
||||
self.setMinimumHeight(500)
|
||||
|
||||
self.setWindowTitle(file_path_as_title(transcription.file))
|
||||
|
||||
self.is_showing_timestamps = True
|
||||
|
||||
self.table_widget = TranscriptionSegmentsEditorWidget(
|
||||
transcription_id=UUID(hex=transcription.id), parent=self
|
||||
)
|
||||
self.table_widget.segment_selected.connect(self.on_segment_selected)
|
||||
|
||||
self.text_display_box = TextDisplayBox(self)
|
||||
font = QFont(self.text_display_box.font().family(), 14)
|
||||
self.text_display_box.setFont(font)
|
||||
|
||||
self.audio_player: Optional[AudioPlayer] = None
|
||||
if platform.system() != "Linux":
|
||||
self.audio_player = AudioPlayer(file_path=transcription.file)
|
||||
|
@ -56,56 +72,61 @@ class TranscriptionViewerWidget(QWidget):
|
|||
self.on_audio_player_position_ms_changed
|
||||
)
|
||||
|
||||
self.current_segment_label = QLabel()
|
||||
self.current_segment_label.setText("")
|
||||
self.current_segment_label = QLabel("", self)
|
||||
self.current_segment_label.setAlignment(Qt.AlignmentFlag.AlignHCenter)
|
||||
self.current_segment_label.setContentsMargins(0, 0, 0, 10)
|
||||
|
||||
buttons_layout = QHBoxLayout()
|
||||
buttons_layout.addStretch()
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
export_button = ExportTranscriptionButton(parent=self)
|
||||
export_button.on_export_triggered.connect(self.on_export_triggered)
|
||||
toolbar = ToolBar(self)
|
||||
|
||||
layout = QGridLayout(self)
|
||||
layout.addWidget(self.table_widget, 0, 0, 1, 2)
|
||||
view_mode_tool_button = TranscriptionViewModeToolButton(shortcuts, self)
|
||||
view_mode_tool_button.view_mode_changed.connect(self.on_view_mode_changed)
|
||||
toolbar.addWidget(view_mode_tool_button)
|
||||
|
||||
export_tool_button = QToolButton()
|
||||
export_tool_button.setText("Export")
|
||||
export_tool_button.setIcon(FileDownloadIcon(self))
|
||||
export_tool_button.setToolButtonStyle(
|
||||
Qt.ToolButtonStyle.ToolButtonTextBesideIcon
|
||||
)
|
||||
|
||||
export_transcription_menu = ExportTranscriptionMenu(
|
||||
transcription, transcription_service, self
|
||||
)
|
||||
export_tool_button.setMenu(export_transcription_menu)
|
||||
export_tool_button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
||||
toolbar.addWidget(export_tool_button)
|
||||
|
||||
layout.setMenuBar(toolbar)
|
||||
|
||||
layout.addWidget(self.table_widget)
|
||||
layout.addWidget(self.text_display_box)
|
||||
if self.audio_player is not None:
|
||||
layout.addWidget(self.audio_player, 1, 0, 1, 1)
|
||||
layout.addWidget(export_button, 1, 1, 1, 1)
|
||||
layout.addWidget(self.current_segment_label, 2, 0, 1, 2)
|
||||
layout.addWidget(self.audio_player)
|
||||
layout.addWidget(self.current_segment_label)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def on_export_triggered(self, output_format: OutputFormat) -> None:
|
||||
default_path = self.transcription.get_output_file_path(
|
||||
output_format=output_format
|
||||
)
|
||||
self.reset_view()
|
||||
|
||||
(output_file_path, nil) = QFileDialog.getSaveFileName(
|
||||
self,
|
||||
_("Save File"),
|
||||
default_path,
|
||||
_("Text files") + f" (*.{output_format.value})",
|
||||
)
|
||||
|
||||
if output_file_path == "":
|
||||
return
|
||||
|
||||
segments = [
|
||||
Segment(
|
||||
start=segment.value("start_time"),
|
||||
end=segment.value("end_time"),
|
||||
text=segment.value("text"),
|
||||
def reset_view(self):
|
||||
if self.is_showing_timestamps:
|
||||
self.text_display_box.hide()
|
||||
self.table_widget.show()
|
||||
else:
|
||||
segments = self.transcription_service.get_transcription_segments(
|
||||
transcription_id=self.transcription.id_as_uuid
|
||||
)
|
||||
for segment in self.table_widget.segments()
|
||||
]
|
||||
self.text_display_box.setPlainText(
|
||||
" ".join(segment.text.strip() for segment in segments)
|
||||
)
|
||||
self.text_display_box.show()
|
||||
self.table_widget.hide()
|
||||
|
||||
write_output(
|
||||
path=output_file_path,
|
||||
segments=segments,
|
||||
output_format=output_format,
|
||||
)
|
||||
def on_view_mode_changed(self, is_timestamps: bool) -> None:
|
||||
self.is_showing_timestamps = is_timestamps
|
||||
self.reset_view()
|
||||
|
||||
def on_segment_selected(self, segment: QSqlRecord):
|
||||
if self.audio_player is not None and (
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import os
|
||||
import random
|
||||
import string
|
||||
|
||||
import pytest
|
||||
from PyQt6.QtSql import QSqlDatabase
|
||||
|
@ -8,6 +10,8 @@ from buzz.db.dao.transcription_dao import TranscriptionDAO
|
|||
from buzz.db.dao.transcription_segment_dao import TranscriptionSegmentDAO
|
||||
from buzz.db.db import setup_test_db
|
||||
from buzz.db.service.transcription_service import TranscriptionService
|
||||
from buzz.settings.settings import Settings
|
||||
from buzz.settings.shortcuts import Shortcuts
|
||||
from buzz.widgets.application import Application
|
||||
|
||||
|
||||
|
@ -52,3 +56,19 @@ def qapp_args(request):
|
|||
return []
|
||||
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def settings():
|
||||
application = "".join(
|
||||
random.choice(string.ascii_letters + string.digits) for _ in range(6)
|
||||
)
|
||||
|
||||
settings = Settings(application=application)
|
||||
yield settings
|
||||
settings.clear()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def shortcuts(settings):
|
||||
return Shortcuts(settings)
|
||||
|
|
63
tests/widgets/export_transcription_menu_test.py
Normal file
63
tests/widgets/export_transcription_menu_test.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
import pathlib
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from buzz.db.entity.transcription import Transcription
|
||||
from buzz.db.entity.transcription_segment import TranscriptionSegment
|
||||
from buzz.model_loader import ModelType, WhisperModelSize
|
||||
from buzz.transcriber.transcriber import Task
|
||||
from buzz.widgets.transcription_viewer.export_transcription_menu import (
|
||||
ExportTranscriptionMenu,
|
||||
)
|
||||
|
||||
|
||||
class TestExportTranscriptionMenu:
|
||||
@pytest.fixture()
|
||||
def transcription(
|
||||
self, transcription_dao, transcription_segment_dao
|
||||
) -> Transcription:
|
||||
id = uuid.uuid4()
|
||||
transcription_dao.insert(
|
||||
Transcription(
|
||||
id=str(id),
|
||||
status="completed",
|
||||
file="testdata/whisper-french.mp3",
|
||||
task=Task.TRANSCRIBE.value,
|
||||
model_type=ModelType.WHISPER.value,
|
||||
whisper_model_size=WhisperModelSize.SMALL.value,
|
||||
)
|
||||
)
|
||||
transcription_segment_dao.insert(TranscriptionSegment(40, 299, "Bien", str(id)))
|
||||
transcription_segment_dao.insert(
|
||||
TranscriptionSegment(299, 329, "venue dans", str(id))
|
||||
)
|
||||
|
||||
return transcription_dao.find_by_id(str(id))
|
||||
|
||||
def test_should_export_segments(
|
||||
self,
|
||||
tmp_path: pathlib.Path,
|
||||
qtbot: QtBot,
|
||||
transcription,
|
||||
transcription_service,
|
||||
shortcuts,
|
||||
mocker,
|
||||
):
|
||||
output_file_path = tmp_path / "whisper.txt"
|
||||
mocker.patch(
|
||||
"PyQt6.QtWidgets.QFileDialog.getSaveFileName",
|
||||
return_value=(str(output_file_path), ""),
|
||||
)
|
||||
|
||||
widget = ExportTranscriptionMenu(
|
||||
transcription,
|
||||
transcription_service,
|
||||
)
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
widget.actions()[0].trigger()
|
||||
|
||||
with open(output_file_path, encoding="utf-8") as output_file:
|
||||
assert "Bien\nvenue dans" in output_file.read()
|
|
@ -1,17 +1,14 @@
|
|||
from PyQt6.QtCore import QSettings
|
||||
|
||||
from buzz.settings.settings import Settings
|
||||
from buzz.settings.shortcut_settings import ShortcutSettings
|
||||
from buzz.widgets.menu_bar import MenuBar
|
||||
from buzz.widgets.preferences_dialog.models.preferences import Preferences
|
||||
from buzz.widgets.preferences_dialog.preferences_dialog import PreferencesDialog
|
||||
|
||||
|
||||
class TestMenuBar:
|
||||
def test_open_preferences_dialog(self, qtbot):
|
||||
def test_open_preferences_dialog(self, qtbot, shortcuts):
|
||||
menu_bar = MenuBar(
|
||||
shortcuts=ShortcutSettings(Settings()).load(),
|
||||
preferences=Preferences.load(QSettings()),
|
||||
shortcuts=shortcuts, preferences=Preferences.load(QSettings())
|
||||
)
|
||||
qtbot.add_widget(menu_bar)
|
||||
|
||||
|
|
|
@ -7,10 +7,9 @@ from buzz.widgets.preferences_dialog.preferences_dialog import PreferencesDialog
|
|||
|
||||
|
||||
class TestPreferencesDialog:
|
||||
def test_create(self, qtbot: QtBot):
|
||||
def test_create(self, qtbot: QtBot, shortcuts):
|
||||
dialog = PreferencesDialog(
|
||||
shortcuts={},
|
||||
preferences=Preferences.load(QSettings()),
|
||||
shortcuts=shortcuts, preferences=Preferences.load(QSettings())
|
||||
)
|
||||
qtbot.add_widget(dialog)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from PyQt6.QtWidgets import QPushButton, QLabel
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from buzz.settings.shortcut import Shortcut
|
||||
from buzz.widgets.preferences_dialog.shortcuts_editor_preferences_widget import (
|
||||
ShortcutsEditorPreferencesWidget,
|
||||
)
|
||||
|
@ -8,10 +8,17 @@ from buzz.widgets.sequence_edit import SequenceEdit
|
|||
|
||||
|
||||
class TestShortcutsEditorWidget:
|
||||
def test_should_reset_to_defaults(self, qtbot):
|
||||
widget = ShortcutsEditorPreferencesWidget(
|
||||
shortcuts=Shortcut.get_default_shortcuts()
|
||||
)
|
||||
def test_should_update_shortcuts(self, qtbot: QtBot, shortcuts):
|
||||
widget = ShortcutsEditorPreferencesWidget(shortcuts=shortcuts)
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
sequence_edit = widget.findChild(SequenceEdit)
|
||||
assert sequence_edit.keySequence().toString() == "Ctrl+R"
|
||||
with qtbot.wait_signal(widget.shortcuts_changed, timeout=1000):
|
||||
sequence_edit.setKeySequence("Ctrl+Shift+R")
|
||||
|
||||
def test_should_reset_to_defaults(self, qtbot, shortcuts):
|
||||
widget = ShortcutsEditorPreferencesWidget(shortcuts=shortcuts)
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
reset_button = widget.findChild(QPushButton)
|
||||
|
@ -26,7 +33,8 @@ class TestShortcutsEditorWidget:
|
|||
("Import File", "Ctrl+O"),
|
||||
("Import URL", "Ctrl+U"),
|
||||
("Open Preferences Window", "Ctrl+,"),
|
||||
("Open Transcript Viewer", "Ctrl+E"),
|
||||
("View Transcript Text", "Ctrl+E"),
|
||||
("View Transcript Timestamps", "Ctrl+T"),
|
||||
("Clear History", "Ctrl+S"),
|
||||
("Cancel Transcription", "Ctrl+X"),
|
||||
)
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import pathlib
|
||||
import uuid
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from PyQt6.QtWidgets import QPushButton
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from buzz.db.entity.transcription import Transcription
|
||||
|
@ -41,8 +38,12 @@ class TestTranscriptionViewerWidget:
|
|||
|
||||
return transcription_dao.find_by_id(str(id))
|
||||
|
||||
def test_should_display_segments(self, qtbot: QtBot, transcription):
|
||||
widget = TranscriptionViewerWidget(transcription)
|
||||
def test_should_display_segments(
|
||||
self, qtbot: QtBot, transcription, transcription_service, shortcuts
|
||||
):
|
||||
widget = TranscriptionViewerWidget(
|
||||
transcription, transcription_service, shortcuts
|
||||
)
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
assert widget.windowTitle() == "whisper-french.mp3"
|
||||
|
@ -54,30 +55,15 @@ class TestTranscriptionViewerWidget:
|
|||
assert editor.model().index(0, 2).data() == 40
|
||||
assert editor.model().index(0, 3).data() == "Bien"
|
||||
|
||||
def test_should_update_segment_text(self, qtbot, transcription):
|
||||
widget = TranscriptionViewerWidget(transcription)
|
||||
def test_should_update_segment_text(
|
||||
self, qtbot, transcription, transcription_service, shortcuts
|
||||
):
|
||||
widget = TranscriptionViewerWidget(
|
||||
transcription, transcription_service, shortcuts
|
||||
)
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
editor = widget.findChild(TranscriptionSegmentsEditorWidget)
|
||||
assert isinstance(editor, TranscriptionSegmentsEditorWidget)
|
||||
|
||||
editor.model().setData(editor.model().index(0, 3), "Biens")
|
||||
|
||||
def test_should_export_segments(
|
||||
self, tmp_path: pathlib.Path, qtbot: QtBot, transcription
|
||||
):
|
||||
widget = TranscriptionViewerWidget(transcription)
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
export_button = widget.findChild(QPushButton)
|
||||
assert isinstance(export_button, QPushButton)
|
||||
|
||||
output_file_path = tmp_path / "whisper.txt"
|
||||
with patch(
|
||||
"PyQt6.QtWidgets.QFileDialog.getSaveFileName"
|
||||
) as save_file_name_mock:
|
||||
save_file_name_mock.return_value = (str(output_file_path), "")
|
||||
export_button.menu().actions()[0].trigger()
|
||||
|
||||
with open(output_file_path, encoding="utf-8") as output_file:
|
||||
assert "Bien\nvenue dans" in output_file.read()
|
||||
|
|
Loading…
Reference in a new issue