uumerrr684 commited on
Commit
9b14533
Β·
verified Β·
1 Parent(s): af3360e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -428
app.py CHANGED
@@ -10,352 +10,44 @@ import uuid
10
  st.set_page_config(
11
  page_title="Chat Flow πŸ•·",
12
  page_icon="πŸ’¬",
13
- initial_sidebar_state="collapsed",
14
- layout="wide"
15
  )
16
 
17
- # Dark theme CSS matching the BuildHub design
18
  st.markdown("""
19
  <style>
20
- /* Import Google Fonts for modern typography */
21
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
22
-
23
- /* Main app dark theme */
24
  .stApp {
25
- background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
26
- font-family: 'Inter', sans-serif;
27
- color: #ffffff;
28
  }
29
 
30
- /* Container styling */
31
  .main .block-container {
32
- max-width: 1200px;
33
- padding: 2rem;
34
  }
35
 
36
- /* Hide Streamlit elements */
37
  #MainMenu {visibility: hidden;}
38
  footer {visibility: hidden;}
39
  header {visibility: hidden;}
40
  .stDeployButton {display: none;}
41
 
42
- /* Dark sidebar with golden accents */
43
- .css-1d391kg {
44
- background: linear-gradient(180deg, #1f1f1f 0%, #2a2a2a 100%);
45
- border-right: 1px solid #333;
46
- padding: 1rem;
47
- }
48
-
49
- .css-1d391kg .stMarkdown {
50
- color: #ffffff;
51
- }
52
-
53
- /* Title styling with golden accent */
54
- h1 {
55
- color: #ffd700;
56
- font-weight: 700;
57
- font-size: 2.5rem;
58
- text-align: center;
59
- margin-bottom: 0.5rem;
60
- text-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
61
- }
62
-
63
- .stCaption {
64
- color: #cccccc;
65
- text-align: center;
66
- font-size: 1.1rem;
67
- margin-bottom: 2rem;
68
- }
69
-
70
- /* Chat messages with modern dark styling */
71
- [data-testid="chat-message-user"] {
72
- background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
73
- color: #1a1a1a;
74
- border-radius: 20px;
75
- padding: 1rem 1.5rem;
76
- margin: 1rem 0;
77
- margin-left: 20%;
78
- box-shadow: 0 4px 15px rgba(255, 215, 0, 0.2);
79
- border: 1px solid rgba(255, 215, 0, 0.3);
80
- }
81
-
82
- [data-testid="chat-message-user"] .stMarkdown {
83
- color: #1a1a1a;
84
- font-weight: 500;
85
- }
86
-
87
- [data-testid="chat-message-assistant"] {
88
- background: linear-gradient(135deg, #2a2a2a 0%, #3a3a3a 100%);
89
- color: #ffffff;
90
- border-radius: 20px;
91
- padding: 1rem 1.5rem;
92
- margin: 1rem 0;
93
- margin-right: 20%;
94
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
95
- border: 1px solid #444;
96
- }
97
-
98
- [data-testid="chat-message-assistant"] .stMarkdown {
99
- color: #ffffff;
100
- }
101
-
102
- /* Chat input with dark theme */
103
- .stChatInput {
104
- background: linear-gradient(135deg, #2a2a2a 0%, #3a3a3a 100%);
105
- border-radius: 25px;
106
- border: 1px solid #444;
107
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
108
- }
109
-
110
- .stChatInput input {
111
- background: transparent;
112
- color: #ffffff;
113
- border: none;
114
- font-size: 16px;
115
- padding: 1rem 1.5rem;
116
- }
117
-
118
- .stChatInput input::placeholder {
119
- color: #888;
120
- }
121
-
122
- /* Sidebar sections */
123
- .css-1d391kg h1, .css-1d391kg h2, .css-1d391kg h3 {
124
- color: #ffd700;
125
- font-weight: 600;
126
- }
127
-
128
- /* Status indicators with golden theme */
129
- .stSuccess {
130
- background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
131
- color: #1a1a1a;
132
- border: none;
133
- border-radius: 10px;
134
- }
135
-
136
- .stInfo {
137
- background: linear-gradient(135deg, #4a90e2 0%, #357abd 100%);
138
- color: #ffffff;
139
- border: none;
140
- border-radius: 10px;
141
- }
142
-
143
- .stError {
144
- background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%);
145
- color: #ffffff;
146
- border: none;
147
- border-radius: 10px;
148
- }
149
-
150
- .stWarning {
151
- background: linear-gradient(135deg, #ffa726 0%, #ff9800 100%);
152
- color: #1a1a1a;
153
- border: none;
154
- border-radius: 10px;
155
- }
156
-
157
- /* Buttons with golden accent */
158
- .stButton button {
159
- background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
160
- color: #1a1a1a;
161
- border: none;
162
- border-radius: 12px;
163
- font-weight: 600;
164
- padding: 0.75rem 1.5rem;
165
- transition: all 0.3s ease;
166
- box-shadow: 0 2px 10px rgba(255, 215, 0, 0.2);
167
- }
168
-
169
- .stButton button:hover {
170
- transform: translateY(-2px);
171
- box-shadow: 0 4px 20px rgba(255, 215, 0, 0.4);
172
- }
173
-
174
- /* Secondary buttons */
175
- .stButton button[kind="secondary"] {
176
- background: linear-gradient(135deg, #444 0%, #555 100%);
177
- color: #ffffff;
178
- border: 1px solid #666;
179
- }
180
-
181
- .stButton button[kind="secondary"]:hover {
182
- background: linear-gradient(135deg, #555 0%, #666 100%);
183
- }
184
-
185
- /* Selectbox styling */
186
- .stSelectbox > div > div {
187
- background: linear-gradient(135deg, #2a2a2a 0%, #3a3a3a 100%);
188
- border: 1px solid #444;
189
- border-radius: 10px;
190
- color: #ffffff;
191
- }
192
-
193
- .stSelectbox > div > div:hover {
194
- border-color: #ffd700;
195
- }
196
-
197
- /* Checkbox styling */
198
- .stCheckbox > label {
199
- color: #ffffff;
200
- }
201
-
202
- /* Text areas */
203
- .stTextArea textarea {
204
- background: linear-gradient(135deg, #2a2a2a 0%, #3a3a3a 100%);
205
- color: #ffffff;
206
- border: 1px solid #444;
207
- border-radius: 10px;
208
- }
209
-
210
- /* Expander styling */
211
- .streamlit-expanderHeader {
212
- background: linear-gradient(135deg, #2a2a2a 0%, #3a3a3a 100%);
213
- color: #ffd700;
214
- border-radius: 10px;
215
- border: 1px solid #444;
216
- }
217
-
218
- .streamlit-expanderContent {
219
- background: #1f1f1f;
220
- border: 1px solid #333;
221
- border-radius: 0 0 10px 10px;
222
- }
223
-
224
- /* Model ID styling */
225
  .model-id {
226
- color: #ffd700;
227
- font-family: 'Courier New', monospace;
228
- font-weight: bold;
229
- background: rgba(255, 215, 0, 0.1);
230
- padding: 0.25rem 0.5rem;
231
- border-radius: 5px;
232
- border: 1px solid rgba(255, 215, 0, 0.3);
233
  }
234
 
235
  .model-attribution {
236
- color: #ffd700;
237
  font-size: 0.8em;
238
  font-style: italic;
239
- text-align: right;
240
- margin-top: 0.5rem;
241
- padding-top: 0.5rem;
242
- border-top: 1px solid #444;
243
- }
244
-
245
- /* Divider styling */
246
- hr {
247
- border-color: #444;
248
- margin: 1.5rem 0;
249
- }
250
-
251
- /* Download button */
252
- .stDownloadButton button {
253
- background: linear-gradient(135deg, #4a90e2 0%, #357abd 100%);
254
- color: #ffffff;
255
- border: none;
256
- border-radius: 10px;
257
- font-weight: 600;
258
- }
259
-
260
- /* Welcome message area */
261
- .welcome-container {
262
- display: flex;
263
- flex-direction: column;
264
- align-items: center;
265
- justify-content: center;
266
- min-height: 400px;
267
- text-align: center;
268
- }
269
-
270
- .welcome-orb {
271
- width: 120px;
272
- height: 120px;
273
- border-radius: 50%;
274
- background: radial-gradient(circle at 30% 30%, #ffd700, #ffed4e, #cc8400);
275
- display: flex;
276
- align-items: center;
277
- justify-content: center;
278
- margin-bottom: 2rem;
279
- box-shadow: 0 0 40px rgba(255, 215, 0, 0.3);
280
- animation: pulse 2s infinite;
281
- }
282
-
283
- @keyframes pulse {
284
- 0% { box-shadow: 0 0 40px rgba(255, 215, 0, 0.3); }
285
- 50% { box-shadow: 0 0 60px rgba(255, 215, 0, 0.5); }
286
- 100% { box-shadow: 0 0 40px rgba(255, 215, 0, 0.3); }
287
- }
288
-
289
- .welcome-title {
290
- font-size: 2rem;
291
- font-weight: 700;
292
- color: #ffd700;
293
- margin-bottom: 1rem;
294
- }
295
-
296
- .welcome-subtitle {
297
- font-size: 1.1rem;
298
- color: #cccccc;
299
- margin-bottom: 2rem;
300
- }
301
-
302
- /* Mobile responsiveness */
303
- @media (max-width: 768px) {
304
- .main .block-container {
305
- padding: 1rem 0.5rem;
306
- max-width: 100%;
307
- }
308
-
309
- h1 {
310
- font-size: 2rem;
311
- }
312
-
313
- [data-testid="chat-message-user"] {
314
- margin-left: 10%;
315
- padding: 0.75rem 1rem;
316
- }
317
-
318
- [data-testid="chat-message-assistant"] {
319
- margin-right: 10%;
320
- padding: 0.75rem 1rem;
321
- }
322
-
323
- .welcome-orb {
324
- width: 80px;
325
- height: 80px;
326
- }
327
-
328
- .welcome-title {
329
- font-size: 1.5rem;
330
- }
331
-
332
- .css-1d391kg {
333
- width: 100% !important;
334
- }
335
- }
336
-
337
- /* Extra small screens */
338
- @media (max-width: 480px) {
339
- [data-testid="chat-message-user"] {
340
- margin-left: 5%;
341
- }
342
-
343
- [data-testid="chat-message-assistant"] {
344
- margin-right: 5%;
345
- }
346
-
347
- .main .block-container {
348
- padding: 0.5rem 0.25rem;
349
- }
350
  }
351
  </style>
352
  """, unsafe_allow_html=True)
