awacke1 commited on
Commit
c5fa0cb
Β·
verified Β·
1 Parent(s): a1e7982

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +189 -1
app.py CHANGED
@@ -379,4 +379,192 @@ def create_streamlit_interface():
379
  """, unsafe_allow_html=True)
380
 
381
  st.title(f"πŸ€–πŸ§ MMO {st.session_state.username}πŸ“πŸ”¬")
382
- st.markdown(f"Welcome to {START_ROOM} - chat, vote, upload, paste images, and enjoy quoting
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  """, unsafe_allow_html=True)
380
 
381
  st.title(f"πŸ€–πŸ§ MMO {st.session_state.username}πŸ“πŸ”¬")
382
+ st.markdown(f"Welcome to {START_ROOM} - chat, vote, upload, paste images, and enjoy quoting! πŸŽ‰")
383
+
384
+ if not st.session_state.server_task:
385
+ st.session_state.server_task = loop.create_task(run_websocket_server())
386
+
387
+ audio_bytes = audio_recorder()
388
+ if audio_bytes:
389
+ await process_voice_input(audio_bytes)
390
+ st.rerun()
391
+
392
+ st.subheader(f"{START_ROOM} Chat πŸ’¬")
393
+ chat_content = await load_chat()
394
+ chat_lines = chat_content.split('\n')
395
+ chat_votes = await load_votes(QUOTE_VOTES_FILE)
396
+ for i, line in enumerate(chat_lines):
397
+ if line.strip() and ': ' in line:
398
+ col1, col2, col3 = st.columns([4, 1, 1])
399
+ with col1:
400
+ st.markdown(line)
401
+ username = line.split(': ')[1].split(' ')[0]
402
+ audio_file = None
403
+ cache_key = f"{line}_{FUN_USERNAMES.get(username, 'en-US-AriaNeural')}"
404
+ if cache_key in st.session_state.audio_cache:
405
+ audio_file = st.session_state.audio_cache[cache_key]
406
+ else:
407
+ cleaned_text = clean_text_for_tts(line.split(': ', 1)[1])
408
+ audio_file = await async_edge_tts_generate(cleaned_text, FUN_USERNAMES.get(username, "en-US-AriaNeural"))
409
+ st.session_state.audio_cache[cache_key] = audio_file
410
+ if audio_file:
411
+ play_and_download_audio(audio_file)
412
+ with col2:
413
+ vote_count = chat_votes.get(line.split('. ')[1] if '. ' in line else line, 0)
414
+ if st.button(f"πŸ‘ {vote_count}", key=f"chat_vote_{i}"):
415
+ comment = st.session_state.message_text
416
+ await save_vote(QUOTE_VOTES_FILE, line.split('. ')[1] if '. ' in line else line, await generate_user_hash(), st.session_state.username, comment)
417
+ if st.session_state.pasted_image_data:
418
+ filename = await save_pasted_image(st.session_state.pasted_image_data, st.session_state.username)
419
+ if filename:
420
+ await save_chat_entry(st.session_state.username, f"Pasted image: {filename}")
421
+ st.session_state.pasted_image_data = None
422
+ st.session_state.message_text = ''
423
+ st.rerun()
424
+ with col3:
425
+ if st.button("πŸ“’ Quote", key=f"quote_{i}"):
426
+ st.session_state.quote_line = line
427
+ st.rerun()
428
+
429
+ if 'quote_line' in st.session_state:
430
+ st.markdown(f"### Quoting: {st.session_state.quote_line}")
431
+ quote_response = st.text_area("Add your response", key="quote_response")
432
+ if st.button("Send Quote πŸš€", key="send_quote"):
433
+ async def process_quote():
434
+ await asyncio.to_thread(log_action, st.session_state.username, "πŸ“’πŸ’¬ - Quote processor - echoes resound!")
435
+ markdown_response = f"### Quote Response\n- **Original**: {st.session_state.quote_line}\n- **{st.session_state.username} Replies**: {quote_response}"
436
+ if st.session_state.pasted_image_data:
437
+ filename = await save_pasted_image(st.session_state.pasted_image_data, st.session_state.username)
438
+ if filename:
439
+ markdown_response += f"\n- **Image**: ![Pasted Image]({filename})"
440
+ st.session_state.pasted_image_data = None
441
+ try:
442
+ await save_chat_entry(st.session_state.username, markdown_response)
443
+ except edge_tts.exceptions.NoAudioReceived:
444
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
445
+ with open(HISTORY_FILE, 'a') as f:
446
+ f.write(f"[{timestamp}] {st.session_state.username}: Quote saved without audio - No audio received\n")
447
+ await asyncio.to_thread(lambda: open(CHAT_FILE, 'a').write(f"[{timestamp}] {st.session_state.username}: {markdown_response}\n"))
448
+ loop.run_until_complete(process_quote())
449
+ del st.session_state.quote_line
450
+ st.session_state.message_text = ''
451
+ st.rerun()
452
+
453
+ new_username = st.selectbox("Change Name", [""] + list(FUN_USERNAMES.keys()), index=0)
454
+ if new_username and new_username != st.session_state.username:
455
+ loop.run_until_complete(save_chat_entry("System 🌟", f"{st.session_state.username} changed name to {new_username}"))
456
+ st.session_state.username = new_username
457
+ st.rerun()
458
+
459
+ message = st.text_input(f"Message as {st.session_state.username}", key="message_input", value=st.session_state.message_text, on_change=lambda: st.session_state.update(message_text=st.session_state.message_input))
460
+ if st.button("Send πŸš€", key="send_button") and message.strip():
461
+ loop.run_until_complete(save_chat_entry(st.session_state.username, message))
462
+ if st.session_state.pasted_image_data:
463
+ filename = loop.run_until_complete(save_pasted_image(st.session_state.pasted_image_data, st.session_state.username))
464
+ if filename:
465
+ loop.run_until_complete(save_chat_entry(st.session_state.username, f"Pasted image: {filename}"))
466
+ st.session_state.pasted_image_data = None
467
+ st.session_state.message_text = ''
468
+ st.rerun()
469
+
470
+ components.html(
471
+ """
472
+ <div id="paste-target">Paste an image here (Ctrl+V)</div>
473
+ <script>
474
+ const pasteTarget = document.getElementById('paste-target');
475
+ pasteTarget.addEventListener('paste', (event) => {
476
+ const items = (event.clipboardData || window.clipboardData).items;
477
+ for (let i = 0; i < items.length; i++) {
478
+ if (items[i].type.indexOf('image') !== -1) {
479
+ const blob = items[i].getAsFile();
480
+ const reader = new FileReader();
481
+ reader.onload = (e) => {
482
+ window.parent.postMessage({
483
+ type: 'streamlit:setComponentValue',
484
+ value: e.target.result
485
+ }, '*');
486
+ pasteTarget.innerHTML = '<p>Image pasted! Processing...</p>';
487
+ };
488
+ reader.readAsDataURL(blob);
489
+ }
490
+ }
491
+ event.preventDefault();
492
+ });
493
+ </script>
494
+ """,
495
+ height=100
496
+ )
497
+
498
+ st.subheader("Media Gallery 🎨🎢πŸŽ₯")
499
+ uploaded_file = st.file_uploader("Upload Media", type=['png', 'jpg', 'mp3', 'mp4'])
500
+ if uploaded_file:
501
+ timestamp = format_timestamp_prefix()
502
+ username = st.session_state.username
503
+ ext = uploaded_file.name.split('.')[-1]
504
+ filename = f"{timestamp}_{username}.{ext}"
505
+ file_path = os.path.join(MEDIA_DIR, filename)
506
+ await asyncio.to_thread(lambda: open(file_path, 'wb').write(uploaded_file.getbuffer()))
507
+ st.success(f"Uploaded {filename}")
508
+ await save_chat_entry(username, f"Uploaded media: {file_path}")
509
+ if file_path.endswith('.mp4'):
510
+ st.session_state.media_notifications.append(file_path) # Trigger autoplay for all clients
511
+
512
+ # Organize gallery by user
513
+ media_files = glob.glob(f"{MEDIA_DIR}/*.png") + glob.glob(f"{MEDIA_DIR}/*.jpg") + glob.glob(f"{MEDIA_DIR}/*.mp3") + glob.glob(f"{MEDIA_DIR}/*.mp4")
514
+ if media_files:
515
+ media_votes = loop.run_until_complete(load_votes(MEDIA_VOTES_FILE))
516
+ users = sorted(set(f.split('_')[-1].split('.')[0] for f in media_files)) # Extract usernames
517
+ for user in users:
518
+ with st.expander(f"{user}'s Media"):
519
+ user_files = [f for f in media_files if user in f]
520
+ for media_file in user_files:
521
+ vote_count = media_votes.get(media_file, 0)
522
+ if vote_count > 0:
523
+ col1, col2, col3 = st.columns([3, 1, 1])
524
+ with col1:
525
+ if media_file.endswith(('.png', '.jpg')):
526
+ st.image(media_file, use_container_width=True, caption=os.path.basename(media_file))
527
+ elif media_file.endswith('.mp3'):
528
+ st.markdown(await get_audio_html(media_file), unsafe_allow_html=True)
529
+ st.caption(os.path.basename(media_file))
530
+ elif media_file.endswith('.mp4'):
531
+ st.markdown(await get_video_html(media_file), unsafe_allow_html=True)
532
+ st.caption(os.path.basename(media_file))
533
+ if media_file in st.session_state.media_notifications:
534
+ st.session_state.media_notifications.remove(media_file) # Autoplay once
535
+ with col2:
536
+ if st.button(f"πŸ‘ {vote_count}", key=f"media_vote_{media_file}"):
537
+ comment = st.session_state.message_text
538
+ loop.run_until_complete(save_vote(MEDIA_VOTES_FILE, media_file, await generate_user_hash(), st.session_state.username, comment))
539
+ st.session_state.message_text = ''
540
+ st.rerun()
541
+ with col3:
542
+ if st.button("πŸ—‘οΈ", key=f"media_delete_{media_file}"):
543
+ await asyncio.to_thread(os.remove, media_file)
544
+ st.rerun()
545
+
546
+ st.subheader("Refresh ⏳")
547
+ refresh_rate = st.slider("Refresh Rate", 1, 300, st.session_state.refresh_rate)
548
+ st.session_state.refresh_rate = refresh_rate
549
+ timer_placeholder = st.empty()
550
+ for i in range(st.session_state.refresh_rate, -1, -1):
551
+ font_name, font_func = random.choice(UNICODE_FONTS)
552
+ countdown_str = "".join(UNICODE_DIGITS[int(d)] for d in str(i)) if i < 10 else font_func(str(i))
553
+ timer_placeholder.markdown(f"<p class='timer'>⏳ {font_func('Refresh in:')} {countdown_str}</p>", unsafe_allow_html=True)
554
+ loop.run_until_complete(asyncio.sleep(1))
555
+ st.rerun()
556
+
557
+ st.sidebar.subheader("Chat History πŸ“œ")
558
+ with open(HISTORY_FILE, 'r') as f:
559
+ history_content = f.read()
560
+ st.sidebar.markdown(history_content)
561
+
562
+ loop.run_until_complete(async_interface())
563
+
564
+ # Main execution - let’s roll! πŸŽ²πŸš€
565
+ def main():
566
+ NODE_NAME, port = get_node_name()
567
+ create_streamlit_interface()
568
+
569
+ if __name__ == "__main__":
570
+ main()