lenzcom commited on
Commit
c80fd01
·
verified ·
1 Parent(s): f537fa7

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. Dockerfile +12 -13
  2. server.js +40 -25
Dockerfile CHANGED
@@ -1,35 +1,34 @@
1
  FROM node:18
2
 
3
- # Cài đặt đầy đủ công cụ build
4
  RUN apt-get update && apt-get install -y \
5
  python3 \
6
- python3-pip \
7
  make \
8
  g++ \
9
  cmake \
10
- curl \
11
  build-essential \
12
  && rm -rf /var/lib/apt/lists/*
13
 
 
 
 
 
 
 
14
  WORKDIR /app
15
 
16
- # Copy package files trước
17
- COPY package*.json ./
18
 
19
- # Cài đặt dependencies với cờ --unsafe-perm để tránh lỗi quyền root
20
- # Bỏ qua script postinstall lúc đầu để tránh build lỗi ngay
21
  RUN npm install --ignore-scripts
22
 
23
- # Copy toàn bộ code
24
- COPY . .
25
 
26
- # Tạo thư mục models
27
  RUN mkdir -p models
28
-
29
- # Tải model (dùng npx từ node_modules local)
30
  RUN npx --no node-llama-cpp pull --dir ./models hf:Qwen/Qwen3-1.7B-GGUF:Q8_0 --filename Qwen3-1.7B-Q8_0.gguf
31
 
32
- # Rebuild node-llama-cpp một cách thủ công để đảm bảo nó nhận diện đúng môi trường Linux
33
  RUN npm rebuild node-llama-cpp
34
 
35
  EXPOSE 7860
 
1
  FROM node:18
2
 
3
+ # Cài đặt tools
4
  RUN apt-get update && apt-get install -y \
5
  python3 \
 
6
  make \
7
  g++ \
8
  cmake \
 
9
  build-essential \
10
  && rm -rf /var/lib/apt/lists/*
11
 
12
+ # Tạo user để chạy non-root
13
+ RUN useradd -m -u 1000 user
14
+ USER user
15
+ ENV HOME=/home/user \
16
+ PATH=/home/user/.local/bin:$PATH
17
+
18
  WORKDIR /app
19
 
20
+ # Copy files với quyền user
21
+ COPY --chown=user package*.json ./
22
 
 
 
23
  RUN npm install --ignore-scripts
24
 
25
+ COPY --chown=user . .
 
26
 
27
+ # Tạo thư mục models và tải model
28
  RUN mkdir -p models
 
 
29
  RUN npx --no node-llama-cpp pull --dir ./models hf:Qwen/Qwen3-1.7B-GGUF:Q8_0 --filename Qwen3-1.7B-Q8_0.gguf
30
 
31
+ # Rebuild
32
  RUN npm rebuild node-llama-cpp
33
 
34
  EXPOSE 7860
server.js CHANGED
@@ -1,11 +1,10 @@
1
  import express from 'express';
2
- import { SystemMessage, HumanMessage, Runnable, LlamaCppLLM } from '../src/index.js';
3
  import bodyParser from 'body-parser';
 
 
4
 
5
- // ============================================================================
6
- // COPIED LOGIC FROM SOLUTION (Simplification for API)
7
- // ============================================================================
8
-
9
  class EmailClassifierRunnable extends Runnable {
10
  constructor(llm) {
11
  super();
@@ -22,7 +21,9 @@ class EmailClassifierRunnable extends Runnable {
22
  return [
23
  new SystemMessage(`You are an email classification assistant. Classify into: Spam, Invoice, Meeting Request, Urgent, Personal, Other.
24
  Respond in strict JSON format: {"category": "Name", "confidence": 0.95, "reason": "Explanation"}`),
25
- new HumanMessage(`Classify this email:\nSubject: ${email.subject}\nBody: ${email.body}`)
 
 
26
  ];
27
  }
28
 
@@ -37,32 +38,44 @@ class EmailClassifierRunnable extends Runnable {
37
  }
38
  }
39
 
40
- // ============================================================================
41
- // SERVER SETUP
42
- // ============================================================================
43
-
44
  const app = express();
45
- const PORT = 7860; // Standard port for Hugging Face Spaces
46
 
47
  app.use(bodyParser.json());
48
 
49
- // Initialize LLM Global
50
- console.log("Loading model...");
51
- const llm = new LlamaCppLLM({
52
- modelPath: './models/Qwen3-1.7B-Q8_0.gguf',
53
- temperature: 0.1,
54
- maxTokens: 200
55
- });
56
- const classifier = new EmailClassifierRunnable(llm);
57
- console.log("Model loaded!");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
  app.post('/classify', async (req, res) => {
 
60
  try {
61
  const { subject, body, from } = req.body;
62
- if (!subject || !body) {
63
- return res.status(400).json({ error: 'Missing subject or body' });
64
- }
65
-
66
  const result = await classifier.invoke({ subject, body, from: from || 'unknown' });
67
  res.json(result);
68
  } catch (error) {
@@ -75,6 +88,8 @@ app.get('/', (req, res) => {
75
  res.send('AI Agent Email Classifier is Running. POST to /classify to use.');
76
  });
77
 
78
- app.listen(PORT, () => {
 
79
  console.log(`Server running on port ${PORT}`);
 
80
  });
 
1
  import express from 'express';
2
+ import { SystemMessage, HumanMessage, Runnable, LlamaCppLLM } from './src/index.js'; // Sửa lại đường dẫn import cho đúng cấu trúc flat nếu cần, nhưng ở đây src vẫn nằm trong root
3
  import bodyParser from 'body-parser';
4
+ import path from 'path';
5
+ import fs from 'fs';
6
 
7
+ // ... (Giữ nguyên phần Class Logic) ...
 
 
 
8
  class EmailClassifierRunnable extends Runnable {
9
  constructor(llm) {
10
  super();
 
21
  return [
22
  new SystemMessage(`You are an email classification assistant. Classify into: Spam, Invoice, Meeting Request, Urgent, Personal, Other.
23
  Respond in strict JSON format: {"category": "Name", "confidence": 0.95, "reason": "Explanation"}`),
24
+ new HumanMessage(`Classify this email:
25
+ Subject: ${email.subject}
26
+ Body: ${email.body}`)
27
  ];
28
  }
29
 
 
38
  }
39
  }
40
 
 
 
 
 
41
  const app = express();
42
+ const PORT = 7860;
43
 
44
  app.use(bodyParser.json());
45
 
46
+ // Log directory content for debugging
47
+ console.log("Current directory:", process.cwd());
48
+ console.log("Files in models:", fs.readdirSync('./models'));
49
+
50
+ let classifier = null;
51
+
52
+ async function initModel() {
53
+ try {
54
+ console.log("Loading model...");
55
+ const modelPath = path.resolve('./models/Qwen3-1.7B-Q8_0.gguf');
56
+ console.log("Model absolute path:", modelPath);
57
+
58
+ const llm = new LlamaCppLLM({
59
+ modelPath: modelPath,
60
+ temperature: 0.1,
61
+ maxTokens: 200
62
+ });
63
+
64
+ // Test invoke to make sure it works
65
+ await llm.invoke("Hello");
66
+
67
+ classifier = new EmailClassifierRunnable(llm);
68
+ console.log("Model loaded and ready!");
69
+ } catch (err) {
70
+ console.error("FATAL ERROR loading model:", err);
71
+ process.exit(1); // Exit to let Docker restart (or show error)
72
+ }
73
+ }
74
 
75
  app.post('/classify', async (req, res) => {
76
+ if (!classifier) return res.status(503).json({ error: "Model is loading..." });
77
  try {
78
  const { subject, body, from } = req.body;
 
 
 
 
79
  const result = await classifier.invoke({ subject, body, from: from || 'unknown' });
80
  res.json(result);
81
  } catch (error) {
 
88
  res.send('AI Agent Email Classifier is Running. POST to /classify to use.');
89
  });
90
 
91
+ // Start server immediately, load model in background
92
+ app.listen(PORT, '0.0.0.0', () => {
93
  console.log(`Server running on port ${PORT}`);
94
+ initModel();
95
  });