353
 
354
  # File to store chat history
355
  HISTORY_FILE = "chat_history.json"
356
- # File to store online users
357
  USERS_FILE = "online_users.json"
358
 
 
359
  def load_chat_history():
360
  """Load chat history from file"""
361
  try:
@@ -366,6 +58,7 @@ def load_chat_history():
366
  st.error(f"Error loading chat history: {e}")
367
  return []
368
 
 
369
  def save_chat_history(messages):
370
  """Save chat history to file"""
371
  try:
@@ -374,6 +67,7 @@ def save_chat_history(messages):
374
  except Exception as e:
375
  st.error(f"Error saving chat history: {e}")
376
 
 
377
  def clear_chat_history():
378
  """Clear chat history file"""
379
  try:
@@ -383,27 +77,33 @@ def clear_chat_history():
383
  except Exception as e:
384
  st.error(f"Error clearing chat history: {e}")
385
 
386
- # User tracking functions
 
 
387
  def get_user_id():
388
  """Get unique ID for this user session"""
389
  if 'user_id' not in st.session_state:
390
- st.session_state.user_id = str(uuid.uuid4())[:8]
 
391
  return st.session_state.user_id
392
 
 
393
  def update_online_users():
394
  """Update that this user is online right now"""
395
  try:
 
396
  users = {}
