bluenevus commited on
Commit
3482478
·
1 Parent(s): 998c37c

Update app.py via AI Editor

Browse files
Files changed (1) hide show
  1. app.py +59 -81
app.py CHANGED
@@ -178,25 +178,29 @@ def right_main_static():
178
  return html.Div([
179
  dbc.Card([
180
  dbc.CardBody([
181
- html.Div(id="chat-window", style={"minHeight": "60vh", "display": "flex", "flexDirection": "column", "justifyContent": "flex-end"}),
 
 
 
 
 
 
 
 
 
182
  html.Div([
183
  dcc.Textarea(
184
  id="user-input",
185
  placeholder="Type your question...",
186
  style={"width": "100%", "height": "60px", "resize": "vertical", "wordWrap": "break-word"},
187
  wrap="soft",
188
- maxLength=1000
 
189
  ),
190
  html.Div([
191
  dbc.Button("Send", id="send-btn", color="primary", className="mt-2 me-2", style={"minWidth": "100px"}),
192
  dbc.Button("New Chat", id="new-chat-btn", color="secondary", className="mt-2", style={"minWidth": "110px"}),
193
  ], style={"float": "right", "display": "flex", "gap": "0.5rem"}),
194
- dcc.Input(
195
- id="chat-name-input",
196
- placeholder="Enter chat name...",
197
- type="text",
198
- style={"width": "100%", "marginTop": "0.5rem", "display": "none"}
199
- ),
200
  ], style={"marginTop": "1rem"}),
201
  html.Div(id="error-message", style={"color": "#bb2124", "marginTop": "0.5rem"}),
202
  ])
@@ -211,7 +215,9 @@ app.layout = html.Div([
211
  html.Div([
212
  html.Div(left_navbar_static(), id='left-navbar', style={"width": "30vw", "height": "100vh", "position": "fixed", "left": 0, "top": 0, "zIndex": 2, "overflowY": "auto"}),
213
  html.Div(right_main_static(), id='right-main', style={"marginLeft": "30vw", "width": "70vw", "overflowY": "auto"})
214
- ], style={"display": "flex"})
 
 
215
  ])
216
 
217
  def _is_supported_doc(filename):
@@ -237,7 +243,7 @@ def assign_session_id(_):
237
  Output("error-message", "children"),
238
  Output("stream-interval", "disabled"),
239
  Output("stream-interval", "n_intervals"),
240
- Output("chat-name-input", "style"),
241
  Input("session-id", "data"),
242
  Input("send-btn", "n_clicks"),
243
  Input("file-upload", "contents"),
@@ -245,11 +251,9 @@ def assign_session_id(_):
245
  Input("stream-interval", "n_intervals"),
246
  State("file-upload", "filename"),
247
  State("user-input", "value"),
248
- State("chat-name-input", "value"),
249
- State("chat-name-input", "style"),
250
  prevent_initial_call=False
251
  )
252
- def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, stream_n, file_names, user_input, chat_name, chat_name_style):
253
  trigger = callback_context.triggered[0]['prop_id'].split('.')[0] if callback_context.triggered else ""
254
  if not session_id:
255
  session_id = get_session_id()
@@ -334,72 +338,22 @@ def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, strea
334
  threading.Thread(target=run_stream, args=(session_id, list(state["messages"])), daemon=True).start()
335
  start_streaming = True
336
 
337
- # Handle New Chat button logic
338
- show_chat_name = chat_name_style if isinstance(chat_name_style, dict) else {}
339
  if trigger == "new-chat-btn":
340
- # If chat name input box is not yet visible, show it
341
- if show_chat_name.get("display", "none") == "none":
342
- show_chat_name["display"] = "block"
343
- upload_cards = [uploaded_file_card(os.path.basename(f["name"]), f["is_img"]) for f in state.get("uploads", [])]
344
- chat_history_items = [
345
- html.Li(
346
- html.Span(
347
- chat["name"],
348
- style={"fontSize": "0.92rem"}
349
- )
350
- ) for chat in state.get("chat_histories", [])[-6:]
351
- ]
352
- chat_cards = [
353
- chat_message_card(msg['content'], is_user=(msg['role'] == "user"))
354
- for msg in state.get("messages", [])
355
- ] + (
356
- [chat_message_card(state["stream_buffer"], is_user=False)]
357
- if state.get("streaming", False) and state.get("stream_buffer", "") else []
358
- )
359
- return (
360
- upload_cards,
361
- chat_history_items,
362
- chat_cards,
363
- "",
364
- not state.get("streaming", False),
365
- 0,
366
- show_chat_name
367
- )
368
- # If input box is visible and has a value, save chat history
369
  else:
370
- chat_dialog = list(state.get("messages", []))
371
- if not chat_dialog:
372
- error = "Cannot save empty chat."
373
- else:
374
- chat_title = chat_name if chat_name and chat_name.strip() else "Chat " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M")
375
- state.setdefault("chat_histories", []).append({
376
- "name": chat_title,
377
- "dialog": chat_dialog
378
- })
379
- state["messages"] = []
380
- state["stream_buffer"] = ""
381
- state["streaming"] = False
382
- save_session_state(session_id)
383
- logger.info(f"Session {session_id}: Saved chat history '{chat_title}'")
384
- show_chat_name["display"] = "none"
385
- upload_cards = [uploaded_file_card(os.path.basename(f["name"]), f["is_img"]) for f in state.get("uploads", [])]
386
- chat_history_items = [
387
- html.Li(
388
- html.Span(
389
- chat["name"],
390
- style={"fontSize": "0.92rem", "fontWeight": "bold"}
391
- )
392
- ) for chat in state.get("chat_histories", [])[-6:]
393
- ]
394
- return (
395
- upload_cards,
396
- chat_history_items,
397
- [],
398
- error,
399
- not state.get("streaming", False),
400
- 0,
401
- show_chat_name
402
- )
403
 
404
  # Handle polling for streaming
405
  if trigger == "stream-interval":
@@ -426,7 +380,7 @@ def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, strea
426
  "",
427
  False,
428
  stream_n+1,
429
- chat_name_style
430
  )
431
  else:
432
  chat_cards = []
@@ -448,7 +402,7 @@ def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, strea
448
  "",
449
  True,
450
  0,
451
- chat_name_style
452
  )
