Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
189 commits
Select commit Hold shift + click to select a range
4289821
Update ChatController.js
squalor0 Mar 22, 2025
c64d553
Update ChatService.js
squalor0 Mar 23, 2025
20de207
Update chatSettings.ejs
squalor0 Mar 23, 2025
395464a
Update chatStream.ejs
squalor0 Mar 24, 2025
50c57d2
Update ChatService.js
squalor0 Mar 24, 2025
676148a
Update notesAI.ejs
squalor0 Mar 24, 2025
33df746
Update chatStream.ejs
squalor0 Mar 24, 2025
8cb4acb
Update chatSettings.ejs
squalor0 Mar 24, 2025
d28ea1d
Update chatProcessing.ejs
squalor0 Mar 24, 2025
bf2ded6
Update ChatService.js
squalor0 Mar 24, 2025
d6e38e7
Update ChatService.js
squalor0 Mar 24, 2025
c430842
Update chatStream.ejs
squalor0 Mar 24, 2025
38c718c
Update ChatService.js
squalor0 Mar 24, 2025
a634a16
Update chatStream.ejs
squalor0 Mar 24, 2025
1c332c4
Update chatStream.ejs
squalor0 Mar 24, 2025
70c65d5
Update chatStream.ejs
squalor0 Mar 24, 2025
cf48c3b
Update chatStream.ejs
squalor0 Mar 24, 2025
4ce480e
Update chatStream.ejs
squalor0 Mar 24, 2025
3714478
Update chatStream.ejs
squalor0 Mar 24, 2025
3c787ee
Update chatStream.ejs
squalor0 Mar 24, 2025
e16f836
Update chatStream.ejs
squalor0 Mar 25, 2025
6a46cdd
Update chatStream.ejs
squalor0 Mar 25, 2025
9d84769
Update chatStream.ejs
squalor0 Mar 25, 2025
a92c280
Update chatStream.ejs
squalor0 Mar 25, 2025
0e479db
Update chatStream.ejs
squalor0 Mar 25, 2025
5222111
Update chatStream.ejs
squalor0 Mar 25, 2025
2c53c3b
Update chatStream.ejs
squalor0 Mar 25, 2025
8e5b846
Update chatStream.ejs
squalor0 Mar 25, 2025
06ea405
Update chatStream.ejs
squalor0 Mar 25, 2025
e73663a
Update chatStream.ejs
squalor0 Mar 25, 2025
4092702
Update chatStream.ejs
squalor0 Mar 25, 2025
e86cc3c
Update chatProcessing.ejs
squalor0 Mar 25, 2025
49b653c
Update chatProcessing.ejs
squalor0 Mar 25, 2025
656a023
Update chatProcessing.ejs
squalor0 Mar 25, 2025
f470eb1
Update chatStream.ejs
squalor0 Mar 27, 2025
1d343d3
Update notesAI.ejs
squalor0 Mar 27, 2025
81c76fc
Update chatStream.ejs
squalor0 Mar 27, 2025
f9be60a
Update chatStream.ejs
squalor0 Mar 27, 2025
0658cfc
Update chatStream.ejs
squalor0 Mar 27, 2025
994a6f1
Update chatStream.ejs
squalor0 Mar 27, 2025
64f32f9
Update chatStream.ejs
squalor0 Mar 29, 2025
0e95b36
Update chatStream.ejs
squalor0 Mar 29, 2025
90d1ea4
Update chatStream.ejs
squalor0 Mar 29, 2025
b6b05d5
Update chatStream.ejs
squalor0 Mar 29, 2025
e03d31b
Update ChatService.js
squalor0 Mar 29, 2025
692d379
Update chatStream.ejs
squalor0 Mar 29, 2025
d0e7b5e
Update chatStream.ejs
squalor0 Mar 29, 2025
73a7749
Update ChatService.js
squalor0 Mar 29, 2025
3ec5063
Update chatStream.ejs
squalor0 Mar 29, 2025
3ffd1c6
Update ChatService.js
squalor0 Mar 29, 2025
9cccdce
Update chatStream.ejs
squalor0 Mar 29, 2025
9177bdb
Update chatStream.ejs
squalor0 Mar 29, 2025
2893e68
Update ChatService.js
squalor0 Mar 29, 2025
bcd1178
Update chatStream.ejs
squalor0 Mar 29, 2025
c3f511c
Update chatStream.ejs
squalor0 Mar 29, 2025
e08c0ff
Update ChatService.js
squalor0 Mar 29, 2025
9c2668b
Update ChatService.js
squalor0 Mar 29, 2025
96d2ab0
Update chatStream.ejs
squalor0 Mar 29, 2025
b6a57a1
Update chatStream.ejs
squalor0 Mar 29, 2025
6f4e994
Update chatStream.ejs
squalor0 Mar 29, 2025
678e87f
Update ChatService.js
squalor0 Mar 29, 2025
2a94c81
Update chatStream.ejs
squalor0 Mar 29, 2025
b2c2b42
Update chatStream.ejs
squalor0 Mar 29, 2025
8951eeb
Update ChatService.js
squalor0 Mar 29, 2025
cbb2d55
Update ChatService.js
squalor0 Mar 29, 2025
f2fe1aa
Update chatStream.ejs
squalor0 Mar 29, 2025
7c8867a
Update ChatService.js
squalor0 Mar 29, 2025
7dc0ec6
Update chatStream.ejs
squalor0 Mar 30, 2025
7d3b046
Update ChatService.js
squalor0 Mar 30, 2025
4a07d9b
Update notesAI.ejs
squalor0 Mar 30, 2025
442cad4
Update ChatService.js
squalor0 Mar 30, 2025
087b048
Update editor.ejs
squalor0 Mar 30, 2025
e0ac091
Update notesAI.ejs
squalor0 Mar 30, 2025
9098caf
Update ChatController.js
squalor0 Mar 30, 2025
623ae3e
Update notesAI.ejs
squalor0 Mar 30, 2025
c3c43b6
Update editor.ejs
squalor0 Mar 30, 2025
1b6929c
Update editor.ejs
squalor0 Mar 30, 2025
deaf284
Update ChatService.js
squalor0 Mar 30, 2025
37e598f
Update chatStream.ejs
squalor0 Mar 30, 2025
e9e72b2
Update chatStream.ejs
squalor0 Mar 30, 2025
123b8d7
Update chatProcessing.ejs
squalor0 Mar 30, 2025
85c6142
Update chatStream.ejs
squalor0 Mar 30, 2025
2a13471
Update chatStream.ejs
squalor0 Mar 30, 2025
10dfae3
Update chatProcessing.ejs
squalor0 Mar 30, 2025
a16e350
Update chatProcessing.ejs
squalor0 Mar 30, 2025
278bf11
Update chatStream.ejs
squalor0 Mar 30, 2025
a00024e
Update chatStream.ejs
squalor0 Mar 30, 2025
9473303
Update chatStream.ejs
squalor0 Mar 30, 2025
1986daf
Update chatStream.ejs
squalor0 Mar 30, 2025
d3f382a
Update chatStream.ejs
squalor0 Mar 30, 2025
8958ef9
Update chatProcessing.ejs
squalor0 Mar 30, 2025
b75a74c
Update chatStream.ejs
squalor0 Mar 30, 2025
069ca2e
Update chatProcessing.ejs
squalor0 Mar 30, 2025
78de6ef
Update chatProcessing.ejs
squalor0 Mar 30, 2025
1252381
Update chatProcessing.ejs
squalor0 Mar 30, 2025
d52902f
Update chatStream.ejs
squalor0 Mar 30, 2025
8d19462
Update chatProcessing.ejs
squalor0 Mar 30, 2025
2db843a
Update chatProcessing.ejs
squalor0 Mar 30, 2025
0c002c8
Update chatProcessing.ejs
squalor0 Mar 30, 2025
5920f3c
Update ChatService.js
squalor0 Mar 30, 2025
0251371
Update chatProcessing.ejs
squalor0 Mar 30, 2025
d739e16
Update chatProcessing.ejs
squalor0 Mar 30, 2025
1514f76
Update chatProcessing.ejs
squalor0 Mar 30, 2025
e1d43a3
Update ChatService.js
squalor0 Mar 30, 2025
3ff3b8d
Update chatStream.ejs
squalor0 Mar 30, 2025
b82359b
Update chatStream.ejs
squalor0 Mar 30, 2025
c2581d7
Update ChatService.js
squalor0 Mar 30, 2025
c99cd9c
Update ChatService.js
squalor0 Mar 30, 2025
8fc767d
Update ChatService.js
squalor0 Mar 30, 2025
206a4a0
Update ChatService.js
squalor0 Mar 30, 2025
a6be0a5
Update chatProcessing.ejs
squalor0 Mar 30, 2025
5e21081
Update ChatService.js
squalor0 Mar 30, 2025
69489af
Update chatStream.ejs
squalor0 Mar 30, 2025
d62bdf0
Update chatProcessing.ejs
squalor0 Mar 30, 2025
cfd087a
Update chatProcessing.ejs
squalor0 Mar 30, 2025
5de8e46
Update chatStream.ejs
squalor0 Mar 30, 2025
47a4194
Update editor.ejs
squalor0 Mar 30, 2025
77af082
Update editor.ejs
squalor0 Mar 30, 2025
3ef86fa
Update ChatService.js
squalor0 Mar 30, 2025
40244d3
Update ChatController.js
squalor0 Mar 30, 2025
564ca1f
Update ChatController.js
squalor0 Mar 30, 2025
a3ba85a
Update ChatService.js
squalor0 Mar 30, 2025
4cbe8fd
Update chatProcessing.ejs
squalor0 Mar 30, 2025
98da3b1
Update chatProcessing.ejs
squalor0 Mar 30, 2025
6a52c45
Update ChatService.js
squalor0 Mar 30, 2025
3e42c94
Update chatProcessing.ejs
squalor0 Mar 30, 2025
c4afe4a
Update chatProcessing.ejs
squalor0 Mar 30, 2025
835aa8a
Update chatStream.ejs
squalor0 Mar 30, 2025
bbef44c
Update chatStream.ejs
squalor0 Mar 30, 2025
0ab2573
Update chatStream.ejs
squalor0 Mar 30, 2025
7f3de10
Update ChatController.js
squalor0 Apr 1, 2025
dc6352e
Update ChatService.js
squalor0 Apr 1, 2025
35ab50c
Update chatStream.ejs
squalor0 Apr 1, 2025
f0addb6
Update chatStream.ejs
squalor0 Apr 1, 2025
0200f28
Update chatStream.ejs
squalor0 Apr 1, 2025
de26738
Update ChatService.js
squalor0 Apr 1, 2025
aa8b543
Update chatStream.ejs
squalor0 Apr 1, 2025
4e08c62
Update chatStream.ejs
squalor0 Apr 1, 2025
184d44b
Update JSONStreamService.js
squalor0 Apr 1, 2025
9fead34
Update JSONStreamService.js
squalor0 Apr 1, 2025
dc5d97a
Update chatStream.ejs
squalor0 Apr 1, 2025
6aa86be
Update chatStream.ejs
squalor0 Apr 1, 2025
cdfe93c
Update chatStream.ejs
squalor0 Apr 1, 2025
f09ff70
Update chatStream.ejs
squalor0 Apr 1, 2025
ea522c9
Update chatStream.ejs
squalor0 Apr 1, 2025
60158a7
Update chatStream.ejs
squalor0 Apr 1, 2025
fa1086f
Update chatStream.ejs
squalor0 Apr 1, 2025
94734b4
Update chatStream.ejs
squalor0 Apr 1, 2025
825972c
Update chatStream.ejs
squalor0 Apr 1, 2025
8234d1d
Update chatStream.ejs
squalor0 Apr 1, 2025
8093a9f
Update chatStream.ejs
squalor0 Apr 1, 2025
9693d4d
Update chatStream.ejs
squalor0 Apr 1, 2025
84e23e4
Update chatStream.ejs
squalor0 Apr 1, 2025
9a4a4b1
Update ChatController.js
squalor0 Apr 1, 2025
c9e0a2e
Update chatStream.ejs
squalor0 Apr 1, 2025
f64d56c
Update chatStream.ejs
squalor0 Apr 1, 2025
a641ec7
Update notesAI.ejs
squalor0 Apr 1, 2025
e8a6cda
Update chatProcessing.ejs
squalor0 Apr 1, 2025
a28d9ac
Update editor.ejs
squalor0 Apr 1, 2025
ef20045
Update editor.ejs
squalor0 Apr 2, 2025
f28fa6e
Update editor.ejs
squalor0 Apr 2, 2025
01d6020
Update chatStream.ejs
squalor0 Apr 2, 2025
962478e
Update ChatService.js
squalor0 Apr 2, 2025
a00c51b
Update chatProcessing.ejs
squalor0 Apr 2, 2025
d0caf76
Update chatProcessing.ejs
squalor0 Apr 2, 2025
915a41e
Update chatStream.ejs
squalor0 Apr 2, 2025
d2f17bd
Update chatProcessing.ejs
squalor0 Apr 2, 2025
9b314ba
Update chatProcessing.ejs
squalor0 Apr 2, 2025
54b5c96
Update chatSettings.ejs
squalor0 Apr 2, 2025
23bf695
Update chatProcessing.ejs
squalor0 Apr 2, 2025
425c4db
Update chatProcessing.ejs
squalor0 Apr 2, 2025
aaaaff7
Update chatProcessing.ejs
squalor0 Apr 2, 2025
293456a
Update chatSettings.ejs
squalor0 Apr 3, 2025
e81fa43
Update ChatService.js
squalor0 Apr 3, 2025
f6b26f5
Update chatSettings.ejs
squalor0 Apr 3, 2025
eb7bbd8
Update chatStream.ejs
squalor0 Apr 3, 2025
93851df
Update chatStream.ejs
squalor0 Apr 3, 2025
5998ff5
Update ChatService.js
squalor0 Apr 3, 2025
85af3e8
Update chatStream.ejs
squalor0 Apr 3, 2025
531a544
Update chatStream.ejs
squalor0 Apr 3, 2025
1895f23
Update chatStream.ejs
squalor0 Apr 3, 2025
e136d16
Update chatStream.ejs
squalor0 Apr 3, 2025
c31b2c4
Update notesAI.ejs
squalor0 Apr 3, 2025
9b81f71
Update notesAI.ejs
squalor0 Apr 4, 2025
8296d40
Add files via upload
squalor0 Apr 4, 2025
3cbc1c8
Rename frontend/nodejs/public/AI Assistant.png to frontend/nodejs/pub…
squalor0 Apr 4, 2025
923d011
Update notesAI.ejs
squalor0 Apr 4, 2025
f80b6ef
Update notesAI.ejs
squalor0 Apr 4, 2025
9b6ebf6
move event handlers for prompt keydown and input outside of the ajax
Apr 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions backend/nodejs/controllers/ChatController.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default class ChatController extends BaseController {
// Read prompt and mode from the POST body
const prompt = req.body.prompt;
const mode = req.body.mode || "default";
const destination = req.body.destination || "chat";

if (!prompt) {
return res.status(400).json({ error: "Prompt is required" });
Expand All @@ -26,18 +27,23 @@ export default class ChatController extends BaseController {
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");

const stream = await this.chatService.getChatResponse(prompt, mode);

stream.on("data", (chunk) => {
res.write(`data: ${chunk.toString()}\n\n`);
const responseOrStream = await this.chatService.getChatResponse(prompt, mode);
if (typeof responseOrStream === 'string') {
res.write(`data: ${JSON.stringify({ fullContent: responseOrStream })}\n\n`);
res.write("data: [DONE]\n\n");
return res.end();
}
responseOrStream.on("data", (chunk) => {
res.write(chunk.toString()+"\n");
});

stream.on("end", () => {
responseOrStream.on("end", () => {
res.write("[DONE]\n");
res.end();
});
} catch (error) {
console.error("Chat API Error:", error);
res.write("data: Error occurred while fetching response\n\n");
res.write(`data: {"fullContent":"ERROR: ${error.message}"}\n\n`);
res.write("data: [DONE]\n\n");
res.end();
}
}
Expand Down
190 changes: 151 additions & 39 deletions backend/nodejs/services/ChatService.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import JSONStreamService from "./JSONStreamService.js";
export default class ChatService {
constructor() {
this.conversationHistory = [];
this.quizInProgress = false;
this.currentQuestion = null;
this.correctAnswer = null;
this.lastAnsweredBy = null;
}

clearHistory() {
this.conversationHistory = [];
this.quizInProgress = false;
this.currentQuestion = null;
this.correctAnswer = null;
this.lastAnsweredBy = null;
}

async getChatResponse(prompt, mode) {
Expand All @@ -16,68 +24,172 @@ export default class ChatService {
}

let formattedPrompt;
let isQuizAnswer = false;
let immediateLocalResponse = null;

switch (mode) {
case "steps":
this.clearHistory();
formattedPrompt = `Explain in a step by step format: ${prompt}`;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
break;
case "example":
this.clearHistory();
formattedPrompt = `Explain with a real world example: ${prompt}`;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
break;
case "flashcards":
this.clearHistory();
formattedPrompt = `Generate 10 questions and answers on this subject: ${prompt}`;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
break;
case "quizmaster":
this.clearHistory();
if (prompt.toLowerCase().includes("start quiz")){
const topic = prompt.replace(/start quiz/i, "").trim();
formattedPrompt = `Generate exactly one question, with its answer, strictly related to '${topic}' without introducing any unrelated details,
explanations, extra text, or deviations. Respond ONLY with this JSON structure:
[
{
"Question": "[the generated question]",
"Answer": "[the generated answer]"
}
]
DO NOT use multiple objects in the array. Combine Question and Answer in the same object. DO NOT add any other keys, explanations, or formatting.
Failure to adhere to this format will result in an invalid response. Do not include additional text, formatting, alternative structures,
variables, markdown, escapes, line breaks, or placeholders`;
this.quizInProgress = true;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
} else if (this.quizInProgress && prompt.toLowerCase().includes("next question")){
const topic = prompt.replace(/next question/i, "").trim();
formattedPrompt = `Generate exactly one more question, with its answer, strictly related to '${topic}' without introducing any unrelated details,
explanations, extra text, or deviations. Respond ONLY with this JSON structure:
[
{
"Question": "[the generated question]",
"Answer": "[the generated answer]"
}
]
DO NOT use multiple objects in the array. Combine Question and Answer in the same object. DO NOT add any other keys, explanations, or formatting.
Failure to adhere to this format will result in an invalid response. Do not include additional text, formatting, alternative structures,
variables, markdown, escapes, line breaks, or placeholders`;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
}else if (this.quizInProgress && prompt.toLowerCase().includes("end quiz")){
this.quizInProgress = false
this.currentQuestion = null;
this.correctAnswer = null;
this.lastAnsweredBy = null;
immediateLocalResponse = "The quiz has ended. Thanks for playing!";
} else if (this.quizInProgress && this.currentQuestion && this.correctAnswer){
isQuizAnswer = true;
immediateLocalResponse = this.validateQuizAnswer(prompt);
}else if (this.quizInProgress){
immediateLocalResponse = `I'm in quiz mode right now. Type "start quiz [topic]" to start a new quiz, "next question" for another question, or "end quiz" to finish.`;
} else {
formattedPrompt = prompt;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
}
break
default:
this.clearHistory();
formattedPrompt = prompt;
this.conversationHistory.push({ role: "user", content: formattedPrompt });
break
}
if(immediateLocalResponse !== null || isQuizAnswer) {
return immediateLocalResponse;
}

// Add user input to conversation history
this.conversationHistory.push({ role: "user", content: formattedPrompt });

try {
const response = await axios.post(
"https://ai.api.parsonlabs.com/v1/chat/completions",
{
model: "deepseek-r1:1.5b",
messages: this.conversationHistory, // IMPORTANT! the entire history must be pushed here, not just one single message.
stream: true,
},
{
headers: { "Content-Type": "application/json" },
responseType: "stream",
}
);
if(mode==='quizmaster' && this.quizInProgress){
const res = await axios.post(
"http://bappity.net:11434/v1/chat/completions",
{
model: "deepseek-r1:1.5b",
messages: this.conversationHistory, // IMPORTANT! the entire history must be pushed here, not just one single message.
},
{ headers: {"Content-Type": "application/json" } }
);
const fullText = res.data.choices?.[0]?.message?.content || "";
this.conversationHistory.push({ role:"assistant", content: fullText.trim() });
return fullText;
}else{
const response = await axios.post(
"http://bappity.net:11434/v1/chat/completions",
{
model: "deepseek-r1:1.5b",
messages: this.conversationHistory, // IMPORTANT! the entire history must be pushed here, not just one single message.
stream: true,
},
{
headers: { "Content-Type": "application/json" },
responseType: "stream",
}
);

// Pipe the response stream through the JSONStreamService
const jsonStreamService = new JSONStreamService();
response.data.pipe(jsonStreamService);
// Pipe the response stream through the JSONStreamService
const jsonStreamService = new JSONStreamService();
response.data.pipe(jsonStreamService);

// Builds and stores the assistant message as it is being streamed in
let assistantMessage = "";
jsonStreamService.on("data", (data) => {
try {
const textData = data.toString().trim();
if (textData === "[DONE]") return; // Ignore the [DONE] marker
const parsedData = JSON.parse(textData);
if (parsedData.fullContent) {
assistantMessage = parsedData.fullContent;
let assistantMessage = "";
let previousFullContent = "";

jsonStreamService.on("data", (data) => {
try {
const textData = data.toString().trim();
if (textData === "[DONE]") return; // Ignore the [DONE] marker
const parsedData = JSON.parse(textData);
if (parsedData.fullContent) {
const newFull = parsedData.fullContent;
const diff = newFull.substring(previousFullContent.length);
previousFullContent = newFull;
assistantMessage = newFull;
}
} catch (e) {
console.error("Error parsing streamed data:", e);
}
} catch (e) {
console.error("Error parsing streamed data:", e);
}
});
});

// Stores the full assistant message in the conversation history array when stream ends
jsonStreamService.on("end", () => {
if (assistantMessage) {
assistantMessage = assistantMessage.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
this.conversationHistory.push({ role: "assistant", content: assistantMessage });
}
});
// Stores the full assistant message in the conversation history array when stream ends
jsonStreamService.on("end", () => {
if (assistantMessage) {
const cleaned = assistantMessage.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
this.conversationHistory.push({ role: "assistant", content: cleaned });
}
});

return jsonStreamService;
return jsonStreamService;
}
} catch (error) {
console.error("Chat API Error:", error);
throw new Error("Error occurred while fetching response");
}
}
validateQuizAnswer(prompt){
let username = "";
let userAnswer = prompt;
const colonIndex = prompt.indexOf(':');
if (colonIndex > 0) {
username = prompt.substring(0, colonIndex).trim();
userAnswer = prompt.substring(colonIndex+1).trim();
}
if (this.isCorrectAnswer(userAnswer, this.correctAnswer)){
if(this.lastAnsweredBy){
return `That's correct, ${username}! But ${this.lastAnsweredby} already answered this question correctly. The answer is ${this.correctAnswer}. Type "next question" for another question.`;
}else{
this.lastAnsweredBy = username;
return `Correct, ${username} gets 1 exp!. The answer was ${this.correctAnswer}. Type "next question" for another question.`;
}
}else{
return `Sorry ${username}, that's not correct. Try again!`;
}
}
isCorrectAnswer(userAnswer, correctAnswer){
if (!userAnswer || !correctAnswer) return false

const normalUserAnswer = userAnswer.toLowerCase().trim();
const normalCorrectAnswer = correctAnswer.toLowerCase().trim();
if (normalUserAnswer.includes(normalCorrectAnswer) || normalCorrectAnswer.includes(normalUserAnswer)) return true;
return false
}
}
2 changes: 1 addition & 1 deletion backend/nodejs/services/JSONStreamService.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ export default class JSONStreamService extends Transform {
}
return null;
}
}
}
Binary file added frontend/nodejs/public/images/AI Assistant.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 58 additions & 13 deletions frontend/nodejs/views/chat/partials/chatProcessing.ejs
Original file line number Diff line number Diff line change
@@ -1,24 +1,69 @@
<script>
// Process AI content, separating <think> tags from visible content
function processAIContent(content) {
const thinkMatch = content.match(/<think>([\s\S]*?)(?:<\/think>|$)/);
if (!thinkMatch) {
return {
thoughts: "",
visible: content
};
console.log("[parser] Raw content:", content);
const thoughtMatches = content.match(/<think>[\s\S]*?<\/think>/g) || [];
const thoughts = thoughtMatches.map(match => match.replace(/<\/?think>/g, "").trim()).join("\n");
const strippedContent = content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();

let question = '';
let answer = '';

const isQuizMode = (window.chatMode === 'quizmaster');
if(isQuizMode){
try {
const jsonBlockMatch = strippedContent.match(/```json\s*([\s\S]*?)```/);
if (jsonBlockMatch && jsonBlockMatch[1]) {
const jsonString = jsonBlockMatch[1].trim();
const parsed = JSON.parse(jsonString);
if (Array.isArray(parsed) && parsed.length > 0) {
const first = parsed[0];
question = first.Question?.toString().trim() || '';
answer = first.Answer?.toString().trim() || '';
}
} else {
const start = strippedContent.indexOf('[');
const end = strippedContent.lastIndexOf(']');
if (start !== -1 && end !== -1) {
const jsonString = strippedContent.substring(start, end + 1);
const parsed = JSON.parse(jsonString);
if (Array.isArray(parsed) && parsed.length > 0) {
const first = parsed[0];
question = first.Question?.toString().trim() || '';
answer = first.Answer?.toString().trim() || '';
}
}
}
} catch (e) {
console.warn("Failed to parse JSON from AI:", e);
}
if (answer) {
window.quizCorrectAnswer = answer;
}
}
const thoughtContent = thinkMatch[1];
let visibleContent = content.replace(/<think>[\s\S]*?(?:<\/think>|$)/, "");
return {
thoughts: thoughtContent,
visible: visibleContent
const visible = (isQuizMode && question)
? `${question}\n\nYourName: YourAnswer`
: strippedContent;
return{
thoughts,
visible,
question,
answer
};
console.log("[parser] Stripped content:", strippedContent);
console.log("[parser] Returning visible:", visible);
}


// Render the full AI response into the container
function renderFullResponse(fullRawContent, container, isFinal = false) {
const $container = $(container);
if ($container.length ===0) {
console.error('Container not found for AI response.');
return;
}
const processedContent = processAIContent(fullRawContent);
$container.empty();
// Retrieve the current default from settings.
const thoughtsDefault = $('input[name="thoughtsDefault"]:checked').val();
if (typeof window.persistedThoughtsState === 'undefined') {
Expand All @@ -41,7 +86,7 @@
innerDiv.className = 'markdown-content';
innerDiv.innerHTML = processMathContent(processedContent.thoughts);
detailsElement.appendChild(innerDiv);
container.appendChild(detailsElement);
container.append(detailsElement);

detailsElement.addEventListener('toggle', function () {
window.persistedThoughtsState = detailsElement.open;
Expand Down Expand Up @@ -77,4 +122,4 @@
return escapeMap[match];
});
}
</script>
</script>
Loading