Compare commits

...

3 commits

Author SHA1 Message Date
Raivis Dejus 91b1775088
Merge 8939447d58 into 3d44a45476 2024-06-14 20:28:25 +00:00
Raivis Dejus 8939447d58 Adding test fixes 2024-06-14 23:28:05 +03:00
Raivis Dejus 99e8dd20a7 Adding translations to transcription view 2024-06-14 19:14:13 +03:00
30 changed files with 539 additions and 120 deletions

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" height="800px" width="800px" version="1.1" id="anna_vital_language_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
<path d="M62.4,101c-1.5-2.1-2.1-3.4-1.8-3.9c0.2-0.5,1.6-0.7,3.9-0.5c2.3,0.2,4.2,0.5,5.8,0.9c1.5,0.4,2.8,1,3.8,1.7
c1,0.7,1.8,1.5,2.3,2.6c0.6,1,1,2.3,1.4,3.7c0.7,2.8,0.5,4.7-0.5,5.7c-1.1,1-2.6,0.8-4.6-0.6c-2.1-1.4-3.9-2.8-5.5-4.2
C65.5,105.1,63.9,103.2,62.4,101z M40.7,190.1c4.8-2.1,9-4.2,12.6-6.4c3.5-2.1,6.6-4.4,9.3-6.8c2.6-2.3,5-4.9,7-7.7
c2-2.7,3.8-5.8,5.4-9.2c1.3,1.2,2.5,2.4,3.8,3.5c1.2,1.1,2.5,2.2,3.8,3.4c1.3,1.2,2.8,2.4,4.3,3.8c1.5,1.4,3.3,2.8,5.3,4.5
c0.7,0.5,1.4,0.9,2.1,1c0.7,0.1,1.7,0,3.1-0.6c1.3-0.5,3-1.4,5.1-2.8c2.1-1.3,4.7-3.1,7.9-5.4c1.6-1.1,2.4-2,2.3-2.7
c-0.1-0.7-1-1-2.7-0.9c-3.1,0.1-5.9,0.1-8.3-0.1c-2.5-0.2-5-0.6-7.4-1.4c-2.4-0.8-4.9-1.9-7.5-3.4c-2.6-1.5-5.6-3.6-9.1-6.2
c1-3.9,1.8-8,2.4-12.4c0.3-2.5,0.6-4.3,0.8-5.6c0.2-1.2,0.5-2.4,0.9-3.3c0.3-0.8,0.4-1.4,0.5-1.9c0.1-0.5-0.1-1-0.4-1.6
c-0.4-0.5-1-1.1-1.9-1.7c-0.9-0.6-2.2-1.4-3.9-2.3c2.4-0.9,5.1-1.7,7.9-2.6c2.7-0.9,5.7-1.8,8.8-2.7c3-0.9,4.5-1.9,4.6-3.1
c0.1-1.2-0.9-2.3-3.2-3.5c-1.5-0.8-2.9-1.1-4.3-0.9c-1.4,0.2-3.2,0.9-5.4,2.2c-0.6,0.4-1.8,0.9-3.4,1.6c-1.7,0.7-3.6,1.5-6,2.5
c-2.4,1-5,2-7.8,3.1c-2.9,1.1-5.8,2.2-8.7,3.2c-2.9,1.1-5.7,2-8.2,2.8c-2.6,0.8-4.6,1.4-6.1,1.6c-3.8,0.8-5.8,1.6-5.9,2.4
c0,0.8,1.5,1.6,4.4,2.4c1.2,0.3,2.3,0.6,3.1,0.6c0.8,0.1,1.7,0.1,2.5,0c0.8-0.1,1.6-0.3,2.4-0.5c0.8-0.3,1.7-0.7,2.8-1.1
c1.6-0.8,3.9-1.7,6.9-2.8c2.9-1,6.6-2.4,11.2-4c0.9,2.7,1.4,6,1.4,9.8c0,3.8-0.4,8.1-1.4,13c-1.3-1.1-2.7-2.3-4.2-3.6
c-1.5-1.3-2.9-2.6-4.3-3.9c-1.6-1.5-3.2-2.5-4.7-3c-1.6-0.5-3.4-0.5-5.5,0c-3.3,0.9-5,1.9-4.9,3.1c0,1.2,1.3,1.8,3.8,1.9
c0.9,0.1,1.8,0.3,2.7,0.6c0.9,0.3,1.9,0.9,3.2,1.8c1.3,0.9,2.9,2.2,4.7,3.8c1.8,1.6,4.2,3.7,7,6.3c-1.2,2.9-2.6,5.6-4.1,8
c-1.5,2.5-3.4,5-5.5,7.3c-2.2,2.4-4.7,4.8-7.7,7.2c-3,2.5-6.6,5.1-10.8,7.8c-4.3,2.8-6.5,4.7-6.5,5.6C35,192.1,37,191.7,40.7,190.1z
M250.5,81.8v165.3l-111.6-36.4L10.5,253.4V76.1l29.9-10V10.4l81.2,28.7L231.3,2.6v73.1L250.5,81.8z M124.2,50.6L22.3,84.6v152.2
l101.9-33.9V50.6L124.2,50.6z M219.4,71.9V19L138.1,46L219.4,71.9z M227,201.9L196.5,92L176,85.6l-30.9,90.8l18.9,5.9l5.8-18.7
l31.9,10l5.7,22.3L227,201.9z M174.8,147.7l22.2,6.9l-10.9-42.9L174.8,147.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -6,7 +6,7 @@ import platform
import sys
from typing import TextIO
from platformdirs import user_log_dir, user_cache_dir
from platformdirs import user_log_dir, user_cache_dir, user_data_dir
from buzz.assets import APP_BASE_DIR
@ -60,6 +60,7 @@ def main():
logging.debug("app_dir: %s", APP_BASE_DIR)
logging.debug("log_dir: %s", log_dir)
logging.debug("cache_dir: %s", user_cache_dir("Buzz"))
logging.debug("data_dir: %s", user_data_dir("Buzz"))
app = Application(sys.argv)
parse_command_line(app)

View file

@ -24,3 +24,18 @@ class TranscriptionSegmentDAO(DAO[TranscriptionSegment]):
)
query.bindValue(":transcription_id", str(transcription_id))
return self._execute_all(query)
def update_segment_translation(self, segment_id: int, translation: str):
query = self._create_query()
query.prepare(
"""
UPDATE transcription_segment
SET translation = :translation
WHERE id = :id
"""
)
query.bindValue(":id", segment_id)
query.bindValue(":translation", translation)
if not query.exec():
raise Exception(query.lastError().text())

View file

