bluenevus commited on
Commit
195b95a
·
1 Parent(s): f6979f1

Update app.py via AI Editor

Browse files
Files changed (1) hide show
  1. app.py +96 -18
app.py CHANGED
@@ -49,6 +49,7 @@ def get_session_state(session_id):
49
  "created": datetime.datetime.utcnow().isoformat(),
50
  "streaming": False,
51
  "stream_buffer": "",
 
52
  }
53
  return SESSION_DATA[session_id]
54
 
@@ -149,7 +150,16 @@ def right_main_static():
149
  wrap="soft",
150
  maxLength=1000
151
  ),
152
- dbc.Button("Send", id="send-btn", color="primary", className="mt-2", style={"float": "right", "minWidth": "100px"}),
 
 
 
 
 
 
 
 
 
153
  ], style={"marginTop": "1rem"}),
154
  html.Div(id="error-message", style={"color": "#bb2124", "marginTop": "0.5rem"}),
155
  ])
@@ -190,15 +200,19 @@ def assign_session_id(_):
190
  Output("error-message", "children"),
191
  Output("stream-interval", "disabled"),
192
  Output("stream-interval", "n_intervals"),
 
193
  Input("session-id", "data"),
194
  Input("send-btn", "n_clicks"),
195
  Input("file-upload", "contents"),
 
196
  State("file-upload", "filename"),
197
  State("user-input", "value"),
 
198
  State("stream-interval", "n_intervals"),
 
199
  prevent_initial_call=False
200
  )
201
- def main_callback(session_id, send_clicks, file_contents, file_names, user_input, stream_n):
202
  trigger = callback_context.triggered[0]['prop_id'].split('.')[0] if callback_context.triggered else ""
203
  if not session_id:
204
  session_id = get_session_id()
@@ -209,6 +223,7 @@ def main_callback(session_id, send_clicks, file_contents, file_names, user_input
209
  error = ""
210
  start_streaming = False
211
 
 
212
  if trigger == "file-upload" and file_contents and file_names:
213
  uploads = []
214
  if not isinstance(file_contents, list):
@@ -228,6 +243,7 @@ def main_callback(session_id, send_clicks, file_contents, file_names, user_input
228
  save_session_state(session_id)
229
  logger.info(f"Session {session_id}: Uploaded files {[u['name'] for u in uploads]}")
230
 
 
231
  if trigger == "send-btn" and user_input and user_input.strip():
232
  state["messages"].append({"role": "user", "content": user_input})
233
  state["streaming"] = True
@@ -253,14 +269,12 @@ def main_callback(session_id, send_clicks, file_contents, file_names, user_input
253
  content = delta.get("content", "")
254
  if content:
255
  reply += content
256
- # Update buffer in session state
257
  session_lock = get_session_lock(session_id)
258
  with session_lock:
259
  load_session_state(session_id)
260
  state = get_session_state(session_id)
261
  state["stream_buffer"] = reply
262
  save_session_state(session_id)
263
- # Finalize message
264
  session_lock = get_session_lock(session_id)
265
  with session_lock:
266
  load_session_state(session_id)
@@ -283,22 +297,89 @@ def main_callback(session_id, send_clicks, file_contents, file_names, user_input
283
  threading.Thread(target=run_stream, args=(session_id, list(state["messages"])), daemon=True).start()
284
  start_streaming = True
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  chat_history = state.get("messages", [])
287
  uploads = state.get("uploads", [])
 
288
  upload_cards = [uploaded_file_card(os.path.basename(f["name"]), f["is_img"]) for f in uploads]
289
- chat_items = [html.Li(html.Span((msg['role'] + ": " + msg['content'])[:40] + ("..." if len(msg['content']) > 40 else ""), style={"fontSize": "0.92rem"})) for msg in chat_history[-6:]]
 
 
 
 
 
 
 
290
  chat_cards = []
291
- for i, msg in enumerate(chat_history):
292
- if msg['role'] == "user":
293
- chat_cards.append(chat_message_card(msg['content'], is_user=True))
294
- elif msg['role'] == "assistant":
295
- chat_cards.append(chat_message_card(msg['content'], is_user=False))
296
  if state.get("streaming", False):
297
- # Add a partial assistant message at the end
298
  if state.get("stream_buffer", ""):
299
  chat_cards.append(chat_message_card(state["stream_buffer"], is_user=False))
300
- return upload_cards, chat_items, chat_cards, error, False, 0 if not start_streaming else False, 0
301
- return upload_cards, chat_items, chat_cards, error, (not state.get("streaming", False)), 0
302
 
303
  @app.callback(
304
  Output("chat-window", "children"),
@@ -314,11 +395,8 @@ def poll_stream(n_intervals, session_id):
314
  state = get_session_state(session_id)
315
  chat_history = state.get("messages", [])
316
  chat_cards = []
317
- for i, msg in enumerate(chat_history):
318
- if msg['role'] == "user":
319
- chat_cards.append(chat_message_card(msg['content'], is_user=True))
320
- elif msg['role'] == "assistant":
321
- chat_cards.append(chat_message_card(msg['content'], is_user=False))
322
  if state.get("streaming", False):
323
  if state.get("stream_buffer", ""):
324
  chat_cards.append(chat_message_card(state["stream_buffer"], is_user=False))
 
49
  "created": datetime.datetime.utcnow().isoformat(),
50
  "streaming": False,
51
  "stream_buffer": "",
52
+ "chat_histories": []
53
  }
54
  return SESSION_DATA[session_id]
55
 
 
150
  wrap="soft",
151
  maxLength=1000
152
  ),
153
+ html.Div([
154
+ dbc.Button("Send", id="send-btn", color="primary", className="mt-2 me-2", style={"minWidth": "100px"}),
155
+ dbc.Button("New Chat", id="new-chat-btn", color="secondary", className="mt-2", style={"minWidth": "110px"}),
156
+ ], style={"float": "right", "display": "flex", "gap": "0.5rem"}),
157
+ dcc.Input(
158
+ id="chat-name-input",
159
+ placeholder="Enter chat name...",
160
+ type="text",
161
+ style={"width": "100%", "marginTop": "0.5rem", "display": "none"}
162
+ ),
163
  ], style={"marginTop": "1rem"}),
164
  html.Div(id="error-message", style={"color": "#bb2124", "marginTop": "0.5rem"}),
165
  ])
 
