File indexing completed on 2024-12-22 04:28:24
0001 /* 0002 SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "speechtotextengineloader.h" 0008 #include "speechtotextclient.h" 0009 #include "textspeechtotext_debug.h" 0010 #include <QCoreApplication> 0011 #include <QDir> 0012 #include <QPluginLoader> 0013 using namespace TextSpeechToText; 0014 class TextSpeechToText::SpeechToTextEngineLoaderPrivate 0015 { 0016 public: 0017 QSet<QString> loadedPlugins; 0018 QHash<QString, SpeechToTextClient *> speechToTextClients; 0019 }; 0020 0021 SpeechToTextEngineLoader *SpeechToTextEngineLoader::self() 0022 { 0023 static SpeechToTextEngineLoader s_self; 0024 return &s_self; 0025 } 0026 0027 SpeechToTextEngineLoader::SpeechToTextEngineLoader(QObject *parent) 0028 : QObject{parent} 0029 , d(new TextSpeechToText::SpeechToTextEngineLoaderPrivate) 0030 { 0031 loadPlugins(); 0032 } 0033 0034 SpeechToTextEngineLoader::~SpeechToTextEngineLoader() = default; 0035 0036 void SpeechToTextEngineLoader::loadPlugins() 0037 { 0038 const QStringList libPaths = QCoreApplication::libraryPaths(); 0039 const QString pathSuffix(QStringLiteral("/kf" QT_STRINGIFY(QT_VERSION_MAJOR)) + QStringLiteral("/speechtotext/")); 0040 for (const QString &libPath : libPaths) { 0041 const QDir dir(libPath + pathSuffix); 0042 if (!dir.exists()) { 0043 continue; 0044 } 0045 for (const QString &fileName : dir.entryList(QDir::Files)) { 0046 loadPlugin(dir.absoluteFilePath(fileName)); 0047 } 0048 } 0049 if (d->loadedPlugins.isEmpty()) { 0050 qCWarning(TEXTSPEECHTOTEXT_LOG) << "No speechtotext plugins available!"; 0051 Q_EMIT noPluginsFound(); 0052 } 0053 } 0054 0055 void SpeechToTextEngineLoader::loadPlugin(const QString &pluginPath) 0056 { 0057 QPluginLoader plugin(pluginPath); 0058 const QString pluginIID = plugin.metaData()[QLatin1String("IID")].toString(); 0059 if (!pluginIID.isEmpty()) { 0060 if (d->loadedPlugins.contains(pluginIID)) { 0061 qCDebug(TEXTSPEECHTOTEXT_LOG) << "Skipping already loaded" << pluginPath; 0062 return; 0063 } 0064 d->loadedPlugins.insert(pluginIID); 0065 } 0066 0067 if (!plugin.load()) { // We do this separately for better error handling 0068 qCDebug(TEXTSPEECHTOTEXT_LOG) << "Unable to load plugin" << pluginPath << "Error:" << plugin.errorString(); 0069 d->loadedPlugins.remove(pluginIID); 0070 return; 0071 } 0072 SpeechToTextClient *client = qobject_cast<SpeechToTextClient *>(plugin.instance()); 0073 if (!client) { 0074 qCWarning(TEXTSPEECHTOTEXT_LOG) << "Invalid plugin loaded" << pluginPath; 0075 plugin.unload(); // don't leave it in memory 0076 return; 0077 } 0078 d->speechToTextClients.insert(client->name(), client); 0079 } 0080 0081 SpeechToTextClient *SpeechToTextEngineLoader::createSpeechToTextClient(const QString &clientName) 0082 { 0083 auto clientsItr = d->speechToTextClients.constFind(clientName); 0084 if (clientsItr == d->speechToTextClients.constEnd()) { 0085 qCWarning(TEXTSPEECHTOTEXT_LOG) << "Client name not found: " << clientName; 0086 Q_EMIT loadingSpeechToTextFailed(); 0087 return nullptr; 0088 } 0089 return (*clientsItr); 0090 } 0091 0092 bool SpeechToTextEngineLoader::hasConfigurationDialog(const QString &clientName) const 0093 { 0094 auto clientsItr = d->speechToTextClients.constFind(clientName); 0095 if (clientsItr == d->speechToTextClients.constEnd()) { 0096 qCWarning(TEXTSPEECHTOTEXT_LOG) << "Client name not found: " << clientName; 0097 return false; 0098 } 0099 return (*clientsItr)->hasConfigurationDialog(); 0100 } 0101 0102 bool SpeechToTextEngineLoader::showConfigureDialog(const QString &clientName, QWidget *parentWidget) 0103 { 0104 auto clientsItr = d->speechToTextClients.constFind(clientName); 0105 if (clientsItr == d->speechToTextClients.constEnd()) { 0106 qCWarning(TEXTSPEECHTOTEXT_LOG) << "Client name not found: " << clientName; 0107 return false; 0108 } 0109 return (*clientsItr)->showConfigureDialog(parentWidget); 0110 } 0111 0112 QMap<QString, QString> SpeechToTextEngineLoader::speechToTextEngineInfos() const 0113 { 0114 QMap<QString, QString> map; 0115 QHashIterator<QString, SpeechToTextClient *> i(d->speechToTextClients); 0116 while (i.hasNext()) { 0117 i.next(); 0118 map.insert(i.key(), i.value()->translatedName()); 0119 } 0120 return map; 0121 } 0122 0123 QString SpeechToTextEngineLoader::fallbackFirstEngine() const 0124 { 0125 if (!d->speechToTextClients.isEmpty()) { 0126 return *d->speechToTextClients.keyBegin(); 0127 } 0128 qCWarning(TEXTSPEECHTOTEXT_LOG) << "No plugin found ! "; 0129 return QString(); 0130 } 0131 0132 bool SpeechToTextEngineLoader::hasEngine() const 0133 { 0134 return !d->speechToTextClients.isEmpty(); 0135 } 0136 0137 #include "moc_speechtotextengineloader.cpp"