397
  if os.path.exists(USERS_FILE):
398
  with open(USERS_FILE, 'r') as f:
399
  users = json.load(f)
400
-
 
401
  user_id = get_user_id()
402
  users[user_id] = {
403
  'last_seen': datetime.now().isoformat(),
404
- 'name': f'User-{user_id}'
405
  }
406
-
407
  # Remove users not seen in last 5 minutes
408
  current_time = datetime.now()
409
  active_users = {}
@@ -411,34 +111,38 @@ def update_online_users():
411
  last_seen = datetime.fromisoformat(data['last_seen'])
412
  if current_time - last_seen < timedelta(minutes=5):
413
  active_users[uid] = data
414
-
 
415
  with open(USERS_FILE, 'w') as f:
416
  json.dump(active_users, f, indent=2)
417
-
418
  return len(active_users)
419
  except Exception:
420
- return 1
 
421
 
422
  def get_online_count():
423
  """Get number of people currently online"""
424
  try:
425
  if not os.path.exists(USERS_FILE):
426
  return 0
427
-
428
  with open(USERS_FILE, 'r') as f:
429
  users = json.load(f)
430
-
 
431
  current_time = datetime.now()
432
  active_count = 0
433
  for data in users.values():
434
  last_seen = datetime.fromisoformat(data['last_seen'])
435
  if current_time - last_seen < timedelta(minutes=5):
436
  active_count += 1
437
-
438
  return active_count
439
  except Exception:
440
  return 0
441
 
 
442
  # Initialize session state with saved history
443
  if "messages" not in st.session_state:
444
  st.session_state.messages = load_chat_history()
@@ -446,6 +150,7 @@ if "messages" not in st.session_state:
446
  # Get API key
