awacke1 commited on
Commit
25818e0
ยท
verified ยท
1 Parent(s): 4b5d1e4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -123
app.py CHANGED
@@ -17,17 +17,9 @@ from audio_recorder_streamlit import audio_recorder
17
  import nest_asyncio
18
  import re
19
  import pytz
20
- import anthropic
21
- import openai
22
- from PyPDF2 import PdfReader
23
- import threading
24
- import json
25
- import zipfile
26
  from gradio_client import Client
27
- from dotenv import load_dotenv
28
  from streamlit_marquee import streamlit_marquee
29
  from collections import defaultdict, Counter
30
- import pandas as pd
31
 
32
  # Patch asyncio for nesting
33
  nest_asyncio.apply()
@@ -65,12 +57,6 @@ AUDIO_DIR = "audio_logs"
65
  STATE_FILE = "user_state.txt"
66
  CHAT_FILE = os.path.join(CHAT_DIR, "sim_chat.md")
67
 
68
- # API Keys
69
- load_dotenv()
70
- anthropic_key = os.getenv('ANTHROPIC_API_KEY', st.secrets.get('ANTHROPIC_API_KEY', ""))
71
- openai_api_key = os.getenv('OPENAI_API_KEY', st.secrets.get('OPENAI_API_KEY', ""))
72
- openai_client = openai.OpenAI(api_key=openai_api_key)
73
-
74
  # Timestamp Helper
75
  def format_timestamp_prefix(username=""):
76
  central = pytz.timezone('US/Central')
@@ -86,7 +72,7 @@ def init_session_state():
86
  'chat_history': [], 'marquee_settings': {
87
  "background": "#1E1E1E", "color": "#FFFFFF", "font-size": "14px",
88
  "animationDuration": "20s", "width": "100%", "lineHeight": "35px"
89
- }, 'username': None, 'autosend': True, 'autosearch': True, 'last_message': "",
90
  'mp3_files': {}, 'timer_start': time.time(), 'auto_refresh': True, 'refresh_rate': 10
91
  }
92
  for k, v in defaults.items():
@@ -95,10 +81,10 @@ def init_session_state():
95
 
96
  # Marquee Helpers
97
  def update_marquee_settings_ui():
98
- st.sidebar.markdown("### ๐ŸŽฏ Marquee Settings")
99
  cols = st.sidebar.columns(2)
100
  with cols[0]:
101
- st.session_state['marquee_settings']['background'] = st.color_picker("๐ŸŽจ Background", "#1E1E1E")
102
  st.session_state['marquee_settings']['color'] = st.color_picker("โœ๏ธ Text", "#FFFFFF")
103
  with cols[1]:
104
  st.session_state['marquee_settings']['font-size'] = f"{st.slider('๐Ÿ“ Size', 10, 24, 14)}px"
@@ -131,7 +117,7 @@ def get_download_link(file, file_type="mp3"):
131
  with open(file, "rb") as f:
132
  b64 = base64.b64encode(f.read()).decode()
133
  mime_types = {"mp3": "audio/mpeg", "png": "image/png", "md": "text/markdown"}
134
- return f'<a href="data:{mime_types.get(file_type, "application/octet-stream")};base64,{b64}" download="{os.path.basename(file)}">{FILE_EMOJIS.get(file_type, "Download")} Download {os.path.basename(file)}</a>'
135
 
136
  def save_username(username):
137
  with open(STATE_FILE, 'w') as f:
@@ -143,6 +129,13 @@ def load_username():
143
  return f.read().strip()
144
  return None
145
 
 
 
 
 
 
 
 
146
  # Audio Processing
147
  async def async_edge_tts_generate(text, voice, username):
148
  cache_key = f"{text[:100]}_{voice}"
@@ -187,35 +180,13 @@ async def load_chat():
187
  lines = content.split('\n')
188
  return list(dict.fromkeys(line for line in lines if line.strip()))
189
 
