Compare commits

...

2 commits

Author SHA1 Message Date
Raivis Dejus 401665b184
Adding setting for custom OpenAI base url (#785) 2024-06-07 19:32:08 +00:00
Raivis Dejus 8fbaf013b9
Add live transcript export (#784) 2024-06-07 17:21:57 +00:00
13 changed files with 334 additions and 53 deletions

View file

@ -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}

View file

@ -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"

View file

@ -28,6 +28,7 @@ class RecordingAmplitudeListener(QObject):
)
self.stream.start()
except sounddevice.PortAudioError:
self.stop_recording()
logging.exception("")
def stop_recording(self):

View file

@ -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"

View file

@ -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]:

View file

@ -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

View file

@ -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):

View file

@ -75,4 +75,4 @@ class PreferencesDialog(QDialog):
self.setLayout(layout)
self.setMinimumHeight(500)
self.setMinimumWidth(500)
self.setMinimumWidth(550)

View file

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

View file

@ -1,5 +1,6 @@
import os
import time
import logging
from threading import Thread
from typing import Callable, Any
from unittest.mock import MagicMock

View file

@ -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

View file

@ -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"

View file

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