@ -8,5 +8,6 @@ class TranscriptionSegment(Entity):
start_time: int
end_time: int
text: str
translation: str
transcription_id: str
id: int = -1

View file

@ -53,13 +53,14 @@ def copy_transcriptions_from_json_to_sqlite(conn: Connection):
for segment in task.segments:
cursor.execute(
"""
INSERT INTO transcription_segment (end_time, start_time, text, transcription_id)
VALUES (?, ?, ?, ?);
INSERT INTO transcription_segment (end_time, start_time, text, translation, transcription_id)
VALUES (?, ?, ?, ?, ?);
""",
(
segment.end,
segment.start,
segment.text,
segment.translation,
transcription_id,
),
)

View file

@ -39,9 +39,13 @@ class TranscriptionService:
start_time=segment.start,
end_time=segment.end,
text=segment.text,
translation='',
transcription_id=str(id),
)
)
def get_transcription_segments(self, transcription_id: UUID):
return self.transcription_segment_dao.get_segments(transcription_id)
def update_segment_translation(self, segment_id: int, translation: str):
return self.transcription_segment_dao.update_segment_translation(segment_id, translation)

View file

@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-10 21:58+0300\n"
"PO-Revision-Date: 2024-06-10 21:59+0300\n"
"POT-Creation-Date: 2024-06-14 18:59+0300\n"
"PO-Revision-Date: 2024-06-14 19:01+0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: lv_LV\n"
@ -39,51 +39,63 @@ msgid "View Transcript Text"
msgstr "Aplūkot atpazīto tekstu"
#: buzz/settings/shortcut.py:23
msgid "View Transcript Translation"
msgstr "Aplūkot tulkojumu"
#: buzz/settings/shortcut.py:24
msgid "View Transcript Timestamps"
msgstr "Aplūkot atpazīšanas laikus"
#: buzz/settings/shortcut.py:25 buzz/widgets/main_window_toolbar.py:60
#: buzz/settings/shortcut.py:26 buzz/widgets/main_window_toolbar.py:60
#: buzz/widgets/main_window.py:222
msgid "Clear History"
msgstr "Notīrīt vēsturi"
#: buzz/settings/shortcut.py:26 buzz/widgets/main_window_toolbar.py:52
#: buzz/settings/shortcut.py:27 buzz/widgets/main_window_toolbar.py:52
msgid "Cancel Transcription"
msgstr "Atcelt atpazīšanu"
#: buzz/widgets/transcription_tasks_table_widget.py:64
#: buzz/widgets/transcription_tasks_table_widget.py:62
msgid "In Progress"
msgstr "Apstrādā"
#: buzz/widgets/transcription_tasks_table_widget.py:65
msgid "Completed"
msgstr "Pabeigts"
#: buzz/widgets/transcription_tasks_table_widget.py:73
#: buzz/widgets/transcription_tasks_table_widget.py:72
msgid "Failed"
msgstr "Neizdevās"
#: buzz/widgets/transcription_tasks_table_widget.py:75
msgid "Canceled"
msgstr "Atcelts"
#: buzz/widgets/transcription_tasks_table_widget.py:75
#: buzz/widgets/transcription_tasks_table_widget.py:77
msgid "Queued"
msgstr "Ierindots"
#: buzz/widgets/transcription_tasks_table_widget.py:83
#: buzz/widgets/transcription_tasks_table_widget.py:85
msgid "File Name / URL"
msgstr "Fails / URL"
#: buzz/widgets/transcription_tasks_table_widget.py:95
#: buzz/widgets/transcription_tasks_table_widget.py:97
msgid "Model"
msgstr "Modelis"
#: buzz/widgets/transcription_tasks_table_widget.py:104
#: buzz/widgets/transcription_tasks_table_widget.py:106
msgid "Task"
msgstr "Uzdevums"
#: buzz/widgets/transcription_tasks_table_widget.py:113
#: buzz/widgets/transcription_tasks_table_widget.py:115
msgid "Status"
msgstr "Statuss"
#: buzz/widgets/transcription_tasks_table_widget.py:121
#: buzz/widgets/transcription_tasks_table_widget.py:123
msgid "Date Added"
msgstr "Pievienots"
#: buzz/widgets/transcription_tasks_table_widget.py:132
#: buzz/widgets/transcription_tasks_table_widget.py:134
msgid "Date Completed"
msgstr "Pabeigts"
@ -140,11 +152,11 @@ msgstr "Gaida MI tulkojumu..."
msgid "Microphone:"
msgstr "Mikrofons:"
#: buzz/widgets/recording_transcriber_widget.py:382
#: buzz/widgets/recording_transcriber_widget.py:391
msgid "An error occurred while starting a new recording:"
msgstr "Sākot jaunu ierakstu notikusi kļūda:"
#: buzz/widgets/recording_transcriber_widget.py:386
#: buzz/widgets/recording_transcriber_widget.py:395
msgid ""
"Please check your audio devices or check the application logs for more "
"information."
@ -161,8 +173,8 @@ msgid ""
"Detected missing permissions, please check that snap permissions have been "
"granted"
msgstr ""
"Ne visi nepieciešamie moduļi darbojas korekti, iespējams nav piešķirtas "
"snap atļaujas"
"Ne visi nepieciešamie moduļi darbojas korekti, iespējams nav piešķirtas snap "
"atļaujas"
#: buzz/widgets/snap_notice.py:16
msgid ""
@ -205,83 +217,111 @@ msgstr ""
msgid "Select audio file"
msgstr "Izvēlieties audio failu"
#: buzz/widgets/main_window.py:278
#: buzz/widgets/main_window.py:280
#: buzz/widgets/preferences_dialog/models_preferences_widget.py:191
msgid "Error"
msgstr "Kļūda"
#: buzz/widgets/main_window.py:278
#: buzz/widgets/main_window.py:280
msgid "Unable to save OpenAI API key to keyring"
msgstr "Neizdevās saglabāt OpenAI API atslēgu atslēgu saišķī"
#: buzz/widgets/transcription_viewer/export_transcription_menu.py:42
msgid "Save File"
msgstr "Saglabāt failu"
#: buzz/widgets/transcription_viewer/export_transcription_menu.py:44
msgid "Text files"
msgstr "Teksta faili"
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:19
msgid "View"
msgstr "Skats"
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:27
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:68
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:34
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:95
msgid "Text"
msgstr "Teksts"
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:33
#: buzz/widgets/transcription_viewer/export_transcription_menu.py:43
#: buzz/widgets/transcription_viewer/export_transcription_menu.py:65
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:40
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:96
msgid "Translation"
msgstr "Tulkojums"
#: buzz/widgets/transcription_viewer/export_transcription_menu.py:79
msgid "Save File"
msgstr "Saglabāt failu"
#: buzz/widgets/transcription_viewer/export_transcription_menu.py:81
msgid "Text files"
msgstr "Teksta faili"
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:26
msgid "View"
msgstr "Skats"
#: buzz/widgets/transcription_viewer/transcription_view_mode_tool_button.py:46
msgid "Timestamps"
msgstr "Laiks"
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:66
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:93
msgid "Start"
msgstr "Sākums"
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:67
#: buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py:94
msgid "End"
msgstr "Beigas"
#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:92
#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:146
msgid "Export"
msgstr "Eksportēt"
#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:160
msgid "Translate"
msgstr "Tulkot"
#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:250
msgid "API Key Required"
msgstr "API atslēgas kļūda"
#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:251
msgid "Please enter OpenAI API Key in preferences"
msgstr "Lūdzu ievadiet OpenAI API atslēgu iestatījumos"
#: buzz/widgets/record_button.py:21
msgid "Stop"
msgstr "Apturēt"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:32
#: buzz/widgets/transcriber/advanced_settings_dialog.py:33
msgid "Advanced Settings"
msgstr "Papildu iestatījumi"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:41
#: buzz/widgets/transcriber/advanced_settings_dialog.py:37
msgid "Speech recognition settings"
msgstr "Runas atpazīšanas iestatījumi"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:46
msgid "Comma-separated, e.g. \"0.0, 0.2, 0.4, 0.6, 0.8, 1.0\""
msgstr "Atdalīti ar komatu, piemēram, \"0.0, 0.2, 0.4, 0.6, 0.8, 1.0\""
#: buzz/widgets/transcriber/advanced_settings_dialog.py:50
#: buzz/widgets/transcriber/advanced_settings_dialog.py:55
msgid "Temperature:"
msgstr "Temperatūra:"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:61
#: buzz/widgets/transcriber/advanced_settings_dialog.py:66
msgid "Initial Prompt:"
msgstr ""
"Sākotnējais\n"
"vaicājums:"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:63
#: buzz/widgets/transcriber/advanced_settings_dialog.py:68
msgid "Translation settings"
msgstr "Tulkojuma iestatījumi"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:72
msgid "Enable AI translation"
msgstr "Tulkot ar MI"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:75
#: buzz/widgets/transcriber/advanced_settings_dialog.py:84
msgid "AI model:"
msgstr "AI modelis:"
#: buzz/widgets/transcriber/advanced_settings_dialog.py:79
#: buzz/widgets/transcriber/advanced_settings_dialog.py:88
msgid "Enter instructions for AI on how to translate..."
msgstr "Ievadiet tulkošanas norādes mākslīgajam intelektam..."
#: buzz/widgets/transcriber/advanced_settings_dialog.py:83
#: buzz/widgets/transcriber/advanced_settings_dialog.py:92
msgid "Instructions for AI:"
msgstr "Norādes MI:"
@ -301,20 +341,20 @@ msgstr "Papildu iestatījumi..."
msgid "Enter prompt..."
msgstr "Ievadiet vaicājumu..."
#: buzz/widgets/transcriber/transcription_options_group_box.py:79
#: buzz/widgets/transcriber/transcription_options_group_box.py:86
msgid "Model:"
msgstr "Modelis:"
#: buzz/widgets/transcriber/transcription_options_group_box.py:83
#: buzz/widgets/transcriber/transcription_options_group_box.py:90
msgid "Task:"
msgstr "Uzdevums:"
#: buzz/widgets/transcriber/transcription_options_group_box.py:84
#: buzz/widgets/transcriber/transcription_options_group_box.py:91
msgid "Language:"
msgstr "Valoda:"
#: buzz/widgets/transcriber/languages_combo_box.py:25
#: buzz/transcriber/transcriber.py:152
#: buzz/transcriber/transcriber.py:153
msgid "Detect Language"
msgstr "Noteikt valodu"
@ -380,10 +420,10 @@ msgstr "OpenAI API atslēgas pārbaude"
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:129
msgid ""
"Your API key is valid. Buzz will use this key to perform Whisper API "
"transcriptions."
"transcriptions and AI translations with ChatGPT."
msgstr ""
"Jūsu API atslēga ir derīga. Buzz izmantos to runas atpazīšanai ar Whisper "
"API."
"API un tulkošanai ar ChatGPT."
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:156
msgid "Select Export Folder"

