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"