453
 
454
  # Default: Build Uploads, Chat History and Chat Window
@@ -470,8 +424,32 @@ def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, strea
470
  if state.get("streaming", False):
471
  if state.get("stream_buffer", ""):
472
  chat_cards.append(chat_message_card(state["stream_buffer"], is_user=False))
473
- return upload_cards, chat_history_items, chat_cards, error, False, 0, chat_name_style
474
- return upload_cards, chat_history_items, chat_cards, error, (not state.get("streaming", False)), 0, chat_name_style
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
 
476
  @app_flask.after_request
477
  def set_session_cookie(resp):
 
178
  return html.Div([
179
  dbc.Card([
180
  dbc.CardBody([
181
+ html.Div(id="chat-window", style={
182
+ "height": "60vh",
183
+ "overflowY": "auto",
184
+ "display": "flex",
185
+ "flexDirection": "column",
186
+ "justifyContent": "flex-end",
187
+ "backgroundColor": "#fff",
188
+ "padding": "0.5rem",
189
+ "borderRadius": "0.5rem"
190
+ }),
191
  html.Div([
192
  dcc.Textarea(
193
  id="user-input",
194
  placeholder="Type your question...",
195
  style={"width": "100%", "height": "60px", "resize": "vertical", "wordWrap": "break-word"},
196
  wrap="soft",
197
+ maxLength=1000,
198
+ autoFocus=True
199
  ),
200
  html.Div([
201
  dbc.Button("Send", id="send-btn", color="primary", className="mt-2 me-2", style={"minWidth": "100px"}),
202
  dbc.Button("New Chat", id="new-chat-btn", color="secondary", className="mt-2", style={"minWidth": "110px"}),
203
  ], style={"float": "right", "display": "flex", "gap": "0.5rem"}),
 
 
 
 
 
 
204
  ], style={"marginTop": "1rem"}),
205
  html.Div(id="error-message", style={"color": "#bb2124", "marginTop": "0.5rem"}),
206
  ])
 
215
  html.Div([
216
  html.Div(left_navbar_static(), id='left-navbar', style={"width": "30vw", "height": "100vh", "position": "fixed", "left": 0, "top": 0, "zIndex": 2, "overflowY": "auto"}),
217
  html.Div(right_main_static(), id='right-main', style={"marginLeft": "30vw", "width": "70vw", "overflowY": "auto"})
218
+ ], style={"display": "flex"}),
219
+ dcc.Store(id="clear-input", data=False),
220
+ dcc.Store(id="scroll-bottom", data=0)
221
  ])
222
 
223
  def _is_supported_doc(filename):
 
243
  Output("error-message", "children"),
244
  Output("stream-interval", "disabled"),
245
  Output("stream-interval", "n_intervals"),
246
+ Output("user-input", "value"),
247
  Input("session-id", "data"),
248
  Input("send-btn", "n_clicks"),
249
  Input("file-upload", "contents"),
 
251
  Input("stream-interval", "n_intervals"),
252
  State("file-upload", "filename"),
253
  State("user-input", "value"),
 
 
254
  prevent_initial_call=False
255
  )
256
+ def main_callback(session_id, send_clicks, file_contents, new_chat_clicks, stream_n, file_names, user_input):
257
  trigger = callback_context.triggered[0]['prop_id'].split('.')[0] if callback_context.triggered else ""
258
  if not session_id:
259
  session_id = get_session_id()
 
338
  threading.Thread(target=run_stream, args=(session_id, list(state["messages"])), daemon=True).start()
339
  start_streaming = True
340
 
341
+ # Handle New Chat button logic: auto-name and reset
 
342
  if trigger == "new-chat-btn":
343
+ chat_dialog = list(state.get("messages", []))
344
+ if not chat_dialog:
345
+ error = "No chat to save. Start chatting!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  else:
347
+ chat_title = "Chat " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M")
348
+ state.setdefault("chat_histories", []).append({
349
+ "name": chat_title,
350
+ "dialog": chat_dialog
351
+ })
352
+ state["messages"] = []
353
+ state["stream_buffer"] = ""
354
+ state["streaming"] = False
355
+ save_session_state(session_id)
356
+ logger.info(f"Session {session_id}: Saved chat history '{chat_title}'")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
  # Handle polling for streaming
359
  if trigger == "stream-interval":
 
380
  "",
381
  False,
382
  stream_n+1,
383
+ ""
384
  )
