ваше сообщение коммита
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
/**
|
||||
* Очередь для AI запросов с приоритизацией
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
const EventEmitter = require('events');
|
||||
@@ -10,50 +18,51 @@ class AIQueue extends EventEmitter {
|
||||
super();
|
||||
this.queue = [];
|
||||
this.processing = false;
|
||||
this.maxConcurrent = 1; // Максимум 1 запрос одновременно (последовательная обработка)
|
||||
this.activeRequests = 0;
|
||||
this.maxConcurrent = 1; // Ограничиваем до 1 для стабильности
|
||||
this.isPaused = false;
|
||||
this.stats = {
|
||||
total: 0,
|
||||
completed: 0,
|
||||
failed: 0,
|
||||
avgResponseTime: 0
|
||||
avgResponseTime: 0,
|
||||
lastProcessedAt: null,
|
||||
initializedAt: Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
// Добавление запроса в очередь
|
||||
async addRequest(request, priority = 0) {
|
||||
const requestId = Date.now() + Math.random();
|
||||
const queueItem = {
|
||||
id: Date.now() + Math.random(),
|
||||
id: requestId,
|
||||
request,
|
||||
priority,
|
||||
timestamp: Date.now(),
|
||||
status: 'pending'
|
||||
status: 'queued',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
// Добавляем в очередь с учетом приоритета
|
||||
this.queue.push(queueItem);
|
||||
this.queue.sort((a, b) => b.priority - a.priority); // Сортировка по приоритету
|
||||
this.queue.sort((a, b) => b.priority - a.priority);
|
||||
|
||||
this.stats.total++;
|
||||
logger.info(`[AIQueue] Added request ${queueItem.id} with priority ${priority}`);
|
||||
logger.info(`[AIQueue] Добавлен запрос ${requestId} с приоритетом ${priority}. Очередь: ${this.queue.length}`);
|
||||
|
||||
// Запускаем обработку если не запущена
|
||||
// Запускаем обработку очереди
|
||||
if (!this.processing) {
|
||||
this.processQueue();
|
||||
}
|
||||
|
||||
return queueItem.id;
|
||||
return requestId;
|
||||
}
|
||||
|
||||
// Обработка очереди
|
||||
async processQueue() {
|
||||
if (this.processing || this.activeRequests >= this.maxConcurrent) {
|
||||
return;
|
||||
}
|
||||
if (this.processing) return;
|
||||
|
||||
this.processing = true;
|
||||
logger.info(`[AIQueue] Начинаем обработку очереди. Запросов в очереди: ${this.queue.length}`);
|
||||
|
||||
while (this.queue.length > 0 && this.activeRequests < this.maxConcurrent) {
|
||||
while (!this.isPaused && this.queue.length > 0 && this.activeRequests < this.maxConcurrent) {
|
||||
const item = this.queue.shift();
|
||||
if (!item) continue;
|
||||
|
||||
@@ -72,6 +81,7 @@ class AIQueue extends EventEmitter {
|
||||
|
||||
this.stats.completed++;
|
||||
this.updateAvgResponseTime(responseTime);
|
||||
this.stats.lastProcessedAt = Date.now();
|
||||
|
||||
logger.info(`[AIQueue] Запрос ${item.id} завершен за ${responseTime}ms`);
|
||||
|
||||
@@ -83,6 +93,7 @@ class AIQueue extends EventEmitter {
|
||||
item.error = error.message;
|
||||
|
||||
this.stats.failed++;
|
||||
this.stats.lastProcessedAt = Date.now();
|
||||
logger.error(`[AIQueue] Запрос ${item.id} завершился с ошибкой:`, error.message);
|
||||
|
||||
// Эмитим событие об ошибке
|
||||
@@ -96,21 +107,24 @@ class AIQueue extends EventEmitter {
|
||||
logger.info(`[AIQueue] Обработка очереди завершена. Осталось запросов: ${this.queue.length}`);
|
||||
|
||||
// Если в очереди еще есть запросы, продолжаем обработку
|
||||
if (this.queue.length > 0) {
|
||||
if (!this.isPaused && this.queue.length > 0) {
|
||||
setTimeout(() => this.processQueue(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка одного запроса
|
||||
async processRequest(request) {
|
||||
// Прямой вызов AI без очереди
|
||||
const aiAssistant = require('./ai-assistant');
|
||||
|
||||
// Используем прямой метод без очереди
|
||||
// Формируем сообщения для API
|
||||
const messages = [];
|
||||
|
||||
// Добавляем системный промпт
|
||||
if (request.systemPrompt) {
|
||||
messages.push({ role: 'system', content: request.systemPrompt });
|
||||
}
|
||||
|
||||
// Добавляем историю сообщений
|
||||
if (request.history && Array.isArray(request.history)) {
|
||||
for (const msg of request.history) {
|
||||
if (msg.role && msg.content) {
|
||||
@@ -118,10 +132,12 @@ class AIQueue extends EventEmitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем текущее сообщение пользователя
|
||||
messages.push({ role: 'user', content: request.message });
|
||||
|
||||
// Прямой вызов API без очереди
|
||||
return await aiAssistant.fallbackRequestOpenAI(messages, request.systemPrompt);
|
||||
// Используем прямой метод для избежания рекурсии
|
||||
return await aiAssistant.directRequest(messages, request.systemPrompt);
|
||||
}
|
||||
|
||||
// Обновление средней скорости ответа
|
||||
@@ -133,8 +149,17 @@ class AIQueue extends EventEmitter {
|
||||
|
||||
// Получение статистики
|
||||
getStats() {
|
||||
const totalProcessed = this.stats.completed + this.stats.failed;
|
||||
return {
|
||||
...this.stats,
|
||||
// совместимость с AIQueueMonitor.vue и маршрутами
|
||||
totalProcessed,
|
||||
totalFailed: this.stats.failed,
|
||||
averageProcessingTime: this.stats.avgResponseTime,
|
||||
currentQueueSize: this.queue.length,
|
||||
runningTasks: this.activeRequests,
|
||||
lastProcessedAt: this.stats.lastProcessedAt,
|
||||
isInitialized: true,
|
||||
// старые поля на всякий случай
|
||||
queueLength: this.queue.length,
|
||||
activeRequests: this.activeRequests,
|
||||
processing: this.processing
|
||||
@@ -146,6 +171,39 @@ class AIQueue extends EventEmitter {
|
||||
this.queue = [];
|
||||
logger.info('[AIQueue] Queue cleared');
|
||||
}
|
||||
|
||||
// Совместимость с роутами AI Queue
|
||||
pause() {
|
||||
this.isPaused = true;
|
||||
logger.info('[AIQueue] Queue paused');
|
||||
}
|
||||
|
||||
resume() {
|
||||
const wasPaused = this.isPaused;
|
||||
this.isPaused = false;
|
||||
logger.info('[AIQueue] Queue resumed');
|
||||
if (wasPaused) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
async addTask(taskData) {
|
||||
// Маппинг к addRequest
|
||||
const priority = this._calcTaskPriority(taskData);
|
||||
const taskId = await this.addRequest(taskData, priority);
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
_calcTaskPriority({ message = '', type, userRole, history }) {
|
||||
let priority = 0;
|
||||
if (userRole === 'admin') priority += 10;
|
||||
if (type === 'chat') priority += 5;
|
||||
if (type === 'analysis') priority += 3;
|
||||
if (type === 'generation') priority += 1;
|
||||
if (message && message.length < 100) priority += 2;
|
||||
if (history && Array.isArray(history) && history.length > 0) priority += 1;
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new AIQueue();
|
||||
Reference in New Issue
Block a user