190
- # Claude and ArXiv Search
191
- async def perform_claude_search(query, username):
192
- client = anthropic.Anthropic(api_key=anthropic_key)
193
- response = client.messages.create(
194
- model="claude-3-sonnet-20240229",
195
- max_tokens=1000,
196
- messages=[{"role": "user", "content": query}]
197
- )
198
- result = response.content[0].text
199
- voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
200
- full_text = f"Claude says: {result}"
201
- md_file, audio_file = await save_chat_entry(username, full_text, voice, True)
202
- return md_file, audio_file, result
203
-
204
- async def perform_arxiv_search(query, username, claude_result=None):
205
- if claude_result is None:
206
- client = anthropic.Anthropic(api_key=anthropic_key)
207
- claude_response = client.messages.create(
208
- model="claude-3-sonnet-20240229",
209
- max_tokens=1000,
210
- messages=[{"role": "user", "content": query}]
211
- )
212
- claude_result = claude_response.content[0].text
213
- enhanced_query = f"{query}\n\n{claude_result}"
214
  gradio_client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
215
  refs = gradio_client.predict(
216
- enhanced_query, 10, "Semantic Search", "mistralai/Mixtral-8x7B-Instruct-v0.1", api_name="/update_with_rag_md"
217
  )[0]
218
- result = f"๐Ÿ”Ž ArXiv Results:\n\n{refs}"
219
  voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
220
  md_file, audio_file = await save_chat_entry(username, result, voice, True)
221
  return md_file, audio_file
@@ -235,6 +206,7 @@ async def websocket_handler(websocket, path):
235
  username, content = message.split('|', 1)
236
  voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
237
  await save_chat_entry(username, content, voice)
 
238
  except websockets.ConnectionClosed:
239
  await save_chat_entry("System ๐ŸŒŸ", f"{username} has left {START_ROOM}!", "en-US-AriaNeural")
240
  finally:
@@ -267,21 +239,22 @@ def start_websocket_server():
267
  # Sim-Oriented Mad Libs
268
  def generate_mad_libs_story(username, inputs):
269
  story = f"""
270
- In the wilds of Colorado, {username} stumbled upon {inputs['plural_noun']}.
271
- These {inputs['adjective1']} critters were {inputs['verb_ing']} all over the Rockies,
272
- freaking out climbers like {inputs['celebrity']}.
273
- Holding a {inputs['object']}, {username} felt {inputs['emotion']} as a {inputs['animal']}
274
- {inputs['verb_past']} past, yelling {inputs['exclamation']} near {inputs['place']}.
275
- Later, munching {inputs['food']} with a {inputs['adjective2']} {inputs['body_part']},
276
- {username} looped โ€œ{inputs['song']}โ€ {inputs['number']} times,
277
- deciding to {inputs['verb_present']} as a {inputs['occupation']}
278
- in a {inputs['color']} {inputs['noun']}โ€”all ending with a {inputs['sound']}!
279
  """
280
  return story.strip()
281
 
282
  # Main Interface
283
  def main():
284
  init_session_state()
 
285
  saved_username = load_username()
286
  if saved_username and saved_username in FUN_USERNAMES:
287
  st.session_state.username = saved_username
@@ -291,88 +264,73 @@ def main():
291
  asyncio.run(save_chat_entry("System ๐ŸŒŸ", f"{st.session_state.username} has joined {START_ROOM}!", "en-US-AriaNeural"))
292
  save_username(st.session_state.username)
293
 
294
- st.title(f"{Site_Name} - {st.session_state.username}")
295
- st.subheader("Chat, Search, or Create a Colorado Sim Story! ๐Ÿ˜‚๐ŸŒฒ")
296
  update_marquee_settings_ui()
297
  chat_text = " ".join([line.split(": ")[-1] for line in asyncio.run(load_chat()) if ": " in line])
298
- display_marquee(f"๐Ÿ”๏ธ {START_ROOM} | {st.session_state.username} | {chat_text}", st.session_state['marquee_settings'], "welcome")
299
 
