Pepguy commited on
Commit
dbc06fe
·
verified ·
1 Parent(s): 9db3fad

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +52 -12
app.js CHANGED
@@ -53,12 +53,18 @@ async function initDB() {
53
  console.log('✅ Connected to Supabase');
54
  if (dbChats) {
55
  dbChats.forEach(c => {
56
- memoryChats[c.id] = { ...c, isGenerating: false };
 
 
 
 
 
 
57
  });
58
  console.log(`✅ Hydrated ${dbChats.length} chats from DB.`);
59
  }
60
 
61
- // Sync to DB every 15 seconds (occasional sync)
62
  setInterval(async () => {
63
  if (dirtyChats.size === 0) return;
64
  const toSync = Array.from(dirtyChats);
@@ -71,6 +77,8 @@ async function initDB() {
71
  id: chat.id,
72
  title: chat.title,
73
  totalTokens: chat.totalTokens,
 
 
74
  messages: chat.messages,
75
  updatedAt: chat.updatedAt
76
  };
@@ -97,7 +105,12 @@ initDB();
97
  // Get all chats (Sidebar)
98
  app.get('/api/chats', (req, res) => {
99
  const chatsList = Object.values(memoryChats).map(c => ({
100
- id: c.id, title: c.title, totalTokens: c.totalTokens, updatedAt: c.updatedAt
 
 
 
 
 
101
  })).sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
102
  res.json(chatsList);
103
  });
@@ -116,6 +129,8 @@ app.post('/api/chats', (req, res) => {
116
  id: newId,
117
  title: "New Chat",
118
  totalTokens: 0,
 
 
119
  messages:[],
120
  isGenerating: false,
121
  updatedAt: new Date().toISOString()
@@ -124,6 +139,20 @@ app.post('/api/chats', (req, res) => {
124
  res.json(memoryChats[newId]);
125
  });
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  // Delete chat permanently
128
  app.delete('/api/chats/:id', async (req, res) => {
129
  const { id } = req.params;
@@ -141,12 +170,12 @@ app.post('/api/chats/:id/stream', async (req, res) => {
141
 
142
  if (!memoryChats[id]) return res.status(404).send("Chat not found");
143
 
144
- // Title generation on first message
145
- if (memoryChats[id].messages.length === 0) {
146
  memoryChats[id].title = prompt.substring(0, 30) + (prompt.length > 30 ? '...' : '');
147
  }
148
 
149
- // 1. SAVE TO MEMORY (Images excluded from storage to save DB space)
150
  memoryChats[id].messages.push({ role: "user", content: prompt });
151
 
152
  const aiMessage = { role: "assistant", content: "", reasoning: "" };
@@ -160,7 +189,9 @@ app.post('/api/chats/:id/stream', async (req, res) => {
160
  res.setHeader('X-Accel-Buffering', 'no');
161
  res.flushHeaders();
162
 
163
- let totalTokenCount = 0;
 
 
164
 
165
  try {
166
  const bedrockModelId = getBedrockModelId(model);
@@ -175,7 +206,7 @@ app.post('/api/chats/:id/stream', async (req, res) => {
175
  contentBlock = [...imageBlocks, ...contentBlock];
176
  }
177
 
178
- // Map history for Bedrock (excluding the newly pushed user message which we manually constructed)
179
  const historicalMessages = memoryChats[id].messages.slice(0, -2).map(m => ({
180
  role: m.role, content:[{ text: m.content }]
181
  }));
@@ -207,16 +238,25 @@ app.post('/api/chats/:id/stream', async (req, res) => {
207
  }
208
  }
209
  if (chunk.metadata && chunk.metadata.usage) {
210
- totalTokenCount = (chunk.metadata.usage.inputTokens || 0) + (chunk.metadata.usage.outputTokens || 0);
 
 
211
  }
212
  }
213
 
214
- // Clean up & finalize memory
215
- memoryChats[id].totalTokens += totalTokenCount;
 
 
216
  memoryChats[id].isGenerating = false;
217
  dirtyChats.add(id);
218
 
219
- res.write(`__USAGE__${JSON.stringify({ totalTokenCount })}`);
 
 
 
 
 
220
  res.end();
221
 
222
  } catch (err) {
 
53
  console.log('✅ Connected to Supabase');
54
  if (dbChats) {
55
  dbChats.forEach(c => {
56
+ // Ensure legacy chats don't crash if they lack the new columns
57
+ memoryChats[c.id] = {
58
+ ...c,
59
+ inputTokens: c.inputTokens || 0,
60
+ outputTokens: c.outputTokens || 0,
61
+ isGenerating: false
62
+ };
63
  });
64
  console.log(`✅ Hydrated ${dbChats.length} chats from DB.`);
65
  }
66
 
67
+ // Sync to DB every 15 seconds
68
  setInterval(async () => {
69
  if (dirtyChats.size === 0) return;
70
  const toSync = Array.from(dirtyChats);
 
77
  id: chat.id,
78
  title: chat.title,
79
  totalTokens: chat.totalTokens,
80
+ inputTokens: chat.inputTokens,
81
+ outputTokens: chat.outputTokens,
82
  messages: chat.messages,
83
  updatedAt: chat.updatedAt
84
  };
 
105
  // Get all chats (Sidebar)
106
  app.get('/api/chats', (req, res) => {
107
  const chatsList = Object.values(memoryChats).map(c => ({
108
+ id: c.id,
109
+ title: c.title,
110
+ totalTokens: c.totalTokens,
111
+ inputTokens: c.inputTokens,
112
+ outputTokens: c.outputTokens,
113
+ updatedAt: c.updatedAt
114
  })).sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
115
  res.json(chatsList);
116
  });
 
129
  id: newId,
130
  title: "New Chat",
131
  totalTokens: 0,
132
+ inputTokens: 0,
133
+ outputTokens: 0,
134
  messages:[],
135
  isGenerating: false,
136
  updatedAt: new Date().toISOString()
 
139
  res.json(memoryChats[newId]);
140
  });
141
 
142
+ // Update chat title manually
143
+ app.put('/api/chats/:id/title', (req, res) => {
144
+ const { id } = req.params;
145
+ const { title } = req.body;
146
+
147
+ if (!memoryChats[id]) return res.status(404).json({ error: "Chat not found" });
148
+ if (!title || typeof title !== 'string') return res.status(400).json({ error: "Invalid title" });
149
+
150
+ memoryChats[id].title = title.trim();
151
+ dirtyChats.add(id);
152
+
153
+ res.json({ success: true, title: memoryChats[id].title });
154
+ });
155
+
156
  // Delete chat permanently
157
  app.delete('/api/chats/:id', async (req, res) => {
158
  const { id } = req.params;
 
170
 
171
  if (!memoryChats[id]) return res.status(404).send("Chat not found");
172
 
173
+ // Title generation ONLY if it hasn't been manually renamed from defaults
174
+ if (memoryChats[id].messages.length === 0 && memoryChats[id].title === "New Chat") {
175
  memoryChats[id].title = prompt.substring(0, 30) + (prompt.length > 30 ? '...' : '');
176
  }
177
 
178
+ // 1. SAVE TO MEMORY
179
  memoryChats[id].messages.push({ role: "user", content: prompt });
180
 
181
  const aiMessage = { role: "assistant", content: "", reasoning: "" };
 
189
  res.setHeader('X-Accel-Buffering', 'no');
190
  res.flushHeaders();
191
 
192
+ let streamInputTokens = 0;
193
+ let streamOutputTokens = 0;
194
+ let streamTotalTokens = 0;
195
 
196
  try {
197
  const bedrockModelId = getBedrockModelId(model);
 
206
  contentBlock = [...imageBlocks, ...contentBlock];
207
  }
208
 
209
+ // Map history for Bedrock
210
  const historicalMessages = memoryChats[id].messages.slice(0, -2).map(m => ({
211
  role: m.role, content:[{ text: m.content }]
212
  }));
 
238
  }
239
  }
240
  if (chunk.metadata && chunk.metadata.usage) {
241
+ streamInputTokens = chunk.metadata.usage.inputTokens || 0;
242
+ streamOutputTokens = chunk.metadata.usage.outputTokens || 0;
243
+ streamTotalTokens = streamInputTokens + streamOutputTokens;
244
  }
245
  }
246
 
247
+ // Clean up & finalize memory with granular token usage
248
+ memoryChats[id].inputTokens += streamInputTokens;
249
+ memoryChats[id].outputTokens += streamOutputTokens;
250
+ memoryChats[id].totalTokens += streamTotalTokens;
251
  memoryChats[id].isGenerating = false;
252
  dirtyChats.add(id);
253
 
254
+ // Send granular usage to frontend
255
+ res.write(`__USAGE__${JSON.stringify({
256
+ inputTokens: streamInputTokens,
257
+ outputTokens: streamOutputTokens,
258
+ totalTokens: streamTotalTokens
259
+ })}`);
260
  res.end();
261
 
262
  } catch (err) {