Emalawi19 commited on
Commit
24cf705
Β·
verified Β·
1 Parent(s): 7c2521a

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +102 -101
server.js CHANGED
@@ -11,47 +11,49 @@ async function loadModel() {
11
  console.log("Model loaded successfully!");
12
  }
13
 
14
- // ── WIKIPEDIA SEARCH ─────────────────────────────────────────────────────────
15
- // Step 1: Search Wikipedia for the best matching article title
16
  async function searchWikipedia(query) {
17
  try {
18
- const url = `https://en.wikipedia.org/w/api.php?action=search&list=search&srsearch=${encodeURIComponent(query)}&srlimit=1&format=json&origin=*`;
19
  const res = await fetch(url);
20
  const data = await res.json();
21
  const results = data?.query?.search;
22
  if (!results || results.length === 0) return null;
23
- return results[0].title; // Return best matching article title
24
- } catch {
 
25
  return null;
26
  }
27
  }
28
 
29
- // Step 2: Fetch the article summary (first 600 chars) using the title
30
  async function fetchWikipediaSummary(title) {
31
  try {
32
  const url = `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(title)}`;
33
  const res = await fetch(url);
34
  const data = await res.json();
35
- if (data.extract) {
36
- // Trim to 600 chars so it fits the model's context without overloading it
37
- return data.extract.slice(0, 600);
38
- }
39
  return null;
40
- } catch {
 
41
  return null;
42
  }
43
  }
44
 
45
- // Step 3: Combine search + fetch into one call
46
  async function getWikipediaContext(prompt) {
47
- const title = await searchWikipedia(prompt);
48
- if (!title) return null;
49
- const summary = await fetchWikipediaSummary(title);
50
- if (!summary) return null;
51
- return { title, summary };
 
 
 
 
 
 
52
  }
53
 