300
- tab_main = st.radio("Action:", ["๐ŸŽค Chat & Voice", "๐Ÿ” Research", "โœจ Mad Libs Sim"], horizontal=True)
301
- st.checkbox("Autosend Chat", key="autosend")
302
- st.checkbox("Autosearch Research", key="autosearch")
303
 
304
  if tab_main == "๐ŸŽค Chat & Voice":
305
- st.subheader(f"{START_ROOM} Chat ๐Ÿ’ฌ")
306
  chat_content = asyncio.run(load_chat())
307
  with st.container():
308
  st.code("\n".join(f"{i+1}. {line}" for i, line in enumerate(chat_content)), language="python")
309
 
310
- message = st.text_input(f"Message as {st.session_state.username}", key="message_input")
311
  if message and message != st.session_state.last_message:
312
  st.session_state.last_message = message
313
- col_send, col_claude, col_arxiv = st.columns([1, 1, 1])
314
  with col_send:
315
- if st.session_state.autosend or st.button("Send ๐Ÿš€"):
316
  voice = FUN_USERNAMES.get(st.session_state.username, "en-US-AriaNeural")
317
  md_file, audio_file = asyncio.run(save_chat_entry(st.session_state.username, message, voice, True))
318
  if audio_file:
319
  play_and_download_audio(audio_file)
320
  st.rerun()
321
- with col_claude:
322
- if st.button("๐Ÿง  Claude"):
323
- md_file, audio_file, _ = asyncio.run(perform_claude_search(message, st.session_state.username))
324
- if audio_file:
325
- play_and_download_audio(audio_file)
326
- st.rerun()
327
- with col_arxiv:
328
- if st.button("๐Ÿ” ArXiv"):
329
- md_file, audio_file = asyncio.run(perform_arxiv_search(message, st.session_state.username))
330
- if audio_file:
331
- play_and_download_audio(audio_file)
332
- st.rerun()
333
 
334
- elif tab_main == "๐Ÿ” Research":
335
- st.subheader("๐Ÿ” Research with Claude & ArXiv")
336
- q = st.text_input("Query:", key="research_query")
337
- if q and (st.session_state.autosearch or st.button("๐Ÿ” Run")):
338
- st.session_state.last_message = q
339
- md_file_claude, audio_file_claude, claude_result = asyncio.run(perform_claude_search(q, st.session_state.username))
340
- if audio_file_claude:
341
- play_and_download_audio(audio_file_claude)
342
- md_file_arxiv, audio_file_arxiv = asyncio.run(perform_arxiv_search(q, st.session_state.username, claude_result))
343
- if audio_file_arxiv:
344
- play_and_download_audio(audio_file_arxiv)
345
 
346
  elif tab_main == "โœจ Mad Libs Sim":
347
- st.subheader("Create Your Colorado Sim Story!")
348
  col1, col2 = st.columns(2)
349
  inputs = {}
350
  with col1:
351
- inputs['plural_noun'] = st.text_input("1. Plural Noun", placeholder="e.g., 'tacos'")
352
- inputs['adjective1'] = st.text_input("2. Adjective", placeholder="e.g., 'spicy'")
353
- inputs['verb_ing'] = st.text_input("3. Verb ending in -ing", placeholder="e.g., 'yeeting'")
354
- inputs['celebrity'] = st.text_input("4. Celebrity Name", placeholder="e.g., 'Elon Musk'")
355
- inputs['object'] = st.text_input("5. Random Object", placeholder="e.g., 'toaster'")
356
- inputs['emotion'] = st.text_input("6. Emotion", placeholder="e.g., 'salty'")
357
- inputs['animal'] = st.text_input("7. Animal", placeholder="e.g., 'elk'")
358
- inputs['verb_past'] = st.text_input("8. Verb (past tense)", placeholder="e.g., 'yeeted'")
359
- inputs['place'] = st.text_input("9. Place", placeholder="e.g., 'Rockies'")
360
- inputs['exclamation'] = st.text_input("10. Exclamation", placeholder="e.g., 'Bruh!'")
361
  with col2:
