First upload version 0.0.1

This commit is contained in:
Neyra
2026-02-05 15:27:49 +08:00
commit 8e9b7201ed
4182 changed files with 593136 additions and 0 deletions

7
server/.env Normal file
View File

@@ -0,0 +1,7 @@
PORT=3000
# Используем прямые слеши или двойные обратные
MODEL_PATH=./model/Vikhr-Qwen-2.5-0.5b-Instruct-Q3_K_M.gguf
# Размер контекстного окна
CONTEXT_SIZE=2048
# Температура модели
TEMPERATURE=0.7

176
server/server.js Normal file
View File

@@ -0,0 +1,176 @@
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import path from 'path';
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();
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("⚠️ Модель НЕ загружена. Ожидание команды из интерфейса...");
} catch (err) {
console.error("❌ Критическая ошибка инициализации движка:", err.message);
process.exit(1);
}
}
initServer();
// --- API Управления Моделью ---
// 1. Загрузка модели
app.post('/api/model/load', async (req, res) => {
const { path: inputPath } = req.body;
if (!inputPath) {
return res.status(400).json({ success: false, message: 'Путь к модели не указан' });
}
if (model) {
return res.status(400).json({ success: false, message: 'Модель уже загружена.' });
}
// Логика путей:
// Если путь относительный (начинается с ./ или имени файла), склеиваем с КОРНЕМ ПРОЕКТА.
// Если абсолютный — оставляем как есть.
let absolutePath;
if (path.isAbsolute(inputPath)) {
absolutePath = inputPath;
} else {
absolutePath = path.join(PROJECT_ROOT, inputPath);
}
try {
console.log(`🔄 [ЗАГРУЗКА] Попытка загрузки модели из: ${absolutePath}`);
model = await llama.loadModel({ modelPath: absolutePath });
context = await model.createContext({
contextSize: 2048
});
console.log("✅ [УСПЕХ] Модель успешно загружена.");
res.json({ success: true, message: `Модель загружена` });
} catch (err) {
console.error(`❌ [ОШИБКА] Не удалось загрузить модель: ${err.message}`);
model = null;
context = null;
res.status(500).json({ success: false, message: err.message });
}
});
// 2. Выгрузка модели
app.post('/api/model/unload', async (req, res) => {
if (!model) {
return res.status(400).json({ success: false, message: 'Нет активной модели.' });
}
try {
console.log("🔄 [ВЫГРУЗКА] Освобождение ресурсов модели...");
if (context) context.dispose();
if (model) model.dispose();
model = null;
context = null;
console.log("✅ [УСПЕХ] Модель выгружена.");
res.json({ success: true, message: "Модель выгружена." });
} catch (err) {
res.status(500).json({ success: false, message: err.message });
}
});
// 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');
try {
await fs.promises.access(modelDir);
const files = await fs.promises.readdir(modelDir);
const ggufModels = files.filter(file => file.endsWith('.gguf')).sort();
res.json(ggufModels);
} catch (err) {
console.log("⚠️ Папка 'model' не найдена в корне проекта.");
res.json([]);
}
});
// --- API Чата ---
app.post('/api/chat', async (req, res) => {
if (!model || !context) {
return res.status(503).send("Модель не загружена.");
}
const { message } = 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, {
onToken: (token) => {
try {
const chunk = model.detokenize(token);
res.write(chunk);
} catch (decodeErr) {
console.error("Ошибка декодирования:", decodeErr);
}
},
temperature: 0.7,
maxTokens: 2000,
});
res.end();
} catch (err) {
console.error("Ошибка генерации:", err.message);
res.write("\n\n[Ошибка генерации]");
res.end();
} finally {
if (sequence) sequence.dispose();
}
});
app.listen(PORT, () => {
console.log(`✅ [СЕРВЕР] Веб-сервер запущен на порту: ${PORT}`);
});