447
  OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY")
448
 
 
449
  @st.cache_data(ttl=300)
450
  def check_api_status():
451
  if not OPENROUTER_API_KEY:
@@ -458,21 +163,24 @@ def check_api_status():
458
  except:
459
  return "Error"
460
 
 
461
  def get_ai_response(messages, model="openai/gpt-3.5-turbo"):
462
  if not OPENROUTER_API_KEY:
463
  return "No API key found. Please add OPENROUTER_API_KEY to environment variables."
464
-
465
  url = "https://openrouter.ai/api/v1/chat/completions"
466
  headers = {
467
  "Content-Type": "application/json",
468
  "Authorization": f"Bearer {OPENROUTER_API_KEY}",
469
- "HTTP-Referer": "http://localhost:8501",
470
- "X-Title": "Streamlit AI Assistant"
471
  }
472
-
473
- api_messages = [{"role": "system", "content": "You are a helpful AI assistant. Provide clear and helpful responses."}]
 
 
474
  api_messages.extend(messages)
475
-
476
  data = {
477
  "model": model,
478
  "messages": api_messages,
@@ -483,25 +191,31 @@ def get_ai_response(messages, model="openai/gpt-3.5-turbo"):
483
  "frequency_penalty": 0,
484
  "presence_penalty": 0
485
  }
486
-
487
  try:
488
- response = requests.post(url, headers=headers, json=data, stream=True, timeout=60)
489
-
 
 
490
  if response.status_code != 200:
491
  error_detail = ""
492
  try:
493
  error_data = response.json()
494
- error_detail = error_data.get('error', {}).get('message', f"HTTP {response.status_code}")
 
495
  except:
496
  error_detail = f"HTTP {response.status_code}: {response.reason}"
497
-
498
  yield f"API Error: {error_detail}. Please try a different model or check your API key."
499
  return
500
-
501
  full_response = ""
502
-
 
 
503
  for line in response.iter_lines():
504
  if line:
 
505
  if line.startswith(b"data: "):
506
  data_str = line[len(b"data: "):].decode("utf-8")
507
  if data_str.strip() == "[DONE]":
@@ -516,7 +230,7 @@ def get_ai_response(messages, model="openai/gpt-3.5-turbo"):
516
  continue
517
  except (KeyError, IndexError):
518
  continue
519
-
520
  except requests.exceptions.Timeout:
521
  yield "Request timed out. Please try again with a shorter message or different model."
522
  except requests.exceptions.ConnectionError:
@@ -526,41 +240,47 @@ def get_ai_response(messages, model="openai/gpt-3.5-turbo"):
526
  except Exception as e:
527
  yield f"Unexpected error: {str(e)}. Please try again or contact support."
528
 
 
529
  # Header
530
  st.title("Chat Flow πŸ•·")
531
  st.caption("10 powerful Models, one simple chat.")
532
 
533
  # Sidebar
534
  with st.sidebar:
535
- st.header("βš™οΈ Settings")
536
-
537
  # API Status
538
  status = check_api_status()
539
  if status == "Connected":
540
  st.success("🟒 API Connected")
541
  elif status == "No API Key":
542
- st.error("❌ No API Key")
543
  else:
544
- st.warning("⚠️ Connection Issue")
545
-
546
  st.divider()
547
-
548
- # Live Users Section
549
- st.header("πŸ‘₯ Live Users")
 
 
550
  online_count = update_online_users()
551
-
 
552
  if online_count == 1:
553
  st.info("🟒 Just you online")
554
  else:
555
  st.success(f"🟒 {online_count} people online")
556
-
 
557
  your_id = get_user_id()
558
  st.caption(f"You: User-{your_id}")
559
-
560
- if st.button("πŸ”„ Refresh", use_container_width=True):
 
561
  st.rerun()
562
-
563
- # Debug section
564
  with st.expander("πŸ” Debug Info"):
565
  if os.path.exists(USERS_FILE):
566
  with open(USERS_FILE, 'r') as f:
@@ -573,11 +293,11 @@ with st.sidebar:
573
  st.write(f"- {uid}: {minutes_ago} min ago")
574
  else:
575
  st.write("No users file yet")
576
-
 
577
  st.divider()
578
-
579
- # Model Selection
580
- st.header("πŸ€– AI Models")
581
  models = [
582
  ("GPT-3.5 Turbo", "openai/gpt-3.5-turbo"),
583
  ("LLaMA 3.1 8B", "meta-llama/llama-3.1-8b-instruct"),
@@ -590,125 +310,139 @@ with st.sidebar:
590
  ("Gemma 3 4B", "google/gemma-3-4b-it:free"),
591
  ("Auto (Best Available)", "openrouter/auto")
592
  ]