362
- inputs['food'] = st.text_input("11. Food Item", placeholder="e.g., 'pizza'")
363
- inputs['adjective2'] = st.text_input("12. Adjective", placeholder="e.g., 'cringe'")
364
- inputs['body_part'] = st.text_input("13. Body Part", placeholder="e.g., 'elbow'")
365
- inputs['number'] = st.text_input("14. Number", placeholder="e.g., '69'")
366
- inputs['song'] = st.text_input("15. Song Title", placeholder="e.g., 'Sweet Caroline'")
367
- inputs['verb_present'] = st.text_input("16. Verb (present tense)", placeholder="e.g., 'slay'")
368
- inputs['occupation'] = st.text_input("17. Occupation", placeholder="e.g., 'influencer'")
369
- inputs['color'] = st.text_input("18. Color", placeholder="e.g., 'teal'")
370
- inputs['noun'] = st.text_input("19. Noun", placeholder="e.g., 'chaos'")
371
- inputs['sound'] = st.text_input("20. Silly Sound Effect", placeholder="e.g., 'Boop!'")
372
-
373
- if st.button("Generate Sim Story! ๐ŸŽ‰"):
374
  story = generate_mad_libs_story(st.session_state.username, inputs)
375
- st.markdown("### Your Colorado Sim Adventure ๐Ÿ”๏ธ")
376
  st.write(story)
377
  voice = FUN_USERNAMES.get(st.session_state.username, "en-US-AriaNeural")
378
  md_file, audio_file = asyncio.run(save_chat_entry(st.session_state.username, story, voice, True))
@@ -380,8 +338,8 @@ def main():
380
  play_and_download_audio(audio_file)
381
 
382
  # Sidebar
383
- st.sidebar.subheader("Character Settings")
384
- new_username = st.sidebar.selectbox("Switch Character", list(FUN_USERNAMES.keys()), index=list(FUN_USERNAMES.keys()).index(st.session_state.username))
385
  if new_username != st.session_state.username:
386
  asyncio.run(save_chat_entry("System ๐ŸŒŸ", f"{st.session_state.username} switched to {new_username}", "en-US-AriaNeural"))
387
  st.session_state.username = new_username
@@ -389,14 +347,5 @@ def main():
389
  save_username(st.session_state.username)
390
  st.rerun()
391
 
392
- st.sidebar.subheader("Chat History")
393
- chat_content = asyncio.run(load_chat())
394
- with st.sidebar.expander("Recent Logs"):
395
- st.code("\n".join(f"{i+1}. {line}" for i, line in enumerate(chat_content[-10:])), language="python")
396
-
397
- if not st.session_state.get('server_running', False):
398
- st.session_state.server_task = threading.Thread(target=start_websocket_server, daemon=True)
399
- st.session_state.server_task.start()
400
-
401
- if __name__ == "__main__":
402
- main()
 
17
  import nest_asyncio
18
  import re
19
  import pytz
 
 
 
 
 
 
20
  from gradio_client import Client
 
21
  from streamlit_marquee import streamlit_marquee
22
  from collections import defaultdict, Counter
 
23
 
24
  # Patch asyncio for nesting
25
  nest_asyncio.apply()
 
57
  STATE_FILE = "user_state.txt"
58
  CHAT_FILE = os.path.join(CHAT_DIR, "sim_chat.md")
59
 
 
 
 
 
 
 
60
  # Timestamp Helper
61
  def format_timestamp_prefix(username=""):
62
  central = pytz.timezone('US/Central')
 
72
  'chat_history': [], 'marquee_settings': {
73
  "background": "#1E1E1E", "color": "#FFFFFF", "font-size": "14px",
74
  "animationDuration": "20s", "width": "100%", "lineHeight": "35px"
75
+ }, 'username': None, 'autosend': True, 'last_message': "",
76
  'mp3_files': {}, 'timer_start': time.time(), 'auto_refresh': True, 'refresh_rate': 10
77
  }
78
  for k, v in defaults.items():
 
81
 
82
  # Marquee Helpers
