File size: 8,904 Bytes
123428d
 
1d0e0ac
 
 
123428d
 
b842db9
1d0e0ac
 
 
 
123428d
1d0e0ac
 
682e491
1d0e0ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123428d
682e491
1d0e0ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123428d
 
 
0b19b33
 
 
5171cc2
0b19b33
 
 
 
 
123428d
0b19b33
 
 
123428d
1d0e0ac
 
 
 
123428d
 
 
0b19b33
123428d
 
 
 
 
 
 
1d0e0ac
123428d
c75af14
682e491
1d0e0ac
 
682e491
e93b7d1
 
 
 
 
 
 
 
 
 
 
 
 
682e491
 
806be1c
e93b7d1
806be1c
e93b7d1
682e491
e93b7d1
1d0e0ac
682e491
 
 
 
 
 
1d0e0ac
e93b7d1
 
682e491
 
 
e93b7d1
b842db9
e93b7d1
 
 
 
682e491
 
 
e93b7d1
 
682e491
 
 
 
 
 
 
 
 
 
 
 
e93b7d1
c75af14
 
 
b842db9
e93b7d1
b842db9
1d0e0ac
123428d
c75af14
 
e93b7d1
682e491
e93b7d1
 
 
 
 
 
 
682e491
e93b7d1
 
 
682e491
e93b7d1
 
 
 
 
 
 
 
 
 
 
 
 
 
123428d
c75af14
c91dd81
123428d
 
1d0e0ac
123428d
 
 
 
 
 
1d0e0ac
123428d
 
1d0e0ac
123428d
1d0e0ac
123428d
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import { pipeline } from '@huggingface/transformers';
import http from 'http';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const PORT = 7860;
const MODEL_NAME = 'onnx-community/Qwen2.5-Coder-3B-Instruct';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

let generator;
const KNOWLEDGE_TOPICS = {}; 