593
-
594
  model_names = [name for name, _ in models]
595
  model_ids = [model_id for _, model_id in models]
596
-
597
- selected_index = st.selectbox("Choose Model", range(len(model_names)),
598
- format_func=lambda x: model_names[x],
599
- index=0)
600
  selected_model = model_ids[selected_index]
601
-
602
- st.markdown(f"**Model ID:** <span class='model-id'>{selected_model}</span>", unsafe_allow_html=True)
603
-
 
 
604
  st.divider()
605
-
606
  # Chat History Controls
607
- st.header("πŸ’¬ Chat History")
608
-
 
609
  if st.session_state.messages:
610
- st.info(f"πŸ“ {len(st.session_state.messages)} messages stored")
611
-
 
612
  auto_save = st.checkbox("Auto-save messages", value=True)
613
-
 
614
  col1, col2 = st.columns(2)
615
  with col1:
616
- if st.button("πŸ’Ύ Save", use_container_width=True):
617
  save_chat_history(st.session_state.messages)
618
- st.success("Saved!")
619
-
620
  with col2:
621
- if st.button("πŸ“‚ Load", use_container_width=True):
622
  st.session_state.messages = load_chat_history()
623
- st.success("Loaded!")
624
  st.rerun()
625
-
626
- with st.expander("πŸ“‹ More Options"):
627
- if st.button("πŸ‘οΈ View History File", use_container_width=True):
628
- if os.path.exists(HISTORY_FILE):
629
- with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
630
- history_content = f.read()
631
- st.text_area("Chat History (JSON)", history_content, height=150)
632
- else:
633
- st.warning("No history file found")
634
-
635
  if os.path.exists(HISTORY_FILE):
636
- with open(HISTORY_FILE, 'rb') as f:
637
- st.download_button(
638
- label="⬇️ Download History",
639
- data=f.read(),
640
- file_name=f"chat_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
641
- mime="application/json",
642
- use_container_width=True
643
- )
644
-
645
- if st.button("πŸ—‘οΈ Clear Chat", use_container_width=True, type="secondary"):
646
- clear_chat_history()
647
- st.success("Chat cleared!")
648
- st.rerun()
 
 
 
649
 
650
- # Welcome message when no messages
651
- if not st.session_state.messages:
652
- st.markdown("""
653
- <div class="welcome-container">
654
- <div class="welcome-orb">
655
- <span style="font-size: 3rem;">πŸ•·</span>
656
- </div>
657
- <div class="welcome-title">Welcome back!</div>
658
- <div class="welcome-subtitle">Which AI model do you want to chat with today?</div>
659
- </div>
660
- """, unsafe_allow_html=True)
661
 
662
  # Display chat messages
663
  for message in st.session_state.messages:
664
  with st.chat_message(message["role"]):
 
665
  if message["role"] == "assistant" and "Response created by:" in message["content"]:
 
666
  parts = message["content"].split("\n\n---\n*Response created by:")
667
  main_content = parts[0]
668
  if len(parts) > 1:
669
  model_name = parts[1].replace("***", "").replace("**", "")
670
  st.markdown(main_content)
671
- st.markdown(f"<div class='model-attribution'>Response created by: <strong>{model_name}</strong></div>", unsafe_allow_html=True)
 
672
  else:
673
  st.markdown(message["content"])
674
  else:
675
  st.markdown(message["content"])
676
 
677
  # Chat input
678
- if prompt := st.chat_input("Tell us about your capabilities..."):
 
679
  update_online_users()
680
-
 
681
  user_message = {"role": "user", "content": prompt}
682
  st.session_state.messages.append(user_message)
683
-
 
684
  if auto_save:
685
  save_chat_history(st.session_state.messages)
686
-
 
687
  with st.chat_message("user"):
688
  st.markdown(prompt)
689
-
 
690
  with st.chat_message("assistant"):
691
  placeholder = st.empty()
692
-
693
  full_response = ""
694
  try:
695
  for response in get_ai_response(st.session_state.messages, selected_model):
696
  full_response = response
697
  placeholder.markdown(full_response + "β–Œ")
698
-
 
699
  placeholder.markdown(full_response)
700
-
701
  except Exception as e:
702
  error_msg = f"An error occurred: {str(e)}"
703
  placeholder.markdown(error_msg)
704
  full_response = error_msg
705
-
706
- full_response_with_attribution = full_response + f"\n\n---\n*Response created by: **{model_names[selected_index]}***"
707
- assistant_message = {"role": "assistant", "content": full_response_with_attribution}
 
 
 