200
  Output("error-message", "children"),
201
  Output("stream-interval", "disabled"),
202
  Output("stream-interval", "n_intervals"),
203
+ Output("chat-name-input", "style"),
204
  Input("session-id", "data"),
205
  Input("send-btn", "n_clicks"),
206
  Input("file-upload", "contents"),
207
+ Input("new-chat-btn", "n_clicks"),
208
  State("file-upload", "filename"),
209
  State("user-input", "value"),
210
+ State("chat-name-input", "value"),
211
  State("stream-interval", "n_intervals"),
212
+ State("chat-name-input", "style"),
213
  prevent_initial_call=False
214
  )
215
+ def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, file_names, user_input, chat_name, stream_n, chat_name_style):
216
  trigger = callback_context.triggered[0]['prop_id'].split('.')[0] if callback_context.triggered else ""
217
  if not session_id:
218
  session_id = get_session_id()
 
223
  error = ""
224
  start_streaming = False
225
 
226
+ # Handle File Upload
227
  if trigger == "file-upload" and file_contents and file_names:
228
  uploads = []
229
  if not isinstance(file_contents, list):
 
243
  save_session_state(session_id)
244
  logger.info(f"Session {session_id}: Uploaded files {[u['name'] for u in uploads]}")
245
 
246
+ # Handle Send
247
  if trigger == "send-btn" and user_input and user_input.strip():
248
  state["messages"].append({"role": "user", "content": user_input})
249
  state["streaming"] = True
 
269
  content = delta.get("content", "")
270
  if content:
271
  reply += content
 
272
  session_lock = get_session_lock(session_id)
273
  with session_lock:
274
  load_session_state(session_id)
275
  state = get_session_state(session_id)
276
  state["stream_buffer"] = reply
277
  save_session_state(session_id)
 
278
  session_lock = get_session_lock(session_id)
279
  with session_lock:
280
  load_session_state(session_id)
 
297
  threading.Thread(target=run_stream, args=(session_id, list(state["messages"])), daemon=True).start()
298
  start_streaming = True
299
 
