Skip to content

Commit

Permalink
add transcript viewer (#686)
Browse files Browse the repository at this point in the history
  • Loading branch information
chidiwilliams authored Mar 15, 2024
1 parent 8ae8300 commit ba522a5
Show file tree
Hide file tree
Showing 31 changed files with 423 additions and 206 deletions.
30 changes: 20 additions & 10 deletions buzz/db/dao/dao.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -11,22 +11,26 @@

class DAO(ABC, Generic[T]):
entity: Type[T]
ignore_fields = []

def __init__(self, table: str, db: QSqlDatabase):
self.db = db
self.table = table

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())

Expand All @@ -37,10 +41,8 @@ def find_by_id(self, id: Any) -> T | None:
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():
Expand All @@ -49,5 +51,13 @@ def _execute(self, query: QSqlQuery) -> T | None:
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)
15 changes: 15 additions & 0 deletions buzz/db/dao/transcription_segment_dao.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from typing import List
from uuid import UUID

from PyQt6.QtSql import QSqlDatabase

from buzz.db.dao.dao import DAO
Expand All @@ -6,6 +9,18 @@

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)
7 changes: 7 additions & 0 deletions buzz/db/entity/transcription.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions buzz/db/entity/transcription_segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ class TranscriptionSegment(Entity):
end_time: int
text: str
transcription_id: str
id: int = -1
3 changes: 3 additions & 0 deletions buzz/db/service/transcription_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ def update_transcription_as_completed(self, id: UUID, segments: List[Segment]):
transcription_id=str(id),
)
)

def get_transcription_segments(self, transcription_id: UUID):
return self.transcription_segment_dao.get_segments(transcription_id)
4 changes: 2 additions & 2 deletions buzz/settings/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@


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):
Expand Down
4 changes: 3 additions & 1 deletion buzz/settings/shortcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ def __new__(cls, sequence: str, description: str):
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")

Expand Down
21 changes: 0 additions & 21 deletions buzz/settings/shortcut_settings.py

This file was deleted.

24 changes: 24 additions & 0 deletions buzz/settings/shortcuts.py
Original file line number Diff line number Diff line change
@@ -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, {})
1 change: 1 addition & 0 deletions buzz/transcriber/file_transcriber.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def stop(self):
...


# 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",
Expand Down
3 changes: 2 additions & 1 deletion buzz/widgets/application.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys

from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import QApplication

from buzz.__version__ import VERSION
Expand All @@ -22,7 +23,7 @@ def __init__(self, argv: list) -> None:
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(
Expand Down
7 changes: 7 additions & 0 deletions buzz/widgets/icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ def __init__(self, parent: QWidget):
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")

Expand Down
21 changes: 10 additions & 11 deletions buzz/widgets/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
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,
Expand Down Expand Up @@ -59,8 +59,7 @@ def __init__(self, transcription_service: TranscriptionService):

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

Expand Down Expand Up @@ -326,7 +325,11 @@ def on_table_double_clicked(self, index: QModelIndex):

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()

Expand Down Expand Up @@ -354,15 +357,12 @@ def on_task_completed(self, task: FileTranscriptionTask, segments: List[Segment]
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()
Expand All @@ -373,7 +373,6 @@ def closeEvent(self, event: QtGui.QCloseEvent) -> None:
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):
Expand Down
28 changes: 14 additions & 14 deletions buzz/widgets/main_window_toolbar.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
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,
EXPAND_ICON_PATH,
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

Expand All @@ -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)

Expand Down Expand Up @@ -59,7 +62,7 @@ def __init__(self, shortcuts: Dict[str, str], parent: Optional[QWidget]):
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()
Expand All @@ -74,21 +77,18 @@ def __init__(self, shortcuts: Dict[str, str], parent: Optional[QWidget]):
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):
Expand Down
Loading

0 comments on commit ba522a5

Please sign in to comment.