708
  st.session_state.messages.append(assistant_message)
709
-
 
710
  if auto_save:
711
  save_chat_history(st.session_state.messages)
712
 
713
- # Footer
714
- st.caption(f"Currently using: **{model_names[selected_index]}**")
 
10
  st.set_page_config(
11
  page_title="Chat Flow πŸ•·",
12
  page_icon="πŸ’¬",
13
+ initial_sidebar_state="collapsed"
 
14
  )
15
 
16
+ # White background
17
  st.markdown("""
18
  <style>
 
 
 
 
19
  .stApp {
20
+ background: white;
 
 
21
  }
22
 
 
23
  .main .block-container {
24
+ max-width: 800px;
 
25
  }
26
 
 
27
  #MainMenu {visibility: hidden;}
28
  footer {visibility: hidden;}
29
  header {visibility: hidden;}
30
  .stDeployButton {display: none;}
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  .model-id {
33
+ color: #28a745;
34
+ font-family: monospace;
 
 
 
 
 
35
  }
36
 
37
  .model-attribution {
38
+ color: #28a745;
39
  font-size: 0.8em;
40
  font-style: italic;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
42
  </style>
43
  """, unsafe_allow_html=True)
44
 
45
  # File to store chat history
46
  HISTORY_FILE = "chat_history.json"
47
+ # NEW: File to store online users
48
  USERS_FILE = "online_users.json"
49
 
50
+
51
  def load_chat_history():
52
  """Load chat history from file"""
53
  try:
 
58
  st.error(f"Error loading chat history: {e}")
59
  return []
60
 
61
+
62
  def save_chat_history(messages):
63
  """Save chat history to file"""
64
  try:
 
67
  except Exception as e:
68
  st.error(f"Error saving chat history: {e}")
69
 
70
+
71
  def clear_chat_history():
72
  """Clear chat history file"""
73
  try:
 
77
  except Exception as e:
78
  st.error(f"Error clearing chat history: {e}")
79
 
80
+ # NEW: User tracking functions
81
+
82
+
83
  def get_user_id():
84
  """Get unique ID for this user session"""
85
  if 'user_id' not in st.session_state:
86
+ st.session_state.user_id = str(uuid.uuid4())[
87
+ :8] # Short ID for family use
88
  return st.session_state.user_id
89
 
90
+
91
  def update_online_users():
92
  """Update that this user is online right now"""
93
  try:
94
+ # Load current online users
95
  users = {}
96
  if os.path.exists(USERS_FILE):
97
  with open(USERS_FILE, 'r') as f:
98
  users = json.load(f)
99
+
100
+ # Add/update this user
101
  user_id = get_user_id()
102
  users[user_id] = {
103
  'last_seen': datetime.now().isoformat(),
104
+ 'name': f'User-{user_id}' # You can customize this
105
  }
106
+
107
  # Remove users not seen in last 5 minutes
108
  current_time = datetime.now()
109
  active_users = {}
 
111
  last_seen = datetime.fromisoformat(data['last_seen'])
112
  if current_time - last_seen < timedelta(minutes=5):
113
  active_users[uid] = data
114
+
115
+ # Save updated list
116
  with open(USERS_FILE, 'w') as f:
117
  json.dump(active_users, f, indent=2)
118
+
119
  return len(active_users)
120
  except Exception:
121
+ return 1 # If error, assume at least you're online
122
+
123
 
124
  def get_online_count():
125
  """Get number of people currently online"""
126
  try:
127
  if not os.path.exists(USERS_FILE):
128
  return 0
129
+
130
  with open(USERS_FILE, 'r') as f:
131
  users = json.load(f)
132
+
133
+ # Check who's still active (last 5 minutes)
134
  current_time = datetime.now()
135
  active_count = 0
136
  for data in users.values():
137
  last_seen = datetime.fromisoformat(data['last_seen'])
138
  if current_time - last_seen < timedelta(minutes=5):
139
  active_count += 1
140
+
141
  return active_count
142
  except Exception:
143
  return 0
144
 
145
+
146
  # Initialize session state with saved history
147
  if "messages" not in st.session_state:
148
  st.session_state.messages = load_chat_history()
 
150
  # Get API key
151
  OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY")
152
 
153
+
154
  @st.cache_data(ttl=300)
155
  def check_api_status():
156
  if not OPENROUTER_API_KEY:
 
163
  except:
164
  return "Error"
165
 
166
+
167
  def get_ai_response(messages, model="openai/gpt-3.5-turbo"):