View file

@ -23,6 +23,7 @@ CREATE TABLE transcription_segment (
end_time INT DEFAULT 0,
start_time INT DEFAULT 0,
text TEXT NOT NULL,
translation TEXT DEFAULT '',
transcription_id TEXT,
FOREIGN KEY (transcription_id) REFERENCES transcription(id) ON DELETE CASCADE
);

View file

@ -20,6 +20,7 @@ class Shortcut(str, enum.Enum):
OPEN_PREFERENCES_WINDOW = ("Ctrl+,", _("Open Preferences Window"))
VIEW_TRANSCRIPT_TEXT = ("Ctrl+E", _("View Transcript Text"))
VIEW_TRANSCRIPT_TRANSLATION = ("Ctrl+L", _("View Transcript Translation"))
VIEW_TRANSCRIPT_TIMESTAMPS = ("Ctrl+T", _("View Transcript Timestamps"))
CLEAR_HISTORY = ("Ctrl+S", _("Clear History"))

View file

@ -103,7 +103,12 @@ class FileTranscriber(QObject):
# TODO: Move to transcription service
def write_output(path: str, segments: List[Segment], output_format: OutputFormat):
def write_output(
path: str,
segments: List[Segment],
output_format: OutputFormat,
segment_key: str = 'text'
):
logging.debug(
"Writing transcription output, path = %s, output format = %s, number of segments = %s",
path,
@ -114,7 +119,7 @@ def write_output(path: str, segments: List[Segment], output_format: OutputFormat
with open(path, "w", encoding="utf-8") as file:
if output_format == OutputFormat.TXT:
for i, segment in enumerate(segments):
file.write(segment.text)
file.write(getattr(segment, segment_key))
file.write("\n")
elif output_format == OutputFormat.VTT:
@ -123,7 +128,7 @@ def write_output(path: str, segments: List[Segment], output_format: OutputFormat
file.write(
f"{to_timestamp(segment.start)} --> {to_timestamp(segment.end)}\n"
)
file.write(f"{segment.text}\n\n")
file.write(f"{getattr(segment, segment_key)}\n\n")
elif output_format == OutputFormat.SRT:
for i, segment in enumerate(segments):
@ -131,7 +136,7 @@ def write_output(path: str, segments: List[Segment], output_format: OutputFormat
file.write(
f'{to_timestamp(segment.start, ms_separator=",")} --> {to_timestamp(segment.end, ms_separator=",")}\n'
)
file.write(f"{segment.text}\n\n")
file.write(f"{getattr(segment, segment_key)}\n\n")
logging.debug("Written transcription output")

View file

@ -125,7 +125,7 @@ class RecordingTranscriber(QObject):
whisper_segments, info = model.transcribe(
audio=samples,
language=self.transcription_options.language
if self.transcription_options.language is not ""
if self.transcription_options.language != ""
else None,
task=self.transcription_options.task.value,
temperature=self.transcription_options.temperature,

View file

@ -25,6 +25,7 @@ class Segment:
start: int # start time in ms
end: int # end time in ms
text: str
translation: str = ""
LANGUAGES = {

View file

@ -121,6 +121,7 @@ class WhisperFileTranscriber(FileTranscriber):
start=int(segment.get("start") * 1000),
end=int(segment.get("end") * 1000),
text=segment.get("text"),
translation=""
)
for segment in result.get("segments")
]
@ -149,6 +150,7 @@ class WhisperFileTranscriber(FileTranscriber):
start=int(word.start * 1000),
end=int(word.end * 1000),
text=word.word,
translation=""
)
)
else:
@ -157,6 +159,7 @@ class WhisperFileTranscriber(FileTranscriber):
start=int(segment.start * 1000),
end=int(segment.end * 1000),
text=segment.text,
translation=""
)
)
@ -181,6 +184,7 @@ class WhisperFileTranscriber(FileTranscriber):
start=int(word.start * 1000),
end=int(word.end * 1000),
text=word.word.strip(),
translation=""
)
for segment in result.segments
for word in segment.words
@ -200,6 +204,7 @@ class WhisperFileTranscriber(FileTranscriber):
start=int(segment.get("start") * 1000),
end=int(segment.get("end") * 1000),
text=segment.get("text"),
translation=""
)
for segment in segments
]
@ -226,6 +231,7 @@ class WhisperFileTranscriber(FileTranscriber):
start=segment.get("start"),
end=segment.get("end"),
text=segment.get("text"),
translation=""
)
for segment in segments_dict
]

