Support multi models. Moved config stuff into config_dialog

This commit is contained in:
mesonium
2024-06-15 22:11:50 +02:00
committed by hueso
parent 31c2868599
commit f5db7f9809
4 changed files with 117 additions and 136 deletions

View File

@@ -1,108 +0,0 @@
# This file is part of Gajim.
#
# Gajim is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import logging
import typing
from gajim.common.app import Any
from gajim.plugins.plugins_i18n import _
from .models import openai_whisper
from .stt_voice_messages import STTVoiceMessagesPlugin
log = logging.getLogger('gajim.p.stt_voice_messages_config')
SUPPORTED_MODELS: dict[str, dict[str, typing.Union[list[str], Any, str]]] = {
'model_openaiwhisper': {
'moduls': ['whisper'],
'class': openai_whisper.WhisperModel,
'name': 'OpenAI Whisper'
},
'model_ctranslate2': {
'moduls': ['ctranslate2'],
'class': None,
'name': _('CTranslate2')
},
'model_faster-whisper': {
'moduls': ['faster-whisper'],
'class': None,
'name:': _('Faster-Whisper')
},
'model_distill': {
'moduls': ['transformers', 'accelerate', 'datasets[audio]'],
'class': None,
'name': _('Distill')
}
}
class Configuration:
def __init__(self, plugin: STTVoiceMessagesPlugin):
self.plugin = plugin
self._available_models: dict[
str, dict[str, typing.Union[list[str], Any, str]]] = {}
self.check_available_moduls()
@property
def available_models(self) -> dict[str, dict[str, typing.Union[list[str], Any, str]]]:
return self._available_models
def on_setting(self, value: Any, data: Any) -> None:
if isinstance(value, str):
value.strip()
log.debug('plugin config before:\n %s', self.plugin.config.data)
self.plugin.config[data] = value
log.debug('plugin config after:\n %s', self.plugin.config.data)
def on_set_model(self, value: Any, data: Any) -> None:
if isinstance(value, str):
value.strip()
log.debug('plugin config before:\n %s', self.plugin.config.data)
self.plugin.config['model_class'] = self._available_models[value][
'class']
self.on_setting(value, data)
log.debug('plugin config after:\n %s', self.plugin.config.data)
@staticmethod
def is_module_available(module: str) -> bool:
try:
__import__(module)
return True
except ModuleNotFoundError:
log.debug('Could not find module %s', module)
return False
except ImportError as ex:
log.debug(str(ex))
return False
def check_available_moduls(self):
for model in SUPPORTED_MODELS:
available = True
for modul in SUPPORTED_MODELS[model]['moduls']:
if not self.is_module_available(modul):
available = False
continue
if available:
self._available_models[model] = SUPPORTED_MODELS[model]
if (self.plugin.config.data['model_class'] is None
and len(self._available_models) > 0):
model = list(self._available_models)[0]
self.on_set_model(model, 'model')
log.debug('Choose first available model!')
else:
log.debug('Available model already chosen!')
log.debug('models = %s', self._available_models)

View File