168
  if not OPENROUTER_API_KEY:
169
  return "No API key found. Please add OPENROUTER_API_KEY to environment variables."
170
+
171
  url = "https://openrouter.ai/api/v1/chat/completions"
172
  headers = {
173
  "Content-Type": "application/json",
174
  "Authorization": f"Bearer {OPENROUTER_API_KEY}",
175
+ "HTTP-Referer": "http://localhost:8501", # Optional: Your site URL
176
+ "X-Title": "Streamlit AI Assistant" # Optional: Your app name
177
  }
178
+
179
+ # Create system message and user messages
180
+ api_messages = [
181
+ {"role": "system", "content": "You are a helpful AI assistant. Provide clear and helpful responses."}]
182
  api_messages.extend(messages)
183
+
184
  data = {
185
  "model": model,
186
  "messages": api_messages,
 
191
  "frequency_penalty": 0,
192
  "presence_penalty": 0
193
  }
194
+
195
  try:
196
+ response = requests.post(url, headers=headers,
197
+ json=data, stream=True, timeout=60)
198
+
199
+ # Better error handling
200
  if response.status_code != 200:
201
  error_detail = ""
202
  try:
203
  error_data = response.json()
204
+ error_detail = error_data.get('error', {}).get(
205
+ 'message', f"HTTP {response.status_code}")
206
  except:
207
  error_detail = f"HTTP {response.status_code}: {response.reason}"
208
+
209
  yield f"API Error: {error_detail}. Please try a different model or check your API key."
210
  return
211
+
212
  full_response = ""
213
+ buffer = ""
214
+
215
+ # Using your working streaming logic
216
  for line in response.iter_lines():
217
  if line:
218
+ # The server sends lines starting with "data: ..."
219
  if line.startswith(b"data: "):
220
  data_str = line[len(b"data: "):].decode("utf-8")
221
  if data_str.strip() == "[DONE]":
 
230
  continue
231
  except (KeyError, IndexError):
232
  continue
233
+
234
  except requests.exceptions.Timeout:
235
  yield "Request timed out. Please try again with a shorter message or different model."
236
  except requests.exceptions.ConnectionError:
 
240
  except Exception as e:
241
  yield f"Unexpected error: {str(e)}. Please try again or contact support."
242
 
243
+
244
  # Header
245
  st.title("Chat Flow πŸ•·")
246
  st.caption("10 powerful Models, one simple chat.")
247
 
248
  # Sidebar
249
  with st.sidebar:
250
+ st.header("Settings")
251
+
252
  # API Status
253
  status = check_api_status()
254
  if status == "Connected":
255
  st.success("🟒 API Connected")
256
  elif status == "No API Key":
257
+ st.error("No API Key")
258
  else:
259
+ st.warning("Connection Issue")
260
+
261
  st.divider()
262
+
263
+ # NEW: Live Users Section
264
+ st.header("πŸ‘₯ Who's Online")
265
+
266
+ # Update that you're online
267
  online_count = update_online_users()
268
+
269
+ # Show live count
270
  if online_count == 1:
271
  st.info("🟒 Just you online")
272
  else:
273
  st.success(f"🟒 {online_count} people online")
274
+
275
+ # Show your session
276
  your_id = get_user_id()
277
  st.caption(f"You: User-{your_id}")
278
+
279
+ # Quick refresh button
280
+ if st.button("Refresh", use_container_width=True):
281
  st.rerun()
282
+
283
+ # === NEW: DEBUG SECTION ===
284
  with st.expander("πŸ” Debug Info"):
285
  if os.path.exists(USERS_FILE):
286
  with open(USERS_FILE, 'r') as f:
 
293
  st.write(f"- {uid}: {minutes_ago} min ago")
294
  else:
295
  st.write("No users file yet")
296
+ # === END DEBUG SECTION ===
297
+
298
  st.divider()
299
+
300
+ # All models including new ones
 
301
  models = [
302
  ("GPT-3.5 Turbo", "openai/gpt-3.5-turbo"),
303
  ("LLaMA 3.1 8B", "meta-llama/llama-3.1-8b-instruct"),
 
310
  ("Gemma 3 4B", "google/gemma-3-4b-it:free"),
311
  ("Auto (Best Available)", "openrouter/auto")
312
  ]
313
+
314
  model_names = [name for name, _ in models]
315
  model_ids = [model_id for _, model_id in models]
316
+
317
+ selected_index = st.selectbox("Model", range(len(model_names)),
318
+ format_func=lambda x: model_names[x],
319
+ index=0)
320
  selected_model = model_ids[selected_index]