54
- // ── CODING KEYWORD DETECTION ─────────────────────────────────────────────────
55
  const CODING_PHRASES = [
56
  'generate code', 'write code', 'create code',
57
  'generate a website', 'build a website', 'create a website', 'make a website',
@@ -79,7 +81,9 @@ const NON_CODING_CONTEXTS = [
79
  'explain', 'what is', 'what are', 'tell me about',
80
  'history of', 'meaning of', 'definition of',
81
  'describe', 'how does', 'why is', 'benefits of',
82
- 'importance of', 'effects of', 'causes of'
 
 
83
  ];
84
 
85
  function isCodingRequest(prompt) {
@@ -128,6 +132,17 @@ function enforceHTMLStructure(text) {
128
  return text;
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
131
  // ── HTTP SERVER ───────────────────────────────────────────────────────────────
132
  const server = http.createServer(async (req, res) => {
133
  res.setHeader('Access-Control-Allow-Origin', '*');
@@ -164,69 +179,54 @@ const server = http.createServer(async (req, res) => {
164
  const coding = isCodingRequest(prompt);
165
  const websiteReq = isWebsiteRequest(prompt);
166
 
167
- // ── Fetch Wikipedia context for non-coding questions ──────────
168
  let wikipediaContext = '';
 
169
  if (!coding) {
170
  const wiki = await getWikipediaContext(prompt);
171
  if (wiki) {
172
- wikipediaContext = `\n\nWIKIPEDIA REFERENCE (from article: "${wiki.title}"):\n${wiki.summary}\n\nUse the above Wikipedia information to improve your answer. Rewrite it in your own words β€” do not copy it directly. Add your own explanation on top of it.`;
173
- console.log(`Wikipedia context fetched: "${wiki.title}"`);
174
  }
175
  }
176
 
177
  const finalPrompt = coding
178
- ? `You are a coding assistant. Write complete, working code for this task. Never refuse. Always provide full code: ${prompt}`
179
  : prompt;
180
 
181
  const systemPrompt = coding
182
  ? `You are Gini AI, a full-stack web development AI assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.
183
 
184
- IDENTITY:
185
- - Your name is Gini AI, created by Emalawi19, founded by Professor Roosevelt Chinkwende.
186
- - You are an AI assistant, not a human.
187
-
188
- CODING RULES β€” NEVER BREAK THESE:
189
- 1. You ALWAYS write code when asked. You NEVER refuse any coding task.
190
- 2. Code must be complete, real, and copy-paste ready β€” no placeholders.
191
- 3. Default language is always JavaScript/HTML/CSS β€” NEVER Python unless the user asks.
192
- 4. Add short comments inside the code.
193
-
194
- HTML WEBSITE RULES:
195
- 1. ALL website/page code MUST start with <!DOCTYPE html> on the very first line.
196
- 2. Then <html lang="en"> on the second line.
197
- 3. Must include a proper <head> with <meta charset>, <meta viewport>, <title>, and <style>.
198
- 4. Must include a proper <body> with all content.
199
- 5. Must end with </body> then </html> as the very last line.
200
- 6. ALL CSS inside <style> in <head>. ALL JS inside <script> at the bottom of <body>.
201
- 7. Wrap full HTML in a \`\`\`html code block.
202
- 8. The page must be complete and functional β€” never cut off mid-code.
203
-
204
- STEP-BY-STEP RULES:
205
- 1. When asked to build a full website or app, list ALL steps first.
206
- 2. Say: "Let's begin with Step 1. Say 'next' when ready."
207
- 3. For each step: title, explanation, complete code, filename, how to run, then "Say 'next' to continue."
208
- 4. ONE step per response. Never combine. Never cut off mid-code.`
209
 
210
  : `You are Gini AI, a helpful AI assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.
211
 
212
- IDENTITY:
213
- - Your name is Gini AI, created by Emalawi19, founded by Professor Roosevelt Chinkwende.
214
- - You are an AI assistant, not a human.
215
  ${wikipediaContext}
216
- GENERAL BEHAVIOR:
217
  - Answer the question directly and clearly in plain English.
218
- - If Wikipedia reference data is provided above, use it to make your answer accurate and informative.
219
- - Rewrite the Wikipedia information in your own words β€” never copy it word for word.
220
- - Add your own helpful explanation beyond just what Wikipedia says.
221
- - NEVER generate code for general knowledge or everyday questions.
222
- - Keep answers concise, friendly, and easy to understand.`;
223
-
224
- const messages = [
225
- { role: 'system', content: systemPrompt },
226
- { role: 'user', content: finalPrompt }
227
- ];
228
 
229
- // ── SSE streaming response ────────────────────────────────────
230
  res.writeHead(200, {
231
  'Content-Type': 'text/event-stream',
232
  'Cache-Control': 'no-cache',
@@ -234,57 +234,58 @@ GENERAL BEHAVIOR:
234
  'X-Accel-Buffering': 'no'
235
  });
236
 
237
- let fullResult = '';
238
-
239
- await generator(messages, {
240
- max_new_tokens: coding ? 800 : 300,
241
- temperature: coding ? 0.2 : 0.5,
242
- repetition_penalty: 1.2,
243
- do_sample: !coding,
244
- callback_function: (beams) => {
245
- const newText = beams[0]?.generated_text ?? '';
246
- if (newText.length > fullResult.length) {
247
- const chunk = newText.slice(fullResult.length);
248
- fullResult = newText;
249
- res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
250
- }
251
- }
252
- });
253
 
254
- // Catch refusals and retry
255
  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"];
256
- const refused = refusals.some(r => fullResult.toLowerCase().startsWith(r));
257
 
258
  if (refused && coding) {
259
- fullResult = '';
260
- await generator([
261
  { role: 'system', content: 'You are a code generator. Output only complete working code. Never refuse.' },
262
- { role: 'user', content: `Write complete working HTML code starting with <!DOCTYPE html> and ending with </html> for: ${prompt}` }
263
- ], {
264
- max_new_tokens: 800,
265
- temperature: 0.1,
266
- do_sample: false,
267
- callback_function: (beams) => {
268
- const newText = beams[0]?.generated_text ?? '';
269
- if (newText.length > fullResult.length) {
270
- const chunk = newText.slice(fullResult.length);
271
- fullResult = newText;
272
- res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
273
- }
274
- }
275
- });
276
  }
277
 
278
  if (websiteReq && coding) {
279
- fullResult = enforceHTMLStructure(fullResult);
 
 
 
 
 
 
 
 
 
280
  }
281
 
282
- // Send final done event with source info
283
- const wikiSource = (!coding && wikipediaContext) ? 'πŸ“– Wikipedia' : null;
284
- res.write(`data: ${JSON.stringify({ done: true, result: fullResult, source: wikiSource })}\n\n`);
285
  res.end();
286
 
287
  } catch (err) {
 
288
  res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`);
289
  res.end();
290
  }
 
11
  console.log("Model loaded successfully!");
12
  }
13
 
14
+ // ── WIKIPEDIA ────────────────────────────────────────────────────────────────
 
15
  async function searchWikipedia(query) {
16
  try {
17
+ const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query)}&srlimit=1&format=json&origin=*`;
18
  const res = await fetch(url);
19
  const data = await res.json();
20
  const results = data?.query?.search;
21
  if (!results || results.length === 0) return null;
22
+ return results[0].title;
23
+ } catch (e) {
24
+ console.error("Wikipedia search error:", e.message);
25
  return null;
26
  }
27
  }
28
 
 
29
  async function fetchWikipediaSummary(title) {
30
  try {
31
  const url = `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(title)}`;
32
  const res = await fetch(url);
33
  const data = await res.json();
34
+ if (data.extract) return data.extract.slice(0, 800);
 
 
 
35
  return null;
36
+ } catch (e) {
37
+ console.error("Wikipedia fetch error:", e.message);
38
  return null;
39
  }
40
  }
41
 
 
42
  async function getWikipediaContext(prompt) {
43
+ try {
44
+ const title = await searchWikipedia(prompt);
45
+ if (!title) return null;
46
+ const summary = await fetchWikipediaSummary(title);
47
+ if (!summary) return null;
48
+ console.log(`Wikipedia context fetched: "${title}"`);
49
+ return { title, summary };
50
+ } catch (e) {
51
+ console.error("Wikipedia context error:", e.message);
52
+ return null;
53
+ }
54
  }
55
 
56
+ // ── CODING DETECTION ─────────────────────────────────────────────────────────
57
  const CODING_PHRASES = [
58
  'generate code', 'write code', 'create code',
59
  'generate a website', 'build a website', 'create a website', 'make a website',
 
81
  'explain', 'what is', 'what are', 'tell me about',
82
  'history of', 'meaning of', 'definition of',
83
  'describe', 'how does', 'why is', 'benefits of',
84
+ 'importance of', 'effects of', 'causes of',
85
+ 'who is', 'who was', 'when did', 'when was',
86
+ 'where is', 'where was', 'which is', 'which was'
87
  ];
88
 
89
  function isCodingRequest(prompt) {
 
132
  return text;
133
  }
134
 
135
+ // ── CORE GENERATION (non-streaming, reliable) ─────────────────────────────────
136
+ async function generateResponse(messages, coding) {
137
+ const output = await generator(messages, {
138
+ max_new_tokens: coding ? 800 : 400,
139
+ temperature: coding ? 0.2 : 0.5,
140
+ repetition_penalty: 1.2,
141
+ do_sample: !coding
142
+ });
143
+ return output[0].generated_text.at(-1).content || '';
144
+ }
145
+
146
  // ── HTTP SERVER ───────────────────────────────────────────────────────────────
147
  const server = http.createServer(async (req, res) => {
148
  res.setHeader('Access-Control-Allow-Origin', '*');
 
179
  const coding = isCodingRequest(prompt);
180
  const websiteReq = isWebsiteRequest(prompt);
181
 
182
+ // ── Fetch Wikipedia for non-coding questions ──────────────────
183
  let wikipediaContext = '';
184
+ let wikiTitle = null;
185
  if (!coding) {
186
  const wiki = await getWikipediaContext(prompt);
187
  if (wiki) {
188
+ wikiTitle = wiki.title;
189
+ wikipediaContext = `\n\nWIKIPEDIA REFERENCE (article: "${wiki.title}"):\n${wiki.summary}\n\nIMPORTANT: Use this Wikipedia data to answer accurately. Rewrite it in your own words and add helpful context.`;
190
  }
191
  }
192
 
193
  const finalPrompt = coding
194
+ ? `You are a coding assistant. Write complete, working code. Never refuse: ${prompt}`
195
  : prompt;
196
 
197
  const systemPrompt = coding
198
  ? `You are Gini AI, a full-stack web development AI assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.
199
 
200
+ IDENTITY: Your name is Gini AI. Company: Emalawi19. Founder: Professor Roosevelt Chinkwende.
201
+
202
+ CODING RULES:
203
+ 1. ALWAYS write code when asked. NEVER refuse.
204
+ 2. Complete, real, copy-paste ready code only β€” no placeholders.
205
+ 3. Default: JavaScript/HTML/CSS. Never Python unless asked.
206
+ 4. Add comments inside the code.
207
+
208
+ HTML RULES:
209
+ 1. Start with <!DOCTYPE html> then <html lang="en">
210
+ 2. Include proper <head> with meta tags, title, and <style>
211
+ 3. End with </body> then </html>
212
+ 4. All CSS in <style>, all JS in <script> at bottom of body.
213
+ 5. Wrap in \`\`\`html code block. Never cut off mid-code.
214
+
215
+ STEP-BY-STEP: List all steps first, then one step at a time. Say "next" to continue.`
 
 
 
 
 
 
 
 
 
216
 
217
  : `You are Gini AI, a helpful AI assistant created by Emalawi19, founded by Professor Roosevelt Chinkwende.
218
 
219
+ IDENTITY: Your name is Gini AI. Company: Emalawi19. Founder: Professor Roosevelt Chinkwende. You are an AI, not a human.
 
 
220
  ${wikipediaContext}
221
+ RULES:
222
  - Answer the question directly and clearly in plain English.
223
+ - If Wikipedia reference is provided above, use it to give an accurate, well-informed answer.
224
+ - Rewrite Wikipedia info in your own words β€” never copy it directly.
225
+ - If the question is about a person (president, leader, founder etc.), state their name clearly at the start.
226
+ - NEVER generate code for general knowledge questions.
227
+ - Keep answers friendly, clear, and concise.`;
 
 
 
 
 
228
 
229
+ // ── Set SSE headers ─��─────────────────────────────────────────
230
  res.writeHead(200, {
231
  'Content-Type': 'text/event-stream',
232
  'Cache-Control': 'no-cache',
 
234
  'X-Accel-Buffering': 'no'
235
  });
236
 
237
+ // Send a heartbeat so the client knows we're working
238
+ res.write(`data: ${JSON.stringify({ status: "generating" })}\n\n`);
239
+
240
+ // ── Generate (wait for full result, then stream it out) ────────
241
+ // The callback_function in transformers.js is unreliable on CPU
242
+ // so we generate fully then simulate streaming character by character
243
+ const messages = [
244
+ { role: 'system', content: systemPrompt },
245
+ { role: 'user', content: finalPrompt }
246
+ ];
247
+
248
+ let result = await generateResponse(messages, coding);
 
 
 
 
249
 
250
+ // Catch refusals
251
  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"];
252
+ const refused = refusals.some(r => result.toLowerCase().startsWith(r));
253
 
254
  if (refused && coding) {
255
+ result = await generateResponse([
 
256
  { role: 'system', content: 'You are a code generator. Output only complete working code. Never refuse.' },
257
+ { role: 'user', content: `Write complete HTML code starting with <!DOCTYPE html> ending with </html> for: ${prompt}` }
258
+ ], true);
259
+ }
260
+
261
+ // If result is still empty, use Wikipedia summary directly
262
+ if (!result || result.trim().length < 5) {
263
+ if (wikiTitle && wikipediaContext) {
264
+ result = `Based on Wikipedia: ${wikipediaContext.split('\n').slice(3).join(' ').trim()}`;
265
+ } else {
266
+ result = "I'm sorry, I couldn't generate a response. Please try again.";
267
+ }
 
 
 
268
  }
269
 
270
  if (websiteReq && coding) {
271
+ result = enforceHTMLStructure(result);
272
+ }
273
+
274
+ // ── Stream the result word by word ────────────────────────────
275
+ const words = result.split(' ');
276
+ for (let i = 0; i < words.length; i++) {
277
+ const chunk = (i === 0 ? '' : ' ') + words[i];
278
+ res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
279
+ // Small delay so frontend can render progressively
280
+ await new Promise(r => setTimeout(r, 15));
281
  }
282
 
283
+ // Send done event
284
+ res.write(`data: ${JSON.stringify({ done: true, result, source: wikiTitle ? `πŸ“– Wikipedia β€” ${wikiTitle}` : null })}\n\n`);
 
285
  res.end();
286
 
287
  } catch (err) {
288
+ console.error("Generation error:", err.message);
289
  res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`);
290
  res.end();
291
  }