View file

@ -8,16 +8,18 @@ from PyQt6.QtCore import QObject, pyqtSignal
from buzz.settings.settings import Settings
from buzz.store.keyring_store import get_password, Key
from buzz.transcriber.transcriber import TranscriptionOptions
from buzz.widgets.transcriber.advanced_settings_dialog import AdvancedSettingsDialog
class Translator(QObject):
translation = pyqtSignal(str)
translation = pyqtSignal(str, int)
finished = pyqtSignal()
is_running = False
def __init__(
self,
transcription_options: TranscriptionOptions,
advanced_settings_dialog: AdvancedSettingsDialog,
parent: Optional[QObject] = None,
) -> None:
super().__init__(parent)
@ -25,6 +27,11 @@ class Translator(QObject):
logging.debug(f"Translator init: {transcription_options}")
self.transcription_options = transcription_options
self.advanced_settings_dialog = advanced_settings_dialog
self.advanced_settings_dialog.transcription_options_changed.connect(
self.on_transcription_options_changed
)
self.queue = queue.Queue()
settings = Settings()
@ -44,7 +51,7 @@ class Translator(QObject):
while self.is_running:
try:
transcript = self.queue.get(timeout=1)
transcript, transcript_id = self.queue.get(timeout=1)
except queue.Empty:
continue
@ -64,13 +71,17 @@ class Translator(QObject):
logging.error(f"Translation error! Server response: {completion}")
next_translation = "Translation error, see logs!"
self.translation.emit(next_translation)
self.translation.emit(next_translation, transcript_id)
self.finished.emit()
def enqueue(self, transcript: str):
if self.is_running:
self.queue.put(transcript)
def on_transcription_options_changed(
self, transcription_options: TranscriptionOptions
):
self.transcription_options = transcription_options
def enqueue(self, transcript: str, transcript_id: Optional[int] = None):
self.queue.put((transcript, transcript_id))
def stop(self):
self.is_running = False

View file

