diff --git a/src/voice_transcriptor/ui/settings_dialog.py b/src/voice_transcriptor/ui/settings_dialog.py index 729349c..4719128 100644 --- a/src/voice_transcriptor/ui/settings_dialog.py +++ b/src/voice_transcriptor/ui/settings_dialog.py @@ -10,11 +10,13 @@ from PySide6.QtWidgets import ( QDialog, QDialogButtonBox, QCheckBox, + QComboBox, QFileDialog, QFormLayout, QHBoxLayout, QLineEdit, QMessageBox, + QPlainTextEdit, QPushButton, QSpinBox, QToolButton, @@ -24,7 +26,17 @@ from PySide6.QtWidgets import ( from voice_transcriptor.models import AppSettings from voice_transcriptor.services.credentials import CredentialError, CredentialService -from voice_transcriptor.services.settings import SettingsError, SettingsRepository +from voice_transcriptor.services.settings import SUPPORTED_MODEL_SUGGESTIONS, SettingsError, SettingsRepository + + +class EditableModelCombo(QComboBox): + """Editable model picker with the previous line-edit convenience API.""" + + def text(self) -> str: + return self.currentText() + + def setText(self, value: str) -> None: + self.setCurrentText(value) class SettingsDialog(QDialog): @@ -44,7 +56,10 @@ class SettingsDialog(QDialog): self._credentials = credentials self.setWindowTitle("Settings") - self.model_input = QLineEdit(settings.model, self) + self.model_input = EditableModelCombo(self) + self.model_input.setEditable(True) + self.model_input.addItems(SUPPORTED_MODEL_SUGGESTIONS) + self.model_input.setCurrentText(settings.model) self.model_input.setObjectName("modelInput") self.language_input = QLineEdit(settings.language, self) self.language_input.setObjectName("languageInput") @@ -53,6 +68,9 @@ class SettingsDialog(QDialog): self.api_key_input.setEchoMode(QLineEdit.EchoMode.Password) self.output_directory_input = QLineEdit(str(settings.output_directory), self) self.output_directory_input.setObjectName("outputDirectoryInput") + self.context_input = QPlainTextEdit(settings.context_vocabulary, self) + self.context_input.setObjectName("contextVocabularyInput") + self.context_input.setPlaceholderText("Names, acronyms, technical terms, and conversation context") self.choose_directory_button = QPushButton("Browse…", self) self.choose_directory_button.setObjectName("chooseDirectoryButton") self.choose_directory_button.clicked.connect(self.choose_output_directory) @@ -65,6 +83,7 @@ class SettingsDialog(QDialog): form.addRow("OpenAI API key", self.api_key_input) form.addRow("Model", self.model_input) form.addRow("Language", self.language_input) + form.addRow("Context / Vocabulary", self.context_input) form.addRow("Output directory", output_directory_layout) self.advanced_toggle = QToolButton(self) @@ -133,7 +152,7 @@ class SettingsDialog(QDialog): ) return - model = self.model_input.text().strip() + model = self.model_input.currentText().strip() language = self.language_input.text().strip() if not model or not language: QMessageBox.warning(self, "Invalid settings", "Model and language are required.") @@ -146,7 +165,7 @@ class SettingsDialog(QDialog): return updated_settings = AppSettings( model, language, output_directory, chunk_duration, overlap, - self.retain_temporary_files_input.isChecked(), + self.retain_temporary_files_input.isChecked(), self.context_input.toPlainText().strip(), ) try: self._repository.save(updated_settings) diff --git a/tests/ui/test_settings_dialog.py b/tests/ui/test_settings_dialog.py index ab049f8..1193034 100644 --- a/tests/ui/test_settings_dialog.py +++ b/tests/ui/test_settings_dialog.py @@ -3,11 +3,12 @@ from __future__ import annotations from pathlib import Path import pytest -from PySide6.QtWidgets import QLineEdit, QMessageBox +from PySide6.QtWidgets import QComboBox, QLineEdit, QMessageBox from voice_transcriptor.models import AppSettings from voice_transcriptor.services.credentials import CredentialError from voice_transcriptor.services.settings import SettingsError +from voice_transcriptor.services.settings import SUPPORTED_MODEL_SUGGESTIONS from voice_transcriptor.ui.settings_dialog import SettingsDialog @@ -53,6 +54,10 @@ def test_populates_fields_from_settings(qtbot, settings: AppSettings) -> None: assert dialog.advanced_panel.isVisible() is False assert dialog.chunk_duration_input.value() == 900 assert dialog.chunk_overlap_input.value() == 15 + assert isinstance(dialog.model_input, QComboBox) + assert dialog.model_input.isEditable() + assert tuple(dialog.model_input.itemText(i) for i in range(dialog.model_input.count())) == SUPPORTED_MODEL_SUGGESTIONS + assert dialog.context_input.toPlainText() == settings.context_vocabulary def test_advanced_settings_are_saved(qtbot, settings: AppSettings) -> None: @@ -98,10 +103,11 @@ def test_save_persists_new_api_key_and_emits_saved_settings(qtbot, settings: App dialog.api_key_input.setText(supplied_key) dialog.model_input.setText("gpt-4o-mini-transcribe") + dialog.context_input.setPlainText("Pix, Banco do Brasil") dialog.save() assert saved_with.args == [ - AppSettings("gpt-4o-mini-transcribe", "pt-BR", settings.output_directory) + AppSettings("gpt-4o-mini-transcribe", "pt-BR", settings.output_directory, context_vocabulary="Pix, Banco do Brasil") ] assert credentials.api_key == supplied_key assert repository.saved == saved_with.args