mirror of
https://github.com/chidiwilliams/buzz.git
synced 2024-06-27 04:00:37 +02:00
Compare commits
2 commits
5904f84ec2
...
401665b184
Author | SHA1 | Date | |
---|---|---|---|
|
401665b184 | ||
|
8fbaf013b9 |
3
Makefile
3
Makefile
|
@ -31,9 +31,6 @@ clean:
|
|||
rm -rf dist/* || true
|
||||
|
||||
COVERAGE_THRESHOLD := 80
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
COVERAGE_THRESHOLD := 74
|
||||
endif
|
||||
|
||||
test: buzz/whisper_cpp.py translation_mo
|
||||
pytest -s -vv --cov=buzz --cov-report=xml --cov-report=html --benchmark-skip --cov-fail-under=${COVERAGE_THRESHOLD}
|
||||
|
|
|
@ -8,8 +8,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-05-26 08:13+0300\n"
|
||||
"PO-Revision-Date: 2024-05-18 16:28+0300\n"
|
||||
"POT-Creation-Date: 2024-06-07 21:05+0300\n"
|
||||
"PO-Revision-Date: 2024-06-07 21:06+0300\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: lv_LV\n"
|
||||
|
@ -43,7 +43,7 @@ msgid "View Transcript Timestamps"
|
|||
msgstr "Aplūkot atpazīšanas laikus"
|
||||
|
||||
#: buzz/settings/shortcut.py:25 buzz/widgets/main_window_toolbar.py:60
|
||||
#: buzz/widgets/main_window.py:199
|
||||
#: buzz/widgets/main_window.py:200
|
||||
msgid "Clear History"
|
||||
msgstr "Notīrīt vēsturi"
|
||||
|
||||
|
@ -124,23 +124,23 @@ msgstr "Adrese nav derīga"
|
|||
msgid "The URL you entered is invalid."
|
||||
msgstr "Jūsu ievadītā URL adrese nav derīga."
|
||||
|
||||
#: buzz/widgets/recording_transcriber_widget.py:60
|
||||
#: buzz/widgets/recording_transcriber_widget.py:63
|
||||
msgid "Live Recording"
|
||||
msgstr "Dzīvā ierakstīšana"
|
||||
|
||||
#: buzz/widgets/recording_transcriber_widget.py:109
|
||||
#: buzz/widgets/recording_transcriber_widget.py:112
|
||||
msgid "Click Record to begin..."
|
||||
msgstr "Klikšķiniet Ierakstīt, lai sāktu..."
|
||||
|
||||
#: buzz/widgets/recording_transcriber_widget.py:121
|
||||
#: buzz/widgets/recording_transcriber_widget.py:124
|
||||
msgid "Microphone:"
|
||||
msgstr "Mikrofons:"
|
||||
|
||||
#: buzz/widgets/recording_transcriber_widget.py:278
|
||||
#: buzz/widgets/recording_transcriber_widget.py:319
|
||||
msgid "An error occurred while starting a new recording:"
|
||||
msgstr "Sākot jaunu ierakstu notikusi kļūda:"
|
||||
|
||||
#: buzz/widgets/recording_transcriber_widget.py:282
|
||||
#: buzz/widgets/recording_transcriber_widget.py:323
|
||||
msgid ""
|
||||
"Please check your audio devices or check the application logs for more "
|
||||
"information."
|
||||
|
@ -168,7 +168,7 @@ msgstr "Fails"
|
|||
msgid "Help"
|
||||
msgstr "Palīdzība"
|
||||
|
||||
#: buzz/widgets/main_window.py:201
|
||||
#: buzz/widgets/main_window.py:202
|
||||
msgid ""
|
||||
"Are you sure you want to delete the selected transcription(s)? This action "
|
||||
"cannot be undone."
|
||||
|
@ -176,16 +176,16 @@ msgstr ""
|
|||
"Vai tiešām vēlaties dzēst izvēlētos transkriptus? Šī ir neatgriezeniska "
|
||||
"darbība."
|
||||
|
||||
#: buzz/widgets/main_window.py:221
|
||||
#: buzz/widgets/main_window.py:222
|
||||
msgid "Select audio file"
|
||||
msgstr "Izvēlieties audio failu"
|
||||
|
||||
#: buzz/widgets/main_window.py:255
|
||||
#: buzz/widgets/main_window.py:256
|
||||
#: buzz/widgets/preferences_dialog/models_preferences_widget.py:191
|
||||
msgid "Error"
|
||||
msgstr "Kļūda"
|
||||
|
||||
#: buzz/widgets/main_window.py:255
|
||||
#: buzz/widgets/main_window.py:256
|
||||
msgid "Unable to save OpenAI API key to keyring"
|
||||
msgstr "Neizdevās saglabāt OpenAI API atslēgu atslēgu saišķī"
|
||||
|
||||
|
@ -285,6 +285,7 @@ msgstr "Ieslēgt mapes vērošanu"
|
|||
|
||||
#: buzz/widgets/preferences_dialog/folder_watch_preferences_widget.py:47
|
||||
#: buzz/widgets/preferences_dialog/folder_watch_preferences_widget.py:50
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:84
|
||||
msgid "Browse"
|
||||
msgstr "Izvēlēties"
|
||||
|
||||
|
@ -304,24 +305,36 @@ msgstr "Izvēlieties vērojamo mapi"
|
|||
msgid "Select Output Folder"
|
||||
msgstr "Izvēlieties rezultātu mapi"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:31
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:44
|
||||
msgid "Test"
|
||||
msgstr "Pārbaudīt"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:37
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:50
|
||||
msgid "OpenAI API key"
|
||||
msgstr "OpenAI API atslēga"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:49
|
||||
msgid "Default export file name"
|
||||
msgstr "Eksporta faila nosaukums"
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:63
|
||||
msgid "OpenAI base url"
|
||||
msgstr "OpenAI adrese"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:74
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:80
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:72
|
||||
msgid "Default export file name"
|
||||
msgstr "Eksporta fails"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:78
|
||||
msgid "Enable live recording transcription export"
|
||||
msgstr "Eksportēt dzīvā ieraksta transkriptus"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:103
|
||||
msgid "Export folder"
|
||||
msgstr "Eksportēt mapē"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:128
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:134
|
||||
msgid "OpenAI API Key Test"
|
||||
msgstr "OpenAI API atslēgas pārbaude"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:75
|
||||
#: 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."
|
||||
|
@ -329,6 +342,10 @@ msgstr ""
|
|||
"Jūsu API atslēga ir derīga. Buzz izmantos to runas atpazīšanai ar Whisper "
|
||||
"API."
|
||||
|
||||
#: buzz/widgets/preferences_dialog/general_preferences_widget.py:157
|
||||
msgid "Select Export Folder"
|
||||
msgstr "Izvēlieties mapi kurā eksportēt"
|
||||
|
||||
#: buzz/widgets/preferences_dialog/models_preferences_widget.py:61
|
||||
msgid "Group"
|
||||
msgstr "Veids"
|
||||
|
|
|
@ -28,6 +28,7 @@ class RecordingAmplitudeListener(QObject):
|
|||
)
|
||||
self.stream.start()
|
||||
except sounddevice.PortAudioError:
|
||||
self.stop_recording()
|
||||
logging.exception("")
|
||||
|
||||
def stop_recording(self):
|
||||
|
|
|
@ -19,6 +19,8 @@ class Settings:
|
|||
RECORDING_TRANSCRIBER_LANGUAGE = "recording-transcriber/language"
|
||||
RECORDING_TRANSCRIBER_TEMPERATURE = "recording-transcriber/temperature"
|
||||
RECORDING_TRANSCRIBER_INITIAL_PROMPT = "recording-transcriber/initial-prompt"
|
||||
RECORDING_TRANSCRIBER_EXPORT_ENABLED = "recording-transcriber/export-enabled"
|
||||
RECORDING_TRANSCRIBER_EXPORT_FOLDER = "recording-transcriber/export-folder"
|
||||
|
||||
FILE_TRANSCRIBER_TASK = "file-transcriber/task"
|
||||
FILE_TRANSCRIBER_MODEL = "file-transcriber/model"
|
||||
|
@ -29,6 +31,7 @@ class Settings:
|
|||
FILE_TRANSCRIBER_EXPORT_FORMATS = "file-transcriber/export-formats"
|
||||
|
||||
DEFAULT_EXPORT_FILE_NAME = "transcriber/default-export-file-name"
|
||||
CUSTOM_OPENAI_BASE_URL = "transcriber/custom-openai-base-url"
|
||||
|
||||
SHORTCUTS = "shortcuts"
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ from typing import Optional, List
|
|||
from PyQt6.QtCore import QObject
|
||||
from openai import OpenAI
|
||||
|
||||
from buzz.settings.settings import Settings
|
||||
from buzz.transcriber.file_transcriber import FileTranscriber
|
||||
from buzz.transcriber.transcriber import FileTranscriptionTask, Segment, Task
|
||||
|
||||
|
@ -15,9 +16,14 @@ from buzz.transcriber.transcriber import FileTranscriptionTask, Segment, Task
|
|||
class OpenAIWhisperAPIFileTranscriber(FileTranscriber):
|
||||
def __init__(self, task: FileTranscriptionTask, parent: Optional["QObject"] = None):
|
||||
super().__init__(task=task, parent=parent)
|
||||
settings = Settings()
|
||||
custom_openai_base_url = settings.value(
|
||||
key=Settings.Key.CUSTOM_OPENAI_BASE_URL, default_value=""
|
||||
)
|
||||
self.task = task.transcription_options.task
|
||||
self.openai_client = OpenAI(
|
||||
api_key=self.transcription_task.transcription_options.openai_access_token
|
||||
api_key=self.transcription_task.transcription_options.openai_access_token,
|
||||
base_url=custom_openai_base_url if custom_openai_base_url else None
|
||||
)
|
||||
|
||||
def transcribe(self) -> List[Segment]:
|
||||
|
|
|
@ -38,7 +38,7 @@ class RecordingTranscriber(QObject):
|
|||
self.transcription_options = transcription_options
|
||||
self.current_stream = None
|
||||
self.input_device_index = input_device_index
|
||||
self.sample_rate = sample_rate
|
||||
self.sample_rate = sample_rate if sample_rate is not None else whisper_audio.SAMPLE_RATE
|
||||
self.model_path = model_path
|
||||
self.n_batch_samples = 5 * self.sample_rate # every 5 seconds
|
||||
# pause queueing if more than 3 batches behind
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
from platformdirs import user_documents_dir
|
||||
|
||||
from PyQt6.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool
|
||||
from PyQt6.QtWidgets import QWidget, QFormLayout, QPushButton, QMessageBox
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget,
|
||||
QFormLayout,
|
||||
QPushButton,
|
||||
QMessageBox,
|
||||
QCheckBox,
|
||||
QHBoxLayout,
|
||||
QFileDialog
|
||||
)
|
||||
from openai import AuthenticationError, OpenAI
|
||||
|
||||
from buzz.settings.settings import Settings
|
||||
|
@ -10,6 +20,7 @@ from buzz.widgets.line_edit import LineEdit
|
|||
from buzz.widgets.openai_api_key_line_edit import OpenAIAPIKeyLineEdit
|
||||
from buzz.locale import _
|
||||
|
||||
|
||||
class GeneralPreferencesWidget(QWidget):
|
||||
openai_api_key_changed = pyqtSignal(str)
|
||||
|
||||
|
@ -19,6 +30,8 @@ class GeneralPreferencesWidget(QWidget):
|
|||
):
|
||||
super().__init__(parent)
|
||||
|
||||
self.settings = Settings()
|
||||
|
||||
self.openai_api_key = get_password(Key.OPENAI_API_KEY)
|
||||
|
||||
layout = QFormLayout(self)
|
||||
|
@ -37,7 +50,17 @@ class GeneralPreferencesWidget(QWidget):
|
|||
layout.addRow(_("OpenAI API key"), self.openai_api_key_line_edit)
|
||||
layout.addRow("", self.test_openai_api_key_button)
|
||||
|
||||
self.settings = Settings()
|
||||
self.custom_openai_base_url = self.settings.value(
|
||||
key=Settings.Key.CUSTOM_OPENAI_BASE_URL, default_value=""
|
||||
)
|
||||
|
||||
self.custom_openai_base_url_line_edit = LineEdit(self.custom_openai_base_url, self)
|
||||
self.custom_openai_base_url_line_edit.textChanged.connect(
|
||||
self.on_custom_openai_base_url_changed
|
||||
)
|
||||
self.custom_openai_base_url_line_edit.setMinimumWidth(200)
|
||||
self.custom_openai_base_url_line_edit.setPlaceholderText("https://api.openai.com/v1")
|
||||
layout.addRow(_("OpenAI base url"), self.custom_openai_base_url_line_edit)
|
||||
|
||||
default_export_file_name = self.settings.get_default_export_file_template()
|
||||
|
||||
|
@ -48,6 +71,37 @@ class GeneralPreferencesWidget(QWidget):
|
|||
default_export_file_name_line_edit.setMinimumWidth(200)
|
||||
layout.addRow(_("Default export file name"), default_export_file_name_line_edit)
|
||||
|
||||
self.recording_export_enabled = self.settings.value(
|
||||
key=Settings.Key.RECORDING_TRANSCRIBER_EXPORT_ENABLED, default_value=False
|
||||
)
|
||||
|
||||
self.export_enabled_checkbox = QCheckBox(_("Enable live recording transcription export"))
|
||||
self.export_enabled_checkbox.setChecked(self.recording_export_enabled)
|
||||
self.export_enabled_checkbox.setObjectName("EnableRecordingExportCheckbox")
|
||||
self.export_enabled_checkbox.stateChanged.connect(self.on_recording_export_enable_changed)
|
||||
layout.addRow("", self.export_enabled_checkbox)
|
||||
|
||||
self.recording_export_folder_browse_button = QPushButton(_("Browse"))
|
||||
self.recording_export_folder_browse_button.clicked.connect(self.on_click_browse_export_folder)
|
||||
self.recording_export_folder_browse_button.setObjectName("RecordingExportFolderBrowseButton")
|
||||
|
||||
recording_export_folder = self.settings.value(
|
||||
key=Settings.Key.RECORDING_TRANSCRIBER_EXPORT_FOLDER, default_value=user_documents_dir()
|
||||
)
|
||||
|
||||
recording_export_folder_row = QHBoxLayout()
|
||||
self.recording_export_folder_line_edit = LineEdit(recording_export_folder, self)
|
||||
self.recording_export_folder_line_edit.textChanged.connect(self.on_recording_export_folder_changed)
|
||||
self.recording_export_folder_line_edit.setObjectName("RecordingExportFolderLineEdit")
|
||||
|
||||
self.recording_export_folder_line_edit.setEnabled(self.recording_export_enabled)
|
||||
self.recording_export_folder_browse_button.setEnabled(self.recording_export_enabled)
|
||||
|
||||
recording_export_folder_row.addWidget(self.recording_export_folder_line_edit)
|
||||
recording_export_folder_row.addWidget(self.recording_export_folder_browse_button)
|
||||
|
||||
layout.addRow(_("Export folder"), recording_export_folder_row)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def on_default_export_file_name_changed(self, text: str):
|
||||
|
@ -84,6 +138,31 @@ class GeneralPreferencesWidget(QWidget):
|
|||
self.update_test_openai_api_key_button()
|
||||
self.openai_api_key_changed.emit(key)
|
||||
|
||||
def on_custom_openai_base_url_changed(self, text: str):
|
||||
self.settings.set_value(Settings.Key.CUSTOM_OPENAI_BASE_URL, text)
|
||||
|
||||
def on_recording_export_enable_changed(self, state: int):
|
||||
self.recording_export_enabled = state == 2
|
||||
|
||||
self.recording_export_folder_line_edit.setEnabled(self.recording_export_enabled)
|
||||
self.recording_export_folder_browse_button.setEnabled(self.recording_export_enabled)
|
||||
|
||||
self.settings.set_value(
|
||||
Settings.Key.RECORDING_TRANSCRIBER_EXPORT_ENABLED,
|
||||
self.recording_export_enabled,
|
||||
)
|
||||
|
||||
def on_click_browse_export_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, _("Select Export Folder"))
|
||||
self.recording_export_folder_line_edit.setText(folder)
|
||||
self.on_recording_export_folder_changed(folder)
|
||||
|
||||
def on_recording_export_folder_changed(self, folder):
|
||||
self.settings.set_value(
|
||||
Settings.Key.RECORDING_TRANSCRIBER_EXPORT_FOLDER,
|
||||
folder,
|
||||
)
|
||||
|
||||
|
||||
class TestOpenAIApiKeyJob(QRunnable):
|
||||
class Signals(QObject):
|
||||
|
|
|
@ -75,4 +75,4 @@ class PreferencesDialog(QDialog):
|
|||
self.setLayout(layout)
|
||||
|
||||
self.setMinimumHeight(500)
|
||||
self.setMinimumWidth(500)
|
||||
self.setMinimumWidth(550)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import os
|
||||
import enum
|
||||
import logging
|
||||
import datetime
|
||||
from enum import auto
|
||||
from typing import Optional, Tuple
|
||||
|
||||
|
@ -136,6 +139,37 @@ class RecordingTranscriberWidget(QWidget):
|
|||
|
||||
self.reset_recording_amplitude_listener()
|
||||
|
||||
self.export_file = None
|
||||
self.export_enabled = self.settings.value(
|
||||
key=Settings.Key.RECORDING_TRANSCRIBER_EXPORT_ENABLED,
|
||||
default_value=False,
|
||||
)
|
||||
|
||||
def setup_for_export(self):
|
||||
export_folder = self.settings.value(
|
||||
key=Settings.Key.RECORDING_TRANSCRIBER_EXPORT_FOLDER,
|
||||
default_value="",
|
||||
)
|
||||
|
||||
date_time_now = datetime.datetime.now().strftime("%d-%b-%Y %H-%M-%S")
|
||||
|
||||
export_file_name_template = Settings().get_default_export_file_template()
|
||||
|
||||
export_file_name = (
|
||||
export_file_name_template.replace("{{ input_file_name }}", "live recording")
|
||||
.replace("{{ task }}", self.transcription_options.task.value)
|
||||
.replace("{{ language }}", self.transcription_options.language or "")
|
||||
.replace("{{ model_type }}", self.transcription_options.model.model_type.value)
|
||||
.replace("{{ model_size }}", self.transcription_options.model.whisper_model_size or "")
|
||||
.replace("{{ date_time }}", date_time_now)
|
||||
+ ".txt"
|
||||
)
|
||||
|
||||
if not os.path.isdir(export_folder):
|
||||
self.export_enabled = False
|
||||
|
||||
self.export_file = os.path.join(export_folder, export_file_name)
|
||||
|
||||
def on_transcription_options_changed(
|
||||
self, transcription_options: TranscriptionOptions
|
||||
):
|
||||
|
@ -180,6 +214,9 @@ class RecordingTranscriberWidget(QWidget):
|
|||
def start_recording(self):
|
||||
self.record_button.setDisabled(True)
|
||||
|
||||
if self.export_enabled:
|
||||
self.setup_for_export()
|
||||
|
||||
model_path = self.transcription_options.model.get_local_model_path()
|
||||
if model_path is not None:
|
||||
self.on_model_loaded(model_path)
|
||||
|
@ -260,6 +297,10 @@ class RecordingTranscriberWidget(QWidget):
|
|||
self.text_box.insertPlainText(text)
|
||||
self.text_box.moveCursor(QTextCursor.MoveOperation.End)
|
||||
|
||||
if self.export_enabled:
|
||||
with open(self.export_file, "a") as f:
|
||||
f.write(text + "\n\n")
|
||||
|
||||
def stop_recording(self):
|
||||
if self.transcriber is not None:
|
||||
self.transcriber.stop_recording()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
import time
|
||||
import logging
|
||||
from threading import Thread
|
||||
from typing import Callable, Any
|
||||
from unittest.mock import MagicMock
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
from PyQt6.QtCore import QThread
|
||||
|
||||
from buzz.model_loader import TranscriptionModel, ModelType, WhisperModelSize
|
||||
from buzz.transcriber.recording_transcriber import RecordingTranscriber
|
||||
from buzz.transcriber.transcriber import TranscriptionOptions, Task
|
||||
from tests.mock_sounddevice import MockInputStream
|
||||
from tests.model_loader import get_model_path
|
||||
|
||||
|
||||
class TestRecordingTranscriber:
|
||||
@pytest.mark.skip(reason="Hanging")
|
||||
def test_should_transcribe(self, qtbot):
|
||||
thread = QThread()
|
||||
|
||||
|
@ -18,15 +17,18 @@ class TestRecordingTranscriber:
|
|||
model_type=ModelType.WHISPER_CPP, whisper_model_size=WhisperModelSize.TINY
|
||||
)
|
||||
|
||||
model_path = get_model_path(transcription_model)
|
||||
transcriber = RecordingTranscriber(
|
||||
transcription_options=TranscriptionOptions(
|
||||
model=transcription_model, language="fr", task=Task.TRANSCRIBE
|
||||
),
|
||||
input_device_index=0,
|
||||
sample_rate=16_000,
|
||||
model_path=model_path,
|
||||
)
|
||||
transcriber.moveToThread(thread)
|
||||
|
||||
thread.started.connect(transcriber.start)
|
||||
thread.finished.connect(thread.deleteLater)
|
||||
|
||||
mock_transcription = Mock()
|
||||
|
@ -35,13 +37,14 @@ class TestRecordingTranscriber:
|
|||
transcriber.finished.connect(thread.quit)
|
||||
transcriber.finished.connect(transcriber.deleteLater)
|
||||
|
||||
with patch("sounddevice.InputStream", side_effect=MockInputStream), patch(
|
||||
"sounddevice.check_input_settings"
|
||||
), qtbot.wait_signal(transcriber.transcription, timeout=60 * 1000):
|
||||
with (patch("sounddevice.InputStream", side_effect=MockInputStream),
|
||||
patch("sounddevice.check_input_settings"),
|
||||
qtbot.wait_signal(transcriber.transcription, timeout=60 * 1000)):
|
||||
thread.start()
|
||||
|
||||
with qtbot.wait_signal(thread.finished, timeout=60 * 1000):
|
||||
transcriber.stop_recording()
|
||||
if transcriber is not None:
|
||||
transcriber.stop_recording()
|
||||
|
||||
text = mock_transcription.call_args[0][0]
|
||||
assert "Bienvenue dans Passe" in text
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from PyQt6.QtWidgets import QPushButton, QMessageBox, QLineEdit
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtWidgets import QPushButton, QMessageBox, QLineEdit, QCheckBox
|
||||
|
||||
from buzz.locale import _
|
||||
from buzz.settings.settings import Settings
|
||||
from buzz.widgets.preferences_dialog.general_preferences_widget import (
|
||||
GeneralPreferencesWidget,
|
||||
)
|
||||
|
@ -49,9 +51,60 @@ class TestGeneralPreferencesWidget:
|
|||
message_box_warning_mock.assert_called()
|
||||
assert message_box_warning_mock.call_args[0][1] == _("OpenAI API Key Test")
|
||||
assert (
|
||||
message_box_warning_mock.call_args[0][2]
|
||||
== "Incorrect API key provided: wrong-ap*-key. You can find your "
|
||||
"API key at https://platform.openai.com/account/api-keys."
|
||||
message_box_warning_mock.call_args[0][2]
|
||||
== "Incorrect API key provided: wrong-ap*-key. You can find your "
|
||||
"API key at https://platform.openai.com/account/api-keys."
|
||||
)
|
||||
|
||||
qtbot.waitUntil(mock_called)
|
||||
|
||||
def test_recording_export_preferences(self, qtbot, mocker):
|
||||
mocker.patch(
|
||||
"PyQt6.QtWidgets.QFileDialog.getExistingDirectory",
|
||||
return_value="/path/to/export/folder",
|
||||
)
|
||||
|
||||
widget = GeneralPreferencesWidget()
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
browse_button = widget.findChild(QPushButton, "RecordingExportFolderBrowseButton")
|
||||
checkbox = widget.findChild(QCheckBox, "EnableRecordingExportCheckbox")
|
||||
|
||||
browse_button_enabled = browse_button.isEnabled()
|
||||
|
||||
qtbot.mouseClick(widget.export_enabled_checkbox, Qt.MouseButton.LeftButton)
|
||||
checkbox.setChecked(not browse_button_enabled)
|
||||
|
||||
assert browse_button.isEnabled() != browse_button_enabled
|
||||
|
||||
qtbot.mouseClick(widget.recording_export_folder_browse_button, Qt.MouseButton.LeftButton)
|
||||
|
||||
assert widget.recording_export_folder_line_edit.text() == "/path/to/export/folder"
|
||||
|
||||
assert widget.settings.value(
|
||||
key=widget.settings.Key.RECORDING_TRANSCRIBER_EXPORT_ENABLED,
|
||||
default_value=False) != browse_button_enabled
|
||||
assert widget.settings.value(
|
||||
key=widget.settings.Key.RECORDING_TRANSCRIBER_EXPORT_FOLDER,
|
||||
default_value='/home/user/documents') == '/path/to/export/folder'
|
||||
|
||||
def test_openai_base_url_preferences(self, qtbot, mocker):
|
||||
widget = GeneralPreferencesWidget()
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
settings = Settings()
|
||||
|
||||
openai_base_url = settings.value(
|
||||
key=Settings.Key.CUSTOM_OPENAI_BASE_URL, default_value=""
|
||||
)
|
||||
|
||||
assert openai_base_url == ""
|
||||
assert widget.custom_openai_base_url_line_edit.text() == ""
|
||||
|
||||
widget.custom_openai_base_url_line_edit.setText("https://localhost:8000/v1")
|
||||
|
||||
updated_openai_base_url = settings.value(
|
||||
key=Settings.Key.CUSTOM_OPENAI_BASE_URL, default_value=""
|
||||
)
|
||||
|
||||
assert updated_openai_base_url == "https://localhost:8000/v1"
|
||||
|
|
|
@ -1,30 +1,110 @@
|
|||
import os
|
||||
import time
|
||||
import tempfile
|
||||
import platform
|
||||
|
||||
from unittest.mock import Mock, patch
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from buzz.locale import _
|
||||
from buzz.widgets.recording_transcriber_widget import RecordingTranscriberWidget
|
||||
from buzz.settings.settings import Settings
|
||||
|
||||
from tests.mock_sounddevice import MockInputStream
|
||||
import pytest
|
||||
|
||||
|
||||
class TestRecordingTranscriberWidget:
|
||||
def test_should_set_window_title(self, qtbot: QtBot):
|
||||
widget = RecordingTranscriberWidget()
|
||||
qtbot.add_widget(widget)
|
||||
assert widget.windowTitle() == _("Live Recording")
|
||||
widget.close()
|
||||
with (patch("sounddevice.InputStream", side_effect=MockInputStream),
|
||||
patch(
|
||||
"buzz.transcriber.recording_transcriber.RecordingTranscriber.get_device_sample_rate",
|
||||
return_value=16_000),
|
||||
patch("sounddevice.check_input_settings")):
|
||||
widget = RecordingTranscriberWidget()
|
||||
qtbot.add_widget(widget)
|
||||
assert widget.windowTitle() == _("Live Recording")
|
||||
|
||||
@pytest.mark.skip(reason="Seg faults on CI")
|
||||
# Test will hang if we call close before mock_sounddevice thread has fully started.
|
||||
time.sleep(3)
|
||||
|
||||
widget.close()
|
||||
|
||||
# on CI transcribed output is garbage, so we check if there is anything
|
||||
@pytest.mark.skipif(
|
||||
platform.system() == "Darwin",
|
||||
reason="Seg faults on CI",
|
||||
)
|
||||
def test_should_transcribe(self, qtbot):
|
||||
widget = RecordingTranscriberWidget()
|
||||
qtbot.add_widget(widget)
|
||||
with (patch("sounddevice.InputStream", side_effect=MockInputStream),
|
||||
patch(
|
||||
"buzz.transcriber.recording_transcriber.RecordingTranscriber.get_device_sample_rate",
|
||||
return_value=16_000),
|
||||
patch("sounddevice.check_input_settings")):
|
||||
widget = RecordingTranscriberWidget()
|
||||
widget.device_sample_rate = 16_000
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
assert len(widget.text_box.toPlainText()) == 0
|
||||
|
||||
def assert_text_box_contains_text():
|
||||
assert len(widget.text_box.toPlainText()) > 0
|
||||
|
||||
widget.record_button.click()
|
||||
qtbot.wait_until(callback=assert_text_box_contains_text, timeout=60 * 1000)
|
||||
|
||||
with qtbot.wait_signal(widget.transcription_thread.finished, timeout=60 * 1000):
|
||||
widget.stop_recording()
|
||||
|
||||
assert len(widget.text_box.toPlainText()) > 0
|
||||
widget.close()
|
||||
|
||||
# on CI transcribed output is garbage, so we check if there is anything
|
||||
@pytest.mark.skipif(
|
||||
platform.system() == "Darwin",
|
||||
reason="Seg faults on CI",
|
||||
)
|
||||
def test_should_transcribe_and_export(self, qtbot):
|
||||
settings = Settings()
|
||||
settings.set_value(
|
||||
Settings.Key.RECORDING_TRANSCRIBER_EXPORT_FOLDER,
|
||||
tempfile.gettempdir(),
|
||||
)
|
||||
|
||||
try:
|
||||
os.remove(os.path.join(tempfile.gettempdir(), 'mock-export-file.txt'))
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
with (patch("sounddevice.InputStream", side_effect=MockInputStream),
|
||||
patch(
|
||||
"buzz.transcriber.recording_transcriber.RecordingTranscriber.get_device_sample_rate",
|
||||
return_value=16_000),
|
||||
patch("sounddevice.check_input_settings"),
|
||||
patch(
|
||||
'buzz.settings.settings.Settings.get_default_export_file_template',
|
||||
return_value='mock-export-file')):
|
||||
|
||||
widget = RecordingTranscriberWidget()
|
||||
widget.device_sample_rate = 16_000
|
||||
widget.export_enabled = True
|
||||
qtbot.add_widget(widget)
|
||||
|
||||
assert len(widget.text_box.toPlainText()) == 0
|
||||
|
||||
def assert_text_box_contains_text():
|
||||
assert len(widget.text_box.toPlainText()) > 0
|
||||
|
||||
widget.record_button.click()
|
||||
qtbot.wait_until(callback=assert_text_box_contains_text, timeout=60 * 1000)
|
||||
|
||||
with qtbot.wait_signal(widget.transcription_thread.finished, timeout=60 * 1000):
|
||||
widget.stop_recording()
|
||||
|
||||
def assert_text_box_contains_text():
|
||||
assert len(widget.text_box.toPlainText()) > 0
|
||||
|
||||
widget.record_button.click()
|
||||
qtbot.wait_until(callback=assert_text_box_contains_text, timeout=60 * 1000)
|
||||
with open(widget.export_file, 'r') as file:
|
||||
contents = file.read()
|
||||
assert len(contents) > 0
|
||||
|
||||
with qtbot.wait_signal(widget.transcription_thread.finished, timeout=60 * 1000):
|
||||
widget.stop_recording()
|
||||
|
||||
assert "Welcome to Passe" in widget.text_box.toPlainText()
|
||||
widget.close()
|
||||
widget.close()
|
||||
|
|
Loading…
Reference in a new issue