385
  else:
386
  chat_cards = []
 
402
  "",
403
  True,
404
  0,
405
+ ""
406
  )
407
 
408
  # Default: Build Uploads, Chat History and Chat Window
 
424
  if state.get("streaming", False):
425
  if state.get("stream_buffer", ""):
426
  chat_cards.append(chat_message_card(state["stream_buffer"], is_user=False))
427
+ return upload_cards, chat_history_items, chat_cards, error, False, 0, ""
428
+ # Always clear input after send
429
+ if trigger == "send-btn":
430
+ return upload_cards, chat_history_items, chat_cards, error, (not state.get("streaming", False)), 0, ""
431
+ return upload_cards, chat_history_items, chat_cards, error, (not state.get("streaming", False)), 0, user_input or ""
432
+
433
+ # Clientside callback for pressing Enter to send
434
+ app.clientside_callback(
435
+ """
436
+ function(n_clicks) {
437
+ var ta = document.getElementById('user-input');
438
+ if (ta) {
439
+ ta.addEventListener('keydown', function(e) {
440
+ if (e.key === 'Enter' && !e.shiftKey) {
441
+ e.preventDefault();
442
+ var sendBtn = document.getElementById('send-btn');
443
+ if(sendBtn){sendBtn.click();}
444
+ }
445
+ }, {once: true});
446
+ }
447
+ return window.dash_clientside.no_update;
448
+ }
449
+ """,
450
+ Output('user-input', 'value'),
451
+ [Input('send-btn', 'n_clicks')]
452
+ )
453
 
454
  @app_flask.after_request
455
  def set_session_cookie(resp):