83
  def update_marquee_settings_ui():
84
+ st.sidebar.markdown("### ๐ŸŽฏ Marquee Settings ๐ŸŽจ")
85
  cols = st.sidebar.columns(2)
86
  with cols[0]:
87
+ st.session_state['marquee_settings']['background'] = st.color_picker("๐ŸŒˆ Background", "#1E1E1E")
88
  st.session_state['marquee_settings']['color'] = st.color_picker("โœ๏ธ Text", "#FFFFFF")
89
  with cols[1]:
90
  st.session_state['marquee_settings']['font-size'] = f"{st.slider('๐Ÿ“ Size', 10, 24, 14)}px"
 
117
  with open(file, "rb") as f:
118
  b64 = base64.b64encode(f.read()).decode()
119
  mime_types = {"mp3": "audio/mpeg", "png": "image/png", "md": "text/markdown"}
120
+ return f'<a href="data:{mime_types.get(file_type, "application/octet-stream")};base64,{b64}" download="{os.path.basename(file)}">{FILE_EMOJIS.get(file_type, "๐Ÿ“ฅ")} Download {os.path.basename(file)}</a>'
121
 
122
  def save_username(username):
123
  with open(STATE_FILE, 'w') as f:
 
129
  return f.read().strip()
130
  return None
131
 
132
+ def load_mp3_viewer():
133
+ mp3_files = sorted(glob.glob("*.mp3"), key=os.path.getmtime)
134
+ for i, mp3 in enumerate(mp3_files, 1):
135
+ filename = os.path.basename(mp3)
136
+ if filename not in st.session_state['mp3_files']:
137
+ st.session_state['mp3_files'][filename] = (i, mp3)
138
+
139
  # Audio Processing
140
  async def async_edge_tts_generate(text, voice, username):
141
  cache_key = f"{text[:100]}_{voice}"
 
180
  lines = content.split('\n')
181
  return list(dict.fromkeys(line for line in lines if line.strip()))
182
 
183
+ # ArXiv Search with Gradio Client
184
+ async def perform_arxiv_search(query, username):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  gradio_client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
186
  refs = gradio_client.predict(
187
+ query, 10, "Semantic Search", "mistralai/Mixtral-8x7B-Instruct-v0.1", api_name="/update_with_rag_md"
188
  )[0]
189
+ result = f"๐Ÿ”Ž ArXiv Insights:\n\n{refs}"
190
  voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
191
  md_file, audio_file = await save_chat_entry(username, result, voice, True)
192
  return md_file, audio_file
 
206
  username, content = message.split('|', 1)
207
  voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
208
  await save_chat_entry(username, content, voice)
209
+ await perform_arxiv_search(content, username) # ArXiv response for every chat input
210
  except websockets.ConnectionClosed:
211
  await save_chat_entry("System ๐ŸŒŸ", f"{username} has left {START_ROOM}!", "en-US-AriaNeural")
212
  finally:
 
239
  # Sim-Oriented Mad Libs
240
  def generate_mad_libs_story(username, inputs):
241
  story = f"""
242
+ ๐ŸŒ„ In the wilds of Colorado, {username} stumbled upon {inputs['plural_noun']}.
243
+ ๐ŸŒŸ These {inputs['adjective1']} critters were {inputs['verb_ing']} all over the Rockies,
244
+ ๐ŸŽค freaking out climbers like {inputs['celebrity']}.
245
+ ๐Ÿ› ๏ธ Holding a {inputs['object']}, {username} felt {inputs['emotion']} as a {inputs['animal']}
246
+ โณ {inputs['verb_past']} past, yelling {inputs['exclamation']} near {inputs['place']}.
247
+ ๐Ÿฝ๏ธ Later, munching {inputs['food']} with a {inputs['adjective2']} {inputs['body_part']},
248
+ ๐ŸŽต {username} looped โ€œ{inputs['song']}โ€ {inputs['number']} times,
249
+ ๐Ÿ’ผ deciding to {inputs['verb_present']} as a {inputs['occupation']}
250
+ ๐ŸŽจ in a {inputs['color']} {inputs['noun']}โ€”all ending with a {inputs['sound']}!
251
  """