@@ -16,6 +16,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import typing
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -23,6 +24,7 @@ import whisper
from gi.repository import Gtk from gi.repository import Gtk
from gajim.common import app from gajim.common import app
from gajim.common.app import Any
from gajim.gtk.builder import get_builder from gajim.gtk.builder import get_builder
from gajim.gtk.const import Setting, SettingKind, SettingType from gajim.gtk.const import Setting, SettingKind, SettingType
from gajim.gtk.settings import SettingsBox from gajim.gtk.settings import SettingsBox
@@ -30,7 +32,7 @@ from gajim.gtk.sidebar_switcher import SideBarSwitcher
from gajim.plugins.helpers import get_builder from gajim.plugins.helpers import get_builder
from gajim.plugins.plugins_i18n import _ from gajim.plugins.plugins_i18n import _
from ..configs import Configuration from ..models import openai_whisper
if TYPE_CHECKING: if TYPE_CHECKING:
from ..stt_voice_messages import STTVoiceMessagesPlugin from ..stt_voice_messages import STTVoiceMessagesPlugin
@@ -38,6 +40,95 @@ if TYPE_CHECKING:
log = logging.getLogger('gajim.p.stt_voice_messages_config_dialog') log = logging.getLogger('gajim.p.stt_voice_messages_config_dialog')
SUPPORTED_MODELS: dict[str, dict[str, typing.Union[list[str], Any, str]]] = {
'model_openaiwhisper': {
'moduls': ['whisper'],
'class': openai_whisper.WhisperModel,
'name': 'OpenAI Whisper'
},
'model_ctranslate2': {
'moduls': ['ctranslate2'],
'class': None,
'name': _('CTranslate2')
},
'model_faster-whisper': {
'moduls': ['faster-whisper'],
'class': None,
'name:': _('Faster-Whisper')
},
'model_distill': {
'moduls': ['transformers', 'accelerate', 'datasets[audio]'],
'class': None,
'name': _('Distill')
}
}
class Configuration:
def __init__(self, plugin: STTVoiceMessagesPlugin):
self._plugin = plugin
self._available_models: dict[
str, dict[str, typing.Union[list[str], Any, str]]] = {}
self.check_available_moduls()
@property
def plugin(self) -> STTVoiceMessagesPlugin:
return self._plugin
@property
def available_models(self) -> dict[str, dict[str, typing.Union[list[str], Any, str]]]:
return self._available_models
def on_setting(self, value: Any, data: Any) -> None:
if isinstance(value, str):
value.strip()
log.debug('plugin config before:\n %s', self.plugin.config.data)
self.plugin.config[data] = value
log.debug('plugin config after:\n %s', self.plugin.config.data)
def on_set_model(self, value: Any, data: Any) -> None:
if isinstance(value, str):
value.strip()
log.debug('plugin config before:\n %s', self.plugin.config.data)
self.plugin.config['model_class'] = self._available_models[value][
'class']
self.on_setting(value, data)
log.debug('plugin config after:\n %s', self.plugin.config.data)
@staticmethod
def is_module_available(module: str) -> bool:
try:
__import__(module)
return True
except ModuleNotFoundError:
log.debug('Could not find module %s', module)
return False
except ImportError as ex:
log.debug(str(ex))
return False
def check_available_moduls(self):
for model in SUPPORTED_MODELS:
available = True
for modul in SUPPORTED_MODELS[model]['moduls']:
if not self.is_module_available(modul):
available = False
continue
if available:
self._available_models[model] = SUPPORTED_MODELS[model]
if (self.plugin.config.data['model_class'] is None
and len(self._available_models) > 0):
model = list(self._available_models)[0]
self.on_set_model(model, 'model')
log.debug('Choose first available model!')
else:
log.debug('Available model already chosen!')
log.debug('models = %s', self._available_models)
class PreferenceBox(SettingsBox): class PreferenceBox(SettingsBox):
def __init__(self, settings: list[Setting]) -> None: def __init__(self, settings: list[Setting]) -> None:
SettingsBox.__init__(self, None) SettingsBox.__init__(self, None)
@@ -52,7 +143,7 @@ class PreferenceBox(SettingsBox):
class STTVoiceMessagesConfigDialog(Gtk.ApplicationWindow): class STTVoiceMessagesConfigDialog(Gtk.ApplicationWindow):
def __init__(self, plugin: STTVoiceMessagesPlugin, parent: Gtk.Window) -> None: def __init__(self, config: Configuration, parent: Gtk.Window) -> None:
Gtk.ApplicationWindow.__init__(self) Gtk.ApplicationWindow.__init__(self)
self.set_application(app.app) self.set_application(app.app)
@@ -72,45 +163,47 @@ class STTVoiceMessagesConfigDialog(Gtk.ApplicationWindow):
self._ui.grid.attach(side_bar_switcher, 0, 0, 1, 1) self._ui.grid.attach(side_bar_switcher, 0, 0, 1, 1)
self.add(self._ui.grid) self.add(self._ui.grid)
self.config = config
self.plugin = self.config.plugin
prefs: list[tuple[str, type[PreferenceBox]]] = [ prefs: list[tuple[str, type[PreferenceBox]]] = [
('stt_behaviour', self.STTBehaviour), ('stt_behaviour', self.STTBehaviour),
('models', self.Models), ('models', self.Models),
('whisper_general', self.OpenAIWhisperGeneral), ('whisper_general', self.OpenAIWhisperGeneral),
] ]
self._add_prefs(prefs) self._add_prefs(prefs)
self.show_all() self.show_all()
class STTBehaviour(PreferenceBox): class STTBehaviour(PreferenceBox):
def __init__(self, config: Configuration) -> None: def __init__(self, config_dialog: STTVoiceMessagesConfigDialog) -> None:
settings = [ settings = [
Setting(SettingKind.SWITCH, Setting(SettingKind.SWITCH,
_('Auto Transcribe'), _('Auto Transcribe'),
SettingType.VALUE, SettingType.VALUE,
value=config.plugin.config['auto_transcribe'], value=config_dialog.plugin.config['auto_transcribe'],
data='auto_transcribe', data='auto_transcribe',
callback=config.on_setting) callback=config_dialog.config.on_setting)
] ]
PreferenceBox.__init__(self, settings) PreferenceBox.__init__(self, settings)
class Models(PreferenceBox): class Models(PreferenceBox):
def __init__(self, config: Configuration) -> None: def __init__(self, config_dialog: STTVoiceMessagesConfigDialog) -> None:
models: list[tuple[str, str]] = [] models: list[tuple[str, str]] = []
for key, value in config.available_models.items(): for key, value in config_dialog.config.available_models.items():
assert value['name'] is str
models.append( models.append(
(key, value['name']) (key, str(value['name']))
) )
settings = [ settings = [
Setting(SettingKind.COMBO, Setting(SettingKind.COMBO,
_('Speech To Text Model'), _('Speech To Text Model'),
SettingType.VALUE, SettingType.VALUE,
value=config.plugin.config['model'], value=config_dialog.plugin.config['model'],
data='model', data='model',
callback=config.on_set_model, callback=config_dialog.config.on_set_model,
props={'combo_items': models}, props={'combo_items': models},
desc=_('Choose Model to use')), desc=_('Choose Model to use')),
] ]
@@ -118,23 +211,23 @@ class STTVoiceMessagesConfigDialog(Gtk.ApplicationWindow):
PreferenceBox.__init__(self, settings) PreferenceBox.__init__(self, settings)
class OpenAIWhisperGeneral(PreferenceBox): class OpenAIWhisperGeneral(PreferenceBox):
def __init__(self, config: Configuration) -> None: def __init__(self, config_dialog: STTVoiceMessagesConfigDialog) -> None:
settings = [ settings = [
Setting(SettingKind.POPOVER, Setting(SettingKind.POPOVER,
_('Language Model Size'), _('Language Model Size'),
SettingType.VALUE, SettingType.VALUE,
value=config.plugin.config['whisperai_model_size'], value=config_dialog.plugin.config['whisperai_model_size'],
data='whisperai_model_size', data='whisperai_model_size',
callback=config.on_setting, callback=config_dialog.config.on_setting,
props={'entries': whisper.available_models()}), props={'entries': whisper.available_models()}),
Setting(SettingKind.SWITCH, Setting(SettingKind.SWITCH,
_('Translate'), _('Translate'),
SettingType.VALUE, SettingType.VALUE,
value=config.plugin.config['whisperai_translate'], value=config_dialog.plugin.config['whisperai_translate'],
data='whisperai_translate', data='whisperai_translate',
callback=config.on_setting) callback=config_dialog.config.on_setting)
] ]
PreferenceBox.__init__(self, settings) PreferenceBox.__init__(self, settings)

