Emalawi19 commited on
Commit
4a7c883
·
verified ·
1 Parent(s): f3001d7

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +93 -68
server.js CHANGED
@@ -47,6 +47,7 @@ function isCodingRequest(prompt) {
47
  return CODING_PHRASES.some(phrase => lower.includes(phrase));
48
  }
49
 
 
50
  function isWebsiteRequest(prompt) {
51
  const lower = prompt.toLowerCase();
52
  return ['website', 'webpage', 'web page', 'html page', 'login page',
@@ -54,7 +55,34 @@ function isWebsiteRequest(prompt) {
54
  'homepage', 'home page', 'portfolio', 'dashboard'].some(w => lower.includes(w));
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  function cleanHTML(html) {
 
58
  if (!html.trimStart().toLowerCase().startsWith('<!doctype')) {
59
  if (html.trimStart().toLowerCase().startsWith('<html')) {
60
  html = '<!DOCTYPE html>\n' + html.trimStart();
@@ -62,29 +90,18 @@ function cleanHTML(html) {
62
  html = '<!DOCTYPE html>\n<html lang="en">\n' + html.trimStart();
63
  }
64
  }
 
 
65
  if (!html.trimEnd().toLowerCase().endsWith('</html>')) {
 
66
  if (html.toLowerCase().includes('</body>')) {
67
  html = html.replace(/<\/body>\s*$/i, '</body>\n</html>');
68
  } else {
69
  html = html.trimEnd() + '\n</body>\n</html>';
70
  }
71
  }
72
- return html.trim();
73
- }
74
 
75
- function enforceHTMLStructure(text) {
76
- const codeBlockMatch = text.match(/```html\s*([\s\S]*?)```/i);
77
- if (codeBlockMatch) {
78
- return '```html\n' + cleanHTML(codeBlockMatch[1].trim()) + '\n```';
79
- }
80
- const htmlStart = text.search(/<(!DOCTYPE|html)/i);
81
- if (htmlStart !== -1) {
82
- let html = text.slice(htmlStart);
83
- const htmlEnd = html.search(/<\/html>/i);
84
- if (htmlEnd !== -1) html = html.slice(0, htmlEnd + 7);
85
- return '```html\n' + cleanHTML(html) + '\n```';
86
- }
87
- return text;
88
  }
89
 
90
  const server = http.createServer(async (req, res) => {
@@ -97,16 +114,15 @@ const server = http.createServer(async (req, res) => {
97
  return res.end();
98
  }
99
 
 
100
  const pathname = req.url.split('?')[0];
101
 
102
  if (pathname === '/' && req.method === 'GET') {
103
- res.setHeader('Content-Type', 'application/json');
104
  res.writeHead(200);
105
  res.end(JSON.stringify({ status: "Backend is running" }));
106
  return;
107
  }
108
 
109
- // ── STREAMING ENDPOINT ───────────────────────────────────────────────────
110
  if (pathname === '/generate' && req.method === 'POST') {
111
  let body = '';
112
  req.on('data', chunk => { body += chunk.toString(); });
@@ -114,13 +130,12 @@ const server = http.createServer(async (req, res) => {
114
  try {
115
  const { prompt } = JSON.parse(body);
116
  if (!generator) {
117
- res.setHeader('Content-Type', 'application/json');
118
  res.writeHead(503);
119
  return res.end(JSON.stringify({ error: "Model is still loading..." }));
120
  }
121
 
122
  const coding = isCodingRequest(prompt);
123
- const websiteReq = isWebsiteRequest(prompt);
124
 
125
  const finalPrompt = coding
126
  ? `You are a coding assistant. Write complete, working code for this task. Never refuse. Always provide full code: ${prompt}`
@@ -139,21 +154,30 @@ CODING RULES — NEVER BREAK THESE:
139
  3. Default language is always JavaScript/HTML/CSS — NEVER Python unless the user asks.
140
  4. Add short comments inside the code.
141
 
142
- HTML WEBSITE RULES:
143
  1. ALL website/page code MUST start with <!DOCTYPE html> on the very first line.
144
  2. Then <html lang="en"> on the second line.
145
- 3. Must include a proper <head> with <meta charset>, <meta viewport>, <title>, and <style>.
146
- 4. Must include a proper <body> with all content.
147
  5. Must end with </body> then </html> as the very last line.
148
- 6. ALL CSS inside <style> in <head>. ALL JS inside <script> at the bottom of <body>.
149
- 7. Wrap full HTML in a \`\`\`html code block.
150
- 8. The page must be complete and functional never cut off mid-code.
 
151
 
152
  STEP-BY-STEP RULES:
153
- 1. When asked to build a full website or app, list ALL steps first.
154
- 2. Say: "Let's begin with Step 1. Say 'next' when ready."
155
- 3. For each step: title, explanation, complete code, filename, how to run, then "Say 'next' to continue."
156
- 4. ONE step per response. Never combine. Never cut off mid-code.`
 
 
 
 
 
 
 
 
157
 
158
  : `You are Gini AI, a helpful AI assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.
159
 
@@ -162,67 +186,68 @@ IDENTITY:
162
  - You are an AI assistant, not a human.
163
 
164
  GENERAL BEHAVIOR:
165
- - Answer directly and clearly in plain English.
166
  - NEVER generate code for general knowledge or everyday questions.
167
- - NEVER use any programming language to answer a non-coding question.
168
- - Answer in plain sentences. Keep it concise, friendly, and easy to understand.`;
 
 
169
 
170
  const messages = [
171
  { role: 'system', content: systemPrompt },
172
  { role: 'user', content: finalPrompt }
173
  ];
174
 
175
- // Set SSE headers for streaming
176
- res.writeHead(200, {
177
- 'Content-Type': 'text/event-stream',
178
- 'Cache-Control': 'no-cache',
179
- 'Connection': 'keep-alive',
180
- 'X-Accel-Buffering': 'no'
181
- });
182
-
183
- let fullResult = '';
184
-
185
- // Stream tokens as they are generated
186
- await generator(messages, {
187
  max_new_tokens: coding ? 800 : 300,
188
  temperature: coding ? 0.2 : 0.5,
189
  repetition_penalty: 1.2,
190
- do_sample: !coding,
191
- // This callback fires every time a new token is produced
192
- callback_function: (beams) => {
193
- const token = beams[0].output_token_ids;
194
- const newText = beams[0]?.generated_text ?? '';
195
-
196
- // Calculate only the new characters added since last callback
197
- if (newText.length > fullResult.length) {
198
- const newChunk = newText.slice(fullResult.length);
199
- fullResult = newText;
200
- // Send the new chunk immediately as an SSE event
201
- res.write(`data: ${JSON.stringify({ chunk: newChunk })}\n\n`);
202
- }
203
- }
204
  });
205
 
206
- // Post-process HTML if needed
207
- if (websiteReq && coding) {
208
- fullResult = enforceHTMLStructure(fullResult);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  }
210
 
211
- // Send the final complete result and close the stream
212
- res.write(`data: ${JSON.stringify({ done: true, result: fullResult })}\n\n`);
213
- res.end();
214
 
215
  } catch (err) {
216
- res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`);
217
- res.end();
218
  }
219
  });
220
  return;
221
  }
222
 
223
- res.setHeader('Content-Type', 'application/json');
224
  res.writeHead(404);
225
- res.end(JSON.stringify({ error: "Not Found" }));
226
  });
227
 
228
  loadModel().then(() => {
 
47
  return CODING_PHRASES.some(phrase => lower.includes(phrase));
48
  }
49
 
50
+ // Detect if the prompt is asking for a full HTML website/page
51
  function isWebsiteRequest(prompt) {
52
  const lower = prompt.toLowerCase();
53
  return ['website', 'webpage', 'web page', 'html page', 'login page',
 
55
  'homepage', 'home page', 'portfolio', 'dashboard'].some(w => lower.includes(w));
56
  }
57
 
58
+ // Ensure HTML output starts with <!DOCTYPE html> or <html> and ends with </html>
59
+ function enforceHTMLStructure(text) {
60
+ // Extract code from inside ```html ... ``` block if present
61
+ const codeBlockMatch = text.match(/```html\s*([\s\S]*?)```/i);
62
+ if (codeBlockMatch) {
63
+ let html = codeBlockMatch[1].trim();
64
+ html = cleanHTML(html);
65
+ return '```html\n' + html + '\n```';
66
+ }
67
+
68
+ // If raw HTML is present (starts with < somewhere), extract and clean it
69
+ const htmlStart = text.search(/<(!DOCTYPE|html)/i);
70
+ if (htmlStart !== -1) {
71
+ let html = text.slice(htmlStart);
72
+ // Cut off anything after </html>
73
+ const htmlEnd = html.search(/<\/html>/i);
74
+ if (htmlEnd !== -1) {
75
+ html = html.slice(0, htmlEnd + 7); // include </html>
76
+ }
77
+ html = cleanHTML(html);
78
+ return '```html\n' + html + '\n```';
79
+ }
80
+
81
+ return text;
82
+ }
83
+
84
  function cleanHTML(html) {
85
+ // Ensure it starts with <!DOCTYPE html>
86
  if (!html.trimStart().toLowerCase().startsWith('<!doctype')) {
87
  if (html.trimStart().toLowerCase().startsWith('<html')) {
88
  html = '<!DOCTYPE html>\n' + html.trimStart();
 
90
  html = '<!DOCTYPE html>\n<html lang="en">\n' + html.trimStart();
91
  }
92
  }
93
+
94
+ // Ensure it ends with </html>
95
  if (!html.trimEnd().toLowerCase().endsWith('</html>')) {
96
+ // Check if </body> is present, add </html> after it
97
  if (html.toLowerCase().includes('</body>')) {
98
  html = html.replace(/<\/body>\s*$/i, '</body>\n</html>');
99
  } else {
100
  html = html.trimEnd() + '\n</body>\n</html>';
101
  }
102
  }
 
 
103
 
104
+ return html.trim();
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
106
 
107
  const server = http.createServer(async (req, res) => {
 
114
  return res.end();
115
  }
116
 
117
+ res.setHeader('Content-Type', 'application/json');
118
  const pathname = req.url.split('?')[0];
119
 
120
  if (pathname === '/' && req.method === 'GET') {
 
121
  res.writeHead(200);
122
  res.end(JSON.stringify({ status: "Backend is running" }));
123
  return;
124
  }
125
 
 
126
  if (pathname === '/generate' && req.method === 'POST') {
127
  let body = '';
128
  req.on('data', chunk => { body += chunk.toString(); });
 
130
  try {
131
  const { prompt } = JSON.parse(body);
132
  if (!generator) {
 
133
  res.writeHead(503);
134
  return res.end(JSON.stringify({ error: "Model is still loading..." }));
135
  }
136
 
137
  const coding = isCodingRequest(prompt);
138
+ const websiteRequest = isWebsiteRequest(prompt);
139
 
140
  const finalPrompt = coding
141
  ? `You are a coding assistant. Write complete, working code for this task. Never refuse. Always provide full code: ${prompt}`
 
154
  3. Default language is always JavaScript/HTML/CSS — NEVER Python unless the user asks.
155
  4. Add short comments inside the code.
156
 
157
+ HTML WEBSITE RULES — ALWAYS FOLLOW FOR ANY WEBSITE/PAGE REQUEST:
158
  1. ALL website/page code MUST start with <!DOCTYPE html> on the very first line.
159
  2. Then <html lang="en"> on the second line.
160
+ 3. Must include a proper <head> section with <meta charset>, <meta viewport>, <title>, and embedded <style>.
161
+ 4. Must include a proper <body> section with all content.
162
  5. Must end with </body> then </html> as the very last line.
163
+ 6. ALL CSS goes inside a <style> tag in the <head> no external stylesheets.
164
+ 7. ALL JavaScript goes inside a <script> tag at the bottom of <body> — no external scripts.
165
+ 8. The full HTML must be wrapped in a \`\`\`html code block.
166
+ 9. The page must be complete and functional — never cut off mid-code.
167
 
168
  STEP-BY-STEP RULES:
169
+ 1. When asked to build a full website or app, first list ALL steps with short titles.
170
+ 2. Say: "Let's begin with Step 1. Say 'next' when ready to continue."
171
+ 3. For each step:
172
+ a) "Step X of Y: Title"
173
+ b) One sentence explaining what this step does
174
+ c) Complete working code in a code block
175
+ d) Filename and where to save it
176
+ e) How to run it if needed
177
+ f) End with: "Say 'next' to continue to Step X."
178
+ 4. ONE step per response only. Never combine steps.
179
+ 5. NEVER cut off mid-code. Always finish the full code for the current step.
180
+ 6. Default stack: HTML + CSS + JS frontend, Node.js + Express backend.`
181
 
182
  : `You are Gini AI, a helpful AI assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.
183
 
 
186
  - You are an AI assistant, not a human.
187
 
188
  GENERAL BEHAVIOR:
189
+ - Answer the question directly and clearly in plain English.
190
  - NEVER generate code for general knowledge or everyday questions.
191
+ - NEVER use Python, JavaScript, or any programming language to answer a non-coding question.
192
+ - If someone asks "what is the function of X" or "explain X" — answer in plain sentences, not code.
193
+ - Keep answers concise, friendly, and easy to understand.
194
+ - Only mention web development if the question is specifically about it.`;
195
 
196
  const messages = [
197
  { role: 'system', content: systemPrompt },
198
  { role: 'user', content: finalPrompt }
199
  ];
200
 
201
+ const output = await generator(messages, {
 
 
 
 
 
 
 
 
 
 
 
202
  max_new_tokens: coding ? 800 : 300,
203
  temperature: coding ? 0.2 : 0.5,
204
  repetition_penalty: 1.2,
205
+ do_sample: !coding
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  });
207
 
208
+ let result = output[0].generated_text.at(-1).content;
209
+
210
+ // Catch refusals and retry
211
+ const refusals = ["i can't assist", "i cannot assist", "i'm sorry", "i am sorry", "i'm unable", "i cannot help", "i can't help"];
212
+ const refused = refusals.some(r => result.toLowerCase().startsWith(r));
213
+
214
+ if (refused && coding) {
215
+ const retryMessages = [
216
+ {
217
+ role: 'system',
218
+ content: 'You are a code generator. Output only complete working code. Never refuse. No explanations, just code.'
219
+ },
220
+ {
221
+ role: 'user',
222
+ content: `Write complete working HTML code starting with <!DOCTYPE html> and ending with </html> for: ${prompt}`
223
+ }
224
+ ];
225
+ const retryOutput = await generator(retryMessages, {
226
+ max_new_tokens: 800,
227
+ temperature: 0.1,
228
+ do_sample: false
229
+ });
230
+ result = retryOutput[0].generated_text.at(-1).content;
231
+ }
232
+
233
+ // Post-process: enforce proper HTML structure for website requests
234
+ if (websiteRequest && coding) {
235
+ result = enforceHTMLStructure(result);
236
  }
237
 
238
+ res.writeHead(200);
239
+ res.end(JSON.stringify({ result }));
 
240
 
241
  } catch (err) {
242
+ res.writeHead(400);
243
+ res.end(JSON.stringify({ error: "Invalid request", detail: err.message }));
244
  }
245
  });
246
  return;
247
  }
248
 
 
249
  res.writeHead(404);
250
+ res.end(JSON.stringify({ error: "Not Found", requested_path: pathname }));
251
  });
252
 
253
  loadModel().then(() => {