починил нейроконструктор, исправил распознавание сообщений из чата
This commit is contained in:
@@ -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 \
|
||||
|
||||
+134
-3
@@ -1,4 +1,5 @@
|
||||
#include "commandprocessor.h"
|
||||
#include "neuraltemplatemanager.h"
|
||||
#include <QRegularExpression>
|
||||
#include <QRandomGenerator>
|
||||
#include <QFile>
|
||||
@@ -6,6 +7,12 @@
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
|
||||
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<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 "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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -59,8 +59,7 @@ public:
|
||||
// Получение относительного пути для веб-сервера
|
||||
QString getWebPath(FileType type, const QString& fileName) const;
|
||||
|
||||
// Копирование файлов из системных в пользовательские (при первом запуске)
|
||||
void copyDefaultFiles();
|
||||
|
||||
|
||||
private:
|
||||
FileManager();
|
||||
|
||||
+29
-10
@@ -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;
|
||||
|
||||
@@ -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<NetworkType, NetworkConfig> 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;
|
||||
|
||||
@@ -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/mediafilemanager.o
|
||||
debug/neuralnetworkmanager.o
|
||||
debug/neuraltemplatemanager.o
|
||||
debug/randommanager.o
|
||||
debug/randomresponses.o
|
||||
debug/soundmanager.o
|
||||
@@ -36,6 +37,7 @@ debug/moc_fsettingsws.o
|
||||
debug/moc_fsinglegrid.o
|
||||
debug/moc_logmanager.o
|
||||
debug/moc_neuralnetworkmanager.o
|
||||
debug/moc_neuraltemplatemanager.o
|
||||
debug/moc_randommanager.o
|
||||
debug/moc_randomresponses.o
|
||||
debug/moc_soundmanager.o
|
||||
|
||||
@@ -11,6 +11,7 @@ release/logmanager.o
|
||||
release/main.o
|
||||
release/mediafilemanager.o
|
||||
release/neuralnetworkmanager.o
|
||||
release/neuraltemplatemanager.o
|
||||
release/randommanager.o
|
||||
release/randomresponses.o
|
||||
release/soundmanager.o
|
||||
@@ -36,6 +37,7 @@ release/moc_fsettingsws.o
|
||||
release/moc_fsinglegrid.o
|
||||
release/moc_logmanager.o
|
||||
release/moc_neuralnetworkmanager.o
|
||||
release/moc_neuraltemplatemanager.o
|
||||
release/moc_randommanager.o
|
||||
release/moc_randomresponses.o
|
||||
release/moc_soundmanager.o
|
||||
|
||||
+109
-19
@@ -36,12 +36,13 @@ uGeneral::uGeneral(QWidget *parent)
|
||||
, m_authStreamer(nullptr)
|
||||
, m_authDA(nullptr)
|
||||
, fLinkForm(nullptr)
|
||||
, m_randomManager(nullptr)
|
||||
, m_neuralTemplateManager(nullptr)
|
||||
, m_isTwitchConnected(false)
|
||||
, m_notificationServers()
|
||||
, m_chatServers()
|
||||
, m_createNotifyDialog(nullptr)
|
||||
, m_createChatDialog(nullptr)
|
||||
, m_randomManager(nullptr)
|
||||
{
|
||||
// ============================================================================
|
||||
// ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
|
||||
@@ -86,7 +87,7 @@ uGeneral::uGeneral(QWidget *parent)
|
||||
|
||||
// Инициализируем структуру папок
|
||||
FileManager::instance().initializeFolderStructure();
|
||||
FileManager::instance().copyDefaultFiles();
|
||||
|
||||
// Получаем пути через FileManager
|
||||
QString sysPath = FileManager::instance().systemPath();
|
||||
|
||||
@@ -181,10 +182,7 @@ uGeneral::uGeneral(QWidget *parent)
|
||||
// Добавьте эту строку в конец метода:
|
||||
initializeNotificationSounds();
|
||||
|
||||
if (db) {
|
||||
m_randomManager = new RandomManager(this);
|
||||
m_randomManager->initialize(db);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -394,6 +392,8 @@ void uGeneral::setupTables()
|
||||
this, &uGeneral::onFilesGridDoubleClicked);
|
||||
connect(ui->widget_3->tableWidget(), &QTableWidget::cellDoubleClicked,
|
||||
this, &uGeneral::onNeiroGridDoubleClicked);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -416,12 +416,40 @@ void uGeneral::initializeManagers()
|
||||
|
||||
// Менеджер случайных ответов (групп)
|
||||
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->setApiKey(NeuralNetworkManager::DeepSeek, "ваш_api_ключ");
|
||||
// nnManager->setModel(NeuralNetworkManager::DeepSeek, "deepseek-chat");
|
||||
nnManager->setPrefix(ui->edtGPTPrefix->text());
|
||||
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();
|
||||
|
||||
@@ -450,6 +478,7 @@ void uGeneral::initializeManagers()
|
||||
context.soundManager = soundManager;
|
||||
context.neuralManager = nnManager;
|
||||
context.randomManager = m_randomManager;
|
||||
context.neuralTemplateManager = m_neuralTemplateManager;
|
||||
context.randomResponses = m_randomResponses;
|
||||
context.mediaFileManager = m_SoundFiles;
|
||||
context.channel = ui->edtChannel->text();
|
||||
@@ -805,7 +834,10 @@ uGeneral::~uGeneral()
|
||||
m_randomManager = nullptr;
|
||||
}
|
||||
|
||||
|
||||
if (m_neuralTemplateManager) {
|
||||
delete m_neuralTemplateManager;
|
||||
m_neuralTemplateManager = nullptr;
|
||||
}
|
||||
delete m_createNotifyDialog;
|
||||
delete m_createChatDialog;
|
||||
delete ui;
|
||||
@@ -1755,7 +1787,15 @@ void uGeneral::on_btnNotifyCheckSub_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()
|
||||
@@ -1946,7 +1986,7 @@ void uGeneral::on_btnNotifyOpenSub_clicked()
|
||||
|
||||
// Проверяем и регистрируем пользователя
|
||||
QString userId = m_userManager->checkUser(msg.displayName, msg);
|
||||
|
||||
LogManager::instance()->debug("uGeneral", "handleNewMessage", message);
|
||||
m_userManager->m_totalMessages++;
|
||||
|
||||
// Обновляем статистику и воспроизводим уведомление
|
||||
@@ -2338,14 +2378,6 @@ void uGeneral::on_btnRmGroup_clicked()
|
||||
db->LoadRandomGroups(ui->lbRandomGroup);
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_btnAddUserName_clicked()
|
||||
{
|
||||
QTextCursor cursor = ui->textBrowser->textCursor();
|
||||
cursor.insertText("[USERNAME]");
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_btnGetDateFollow_clicked()
|
||||
{
|
||||
QTextCursor cursor = ui->textBrowser->textCursor();
|
||||
@@ -2465,9 +2497,52 @@ void uGeneral::on_btnEdtCommand_clicked()
|
||||
|
||||
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)
|
||||
{
|
||||
if (!stylesDir.exists()) {
|
||||
@@ -3231,6 +3306,8 @@ void uGeneral::on_cbNotifyFileAgain3_stateChanged(int arg1)
|
||||
|
||||
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_btnGetAgeAccaunt_clicked();
|
||||
void on_btnRandomUserName_clicked();
|
||||
@@ -347,6 +346,10 @@ private slots:
|
||||
void on_btnThemesFolder_clicked();
|
||||
|
||||
void onNotifyServerUpdated(HttpServer *server, const QString &name);
|
||||
void on_btnOpenStream_clicked();
|
||||
|
||||
void on_btnAUserName_clicked();
|
||||
|
||||
public slots:
|
||||
// Установка статуса подключения к Twitch
|
||||
void setTwitchConnected(bool connected);
|
||||
@@ -371,7 +374,7 @@ private:
|
||||
RandomManager *m_randomManager;
|
||||
MediaFileManager *m_SoundFiles;
|
||||
MediaFileManager *m_TextFiles;
|
||||
|
||||
NeuralTemplateManager *m_neuralTemplateManager;
|
||||
QList<TimerInfo> m_timers; // Список таймеров
|
||||
int m_nextTimerId = 1; // Следующий ID таймера
|
||||
bool m_isTwitchConnected = false; // Статус подключения к Twitch
|
||||
@@ -479,7 +482,7 @@ private:
|
||||
|
||||
void loadSavedChats();
|
||||
void loadSavedNotifications();
|
||||
|
||||
void loadNeuralTemplatesFromTableWidget();
|
||||
void processUserCommand(const QString &username, const QString &commandText);
|
||||
void sendChatResponse(const QString &response);
|
||||
};
|
||||
|
||||
+58
-109
@@ -92,9 +92,12 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<width>75</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
@@ -206,28 +209,23 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
<width>75</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnGetClientID">
|
||||
<property name="text">
|
||||
<string>Получить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@@ -430,26 +428,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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 class="QPushButton" name="btnOpenFolderSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>320</y>
|
||||
<width>181</width>
|
||||
<width>231</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -462,7 +447,7 @@
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>350</y>
|
||||
<width>181</width>
|
||||
<width>231</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -475,7 +460,7 @@
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>380</y>
|
||||
<width>181</width>
|
||||
<width>231</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -790,7 +775,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>200</y>
|
||||
<y>190</y>
|
||||
<width>361</width>
|
||||
<height>111</height>
|
||||
</rect>
|
||||
@@ -798,110 +783,74 @@
|
||||
<property name="title">
|
||||
<string>Вставки</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="btnAddUserName">
|
||||
<widget class="QWidget" name="gridLayoutWidget_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
<width>361</width>
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Обращение</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<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">
|
||||
<string>Follow</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<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">
|
||||
<string>Age</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnGPT">
|
||||
<property name="geometry">
|
||||
<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>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<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">
|
||||
<string>Картинка</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnRandomUserName">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>80</y>
|
||||
<width>151</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="btnGPT">
|
||||
<property name="text">
|
||||
<string>Рандомный пользователь</string>
|
||||
<string>Нейронка</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnGetChannelStat">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>170</x>
|
||||
<y>80</y>
|
||||
<width>161</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="btnCounterAtoText">
|
||||
<property name="text">
|
||||
<string>Статистика канала</string>
|
||||
<string>Счетчик</string>
|
||||
</property>
|
||||
</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 class="QPushButton" name="btnAddCommand">
|
||||
<property name="geometry">
|
||||
|
||||
+62
-29
@@ -5,6 +5,8 @@
|
||||
#include <QDateTime>
|
||||
#include <QCoreApplication>
|
||||
#include <synchapi.h>
|
||||
#include "logmanager.h"
|
||||
#include "qregularexpression.h"
|
||||
|
||||
WebSocketClient::WebSocketClient(QObject *parent) :
|
||||
QObject(parent),
|
||||
@@ -24,6 +26,7 @@ WebSocketClient::~WebSocketClient()
|
||||
delete m_webSocket;
|
||||
}
|
||||
|
||||
|
||||
bool WebSocketClient::connectToServer(const QString &url)
|
||||
{
|
||||
if (m_webSocket) {
|
||||
@@ -154,42 +157,72 @@ void WebSocketClient::onPingTimeout()
|
||||
|
||||
void WebSocketClient::onTextMessageReceived(const QString &message)
|
||||
{
|
||||
QStringList lines = message.split("\r\n", Qt::SkipEmptyParts);
|
||||
|
||||
// Обработка PING от сервера
|
||||
if (message.startsWith("PING")) {
|
||||
for (const QString &line : lines) {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
// Обработка успешной аутентификации
|
||||
if (message.contains("001") && !m_currentChannel.isEmpty()) {
|
||||
else if (isCapAck) {
|
||||
qDebug() << "Capabilities acknowledged";
|
||||
}
|
||||
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);
|
||||
return; // Добавить return после первого успешного подключения
|
||||
}
|
||||
|
||||
// Обработка сообщений чата
|
||||
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);
|
||||
|
||||
|
||||
else {
|
||||
qDebug() << "OTHER message:" << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void WebSocketClient::onErrorInternal(QAbstractSocket::SocketError error)
|
||||
|
||||
Reference in New Issue
Block a user