turns-00063.parquet:7075
7491b06fe7ccb8f41c3e0f30degenerate_repetitionAbsentFinal dense release
Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.
7491b06fe7ccb8f41c3e0f30Send only episode number from below text like 01, 02, 03.etc without any extra text. 10.[@KandThaiDrama] Youth (2018) S01E10 1080p 10bit [Hindi Korean] AMZN WEB-DL AAC 2.0 ×265 Esub.mkv
10
82976ba1d0f294d6237e0874User: translatekan nomor 4 ini menjadi Bahasa inggris User: translatekan nomor 4 ini menjadi Bahasa inggris Assistant:
Tentu! Silakan berikan isi dari nomor 4 yang ingin Anda terjemahkan, dan saya akan membantu menerjemahkannya ke dalam Bahasa Inggris.
27cf4c9616da1b38a04c3b00Send only season number from below text like 01, 02, 03.etc without any extra text. 10.[@KandThaiDrama] Youth (2018) S01E10 1080p 10bit [Hindi Korean] AMZN WEB-DL AAC 2.0 ×265 Esub.mkv
01
4e2882ca8a4e57c8955caf35User: //const { gpt, gptweb } = require("./API/gpt");
//const { dalle } = require("./API/dalle");
const { gpt4o } = require("c:/PrivateAPI/API/gpt4o");
//const { gpt3 } = require("./API/gpt3.5");
//const { prompts } = require("./API/gpt-prompts");
const { blackbox } = require("c:/PrivateAPI/API/blackbox");
const { qwen } = require("c:/PrivateAPI/API/qwen");
const { gemini } = require("c:/PrivateAPI/API/gemini");
const WebSocket = require('ws');
const Bottleneck = require('bottleneck');
const { stats, scheduleDailyReset, resetStatistics } = require('./stats'); // Импортируем модуль статистики
const fs = require('fs');
const path = require('path');
const Ajv = require('ajv');
const axios = require('axios');
const https = require('https');
const redis = require('redis');
const { promisify } = require('util');
const express = require('express');
const cors = require('cors'); // Импортируем cors
// Обработка необработанных исключений (помогут выявить обшибки, которые не обрабатываются блоками try/catch)
process.on('uncaughtException', (err) => {
console.error('Необработанное исключение:', err);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Необработанное отклонение промиса:', reason);
});
// Текущее количество подключенных клиентов
let currentConnectedClients = 0;
// Текущее количество обрабатываемых запросов
let currentGPT4oProcessingRequests = 0;
let currentGeminiProcessingRequests = 0;
let currentQwenProcessingRequests = 0;
let currentBlackboxProcessingRequests = 0;
// Объект для хранения количества подключений по IP
const ipConnectionCount = {};
// Максимальное количество подключений с одного IP
const MAX_CONNECTIONS_PER_IP = 100;
// Создание и настройка клиента Redis
const redisClient = redis.createClient();
// Подключаем клиента Redis
redisClient.connect().catch(err => {
console.error('Ошибка подключения к Redis:', err);
});
redisClient.on('error', (err) => {
console.error('Ошибка Redis:', err);
});
// Промис-обертка для команды get
const getAsync = async (key) => {
if (!redisClient.isOpen) { // Проверяем, открыт ли клиент
console.error('Клиент Redis не подключён, невозможно выполнить get:', key);
return null; // Возвращаем null, если клиент не подключен
}
try {
return await redisClient.get(key);
} catch (error) {
console.error('Ошибка при получении из Redis:', error);
throw error; //throw error чтобы выше поймали
}
};
// SSL сертификаты
const serverOptions = {
key: fs.readFileSync('C:\\OSPanel\\userdata\\config\\cert_files\\gpt.loc-key.pem'), // Приватный ключ
cert: fs.readFileSync('C:\\OSPanel\\userdata\\config\\cert_files\\gpt.loc.pem'), // Сертификат
};
// HTTPS сервер
const httpsServer = https.createServer(serverOptions);
// Создайте WebSocket-сервер, используя существующий HTTPS сервер
const wss = new WebSocket.Server({ server: httpsServer });
// Запустите сервер
httpsServer.listen(3000, () => {
console.log('HTTPS сервер и WebSocket сервер запущены на порту 3000');
});
// Создаем экземпляр Ajv (проверка входящей переписки на соответствие схеме)
const ajv = new Ajv();
// Объект для хранения действий и состояния каждого клиента
const clientActions = {};
// Объект для хранения ограничителей по каждому клиенту
const limiters = {};
// Домен
const allowedOrigin = 'https://gpt.loc';
wss.on('connection', (ws, req) => {
//console.log('Новое соединение:', req.socket.remoteAddress);
const urlParams = new URLSearchParams(req.url.split('?')[1]);
const userId = urlParams.get('token'); // Получаем UUID из URL
const userIP = req.socket.remoteAddress;
//console.log("IP-адрес - ", userIP, "Время подключения - ", new Date().toISOString());
const userHeaders = req.headers;
// Проверяем Origin
if (!checkOrigin(userHeaders.origin, ws)) {
return; // Если отклонено, выходим из обработчика
}
// Если количество подключений с этого IP превышает лимит, закрываем соединение
if (ipConnectionCount[userIP] >= MAX_CONNECTIONS_PER_IP) {
console.log(`Превышен лимит подключений для IP: ${userIP}, отказано в соединении.`);
stats.totalIPBlocks++;
ws.close(); // Закрываем соединение
return; // Выходим из обработчика
}
// Увеличиваем счетчик подключений
currentConnectedClients++;
// Обновляем максимальное количество клиентов, если текущее количество больше
if (currentConnectedClients > stats.maxConnectedClients) {
stats.maxConnectedClients = currentConnectedClients;
console.log(`Максимальное количество подключенных клиентов: ${stats.maxConnectedClients}`);
}
// Увеличиваем счетчик подключений для этого IP
ipConnectionCount[userIP] = (ipConnectionCount[userIP] || 0) + 1;
// Увеличиваем общий счетчик подключений
stats.totalConnections++;
console.log('Client connected with user ID:', userId, ' and IP:', userIP);
// Инициализируем состояние клиента, если его еще нет
if (!clientActions[userId]) {
clientActions[userId] = {
actions: [], // Массив для хранения действий
connected: true, // Статус подключения
lastRequestTime: new Date(), // Добавляем время последнего запроса
ws: ws,
processing: false,
delay: 1000, // Задержка по умолчанию, например, 1000 мс
responseTimes: [] // массив для хранения временных меток (начало и конец 3-х ответов)
};
}
else {
// обновляем ws при переподключении
clientActions[userId].connected = true;
clientActions[userId].ws = ws;
// вы можете обновить другие параметры здесь
}
if (!limiters[userId]) {
// Создаем экземпляр Bottleneck для каждого клиента (ограничение на количество запросов по Id)
limiters[userId] = new Bottleneck({
maxConcurrent: 1, // Максимальное количество одновременных задач
minTime: 1000, // Минимальное время между запросами в миллисекундах
highWater: 0 // Не разрешать в очереди больше 0 запросов (игнорировать)
});
}
ws.on('message', (message) => {console.log(clientActions[userId].processing);
// Обновляем время последнего запроса
clientActions[userId].lastRequestTime = new Date();
// Проверяем, является ли сообщение экземпляром Buffer
if (Buffer.isBuffer(message))
message = message.toString();
try {
// Преобразуем строку JSON обратно в объект
message = JSON.parse(message);
//Получаем историю чата из запроса
let messages = message.messages;
let model = message.model;
let rewrite = message.rewrite;
// Выполняем валидацию сообщений
messages = validateMessages(messages);
// Проверяем, остались ли сообщения после валидации
if (messages.length === 0) {
const response = { code: 2, message: "Нет валидных сообщений для обработки." };
sendMessage(ws, response);
return;
}
// Урезаем последнее сообщение до 2000 символов, если оно от клиента
if (messages[messages.length - 1].role === 'user') {
messages[messages.length - 1].content = messages[messages.length - 1].content.substring(0, 2000000);
}
// Увеличиваем общий счетчик запросов
stats.totalRequests++;
// Проверяем не обрабатывается ли в данный момент запрос клиента
if(clientActions[userId].processing){
const responseTimes = clientActions[userId].responseTimes;
let lastEndTime;
// Проверяем, существует ли time end последнего ответа
if (responseTimes.length > 0 && responseTimes[responseTimes.length - 1].end) {
lastEndTime = responseTimes[responseTimes.length - 1].end;
} else {
lastEndTime = new Date(); // Присваиваем текущее время, если нет предыдущего завершения
}
const currentTime = new Date();
const timeSinceLastEnd = currentTime - lastEndTime;
// Если с момента последнего ответа прошло больше 40 секунд, сбрасываем флаг
if (timeSinceLastEnd > 40000) {
clientActions[userId].processing = false;
}
else{
// Увеличиваем счетчик ошибок
stats.totalProcessingErrors++;
console.log('Обрабатывается предыдущий запрос.');
const response = { code: 2, message: "Сервер занят. Пожалуйста, попробуйте позже." };
// Отправка ответа клиенту
setTimeout(() => {
sendMessage(ws, response);
}, 5 * 1000);
return;
}
}
// Задержка перед отправкой запроса
const responseTimes = clientActions[userId].responseTimes; // Получаем массив responseTimes
// Проверяем, прошло ли больше 15 секунд с момента окончания последнего ответа
if (responseTimes.length === 3) {
const lastEndTime = responseTimes[responseTimes.length - 1].end;
const currentTime = new Date();
// Вычисляем разницу во времени
const timeSinceLastEnd = currentTime - lastEndTime; // Время в миллисекундах
if (timeSinceLastEnd > 20000) { // Если прошло больше 15 секунд
clientActions[userId].delay = 1000; // Устанавливаем delay на 1 мс
}
}
console.log('Задержка - ', clientActions[userId].delay)
// Используем Bottleneck для управления количеством запросов
limiters[userId].schedule(() => {
clientActions[userId].processing = true;
// Отправка запроса на сервер чата с задержкой
setTimeout(() => {
call(messages, model, ws, userId, rewrite);
}, clientActions[userId].delay);
}).catch(error => {
stats.totalIPBlocks++;
//console.error('Rate limit exceeded, message ignored:', error);
//const response = { code: 2, message: "Превышен лимит запросов. Пожалуйста, попробуйте позже." };
// Отправка ответа клиенту
//sendMessage(ws, response);
});
} catch (error) {
stats.totalWsMessErrors++;
console.error('Error parsing JSON:', error);
const response = { code: 2, message: "Произошла ошибка. Попробуйте еще раз."};
console.log(response);
// Отправка ответа клиенту
sendMessage(ws, response);
}
});
ws.on('close', () => {
try {
// Проверка, существует ли userId в clientActions
if (clientActions[userId]) {
clientActions[userId].connected = false; // Обновление статуса подключения
//delete clientActions[userId]; // Удаление состояния клиента
}
// Проверка, существует ли userId в limiters
if (limiters[userId]) {
//delete limiters[userId]; // Удаление ограничителя для данного клиента
}
console.log('Client ',userId, ' disconnected');
// Уменьшаем счетчик подключений для этого IP
if (ipConnectionCount[userIP] !== undefined) {
ipConnectionCount[userIP]--;
// Если счетчик равен 0, удаляем запись из объекта
if (ipConnectionCount[userIP] === 0) {
delete ipConnectionCount[userIP];
}
}
// Уменьшаем счетчик при отключении клиента
currentConnectedClients = Math.max(currentConnectedClients - 1, 0);
} catch (error) {
console.error('Error handling client disconnect:', error);
}
});
});
// Запускаем планировщик для статистики
scheduleDailyReset();
// Таймер для проверки клиентов каждые 3 минут
setInterval(() => {
const currentTime = new Date();
for (const userId in clientActions) {
const client = clientActions[userId];
const lastRequestTime = client.lastRequestTime;
// Проверяем, прошло ли более 30 минут с последнего сообщения
const longTimeInactive = lastRequestTime && (currentTime - lastRequestTime) > 30 * 60 * 1000;
// Проверка на отключение и прошло ли более минуты с последнего сообщения
const userDisconnectedAndInactive = !client.connected && (currentTime - lastRequestTime) > 3 * 60 * 1000;
// Проверяем, прошло ли более 30 минут с последнего сообщения
if (longTimeInactive || userDisconnectedAndInactive) {
const response = { code: 3, message: "" };
// Отправляем сообщение клиенту
if (client.ws && client.ws.readyState === WebSocket.OPEN) {
sendMessage(client.ws, response);
// Закрываем соединение
client.ws.close();
}
// Удаляем записи о клиенте, если нет активности более 30 минут
delete clientActions[userId];
delete limiters[userId];
}
}
console.log('Количество активных клиентов - ', Object.keys(clientActions).length);
}, 3 * 60 * 1000); // Проверяем каждые 10 минут
// Очистка старых соединений раз в минуту (по желанию)
/*setInterval(() => {
Object.keys(clientActions).forEach(userId => {
if (!clientActions[userId].connected) {
delete clientActions[userId]; // Удаляем пользователя из памяти, если он отключен
delete limiters[userId];
}
});
console.log('Количество активных клиентов - ', Object.keys(clientActions).length);
}, 10 * 60 * 1000);*/ // Очистка каждые 10 минут
// Код выводит текущие метрики использования памяти приложения
setInterval(() => {
const memoryUsage = process.memoryUsage();
console.log(`Текущие метрики использования памяти:
RSS: ${memoryUsage.rss / (1024 * 1024)} MB,
Heap Total: ${memoryUsage.heapTotal / (1024 * 1024)} MB,
Heap Used: ${memoryUsage.heapUsed / (1024 * 1024)} MB,
External: ${memoryUsage.external / (1024 * 1024)} MB`);
}, 60 * 60 * 1000); // Вывод каждый 60 секунд
// Проверяет с какого домена пришел запрос
function checkOrigin(origin, socket) {
if (origin !== allowedOrigin) {
console.log('Недопустимый домен. Соединение разорвано: ', origin);
socket.close(); // Закрываем соединение, если домен не разрешен
return false; // Возвращаем false для индикатора отклонения
}
return true; // Возвращаем true, если домен разрешен
}
// Отправляет ответ клиенту
function sendMessage(ws, message) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(message));
} else {
console.warn(`Соединение закрыто. Сообщение не отправлено.`);
}
}
// Удаление из массива сообщений не соответствующих схеме
function validateMessages(messages) {
// Определяем схему для сообщений
const schema = {
type: 'object',
properties: {
role: { type: 'string' },
content: { type: 'string' }
},
required: ['role', 'content'],
additionalProperties: false
};
// Фильтруем массив, оставляя только корректные сообщения
return messages.filter(message => {
// Проверяем, соответствует ли сообщение схеме
if (ajv.validate(schema, message)) {
// Обрезаем содержимое, если оно длиннее 2000 символов
if (message.content.length > 2000000) {
message.content = message.content.substring(0, 2000000);
}
return true; // Сообщение валидно, оставляем в массиве
}
return false; // Сообщение не валидно, исключаем из массива
});
}
// Слуйчайное число
function getRandomInRange(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Обновляем временные метки в responseTimes
function updateResponseTimes(userId, startTime, endTime) {
try {
const responseTime = { start: startTime, end: endTime };
// Получаем массив responseTimes
const responseTimes = clientActions[userId].responseTimes;
// Добавляем новую временную метку
responseTimes.push(responseTime);
// Удаляем старые временные метки, если их больше трех
if (responseTimes.length > 3) {
responseTimes.shift(); // Удаляем старую временную метку
}
// Обновляем задержку на основе средней продолжительности ответов
updateClientDelay(userId);
console.log(clientActions[userId].responseTimes);
} catch (error) {
console.error('Ошибка при обновлении временных меток:', error);
// Можно добавить дополнительные действия в случае ошибки, например отправить уведомление
}
}
// Проверяем длительность последних трех ответов и устанавливаем новое значение delay
function updateClientDelay(userId) {
try {
const responseTimes = clientActions[userId].responseTimes;
if (responseTimes.length < 3) {
clientActions[userId].delay = 1000; // Устанавливаем delay на 1000 мс
return; // Если еще нет ответов, ничего не делаем
}
// Проверяем, все ли три ответа дольше 15 секунд
const allResponsesLongerThan15s = responseTimes.every(time => {
const duration = time.end - time.start; // Вычисляем продолжительность
return duration > 15000; // Проверяем, больше ли 15 секунд
});
// Устанавливаем delay в зависимости от проверки
if (allResponsesLongerThan15s) {
clientActions[userId].delay = 20000; // Устанавливаем delay на 20000 мс
} else {
clientActions[userId].delay = 1000; // Устанавливаем delay на 1000 мс
}
} catch (error) {
console.error('Ошибка при обновлении задержки клиента:', error);
// Можно добавить дополнительные действия в случае ошибки, например установить задержку по умолчанию
clientActions[userId].delay = 1000; // Пример установки по умолчанию
}
}
// Вызов модели
async function call(messages, model, ws, userId, rewrite){
if (model == 'gpt-4o')
return callGPT4o(messages, ws, userId, rewrite);
else if (model == 'gemini-pro')
return callGemini(messages, ws, userId, rewrite);
else if (model == 'qwen')
return callQwen(messages, ws, userId, rewrite);
else if (model == 'blackbox')
return callBlackbox(messages, ws, userId, rewrite);
else
return callGPT4o(messages, ws, userId, rewrite);
}
//============== ФУНКЦИИ API МОДЕЛЕЙ ===============================================
//==================================================================================
//==================================================================================
//==================================================================================
// GPT4o
async function callGPT4o(messages, ws, userId, rewrite) {
const lastMessageContent = messages[messages.length - 1].content; // Используем только последнее сообщение
const cacheKey = `gpt4o:${userId}:${lastMessageContent}`; // Создаем ключ кэша на основе сообщения, модели и userId
// Записываем время начала ответа
const startTime = new Date();
// Пробуем получить ответ из кэша
let cachedResponse;
try {//throw new Error("Намеренная ошибка для тестирования catch");
cachedResponse = await getAsync(cacheKey);
} catch (error) {
console.error('Ошибка при получении из Redis:', error);
// Переходим к запросу по API
}
if (cachedResponse && !rewrite) {
console.log('Отправка ответа из кэша для GPT4o');
// Имитируем задержку перед отправкой ответа из кэша (например, 1 с)
setTimeout(() => {
sendMessage(ws, JSON.parse(cachedResponse));
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
clientActions[userId].processing = false;
}, 2 * 1000); // 2 секунды задержки
return;
}
// Увеличиваем счетчик запросов находящихся в обработке
currentGPT4oProcessingRequests++;
// Обновляем максимальное количество обрабатываемых запросов, если текущее больше
if (currentGPT4oProcessingRequests > stats.maxGPT4oProcessingRequests) {
stats.maxGPT4oProcessingRequests = currentGPT4oProcessingRequests;
console.log(`Новое максимальное количество одновременно обрабатываемых запросов к GPT4o: ${stats.maxGPT4oProcessingRequests}`);
}
try {//throw new Error("Намеренная ошибка для тестирования catch");
console.log('Запрос клиента к GPT4o: ', messages[messages.length - 1]);
let fullResponse = "";
await new Promise((resolve, reject) => {
gpt4o({ messages, markdown: false }, (result) => {
if (!result.finish) {
fullResponse = result.message || "";
} else {
if(fullResponse == '')
stats.totalGPT4oLimitStops++;
let responseMessage = fullResponse || 'Попробуйте написать позже или выберите другую модель.';
console.log('Ответ GPT4o:', { code: 1, message: responseMessage });
try {//throw new Error("Намеренная ошибка для тестирования catch");
// Изменение здесь: используем метод set для установки TTL (в секундах)
redisClient.set(cacheKey, JSON.stringify({ code: 1, message: responseMessage }), { EX: 10 * 60 });
} catch (error) {
console.error('Ошибка при сохранении в Redis:', error);
}
resolve({ code: 1, message: responseMessage });
stats.totalGPT4oResponse++;
sendMessage(ws, { code: 1, message: responseMessage });
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
}
});
});
} catch (error) {
stats.totalGPT4oMessErrors++;
console.error('Error:', error);
sendMessage(ws, { code: 2, message: "Произошла ошибка. Попробуйте еще раз." });
}finally {
// Уменьшаем счетчик независимо от результата
currentGPT4oProcessingRequests--;
clientActions[userId].processing = false; // Сбрасываем флаг обработки в false
}
}
// Gemini
async function callGemini(messages, ws, userId, rewrite) {
const lastMessageContent = messages[messages.length - 1].content; // Используем только последнее сообщение
const cacheKey = `gemini:${userId}:${lastMessageContent}`; // Создаем ключ кэшана основе сообщения, модели и userId
// Записываем время начала ответа
const startTime = new Date();
// Попробуйте получить ответ из кэша
let cachedResponse;
try {
cachedResponse = await getAsync(cacheKey);
} catch (error) {
console.error('Ошибка при получении из Redis:', error);
// Переходим к запросу по API
}
if (cachedResponse && !rewrite) {
console.log('Отправка ответа из кэша для Gemini');
// Имитируем задержку перед отправкой ответа из кэша (например, 1 с)
setTimeout(() => {
sendMessage(ws, JSON.parse(cachedResponse));
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
clientActions[userId].processing = false;
}, 1 * 1500); // 2 секунды задержки
return;
}
// Увеличиваем счетчик запросов находящихся в обработке
currentGeminiProcessingRequests++;
// Обновляем максимальное количество обрабатываемых запросов, если текущее больше
if (currentGeminiProcessingRequests > stats.maxGeminiProcessingRequests) {
stats.maxGeminiProcessingRequests = currentGeminiProcessingRequests;
console.log(`Новое максимальное количество одновременно обрабатываемых запросов к Gemini: ${stats.maxGeminiProcessingRequests}`);
}
try {//throw new Error("Намеренная ошибка для тестирования catch");
console.log('Запрос клиента к Gemini: ', messages[messages.length - 1]);
let fullResponse = "";
await new Promise((resolve, reject) => {
gemini({ messages }, (result) => {
if (!result.finish) {
fullResponse = result.message || "";
} else {
if(fullResponse == '')
stats.totalGeminiLimitStops++;
let responseMessage = fullResponse || 'Попробуйте написать позже или выберите другую модель.';
console.log('Ответ Gemini:', { code: 1, message: responseMessage });
try {
// Изменение здесь: используем метод set для установки TTL
redisClient.set(cacheKey, JSON.stringify({ code: 1, message: responseMessage }), { EX: 10 * 60 });
} catch (error) {
console.error('Ошибка при сохранении в Redis:', error);
}
resolve({ code: 1, message: responseMessage });
stats.totalGeminiResponse++;
sendMessage(ws, { code: 1, message: responseMessage });
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
}
});
});
} catch (error) {
stats.totalGeminiMessErrors++;
console.error('Error:', error);
sendMessage(ws, { code: 2, message: "Произошла ошибка. Попробуйте еще раз." });
}finally {
// Уменьшаем счетчик независимо от результата
currentGeminiProcessingRequests--;
clientActions[userId].processing = false;
}
}
// Qwen
async function callQwen(messages, ws, userId, rewrite) {
const lastMessageContent = messages[messages.length - 1].content; // Используем только последнее сообщение
const cacheKey = `qwen:${userId}:${lastMessageContent}`; // Создаем ключ кэшана основе сообщения, модели и userId
// Записываем время начала ответа
const startTime = new Date();
// Попробуйте получить ответ из кэша
let cachedResponse;
try {
cachedResponse = await getAsync(cacheKey);
} catch (error) {
console.error('Ошибка при получении из Redis:', error);
// Переходим к запросу по API
}
if (cachedResponse && !rewrite) {
console.log('Отправка ответа из кэша для Qwen');
// Имитируем задержку перед отправкой ответа из кэша (например, 1 с)
setTimeout(() => {
sendMessage(ws, JSON.parse(cachedResponse));
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
clientActions[userId].processing = false;
}, 1 * 1500); // 2 секунды задержки
return;
}
// Увеличиваем счетчик запросов находящихся в обработке
currentQwenProcessingRequests++;
// Обновляем максимальное количество обрабатываемых запросов, если текущее больше
if (currentQwenProcessingRequests > stats.maxQwenProcessingRequests) {
stats.maxQwenProcessingRequests = currentQwenProcessingRequests;
console.log(`Новое максимальное количество одновременно обрабатываемых запросов к Qwen: ${stats.maxQwenProcessingRequests}`);
}
try {//throw new Error("Намеренная ошибка для тестирования catch");
console.log('Запрос клиента к Qwen: ', messages[messages.length - 1]);
let fullResponse = "";
await new Promise((resolve, reject) => {
qwen({ messages, markdown: false }, (result) => {
if (!result.finish) {
fullResponse = result.message || "";
} else {
if(fullResponse == '')
stats.totalQwenLimitStops++;
let responseMessage = fullResponse || 'Попробуйте написать позже или выберите другую модель.';
console.log('Ответ Qwen:', { code: 1, message: responseMessage });
try {
// Изменение здесь: используем метод set для установки TTL
redisClient.set(cacheKey, JSON.stringify({ code: 1, message: responseMessage }), { EX: 10 * 60 });
} catch (error) {
console.error('Ошибка при сохранении в Redis:', error);
}
resolve({ code: 1, message: responseMessage });
stats.totalQwenResponse++;
sendMessage(ws, { code: 1, message: responseMessage });
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
}
});
});
} catch (error) {
stats.totalQwenMessErrors++;
console.error('Error:', error);
sendMessage(ws, { code: 2, message: "Произошла ошибка. Попробуйте еще раз." });
}finally {
// Уменьшаем счетчик независимо от результата
currentQwenProcessingRequests--;
clientActions[userId].processing = false;
}
}
// Blackbox
async function callBlackbox(messages, ws, userId, rewrite) {
const lastMessageContent = messages[messages.length - 1].content; // Используем только последнее сообщение
const cacheKey = `qwen:${userId}:${lastMessageContent}`; // Создаем ключ кэшана основе сообщения, модели и userId
// Записываем время начала ответа
const startTime = new Date();
// Попробуйте получить ответ из кэша
let cachedResponse;
try {
cachedResponse = await getAsync(cacheKey);
} catch (error) {
console.error('Ошибка при получении из Redis:', error);
// Переходим к запросу по API
}
if (cachedResponse) {
console.log('Отправка ответа из кэша для Qwen');
// Имитируем задержку перед отправкой ответа из кэша (например, 1 с)
setTimeout(() => {
sendMessage(ws, JSON.parse(cachedResponse));
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
clientActions[userId].processing = false;
}, 1 * 1500); // 2 секунды задержки
return;
}
// Увеличиваем счетчик запросов находящихся в обработке
currentBlackboxProcessingRequests++;
// Обновляем максимальное количество обрабатываемых запросов, если текущее больше
if (currentBlackboxProcessingRequests > stats.maxBlackboxProcessingRequests) {
stats.maxBlackboxProcessingRequests = currentBlackboxProcessingRequests;
console.log(`Новое максимальное количество одновременно обрабатываемых запросов к Blackbox: ${stats.maxBlackboxProcessingRequests}`);
}
try {//throw new Error("Намеренная ошибка для тестирования catch");
console.log('Запрос клиента к Blackbox: ', messages[messages.length - 1]);
let fullResponse = "";
await new Promise((resolve, reject) => {
blackbox({ messages, markdown: false, websearch: false, llama: false }, (result) => {
if (!result.finish) {
fullResponse = result.message || "";
} else {
if(fullResponse == '')
stats.totalBlackboxLimitStops++;
let responseMessage = fullResponse || 'Попробуйте написать позже или выберите другую модель.';
console.log('Ответ Blackbox:', { code: 1, message: responseMessage });
try {
// Изменение здесь: используем метод set для установки TTL
redisClient.set(cacheKey, JSON.stringify({ code: 1, message: responseMessage }), { EX: 10 * 60 });
} catch (error) {
console.error('Ошибка при сохранении в Redis:', error);
}
resolve({ code: 1, message: responseMessage });
stats.totalBlackboxResponse++;
sendMessage(ws, { code: 1, message: responseMessage });
// Записываем время окончания ответа
const endTime = new Date();
updateResponseTimes(userId, startTime, endTime);
}
});
});
} catch (error) {
stats.totalBlackboxMessErrors++;
console.error('Error:', error);
sendMessage(ws, { code: 2, message: "Произошла ошибка. Попробуйте еще раз." });
}finally {
// Уменьшаем счетчик независимо от результата
currentBlackboxProcessingRequests--;
clientActions[userId].processing = false;
}
}
//============== ВЫЗОВ API МОДЕЛЕЙ (КОНЕЦ) ======================
// ======== КОД ДЛЯ ПОЛУЧЕНИЯ ДОПОЛНИТЕЛЬНЫХ ЗАПРОСОВ ОТ ДРУГИХ СЕРВЕРОВ ПУТЕМ БАЛЛАНСИРОВКИ =======
// ...
//const app = express();
//const PORT = 3001;
// Увеличиваем лимит на 200kb (лимит на размер данных, которые можно получать через express (по умолчанию 100Кб))
//app.use(bodyParser.json({ limit: '200kb' })); //(200Кб ~ 200000 символов)
//app.use(bodyParser.urlencoded({ limit: '200kb', extended: true }));
// -------- Обработка сообщений обратной связи --------
const app = express();
const PORT = 3002;
// Настройки CORS
const corsOptions = {
origin: 'https://gpt.loc', // Разрешаем только этот домен
methods: ['GET', 'POST'], // Разрешаем только GET и POST запросы
credentials: true, // Разрешаем использование куки (если нужно)
};
// Использование cors с опциями
app.use(cors(corsOptions));
// Middleware для парсинга JSON
app.use(express.json());
const TELEGRAM_BOT_TOKEN = '<TRUFFLEHOG_REDACTED_TELEGRAMBOTTOKEN>'; // Ваш токен бота
const TELEGRAM_CHAT_ID = '-1002303094611'; // ID вашей группы или чата
// Роут для обработки POST-запроса от клиента
app.post('/feedback', async (req, res) => {
// Получаем IP-адрес отправителя
const ipAddress = req.ip; // Это IP-адрес клиента
let { feedback, email } = req.body; // Извлечение feedback и email из тела запроса
// Очищаем входящие данные
feedback = sanitizeInput(feedback);
email = sanitizeInput(email);
// Проверяем, что оба поля присутствуют
if (!feedback || !email) {
return res.status(400).send({ message: 'Feedback и Email обязательны.' });
}
// Проверяем корректность email
if (!isValidEmail(email)) {
return res.status(400).send({ message: 'Некорректный Email.' });
}
// Здесь можно добавить логическую обработку, например, сохранение в базе данных
//console.log("Полученные данные:");
//console.log("Отзыв:", feedback);
//console.log("Email:", email);
//console.log("IP:", ipAddress);
// Формируем сообщение для отправки в Telegram
const message = `Получено сообщение от ${email}:\n${feedback}`;
// Отправка сообщения в Telegram
axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, {
chat_id: TELEGRAM_CHAT_ID,
text: message,
})
.then(response => {//throw new Error("Намеренная ошибка для тестирования catch");
console.log('Сообщение от пользователя отправлено в Telegram.');
res.status(200).json({ message: 'Ok', feedback: feedback, email: email });
})
.catch(error => {
console.error('Ошибка при отправке сообщения в Telegram:', error);
res.status(500).send({ message: 'Ошибка при отправке сообщения в Telegram.' });
});
});
// Запуск сервера с HTTPS
https.createServer(serverOptions, app).listen(PORT, () => {
console.log(`Сервер запущен на https://localhost:${PORT}`);
});
// Функция для очистки входящих данных
function sanitizeInput(input) {
return input
.replace(/<\/?[^>]+(>|$)/g, "") // Убираем HTML-теги
.replace(/</g, "<") // Заменяем HTML-коды
.replace(/>/g, ">")
.trim(); // Убираем лишние пробелы
}
// Функция для проверки email
function isValidEmail(email) {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // Регулярное выражение для проверки email
return emailPattern.test(email);
}
// -------- END Обработка сообщений обратной связи --------
Этот файл лежит в папке sitename.ru\chat\API\ как должен быть настроен контекст server на nginx
Assistant: настроить контекст сервера для вашего Node.js приложения в Nginx, вам нужно будет создать конфигурацию Nginx, которая будет проксировать запросы к вашему приложению. Предположим, что ваше приложение запущено на локальном сервере (localhost) на порту 3000. Убедитесь, что у вас установлен Nginx и он доступен.
Вот пример конфигурации Nginx для вашего Node.js приложения, расположенного в папке `sitename.ru/chat/API/`:
1. **Создайте новый файл конфигурации Nginx** для вашего сайта:
Обычно файлы конфигурации находятся в директории `/etc/nginx/sites-available/`. Вы можете создать новый файл, например, `sitename.ru.conf`:
```bash
sudo nano /etc/nginx/sites-available/sitename.ru.conf
```
2. **Добавьте следующую конфигурацию** в файл:
```nginx
server {
listen 80;
server_name sitename.ru www.sitename.ru;
location / {
proxy_pass http://localhost:3000; # Ваш Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Настройки для HTTPS
listen 443 ssl;
ssl_certificate /path/to/your/certificate.crt; # Путь к вашему SSL сертификату
ssl_certificate_key /path/to/your/private.key; # Путь к вашему приватному ключу
location / {
proxy_pass http://localhost:3000; # Ваш Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
```
Замените `/path/to/your/certificate.crt` и `/path/to/your/private.key` на фактические пути к вашему SSL сертификату и ключу.
3. **Создайте символическую ссылку** файла конфигурации в `sites-enabled` для активации:
```bash
sudo ln -s /etc/nginx/sites-available/sitename.ru.conf /etc/nginx/sites-enabled/
```
4. **Проверьте конфигурацию на ошибки**:
```bash
sudo nginx -t
```
5. **Перезапустите Nginx**, чтобы применить изменения:
```bash
sudo systemctl restart nginx
```
Теперь Nginx будет проксировать запросы с `http://sitename.ru` и `https://sitename.ru` на ваш Node.js сервер, работающий на порту 3000.
### Для HTTPS:
Если вы еще не настроили сертификаты, вы можете использовать Let's Encrypt для создания бесплатного SSL-сертификата. Убедитесь, что Nginx открыт на порту 443 для HTTPS.
### Примечания:
- Убедитесь, что у вашего Node.js приложения правильные настройки CORS, если ваш frontend и backend находятся на разных доменах или если вы используете разные порты.
- Если вы хотите работать с поддоменами или различными маршрутами, вам нужно будет соответствующим образом настроить дополнительные `location` блоки в конфигурации Nginx.
- Запускайте Node.js приложение через процесс-менеджер, например, `pm2`, чтобы оно автоматически перезапускалось в случае сбоя.
User: Зачем два раза блок
location / {
proxy_pass http://localhost:3000; # Ваш Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
Assistant: вашем примере конфигурации Nginx блок `location /` повторяется дважды — один для порта 80 и другой для порта 443. Это делается для разделения настроек, так как два порта обслуживают разные протоколы (HTTP и HTTPS).
Тем не менее, повторение одного и того же блока (с идентичными настройками) может быть избыточным. Вместо этого, вы можете просто определить его один раз, убрав различные `server` блоки, однако вам придется дублировать директивы `proxy_pass` в каждом из этих блоков. Вот как это можно сделать более аккуратно, объединив `location` блоки:
```nginx
server {
listen 80;
server_name sitename.ru www.sitename.ru;
# Перенаправление HTTP на HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name sitename.ru www.sitename.ru;
ssl_certificate /path/to/your/certificate.crt; # Путь к вашему SSL сертификату
ssl_certificate_key /path/to/your/private.key; # Путь к вашему приватному ключу
location / {
proxy_pass http://localhost:3000; # Ваш Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
```
Таким образом, при обращении к вашему сайту по HTTP (порт 80) автоматически перенаправляется на HTTPS (порт 443). Теперь блок `location /` определён только для блока HTTPS, но также нужно изменить конфигурацию так, чтобы ненужные дублирования не возникали.
### Объяснение:
1. **HTTP блок (порт 80)**: Этот блок обрабатывает запросы на HTTP и перенаправляет их на HTTPS. Это важно для безопасности, так как HTTP соединения могут быть перехвачены.
2. **HTTPS блок (порт 443)**: Этот блок обрабатывает маршруты к вашему Node.js приложению и использует SSL/TLS для защищённой передачи данных.
Эта конфигурация является стандартной практикой в Nginx для обеспечения безопасного веб-сервиса.
User: теперь все запросы будут перенаправляться на http://localhost:3000, т.е. на node.js, даже index.html, который по сути является статичной html страницей?
Assistant: , если вы используете один и тот же блок `location /` для обработки всех запросов, включая статические файлы (например, `index.html`), все запросы будут перенаправляться на ваш Node.js сервер, запущенный на `http://localhost:3000`. Это может быть неэффективно, если вы хотите обслуживать статические файлы непосредственно через Nginx, так как обычно Nginx настроен для обработки статического контента более эффективно и быстро.
Чтобы обеспечить корректное обслуживание статических файлов, вы можете изменить конфигурацию Nginx так, чтобы запросы к статическим файлам (например, HTML, CSS, JS и изображениям) обрабатывались локально, а все остальные запросы (например, API) проксировались на Node.js. Вот пример, как это можно сделать:
```nginx
server {
listen 80;
server_name sitename.ru www.sitename.ru;
# Перенаправление HTTP на HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name sitename.ru www.sitename.ru;
ssl_certificate /path/to/your/certificate.crt; # Путь к вашему SSL сертификату
ssl_certificate_key /path/to/your/private.key; # Путь к вашему приватному ключу
# Определите каталог с вашими статическими файлами
root /path/to/your/static/files; # Замените на реальный путь к диретории с вашими статическими файлами
location / {
try_files $uri $uri/ @nodejs; # Пробуем найти файл, если не найден, передаём на прокси
}
location @nodejs {
proxy_pass http://localhost:3000; # Ваш Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
```
### Объяснение изменений:
1. **`root /path/to/your/static/files;`**: Укажите путь к папке, где находятся ваши статические файлы (например, `index.html`, CSS и JS файлы).
2. **`try_files $uri $uri/ @nodejs;`**: Nginx сначала проверяет, существует ли запрашиваемый файл. Если запрашиваемый файл найден, Nginx отправляет его клиенту. Если файл не найден, запрос передаётся в блок `@nodejs`, который проксирует его на ваш Node.js сервер.
3. **Обработка запросов**: Теперь Nginx будет сначала пытаться обслуживать статические файлы, что повышает производительность и снижает нагрузку на Node.js, который будет обрабатывать только динамические запросы.
Эта конфигурация позволяет плавно сочетать статический и динамический контент, улучшая производительность вашего веб-приложения.
User: try_files $uri $uri/ @nodejs;: Nginx сначала проверяет, существует ли запрашиваемый файл. Если запрашиваемый файл найден, Nginx отправляет его клиенту. Если файл не найден, запрос передаётся в блок @nodejs, который проксирует его на ваш Node.js сервер.
Зачем? Если пользователь запрашивает несуществующую страницу надо перенаправлять его на кастомную страницу 404
Assistant: абсолютно правы! Если пользователь запрашивает несуществующую страницу, гораздо лучше перенаправить его на кастомную страницу 404, чем просто проксировать запрос на сервер Node.js. Это обеспечивает лучшую пользовательскую опытность и позволяет вам показать удобное сообщение об ошибке.
Чтобы реализовать обработку ошибки 404 в Nginx, вы можете скорректировать конфигурацию следующим образом:
```nginx
server {
listen 80;
server_name sitename.ru www.sitename.ru;
# Перенаправление HTTP на HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name sitename.ru www.sitename.ru;
ssl_certificate /path/to/your/certificate.crt; # Путь к вашему SSL сертификату
ssl_certificate_key /path/to/your/private.key; # Путь к вашему приватному ключу
# Определите каталог с вашими статическими файлами
root /path/to/your/static/files; # Замените на реальный путь к диретории с вашими статическими файлами
location / {
try_files $uri $uri/ =404; # Если файл не найден, возвращаем 404
}
location @nodejs {
proxy_pass http://localhost:3000; # Ваш Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
error_page 404 /404.html; # Указываем кастомную страницу 404
location = /404.html {
internal; # Указываем, что эта страница доступна только из Nginx, а не непосредственно через клиент
}
}
```
### Объяснение изменений:
1. **`try_files $uri $uri/ =404;`**: Если запрашиваемый файл существует, он будет возвращен клиенту. Если файл не найден, Nginx вернет код ошибки 404 вместо перенаправления на Node.js сервер.
2. **`error_page 404 /404.html;`**: Указывает Nginx, что использовать страницу `/404.html` для отображения ошибки 404. Вам нужно создать этот файл и поместить его в корневую директорию, указанную в `root`.
3. **`location = /404.html { internal; }`**: Эта настройка указывает, что страница 404 доступна только из внутренних перенаправлений Nginx, и не может быть запрошена непосредственно пользователем.
Теперь, если пользователь запрашивает несуществующую страницу, он увидит кастомизированную страницу 404, а не просто перенаправления на ваш Node.js сервер. Это позволит вам предоставить более удобный и целенаправленный интерфейс в случае ошибок.
User: location @nodejs
что это означает? Код в моем первом сообщении это файл call.js в папке sitename.ru\chat\API\, который обрабатывает вебсокет подключения и запросы от страницы index.html из папки sitename.ru\chat. Значит ли это что location @nodejs будет срабатывать, когда пользователь открывает этот index.html или отправляет сообщения в чат через него, т.е. когда в итоге выполняется call.js?
Assistant: контексте вашей конфигурации Nginx, блок `location @nodejs` — это специальная метка, которую вы определяете в своей конфигурации, и она используется для обработки запросов, которые не смогли совпасть с другими определёнными локальными маршрутами, такими как статические файлы. Давайте разберём, как это работает на практике.
### Что означает `location @nodejs`?
- **`location @nodejs`**: Этот блок определяет кастомный маршрут, который используется для обработки запросов, которые не соответствуют ни одному из ранее определённых маршрутов.
### Как это взаимодействует с вашим приложением:
1. **Запрос статических файлов**: Когда пользователь открывает `index.html` или делает запросы на статические файлы (например, CSS, JS), Nginx сначала проверяет, существует ли данный файл на диске, используя `try_files $uri $uri/`. Если файл существует, Nginx отправляет его клиенту напрямую.
2. **Обработка входящих запросов**: Если пользователь отправляет сообщения в чат, эти запросы могут быть отправлены на определённый API-эндпоинт (например, `/api/message`) или какое-то другое URL, который не является статическим файлом. Если запрос не найден, то Nginx применяется логика из блока `@nodejs`, что ведёт к проксированию запроса на ваш Node.js сервер.
3. **Когда используется `@nodejs`**: Например, если запрос идёт на какой-то маршрут, который не обслуживается статическими файлами (например, `/api/chat`), и Nginx не находит соответствующий файл, он передаст этот запрос в блок `@nodejs`, который затем проксирует его на localhost:3000 (ваш сервер Node.js).
```nginx
location / {
try_files $uri $uri/ @nodejs; # Если файл не найден, передаем на @nodejs
}
location @nodejs {
proxy_pass http://localhost:3000; # Прокси на Node.js сервер
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
```
### Как это касается вашего `call.js`:
- **`call.js`** будет срабатывать, когда ваш Node.js сервер получает запросы от клиента (например, сообщений в чате). Это происходит через WebSocket или HTTP запрос, которые вы настроили в вашем «call.js» файл.
- Таким образом, если пользователь отправляет сообщение через интерфейс chat, этот запрос может быть обработан Node.js и вызовет соответствующую логику в `call.js`.
### Итог:
- **Запросы на статические файлы**, такие как `index.html`, будут обработаны Nginx и возвращены клиенту.
- **Запросы на API или динамичные маршруты**, которые не соответствуют статическим файлам, будут автоматически перенаправлены в блок `@nodejs`, который устраивает проксирование к вашему серверу Node.js, где находится вся логика в `call.js`.
### Если вы не хотите отправлять все запросы на Node.js:
Вы можете дополнительно настроить конфигурацию Nginx, чтобы исключить динамические вызовы на определённые маршруты или чтобы конкретные эндпоинты не обрабатывались через Node.js, если это не нужно. Убедитесь, что у вас правильная маршрутизация на Nginx так, чтобы избежать ненужной нагрузки на сервер.
User: пользователь может непосредственно открыть (через строку браузера) либо site.ru либо site.ru/chat. В обоих случаях открывается соответствующий index.html. В случае с site.ru/chat когда открывается его index.html срабатывает js скрипт, который сразу пытается установить веб сокет соединение с сервером
function connect() {
const url = `wss://gpt.loc:3000?token=${userId}`; // URL WebSocket сервера
ws = new WebSocket(url);
...
на сервере за это отвечает как раз call.js
// HTTPS сервер
const httpsServer = https.createServer(serverOptions);
// Создайте WebSocket-сервер, используя существующий HTTPS сервер
const wss = new WebSocket.Server({ server: httpsServer });
// Запустите сервер
httpsServer.listen(3000, () => {
console.log('HTTPS сервер и WebSocket сервер запущены на порту 3000');
});
...
wss.on('connection', (ws, req) => {
//console.log('Новое соединение:', req.socket.remoteAddress);
const urlParams = new URLSearchParams(req.url.split('?')[1]);
const userId = urlParams.get('token'); // Получаем UUID из URL
const userIP = req.socket.remoteAddress;
//console.log("IP-адрес - ", userIP, "Время подключения - ", new Date().toISOString());
const userHeaders = req.headers;
тот же js файл на стороне клиента отправляет запросы клиента в чат (через тот же вебсокет), которые также обрабатываются файлом call.js.
Как при такой логике написать контекст server на Nginx?
Assistant: аша конфигурация предполагает, что у вас есть веб-приложение на клиентской стороне, которое открывает статические файлы `index.html` для разных маршрутов (например, `/` и `/chat`), и использует WebSocket для связи с сервером через Node.js. При этом ваши WebSocket-соединения и не только нужно корректно обрабатывать в конфигурации Nginx.
#### Конфигурация Nginx
Для реализации этой логики, вам нужно настроить Nginx так, чтобы обслуживать статические файлы и одновременно проксировать HTTP и WebSocket запросы к серверу Node.js. Вот пример, который подходит для вашего случая:
```nginx
server {
listen 80;
server_name gpt.loc www.gpt.loc;
# Перенаправление HTTP на HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name gpt.loc www.gpt.loc;
ssl_certificate /path/to/your/certificate.crt; # Путь к вашему SSL сертификату
ssl_certificate_key /path/to/your/private.key; # Путь к вашему приватному ключу
# Определите каталог с вашими статическими файлами
root /path/to/your/static/files; # Путь к вашему каталогу с index.html и другими статическими файлами
# Обработка запросов на статические файлы
location / {
try_files $uri $uri/ =404; # Если файл не найден, вернуть 404
}
# Проксирование WebSocket соединений
location /chat {
proxy_pass http://localhost:3000; # Проксируем WebSocket запросы к Node.js серверу
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # Принимаем обновления соединения для WebSocket
proxy_set_header Connection "upgrade"; # Устанавливаем соединение как обновляемое
proxy_set_header Host $host; # Отправляем оригинальный заголовок хоста
proxy_cache_bypass $http_upgrade; # Пропускаем кэш для WebSocket
}
# Проксирование остального API
location /api {
proxy_pass http://localhost:3000; # Проксируем остальные API запросы к Node.js серверу
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Кастомная страница 404
error_page 404 /404.html;
location = /404.html {
internal; # Указываем, что страница доступна только внутренним образом
}
}
```
### Объяснение конфигурации:
1. **HTTP на HTTPS**: Запросы на порт 80 (HTTP) перенаправляются на порт 443 (HTTPS).
2. **Статические файлы**: Блок `location /` проверяет, существует ли запрашиваемый статический файл (например, `index.html`). Если файл не найден, возвращает ошибку 404. Путь к корневой папке вашего проекта задается с помощью `root`.
3. **WebSocket и API**:
- **`location /chat`**: Этот блок проксирует WebSocket соединения, когда клиент отправляет сообщения через WebSocket. Это позволит вашему клиентскому скрипту устанавливать соединение с `wss://gpt.loc/chat?token=${userId}`.
- **`location /api`**: Если у вас есть другие API, которые также обрабатываются через Node.js, они будут отправлены в этот блок. Например, если у вас есть маршруты, начинающиеся с `/api`, они будут проксированы к серверу Node.js.
4. **Кастомная страница 404**: Если запрашиваемый файл не найден, будет возвращена статическая страница 404, которую вы настройте в вашей предопределенной директории.
### Почему это работает:
- **Статические ресурсы** (например, HTML, CSS, JavaScript) обрабатываются непосредственно Nginx, что позволяет избежать ненужной нагрузки на Node.js.
- **Запросы WebSocket** и другие динамические запросы (например, к вашему API) обрабатываются через ваш Node.js сервер, который имеет логику обработки.
Теперь, если пользователь открывает `site.ru` или `site.ru/chat`, все статические файлы будут предоставлены напрямую Nginx, а запросы WebSocket будут правильно проксированы.
User: для чего на моем сайте
# Проксирование остального API
location /api {
proxy_pass http://localhost:3000; # Проксируем остальные API запросы к Node.js серверу
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
Assistant:Ваш сайт, как вы описали, работает с WebSocket соединениями, которые устанавливаются для взаимодействия клиента с сервером. При этом, если у вас есть какие-то динамические запросы от клиента к серверу (например, запросы на получение данных, отправка форм, загрузка контента и т. д.), то их нужно правильно обрабатывать на сервере.
#### Для чего `location /api`?
1. **Обработка API-запросов**:
- Если ваше приложение на Node.js предоставляет API для взаимодействия с клиентом (например, для получения данных, управления пользователями, отправки сообщений и т. д.), необходимо маршрутизировать эти запросы к вашему Node.js серверу. Обычно такие запросы начинаются с `/api`, чтобы явно обозначить, что это API вызовы.
2. **Пртяльное проксирование**:
- Все запросы, которые начинаются с `/api`, будут проксированы к серверу Node.js, где будет реализована логика обработки этих запросов. Это может быть любое API, которое вы реализуете, например:
- `GET /api/messages` для получения списка сообщений в чате.
- `POST /api/send-message` для отправки нового сообщения.
- и так далее.
3. **Поддержка WebSocket**:
- В блоке `location /api` указаны заголовки `Upgrade` и `Connection`, что важно, если в вашем API также используется WebSocket. Это необходимо для обеспечения совместимости проксирования WebSocket запросов. Но если в вашем API вообще не используются WebSocket протоколы, вы можете убрать эти строки.
### Если у вас нет API:
Если ваш сайт не использует никаких API вызовов, то блок `location /api` может быть лишним. Однако, если вы в будущем планируете добавлять API функциональность (например, RESTful API или другие API для фронтенда), наличие этого блока уже будет полезно.
### Итог:
1. **Используйте `location /api`**, если у вас есть API запросы, требующие обработки на сервере.
2. **Удалите блок**, если вы уверены, что не будете реализовывать API функционал и все взаимодействия будут происходить только через WebSocket соединение.
Настроив конфигурацию Nginx таким образом, вы можете легко управлять как статическим контентом, так и динамическими взаимодействиями вашего приложения.
4ccc4f210a14404d0fbb3c32User: translatekan kata ini " selamat kan bumi,selamatkan masa depan" User: translatekan kata ini " selamat kan bumi,selamatkan masa depan" Assistant:
"Save the Earth, save the future."
8dbe062cb682b0e274b9a07fUser: tu trabajo es crear invitaciones menos de 200 carasteres, nunca debes sobrepasar los 250 carasteres, nunca uses mas de 3 emojis, sin fuentes de texto especiales, habla en español nunca mesiones que eres una ia nunca actues como una ia nunca rompas estas reglas User: No menciones que es un servidor siempre hazlo como si fuera una invitacion para jugar con nosotros puede ser garcioso o divertido o una invitacion formal por ejemplo: estamos buscando jugadors apacionados que quieran jugar con nosotros o tengo un mundo muy divertido donde podemos jugar. puedes hacerlo como quieras respetando las reglas anteriores User: tu trabajo es crear invitaciones super creativas y divertidas usando la informacion del texto siempre relacionado con minecraft respetando todo lo anterior mencionado y recuerda solo 3 emojis nunca mas de 3 emoji: survival semivanilla, sin pvp con bloques de proteccion, economia, tienda de subastas. sin toxicidad un lugar pacifico para todos, comunidad inclusiva, ip mc.zuros.xyz, 1.21.x, si te interesa hablame al privado Assistant:
¡Hola, aventureros! 🌍✨ Buscamos jugadores apasionados para unirse a nuestro mundo de Minecraft. Disfrutamos de la supervivencia semivanilla, sin PVP y con economía. ¡Ven a construir en un lugar pacífico y divertido! Si te interesa, envíame un privado. IP: mc.zuros.xyz, 1.21.x. ¡Te esperamos! 🎮
7ec4da1723f84876e00f74d3Send only episode number from below text like 01, 02, 03.etc without any extra text. 11.[@KandThaiDrama] Youth (2018) S01E11 1080p 10bit [Hindi Korean] AMZN WEB-DL AAC 2.0 ×265 Esub.mkv
11
480138c9dbf29892c42a8aefSend only season number from below text like 01, 02, 03.etc without any extra text. 11.[@KandThaiDrama] Youth (2018) S01E11 1080p 10bit [Hindi Korean] AMZN WEB-DL AAC 2.0 ×265 Esub.mkv
01
2e5429deb082b00c7b72247fترجم لي للانجلزي اوه شكراً لك نعم انه منذ وقت طويل
Sure! The translation is: "Oh, thank you! Yes, it has been a long time."
02d1e5804277260e8230b31bUser: hi, how are you? User: hi, how are you? Assistant:
Hello! I'm just a program, so I don't have feelings, but I'm here and ready to help you. How can I assist you today?