Email / backup /server.js
lenzcom's picture
Upload folder using huggingface_hub
2396865 verified
console.log("--> SERVER STARTING...");
import express from 'express';
// --- DYNAMIC IMPORT ---
let SystemMessage, HumanMessage, AIMessage, LlamaCppLLM;
try {
const module = await import('./src/index.js');
SystemMessage = module.SystemMessage;
HumanMessage = module.HumanMessage;
AIMessage = module.AIMessage;
LlamaCppLLM = module.LlamaCppLLM;
console.log("--> Modules loaded successfully");
} catch (e) {
console.error("--> FATAL IMPORT ERROR:", e);
}
import bodyParser from 'body-parser';
import fs from 'fs';
import path from 'path';
// --- CONFIGURATION ---
const PORT = 7860;
const MODEL_PATH = './models/Qwen3-1.7B-Q8_0.gguf';
const MODEL_NAME = "dahanhstd-1.0"; // Tên model tùy chỉnh
// --- LOAD PROMPTS ---
const PROMPTS = {
"default": "You are a helpful AI assistant. Answer concisely.",
"talk2people": fs.existsSync('MssterPrompt_Talk2People.txt')
? fs.readFileSync('MssterPrompt_Talk2People.txt', 'utf-8')
: "You are a creative Video Director specializing in realistic Vietnamese scenes.",
"coder": "You are an expert programmer."
};
// --- HTML TEMPLATE (GIAO DIỆN CHAT) ---
const HTML_PAGE = `
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dạ Hành AI Studio</title>
<style>
:root { --primary:#00ff88; --bg:#121212; --chat-bg:#1e1e1e; --user-bg:#2a2a2a; --ai-bg:#0a3a2a; }
body { font-family:'Segoe UI',sans-serif; background:var(--bg); color:white; margin:0; display:flex; height:100vh; overflow:hidden; }
.sidebar { width:260px; background:#000; padding:20px; border-right:1px solid #333; display:flex; flex-direction:column; }
.main { flex:1; display:flex; flex-direction:column; padding:20px; position:relative; }
h1 { font-size:1.2rem; color:var(--primary); margin-bottom:20px; text-transform:uppercase; letter-spacing:1px; }
select { width:100%; padding:12px; background:#333; color:white; border:1px solid #555; border-radius:8px; margin-bottom:20px; outline:none; }
#chat-box { flex:1; overflow-y:auto; background:var(--chat-bg); border-radius:12px; padding:20px; margin-bottom:20px; display:flex; flex-direction:column; gap:15px; scroll-behavior:smooth; }
.message { max-width:80%; padding:12px 18px; border-radius:18px; line-height:1.5; font-size:0.95rem; animation:fadeIn 0.3s ease; }
.message.ai { align-self:flex-start; background:var(--ai-bg); border-bottom-left-radius:4px; }
.message.user { align-self:flex-end; background:var(--user-bg); border-bottom-right-radius:4px; color:#ddd; }
.input-area { display:flex; gap:10px; }
input { flex:1; padding:15px 20px; border-radius:30px; border:1px solid #444; background:#222; color:white; outline:none; font-size:1rem; }
input:focus { border-color:var(--primary); }
button { padding:10px 30px; border-radius:30px; border:none; background:var(--primary); color:black; font-weight:bold; cursor:pointer; transition:0.2s; }
button:hover { transform:scale(1.05); box-shadow:0 0 10px var(--primary); }
.status { margin-top:auto; font-size:0.8rem; color:#666; border-top:1px solid #333; padding-top:15px; }
@keyframes fadeIn { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:translateY(0); } }
/* Scrollbar */
::-webkit-scrollbar { width:8px; }
::-webkit-scrollbar-track { background:#1e1e1e; }
::-webkit-scrollbar-thumb { background:#444; border-radius:4px; }
</style>
</head>
<body>
<div class="sidebar">
<h1>DẠ HÀNH STUDIO</h1>
<label style="font-size:0.9rem; color:#aaa; margin-bottom:5px">Chọn Role:</label>
<select id="role-select">
<option value="talk2people">🎬 Đạo diễn (Talk2People)</option>
<option value="coder">💻 Coder Expert</option>
<option value="default">🤖 Trợ lý ảo</option>
</select>
<div class="status">
Model: <b>${MODEL_NAME}</b><br>
Privacy: <b>Local Safe</b><br>
Status: <span id="status-text" style="color:yellow">Connecting...</span>
</div>
</div>
<div class="main">
<div id="chat-box"></div>
<div class="input-area">
<input type="text" id="user-input" placeholder="Nhập tin nhắn..." autocomplete="off">
<button onclick="sendMessage()">GỬI</button>
</div>
</div>
<script>
const chatBox = document.getElementById('chat-box');
const userInput = document.getElementById('user-input');
const roleSelect = document.getElementById('role-select');
const statusText = document.getElementById('status-text');
let chatHistory = [];
function addMessage(role, text) {
const div = document.createElement('div');
div.className = 'message ' + role;
div.innerText = text;
chatBox.appendChild(div);
chatBox.scrollTop = chatBox.scrollHeight;
}
async function checkHealth() {
try {
const res = await fetch('/info');
const data = await res.json();
statusText.innerText = "Online";
statusText.style.color = "#00ff88";
addMessage('ai', "Xin chào đây là hệ thống bot AI hoạt động riêng tư được đào tạo bởi Dạ Hành Studio, Không phụ thuộc vào Google");
} catch (e) {
statusText.innerText = "Offline";
statusText.style.color = "red";
}
}
async function sendMessage() {
const text = userInput.value.trim();
if (!text) return;
addMessage('user', text);
userInput.value = '';
chatHistory.push({ role: 'user', content: text });
// Loading effect
const loadingId = 'loading-' + Date.now();
const loadingDiv = document.createElement('div');
loadingDiv.className = 'message ai';
loadingDiv.id = loadingId;
loadingDiv.innerText = '...';
chatBox.appendChild(loadingDiv);
chatBox.scrollTop = chatBox.scrollHeight;
try {
const response = await fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: text,
history: chatHistory.slice(-10),
role: roleSelect.value
})
});
const data = await response.json();
document.getElementById(loadingId).remove();
if(data.error) {
addMessage('ai', 'Lỗi: ' + data.error);
} else {
addMessage('ai', data.reply);
chatHistory.push({ role: 'ai', content: data.reply });
}
} catch (error) {
document.getElementById(loadingId).remove();
addMessage('ai', 'Lỗi kết nối: ' + error.message);
}
}
userInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') sendMessage(); });
roleSelect.addEventListener('change', () => {
chatHistory = [];
chatBox.innerHTML = '';
addMessage('ai', "Đã chuyển sang chế độ: " + roleSelect.options[roleSelect.selectedIndex].text);
});
checkHealth();
</script>
</body>
</html>
`;
// --- AI ENGINE ---
let llm = null;
async function initModel() {
if (!LlamaCppLLM) return;
try {
console.log('--> Loading model...');
if (!fs.existsSync(MODEL_PATH)) {
console.error(`--> Model not found at ${MODEL_PATH}`);
// Fallback: check if we are in /app
return;
}
llm = new LlamaCppLLM({
modelPath: MODEL_PATH,
temperature: 0.7,
maxTokens: 1024
});
await llm.invoke("Hello");
console.log('--> Model loaded successfully.');
} catch (err) {
console.error('--> FATAL MODEL ERROR:', err.message);
}
}
// --- SERVER SETUP ---
const app = express();
app.use(bodyParser.json());
// 1. API: CHAT (Public API for other apps)
app.post('/chat', async (req, res) => {
// API Response Format
const apiResponse = {
model: MODEL_NAME,
created: Date.now(),
reply: "",
error: null
};
if (!llm) {
apiResponse.error = "System initializing or Model missing";
return res.status(503).json(apiResponse);
}
try {
const { message, history = [], role = 'default' } = req.body;
const systemInstruction = PROMPTS[role] || PROMPTS['default'];
const messages = [new SystemMessage(systemInstruction)];
history.forEach(msg => {
if (msg.role === 'user') messages.push(new HumanMessage(msg.content));
if (msg.role === 'ai') messages.push(new AIMessage(msg.content));
});
messages.push(new HumanMessage(message));
const response = await llm.invoke(messages);
apiResponse.reply = response.content;
res.json(apiResponse);
} catch (error) {
apiResponse.error = error.message;
res.status(500).json(apiResponse);
}
});
// 2. API: INFO
app.get('/info', (req, res) => {
res.json({
model: MODEL_NAME,
status: llm ? "ready" : "loading",
roles: Object.keys(PROMPTS)
});
});
// 3. UI: HOME PAGE (Direct HTML Render)
app.get('/', (req, res) => {
res.send(HTML_PAGE);
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`--> Server listening on ${PORT}`);
initModel();
});