252
  return story.strip()
253
 
254
  # Main Interface
255
  def main():
256
  init_session_state()
257
+ load_mp3_viewer()
258
  saved_username = load_username()
259
  if saved_username and saved_username in FUN_USERNAMES:
260
  st.session_state.username = saved_username
 
264
  asyncio.run(save_chat_entry("System ๐ŸŒŸ", f"{st.session_state.username} has joined {START_ROOM}!", "en-US-AriaNeural"))
265
  save_username(st.session_state.username)
266
 
267
+ st.title(f"๐ŸŽ‰ {Site_Name} - {st.session_state.username} ๐Ÿ”๏ธ")
268
+ st.subheader("๐ŸŒฒ Chat, Explore Audio, or Create a Sim Story! ๐ŸŽค")
269
  update_marquee_settings_ui()
270
  chat_text = " ".join([line.split(": ")[-1] for line in asyncio.run(load_chat()) if ": " in line])
271
+ display_marquee(f"๐Ÿ”๏ธ {START_ROOM} | ๐ŸŽ™๏ธ {st.session_state.username} | ๐Ÿ’ฌ {chat_text}", st.session_state['marquee_settings'], "welcome")
272
 
273
+ tab_main = st.radio("๐ŸŽฎ Action:", ["๐ŸŽค Chat & Voice", "๐ŸŽต Audio Gallery", "โœจ Mad Libs Sim"], horizontal=True)
274
+ st.checkbox("๐Ÿš€ Autosend Chat", key="autosend")
 
275
 
276
  if tab_main == "๐ŸŽค Chat & Voice":
277
+ st.subheader(f"๐Ÿ’ฌ {START_ROOM} Chat ๐ŸŒŸ")
278
  chat_content = asyncio.run(load_chat())
279
  with st.container():
280
  st.code("\n".join(f"{i+1}. {line}" for i, line in enumerate(chat_content)), language="python")
281
 
282
+ message = st.text_input(f"๐Ÿ’ฌ Message as {st.session_state.username}", key="message_input", placeholder="Type your wild thoughts! ๐ŸŒˆ")
283
  if message and message != st.session_state.last_message:
284
  st.session_state.last_message = message
285
+ col_send = st.columns(1)[0]
286
  with col_send:
287
+ if st.session_state.autosend or st.button("๐Ÿš€ Send Message ๐ŸŽ™๏ธ"):
288
  voice = FUN_USERNAMES.get(st.session_state.username, "en-US-AriaNeural")
289
  md_file, audio_file = asyncio.run(save_chat_entry(st.session_state.username, message, voice, True))
290
  if audio_file:
291
  play_and_download_audio(audio_file)
292
  st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
+ elif tab_main == "๐ŸŽต Audio Gallery":
295
+ st.subheader("๐ŸŽต Audio Gallery ๐ŸŽง")
296
+ mp3_files = sorted(glob.glob("*.mp3"), key=os.path.getmtime)
297
+ if mp3_files:
298
+ for i, mp3 in enumerate(mp3_files):
299
+ with st.expander(f"๐ŸŽต {i+1}. {os.path.basename(mp3)}"):
300
+ play_and_download_audio(mp3)
301
+ else:
302
+ st.write("๐ŸŽถ No audio files yetโ€”chat or create a story to generate some! ๐ŸŽค")
 
 
303
 
304
  elif tab_main == "โœจ Mad Libs Sim":
305
+ st.subheader("โœจ Create Your Colorado Sim Story! ๐ŸŽ‰")
306
  col1, col2 = st.columns(2)
307
  inputs = {}
308
  with col1:
