everydaycats commited on
Commit
9e7d11c
·
verified ·
1 Parent(s): 8086716

Update aiEngine.js

Browse files
Files changed (1) hide show
  1. aiEngine.js +56 -26
aiEngine.js CHANGED
@@ -38,7 +38,13 @@ export const AIEngine = {
38
  config,
39
  contents,
40
  });
41
- return response.text;
 
 
 
 
 
 
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
- return response.text;
 
 
 
 
 
 
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
- return JSON.parse(text);
 
 
 
 
 
 
 
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
- return JSON.parse(response.text);
 
 
 
 
 
 
 
 
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
- /* const inlineData = chunk.candidates[0].content.parts[0].inlineData;
181
- const rawB64 = (inlineData.data || "").replace(/\s+/g, "");
182
- // Return raw Base64
183
- return rawB64;
184
- */
185
-
186
- // inlineData is the object from the model: { mimeType: 'image/png', data: '...base64...' }
187
- const inlineData = chunk.candidates[0].content.parts[0].inlineData;
188
- const rawB64 = (inlineData.data || "").replace(/\s+/g, ""); // remove whitespace/newlines just in case
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
- return null;
 
 
 
 
 
 
 
 
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
  }