починил нейроконструктор, исправил распознавание сообщений из чата
This commit is contained in:
@@ -34,6 +34,7 @@ SOURCES += \
|
|||||||
main.cpp \
|
main.cpp \
|
||||||
mediafilemanager.cpp \
|
mediafilemanager.cpp \
|
||||||
neuralnetworkmanager.cpp \
|
neuralnetworkmanager.cpp \
|
||||||
|
neuraltemplatemanager.cpp \
|
||||||
randommanager.cpp \
|
randommanager.cpp \
|
||||||
randomresponses.cpp \
|
randomresponses.cpp \
|
||||||
soundmanager.cpp \
|
soundmanager.cpp \
|
||||||
@@ -65,6 +66,7 @@ HEADERS += \
|
|||||||
mediafilemanager.h \
|
mediafilemanager.h \
|
||||||
miniaudio.h \
|
miniaudio.h \
|
||||||
neuralnetworkmanager.h \
|
neuralnetworkmanager.h \
|
||||||
|
neuraltemplatemanager.h \
|
||||||
randommanager.h \
|
randommanager.h \
|
||||||
randomresponses.h \
|
randomresponses.h \
|
||||||
soundmanager.h \
|
soundmanager.h \
|
||||||
|
|||||||
+134
-3
@@ -1,4 +1,5 @@
|
|||||||
#include "commandprocessor.h"
|
#include "commandprocessor.h"
|
||||||
|
#include "neuraltemplatemanager.h"
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
@@ -6,6 +7,12 @@
|
|||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
struct Replacement {
|
||||||
|
int start;
|
||||||
|
int length;
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
CommandProcessor::CommandProcessor(QObject *parent)
|
CommandProcessor::CommandProcessor(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
@@ -48,14 +55,13 @@ QString CommandProcessor::generateResponse(QString userIndex, const QString &com
|
|||||||
Command cmd = findCommand(command);
|
Command cmd = findCommand(command);
|
||||||
if (cmd.command.isEmpty()) {
|
if (cmd.command.isEmpty()) {
|
||||||
qDebug() << "Команда не найдена:" << command;
|
qDebug() << "Команда не найдена:" << command;
|
||||||
return QString("Команда '%1' не найдена").arg(command);
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Найдена команда:" << cmd.command << "ответ:" << cmd.response;
|
qDebug() << "Найдена команда:" << cmd.command << "ответ:" << cmd.response;
|
||||||
|
|
||||||
QString fullCommand = command + (message.isEmpty() ? "" : " " + message);
|
QString fullCommand = command + (message.isEmpty() ? "" : " " + message);
|
||||||
QString result = processCommand(username, fullCommand, cmd.response);
|
QString result = processCommand(username, fullCommand, cmd.response);
|
||||||
|
|
||||||
qDebug() << "Итоговый результат:" << result;
|
qDebug() << "Итоговый результат:" << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -111,6 +117,9 @@ QString CommandProcessor::processCommand(const QString &sender, const QString &f
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response = parseNeuralTemplates(response, sender, parameters);
|
||||||
|
|
||||||
response = parseRandomNumbers(response); // Затем обрабатываем случайные числа ВНУТРИ них
|
response = parseRandomNumbers(response); // Затем обрабатываем случайные числа ВНУТРИ них
|
||||||
response = parseSounds(response);
|
response = parseSounds(response);
|
||||||
response = parseTextFiles(response);
|
response = parseTextFiles(response);
|
||||||
@@ -372,7 +381,7 @@ QString CommandProcessor::parseAI(const QString &response, const QString &questi
|
|||||||
eventLoop.quit();
|
eventLoop.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_context.neuralManager->sendMessage(question, NeuralNetworkManager::DeepSeek);
|
m_context.neuralManager->sendMessage(question);
|
||||||
|
|
||||||
QTimer::singleShot(60000, &eventLoop, &QEventLoop::quit);
|
QTimer::singleShot(60000, &eventLoop, &QEventLoop::quit);
|
||||||
eventLoop.exec();
|
eventLoop.exec();
|
||||||
@@ -474,3 +483,125 @@ QString CommandProcessor::getPeriodEnding(int n, int r)
|
|||||||
return endings[r][2];
|
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<Replacement> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "neuralnetworkmanager.h"
|
#include "neuralnetworkmanager.h"
|
||||||
#include "randommanager.h"
|
#include "randommanager.h"
|
||||||
#include "randomresponses.h"
|
#include "randomresponses.h"
|
||||||
|
#include "neuraltemplatemanager.h"
|
||||||
|
|
||||||
class CommandProcessor : public QObject
|
class CommandProcessor : public QObject
|
||||||
{
|
{
|
||||||
@@ -32,6 +33,7 @@ public:
|
|||||||
RandomManager* randomManager = nullptr;
|
RandomManager* randomManager = nullptr;
|
||||||
RandomResponses* randomResponses = nullptr;
|
RandomResponses* randomResponses = nullptr;
|
||||||
MediaFileManager* mediaFileManager = nullptr;
|
MediaFileManager* mediaFileManager = nullptr;
|
||||||
|
NeuralTemplateManager *neuralTemplateManager = nullptr;
|
||||||
QString channel;
|
QString channel;
|
||||||
int notifyVolume = 50;
|
int notifyVolume = 50;
|
||||||
};
|
};
|
||||||
@@ -61,6 +63,7 @@ private:
|
|||||||
QString parseBan(const QString &response, const QString &sender);
|
QString parseBan(const QString &response, const QString &sender);
|
||||||
QString parseAPI(const QString &response, const QString &sender);
|
QString parseAPI(const QString &response, const QString &sender);
|
||||||
QString parseAI(const QString &response, const QString &question);
|
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 extractParameters(const QString &fullCommand);
|
||||||
QString getUsernameByIndex(QString userIndex) const;
|
QString getUsernameByIndex(QString userIndex) const;
|
||||||
|
|||||||
@@ -162,22 +162,4 @@ QString FileManager::getWebPath(FileType type, const QString& fileName) const
|
|||||||
return QString("/%1/%2").arg(folder).arg(fileName);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-2
@@ -59,8 +59,7 @@ public:
|
|||||||
// Получение относительного пути для веб-сервера
|
// Получение относительного пути для веб-сервера
|
||||||
QString getWebPath(FileType type, const QString& fileName) const;
|
QString getWebPath(FileType type, const QString& fileName) const;
|
||||||
|
|
||||||
// Копирование файлов из системных в пользовательские (при первом запуске)
|
|
||||||
void copyDefaultFiles();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileManager();
|
FileManager();
|
||||||
|
|||||||
+29
-10
@@ -124,6 +124,18 @@ void NeuralNetworkManager::setupDefaultConfigs()
|
|||||||
networkConfigs[Ollama] = ollamaConfig;
|
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)
|
void NeuralNetworkManager::sendMessage(const QString &message, NetworkType networkType)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&mutex);
|
QMutexLocker locker(&mutex);
|
||||||
@@ -138,8 +150,6 @@ void NeuralNetworkManager::sendMessage(const QString &message, NetworkType netwo
|
|||||||
qint64 currentTime = QDateTime::currentSecsSinceEpoch();
|
qint64 currentTime = QDateTime::currentSecsSinceEpoch();
|
||||||
|
|
||||||
if (!isGigaChatTokenValid()) {
|
if (!isGigaChatTokenValid()) {
|
||||||
|
|
||||||
|
|
||||||
// Добавляем сообщение в очередь
|
// Добавляем сообщение в очередь
|
||||||
PendingMessage pendingMsg;
|
PendingMessage pendingMsg;
|
||||||
pendingMsg.message = message;
|
pendingMsg.message = message;
|
||||||
@@ -154,7 +164,6 @@ void NeuralNetworkManager::sendMessage(const QString &message, NetworkType netwo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если токен валиден, отправляем сообщение сразу
|
// Если токен валиден, отправляем сообщение сразу
|
||||||
sendMessageInternal(message, networkType);
|
sendMessageInternal(message, networkType);
|
||||||
}
|
}
|
||||||
@@ -424,17 +433,15 @@ void NeuralNetworkManager::handleGigaChatTokenReply(QNetworkReply *reply)
|
|||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
QString errorMsg = QString("Ошибка получения токена GigaChat: %1").arg(reply->errorString());
|
QString errorMsg = QString("Ошибка получения токена GigaChat: %1").arg(reply->errorString());
|
||||||
|
|
||||||
// Очищаем очередь сообщений если не удалось получить токен
|
gigaChatAuth.tokenExpiry = 0;
|
||||||
pendingMessages.clear();
|
|
||||||
emit errorOccurred(errorMsg);
|
emit errorOccurred(errorMsg);
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||||
if (doc.isNull()) {
|
if (doc.isNull()) {
|
||||||
pendingMessages.clear();
|
|
||||||
emit errorOccurred("Неверный формат ответа от GigaChat");
|
emit errorOccurred("Неверный формат ответа от GigaChat");
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
@@ -444,6 +451,7 @@ void NeuralNetworkManager::handleGigaChatTokenReply(QNetworkReply *reply)
|
|||||||
QJsonObject json = doc.object();
|
QJsonObject json = doc.object();
|
||||||
|
|
||||||
if (json.contains("access_token")) {
|
if (json.contains("access_token")) {
|
||||||
|
m_tokenRetryCount = 0;
|
||||||
gigaChatAuth.accessToken = json["access_token"].toString();
|
gigaChatAuth.accessToken = json["access_token"].toString();
|
||||||
|
|
||||||
int expiresIn = json.contains("expires_in")
|
int expiresIn = json.contains("expires_in")
|
||||||
@@ -463,10 +471,10 @@ void NeuralNetworkManager::handleGigaChatTokenReply(QNetworkReply *reply)
|
|||||||
QString errorMsg = json["error"].toString();
|
QString errorMsg = json["error"].toString();
|
||||||
|
|
||||||
// Очищаем очередь сообщений
|
// Очищаем очередь сообщений
|
||||||
pendingMessages.clear();
|
|
||||||
emit errorOccurred("Ошибка GigaChat: " + errorMsg);
|
emit errorOccurred("Ошибка GigaChat: " + errorMsg);
|
||||||
} else {
|
} else {
|
||||||
pendingMessages.clear();
|
|
||||||
emit errorOccurred("Неизвестный формат ответа от GigaChat");
|
emit errorOccurred("Неизвестный формат ответа от GigaChat");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,9 +521,20 @@ void NeuralNetworkManager::requestGigaChatToken()
|
|||||||
return;
|
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()) {
|
if (gigaChatAuth.clientId.isEmpty() || gigaChatAuth.authorizationCode.isEmpty()) {
|
||||||
emit errorOccurred("Не установлены учетные данные GigaChat");
|
emit errorOccurred("Не установлены учетные данные GigaChat");
|
||||||
|
|
||||||
// Очищаем очередь сообщений
|
// Очищаем очередь сообщений
|
||||||
pendingMessages.clear();
|
pendingMessages.clear();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ public:
|
|||||||
~NeuralNetworkManager();
|
~NeuralNetworkManager();
|
||||||
|
|
||||||
// Основные методы
|
// Основные методы
|
||||||
|
void setCurrentNetworkType(NetworkType type);
|
||||||
|
void sendMessage(const QString &message);
|
||||||
void sendMessage(const QString &message, NetworkType networkType);
|
void sendMessage(const QString &message, NetworkType networkType);
|
||||||
void setPrefix(const QString &prefix);
|
void setPrefix(const QString &prefix);
|
||||||
void setApiKey(NetworkType networkType, const QString &apiKey);
|
void setApiKey(NetworkType networkType, const QString &apiKey);
|
||||||
@@ -63,7 +65,7 @@ private:
|
|||||||
// SSL настройки
|
// SSL настройки
|
||||||
void setupSSL();
|
void setupSSL();
|
||||||
void setupSSLForGigaChat();
|
void setupSSLForGigaChat();
|
||||||
|
NetworkType m_currentNetworkType = DeepSeek;
|
||||||
// Основные переменные
|
// Основные переменные
|
||||||
QNetworkAccessManager *networkManager;
|
QNetworkAccessManager *networkManager;
|
||||||
QMap<NetworkType, NetworkConfig> networkConfigs;
|
QMap<NetworkType, NetworkConfig> networkConfigs;
|
||||||
@@ -86,6 +88,9 @@ private:
|
|||||||
bool isGigaChatTokenValid() const;
|
bool isGigaChatTokenValid() const;
|
||||||
bool shouldRefreshGigaChatToken() const;
|
bool shouldRefreshGigaChatToken() const;
|
||||||
|
|
||||||
|
int m_tokenRetryCount = 0;
|
||||||
|
const int MAX_TOKEN_RETRIES = 3;
|
||||||
|
|
||||||
// Очередь сообщений для GigaChat
|
// Очередь сообщений для GigaChat
|
||||||
struct PendingMessage {
|
struct PendingMessage {
|
||||||
QString message;
|
QString message;
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// neuratemplatemanager.cpp
|
||||||
|
#include "neuraltemplatemanager.h"
|
||||||
|
#include "qdebug.h"
|
||||||
|
#include <QTableWidget>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// neuratemplatemanager.h
|
||||||
|
#ifndef NEURALTEMPLATEMANAGER_H
|
||||||
|
#define NEURALTEMPLATEMANAGER_H
|
||||||
|
|
||||||
|
#include "qtablewidget.h"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
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<Template>& templates() const { return m_templates; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVector<Template> m_templates;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NEURALTEMPLATEMANAGER_H
|
||||||
@@ -11,6 +11,7 @@ debug/logmanager.o
|
|||||||
debug/main.o
|
debug/main.o
|
||||||
debug/mediafilemanager.o
|
debug/mediafilemanager.o
|
||||||
debug/neuralnetworkmanager.o
|
debug/neuralnetworkmanager.o
|
||||||
|
debug/neuraltemplatemanager.o
|
||||||
debug/randommanager.o
|
debug/randommanager.o
|
||||||
debug/randomresponses.o
|
debug/randomresponses.o
|
||||||
debug/soundmanager.o
|
debug/soundmanager.o
|
||||||
@@ -36,6 +37,7 @@ debug/moc_fsettingsws.o
|
|||||||
debug/moc_fsinglegrid.o
|
debug/moc_fsinglegrid.o
|
||||||
debug/moc_logmanager.o
|
debug/moc_logmanager.o
|
||||||
debug/moc_neuralnetworkmanager.o
|
debug/moc_neuralnetworkmanager.o
|
||||||
|
debug/moc_neuraltemplatemanager.o
|
||||||
debug/moc_randommanager.o
|
debug/moc_randommanager.o
|
||||||
debug/moc_randomresponses.o
|
debug/moc_randomresponses.o
|
||||||
debug/moc_soundmanager.o
|
debug/moc_soundmanager.o
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ release/logmanager.o
|
|||||||
release/main.o
|
release/main.o
|
||||||
release/mediafilemanager.o
|
release/mediafilemanager.o
|
||||||
release/neuralnetworkmanager.o
|
release/neuralnetworkmanager.o
|
||||||
|
release/neuraltemplatemanager.o
|
||||||
release/randommanager.o
|
release/randommanager.o
|
||||||
release/randomresponses.o
|
release/randomresponses.o
|
||||||
release/soundmanager.o
|
release/soundmanager.o
|
||||||
@@ -36,6 +37,7 @@ release/moc_fsettingsws.o
|
|||||||
release/moc_fsinglegrid.o
|
release/moc_fsinglegrid.o
|
||||||
release/moc_logmanager.o
|
release/moc_logmanager.o
|
||||||
release/moc_neuralnetworkmanager.o
|
release/moc_neuralnetworkmanager.o
|
||||||
|
release/moc_neuraltemplatemanager.o
|
||||||
release/moc_randommanager.o
|
release/moc_randommanager.o
|
||||||
release/moc_randomresponses.o
|
release/moc_randomresponses.o
|
||||||
release/moc_soundmanager.o
|
release/moc_soundmanager.o
|
||||||
|
|||||||
+109
-19
@@ -36,12 +36,13 @@ uGeneral::uGeneral(QWidget *parent)
|
|||||||
, m_authStreamer(nullptr)
|
, m_authStreamer(nullptr)
|
||||||
, m_authDA(nullptr)
|
, m_authDA(nullptr)
|
||||||
, fLinkForm(nullptr)
|
, fLinkForm(nullptr)
|
||||||
|
, m_randomManager(nullptr)
|
||||||
|
, m_neuralTemplateManager(nullptr)
|
||||||
, m_isTwitchConnected(false)
|
, m_isTwitchConnected(false)
|
||||||
, m_notificationServers()
|
, m_notificationServers()
|
||||||
, m_chatServers()
|
, m_chatServers()
|
||||||
, m_createNotifyDialog(nullptr)
|
, m_createNotifyDialog(nullptr)
|
||||||
, m_createChatDialog(nullptr)
|
, m_createChatDialog(nullptr)
|
||||||
, m_randomManager(nullptr)
|
|
||||||
{
|
{
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
|
// ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
|
||||||
@@ -86,7 +87,7 @@ uGeneral::uGeneral(QWidget *parent)
|
|||||||
|
|
||||||
// Инициализируем структуру папок
|
// Инициализируем структуру папок
|
||||||
FileManager::instance().initializeFolderStructure();
|
FileManager::instance().initializeFolderStructure();
|
||||||
FileManager::instance().copyDefaultFiles();
|
|
||||||
// Получаем пути через FileManager
|
// Получаем пути через FileManager
|
||||||
QString sysPath = FileManager::instance().systemPath();
|
QString sysPath = FileManager::instance().systemPath();
|
||||||
|
|
||||||
@@ -181,10 +182,7 @@ uGeneral::uGeneral(QWidget *parent)
|
|||||||
// Добавьте эту строку в конец метода:
|
// Добавьте эту строку в конец метода:
|
||||||
initializeNotificationSounds();
|
initializeNotificationSounds();
|
||||||
|
|
||||||
if (db) {
|
|
||||||
m_randomManager = new RandomManager(this);
|
|
||||||
m_randomManager->initialize(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,6 +392,8 @@ void uGeneral::setupTables()
|
|||||||
this, &uGeneral::onFilesGridDoubleClicked);
|
this, &uGeneral::onFilesGridDoubleClicked);
|
||||||
connect(ui->widget_3->tableWidget(), &QTableWidget::cellDoubleClicked,
|
connect(ui->widget_3->tableWidget(), &QTableWidget::cellDoubleClicked,
|
||||||
this, &uGeneral::onNeiroGridDoubleClicked);
|
this, &uGeneral::onNeiroGridDoubleClicked);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -416,12 +416,40 @@ void uGeneral::initializeManagers()
|
|||||||
|
|
||||||
// Менеджер случайных ответов (групп)
|
// Менеджер случайных ответов (групп)
|
||||||
m_randomResponses = new RandomResponses(this);
|
m_randomResponses = new RandomResponses(this);
|
||||||
|
m_neuralTemplateManager = new NeuralTemplateManager(this);
|
||||||
|
QTableWidget* table = ui->widget_3->tableWidget();
|
||||||
|
m_neuralTemplateManager->loadFromTableWidget(table);
|
||||||
// Менеджер нейросети (если есть)
|
// Менеджер нейросети (если есть)
|
||||||
nnManager = new NeuralNetworkManager(this);
|
nnManager = new NeuralNetworkManager(this);
|
||||||
// Настройка нейросети (пример)
|
// Настройка нейросети (пример)
|
||||||
// nnManager->setApiKey(NeuralNetworkManager::DeepSeek, "ваш_api_ключ");
|
nnManager->setPrefix(ui->edtGPTPrefix->text());
|
||||||
// nnManager->setModel(NeuralNetworkManager::DeepSeek, "deepseek-chat");
|
if (ui->rbGC->isChecked()) {
|
||||||
|
// GigaChat
|
||||||
|
nnManager->setCurrentNetworkType(NeuralNetworkManager::GigaChat);
|
||||||
|
nnManager->setGigaChatCredentials(ui->edtAIP1->text(), ui->edtAIP2->text());
|
||||||
|
qDebug() << "GigaChat";
|
||||||
|
}
|
||||||
|
else if (ui->rbDS->isChecked()) {
|
||||||
|
// DeepSeek
|
||||||
|
nnManager->setCurrentNetworkType(NeuralNetworkManager::DeepSeek);
|
||||||
|
nnManager->setApiKey(NeuralNetworkManager::DeepSeek, ui->edtAIP1->text());
|
||||||
|
|
||||||
|
qDebug() << "DeepSeek";
|
||||||
|
}
|
||||||
|
else if (ui->rbCG->isChecked()) {
|
||||||
|
// ChatGPT
|
||||||
|
nnManager->setCurrentNetworkType(NeuralNetworkManager::ChatGPT);
|
||||||
|
nnManager->setApiKey(NeuralNetworkManager::ChatGPT, ui->edtAIP1->text());
|
||||||
|
qDebug() << "ChatGPT";
|
||||||
|
}
|
||||||
|
else if (ui->RBCustom->isChecked()) {
|
||||||
|
// Ollama
|
||||||
|
nnManager->setCurrentNetworkType(NeuralNetworkManager::Ollama);
|
||||||
|
nnManager->setApiKey(NeuralNetworkManager::Ollama, ui->edtAIP1->text());
|
||||||
|
nnManager->setOllamaUrl(ui->edtAIP2->text());
|
||||||
|
qDebug() << "Ollama";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
m_SoundFiles = new MediaFileManager();
|
m_SoundFiles = new MediaFileManager();
|
||||||
|
|
||||||
@@ -450,6 +478,7 @@ void uGeneral::initializeManagers()
|
|||||||
context.soundManager = soundManager;
|
context.soundManager = soundManager;
|
||||||
context.neuralManager = nnManager;
|
context.neuralManager = nnManager;
|
||||||
context.randomManager = m_randomManager;
|
context.randomManager = m_randomManager;
|
||||||
|
context.neuralTemplateManager = m_neuralTemplateManager;
|
||||||
context.randomResponses = m_randomResponses;
|
context.randomResponses = m_randomResponses;
|
||||||
context.mediaFileManager = m_SoundFiles;
|
context.mediaFileManager = m_SoundFiles;
|
||||||
context.channel = ui->edtChannel->text();
|
context.channel = ui->edtChannel->text();
|
||||||
@@ -805,7 +834,10 @@ uGeneral::~uGeneral()
|
|||||||
m_randomManager = nullptr;
|
m_randomManager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_neuralTemplateManager) {
|
||||||
|
delete m_neuralTemplateManager;
|
||||||
|
m_neuralTemplateManager = nullptr;
|
||||||
|
}
|
||||||
delete m_createNotifyDialog;
|
delete m_createNotifyDialog;
|
||||||
delete m_createChatDialog;
|
delete m_createChatDialog;
|
||||||
delete ui;
|
delete ui;
|
||||||
@@ -1755,7 +1787,15 @@ void uGeneral::on_btnNotifyCheckSub_clicked()
|
|||||||
|
|
||||||
void uGeneral::on_btnNotifyOpen_clicked()
|
void uGeneral::on_btnNotifyOpen_clicked()
|
||||||
{
|
{
|
||||||
|
QString sourceFile = QFileDialog::getOpenFileName(this,
|
||||||
|
"Выберите файл для уведомлений",
|
||||||
|
QDir::homePath(),
|
||||||
|
"Звуковой файл (*.mp3);;Все файлы (*.*)");
|
||||||
|
|
||||||
|
if (sourceFile.isEmpty()) {
|
||||||
|
return; // Пользователь отменил выбор
|
||||||
|
}
|
||||||
|
ui->edtNotifyFileName->setText(sourceFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uGeneral::on_btnNotifyOpenMod_clicked()
|
void uGeneral::on_btnNotifyOpenMod_clicked()
|
||||||
@@ -1946,7 +1986,7 @@ void uGeneral::on_btnNotifyOpenSub_clicked()
|
|||||||
|
|
||||||
// Проверяем и регистрируем пользователя
|
// Проверяем и регистрируем пользователя
|
||||||
QString userId = m_userManager->checkUser(msg.displayName, msg);
|
QString userId = m_userManager->checkUser(msg.displayName, msg);
|
||||||
|
LogManager::instance()->debug("uGeneral", "handleNewMessage", message);
|
||||||
m_userManager->m_totalMessages++;
|
m_userManager->m_totalMessages++;
|
||||||
|
|
||||||
// Обновляем статистику и воспроизводим уведомление
|
// Обновляем статистику и воспроизводим уведомление
|
||||||
@@ -2338,14 +2378,6 @@ void uGeneral::on_btnRmGroup_clicked()
|
|||||||
db->LoadRandomGroups(ui->lbRandomGroup);
|
db->LoadRandomGroups(ui->lbRandomGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uGeneral::on_btnAddUserName_clicked()
|
|
||||||
{
|
|
||||||
QTextCursor cursor = ui->textBrowser->textCursor();
|
|
||||||
cursor.insertText("[USERNAME]");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void uGeneral::on_btnGetDateFollow_clicked()
|
void uGeneral::on_btnGetDateFollow_clicked()
|
||||||
{
|
{
|
||||||
QTextCursor cursor = ui->textBrowser->textCursor();
|
QTextCursor cursor = ui->textBrowser->textCursor();
|
||||||
@@ -2465,9 +2497,52 @@ void uGeneral::on_btnEdtCommand_clicked()
|
|||||||
|
|
||||||
void uGeneral::loadQssFiles()
|
void uGeneral::loadQssFiles()
|
||||||
{
|
{
|
||||||
|
// Очищаем ComboBox
|
||||||
|
ui->cbTheme->clear();
|
||||||
|
|
||||||
|
// Добавляем опцию "Без темы"
|
||||||
|
ui->cbTheme->addItem("Без темы", "");
|
||||||
|
// 1. Загружаем системные стили (из папки приложения)
|
||||||
|
QString systemStylesPath = FileManager::instance().getPath(FileManager::SystemStyles);
|
||||||
|
QDir systemStylesDir(systemStylesPath);
|
||||||
|
|
||||||
|
if (systemStylesDir.exists()) {
|
||||||
|
qDebug() << "Системные стили из:" << systemStylesPath;
|
||||||
|
loadStylesFromDirectory(systemStylesDir, "Системные");
|
||||||
|
} else {
|
||||||
|
qWarning() << "Папка системных стилей не найдена:" << systemStylesPath;
|
||||||
|
|
||||||
|
// Создаем папку, если ее нет
|
||||||
|
systemStylesDir.mkpath(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Загружаем пользовательские стили (из папки данных пользователя)
|
||||||
|
QString userStylesPath = FileManager::instance().getPath(FileManager::Styles);
|
||||||
|
QDir userStylesDir(userStylesPath);
|
||||||
|
|
||||||
|
if (userStylesDir.exists()) {
|
||||||
|
qDebug() << "Пользовательские стили из:" << userStylesPath;
|
||||||
|
loadStylesFromDirectory(userStylesDir, "Пользовательские");
|
||||||
|
} else {
|
||||||
|
qWarning() << "Папка пользовательских стилей не найдена:" << userStylesPath;
|
||||||
|
|
||||||
|
// Создаем папку
|
||||||
|
userStylesDir.mkpath(".");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверяем, есть ли темы
|
||||||
|
if (ui->cbTheme->count() <= 1) { // Только "Без темы"
|
||||||
|
qWarning() << "Темы не найдены, создаем базовые";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Загружено тем:" << ui->cbTheme->count() - 1; // Минус "Без темы"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void uGeneral::loadStylesFromDirectory(const QDir &stylesDir, const QString &category)
|
void uGeneral::loadStylesFromDirectory(const QDir &stylesDir, const QString &category)
|
||||||
{
|
{
|
||||||
if (!stylesDir.exists()) {
|
if (!stylesDir.exists()) {
|
||||||
@@ -3231,6 +3306,8 @@ void uGeneral::on_cbNotifyFileAgain3_stateChanged(int arg1)
|
|||||||
|
|
||||||
void uGeneral::on_btnThemesFolder_clicked()
|
void uGeneral::on_btnThemesFolder_clicked()
|
||||||
{
|
{
|
||||||
|
QString userThemesPath = FileManager::instance().getPath(FileManager::Styles);
|
||||||
|
QDesktopServices::openUrl(QUrl::fromLocalFile(userThemesPath));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3281,3 +3358,16 @@ void uGeneral::loadSavedChats()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uGeneral::on_btnOpenStream_clicked()
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl("https://www.twitch.tv/" + ui->edtChannel->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uGeneral::on_btnAUserName_clicked()
|
||||||
|
{
|
||||||
|
QTextCursor cursor = ui->textBrowser->textCursor();
|
||||||
|
cursor.insertText("[USERNAME]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -219,7 +219,6 @@ private slots:
|
|||||||
// ========================================================================
|
// ========================================================================
|
||||||
// СЛОТЫ ДЛЯ РАБОТЫ С ПОЛЬЗОВАТЕЛЯМИ
|
// СЛОТЫ ДЛЯ РАБОТЫ С ПОЛЬЗОВАТЕЛЯМИ
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
void on_btnAddUserName_clicked();
|
|
||||||
void on_btnGetDateFollow_clicked();
|
void on_btnGetDateFollow_clicked();
|
||||||
void on_btnGetAgeAccaunt_clicked();
|
void on_btnGetAgeAccaunt_clicked();
|
||||||
void on_btnRandomUserName_clicked();
|
void on_btnRandomUserName_clicked();
|
||||||
@@ -347,6 +346,10 @@ private slots:
|
|||||||
void on_btnThemesFolder_clicked();
|
void on_btnThemesFolder_clicked();
|
||||||
|
|
||||||
void onNotifyServerUpdated(HttpServer *server, const QString &name);
|
void onNotifyServerUpdated(HttpServer *server, const QString &name);
|
||||||
|
void on_btnOpenStream_clicked();
|
||||||
|
|
||||||
|
void on_btnAUserName_clicked();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// Установка статуса подключения к Twitch
|
// Установка статуса подключения к Twitch
|
||||||
void setTwitchConnected(bool connected);
|
void setTwitchConnected(bool connected);
|
||||||
@@ -371,7 +374,7 @@ private:
|
|||||||
RandomManager *m_randomManager;
|
RandomManager *m_randomManager;
|
||||||
MediaFileManager *m_SoundFiles;
|
MediaFileManager *m_SoundFiles;
|
||||||
MediaFileManager *m_TextFiles;
|
MediaFileManager *m_TextFiles;
|
||||||
|
NeuralTemplateManager *m_neuralTemplateManager;
|
||||||
QList<TimerInfo> m_timers; // Список таймеров
|
QList<TimerInfo> m_timers; // Список таймеров
|
||||||
int m_nextTimerId = 1; // Следующий ID таймера
|
int m_nextTimerId = 1; // Следующий ID таймера
|
||||||
bool m_isTwitchConnected = false; // Статус подключения к Twitch
|
bool m_isTwitchConnected = false; // Статус подключения к Twitch
|
||||||
@@ -479,7 +482,7 @@ private:
|
|||||||
|
|
||||||
void loadSavedChats();
|
void loadSavedChats();
|
||||||
void loadSavedNotifications();
|
void loadSavedNotifications();
|
||||||
|
void loadNeuralTemplatesFromTableWidget();
|
||||||
void processUserCommand(const QString &username, const QString &commandText);
|
void processUserCommand(const QString &username, const QString &commandText);
|
||||||
void sendChatResponse(const QString &response);
|
void sendChatResponse(const QString &response);
|
||||||
};
|
};
|
||||||
|
|||||||
+58
-109
@@ -92,9 +92,12 @@
|
|||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Preferred</enum>
|
||||||
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>40</width>
|
<width>75</width>
|
||||||
<height>20</height>
|
<height>20</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
@@ -206,28 +209,23 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
<spacer name="horizontalSpacer_2">
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer_4">
|
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Preferred</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>20</width>
|
<width>75</width>
|
||||||
<height>40</height>
|
<height>20</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnGetClientID">
|
<layout class="QVBoxLayout" name="verticalLayout_10"/>
|
||||||
<property name="text">
|
|
||||||
<string>Получить</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
@@ -430,26 +428,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="btnGetDADef">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>10</x>
|
|
||||||
<y>270</y>
|
|
||||||
<width>151</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Получить данные DA</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="btnOpenFolderSettings">
|
<widget class="QPushButton" name="btnOpenFolderSettings">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>320</y>
|
<y>320</y>
|
||||||
<width>181</width>
|
<width>231</width>
|
||||||
<height>23</height>
|
<height>23</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -462,7 +447,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>350</y>
|
<y>350</y>
|
||||||
<width>181</width>
|
<width>231</width>
|
||||||
<height>23</height>
|
<height>23</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -475,7 +460,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>380</y>
|
<y>380</y>
|
||||||
<width>181</width>
|
<width>231</width>
|
||||||
<height>23</height>
|
<height>23</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -790,7 +775,7 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>200</y>
|
<y>190</y>
|
||||||
<width>361</width>
|
<width>361</width>
|
||||||
<height>111</height>
|
<height>111</height>
|
||||||
</rect>
|
</rect>
|
||||||
@@ -798,110 +783,74 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Вставки</string>
|
<string>Вставки</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QPushButton" name="btnAddUserName">
|
<widget class="QWidget" name="gridLayoutWidget_2">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>0</x>
|
||||||
<y>20</y>
|
<y>20</y>
|
||||||
<width>75</width>
|
<width>361</width>
|
||||||
<height>23</height>
|
<height>91</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<string>Обращение</string>
|
<item row="0" column="1">
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QPushButton" name="btnGetDateFollow">
|
<widget class="QPushButton" name="btnGetDateFollow">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>90</x>
|
|
||||||
<y>20</y>
|
|
||||||
<width>75</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Follow</string>
|
<string>Follow</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
<widget class="QPushButton" name="btnGetAgeAccaunt">
|
<widget class="QPushButton" name="btnGetAgeAccaunt">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>170</x>
|
|
||||||
<y>20</y>
|
|
||||||
<width>75</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Age</string>
|
<string>Age</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="btnGPT">
|
</item>
|
||||||
<property name="geometry">
|
<item row="1" column="3">
|
||||||
<rect>
|
|
||||||
<x>250</x>
|
|
||||||
<y>20</y>
|
|
||||||
<width>81</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Нейронка</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QPushButton" name="btnCounterAddtoText">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>10</x>
|
|
||||||
<y>50</y>
|
|
||||||
<width>75</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Счетчик</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QPushButton" name="btnAIPic">
|
<widget class="QPushButton" name="btnAIPic">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>250</x>
|
|
||||||
<y>50</y>
|
|
||||||
<width>81</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Картинка</string>
|
<string>Картинка</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="btnRandomUserName">
|
</item>
|
||||||
<property name="geometry">
|
<item row="0" column="3">
|
||||||
<rect>
|
<widget class="QPushButton" name="btnGPT">
|
||||||
<x>10</x>
|
|
||||||
<y>80</y>
|
|
||||||
<width>151</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Рандомный пользователь</string>
|
<string>Нейронка</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="btnGetChannelStat">
|
</item>
|
||||||
<property name="geometry">
|
<item row="1" column="0">
|
||||||
<rect>
|
<widget class="QPushButton" name="btnCounterAtoText">
|
||||||
<x>170</x>
|
|
||||||
<y>80</y>
|
|
||||||
<width>161</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Статистика канала</string>
|
<string>Счетчик</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPushButton" name="btnAUserName">
|
||||||
|
<property name="text">
|
||||||
|
<string>Обращение</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="3">
|
||||||
|
<widget class="QPushButton" name="btnGetChannelStat">
|
||||||
|
<property name="text">
|
||||||
|
<string>Статистика</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QPushButton" name="btnRandomUserName">
|
||||||
|
<property name="text">
|
||||||
|
<string>Рандом</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="btnAddCommand">
|
<widget class="QPushButton" name="btnAddCommand">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
|
|||||||
+62
-29
@@ -5,6 +5,8 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <synchapi.h>
|
#include <synchapi.h>
|
||||||
|
#include "logmanager.h"
|
||||||
|
#include "qregularexpression.h"
|
||||||
|
|
||||||
WebSocketClient::WebSocketClient(QObject *parent) :
|
WebSocketClient::WebSocketClient(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
@@ -24,6 +26,7 @@ WebSocketClient::~WebSocketClient()
|
|||||||
delete m_webSocket;
|
delete m_webSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WebSocketClient::connectToServer(const QString &url)
|
bool WebSocketClient::connectToServer(const QString &url)
|
||||||
{
|
{
|
||||||
if (m_webSocket) {
|
if (m_webSocket) {
|
||||||
@@ -154,44 +157,74 @@ void WebSocketClient::onPingTimeout()
|
|||||||
|
|
||||||
void WebSocketClient::onTextMessageReceived(const QString &message)
|
void WebSocketClient::onTextMessageReceived(const QString &message)
|
||||||
{
|
{
|
||||||
|
QStringList lines = message.split("\r\n", Qt::SkipEmptyParts);
|
||||||
|
|
||||||
// Обработка PING от сервера
|
for (const QString &line : lines) {
|
||||||
if (message.startsWith("PING")) {
|
if (line.isEmpty()) continue;
|
||||||
|
|
||||||
|
qDebug() << "RAW LINE:" << line;
|
||||||
|
|
||||||
|
// Определяем тип сообщения
|
||||||
|
bool isPing = line.startsWith("PING");
|
||||||
|
bool isPrivmsg = false;
|
||||||
|
bool isUserState = line.contains("USERSTATE");
|
||||||
|
bool isRoomState = line.contains("ROOMSTATE");
|
||||||
|
bool isUserNotice = line.contains("USERNOTICE");
|
||||||
|
bool isJoin = line.contains(" JOIN ");
|
||||||
|
bool isNamesList = (line.contains("353") || line.contains("366"));
|
||||||
|
bool isCapAck = line.contains("CAP * ACK");
|
||||||
|
|
||||||
|
// Проверяем PRIVMSG отдельно, чтобы избежать ложных срабатываний
|
||||||
|
if (line.contains("PRIVMSG", Qt::CaseInsensitive)) {
|
||||||
|
// Проверяем структуру PRIVMSG сообщения
|
||||||
|
// Должно быть: @теги :префикс PRIVMSG #канал :сообщение
|
||||||
|
if (!isUserState && !isRoomState && !isUserNotice) {
|
||||||
|
// Проверяем наличие канала и текста сообщения
|
||||||
|
if (line.contains(" #") && line.contains(" :")) {
|
||||||
|
isPrivmsg = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка в зависимости от типа
|
||||||
|
if (isPing) {
|
||||||
send("PONG :tmi.twitch.tv\r\n");
|
send("PONG :tmi.twitch.tv\r\n");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (isCapAck) {
|
||||||
// Обработка успешной аутентификации
|
qDebug() << "Capabilities acknowledged";
|
||||||
if (message.contains("001") && !m_currentChannel.isEmpty()) {
|
}
|
||||||
|
else if (isPrivmsg) {
|
||||||
|
qDebug() << "PRIVMSG detected (final):" << line;
|
||||||
|
emit onNewMessage(line);
|
||||||
|
}
|
||||||
|
else if (isJoin) {
|
||||||
|
qDebug() << "JOIN detected:" << line;
|
||||||
|
// emit onUserJoined(line);
|
||||||
|
}
|
||||||
|
else if (isUserState) {
|
||||||
|
qDebug() << "USERSTATE detected:" << line;
|
||||||
|
// emit onUserState(line);
|
||||||
|
}
|
||||||
|
else if (isRoomState) {
|
||||||
|
qDebug() << "ROOMSTATE detected:" << line;
|
||||||
|
// emit onRoomState(line);
|
||||||
|
}
|
||||||
|
else if (isUserNotice) {
|
||||||
|
qDebug() << "USERNOTICE detected:" << line;
|
||||||
|
// emit onUserNotice(line);
|
||||||
|
}
|
||||||
|
else if (isNamesList) {
|
||||||
|
qDebug() << "NAMES list:" << line;
|
||||||
|
}
|
||||||
|
else if (line.contains("001") && !m_currentChannel.isEmpty()) {
|
||||||
joinChannel(m_currentChannel);
|
joinChannel(m_currentChannel);
|
||||||
return; // Добавить return после первого успешного подключения
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// Обработка сообщений чата
|
qDebug() << "OTHER message:" << line;
|
||||||
if (message.contains("PRIVMSG")) {
|
|
||||||
// Извлекаем информацию из сообщения
|
|
||||||
// Формат: :nick!nick@nick.tmi.twitch.tv PRIVMSG #channel :message
|
|
||||||
QString cleanMessage = message;
|
|
||||||
emit onNewMessage(cleanMessage);
|
|
||||||
// Удаляем служебную информацию для чистого отображения
|
|
||||||
int msgIndex = cleanMessage.indexOf("PRIVMSG");
|
|
||||||
if (msgIndex != -1) {
|
|
||||||
int channelIndex = cleanMessage.indexOf("#", msgIndex);
|
|
||||||
int messageIndex = cleanMessage.indexOf(" :", channelIndex);
|
|
||||||
if (messageIndex != -1) {
|
|
||||||
QString chatMessage = cleanMessage.mid(messageIndex + 2).trimmed();
|
|
||||||
QString sender = cleanMessage.mid(1, cleanMessage.indexOf("!") - 1);
|
|
||||||
QString channel = cleanMessage.mid(channelIndex + 1,
|
|
||||||
messageIndex - channelIndex - 1);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::onErrorInternal(QAbstractSocket::SocketError error)
|
void WebSocketClient::onErrorInternal(QAbstractSocket::SocketError error)
|
||||||
{
|
{
|
||||||
QString errorMsg = QString("WebSocket error: %1 - %2")
|
QString errorMsg = QString("WebSocket error: %1 - %2")
|
||||||
|
|||||||
Reference in New Issue
Block a user