Update app.py
Browse files
app.py
CHANGED
@@ -30,6 +30,26 @@ QUOTE_VOTES_FILE = os.path.join(VOTE_DIR, "quote_votes.md")
|
|
30 |
IMAGE_VOTES_FILE = os.path.join(VOTE_DIR, "image_votes.md")
|
31 |
HISTORY_FILE = os.path.join(VOTE_DIR, "vote_history.md")
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
# Node name - the appβs codename generator, sneaky and slick! π΅οΈββοΈπΎ
|
34 |
def get_node_name():
|
35 |
"""π² Spins the wheel of fate to name our node - a random alias or user pick! π·οΈ"""
|
@@ -206,7 +226,7 @@ async def start_websocket_server(host='0.0.0.0', port=8765):
|
|
206 |
|
207 |
# Chat interface maker - the stage builder for our chat extravaganza! πποΈ
|
208 |
def create_streamlit_interface(initial_username):
|
209 |
-
"""ποΈ Sets up the chat stage with live updates, timers, voting, and refresh flair! π"""
|
210 |
# Custom CSS for a sleek chat box and timer
|
211 |
st.markdown("""
|
212 |
<style>
|
@@ -220,16 +240,22 @@ def create_streamlit_interface(initial_username):
|
|
220 |
overflow-y: auto;
|
221 |
}
|
222 |
.timer {
|
223 |
-
font-size:
|
224 |
color: #ffcc00;
|
225 |
text-align: center;
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
}
|
227 |
</style>
|
228 |
""", unsafe_allow_html=True)
|
229 |
|
230 |
# Title and intro
|
231 |
st.title(f"Chat & Quote Node: {NODE_NAME}")
|
232 |
-
st.markdown("Chat, vote on messages, quotes, and images -
|
233 |
|
234 |
# Session state for username, refresh rate, and quote index
|
235 |
if 'username' not in st.session_state:
|
@@ -238,6 +264,8 @@ def create_streamlit_interface(initial_username):
|
|
238 |
st.session_state.refresh_rate = 5
|
239 |
if 'last_refresh' not in st.session_state:
|
240 |
st.session_state.last_refresh = time.time()
|
|
|
|
|
241 |
if 'quote_index' not in st.session_state:
|
242 |
quotes = load_quotes("famous")
|
243 |
st.session_state.quote_index = random.randint(0, max(0, len(quotes) - 1)) if quotes else 0
|
@@ -257,25 +285,25 @@ def create_streamlit_interface(initial_username):
|
|
257 |
if st.button(f"π", key=f"chat_vote_{i}"):
|
258 |
user_hash = generate_user_hash()
|
259 |
save_vote(QUOTE_VOTES_FILE, line, user_hash)
|
260 |
-
st.session_state.
|
261 |
st.rerun()
|
262 |
|
263 |
user_list = get_user_list(chat_content)
|
264 |
new_username = st.selectbox("Switch User", user_list + [st.session_state.username], index=len(user_list))
|
265 |
if new_username != st.session_state.username:
|
266 |
st.session_state.username = new_username
|
|
|
267 |
|
268 |
message = st.text_input("Message", placeholder="Type your epic line here! βοΈ")
|
269 |
if st.button("Send π") and message.strip():
|
270 |
save_chat_entry(st.session_state.username, message)
|
271 |
-
st.session_state.
|
272 |
st.rerun()
|
273 |
|
274 |
# Quote section
|
275 |
st.subheader("Quote of the Moment π")
|
276 |
quotes = load_quotes(st.session_state.quote_source)
|
277 |
if quotes:
|
278 |
-
# Ensure quote_index is within bounds
|
279 |
st.session_state.quote_index = st.session_state.quote_index % len(quotes)
|
280 |
quote = quotes[st.session_state.quote_index]
|
281 |
col1, col2 = st.columns([5, 1])
|
@@ -285,12 +313,12 @@ def create_streamlit_interface(initial_username):
|
|
285 |
if st.button("π Upvote", key="quote_vote"):
|
286 |
user_hash = generate_user_hash()
|
287 |
save_vote(QUOTE_VOTES_FILE, quote, user_hash)
|
288 |
-
st.session_state.
|
289 |
st.rerun()
|
290 |
-
if time.time() - st.session_state.last_refresh > 10:
|
291 |
st.session_state.quote_index = (st.session_state.quote_index + 1) % len(quotes)
|
292 |
st.session_state.quote_source = "custom" if st.session_state.quote_source == "famous" else "famous"
|
293 |
-
quotes = load_quotes(st.session_state.quote_source)
|
294 |
st.session_state.quote_index = st.session_state.quote_index % len(quotes) if quotes else 0
|
295 |
st.session_state.last_refresh = time.time()
|
296 |
st.rerun()
|
@@ -310,51 +338,57 @@ def create_streamlit_interface(initial_username):
|
|
310 |
if st.button(f"π Upvote {image1}", key=f"img_vote_{image1}"):
|
311 |
user_hash = generate_user_hash()
|
312 |
save_vote(IMAGE_VOTES_FILE, image1, user_hash)
|
313 |
-
st.session_state.
|
314 |
st.rerun()
|
315 |
with col2:
|
316 |
st.image(os.path.join(image_dir, image2))
|
317 |
if st.button(f"π Upvote {image2}", key=f"img_vote_{image2}"):
|
318 |
user_hash = generate_user_hash()
|
319 |
save_vote(IMAGE_VOTES_FILE, image2, user_hash)
|
320 |
-
st.session_state.
|
321 |
st.rerun()
|
322 |
else:
|
323 |
st.error("Need at least 2 images in the directory for voting!")
|
324 |
|
325 |
-
# Refresh rate controls
|
326 |
st.subheader("Set Refresh Rate β³")
|
327 |
refresh_rate = st.slider("Refresh Rate (seconds)", min_value=1, max_value=300, value=st.session_state.refresh_rate, step=1)
|
328 |
-
st.session_state.refresh_rate
|
|
|
|
|
329 |
|
330 |
col1, col2, col3 = st.columns(3)
|
331 |
with col1:
|
332 |
if st.button("π Small (1s)"):
|
333 |
st.session_state.refresh_rate = 1
|
334 |
-
st.session_state.
|
335 |
st.rerun()
|
336 |
with col2:
|
337 |
if st.button("π’ Medium (5s)"):
|
338 |
st.session_state.refresh_rate = 5
|
339 |
-
st.session_state.
|
340 |
st.rerun()
|
341 |
with col3:
|
342 |
if st.button("π Large (5m)"):
|
343 |
st.session_state.refresh_rate = 300
|
344 |
-
st.session_state.
|
345 |
st.rerun()
|
346 |
|
347 |
-
#
|
348 |
-
elapsed = time.time() - st.session_state.
|
349 |
-
remaining = max(0, st.session_state.refresh_rate -
|
350 |
-
|
|
|
|
|
|
|
351 |
|
352 |
# Auto-refresh logic
|
353 |
if elapsed >= st.session_state.refresh_rate:
|
|
|
354 |
st.session_state.last_refresh = time.time()
|
355 |
st.rerun()
|
356 |
else:
|
357 |
-
st.markdown(f"<script>window.setTimeout(() => window.location.reload(),
|
358 |
|
359 |
# Sidebar vote stats
|
360 |
st.sidebar.subheader("Vote Totals")
|
|
|
30 |
IMAGE_VOTES_FILE = os.path.join(VOTE_DIR, "image_votes.md")
|
31 |
HISTORY_FILE = os.path.join(VOTE_DIR, "vote_history.md")
|
32 |
|
33 |
+
# Unicode digit conversion table - the magic map for emoji numbers! π’β¨
|
34 |
+
UNICODE_DIGITS = {
|
35 |
+
0: "0οΈβ£", 1: "1οΈβ£", 2: "2οΈβ£", 3: "3οΈβ£", 4: "4οΈβ£",
|
36 |
+
5: "5οΈβ£", 6: "6οΈβ£", 7: "7οΈβ£", 8: "8οΈβ£", 9: "9οΈβ£"
|
37 |
+
}
|
38 |
+
|
39 |
+
# Unicode font examples - the stylish wardrobe of text flair! ππ
|
40 |
+
UNICODE_FONTS = [
|
41 |
+
("Normal", lambda x: x), # Plain olβ text
|
42 |
+
("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)),
|
43 |
+
("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)),
|
44 |
+
("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)),
|
45 |
+
("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)),
|
46 |
+
("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)),
|
47 |
+
("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)),
|
48 |
+
("Sans 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)),
|
49 |
+
("Mono", 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)),
|
50 |
+
("Circle", lambda x: "".join(chr(ord(c) + 0x24B6 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x24D0 - 0x61) if 'a' <= c <= 'z' else c for c in x))
|
51 |
+
]
|
52 |
+
|
53 |
# Node name - the appβs codename generator, sneaky and slick! π΅οΈββοΈπΎ
|
54 |
def get_node_name():
|
55 |
"""π² Spins the wheel of fate to name our node - a random alias or user pick! π·οΈ"""
|
|
|
226 |
|
227 |
# Chat interface maker - the stage builder for our chat extravaganza! πποΈ
|
228 |
def create_streamlit_interface(initial_username):
|
229 |
+
"""ποΈ Sets up the chat stage with live updates, pulsing timers, voting, and refresh flair! π"""
|
230 |
# Custom CSS for a sleek chat box and timer
|
231 |
st.markdown("""
|
232 |
<style>
|
|
|
240 |
overflow-y: auto;
|
241 |
}
|
242 |
.timer {
|
243 |
+
font-size: 24px;
|
244 |
color: #ffcc00;
|
245 |
text-align: center;
|
246 |
+
animation: pulse 1s infinite;
|
247 |
+
}
|
248 |
+
@keyframes pulse {
|
249 |
+
0% { transform: scale(1); }
|
250 |
+
50% { transform: scale(1.1); }
|
251 |
+
100% { transform: scale(1); }
|
252 |
}
|
253 |
</style>
|
254 |
""", unsafe_allow_html=True)
|
255 |
|
256 |
# Title and intro
|
257 |
st.title(f"Chat & Quote Node: {NODE_NAME}")
|
258 |
+
st.markdown("Chat, vote on messages, quotes, and images - watch the timer pulse! π")
|
259 |
|
260 |
# Session state for username, refresh rate, and quote index
|
261 |
if 'username' not in st.session_state:
|
|
|
264 |
st.session_state.refresh_rate = 5
|
265 |
if 'last_refresh' not in st.session_state:
|
266 |
st.session_state.last_refresh = time.time()
|
267 |
+
if 'timer_start' not in st.session_state:
|
268 |
+
st.session_state.timer_start = time.time() # Autostart timer
|
269 |
if 'quote_index' not in st.session_state:
|
270 |
quotes = load_quotes("famous")
|
271 |
st.session_state.quote_index = random.randint(0, max(0, len(quotes) - 1)) if quotes else 0
|
|
|
285 |
if st.button(f"π", key=f"chat_vote_{i}"):
|
286 |
user_hash = generate_user_hash()
|
287 |
save_vote(QUOTE_VOTES_FILE, line, user_hash)
|
288 |
+
st.session_state.timer_start = time.time()
|
289 |
st.rerun()
|
290 |
|
291 |
user_list = get_user_list(chat_content)
|
292 |
new_username = st.selectbox("Switch User", user_list + [st.session_state.username], index=len(user_list))
|
293 |
if new_username != st.session_state.username:
|
294 |
st.session_state.username = new_username
|
295 |
+
st.session_state.timer_start = time.time()
|
296 |
|
297 |
message = st.text_input("Message", placeholder="Type your epic line here! βοΈ")
|
298 |
if st.button("Send π") and message.strip():
|
299 |
save_chat_entry(st.session_state.username, message)
|
300 |
+
st.session_state.timer_start = time.time()
|
301 |
st.rerun()
|
302 |
|
303 |
# Quote section
|
304 |
st.subheader("Quote of the Moment π")
|
305 |
quotes = load_quotes(st.session_state.quote_source)
|
306 |
if quotes:
|
|
|
307 |
st.session_state.quote_index = st.session_state.quote_index % len(quotes)
|
308 |
quote = quotes[st.session_state.quote_index]
|
309 |
col1, col2 = st.columns([5, 1])
|
|
|
313 |
if st.button("π Upvote", key="quote_vote"):
|
314 |
user_hash = generate_user_hash()
|
315 |
save_vote(QUOTE_VOTES_FILE, quote, user_hash)
|
316 |
+
st.session_state.timer_start = time.time()
|
317 |
st.rerun()
|
318 |
+
if time.time() - st.session_state.last_refresh > 10:
|
319 |
st.session_state.quote_index = (st.session_state.quote_index + 1) % len(quotes)
|
320 |
st.session_state.quote_source = "custom" if st.session_state.quote_source == "famous" else "famous"
|
321 |
+
quotes = load_quotes(st.session_state.quote_source)
|
322 |
st.session_state.quote_index = st.session_state.quote_index % len(quotes) if quotes else 0
|
323 |
st.session_state.last_refresh = time.time()
|
324 |
st.rerun()
|
|
|
338 |
if st.button(f"π Upvote {image1}", key=f"img_vote_{image1}"):
|
339 |
user_hash = generate_user_hash()
|
340 |
save_vote(IMAGE_VOTES_FILE, image1, user_hash)
|
341 |
+
st.session_state.timer_start = time.time()
|
342 |
st.rerun()
|
343 |
with col2:
|
344 |
st.image(os.path.join(image_dir, image2))
|
345 |
if st.button(f"π Upvote {image2}", key=f"img_vote_{image2}"):
|
346 |
user_hash = generate_user_hash()
|
347 |
save_vote(IMAGE_VOTES_FILE, image2, user_hash)
|
348 |
+
st.session_state.timer_start = time.time()
|
349 |
st.rerun()
|
350 |
else:
|
351 |
st.error("Need at least 2 images in the directory for voting!")
|
352 |
|
353 |
+
# Refresh rate controls with pulsing timer
|
354 |
st.subheader("Set Refresh Rate β³")
|
355 |
refresh_rate = st.slider("Refresh Rate (seconds)", min_value=1, max_value=300, value=st.session_state.refresh_rate, step=1)
|
356 |
+
if refresh_rate != st.session_state.refresh_rate:
|
357 |
+
st.session_state.refresh_rate = refresh_rate
|
358 |
+
st.session_state.timer_start = time.time() # Reset timer on change
|
359 |
|
360 |
col1, col2, col3 = st.columns(3)
|
361 |
with col1:
|
362 |
if st.button("π Small (1s)"):
|
363 |
st.session_state.refresh_rate = 1
|
364 |
+
st.session_state.timer_start = time.time()
|
365 |
st.rerun()
|
366 |
with col2:
|
367 |
if st.button("π’ Medium (5s)"):
|
368 |
st.session_state.refresh_rate = 5
|
369 |
+
st.session_state.timer_start = time.time()
|
370 |
st.rerun()
|
371 |
with col3:
|
372 |
if st.button("π Large (5m)"):
|
373 |
st.session_state.refresh_rate = 300
|
374 |
+
st.session_state.timer_start = time.time()
|
375 |
st.rerun()
|
376 |
|
377 |
+
# Pulsing countdown timer with emoji digits and random Unicode font
|
378 |
+
elapsed = int(time.time() - st.session_state.timer_start)
|
379 |
+
remaining = max(0, st.session_state.refresh_rate - (elapsed % st.session_state.refresh_rate))
|
380 |
+
font_name, font_func = random.choice(UNICODE_FONTS)
|
381 |
+
countdown_str = "".join(UNICODE_DIGITS[int(d)] for d in str(remaining)) if remaining < 10 else font_func(str(remaining))
|
382 |
+
timer_emoji = "β³" if remaining % 2 == 0 else "π" # Pulse effect
|
383 |
+
st.markdown(f"<p class='timer'>{timer_emoji} {font_func('Next refresh in:')} {countdown_str} {font_func('seconds')}</p>", unsafe_allow_html=True)
|
384 |
|
385 |
# Auto-refresh logic
|
386 |
if elapsed >= st.session_state.refresh_rate:
|
387 |
+
st.session_state.timer_start = time.time()
|
388 |
st.session_state.last_refresh = time.time()
|
389 |
st.rerun()
|
390 |
else:
|
391 |
+
st.markdown(f"<script>window.setTimeout(() => window.location.reload(), 1000);</script>", unsafe_allow_html=True)
|
392 |
|
393 |
# Sidebar vote stats
|
394 |
st.sidebar.subheader("Vote Totals")
|