Update aiEngine.js
Browse files- aiEngine.js +32 -16
aiEngine.js
CHANGED
|
@@ -20,50 +20,60 @@ const flattenHistory = (history, currentInput, systemPrompt) => {
|
|
| 20 |
return `System: ${systemPrompt}\n\n${context}\nUser: ${currentInput}\nAssistant:`;
|
| 21 |
};
|
| 22 |
|
| 23 |
-
// HELPER: STREAM SPLITTER
|
| 24 |
const handleStreamResponse = async (response, onThink, onOutput) => {
|
| 25 |
if (!response.ok) throw new Error(`Stream Error: ${response.statusText}`);
|
| 26 |
|
| 27 |
const reader = response.body.getReader();
|
| 28 |
const decoder = new TextDecoder("utf-8");
|
| 29 |
|
| 30 |
-
// fullText is what gets saved to the DB. It should NOT contain thoughts.
|
| 31 |
let fullText = "";
|
|
|
|
| 32 |
|
| 33 |
while (true) {
|
| 34 |
const { done, value } = await reader.read();
|
| 35 |
if (done) break;
|
| 36 |
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
-
//
|
| 40 |
if (chunk.startsWith("__THINK__")) {
|
| 41 |
const thoughtContent = chunk.replace("__THINK__", "");
|
| 42 |
if (onThink) onThink(thoughtContent);
|
| 43 |
}
|
| 44 |
-
// CASE 2: Mixed Chunk (Output then Thought)
|
| 45 |
else if (chunk.includes("__THINK__")) {
|
| 46 |
const parts = chunk.split("__THINK__");
|
| 47 |
-
|
| 48 |
-
// part[0] is real output
|
| 49 |
if (parts[0]) {
|
| 50 |
if (onOutput) onOutput(parts[0]);
|
| 51 |
fullText += parts[0];
|
| 52 |
}
|
| 53 |
-
|
| 54 |
-
// part[1] is thought
|
| 55 |
if (parts[1] && onThink) {
|
| 56 |
onThink(parts[1]);
|
| 57 |
}
|
| 58 |
}
|
| 59 |
-
// CASE 3: Pure Output Chunk
|
| 60 |
else {
|
| 61 |
if (onOutput) onOutput(chunk);
|
| 62 |
fullText += chunk;
|
| 63 |
}
|
| 64 |
}
|
| 65 |
|
| 66 |
-
return {
|
|
|
|
|
|
|
|
|
|
| 67 |
};
|
| 68 |
|
| 69 |
export const AIEngine = {
|
|
@@ -104,7 +114,7 @@ export const AIEngine = {
|
|
| 104 |
model: "gpt",
|
| 105 |
prompt: fullPrompt,
|
| 106 |
system_prompt: systemPrompt,
|
| 107 |
-
images: images
|
| 108 |
})
|
| 109 |
});
|
| 110 |
|
|
@@ -137,7 +147,7 @@ export const AIEngine = {
|
|
| 137 |
|
| 138 |
return {
|
| 139 |
text: result.data,
|
| 140 |
-
usage: { totalTokenCount: 0 }
|
| 141 |
};
|
| 142 |
} catch (error) {
|
| 143 |
console.log("PM error: ",error);
|
|
@@ -165,7 +175,7 @@ export const AIEngine = {
|
|
| 165 |
|
| 166 |
return {
|
| 167 |
text: result.data,
|
| 168 |
-
usage: { totalTokenCount: 0 }
|
| 169 |
};
|
| 170 |
} catch (error) {
|
| 171 |
console.log("Worker error: ",error);
|
|
@@ -186,7 +196,11 @@ export const AIEngine = {
|
|
| 186 |
});
|
| 187 |
|
| 188 |
const result = await response.json();
|
| 189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
|
| 191 |
} catch (error) {
|
| 192 |
console.log("GenerateQ error: ",error)
|
|
@@ -206,7 +220,9 @@ export const AIEngine = {
|
|
| 206 |
});
|
| 207 |
|
| 208 |
const result = await response.json();
|
| 209 |
-
|
|
|
|
|
|
|
| 210 |
|
| 211 |
} catch (error) {
|
| 212 |
console.log("GenerateQ error: ",error)
|
|
|
|
| 20 |
return `System: ${systemPrompt}\n\n${context}\nUser: ${currentInput}\nAssistant:`;
|
| 21 |
};
|
| 22 |
|
| 23 |
+
// HELPER: STREAM SPLITTER & USAGE PARSER
|
| 24 |
const handleStreamResponse = async (response, onThink, onOutput) => {
|
| 25 |
if (!response.ok) throw new Error(`Stream Error: ${response.statusText}`);
|
| 26 |
|
| 27 |
const reader = response.body.getReader();
|
| 28 |
const decoder = new TextDecoder("utf-8");
|
| 29 |
|
|
|
|
| 30 |
let fullText = "";
|
| 31 |
+
let usage = { totalTokenCount: 0 }; // Default
|
| 32 |
|
| 33 |
while (true) {
|
| 34 |
const { done, value } = await reader.read();
|
| 35 |
if (done) break;
|
| 36 |
|
| 37 |
+
let chunk = decoder.decode(value, { stream: true });
|
| 38 |
+
|
| 39 |
+
// CHECK FOR USAGE FOOTER
|
| 40 |
+
if (chunk.includes("__USAGE__")) {
|
| 41 |
+
const parts = chunk.split("__USAGE__");
|
| 42 |
+
chunk = parts[0]; // The text part
|
| 43 |
+
try {
|
| 44 |
+
if (parts[1]) {
|
| 45 |
+
usage = JSON.parse(parts[1]);
|
| 46 |
+
}
|
| 47 |
+
} catch (e) {
|
| 48 |
+
console.warn("Failed to parse usage footer:", e);
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
|
| 52 |
+
// STANDARD CHUNK PROCESSING
|
| 53 |
if (chunk.startsWith("__THINK__")) {
|
| 54 |
const thoughtContent = chunk.replace("__THINK__", "");
|
| 55 |
if (onThink) onThink(thoughtContent);
|
| 56 |
}
|
|
|
|
| 57 |
else if (chunk.includes("__THINK__")) {
|
| 58 |
const parts = chunk.split("__THINK__");
|
|
|
|
|
|
|
| 59 |
if (parts[0]) {
|
| 60 |
if (onOutput) onOutput(parts[0]);
|
| 61 |
fullText += parts[0];
|
| 62 |
}
|
|
|
|
|
|
|
| 63 |
if (parts[1] && onThink) {
|
| 64 |
onThink(parts[1]);
|
| 65 |
}
|
| 66 |
}
|
|
|
|
| 67 |
else {
|
| 68 |
if (onOutput) onOutput(chunk);
|
| 69 |
fullText += chunk;
|
| 70 |
}
|
| 71 |
}
|
| 72 |
|
| 73 |
+
return {
|
| 74 |
+
text: fullText,
|
| 75 |
+
usage: usage
|
| 76 |
+
};
|
| 77 |
};
|
| 78 |
|
| 79 |
export const AIEngine = {
|
|
|
|
| 114 |
model: "gpt",
|
| 115 |
prompt: fullPrompt,
|
| 116 |
system_prompt: systemPrompt,
|
| 117 |
+
images: images
|
| 118 |
})
|
| 119 |
});
|
| 120 |
|
|
|
|
| 147 |
|
| 148 |
return {
|
| 149 |
text: result.data,
|
| 150 |
+
usage: result.usage || { totalTokenCount: 0 }
|
| 151 |
};
|
| 152 |
} catch (error) {
|
| 153 |
console.log("PM error: ",error);
|
|
|
|
| 175 |
|
| 176 |
return {
|
| 177 |
text: result.data,
|
| 178 |
+
usage: result.usage || { totalTokenCount: 0 }
|
| 179 |
};
|
| 180 |
} catch (error) {
|
| 181 |
console.log("Worker error: ",error);
|
|
|
|
| 196 |
});
|
| 197 |
|
| 198 |
const result = await response.json();
|
| 199 |
+
|
| 200 |
+
return {
|
| 201 |
+
...JSON.parse(result.data),
|
| 202 |
+
usage: result.usage || { totalTokenCount: 0 }
|
| 203 |
+
};
|
| 204 |
|
| 205 |
} catch (error) {
|
| 206 |
console.log("GenerateQ error: ",error)
|
|
|
|
| 220 |
});
|
| 221 |
|
| 222 |
const result = await response.json();
|
| 223 |
+
const parsed = JSON.parse(result.data);
|
| 224 |
+
parsed.usage = result.usage || { totalTokenCount: 0 };
|
| 225 |
+
return parsed;
|
| 226 |
|
| 227 |
} catch (error) {
|
| 228 |
console.log("GenerateQ error: ",error)
|