300
+ # Handle New Chat button logic
301
+ show_chat_name = chat_name_style if isinstance(chat_name_style, dict) else {}
302
+ if trigger == "new-chat-btn":
303
+ # If chat name input box is not yet visible, show it
304
+ if show_chat_name.get("display", "none") == "none":
305
+ show_chat_name["display"] = "block"
306
+ return (
307
+ [uploaded_file_card(os.path.basename(f["name"]), f["is_img"]) for f in state.get("uploads", [])],
308
+ [
309
+ html.Li(
310
+ html.Span(
311
+ chat["name"],
312
+ style={"fontSize": "0.92rem"}
313
+ )
314
+ ) for chat in state.get("chat_histories", [])[-6:]
315
+ ],
316
+ [
317
+ chat_message_card(msg['content'], is_user=(msg['role'] == "user"))
318
+ for msg in state.get("messages", [])
319
+ ] + (
320
+ [chat_message_card(state["stream_buffer"], is_user=False)]
321
+ if state.get("streaming", False) and state.get("stream_buffer", "") else []
322
+ ),
323
+ "",
324
+ not state.get("streaming", False),
325
+ 0,
326
+ show_chat_name
327
+ )
328
+ # If input box is visible and has a value, save chat history
329
+ else:
330
+ chat_dialog = list(state.get("messages", []))
331
+ if not chat_dialog:
332
+ error = "Cannot save empty chat."
333
+ else:
334
+ chat_title = chat_name if chat_name and chat_name.strip() else "Chat " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M")
335
+ state.setdefault("chat_histories", []).append({
336
+ "name": chat_title,
337
+ "dialog": chat_dialog
338
+ })
339
+ state["messages"] = []
340
+ state["stream_buffer"] = ""
341
+ state["streaming"] = False
342
+ save_session_state(session_id)
343
+ logger.info(f"Session {session_id}: Saved chat history '{chat_title}'")
344
+ show_chat_name["display"] = "none"
345
+ return (
346
+ [uploaded_file_card(os.path.basename(f["name"]), f["is_img"]) for f in state.get("uploads", [])],
347
+ [
348
+ html.Li(
349
+ html.Span(
350
+ chat["name"],
351
+ style={"fontSize": "0.92rem", "fontWeight": "bold"}
352
+ )
353
+ ) for chat in state.get("chat_histories", [])[-6:]
354
+ ],
355
+ [],
356
+ error,
357
+ not state.get("streaming", False),
358
+ 0,
359
+ show_chat_name
360
+ )
361
+
362
+ # Build Uploads, Chat History and Chat Window
363
  chat_history = state.get("messages", [])
364
  uploads = state.get("uploads", [])
365
+ chat_histories = state.get("chat_histories", [])
366
  upload_cards = [uploaded_file_card(os.path.basename(f["name"]), f["is_img"]) for f in uploads]
367
+ chat_history_items = [
368
+ html.Li(
369
+ html.Span(
370
+ chat["name"],
371
+ style={"fontSize": "0.92rem", "fontWeight": "bold" if i == len(chat_histories)-1 else "normal"}
372
+ )
373
+ ) for i, chat in enumerate(chat_histories[-6:])
374
+ ]
375
  chat_cards = []
376
+ for msg in chat_history:
377
+ chat_cards.append(chat_message_card(msg['content'], is_user=(msg['role'] == "user")))
 
 
 
378
  if state.get("streaming", False):
 
379
  if state.get("stream_buffer", ""):
380
  chat_cards.append(chat_message_card(state["stream_buffer"], is_user=False))
381
+ return upload_cards, chat_history_items, chat_cards, error, False, 0, show_chat_name
382
+ return upload_cards, chat_history_items, chat_cards, error, (not state.get("streaming", False)), 0, show_chat_name
383
 
384
  @app.callback(
385
  Output("chat-window", "children"),
 
395
  state = get_session_state(session_id)
396
  chat_history = state.get("messages", [])
397
  chat_cards = []
398
+ for msg in chat_history:
399
+ chat_cards.append(chat_message_card(msg['content'], is_user=(msg['role'] == "user")))
 
 
 
400
  if state.get("streaming", False):
401
  if state.get("stream_buffer", ""):
402
  chat_cards.append(chat_message_card(state["stream_buffer"], is_user=False))