добавлние блоков чата слева и правка багов с ним связанных.

This commit is contained in:
Neyra
2026-02-10 20:47:33 +08:00
parent a1bba1d3d1
commit a60cc2f457
11 changed files with 833 additions and 425 deletions

View File

@@ -6,15 +6,12 @@ import fs from 'fs';
import { fileURLToPath } from 'url';
import { getLlama, LlamaChatSession } from 'node-llama-cpp';
// Определяем пути
// __dirname теперь указывает на папку server
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Поднимаемся на уровень выше, чтобы попасть в корень проекта
const PROJECT_ROOT = path.join(__dirname, '..');
// Настраиваем dotenv явно, чтобы он нашел файл .env в корне
dotenv.config({ path: path.join(PROJECT_ROOT, '.env') });
const app = express();
@@ -22,22 +19,19 @@ const PORT = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
// Статику (HTML, CSS, JS) теперь берем из папки public в корне
app.use(express.static(path.join(PROJECT_ROOT, 'public')));
let llama = null;
let model = null;
let context = null;
// --- Инициализация Сервера ---
console.log("🌐 Запуск веб-сервера...");
async function initServer() {
try {
llama = await getLlama();
console.log("✅ Движок Llama инициализирован (папка server/).");
console.log("⚠️ Модель НЕ загружена. Ожидание команды из интерфейса...");
console.log("✅ Движок Llama инициализирован.");
console.log("⚠️ Модель НЕ загружена.");
} catch (err) {
console.error("❌ Критическая ошибка инициализации движка:", err.message);
process.exit(1);
@@ -46,9 +40,50 @@ async function initServer() {
initServer();
// --- API Истории Чатов ---
// 1. Загрузка истории чата
app.get('/api/chat/load', async (req, res) => {
const { id } = req.query;
if (!id) return res.status(400).json({ error: 'ID чата не указан' });
const filePath = path.join(PROJECT_ROOT, 'userdata', `${id}.json`);
try {
// Читаем файл
const data = await fs.promises.readFile(filePath, 'utf8');
res.json(JSON.parse(data));
} catch (err) {
// Если файла нет (новый чат) - возвращаем пустой массив
res.json([]);
}
});
// 2. Сохранение истории чата
app.post('/api/chat/save', async (req, res) => {
const { id, history } = req.body;
if (!id || !history) return res.status(400).json({ error: 'Нет ID или истории' });
const userDataDir = path.join(PROJECT_ROOT, 'userdata');
// Если папки нет, создаем
if (!fs.existsSync(userDataDir)) {
await fs.promises.mkdir(userDataDir);
}
const filePath = path.join(userDataDir, `${id}.json`);
try {
await fs.promises.writeFile(filePath, JSON.stringify(history, null, 2));
res.json({ success: true });
} catch (err) {
console.error("Ошибка сохранения чата:", err);
res.status(500).json({ error: 'Не удалось сохранить файл' });
}
});
// --- API Управления Моделью ---
// 1. Загрузка модели
app.post('/api/model/load', async (req, res) => {
const { path: inputPath } = req.body;
@@ -60,9 +95,6 @@ app.post('/api/model/load', async (req, res) => {
return res.status(400).json({ success: false, message: 'Модель уже загружена.' });
}
// Логика путей:
// Если путь относительный (начинается с ./ или имени файла), склеиваем с КОРНЕМ ПРОЕКТА.
// Если абсолютный — оставляем как есть.
let absolutePath;
if (path.isAbsolute(inputPath)) {
absolutePath = inputPath;
@@ -89,7 +121,6 @@ app.post('/api/model/load', async (req, res) => {
}
});
// 2. Выгрузка модели
app.post('/api/model/unload', async (req, res) => {
if (!model) {
return res.status(400).json({ success: false, message: 'Нет активной модели.' });
@@ -108,15 +139,12 @@ app.post('/api/model/unload', async (req, res) => {
}
});
// 3. Остановка сервера
app.post('/api/server/stop', (req, res) => {
console.log("🛑 [СЕРВЕР] Остановка...");
res.json({ success: true, message: "Остановка..." });
setTimeout(() => process.exit(0), 500);
});
// --- API Автодополнения ---
// Считывает папку model из КОРНЯ ПРОЕКТА
app.get('/api/models/list', async (req, res) => {
const modelDir = path.join(PROJECT_ROOT, 'model');
@@ -126,29 +154,39 @@ app.get('/api/models/list', async (req, res) => {
const ggufModels = files.filter(file => file.endsWith('.gguf')).sort();
res.json(ggufModels);
} catch (err) {
console.log("⚠️ Папка 'model' не найдена в корне проекта.");
console.log("⚠️ Папка 'model' не найдена.");
res.json([]);
}
});
// --- API Чата ---
// --- API Чата (С историей) ---
app.post('/api/chat', async (req, res) => {
if (!model || !context) {
return res.status(503).send("Модель не загружена.");
}
const { message } = req.body;
const { message, history } = req.body;
if (!message) return res.status(400).json({ error: 'Message is required' });
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.setHeader('Transfer-Encoding', 'chunked');
let sequence;
try {
sequence = context.getSequence();
const session = new LlamaChatSession({ contextSequence: sequence });
await session.prompt(message, {
// Формируем промпт из истории + новое сообщение
let fullPrompt = "";
if (Array.isArray(history)) {
history.forEach(msg => {
fullPrompt += `${msg.role === 'user' ? 'User' : 'Bot'}: ${msg.content}\n`;
});
}
fullPrompt += `User: ${message}\nBot:`;
await session.prompt(fullPrompt, {
onToken: (token) => {
try {
const chunk = model.detokenize(token);
@@ -171,6 +209,33 @@ app.post('/api/chat', async (req, res) => {
}
});
// --- API Переименования Чата ---
app.post('/api/chat/rename', async (req, res) => {
const { oldId, newName } = req.body;
if (!oldId || !newName) {
return res.status(400).json({ error: 'Не указан старый ID или новое имя' });
}
// Защита от некорректных имен файлов
// Убираем символы, запрещенные в Windows: \ / : * ? " < > |
const cleanName = newName.replace(/[\\/:*?"<>|]/g, '');
if (cleanName === '') {
return res.status(400).json({ error: 'Имя не может быть пустым' });
}
const oldPath = path.join(PROJECT_ROOT, 'userdata', `${oldId}.json`);
const newPath = path.join(PROJECT_ROOT, 'userdata', `${cleanName}.json`);
try {
// Переименовываем файл
await fs.promises.rename(oldPath, newPath);
res.json({ success: true, newId: cleanName });
} catch (err) {
console.error("Ошибка переименования:", err);
res.status(500).json({ error: err.message });
}
});
app.listen(PORT, () => {
console.log(`✅ [СЕРВЕР] Веб-сервер запущен на порту: www.localhost:${PORT}`);
console.log(`✅ [СЕРВЕР] Веб-сервер запущен на порту: ${PORT}`);
});