309
+ inputs['plural_noun'] = st.text_input("๐ŸŒŸ Plural Noun", placeholder="e.g., 'tacos'", key="plural_noun")
310
+ inputs['adjective1'] = st.text_input("๐ŸŽจ Adjective", placeholder="e.g., 'spicy'", key="adjective1")
311
+ inputs['verb_ing'] = st.text_input("โณ Verb ending in -ing", placeholder="e.g., 'yeeting'", key="verb_ing")
312
+ inputs['celebrity'] = st.text_input("๐ŸŽค Celebrity Name", placeholder="e.g., 'Elon Musk'", key="celebrity")
313
+ inputs['object'] = st.text_input("๐Ÿ› ๏ธ Random Object", placeholder="e.g., 'toaster'", key="object")
314
+ inputs['emotion'] = st.text_input("โค๏ธ Emotion", placeholder="e.g., 'salty'", key="emotion")
315
+ inputs['animal'] = st.text_input("๐ŸฆŒ Animal", placeholder="e.g., 'elk'", key="animal")
316
+ inputs['verb_past'] = st.text_input("โฎ๏ธ Verb (past tense)", placeholder="e.g., 'yeeted'", key="verb_past")
317
+ inputs['place'] = st.text_input("๐ŸŒ Place", placeholder="e.g., 'Rockies'", key="place")
318
+ inputs['exclamation'] = st.text_input("โ— Exclamation", placeholder="e.g., 'Bruh!'", key="exclamation")
319
  with col2:
320
+ inputs['food'] = st.text_input("๐Ÿฝ๏ธ Food Item", placeholder="e.g., 'pizza'", key="food")
321
+ inputs['adjective2'] = st.text_input("โœจ Adjective", placeholder="e.g., 'cringe'", key="adjective2")
322
+ inputs['body_part'] = st.text_input("๐Ÿฆด Body Part", placeholder="e.g., 'elbow'", key="body_part")
323
+ inputs['number'] = st.text_input("๐Ÿ”ข Number", placeholder="e.g., '69'", key="number")
324
+ inputs['song'] = st.text_input("๐ŸŽต Song Title", placeholder="e.g., 'Sweet Caroline'", key="song")
325
+ inputs['verb_present'] = st.text_input("โ–ถ๏ธ Verb (present tense)", placeholder="e.g., 'slay'", key="verb_present")
326
+ inputs['occupation'] = st.text_input("๐Ÿ’ผ Occupation", placeholder="e.g., 'influencer'", key="occupation")
327
+ inputs['color'] = st.text_input("๐ŸŒˆ Color", placeholder="e.g., 'teal'", key="color")
328
+ inputs['noun'] = st.text_input("๐Ÿ“‹ Noun", placeholder="e.g., 'chaos'", key="noun")
329
+ inputs['sound'] = st.text_input("๐Ÿ”Š Silly Sound Effect", placeholder="e.g., 'Boop!'", key="sound")
330
+
331
+ if st.button("๐ŸŽ‰ Generate Sim Story! ๐ŸŽค"):
332
  story = generate_mad_libs_story(st.session_state.username, inputs)
333
+ st.markdown("### ๐ŸŒ„ Your Colorado Sim Adventure ๐Ÿ”๏ธ")
334
  st.write(story)
335
  voice = FUN_USERNAMES.get(st.session_state.username, "en-US-AriaNeural")
336
  md_file, audio_file = asyncio.run(save_chat_entry(st.session_state.username, story, voice, True))
 
338
  play_and_download_audio(audio_file)
339
 
340
  # Sidebar
341
+ st.sidebar.subheader("๐ŸŽญ Character Settings")
342
+ new_username = st.sidebar.selectbox("๐Ÿ”„ Switch Character", list(FUN_USERNAMES.keys()), index=list(FUN_USERNAMES.keys()).index(st.session_state.username))
343
  if new_username != st.session_state.username:
344
  asyncio.run(save_chat_entry("System ๐ŸŒŸ", f"{st.session_state.username} switched to {new_username}", "en-US-AriaNeural"))
345
  st.session_state.username = new_username
 
347
  save_username(st.session_state.username)
348
  st.rerun()
349
 
350
+ st.sidebar.subheader("๐Ÿ’ฌ Chat History")
351
+ chat_content = asyncio