View File

@@ -13,14 +13,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>. # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk
import logging import logging
from .. import helper from gi.repository import Gtk
from gajim.plugins.gajimplugin import GajimPluginConfig from gajim.plugins.gajimplugin import GajimPluginConfig
from gajim.plugins.plugins_i18n import _ from gajim.plugins.plugins_i18n import _
from .. import helper
log = logging.getLogger('gajim.p.stt_voice_messages_sttbox') log = logging.getLogger('gajim.p.stt_voice_messages_sttbox')
class STTBox(Gtk.Box): class STTBox(Gtk.Box):
@@ -52,9 +53,6 @@ class STTBox(Gtk.Box):
self.show_all() self.show_all()
#def update_config(self, config: GajimPluginConfig):
# self._model = config.data['class']()
def _on_transcribe_clicked(self, _button: Gtk.Button) -> None: def _on_transcribe_clicked(self, _button: Gtk.Button) -> None:
log.debug('config.data = %s', self._config.data) log.debug('config.data = %s', self._config.data)
model_class = self._config.data['model_class'] model_class = self._config.data['model_class']

View File

@@ -15,17 +15,13 @@
from __future__ import annotations from __future__ import annotations
import logging
from functools import partial from functools import partial
from pathlib import Path
from gi.repository import Gtk
from gajim.plugins import GajimPlugin from gajim.plugins import GajimPlugin
from gajim.plugins.plugins_i18n import _ from gajim.plugins.plugins_i18n import _
from .gtk.config_dialog import *
from .gtk.sttbox import STTBox from .gtk.sttbox import STTBox
from .gtk.config_dialog import STTVoiceMessagesConfigDialog
log = logging.getLogger('gajim.p.stt_voice_messages') log = logging.getLogger('gajim.p.stt_voice_messages')
@@ -33,7 +29,9 @@ log = logging.getLogger('gajim.p.stt_voice_messages')
class STTVoiceMessagesPlugin(GajimPlugin): class STTVoiceMessagesPlugin(GajimPlugin):
def init(self) -> None: def init(self) -> None:
self.description = _('Transcribes voice messages to text.') self.description = _('Transcribes voice messages to text.')
self.config_dialog = partial(STTVoiceMessagesConfigDialog, self) self._config = Configuration(self)
self._config.check_available_moduls()
self.config_dialog = partial(STTVoiceMessagesConfigDialog, self._config)
self.gui_extension_points = { self.gui_extension_points = {
'preview_audio': (self._on_preview_audio_created, None), 'preview_audio': (self._on_preview_audio_created, None),