From cbb875f3f8fe31fe3f83d06eef1e15ebf69e871d Mon Sep 17 00:00:00 2001 From: PTyTb Date: Sun, 8 Feb 2026 17:29:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D1=87=D0=B8=D0=BD=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=B9=D1=80=D0=BE=D0=BA=D0=BE=D0=BD=D1=81=D1=82?= =?UTF-8?q?=D1=80=D1=83=D0=BA=D1=82=D0=BE=D1=80,=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=B7=D0=BD=D0=B0=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B8=D0=B7=20?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TTW_Bot.pro | 2 + commandprocessor.cpp | 137 ++++++++++++++++++++- commandprocessor.h | 3 + filemanager.cpp | 18 --- filemanager.h | 3 +- neuralnetworkmanager.cpp | 39 ++++-- neuralnetworkmanager.h | 7 +- neuraltemplatemanager.cpp | 55 +++++++++ neuraltemplatemanager.h | 33 +++++ object_script.TTW_Bot.Debug | 2 + object_script.TTW_Bot.Release | 2 + ugeneral.cpp | 128 ++++++++++++++++--- ugeneral.h | 9 +- ugeneral.ui | 225 +++++++++++++--------------------- websocketclient.cpp | 91 +++++++++----- 15 files changed, 531 insertions(+), 223 deletions(-) create mode 100644 neuraltemplatemanager.cpp create mode 100644 neuraltemplatemanager.h diff --git a/TTW_Bot.pro b/TTW_Bot.pro index ee65a50..ed4cfd8 100644 --- a/TTW_Bot.pro +++ b/TTW_Bot.pro @@ -34,6 +34,7 @@ SOURCES += \ main.cpp \ mediafilemanager.cpp \ neuralnetworkmanager.cpp \ + neuraltemplatemanager.cpp \ randommanager.cpp \ randomresponses.cpp \ soundmanager.cpp \ @@ -65,6 +66,7 @@ HEADERS += \ mediafilemanager.h \ miniaudio.h \ neuralnetworkmanager.h \ + neuraltemplatemanager.h \ randommanager.h \ randomresponses.h \ soundmanager.h \ diff --git a/commandprocessor.cpp b/commandprocessor.cpp index d106239..040a9dc 100644 --- a/commandprocessor.cpp +++ b/commandprocessor.cpp @@ -1,4 +1,5 @@ #include "commandprocessor.h" +#include "neuraltemplatemanager.h" #include #include #include @@ -6,6 +7,12 @@ #include #include +struct Replacement { + int start; + int length; + QString text; +}; + CommandProcessor::CommandProcessor(QObject *parent) : QObject(parent) { @@ -48,14 +55,13 @@ QString CommandProcessor::generateResponse(QString userIndex, const QString &com Command cmd = findCommand(command); if (cmd.command.isEmpty()) { qDebug() << "Команда не найдена:" << command; - return QString("Команда '%1' не найдена").arg(command); + return ""; } qDebug() << "Найдена команда:" << cmd.command << "ответ:" << cmd.response; QString fullCommand = command + (message.isEmpty() ? "" : " " + message); QString result = processCommand(username, fullCommand, cmd.response); - qDebug() << "Итоговый результат:" << result; return result; } @@ -111,6 +117,9 @@ QString CommandProcessor::processCommand(const QString &sender, const QString &f break; } } + + response = parseNeuralTemplates(response, sender, parameters); + response = parseRandomNumbers(response); // Затем обрабатываем случайные числа ВНУТРИ них response = parseSounds(response); response = parseTextFiles(response); @@ -372,7 +381,7 @@ QString CommandProcessor::parseAI(const QString &response, const QString &questi eventLoop.quit(); }); - m_context.neuralManager->sendMessage(question, NeuralNetworkManager::DeepSeek); + m_context.neuralManager->sendMessage(question); QTimer::singleShot(60000, &eventLoop, &QEventLoop::quit); eventLoop.exec(); @@ -474,3 +483,125 @@ QString CommandProcessor::getPeriodEnding(int n, int r) return endings[r][2]; } } + +QString CommandProcessor::parseNeuralTemplates(const QString &response, const QString &sender, const QString ¶meters) +{ + QString result = response; + qDebug() << "parseNeuralTemplates: входная строка:" << response; + + // Исправленное регулярное выражение + QRegularExpression regex("<\\|([^<]+)<\\|"); + QRegularExpressionMatchIterator matches = regex.globalMatch(response); + + QList replacements; + int matchCount = 0; + + while (matches.hasNext()) { + matchCount++; + QRegularExpressionMatch match = matches.next(); + QString templateName = match.captured(1).trimmed(); + qDebug() << "Найден шаблон:" << templateName << "на позиции" << match.capturedStart(); + + if (m_context.neuralTemplateManager) { + QString templateText = m_context.neuralTemplateManager->getTemplateText(templateName); + qDebug() << "Текст шаблона:" << templateText; + + if (!templateText.isEmpty()) { + // Заменяем плейсхолдеры в шаблоне + QString processedTemplate = templateText; + processedTemplate.replace("[TO]", parameters); + processedTemplate.replace("[USERNAME]", sender); + + qDebug() << "Шаблон после замены плейсхолдеров:" << processedTemplate; + + // Получаем ответ от нейросети + QString aiResponse; + if (m_context.neuralManager) { + // Создаем event loop для асинхронного ожидания + QEventLoop eventLoop; + bool responseReceived = false; + bool errorOccurred = false; + QString errorMessage; + + // Подключаем сигналы от нейросети + auto conn1 = connect(m_context.neuralManager, &NeuralNetworkManager::responseReceived, + [&](const QString &responseText) { + aiResponse = responseText; + responseReceived = true; + eventLoop.quit(); + }); + + auto conn2 = connect(m_context.neuralManager, &NeuralNetworkManager::errorOccurred, + [&](const QString &error) { + errorMessage = error; + errorOccurred = true; + eventLoop.quit(); + }); + + // Отправляем запрос к нейросети + qDebug() << "Отправляем запрос к нейросети:" << processedTemplate; + m_context.neuralManager->sendMessage(processedTemplate); + + // Таймаут 30 секунд + QTimer::singleShot(30000, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + disconnect(conn1); + disconnect(conn2); + + if (errorOccurred) { + aiResponse = QString("Ошибка нейросети: %1").arg(errorMessage); + qDebug() << "Ошибка нейросети:" << errorMessage; + } else if (!responseReceived) { + aiResponse = "Таймаут при ожидании ответа от нейросети"; + qDebug() << "Таймаут нейросети"; + } else { + qDebug() << "Получен ответ от нейросети:" << aiResponse; + } + } else { + aiResponse = "Нейросеть недоступна"; + qDebug() << "NeuralManager не доступен"; + } + + // Заменяем шаблон на ответ от нейросети + Replacement repl; + repl.start = match.capturedStart(); + repl.length = match.capturedLength(); + repl.text = aiResponse; + replacements.append(repl); + } else { + qDebug() << "Шаблон не найден или пустой:" << templateName; + // Если шаблон не найден, оставляем как есть или заменяем на заглушку + Replacement repl; + repl.start = match.capturedStart(); + repl.length = match.capturedLength(); + repl.text = "[Шаблон не найден]"; + replacements.append(repl); + } + } else { + qDebug() << "NeuralTemplateManager не доступен"; + // Если менеджер не доступен, заменяем на заглушку + Replacement repl; + repl.start = match.capturedStart(); + repl.length = match.capturedLength(); + repl.text = "[Нейросеть недоступна]"; + replacements.append(repl); + } + } + + qDebug() << "Всего найдено шаблонов:" << matchCount; + + // Выполняем замены с конца к началу + std::sort(replacements.begin(), replacements.end(), + [](const Replacement &a, const Replacement &b) { + return a.start > b.start; + }); + + for (const auto &replacement : replacements) { + result.replace(replacement.start, replacement.length, replacement.text); + } + + qDebug() << "parseNeuralTemplates: результат:" << result; + return result; +} + diff --git a/commandprocessor.h b/commandprocessor.h index 9a9e3a9..ab844a6 100644 --- a/commandprocessor.h +++ b/commandprocessor.h @@ -13,6 +13,7 @@ #include "neuralnetworkmanager.h" #include "randommanager.h" #include "randomresponses.h" +#include "neuraltemplatemanager.h" class CommandProcessor : public QObject { @@ -32,6 +33,7 @@ public: RandomManager* randomManager = nullptr; RandomResponses* randomResponses = nullptr; MediaFileManager* mediaFileManager = nullptr; + NeuralTemplateManager *neuralTemplateManager = nullptr; QString channel; int notifyVolume = 50; }; @@ -61,6 +63,7 @@ private: QString parseBan(const QString &response, const QString &sender); QString parseAPI(const QString &response, const QString &sender); QString parseAI(const QString &response, const QString &question); + QString parseNeuralTemplates(const QString &response, const QString &sender, const QString ¶meters); QString extractParameters(const QString &fullCommand); QString getUsernameByIndex(QString userIndex) const; diff --git a/filemanager.cpp b/filemanager.cpp index 4b8ee41..4951c8d 100644 --- a/filemanager.cpp +++ b/filemanager.cpp @@ -162,22 +162,4 @@ QString FileManager::getWebPath(FileType type, const QString& fileName) const return QString("/%1/%2").arg(folder).arg(fileName); } -void FileManager::copyDefaultFiles() -{ - // Копируем системные стили в пользовательскую папку при первом запуске - QString systemStylesPath = getPath(SystemStyles); - QDir systemStylesDir(systemStylesPath); - if (systemStylesDir.exists()) { - QStringList qssFiles = systemStylesDir.entryList(QStringList() << "*.qss" << "*.QSS", QDir::Files); - - for (const QString& file : qssFiles) { - QString sourcePath = systemStylesDir.absoluteFilePath(file); - QString destPath = getFullPath(Styles, file); - - if (!QFile::exists(destPath)) { - QFile::copy(sourcePath, destPath); - } - } - } -} diff --git a/filemanager.h b/filemanager.h index e2a4044..81805ea 100644 --- a/filemanager.h +++ b/filemanager.h @@ -59,8 +59,7 @@ public: // Получение относительного пути для веб-сервера QString getWebPath(FileType type, const QString& fileName) const; - // Копирование файлов из системных в пользовательские (при первом запуске) - void copyDefaultFiles(); + private: FileManager(); diff --git a/neuralnetworkmanager.cpp b/neuralnetworkmanager.cpp index 464bf3e..5af4bb9 100644 --- a/neuralnetworkmanager.cpp +++ b/neuralnetworkmanager.cpp @@ -124,6 +124,18 @@ void NeuralNetworkManager::setupDefaultConfigs() networkConfigs[Ollama] = ollamaConfig; } +void NeuralNetworkManager::setCurrentNetworkType(NetworkType type) +{ + QMutexLocker locker(&mutex); + m_currentNetworkType = type; +} + +void NeuralNetworkManager::sendMessage(const QString &message) +{ + // Используем текущий тип сети + sendMessage(message, m_currentNetworkType); +} + void NeuralNetworkManager::sendMessage(const QString &message, NetworkType networkType) { QMutexLocker locker(&mutex); @@ -138,8 +150,6 @@ void NeuralNetworkManager::sendMessage(const QString &message, NetworkType netwo qint64 currentTime = QDateTime::currentSecsSinceEpoch(); if (!isGigaChatTokenValid()) { - - // Добавляем сообщение в очередь PendingMessage pendingMsg; pendingMsg.message = message; @@ -154,7 +164,6 @@ void NeuralNetworkManager::sendMessage(const QString &message, NetworkType netwo return; } } - // Если токен валиден, отправляем сообщение сразу sendMessageInternal(message, networkType); } @@ -424,17 +433,15 @@ void NeuralNetworkManager::handleGigaChatTokenReply(QNetworkReply *reply) if (reply->error() != QNetworkReply::NoError) { QString errorMsg = QString("Ошибка получения токена GigaChat: %1").arg(reply->errorString()); - // Очищаем очередь сообщений если не удалось получить токен - pendingMessages.clear(); + gigaChatAuth.tokenExpiry = 0; emit errorOccurred(errorMsg); - reply->deleteLater(); return; } QJsonDocument doc = QJsonDocument::fromJson(data); if (doc.isNull()) { - pendingMessages.clear(); + emit errorOccurred("Неверный формат ответа от GigaChat"); reply->deleteLater(); @@ -444,6 +451,7 @@ void NeuralNetworkManager::handleGigaChatTokenReply(QNetworkReply *reply) QJsonObject json = doc.object(); if (json.contains("access_token")) { + m_tokenRetryCount = 0; gigaChatAuth.accessToken = json["access_token"].toString(); int expiresIn = json.contains("expires_in") @@ -463,10 +471,10 @@ void NeuralNetworkManager::handleGigaChatTokenReply(QNetworkReply *reply) QString errorMsg = json["error"].toString(); // Очищаем очередь сообщений - pendingMessages.clear(); + emit errorOccurred("Ошибка GigaChat: " + errorMsg); } else { - pendingMessages.clear(); + emit errorOccurred("Неизвестный формат ответа от GigaChat"); } @@ -513,9 +521,20 @@ void NeuralNetworkManager::requestGigaChatToken() return; } + // Проверяем количество попыток + if (m_tokenRetryCount >= MAX_TOKEN_RETRIES) { + qDebug() << "Превышено максимальное количество попыток получения токена"; + m_tokenRetryCount = 0; + pendingMessages.clear(); // Только после превышения лимита очищаем очередь + emit errorOccurred("Не удалось получить токен GigaChat после нескольких попыток"); + return; + } + + m_tokenRetryCount++; + isProcessingGigaChatToken = true; + if (gigaChatAuth.clientId.isEmpty() || gigaChatAuth.authorizationCode.isEmpty()) { emit errorOccurred("Не установлены учетные данные GigaChat"); - // Очищаем очередь сообщений pendingMessages.clear(); return; diff --git a/neuralnetworkmanager.h b/neuralnetworkmanager.h index a1f42ce..712a459 100644 --- a/neuralnetworkmanager.h +++ b/neuralnetworkmanager.h @@ -27,6 +27,8 @@ public: ~NeuralNetworkManager(); // Основные методы + void setCurrentNetworkType(NetworkType type); + void sendMessage(const QString &message); void sendMessage(const QString &message, NetworkType networkType); void setPrefix(const QString &prefix); void setApiKey(NetworkType networkType, const QString &apiKey); @@ -63,7 +65,7 @@ private: // SSL настройки void setupSSL(); void setupSSLForGigaChat(); - + NetworkType m_currentNetworkType = DeepSeek; // Основные переменные QNetworkAccessManager *networkManager; QMap networkConfigs; @@ -86,6 +88,9 @@ private: bool isGigaChatTokenValid() const; bool shouldRefreshGigaChatToken() const; + int m_tokenRetryCount = 0; + const int MAX_TOKEN_RETRIES = 3; + // Очередь сообщений для GigaChat struct PendingMessage { QString message; diff --git a/neuraltemplatemanager.cpp b/neuraltemplatemanager.cpp new file mode 100644 index 0000000..0a137e2 --- /dev/null +++ b/neuraltemplatemanager.cpp @@ -0,0 +1,55 @@ +// neuratemplatemanager.cpp +#include "neuraltemplatemanager.h" +#include "qdebug.h" +#include + +NeuralTemplateManager::NeuralTemplateManager(QObject *parent) + : QObject(parent) +{ +} + +void NeuralTemplateManager::addTemplate(const QString &name, const QString &templateText) +{ + // Проверяем, нет ли уже шаблона с таким именем + for (int i = 0; i < m_templates.size(); ++i) { + if (m_templates[i].name.compare(name, Qt::CaseInsensitive) == 0) { + m_templates[i].templateText = templateText; + return; + } + } + m_templates.append({name, templateText}); +} + +QString NeuralTemplateManager::getTemplateText(const QString &name) const +{ + for (const Template &t : m_templates) { + if (t.name.compare(name, Qt::CaseInsensitive) == 0) { + return t.templateText; + } + } + return QString(); +} + +void NeuralTemplateManager::clear() +{ + m_templates.clear(); +} + +void NeuralTemplateManager::loadFromTableWidget(QTableWidget *table) +{ + clear(); + if (!table) return; + qDebug()<< "Table Found"; + for (int row = 0; row < table->rowCount(); ++row) { + QTableWidgetItem *nameItem = table->item(row, 0); + QTableWidgetItem *templateItem = table->item(row, 1); + if (nameItem && templateItem) { + QString name = nameItem->text().trimmed(); + QString templateText = templateItem->text().trimmed(); + qDebug()<< "Template add " << name; + if (!name.isEmpty() && !templateText.isEmpty()) { + addTemplate(name, templateText); + } + } + } +} diff --git a/neuraltemplatemanager.h b/neuraltemplatemanager.h new file mode 100644 index 0000000..cafd222 --- /dev/null +++ b/neuraltemplatemanager.h @@ -0,0 +1,33 @@ +// neuratemplatemanager.h +#ifndef NEURALTEMPLATEMANAGER_H +#define NEURALTEMPLATEMANAGER_H + +#include "qtablewidget.h" +#include +#include +#include + +class NeuralTemplateManager : public QObject +{ + Q_OBJECT + +public: + struct Template { + QString name; + QString templateText; + }; + + explicit NeuralTemplateManager(QObject *parent = nullptr); + + void addTemplate(const QString &name, const QString &templateText); + QString getTemplateText(const QString &name) const; + void clear(); + void loadFromTableWidget(QTableWidget *table); + + const QVector