@ -74,6 +74,11 @@ class FileDownloadIcon(Icon):
super().__init__(get_path("assets/file_download_black_24dp.svg"), parent)
class TranslateIcon(Icon):
def __init__(self, parent: QWidget):
super().__init__(get_path("assets/translate_black.svg"), parent)
class VisibilityIcon(Icon):
def __init__(self, parent: QWidget):
super().__init__(

View file

@ -141,6 +141,8 @@ class MainWindow(QMainWindow):
self.folder_watcher.task_found.connect(self.add_task)
self.folder_watcher.find_tasks()
self.transcription_viewer_widget = None
if os.environ.get('SNAP_NAME', '') == 'buzz':
logging.debug("Running in a snap environment")
self.check_linux_permissions()
@ -267,6 +269,8 @@ class MainWindow(QMainWindow):
self.on_openai_access_token_changed
)
file_transcriber_window.show()
file_transcriber_window.raise_()
file_transcriber_window.activateWindow()
@staticmethod
def on_openai_access_token_changed(access_token: str):
@ -347,14 +351,14 @@ class MainWindow(QMainWindow):
self.open_transcription_viewer(transcription)
def open_transcription_viewer(self, transcription: Transcription):
transcription_viewer_widget = TranscriptionViewerWidget(
self.transcription_viewer_widget = TranscriptionViewerWidget(
transcription=transcription,
transcription_service=self.transcription_service,
shortcuts=self.shortcuts,
parent=self,
flags=Qt.WindowType.Window,
)
transcription_viewer_widget.show()
self.transcription_viewer_widget.show()
def add_task(self, task: FileTranscriptionTask):
self.transcription_service.create_transcription(task)
@ -396,6 +400,10 @@ class MainWindow(QMainWindow):
self.transcriber_worker.stop()
self.transcriber_thread.quit()
self.transcriber_thread.wait()
if self.transcription_viewer_widget is not None:
self.transcription_viewer_widget.close()
super().closeEvent(event)
def save_geometry(self):

View file

@ -126,7 +126,7 @@ class GeneralPreferencesWidget(QWidget):
QMessageBox.information(
self,
_("OpenAI API Key Test"),
_("Your API key is valid. Buzz will use this key to perform Whisper API transcriptions."),
_("Your API key is valid. Buzz will use this key to perform Whisper API transcriptions and AI translations with ChatGPT."),
)
def on_test_openai_api_key_failure(self, error: str):

View file

@ -127,12 +127,12 @@ class RecordingTranscriberWidget(QWidget):
self.translation_text_box = TextDisplayBox(self)
self.translation_text_box.setPlaceholderText(_("Waiting for AI translation..."))
transcription_options_group_box = TranscriptionOptionsGroupBox(
self.transcription_options_group_box = TranscriptionOptionsGroupBox(
default_transcription_options=self.transcription_options,
model_types=model_types,
parent=self,
)
transcription_options_group_box.transcription_options_changed.connect(
self.transcription_options_group_box.transcription_options_changed.connect(
self.on_transcription_options_changed
)
@ -145,7 +145,7 @@ class RecordingTranscriberWidget(QWidget):
record_button_layout.addWidget(self.audio_meter_widget)
record_button_layout.addWidget(self.record_button)
layout.addWidget(transcription_options_group_box)
layout.addWidget(self.transcription_options_group_box)
layout.addLayout(recording_options_layout)
layout.addLayout(record_button_layout)
layout.addWidget(self.transcription_text_box)
@ -289,7 +289,10 @@ class RecordingTranscriberWidget(QWidget):
if self.transcription_options.enable_llm_translation:
self.translation_thread = QThread()
self.translator = Translator(self.transcription_options)
self.translator = Translator(
self.transcription_options,
self.transcription_options_group_box.advanced_settings_dialog,
)
self.translator.moveToThread(self.translation_thread)
@ -354,7 +357,7 @@ class RecordingTranscriberWidget(QWidget):
with open(self.transcript_export_file, "a") as f:
f.write(text + "\n\n")
def on_next_translation(self, text: str):
def on_next_translation(self, text: str, _: Optional[int] = None):
if len(text) > 0:
self.translation_text_box.moveCursor(QTextCursor.MoveOperation.End)
if len(self.translation_text_box.toPlainText()) > 0:

View file

@ -6,6 +6,7 @@ from PyQt6.QtWidgets import (
QCheckBox,
QPlainTextEdit,
QFormLayout,
QLabel,
)
from buzz.locale import _
@ -33,6 +34,10 @@ class AdvancedSettingsDialog(QDialog):
layout = QFormLayout(self)
transcription_settings_title= _("Speech recognition settings")
transcription_settings_title_label = QLabel(f"<h4>{transcription_settings_title}</h4>", self)
layout.addRow("", transcription_settings_title_label)
default_temperature_text = ", ".join(
[str(temp) for temp in transcription_options.temperature]
)
@ -60,6 +65,10 @@ class AdvancedSettingsDialog(QDialog):
layout.addRow(_("Initial Prompt:"), self.initial_prompt_text_edit)
translation_settings_title= _("Translation settings")
translation_settings_title_label = QLabel(f"<h4>{translation_settings_title}</h4>", self)
layout.addRow("", translation_settings_title_label)
self.enable_llm_translation_checkbox = QCheckBox(_("Enable AI translation"))
self.enable_llm_translation_checkbox.setChecked(self.transcription_options.enable_llm_translation)
self.enable_llm_translation_checkbox.stateChanged.connect(self.on_enable_llm_translation_changed)

View file

@ -39,6 +39,13 @@ class TranscriptionOptionsGroupBox(QGroupBox):
)
self.model_type_combo_box.changed.connect(self.on_model_type_changed)
self.advanced_settings_dialog = AdvancedSettingsDialog(
transcription_options=self.transcription_options, parent=self
)
self.advanced_settings_dialog.transcription_options_changed.connect(
self.on_transcription_options_changed
)
self.whisper_model_size_combo_box = QComboBox(self)
self.whisper_model_size_combo_box.addItems(
[size.value.title() for size in WhisperModelSize]
@ -102,13 +109,7 @@ class TranscriptionOptionsGroupBox(QGroupBox):
self.transcription_options_changed.emit(self.transcription_options)
def open_advanced_settings(self):
dialog = AdvancedSettingsDialog(
transcription_options=self.transcription_options, parent=self
)
dialog.transcription_options_changed.connect(
self.on_transcription_options_changed
)
dialog.exec()
self.advanced_settings_dialog.exec()
def on_transcription_options_changed(
self, transcription_options: TranscriptionOptions

View file

@ -59,7 +59,8 @@ def format_record_status_text(record: QSqlRecord) -> str:
status = FileTranscriptionTask.Status(record.value("status"))
match status:
case FileTranscriptionTask.Status.IN_PROGRESS:
return f'{_("In Progress")} ({record.value("progress") :.0%})'
in_progress_label = _("In Progress")
return f'{in_progress_label} ({record.value("progress") :.0%})'
case FileTranscriptionTask.Status.COMPLETED:
status = _("Completed")
started_at = record.value("time_started")
@ -68,7 +69,8 @@ def format_record_status_text(record: QSqlRecord) -> str:
status += f" ({TranscriptionTasksTableWidget.format_timedelta(datetime.fromisoformat(completed_at) - datetime.fromisoformat(started_at))})"
return status
case FileTranscriptionTask.Status.FAILED:
return f'{_("Failed")} ({record.value("error_message")})'
failed_label = _("Failed")
return f'{failed_label} ({record.value("error_message")})'
case FileTranscriptionTask.Status.CANCELED:
return _("Canceled")
case FileTranscriptionTask.Status.QUEUED:

View file

@ -1,3 +1,4 @@
import logging
from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QWidget, QMenu, QFileDialog
@ -23,15 +24,48 @@ class ExportTranscriptionMenu(QMenu):
self.transcription = transcription
self.transcription_service = transcription_service
actions = [
QAction(text=output_format.value.upper(), parent=self)
for output_format in OutputFormat
self.segments = [
Segment(
start=segment.start_time,
end=segment.end_time,
text=segment.text,
translation=segment.translation)
for segment in self.transcription_service.get_transcription_segments(
transcription_id=self.transcription.id_as_uuid
)
]
if self.segments and len(self.segments[0].translation) > 0:
text_label = _("Text")
translation_label = _("Translation")
actions = [
action
for output_format in OutputFormat
for action in [
QAction(text=f"{output_format.value.upper()} - {text_label}", parent=self),
QAction(text=f"{output_format.value.upper()} - {translation_label}", parent=self)
]
]
else:
actions = [
QAction(text=output_format.value.upper(), parent=self)
for output_format in OutputFormat
]
self.addActions(actions)
self.triggered.connect(self.on_menu_triggered)
@staticmethod
def extract_format_and_segment_key(action_text: str):
parts = action_text.split('-')
output_format = parts[0].strip()
label = parts[1].strip() if len(parts) > 1 else None
segment_key = 'translation' if label == _('Translation') else 'text'
return output_format, segment_key
def on_menu_triggered(self, action: QAction):
output_format = OutputFormat[action.text()]
output_format_value, segment_key = self.extract_format_and_segment_key(action.text())
output_format = OutputFormat[output_format_value]
default_path = self.transcription.get_output_file_path(
output_format=output_format
@ -47,15 +81,9 @@ class ExportTranscriptionMenu(QMenu):
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,
segments=self.segments,
output_format=output_format,
segment_key=segment_key
)

View file

@ -1,19 +1,22 @@
import enum
import logging
from dataclasses import dataclass
from typing import Optional
from uuid import UUID
from PyQt6.QtCore import pyqtSignal, Qt, QModelIndex, QItemSelection
from PyQt6.QtSql import QSqlTableModel, QSqlRecord
from PyQt6.QtGui import QFontMetrics
from PyQt6.QtGui import QFontMetrics, QTextOption
from PyQt6.QtWidgets import (
QWidget,
QTableView,
QStyledItemDelegate,
QAbstractItemView,
QTextEdit,
)
from buzz.locale import _
from buzz.translator import Translator
from buzz.transcriber.file_transcriber import to_timestamp
@ -22,6 +25,7 @@ class Column(enum.Enum):
END = enum.auto()
START = enum.auto()
TEXT = enum.auto()
TRANSLATION = enum.auto()
TRANSCRIPTION_ID = enum.auto()
@ -38,6 +42,18 @@ class TimeStampDelegate(QStyledItemDelegate):
return to_timestamp(value)
class WordWrapDelegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = QTextEdit(parent)
editor.setWordWrapMode(QTextOption.WrapMode.WordWrap)
editor.setAcceptRichText(False)
return editor
def setModelData(self, editor, model, index):
model.setData(index, editor.toPlainText())
class TranscriptionSegmentModel(QSqlTableModel):
def __init__(self, transcription_id: UUID):
super().__init__()
@ -53,20 +69,31 @@ class TranscriptionSegmentModel(QSqlTableModel):
class TranscriptionSegmentsEditorWidget(QTableView):
PARENT_PADDINGS = 40
segment_selected = pyqtSignal(QSqlRecord)
def __init__(self, transcription_id: UUID, parent: Optional[QWidget]):
def __init__(
self,
transcription_id: UUID,
translator: Translator,
parent: Optional[QWidget]
):
super().__init__(parent)
self.translator = translator
self.translator.translation.connect(self.update_translation)
model = TranscriptionSegmentModel(transcription_id=transcription_id)
self.setModel(model)
timestamp_delegate = TimeStampDelegate()
word_wrap_delegate = WordWrapDelegate()
self.column_definitions: list[ColDef] = [
ColDef("start", _("Start"), Column.START, delegate=timestamp_delegate),
ColDef("end", _("End"), Column.END, delegate=timestamp_delegate),
ColDef("text", _("Text"), Column.TEXT),
ColDef("text", _("Text"), Column.TEXT, delegate=word_wrap_delegate),
ColDef("translation", _("Translation"), Column.TRANSLATION, delegate=word_wrap_delegate),
]
for i in range(model.columnCount()):
@ -91,17 +118,52 @@ class TranscriptionSegmentsEditorWidget(QTableView):
self.selectionModel().selectionChanged.connect(self.on_selection_changed)
model.select()
self.has_translations = self.has_non_empty_translation()
# Show start before end
self.horizontalHeader().swapSections(1, 2)
font_metrics = QFontMetrics(self.font())
max_row_height = font_metrics.height() * 3
max_row_height = font_metrics.height() * 4
for row in range(self.model().rowCount()):
self.setRowHeight(row, max_row_height)
self.horizontalHeader().setStretchLastSection(True)
self.setColumnWidth(Column.START.value, 95)
self.setColumnWidth(Column.END.value, 95)
self.setWordWrap(True)
self.resizeColumnsToContents()
def has_non_empty_translation(self) -> bool:
for i in range(self.model().rowCount()):
if self.model().record(i).value("translation").strip():
return True
return False
def resizeEvent(self, event):
super().resizeEvent(event)
if not self.has_translations:
self.hideColumn(Column.TRANSLATION.value)
else:
self.showColumn(Column.TRANSLATION.value)
text_column_count = 2 if self.has_translations else 1
time_column_widths = self.columnWidth(Column.START.value) + self.columnWidth(Column.END.value)
text_column_width = (
int((self.parent().width() - self.PARENT_PADDINGS - time_column_widths) / text_column_count))
self.setColumnWidth(Column.TEXT.value, text_column_width)
self.setColumnWidth(Column.TRANSLATION.value, text_column_width)
def update_translation(self, translation: str, segment_id: Optional[int] = None):
self.has_translations = True
self.resizeEvent(None)
for row in range(self.model().rowCount()):
if self.model().record(row).value("id") == segment_id:
self.model().setData(self.model().index(row, Column.TRANSLATION.value), translation)
break
def on_selection_changed(
self, selected: QItemSelection, _deselected: QItemSelection

View file

@ -1,3 +1,4 @@
from enum import Enum
from typing import Optional
from PyQt6.QtCore import pyqtSignal, Qt
@ -10,8 +11,14 @@ from buzz.settings.shortcuts import Shortcuts
from buzz.widgets.icon import VisibilityIcon
class ViewMode(Enum):
TEXT = "Text"
TRANSLATION = "Translation"
TIMESTAMPS = "Timestamps"
class TranscriptionViewModeToolButton(QToolButton):
view_mode_changed = pyqtSignal(bool) # is_timestamps?
view_mode_changed = pyqtSignal(ViewMode)
def __init__(self, shortcuts: Shortcuts, parent: Optional[QWidget] = None):
super().__init__(parent)
@ -26,12 +33,19 @@ class TranscriptionViewModeToolButton(QToolButton):
menu.addAction(
_("Text"),
QKeySequence(shortcuts.get(Shortcut.VIEW_TRANSCRIPT_TEXT)),
lambda: self.view_mode_changed.emit(False),
lambda: self.view_mode_changed.emit(ViewMode.TEXT),
)
menu.addAction(
_("Translation"),
QKeySequence(shortcuts.get(Shortcut.VIEW_TRANSCRIPT_TRANSLATION)),
lambda: self.view_mode_changed.emit(ViewMode.TRANSLATION)
)
menu.addAction(
_("Timestamps"),
QKeySequence(shortcuts.get(Shortcut.VIEW_TRANSCRIPT_TIMESTAMPS)),
lambda: self.view_mode_changed.emit(True),
lambda: self.view_mode_changed.emit(ViewMode.TIMESTAMPS),
)
self.setMenu(menu)

View file

@ -1,8 +1,9 @@
import logging
import platform
from typing import Optional
from uuid import UUID
from PyQt6.QtCore import Qt
from PyQt6.QtCore import Qt, QThread
from PyQt6.QtGui import QFont
from PyQt6.QtMultimedia import QMediaPlayer
from PyQt6.QtSql import QSqlRecord
@ -11,6 +12,7 @@ from PyQt6.QtWidgets import (
QVBoxLayout,
QToolButton,
QLabel,
QMessageBox,
)
from buzz.locale import _
@ -18,25 +20,36 @@ from buzz.db.entity.transcription import Transcription
from buzz.db.service.transcription_service import TranscriptionService
from buzz.paths import file_path_as_title
from buzz.settings.shortcuts import Shortcuts
from buzz.settings.settings import Settings
from buzz.store.keyring_store import get_password, Key
from buzz.widgets.audio_player import AudioPlayer
from buzz.widgets.icon import (
FileDownloadIcon,
TranslateIcon
)
from buzz.translator import Translator
from buzz.widgets.text_display_box import TextDisplayBox
from buzz.widgets.toolbar import ToolBar
from buzz.transcriber.transcriber import TranscriptionOptions
from buzz.widgets.transcriber.advanced_settings_dialog import AdvancedSettingsDialog
from buzz.widgets.transcription_viewer.export_transcription_menu import (
ExportTranscriptionMenu,
)
from buzz.widgets.preferences_dialog.models.file_transcription_preferences import (
FileTranscriptionPreferences,
)
from buzz.widgets.transcription_viewer.transcription_segments_editor_widget import (
TranscriptionSegmentsEditorWidget,
)
from buzz.widgets.transcription_viewer.transcription_view_mode_tool_button import (
TranscriptionViewModeToolButton,
ViewMode
)
class TranscriptionViewerWidget(QWidget):
transcription: Transcription
settings = Settings()
def __init__(
self,
@ -55,10 +68,51 @@ class TranscriptionViewerWidget(QWidget):
self.setWindowTitle(file_path_as_title(transcription.file))
self.is_showing_timestamps = True
self.translation_thread = None
self.translator = None
self.view_mode = ViewMode.TIMESTAMPS
self.openai_access_token = get_password(Key.OPENAI_API_KEY)
preferences = self.load_preferences()
(
self.transcription_options,
self.file_transcription_options,
) = preferences.to_transcription_options(
openai_access_token=self.openai_access_token,
)
self.transcription_options_dialog = AdvancedSettingsDialog(
transcription_options=self.transcription_options, parent=self
)
self.transcription_options_dialog.transcription_options_changed.connect(
self.on_transcription_options_changed
)
self.translator = Translator(
self.transcription_options,
self.transcription_options_dialog,
)
self.translation_thread = QThread()
self.translator.moveToThread(self.translation_thread)
self.translation_thread.started.connect(self.translator.start)
self.translation_thread.finished.connect(
self.translation_thread.deleteLater
)
self.translator.finished.connect(self.translation_thread.quit)
self.translator.finished.connect(self.translator.deleteLater)
self.translation_thread.start()
self.table_widget = TranscriptionSegmentsEditorWidget(
transcription_id=UUID(hex=transcription.id), parent=self
transcription_id=UUID(hex=transcription.id),
translator=self.translator,
parent=self
)
self.table_widget.segment_selected.connect(self.on_segment_selected)
@ -102,6 +156,16 @@ class TranscriptionViewerWidget(QWidget):
export_tool_button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
toolbar.addWidget(export_tool_button)
translate_button = QToolButton()
translate_button.setText(_("Translate"))
translate_button.setIcon(TranslateIcon(self))
translate_button.setToolButtonStyle(
Qt.ToolButtonStyle.ToolButtonTextBesideIcon
)
translate_button.clicked.connect(self.on_translate_button_clicked)
toolbar.addWidget(translate_button)
layout.setMenuBar(toolbar)
layout.addWidget(self.table_widget)
@ -114,10 +178,10 @@ class TranscriptionViewerWidget(QWidget):
self.reset_view()
def reset_view(self):
if self.is_showing_timestamps:
if self.view_mode == ViewMode.TIMESTAMPS:
self.text_display_box.hide()
self.table_widget.show()
else:
elif self.view_mode == ViewMode.TEXT:
segments = self.transcription_service.get_transcription_segments(
transcription_id=self.transcription.id_as_uuid
)
@ -126,9 +190,19 @@ class TranscriptionViewerWidget(QWidget):
)
self.text_display_box.show()
self.table_widget.hide()
else: # ViewMode.TRANSLATION
# TODO add check for if translation exists
segments = self.transcription_service.get_transcription_segments(
transcription_id=self.transcription.id_as_uuid
)
self.text_display_box.setPlainText(
" ".join(segment.translation.strip() for segment in segments)
)
self.text_display_box.show()
self.table_widget.hide()
def on_view_mode_changed(self, is_timestamps: bool) -> None:
self.is_showing_timestamps = is_timestamps
def on_view_mode_changed(self, view_mode: ViewMode) -> None:
self.view_mode = view_mode
self.reset_view()
def on_segment_selected(self, segment: QSqlRecord):
@ -154,3 +228,46 @@ class TranscriptionViewerWidget(QWidget):
)
if current_segment is not None:
self.current_segment_label.setText(current_segment.value("text"))
def load_preferences(self):
self.settings.settings.beginGroup("file_transcriber")
preferences = FileTranscriptionPreferences.load(settings=self.settings.settings)
self.settings.settings.endGroup()
return preferences
def open_advanced_settings(self):
self.transcription_options_dialog.show()
def on_transcription_options_changed(
self, transcription_options: TranscriptionOptions
):
self.transcription_options = transcription_options
def on_translate_button_clicked(self):
if len(self.openai_access_token) == 0:
QMessageBox.information(
self,
_("API Key Required"),
_("Please enter OpenAI API Key in preferences")
)
return
if self.transcription_options.llm_model == "" or self.transcription_options.llm_prompt == "":
self.transcription_options_dialog.show()
return
segments = self.table_widget.segments()
for segment in segments:
self.translator.enqueue(segment.value("text"), segment.value("id"))
def closeEvent(self, event):
self.hide()
self.translator.stop()
if self.translation_thread.isRunning():
self.translation_thread.quit()
self.translation_thread.wait()
super().closeEvent(event)

View file

@ -111,7 +111,11 @@ class TestAdvancedSettingsDialog:
def test_should_update_advanced_settings(self, qtbot: QtBot):
dialog = AdvancedSettingsDialog(
transcription_options=TranscriptionOptions(
temperature=(0.0, 0.8), initial_prompt="prompt"
temperature=(0.0, 0.8),
initial_prompt="prompt",
enable_llm_translation=False,
llm_model="",
llm_prompt=""
)
)
qtbot.add_widget(dialog)
@ -122,12 +126,21 @@ class TestAdvancedSettingsDialog:
assert dialog.windowTitle() == _("Advanced Settings")
assert dialog.temperature_line_edit.text() == "0.0, 0.8"
assert dialog.initial_prompt_text_edit.toPlainText() == "prompt"
assert dialog.enable_llm_translation_checkbox.isChecked() is False
assert dialog.llm_model_line_edit.text() == ""
assert dialog.llm_prompt_text_edit.toPlainText() == ""
dialog.temperature_line_edit.setText("0.0, 0.8, 1.0")
dialog.initial_prompt_text_edit.setPlainText("new prompt")
dialog.enable_llm_translation_checkbox.setChecked(True)
dialog.llm_model_line_edit.setText("model")
dialog.llm_prompt_text_edit.setPlainText("Please translate this text")
assert transcription_options_mock.call_args[0][0].temperature == (0.0, 0.8, 1.0)
assert transcription_options_mock.call_args[0][0].initial_prompt == "new prompt"
assert transcription_options_mock.call_args[0][0].enable_llm_translation is True
assert transcription_options_mock.call_args[0][0].llm_model == "model"
assert transcription_options_mock.call_args[0][0].llm_prompt == "Please translate this text"
class TestTemperatureValidator:

View file

@ -7,6 +7,7 @@ from PyQt6.QtCore import QThread
from buzz.translator import Translator
from buzz.transcriber.transcriber import TranscriptionOptions
from buzz.widgets.transcriber.advanced_settings_dialog import AdvancedSettingsDialog
class TestTranslator:
@ -21,7 +22,7 @@ class TestTranslator:
if side_effect.call_count < 3:
raise Empty
return 'Hello, how are you?'
return "Hello, how are you?", None
side_effect.call_count = 0
@ -31,11 +32,18 @@ class TestTranslator:
mock_chat.completions.create.return_value = Mock(
choices=[Mock(message=Mock(content="AI Translated: Hello, how are you?"))]
)
translator = Translator(TranscriptionOptions(
transcription_options = TranscriptionOptions(
enable_llm_translation=False,
llm_model="llama3",
llm_prompt="Please translate this text:",
))
)
translator = Translator(
transcription_options,
AdvancedSettingsDialog(
transcription_options=transcription_options, parent=None
)
)
translator.queue = mock_queue
translator.start()
@ -59,12 +67,18 @@ class TestTranslator:
)
self.translation_thread = QThread()
self.translator = Translator(TranscriptionOptions(
self.transcription_options = TranscriptionOptions(
enable_llm_translation=False,
llm_model="llama3",
llm_prompt="Please translate this text:",
))
)
self.translator = Translator(
self.transcription_options,
AdvancedSettingsDialog(
transcription_options=self.transcription_options, parent=None
)
)
self.translator.moveToThread(self.translation_thread)

View file

@ -30,9 +30,9 @@ class TestExportTranscriptionMenu:
whisper_model_size=WhisperModelSize.SMALL.value,
)
)
transcription_segment_dao.insert(TranscriptionSegment(40, 299, "Bien", str(id)))
transcription_segment_dao.insert(TranscriptionSegment(40, 299, "Bien", "", str(id)))
transcription_segment_dao.insert(
TranscriptionSegment(299, 329, "venue dans", str(id))
TranscriptionSegment(299, 329, "venue dans", "", str(id))
)
return transcription_dao.find_by_id(str(id))

View file

@ -35,6 +35,7 @@ class TestShortcutsEditorWidget:
(_("Import URL"), "Ctrl+U"),
(_("Open Preferences Window"), "Ctrl+,"),
(_("View Transcript Text"), "Ctrl+E"),
(_("View Transcript Translation"), "Ctrl+L"),
(_("View Transcript Timestamps"), "Ctrl+T"),
(_("Clear History"), "Ctrl+S"),
(_("Cancel Transcription"), "Ctrl+X"),

View file

@ -1,12 +1,18 @@
import uuid
import time
import pytest
from pytestqt.qtbot import QtBot
from buzz.locale import _
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.transcription_view_mode_tool_button import (
TranscriptionViewModeToolButton,
ViewMode
)
from buzz.widgets.transcription_viewer.transcription_segments_editor_widget import (
TranscriptionSegmentsEditorWidget,
)
@ -32,9 +38,9 @@ class TestTranscriptionViewerWidget:
whisper_model_size=WhisperModelSize.SMALL.value,
)
)
transcription_segment_dao.insert(TranscriptionSegment(40, 299, "Bien", str(id)))
transcription_segment_dao.insert(TranscriptionSegment(40, 299, "Bien", "", str(id)))
transcription_segment_dao.insert(
TranscriptionSegment(299, 329, "venue dans", str(id))
TranscriptionSegment(299, 329, "venue dans", "", str(id))
)
return transcription_dao.find_by_id(str(id))
@ -55,6 +61,8 @@ class TestTranscriptionViewerWidget:
assert editor.model().index(0, 1).data() == 299
assert editor.model().index(0, 2).data() == 40
assert editor.model().index(0, 3).data() == "Bien"
widget.close()
time.sleep(3)
def test_should_update_segment_text(
self, qtbot, transcription, transcription_service, shortcuts
@ -68,3 +76,27 @@ class TestTranscriptionViewerWidget:
assert isinstance(editor, TranscriptionSegmentsEditorWidget)
editor.model().setData(editor.model().index(0, 3), "Biens")
widget.close()
time.sleep(3)
def test_text_button_changes_view_mode(
self, qtbot, transcription, transcription_service, shortcuts
):
widget = TranscriptionViewerWidget(
transcription, transcription_service, shortcuts
)
qtbot.add_widget(widget)
view_mode_tool_button = widget.findChild(TranscriptionViewModeToolButton)
menu = view_mode_tool_button.menu()
text_action = next(action for action in menu.actions() if action.text() == _("Text"))
text_action.trigger()
assert widget.view_mode == ViewMode.TEXT
text_action = next(action for action in menu.actions() if action.text() == _("Translation"))
text_action.trigger()
assert widget.view_mode == ViewMode.TRANSLATION
widget.close()
time.sleep(3)