awacke1 commited on
Commit
ac4cd0d
Β·
verified Β·
1 Parent(s): a9bc037

Create backup.Voice.Working.v5.app.py

Browse files
Files changed (1) hide show
  1. backup.Voice.Working.v5.app.py +546 -0
backup.Voice.Working.v5.app.py ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import asyncio
3
+ import websockets
4
+ import uuid
5
+ import argparse
6
+ from datetime import datetime
7
+ import os
8
+ import random
9
+ import time
10
+ import hashlib
11
+ from PIL import Image
12
+ import glob
13
+ from urllib.parse import quote
14
+ import base64
15
+ import io
16
+ import streamlit.components.v1 as components
17
+ import edge_tts
18
+ from audio_recorder_streamlit import audio_recorder
19
+ import nest_asyncio
20
+
21
+ # Patch for nested async - sneaky fix! 🐍✨
22
+ nest_asyncio.apply()
23
+
24
+ # Static config - constants rule! πŸ“πŸ‘‘
25
+ icons = 'πŸ€–πŸ§ πŸ”¬πŸ“'
26
+ START_ROOM = "Sector 🌌"
27
+
28
+ # Page setup - dressing up the window! πŸ–ΌοΈπŸŽ€
29
+ st.set_page_config(
30
+ page_title="πŸ€–πŸ§ MMO Chat BrainπŸ“πŸ”¬",
31
+ page_icon=icons,
32
+ layout="wide",
33
+ initial_sidebar_state="auto"
34
+ )
35
+
36
+ # Funky usernames - who’s who in the zoo! 🎭🐾
37
+ FUN_USERNAMES = {
38
+ "CosmicJester 🌌": "en-US-AriaNeural",
39
+ "PixelPanda 🐼": "en-US-JennyNeural",
40
+ "QuantumQuack πŸ¦†": "en-GB-SoniaNeural",
41
+ "StellarSquirrel 🐿️": "en-AU-NatashaNeural",
42
+ "GizmoGuru βš™οΈ": "en-CA-ClaraNeural",
43
+ "NebulaNinja 🌠": "en-US-GuyNeural",
44
+ "ByteBuster πŸ’Ύ": "en-GB-RyanNeural",
45
+ "GalacticGopher 🌍": "en-AU-WilliamNeural",
46
+ "RocketRaccoon πŸš€": "en-CA-LiamNeural",
47
+ "EchoElf 🧝": "en-US-AriaNeural",
48
+ "PhantomFox 🦊": "en-US-JennyNeural",
49
+ "WittyWizard πŸ§™": "en-GB-SoniaNeural",
50
+ "LunarLlama πŸŒ™": "en-AU-NatashaNeural",
51
+ "SolarSloth β˜€οΈ": "en-CA-ClaraNeural",
52
+ "AstroAlpaca πŸ¦™": "en-US-GuyNeural",
53
+ "CyberCoyote 🐺": "en-GB-RyanNeural",
54
+ "MysticMoose 🦌": "en-AU-WilliamNeural",
55
+ "GlitchGnome 🧚": "en-CA-LiamNeural",
56
+ "VortexViper 🐍": "en-US-AriaNeural",
57
+ "ChronoChimp πŸ’": "en-US-JennyNeural"
58
+ }
59
+
60
+ # Folders galore - organizing chaos! πŸ“‚πŸŒ€
61
+ CHAT_DIR = "chat_logs"
62
+ VOTE_DIR = "vote_logs"
63
+ STATE_FILE = "user_state.txt"
64
+ AUDIO_DIR = "audio_logs"
65
+ HISTORY_DIR = "history_logs"
66
+ os.makedirs(CHAT_DIR, exist_ok=True)
67
+ os.makedirs(VOTE_DIR, exist_ok=True)
68
+ os.makedirs(AUDIO_DIR, exist_ok=True)
69
+ os.makedirs(HISTORY_DIR, exist_ok=True)
70
+
71
+ CHAT_FILE = os.path.join(CHAT_DIR, "global_chat.md")
72
+ QUOTE_VOTES_FILE = os.path.join(VOTE_DIR, "quote_votes.md")
73
+ MEDIA_VOTES_FILE = os.path.join(VOTE_DIR, "media_votes.md")
74
+ HISTORY_FILE = os.path.join(HISTORY_DIR, "chat_history.md")
75
+
76
+ # Fancy digits - numbers got style! πŸ”’πŸ’ƒ
77
+ UNICODE_DIGITS = {i: f"{i}\uFE0F⃣" for i in range(10)}
78
+
79
+ # Massive font collection - typography bonanza! πŸ–‹οΈπŸŽ¨
80
+ UNICODE_FONTS = [
81
+ ("Normal", lambda x: x),
82
+ ("Bold", lambda x: "".join(chr(ord(c) + 0x1D400 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D41A - 0x61) if 'a' <= c <= 'z' else c for c in x)),
83
+ ("Italic", lambda x: "".join(chr(ord(c) + 0x1D434 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D44E - 0x61) if 'a' <= c <= 'z' else c for c in x)),
84
+ ("Bold Italic", lambda x: "".join(chr(ord(c) + 0x1D468 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D482 - 0x61) if 'a' <= c <= 'z' else c for c in x)),
85
+ ("Script", lambda x: "".join(chr(ord(c) + 0x1D49C - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D4B6 - 0x61) if 'a' <= c <= 'z' else c for c in x)),
86
+ ("Bold Script", lambda x: "".join(chr(ord(c) + 0x1D4D0 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D4EA - 0x61) if 'a' <= c <= 'z' else c for c in x)),
87
+ ("Fraktur", lambda x: "".join(chr(ord(c) + 0x1D504 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D51E - 0x61) if 'a' <= c <= 'z' else c for c in x)),
88
+ ("Bold Fraktur", lambda x: "".join(chr(ord(c) + 0x1D56C - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D586 - 0x61) if 'a' <= c <= 'z' else c for c in x)),
89
+ ("Double Struck", lambda x: "".join(chr(ord(c) + 0x1D538 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D552 - 0x61) if 'a' <= c <= 'z' else c for c in x)),
90
+ ("Sans Serif", lambda x: "".join(chr(ord(c) + 0x1D5A0 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D5BA - 0x61) if 'a' <= c <= 'z' else c for c in x)),
91
+ ("Sans Serif Bold", lambda x: "".join(chr(ord(c) + 0x1D5D4 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D5EE - 0x61) if 'a' <= c <= 'z' else c for c in x)),
92
+ ("Sans Serif Italic", lambda x: "".join(chr(ord(c) + 0x1D608 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D622 - 0x61) if 'a' <= c <= 'z' else c for c in x)),
93
+ ("Sans Serif Bold Italic", lambda x: "".join(chr(ord(c) + 0x1D63C - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D656 - 0x61) if 'a' <= c <= 'z' else c for c in x)),
94
+ ("Monospace", lambda x: "".join(chr(ord(c) + 0x1D670 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x1D68A - 0x61) if 'a' <= c <= 'z' else c for c in x)),
95
+ ("Circled", lambda x: "".join(chr(ord(c) - 0x41 + 0x24B6) if 'A' <= c <= 'Z' else chr(ord(c) - 0x61 + 0x24D0) if 'a' <= c <= 'z' else c for c in x)),
96
+ ("Squared", lambda x: "".join(chr(ord(c) - 0x41 + 0x1F130) if 'A' <= c <= 'Z' else c for c in x)),
97
+ ("Negative Circled", lambda x: "".join(chr(ord(c) - 0x41 + 0x1F150) if 'A' <= c <= 'Z' else c for c in x)),
98
+ ("Negative Squared", lambda x: "".join(chr(ord(c) - 0x41 + 0x1F170) if 'A' <= c <= 'Z' else c for c in x)),
99
+ ("Regional Indicator", lambda x: "".join(chr(ord(c) - 0x41 + 0x1F1E6) if 'A' <= c <= 'Z' else c for c in x)),
100
+ ]
101
+
102
+ # Global state - keeping tabs! πŸŒπŸ“‹
103
+ if 'server_running' not in st.session_state:
104
+ st.session_state.server_running = False
105
+ if 'server_task' not in st.session_state:
106
+ st.session_state.server_task = None
107
+ if 'active_connections' not in st.session_state:
108
+ st.session_state.active_connections = {}
109
+
110
+ # Timestamp wizardry - clock ticks with flair! ⏰🎩
111
+ def format_timestamp_prefix():
112
+ return datetime.now().strftime("%Y%m%d_%H%M%S")
113
+
114
+ # Node naming - christening the beast! 🌐🍼
115
+ def get_node_name():
116
+ parser = argparse.ArgumentParser(description='Start a chat node with a specific name')
117
+ parser.add_argument('--node-name', type=str, default=None)
118
+ parser.add_argument('--port', type=int, default=8501)
119
+ args = parser.parse_args()
120
+ username = st.session_state.get('username', 'System 🌟')
121
+ log_action(username, "🌐🍼 - Node naming - christening the beast!")
122
+ return args.node_name or f"node-{uuid.uuid4().hex[:8]}", args.port
123
+
124
+ # Action logger - spying on deeds! πŸ•΅οΈπŸ“œ
125
+ def log_action(username, action):
126
+ if 'action_log' not in st.session_state:
127
+ st.session_state.action_log = {}
128
+ user_log = st.session_state.action_log.setdefault(username, {})
129
+ current_time = time.time()
130
+ user_log = {k: v for k, v in user_log.items() if current_time - v < 10}
131
+ st.session_state.action_log[username] = user_log
132
+ if action not in user_log:
133
+ with open(HISTORY_FILE, 'a') as f:
134
+ f.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {username}: {action}\n")
135
+ user_log[action] = current_time
136
+
137
+ # Chat saver - words locked tight! πŸ’¬πŸ”’
138
+ async def save_chat_entry(username, message):
139
+ await asyncio.to_thread(log_action, username, "πŸ’¬πŸ”’ - Chat saver - words locked tight!")
140
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
141
+ entry = f"[{timestamp}] {username}: {message}"
142
+ await asyncio.to_thread(lambda: open(CHAT_FILE, 'a').write(f"{entry}\n"))
143
+ voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
144
+ audio_file = await async_edge_tts_generate(message, voice)
145
+ if audio_file:
146
+ with open(HISTORY_FILE, 'a') as f:
147
+ f.write(f"[{timestamp}] {username}: Audio generated - {audio_file}\n")
148
+
149
+ # Chat loader - history unleashed! πŸ“œπŸš€
150
+ async def load_chat():
151
+ username = st.session_state.get('username', 'System 🌟')
152
+ await asyncio.to_thread(log_action, username, "πŸ“œπŸš€ - Chat loader - history unleashed!")
153
+ if not os.path.exists(CHAT_FILE):
154
+ await asyncio.to_thread(lambda: open(CHAT_FILE, 'a').write(f"# {START_ROOM} Chat\n\nWelcome to the cosmic hub - start chatting! 🎀\n"))
155
+ with open(CHAT_FILE, 'r') as f:
156
+ content = await asyncio.to_thread(f.read)
157
+ return content
158
+
159
+ # User lister - who’s in the gang! πŸ‘₯πŸŽ‰
160
+ async def get_user_list(chat_content):
161
+ username = st.session_state.get('username', 'System 🌟')
162
+ await asyncio.to_thread(log_action, username, "πŸ‘₯πŸŽ‰ - User lister - who’s in the gang!")
163
+ users = set()
164
+ for line in chat_content.split('\n'):
165
+ if line.strip() and ': ' in line:
166
+ user = line.split(': ')[1].split(' ')[0]
167
+ users.add(user)
168
+ return sorted(list(users))
169
+
170
+ # Join checker - been here before? πŸšͺπŸ”
171
+ async def has_joined_before(client_id, chat_content):
172
+ username = st.session_state.get('username', 'System 🌟')
173
+ await asyncio.to_thread(log_action, username, "πŸšͺπŸ” - Join checker - been here before?")
174
+ return any(f"Client-{client_id} has joined" in line for line in chat_content.split('\n'))
175
+
176
+ # Suggestion maker - old quips resurface! πŸ’‘πŸ“
177
+ async def get_message_suggestions(chat_content, prefix):
178
+ username = st.session_state.get('username', 'System 🌟')
179
+ await asyncio.to_thread(log_action, username, "πŸ’‘πŸ“ - Suggestion maker - old quips resurface!")
180
+ lines = chat_content.split('\n')
181
+ messages = [line.split(': ', 1)[1] for line in lines if ': ' in line and line.strip()]
182
+ return [msg for msg in messages if msg.lower().startswith(prefix.lower())][:5]
183
+
184
+ # Vote saver - cheers recorded! πŸ‘πŸ“Š
185
+ async def save_vote(file, item, user_hash, username, comment=""):
186
+ await asyncio.to_thread(log_action, username, "πŸ‘πŸ“Š - Vote saver - cheers recorded!")
187
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
188
+ entry = f"[{timestamp}] {user_hash} voted for {item}"
189
+ await asyncio.to_thread(lambda: open(file, 'a').write(f"{entry}\n"))
190
+ await asyncio.to_thread(lambda: open(HISTORY_FILE, "a").write(f"- {timestamp} - User {user_hash} voted for {item}\n"))
191
+ chat_message = f"{username} upvoted: \"{item}\""
192
+ if comment:
193
+ chat_message += f" - {comment}"
194
+ await save_chat_entry(username, chat_message)
195
+
196
+ # Vote counter - tallying the love! πŸ†πŸ“ˆ
197
+ async def load_votes(file):
198
+ username = st.session_state.get('username', 'System οΏ½οΏ½οΏ½οΏ½')
199
+ await asyncio.to_thread(log_action, username, "πŸ†πŸ“ˆ - Vote counter - tallying the love!")
200
+ if not os.path.exists(file):
201
+ await asyncio.to_thread(lambda: open(file, 'w').write("# Vote Tally\n\nNo votes yet - get clicking! πŸ–±οΈ\n"))
202
+ with open(file, 'r') as f:
203
+ content = await asyncio.to_thread(f.read)
204
+ lines = content.strip().split('\n')[2:] # Process content after reading
205
+ votes = {}
206
+ user_votes = set()
207
+ for line in lines:
208
+ if line.strip() and 'voted for' in line:
209
+ user_hash = line.split('] ')[1].split(' voted for ')[0]
210
+ item = line.split('voted for ')[1]
211
+ vote_key = f"{user_hash}-{item}"
212
+ if vote_key not in user_votes:
213
+ votes[item] = votes.get(item, 0) + 1
214
+ user_votes.add(vote_key)
215
+ return votes
216
+
217
+ # Hash generator - secret codes ahoy! πŸ”‘πŸ•΅οΈ
218
+ async def generate_user_hash():
219
+ username = st.session_state.get('username', 'System 🌟')
220
+ await asyncio.to_thread(log_action, username, "πŸ”‘πŸ•΅οΈ - Hash generator - secret codes ahoy!")
221
+ if 'user_hash' not in st.session_state:
222
+ st.session_state.user_hash = hashlib.md5(str(random.getrandbits(128)).encode()).hexdigest()[:8]
223
+ return st.session_state.user_hash
224
+
225
+ # Audio maker - voices come alive! 🎢🌟
226
+ async def async_edge_tts_generate(text, voice, rate=0, pitch=0, file_format="mp3"):
227
+ username = st.session_state.get('username', 'System 🌟')
228
+ await asyncio.to_thread(log_action, username, "🎢🌟 - Audio maker - voices come alive!")
229
+ timestamp = format_timestamp_prefix()
230
+ filename = os.path.join(AUDIO_DIR, f"audio_{timestamp}_{random.randint(1000, 9999)}.mp3")
231
+ communicate = edge_tts.Communicate(text, voice, rate=f"{rate:+d}%", pitch=f"{pitch:+d}Hz")
232
+ await communicate.save(filename)
233
+ return filename if os.path.exists(filename) else None
234
+
235
+ # Audio player - tunes blast off! πŸ”ŠπŸš€
236
+ def play_and_download_audio(file_path):
237
+ if file_path and os.path.exists(file_path):
238
+ st.audio(file_path)
239
+ with open(file_path, "rb") as f:
240
+ b64 = base64.b64encode(f.read()).decode()
241
+ dl_link = f'<a href="data:audio/mpeg;base64,{b64}" download="{os.path.basename(file_path)}">🎡 Download {os.path.basename(file_path)}</a>'
242
+ st.markdown(dl_link, unsafe_allow_html=True)
243
+
244
+ # Image saver - pics preserved! πŸ“ΈπŸ’Ύ
245
+ async def save_pasted_image(image_data):
246
+ username = st.session_state.get('username', 'System 🌟')
247
+ await asyncio.to_thread(log_action, username, "πŸ“ΈπŸ’Ύ - Image saver - pics preserved!")
248
+ timestamp = format_timestamp_prefix()
249
+ filename = f"paste_{timestamp}.png"
250
+ filepath = os.path.join('./', filename)
251
+ if ',' in image_data:
252
+ image_data = image_data.split(',')[1]
253
+ img_bytes = base64.b64decode(image_data)
254
+ img = Image.open(io.BytesIO(img_bytes))
255
+ await asyncio.to_thread(img.save, filepath, "PNG")
256
+ return filename
257
+
258
+ # Video renderer - movies roll! πŸŽ₯🎬
259
+ async def get_video_html(video_path, width="100%"):
260
+ username = st.session_state.get('username', 'System 🌟')
261
+ await asyncio.to_thread(log_action, username, "πŸŽ₯🎬 - Video renderer - movies roll!")
262
+ video_url = f"data:video/mp4;base64,{base64.b64encode(await asyncio.to_thread(open, video_path, 'rb').read()).decode()}"
263
+ return f'<video width="{width}" controls autoplay muted loop><source src="{video_url}" type="video/mp4">Your browser does not support the video tag.</video>'
264
+
265
+ # Audio renderer - sounds soar! 🎢✈️
266
+ async def get_audio_html(audio_path, width="100%"):
267
+ username = st.session_state.get('username', 'System 🌟')
268
+ await asyncio.to_thread(log_action, username, "🎢✈️ - Audio renderer - sounds soar!")
269
+ audio_url = f"data:audio/mpeg;base64,{base64.b64encode(await asyncio.to_thread(open, audio_path, 'rb').read()).decode()}"
270
+ return f'<audio controls style="width: {width};"><source src="{audio_url}" type="audio/mpeg">Your browser does not support the audio element.</audio>'
271
+
272
+ # Websocket handler - chat links up! πŸŒπŸ”—
273
+ async def websocket_handler(websocket, path):
274
+ username = st.session_state.get('username', 'System 🌟')
275
+ await asyncio.to_thread(log_action, username, "πŸŒπŸ”— - Websocket handler - chat links up!")
276
+ try:
277
+ client_id = str(uuid.uuid4())
278
+ room_id = "chat"
279
+ st.session_state.active_connections.setdefault(room_id, {})[client_id] = websocket
280
+ chat_content = await load_chat()
281
+ username = st.session_state.get('username', random.choice(list(FUN_USERNAMES.keys())))
282
+ if not await has_joined_before(client_id, chat_content):
283
+ await save_chat_entry(f"Client-{client_id}", f"{username} has joined {START_ROOM}!")
284
+ async for message in websocket:
285
+ parts = message.split('|', 1)
286
+ if len(parts) == 2:
287
+ username, content = parts
288
+ await save_chat_entry(username, content)
289
+ await broadcast_message(f"{username}|{content}", room_id)
290
+ except websockets.ConnectionClosed:
291
+ pass
292
+ finally:
293
+ if room_id in st.session_state.active_connections and client_id in st.session_state.active_connections[room_id]:
294
+ del st.session_state.active_connections[room_id][client_id]
295
+
296
+ # Message broadcaster - words fly far! πŸ“’βœˆοΈ
297
+ async def broadcast_message(message, room_id):
298
+ username = st.session_state.get('username', 'System 🌟')
299
+ await asyncio.to_thread(log_action, username, "πŸ“’βœˆοΈ - Message broadcaster - words fly far!")
300
+ if room_id in st.session_state.active_connections:
301
+ disconnected = []
302
+ for client_id, ws in st.session_state.active_connections[room_id].items():
303
+ try:
304
+ await ws.send(message)
305
+ except websockets.ConnectionClosed:
306
+ disconnected.append(client_id)
307
+ for client_id in disconnected:
308
+ del st.session_state.active_connections[room_id][client_id]
309
+
310
+ # Server starter - web spins up! πŸ–₯οΈπŸŒ€
311
+ async def run_websocket_server():
312
+ username = st.session_state.get('username', 'System 🌟')
313
+ await asyncio.to_thread(log_action, username, "πŸ–₯οΈπŸŒ€ - Server starter - web spins up!")
314
+ if not st.session_state.server_running:
315
+ server = await websockets.serve(websocket_handler, '0.0.0.0', 8765)
316
+ st.session_state.server_running = True
317
+ await server.wait_closed()
318
+
319
+ # Voice processor - speech to text! πŸŽ€πŸ“
320
+ async def process_voice_input(audio_bytes):
321
+ username = st.session_state.get('username', 'System 🌟')
322
+ await asyncio.to_thread(log_action, username, "πŸŽ€πŸ“ - Voice processor - speech to text!")
323
+ if audio_bytes:
324
+ text = "Voice input simulation" # Replace with actual speech-to-text logic
325
+ await save_chat_entry(username, text)
326
+
327
+ # Interface builder - UI takes shape! πŸŽ¨πŸ–ŒοΈ
328
+ def create_streamlit_interface():
329
+ # Run async tasks within an event loop
330
+ loop = asyncio.new_event_loop()
331
+ asyncio.set_event_loop(loop)
332
+
333
+ async def async_interface():
334
+ if 'username' not in st.session_state:
335
+ chat_content = await load_chat()
336
+ available_names = [name for name in FUN_USERNAMES if not any(f"{name} has joined" in line for line in chat_content.split('\n'))]
337
+ st.session_state.username = random.choice(available_names) if available_names else random.choice(list(FUN_USERNAMES.keys()))
338
+
339
+ if 'refresh_rate' not in st.session_state:
340
+ st.session_state.refresh_rate = 5
341
+ if 'timer_start' not in st.session_state:
342
+ st.session_state.timer_start = time.time()
343
+ if 'quote_line' not in st.session_state:
344
+ st.session_state.quote_line = None
345
+ if 'pasted_image_data' not in st.session_state:
346
+ st.session_state.pasted_image_data = None
347
+ if 'message_text' not in st.session_state:
348
+ st.session_state.message_text = ""
349
+ if 'audio_cache' not in st.session_state:
350
+ st.session_state.audio_cache = {}
351
+ if 'chat_history' not in st.session_state:
352
+ st.session_state.chat_history = []
353
+
354
+ st.markdown("""
355
+ <style>
356
+ .chat-box {font-family: monospace; background: #1e1e1e; color: #d4d4d4; padding: 10px; border-radius: 5px; height: 300px; overflow-y: auto;}
357
+ .timer {font-size: 24px; color: #ffcc00; text-align: center; animation: pulse 1s infinite;}
358
+ @keyframes pulse {0% {transform: scale(1);} 50% {transform: scale(1.1);} 100% {transform: scale(1);}}
359
+ #paste-target {border: 2px dashed #ccc; padding: 20px; text-align: center; cursor: pointer;}
360
+ </style>
361
+ """, unsafe_allow_html=True)
362
+
363
+ st.title(f"πŸ€–πŸ§ MMO {st.session_state.username}πŸ“πŸ”¬")
364
+ st.markdown(f"Welcome to {START_ROOM} - chat, vote, upload, paste images, and enjoy quoting! πŸŽ‰")
365
+
366
+ # Start websocket server if not running
367
+ if not st.session_state.server_task:
368
+ st.session_state.server_task = loop.create_task(run_websocket_server())
369
+
370
+ # Voice Input
371
+ audio_bytes = audio_recorder()
372
+ if audio_bytes:
373
+ await process_voice_input(audio_bytes)
374
+ st.rerun()
375
+
376
+ # Chat Section
377
+ st.subheader(f"{START_ROOM} Chat πŸ’¬")
378
+ chat_content = await load_chat()
379
+ chat_lines = chat_content.split('\n')
380
+ chat_votes = await load_votes(QUOTE_VOTES_FILE)
381
+ for i, line in enumerate(chat_lines):
382
+ if line.strip() and ': ' in line:
383
+ col1, col2, col3 = st.columns([4, 1, 1])
384
+ with col1:
385
+ st.markdown(line)
386
+ username = line.split(': ')[1].split(' ')[0]
387
+ audio_file = None
388
+ cache_key = f"{line}_{FUN_USERNAMES.get(username, 'en-US-AriaNeural')}"
389
+ if cache_key in st.session_state.audio_cache:
390
+ audio_file = st.session_state.audio_cache[cache_key]
391
+ else:
392
+ audio_file = await async_edge_tts_generate(line.split(': ', 1)[1], FUN_USERNAMES.get(username, "en-US-AriaNeural"))
393
+ st.session_state.audio_cache[cache_key] = audio_file
394
+ if audio_file:
395
+ play_and_download_audio(audio_file)
396
+ with col2:
397
+ vote_count = chat_votes.get(line.split('. ')[1] if '. ' in line else line, 0)
398
+ if st.button(f"πŸ‘ {vote_count}", key=f"chat_vote_{i}"):
399
+ comment = st.session_state.message_text
400
+ await save_vote(QUOTE_VOTES_FILE, line.split('. ')[1] if '. ' in line else line, await generate_user_hash(), st.session_state.username, comment)
401
+ if st.session_state.pasted_image_data:
402
+ filename = await save_pasted_image(st.session_state.pasted_image_data)
403
+ if filename:
404
+ await save_chat_entry(st.session_state.username, f"Pasted image: {filename}")
405
+ st.session_state.pasted_image_data = None
406
+ st.session_state.message_text = ''
407
+ st.rerun()
408
+ with col3:
409
+ if st.button("πŸ“’ Quote", key=f"quote_{i}"):
410
+ st.session_state.quote_line = line
411
+ st.rerun()
412
+
413
+ # Quoting Section
414
+ if 'quote_line' in st.session_state:
415
+ st.markdown(f"### Quoting: {st.session_state.quote_line}")
416
+ quote_response = st.text_area("Add your response", key="quote_response")
417
+ if st.button("Send Quote πŸš€", key="send_quote"):
418
+ async def process_quote():
419
+ await asyncio.to_thread(log_action, st.session_state.username, "πŸ“’πŸ’¬ - Quote processor - echoes resound!")
420
+ markdown_response = f"### Quote Response\n- **Original**: {st.session_state.quote_line}\n- **{st.session_state.username} Replies**: {quote_response}"
421
+ if st.session_state.pasted_image_data:
422
+ filename = await save_pasted_image(st.session_state.pasted_image_data)
423
+ if filename:
424
+ markdown_response += f"\n- **Image**: ![Pasted Image]({filename})"
425
+ st.session_state.pasted_image_data = None
426
+ await save_chat_entry(st.session_state.username, markdown_response)
427
+ loop.run_until_complete(process_quote())
428
+ del st.session_state.quote_line
429
+ st.session_state.message_text = ''
430
+ st.rerun()
431
+
432
+ # Username changer
433
+ new_username = st.selectbox("Change Name", [""] + list(FUN_USERNAMES.keys()), index=0)
434
+ if new_username and new_username != st.session_state.username:
435
+ loop.run_until_complete(save_chat_entry("System 🌟", f"{st.session_state.username} changed name to {new_username}"))
436
+ st.session_state.username = new_username
437
+ st.rerun()
438
+
439
+ # Message Input
440
+ 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))
441
+ if st.button("Send πŸš€", key="send_button") and message.strip():
442
+ loop.run_until_complete(save_chat_entry(st.session_state.username, message))
443
+ if st.session_state.pasted_image_data:
444
+ filename = loop.run_until_complete(save_pasted_image(st.session_state.pasted_image_data))
445
+ if filename:
446
+ loop.run_until_complete(save_chat_entry(st.session_state.username, f"Pasted image: {filename}"))
447
+ st.session_state.pasted_image_data = None
448
+ st.session_state.message_text = ''
449
+ st.rerun()
450
+
451
+ # Paste Target
452
+ components.html(
453
+ """
454
+ <div id="paste-target">Paste an image here (Ctrl+V)</div>
455
+ <script>
456
+ const pasteTarget = document.getElementById('paste-target');
457
+ pasteTarget.addEventListener('paste', (event) => {
458
+ const items = (event.clipboardData || window.clipboardData).items;
459
+ for (let i = 0; i < items.length; i++) {
460
+ if (items[i].type.indexOf('image') !== -1) {
461
+ const blob = items[i].getAsFile();
462
+ const reader = new FileReader();
463
+ reader.onload = (e) => {
464
+ window.parent.postMessage({
465
+ type: 'streamlit:setComponentValue',
466
+ value: e.target.result
467
+ }, '*');
468
+ pasteTarget.innerHTML = '<p>Image pasted! Processing...</p>';
469
+ };
470
+ reader.readAsDataURL(blob);
471
+ }
472
+ }
473
+ event.preventDefault();
474
+ });
475
+ </script>
476
+ """,
477
+ height=100
478
+ )
479
+
480
+ # Media Section
481
+ st.subheader("Media Gallery 🎨🎢πŸŽ₯")
482
+ uploaded_file = st.file_uploader("Upload Media", type=['png', 'jpg', 'mp3', 'mp4'])
483
+ if uploaded_file:
484
+ file_path = os.path.join('./', uploaded_file.name)
485
+ await asyncio.to_thread(lambda: open(file_path, 'wb').write(uploaded_file.getbuffer()))
486
+ st.success(f"Uploaded {uploaded_file.name}")
487
+
488
+ media_files = glob.glob("./*.png") + glob.glob("./*.jpg") + glob.glob("./*.mp3") + glob.glob("./*.mp4")
489
+ if media_files:
490
+ cols = st.columns(3)
491
+ media_votes = loop.run_until_complete(load_votes(MEDIA_VOTES_FILE))
492
+ for idx, media_file in enumerate(media_files):
493
+ vote_count = media_votes.get(media_file, 0)
494
+ if vote_count > 0:
495
+ with cols[idx % 3]:
496
+ if media_file.endswith(('.png', '.jpg')):
497
+ st.image(media_file, use_container_width=True)
498
+ elif media_file.endswith('.mp3'):
499
+ st.markdown(loop.run_until_complete(get_audio_html(media_file)), unsafe_allow_html=True)
500
+ elif media_file.endswith('.mp4'):
501
+ st.markdown(loop.run_until_complete(get_video_html(media_file)), unsafe_allow_html=True)
502
+ col1, col2 = st.columns(2)
503
+ with col1:
504
+ if st.button(f"πŸ‘ {vote_count}", key=f"media_vote_{idx}"):
505
+ comment = st.session_state.message_text
506
+ loop.run_until_complete(save_vote(MEDIA_VOTES_FILE, media_file, await generate_user_hash(), st.session_state.username, comment))
507
+ if st.session_state.pasted_image_data:
508
+ filename = loop.run_until_complete(save_pasted_image(st.session_state.pasted_image_data))
509
+ if filename:
510
+ loop.run_until_complete(save_chat_entry(st.session_state.username, f"Pasted image: {filename}"))
511
+ st.session_state.pasted_image_data = None
512
+ st.session_state.message_text = ''
513
+ st.rerun()
514
+ with col2:
515
+ if st.button("πŸ—‘οΈ", key=f"media_delete_{idx}"):
516
+ await asyncio.to_thread(os.remove, media_file)
517
+ st.rerun()
518
+
519
+ # Refresh Timer
520
+ st.subheader("Refresh ⏳")
521
+ refresh_rate = st.slider("Refresh Rate", 1, 300, st.session_state.refresh_rate)
522
+ st.session_state.refresh_rate = refresh_rate
523
+ timer_placeholder = st.empty()
524
+ for i in range(st.session_state.refresh_rate, -1, -1):
525
+ font_name, font_func = random.choice(UNICODE_FONTS)
526
+ countdown_str = "".join(UNICODE_DIGITS[int(d)] for d in str(i)) if i < 10 else font_func(str(i))
527
+ timer_placeholder.markdown(f"<p class='timer'>⏳ {font_func('Refresh in:')} {countdown_str}</p>", unsafe_allow_html=True)
528
+ loop.run_until_complete(asyncio.sleep(1))
529
+ st.rerun()
530
+
531
+ # Sidebar History
532
+ st.sidebar.subheader("Chat History πŸ“œ")
533
+ with open(HISTORY_FILE, 'r') as f:
534
+ history_content = f.read()
535
+ st.sidebar.markdown(history_content)
536
+
537
+ # Run the async interface
538
+ loop.run_until_complete(async_interface())
539
+
540
+ # Main execution - let’s roll! πŸŽ²πŸš€
541
+ def main():
542
+ NODE_NAME, port = get_node_name()
543
+ create_streamlit_interface()
544
+
545
+ if __name__ == "__main__":
546
+ main()