Spaces:
Sleeping
Sleeping
Update aiEngine.js
Browse files- aiEngine.js +56 -26
aiEngine.js
CHANGED
|
@@ -38,7 +38,13 @@ export const AIEngine = {
|
|
| 38 |
config,
|
| 39 |
contents,
|
| 40 |
});
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
} catch (error) {
|
| 43 |
console.error("PM AI Error:", error);
|
| 44 |
throw error;
|
|
@@ -87,7 +93,13 @@ export const AIEngine = {
|
|
| 87 |
config,
|
| 88 |
contents,
|
| 89 |
});
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
} catch (error) {
|
| 92 |
console.error("Worker AI Error:", error);
|
| 93 |
throw error;
|
|
@@ -114,9 +126,17 @@ export const AIEngine = {
|
|
| 114 |
});
|
| 115 |
|
| 116 |
const text = response.text;
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
} catch (e) {
|
| 119 |
console.error("Analyst Error:", e);
|
|
|
|
| 120 |
return { status: "ACCEPTED", questions: [{ id: "fallback", label: "Please describe the core gameplay loop in detail.", type: "textarea" }] };
|
| 121 |
}
|
| 122 |
},
|
|
@@ -139,9 +159,18 @@ export const AIEngine = {
|
|
| 139 |
},
|
| 140 |
contents: [{ role: 'user', parts: [{ text: input }] }]
|
| 141 |
});
|
| 142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
} catch (e) {
|
| 144 |
console.error("Grading Error:", e);
|
|
|
|
| 145 |
return { feasibility: 80, rating: "B", title: "Untitled Project", summary: "Standard project structure detected." };
|
| 146 |
}
|
| 147 |
},
|
|
@@ -172,37 +201,38 @@ export const AIEngine = {
|
|
| 172 |
contents,
|
| 173 |
});
|
| 174 |
|
|
|
|
|
|
|
| 175 |
for await (const chunk of response) {
|
| 176 |
if (!chunk.candidates || !chunk.candidates[0].content || !chunk.candidates[0].content.parts) {
|
| 177 |
continue;
|
| 178 |
}
|
|
|
|
|
|
|
| 179 |
if (chunk.candidates?.[0]?.content?.parts?.[0]?.inlineData) {
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
const mimeType = inlineData.mimeType || "image/png";
|
| 190 |
-
|
| 191 |
-
// ensure it's a Buffer (optional, for validation)
|
| 192 |
-
const buffer = Buffer.from(rawB64, "base64");
|
| 193 |
-
|
| 194 |
-
// produce a canonical base64 string (this also validates)
|
| 195 |
-
const base64 = buffer.toString("base64");
|
| 196 |
-
|
| 197 |
-
// build a browser-friendly data URL and return it
|
| 198 |
-
const dataUrl = `data:${mimeType};base64,${base64}`;
|
| 199 |
-
return dataUrl;
|
| 200 |
-
|
| 201 |
}
|
| 202 |
}
|
| 203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
} catch (error) {
|
| 205 |
console.error("Image Gen Error:", error);
|
|
|
|
| 206 |
return null;
|
| 207 |
}
|
| 208 |
}
|
|
|
|
| 38 |
config,
|
| 39 |
contents,
|
| 40 |
});
|
| 41 |
+
|
| 42 |
+
// Return both text and usage metadata
|
| 43 |
+
return {
|
| 44 |
+
text: response.text,
|
| 45 |
+
usage: response.usageMetadata
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
} catch (error) {
|
| 49 |
console.error("PM AI Error:", error);
|
| 50 |
throw error;
|
|
|
|
| 93 |
config,
|
| 94 |
contents,
|
| 95 |
});
|
| 96 |
+
|
| 97 |
+
// Return both text and usage metadata
|
| 98 |
+
return {
|
| 99 |
+
text: response.text,
|
| 100 |
+
usage: response.usageMetadata
|
| 101 |
+
};
|
| 102 |
+
|
| 103 |
} catch (error) {
|
| 104 |
console.error("Worker AI Error:", error);
|
| 105 |
throw error;
|
|
|
|
| 126 |
});
|
| 127 |
|
| 128 |
const text = response.text;
|
| 129 |
+
const parsed = JSON.parse(text);
|
| 130 |
+
|
| 131 |
+
// Attach usage to the JSON object
|
| 132 |
+
return {
|
| 133 |
+
...parsed,
|
| 134 |
+
usage: response.usageMetadata
|
| 135 |
+
};
|
| 136 |
+
|
| 137 |
} catch (e) {
|
| 138 |
console.error("Analyst Error:", e);
|
| 139 |
+
// On failure, we don't return usage, so no charge applies
|
| 140 |
return { status: "ACCEPTED", questions: [{ id: "fallback", label: "Please describe the core gameplay loop in detail.", type: "textarea" }] };
|
| 141 |
}
|
| 142 |
},
|
|
|
|
| 159 |
},
|
| 160 |
contents: [{ role: 'user', parts: [{ text: input }] }]
|
| 161 |
});
|
| 162 |
+
|
| 163 |
+
const parsed = JSON.parse(response.text);
|
| 164 |
+
|
| 165 |
+
// Attach usage to the JSON object
|
| 166 |
+
return {
|
| 167 |
+
...parsed,
|
| 168 |
+
usage: response.usageMetadata
|
| 169 |
+
};
|
| 170 |
+
|
| 171 |
} catch (e) {
|
| 172 |
console.error("Grading Error:", e);
|
| 173 |
+
// On failure, no usage returned
|
| 174 |
return { feasibility: 80, rating: "B", title: "Untitled Project", summary: "Standard project structure detected." };
|
| 175 |
}
|
| 176 |
},
|
|
|
|
| 201 |
contents,
|
| 202 |
});
|
| 203 |
|
| 204 |
+
let finalDataUrl = null;
|
| 205 |
+
|
| 206 |
for await (const chunk of response) {
|
| 207 |
if (!chunk.candidates || !chunk.candidates[0].content || !chunk.candidates[0].content.parts) {
|
| 208 |
continue;
|
| 209 |
}
|
| 210 |
+
|
| 211 |
+
// Capture image data if present
|
| 212 |
if (chunk.candidates?.[0]?.content?.parts?.[0]?.inlineData) {
|
| 213 |
+
const inlineData = chunk.candidates[0].content.parts[0].inlineData;
|
| 214 |
+
const rawB64 = (inlineData.data || "").replace(/\s+/g, "");
|
| 215 |
+
const mimeType = inlineData.mimeType || "image/png";
|
| 216 |
+
const buffer = Buffer.from(rawB64, "base64");
|
| 217 |
+
const base64 = buffer.toString("base64");
|
| 218 |
+
|
| 219 |
+
finalDataUrl = `data:${mimeType};base64,${base64}`;
|
| 220 |
+
// We do NOT return here immediately, we continue to allow the stream to finish
|
| 221 |
+
// so we can access the aggregated usage metadata at the end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
}
|
| 223 |
}
|
| 224 |
+
|
| 225 |
+
// Retrieve the full response object to get usage metadata
|
| 226 |
+
const aggregatedResponse = await response.response;
|
| 227 |
+
|
| 228 |
+
return {
|
| 229 |
+
image: finalDataUrl,
|
| 230 |
+
usage: aggregatedResponse.usageMetadata
|
| 231 |
+
};
|
| 232 |
+
|
| 233 |
} catch (error) {
|
| 234 |
console.error("Image Gen Error:", error);
|
| 235 |
+
// On failure, return null (logic in backend handles null as no-op)
|
| 236 |
return null;
|
| 237 |
}
|
| 238 |
}
|