Spaces:
Paused
Paused
| 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}`); | |
| }); | |
| }); |