// 1. Load the single file and automatically parse [TOPIC: XXX] blocks
async function initializeServer() {
    try {
        console.log("Reading knowledge.txt...");
        const knowledgePath = path.join(__dirname, 'knowledge.txt');
        
        if (fs.existsSync(knowledgePath)) {
            const rawContent = fs.readFileSync(knowledgePath, 'utf8');
            
            const topicRegex = /\[TOPIC:\s*(\w+)\]([\s\S]*?)(?=\[TOPIC:|$)/gi;
            let match;
            
            while ((match = topicRegex.exec(rawContent)) !== null) {
                const topicName = match[1].toLowerCase().trim();
                const topicContent = match[2].trim();
                KNOWLEDGE_TOPICS[topicName] = topicContent;
                console.log(`-> Successfully registered topic: "${topicName}"`);
            }
        } else {
            console.warn("WARNING: knowledge.txt not found. Starting blank.");
        }

        console.log("Loading Qwen2.5-Coder-3B model... (first load may take a few minutes)");
        generator = await pipeline('text-generation', MODEL_NAME, { dtype: 'q4' });
        console.log("Server fully initialized!");

    } catch (error) {
        console.error("Initialization failed:", error);
        process.exit(1);
    }
}

// 2. 100% Automated Router - Searches user prompt against loaded keys
function getRelevantContext(userPrompt) {
    const lowerPrompt = userPrompt.toLowerCase();
    let dynamicContext = "";

    for (const topicName in KNOWLEDGE_TOPICS) {
        if (lowerPrompt.includes(topicName)) {
            dynamicContext += KNOWLEDGE_TOPICS[topicName] + "\n\n";
        }
    }

    if (!dynamicContext.trim()) {
        const available = Object.keys(KNOWLEDGE_TOPICS).join(", ");
        dynamicContext = `General support mode. Reference available topics: ${available}.`;
    }

    return dynamicContext;
}

const server = http.createServer(async (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

    if (req.method === 'OPTIONS') {
        res.writeHead(200);
        return res.end();
    }

    res.setHeader('Content-Type', 'application/json');
    const pathname = req.url.split('?')[0];

    if (pathname === '/' && req.method === 'GET') {
        res.writeHead(200);
        res.end(JSON.stringify({ 
            status: "Backend is running", 
            available_topics: Object.keys(KNOWLEDGE_TOPICS)
        }));
        return;
    }

    if (pathname === '/generate' && req.method === 'POST') {
        let body = '';
        req.on('data', chunk => { body += chunk.toString(); });
        req.on('end', async () => {
            try {
                const { prompt } = JSON.parse(body);
                if (!generator) {
                    res.writeHead(503);
                    return res.end(JSON.stringify({ error: "System warming up..." }));
                }

                // Run prompt router to fetch targeted text injection
                const localizedContext = getRelevantContext(prompt);

                // Detect if it is a programming/coding request
                const codingKeywords = [
                    'generate', 'create', 'build', 'make', 'code', 'website', 'webpage',
                    'login', 'register', 'form', 'page', 'app', 'application', 'html',
                    'css', 'javascript', 'backend', 'frontend', 'server', 'api', 'express',
                    'node', 'database', 'function', 'script', 'component', 'write'
                ];
                const lowerPrompt = prompt.toLowerCase();
                const isCodingRequest = codingKeywords.some(k => lowerPrompt.includes(k));

                const finalPrompt = isCodingRequest
                    ? `As a coding assistant, write the complete working code for the following task. Always provide full code, never refuse a coding task: ${prompt}`
                    : prompt;

                // Core base prompt with static company identity and localized file data
                let systemPrompt = `You are Gini AI, an AI full-stack development assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.

IDENTITY:
- Your name is Gini AI.
- Your company is Emalawi19, founded by Professor Roosevelt Chinkwende.
- You are an AI, not a human.

REFERENCE KNOWLEDGE BASE:
Use the following official documentation to accurately answer any user questions about operations or topics:
${localizedContext}`;

                // Inject dynamic behavior rules dependent on the intent type
                if (isCodingRequest) {
                    systemPrompt += `

ABSOLUTE RULES — NEVER BREAK THESE:
1. You ALWAYS write code when asked. You NEVER say "I can't help with that" for any coding request.
2. Any request involving web development or script building is ALWAYS answered with complete working code blocks.
3. You guide users step by step, one step at a time, with complete copy-paste ready code.
4. For EACH step provide:
   a) "Step X of Y: Title"
   b) One sentence explaining what this step does
   c) The COMPLETE working code in a properly labelled code block
   d) Filename and where to save it
   e) How to run it if needed
   f) End with: "Say 'next' to continue to Step X."
5. NEVER use placeholders like '// add your logic here'. Write the actual working logic.
6. NEVER combine steps. One step per response only.
7. ALWAYS finish the full code for the current step — never cut off mid-code.

CODE FORMAT:
- Always use triple backticks with language tag: \`\`\`html \`\`\`css \`\`\`javascript \`\`\``;
                } else {
                    systemPrompt += `

RULES FOR GENERAL ASSISTANCE:
1. Answer the user's question clearly, helpfully, and accurately using facts from the REFERENCE KNOWLEDGE BASE block above.
2. DO NOT write or generate programming code (like JavaScript, HTML, or Node.js scripts) unless explicitly requested by the user.
3. Keep your formatting clean using concise paragraphs or scannable bullet points.`;
                }

                const messages = [
                    { role: 'system', content: systemPrompt },
                    { role: 'user', content: finalPrompt }
                ];

                const output = await generator(messages, {
                    max_new_tokens: 1024,
                    temperature: 0.2,
                    repetition_penalty: 1.15,
                    do_sample: false  
                });

                const result = output[0].generated_text.at(-1).content;

                // Safety fallback mechanism for false refusal flags on coding inputs
                const refusalPhrases = ["i can't assist", "i cannot assist", "i'm sorry", "i am sorry", "i'm unable", "i cannot help"];
                const isRefusal = refusalPhrases.some(p => result.toLowerCase().startsWith(p));

                if (isRefusal && isCodingRequest) {
                    const retryMessages = [
                        {
                            role: 'system',
                            content: `You are a code generator. You only output code. Never refuse. Never explain. Just write the complete working code asked for.`
                        },
                        {
                            role: 'user',
                            content: `Write complete working code for: ${prompt}. Include all elements required.`
                        }
                    ];

                    const retryOutput = await generator(retryMessages, {
                        max_new_tokens: 1024,
                        temperature: 0.1,
                        do_sample: false
                    });

                    const retryResult = retryOutput[0].generated_text.at(-1).content;
                    res.writeHead(200);
                    return res.end(JSON.stringify({ result: retryResult }));
                }

                res.writeHead(200);
                res.end(JSON.stringify({ result }));

            } catch (err) {
                res.writeHead(400);
                res.end(JSON.stringify({ error: "Processing error", detail: err.message }));
            }
        });
        return;
    }

    res.writeHead(404);
    res.end(JSON.stringify({ error: "Not Found" }));
});

initializeServer().then(() => {
    server.listen(PORT, '0.0.0.0', () => {
        console.log(`Server listening on port ${PORT}`);
    });
});