321
+
322
+ # Show selected model ID in green
323
+ st.markdown(
324
+ f"**Model ID:** <span class='model-id'>{selected_model}</span>", unsafe_allow_html=True)
325
+
326
  st.divider()
327
+
328
  # Chat History Controls
329
+ st.header("Chat History")
330
+
331
+ # Show number of messages
332
  if st.session_state.messages:
333
+ st.info(f"Messages stored: {len(st.session_state.messages)}")
334
+
335
+ # Auto-save toggle
336
  auto_save = st.checkbox("Auto-save messages", value=True)
337
+
338
+ # Manual save/load buttons
339
  col1, col2 = st.columns(2)
340
  with col1:
341
+ if st.button("Save History", use_container_width=True):
342
  save_chat_history(st.session_state.messages)
343
+ st.success("History saved!")
344
+
345
  with col2:
346
+ if st.button("Load History", use_container_width=True):
347
  st.session_state.messages = load_chat_history()
348
+ st.success("History loaded!")
349
  st.rerun()
350
+
351
+ st.divider()
352
+
353
+ # View History
354
+ if st.button("View History File", use_container_width=True):
 
 
 
 
 
355
  if os.path.exists(HISTORY_FILE):
356
+ with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
357
+ history_content = f.read()
358
+ st.text_area("Chat History (JSON)", history_content, height=200)
359
+ else:
360
+ st.warning("No history file found")
361
+
362
+ # Download History
363
+ if os.path.exists(HISTORY_FILE):
364
+ with open(HISTORY_FILE, 'rb') as f:
365
+ st.download_button(
366
+ label="Download History",
367
+ data=f.read(),
368
+ file_name=f"chat_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
369
+ mime="application/json",
370
+ use_container_width=True
371
+ )
372
 
373
+ st.divider()
374
+
375
+ # Clear controls
376
+ if st.button("Clear Chat", use_container_width=True, type="secondary"):
377
+ clear_chat_history()
378
+ st.success("Chat cleared!")
379
+ st.rerun()
380
+
381
+ # Show welcome message when no messages
 
 
382
 
383
  # Display chat messages
384
  for message in st.session_state.messages:
385
  with st.chat_message(message["role"]):
386
+ # Check if this is an assistant message with attribution
387
  if message["role"] == "assistant" and "Response created by:" in message["content"]:
388
+ # Split content and attribution
389
  parts = message["content"].split("\n\n---\n*Response created by:")
390
  main_content = parts[0]
391
  if len(parts) > 1:
392
  model_name = parts[1].replace("***", "").replace("**", "")
393
  st.markdown(main_content)
394
+ st.markdown(
395
+ f"<div class='model-attribution'>Response created by: <strong>{model_name}</strong></div>", unsafe_allow_html=True)
396
  else:
397
  st.markdown(message["content"])
398
  else:
399
  st.markdown(message["content"])
400
 
401
  # Chat input
402
+ if prompt := st.chat_input("Chat Smarter. Chat many Brains"):
403
+ # NEW: Update online status when user sends message
404
  update_online_users()
405
+
406
+ # Add user message
407
  user_message = {"role": "user", "content": prompt}
408
  st.session_state.messages.append(user_message)
409
+
410
+ # Auto-save if enabled
411
  if auto_save:
412
  save_chat_history(st.session_state.messages)
413
+
414
+ # Display user message
415
  with st.chat_message("user"):
416
  st.markdown(prompt)
417
+
418
+ # Get AI response
419
  with st.chat_message("assistant"):
420
  placeholder = st.empty()
421
+
422
  full_response = ""
423
  try:
424
  for response in get_ai_response(st.session_state.messages, selected_model):
425
  full_response = response
426
  placeholder.markdown(full_response + "β–Œ")
427
+
428
+ # Remove cursor and show final response
429
  placeholder.markdown(full_response)
430
+
431
  except Exception as e:
432
  error_msg = f"An error occurred: {str(e)}"
433
  placeholder.markdown(error_msg)
434
  full_response = error_msg
435
+
436
+ # Add AI response to messages with attribution
437
+ full_response_with_attribution = full_response + \
438
+ f"\n\n---\n*Response created by: **{model_names[selected_index]}***"
439
+ assistant_message = {"role": "assistant",
440
+ "content": full_response_with_attribution}
441
  st.session_state.messages.append(assistant_message)
442
+
443
+ # Auto-save if enabled
444
  if auto_save:
445
  save_chat_history(st.session_state.messages)
446
 
447
+ # Show currently using model
448
+ st.caption(f"Currently using: **{model_names[selected_index]}**")