awacke1 commited on
Commit
143f307
Β·
verified Β·
1 Parent(s): c1728eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +414 -174
app.py CHANGED
@@ -1,94 +1,202 @@
1
  import streamlit as st
2
- import anthropic
3
- import os
4
- import base64
5
- import glob
6
- import json
7
- import pytz
8
  from datetime import datetime
9
- from streamlit.components.v1 import html
 
 
 
10
  from PIL import Image
 
11
  import re
12
  from urllib.parse import quote
13
 
14
- # 1. App Configuration
15
- Site_Name = 'πŸ€–πŸ§ Claude35πŸ“πŸ”¬'
16
- title="πŸ€–πŸ§ Claude35πŸ“πŸ”¬"
17
- helpURL='https://huggingface.co/awacke1'
18
- bugURL='https://huggingface.co/spaces/awacke1'
19
- icons='πŸ€–πŸ§ πŸ”¬πŸ“'
20
 
21
  st.set_page_config(
22
  page_title=title,
23
  page_icon=icons,
24
  layout="wide",
25
- initial_sidebar_state="auto",
26
- menu_items={
27
- 'Get Help': helpURL,
28
- 'Report a bug': bugURL,
29
- 'About': title
30
- }
31
  )
32
 
33
- # Set up the Anthropic client
34
- client = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
35
-
36
- # Initialize session state
37
- if "chat_history" not in st.session_state:
38
- st.session_state.chat_history = []
39
-
40
- # Helper Functions: All Your Essentials πŸš€
41
-
42
- # Function to get a file download link (because you deserve easy downloads 😎)
43
- def get_download_link(file_path):
44
- with open(file_path, "rb") as file:
45
- contents = file.read()
46
- b64 = base64.b64encode(contents).decode()
47
- file_name = os.path.basename(file_path)
48
- return f'<a href="data:file/txt;base64,{b64}" download="{file_name}">Download {file_name}πŸ“‚</a>'
49
-
50
- # Function to generate a filename based on prompt and time (because names matter πŸ•’)
51
- def generate_filename(prompt, file_type):
52
- central = pytz.timezone('US/Central')
53
- safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
54
- safe_prompt = re.sub(r'\W+', '_', prompt)[:90]
55
- return f"{safe_date_time}_{safe_prompt}.{file_type}"
56
-
57
- # Function to create and save a file (and avoid the black hole of lost data πŸ•³)
58
- def create_file(filename, prompt, response, should_save=True):
59
- if not should_save:
60
- return
61
- with open(filename, 'w', encoding='utf-8') as file:
62
- file.write(prompt + "\n\n" + response)
63
-
64
- # Function to load file content (for revisiting the past πŸ“œ)
65
- def load_file(file_name):
66
- with open(file_name, "r", encoding='utf-8') as file:
67
- content = file.read()
68
- return content
69
-
70
- # Function to display handy glossary entity links (search like a pro πŸ”)
71
- def display_glossary_entity(k):
72
- search_urls = {
73
- "πŸš€πŸŒŒArXiv": lambda k: f"/?q={quote(k)}",
74
- "πŸ“–": lambda k: f"https://en.wikipedia.org/wiki/{quote(k)}",
75
- "πŸ”": lambda k: f"https://www.google.com/search?q={quote(k)}",
76
- "πŸŽ₯": lambda k: f"https://www.youtube.com/results?search_query={quote(k)}",
77
- }
78
- links_md = ' '.join([f"[{emoji}]({url(k)})" for emoji, url in search_urls.items()])
79
- st.markdown(f"**{k}** <small>{links_md}</small>", unsafe_allow_html=True)
80
-
81
- # Function to create zip of files (because more is more 🧳)
82
- def create_zip_of_files(files):
83
- import zipfile
84
- zip_name = "all_files.zip"
85
- with zipfile.ZipFile(zip_name, 'w') as zipf:
86
- for file in files:
87
- zipf.write(file)
88
- return zip_name
89
-
90
- # Function to create HTML for autoplaying and looping video (for the full cinematic effect πŸŽ₯)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  def get_video_html(video_path, width="100%"):
 
92
  video_url = f"data:video/mp4;base64,{base64.b64encode(open(video_path, 'rb').read()).decode()}"
93
  return f'''
94
  <video width="{width}" controls autoplay muted loop>
@@ -97,8 +205,8 @@ def get_video_html(video_path, width="100%"):
97
  </video>
98
  '''
99
 
100
- # Function to create HTML for audio player (when life needs a soundtrack 🎢)
101
  def get_audio_html(audio_path, width="100%"):
 
102
  audio_url = f"data:audio/mpeg;base64,{base64.b64encode(open(audio_path, 'rb').read()).decode()}"
103
  return f'''
104
  <audio controls style="width: {width};">
@@ -107,109 +215,241 @@ def get_audio_html(audio_path, width="100%"):
107
  </audio>
108
  '''
109
 
 
110
 
111
- # Streamlit App Layout (like a house with better flow 🏑)
112
- def main():
113
-
114
- # Sidebar with Useful Controls (All the VIP actions πŸŽ›)
115
- st.sidebar.title("🧠ClaudeπŸ“")
116
-
117
- all_files = glob.glob("*.md")
118
- all_files.sort(reverse=True)
 
 
 
119
 
120
- if st.sidebar.button("πŸ—‘ Delete All"):
121
- for file in all_files:
122
- os.remove(file)
123
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
- if st.sidebar.button("⬇️ Download All"):
126
- zip_file = create_zip_of_files(all_files)
127
- st.sidebar.markdown(get_download_link(zip_file), unsafe_allow_html=True)
 
 
128
 
129
- for file in all_files:
130
- col1, col2, col3, col4 = st.sidebar.columns([1,3,1,1])
 
 
 
 
 
131
  with col1:
132
- if st.button("🌐", key="view_"+file):
133
- st.session_state.current_file = file
134
- st.session_state.file_content = load_file(file)
135
  with col2:
136
- st.markdown(get_download_link(file), unsafe_allow_html=True)
137
- with col3:
138
- if st.button("πŸ“‚", key="edit_"+file):
139
- st.session_state.current_file = file
140
- st.session_state.file_content = load_file(file)
141
- with col4:
142
- if st.button("πŸ—‘", key="delete_"+file):
143
- os.remove(file)
144
  st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
- # Main Area: Chat with Claude (He’s a good listener πŸ’¬)
147
- user_input = st.text_area("Message πŸ“¨:", height=100)
148
-
149
- if st.button("Send πŸ“¨"):
150
- if user_input:
151
- response = client.messages.create(
152
- model="claude-3-sonnet-20240229",
153
- max_tokens=1000,
154
- messages=[
155
- {"role": "user", "content": user_input}
156
- ]
157
- )
158
- st.write("Claude's reply 🧠:")
159
- st.write(response.content[0].text)
160
-
161
- filename = generate_filename(user_input, "md")
162
- create_file(filename, user_input, response.content[0].text)
163
-
164
- st.session_state.chat_history.append({"user": user_input, "claude": response.content[0].text})
165
-
166
- # Display Chat History (Never forget a good chat πŸ’­)
167
- st.subheader("Past Conversations πŸ“œ")
168
- for chat in st.session_state.chat_history:
169
- st.text_area("You said πŸ’¬:", chat["user"], height=100, disabled=True)
170
- st.text_area("Claude replied πŸ€–:", chat["claude"], height=200, disabled=True)
171
- st.markdown("---")
172
-
173
- # File Editor (When you need to tweak things ✏️)
174
- if hasattr(st.session_state, 'current_file'):
175
- st.subheader(f"Editing: {st.session_state.current_file} πŸ› ")
176
- new_content = st.text_area("File Content ✏️:", st.session_state.file_content, height=300)
177
- if st.button("Save Changes πŸ’Ύ"):
178
- with open(st.session_state.current_file, 'w', encoding='utf-8') as file:
179
- file.write(new_content)
180
- st.success("File updated successfully! πŸŽ‰")
181
-
182
- # Image Gallery (For your viewing pleasure πŸ“Έ)
183
- st.subheader("Image Gallery πŸ–Ό")
184
- image_files = glob.glob("*.png") + glob.glob("*.jpg") + glob.glob("*.jpeg")
185
- image_cols = st.slider("Gallery Columns πŸ–Ό", min_value=1, max_value=15, value=5)
186
- cols = st.columns(image_cols)
187
- for idx, image_file in enumerate(image_files):
188
- with cols[idx % image_cols]:
189
- img = Image.open(image_file)
190
- #st.image(img, caption=image_file, use_container_width=True)
191
- st.image(img, use_container_width=True)
192
- display_glossary_entity(os.path.splitext(image_file)[0])
193
-
194
- # Video Gallery (Let’s roll the tapes 🎬)
195
- st.subheader("Video Gallery πŸŽ₯")
196
- video_files = glob.glob("*.mp4")
197
- video_cols = st.slider("Gallery Columns 🎬", min_value=1, max_value=5, value=3)
198
- cols = st.columns(video_cols)
199
- for idx, video_file in enumerate(video_files):
200
- with cols[idx % video_cols]:
201
- st.markdown(get_video_html(video_file, width="100%"), unsafe_allow_html=True)
202
- display_glossary_entity(os.path.splitext(video_file)[0])
203
-
204
- # Audio Gallery (Tunes for the mood 🎢)
205
- st.subheader("Audio Gallery 🎧")
206
- audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
207
- audio_cols = st.slider("Gallery Columns 🎢", min_value=1, max_value=15, value=5)
208
- cols = st.columns(audio_cols)
209
- for idx, audio_file in enumerate(audio_files):
210
- with cols[idx % audio_cols]:
211
- st.markdown(get_audio_html(audio_file, width="100%"), unsafe_allow_html=True)
212
- display_glossary_entity(os.path.splitext(audio_file)[0])
213
 
214
  if __name__ == "__main__":
215
- main()
 
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
  import re
14
  from urllib.parse import quote
15
 
16
+ # App Configuration
17
+ Site_Name = 'πŸ€–πŸ§ Chat & Quote NodeπŸ“πŸ”¬'
18
+ title = "πŸ€–πŸ§ Chat & Quote NodeπŸ“πŸ”¬"
19
+ icons = 'πŸ€–πŸ§ πŸ”¬πŸ“'
20
+ START_ROOM = "Sector 🌌"
 
21
 
22
  st.set_page_config(
23
  page_title=title,
24
  page_icon=icons,
25
  layout="wide",
26
+ initial_sidebar_state="auto"
 
 
 
 
 
27
  )
28
 
29
+ # Fun usernames with emojis - the VIP list of quirky characters! πŸŽ‰πŸ˜œ
30
+ FUN_USERNAMES = [
31
+ "CosmicJester 🌌", "PixelPanda 🐼", "QuantumQuack πŸ¦†", "StellarSquirrel 🐿️",
32
+ "GizmoGuru βš™οΈ", "NebulaNinja 🌠", "ByteBuster πŸ’Ύ", "GalacticGopher 🌍",
33
+ "RocketRaccoon πŸš€", "EchoElf 🧝", "PhantomFox 🦊", "WittyWizard πŸ§™",
34
+ "LunarLlama πŸŒ™", "SolarSloth β˜€οΈ", "AstroAlpaca πŸ¦™", "CyberCoyote 🐺",
35
+ "MysticMoose 🦌", "GlitchGnome 🧚", "VortexViper 🐍", "ChronoChimp πŸ’"
36
+ ]
37
+
38
+ # Directories for chat and votes - the secret vaults where tales and tallies are stashed! πŸ—„οΈπŸ”’
39
+ CHAT_DIR = "chat_logs"
40
+ VOTE_DIR = "vote_logs"
41
+ MEDIA_DIR = "media"
42
+ os.makedirs(CHAT_DIR, exist_ok=True)
43
+ os.makedirs(VOTE_DIR, exist_ok=True)
44
+ os.makedirs(MEDIA_DIR, exist_ok=True)
45
+
46
+ # Persistent files - the grand tomes of chatter and votes! πŸ“–βœ¨
47
+ CHAT_FILE = os.path.join(CHAT_DIR, "global_chat.md")
48
+ QUOTE_VOTES_FILE = os.path.join(VOTE_DIR, "quote_votes.md")
49
+ IMAGE_VOTES_FILE = os.path.join(VOTE_DIR, "image_votes.md")
50
+ HISTORY_FILE = os.path.join(VOTE_DIR, "vote_history.md")
51
+
52
+ # Unicode digit conversion table - the magic map for emoji numbers! πŸ”’βœ¨
53
+ UNICODE_DIGITS = {
54
+ 0: "0️⃣", 1: "1️⃣", 2: "2️⃣", 3: "3️⃣", 4: "4️⃣",
55
+ 5: "5️⃣", 6: "6️⃣", 7: "7️⃣", 8: "8️⃣", 9: "9️⃣"
56
+ }
57
+
58
+ # Unicode font examples - the stylish wardrobe of text flair! πŸ‘—πŸ“
59
+ UNICODE_FONTS = [
60
+ ("Normal", lambda x: x),
61
+ ("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)),
62
+ ("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)),
63
+ ("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)),
64
+ ("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)),
65
+ ("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)),
66
+ ("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)),
67
+ ("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)),
68
+ ("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)),
69
+ ("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))
70
+ ]
71
+
72
+ # Node name - the app’s codename generator, sneaky and slick! πŸ•΅οΈβ€β™‚οΈπŸ’Ύ
73
+ def get_node_name():
74
+ """🎲 Spins the wheel of fate to name our node - a random alias or user pick! 🏷️"""
75
+ parser = argparse.ArgumentParser(description='Start a chat node with a specific name')
76
+ parser.add_argument('--node-name', type=str, default=None, help='Name for this chat node')
77
+ parser.add_argument('--port', type=int, default=8501, help='Port to run the Streamlit interface on')
78
+ args = parser.parse_args()
79
+ return args.node_name or f"node-{uuid.uuid4().hex[:8]}", args.port
80
+
81
+ # Chat saver - the scribe etching epic messages into the eternal scroll! πŸ–‹οΈπŸ“œ
82
+ def save_chat_entry(username, message):
83
+ """πŸ–ŒοΈ Carves a chat line into the grand Markdown tome - history in the making! πŸ›οΈ"""
84
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
85
+ entry = f"[{timestamp}] {username}: {message}"
86
+ try:
87
+ with open(CHAT_FILE, 'a') as f:
88
+ f.write(f"{entry}\n")
89
+ return True
90
+ except Exception as e:
91
+ print(f"Oops! Failed to save chat: {e}")
92
+ return False
93
+
94
+ # Chat loader - the archaeologist unearthing the chat saga! β›οΈπŸ“š
95
+ def load_chat():
96
+ """πŸ” Digs up the chat treasure from the filesystem - tales of old and new! πŸ’°"""
97
+ if not os.path.exists(CHAT_FILE):
98
+ with open(CHAT_FILE, 'w') as f:
99
+ f.write(f"# {START_ROOM} Chat\n\nWelcome to the cosmic hub - start chatting! 🎀\n")
100
+ try:
101
+ with open(CHAT_FILE, 'r') as f:
102
+ content = f.read()
103
+ lines = content.strip().split('\n')
104
+ numbered_content = "\n".join(f"{i+1}. {line}" for i, line in enumerate(lines) if line.strip())
105
+ return numbered_content
106
+ except Exception as e:
107
+ print(f"Chat load hiccup: {e}")
108
+ return f"# Error loading {START_ROOM} chat\nSomething went wonky! 😡"
109
+
110
+ # User list grabber - the social butterfly spotting all the chatters! πŸ¦‹πŸ‘₯
111
+ def get_user_list(chat_content):
112
+ """πŸ‘€ Peeks at the chat to spot all the cool cats talking - who’s in the club? 🎸"""
113
+ users = set()
114
+ for line in chat_content.split('\n'):
115
+ if line.strip() and ': ' in line:
116
+ user = line.split(': ')[1].split(' ')[0]
117
+ users.add(user)
118
+ return sorted(list(users))
119
+
120
+ # Quote loader - the sage pulling wisdom from the ages! πŸ“œπŸ§™
121
+ def load_quotes(source="famous"):
122
+ """πŸ“š Grabs a stack of wise words from famous folks or custom quips! πŸ—£οΈ"""
123
+ famous_quotes = [
124
+ "The true sign of intelligence is not knowledge but imagination. – Albert Einstein",
125
+ "I have not failed. I've just found 10,000 ways that won't work. – Thomas Edison",
126
+ "Innovation distinguishes between a leader and a follower. – Steve Jobs",
127
+ "Research is what I'm doing when I don't know what I'm doing. – Wernher von Braun",
128
+ "The only way to discover the limits of the possible is to go beyond them into the impossible. – Arthur C. Clarke",
129
+ "Success is a science; if you have the conditions, you get the result. – Oscar Wilde",
130
+ "An expert is a person who has made all the mistakes that can be made in a very narrow field. – Niels Bohr",
131
+ "The important thing is to not stop questioning. Curiosity has its own reason for existing. – Albert Einstein",
132
+ "The best way to predict the future is to invent it. – Alan Kay",
133
+ "If I have seen further it is by standing on the shoulders of Giants. – Isaac Newton",
134
+ "Logic will get you from A to B. Imagination will take you everywhere. – Albert Einstein",
135
+ "Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world. – Albert Einstein",
136
+ "Science is a way of thinking much more than it is a body of knowledge. – Carl Sagan",
137
+ "We cannot solve our problems with the same thinking we used when we created them. – Albert Einstein",
138
+ "The true method of knowledge is experiment. – William Blake",
139
+ "The scientist is not a person who gives the right answers, he's one who asks the right questions. – Claude Levi-Strauss",
140
+ "It's kind of fun to do the impossible. – Walt Disney",
141
+ "Any sufficiently advanced technology is indistinguishable from magic. – Arthur C. Clarke",
142
+ "Creativity is intelligence having fun. – Albert Einstein",
143
+ "To invent, you need a good imagination and a pile of junk. – Thomas Edison"
144
+ ]
145
+ custom_quotes = [
146
+ "Every age unfolds a new lesson. Life's chapters evolve, each teaching us anew.",
147
+ "From infancy to twilight, our journey is painted in growth. Every stage shines with its own wisdom.",
148
+ "Love is the universal language, transcending boundaries and touching souls.",
149
+ "Through love, we find connection, unity, and the essence of existence."
150
+ ]
151
+ quotes = famous_quotes if source == "famous" else custom_quotes
152
+ return quotes if quotes else ["No quotes available - check back later! πŸ“­"]
153
+
154
+ # Vote saver - the tally keeper counting thumbs up! πŸ‘πŸ“Š
155
+ def save_vote(file, item, user_hash):
156
+ """✍️ Tallies a vote in the grand ledger - your opinion matters! πŸ—³οΈ"""
157
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
158
+ entry = f"[{timestamp}] {user_hash} voted for {item}"
159
+ try:
160
+ with open(file, 'a') as f:
161
+ f.write(f"{entry}\n")
162
+ with open(HISTORY_FILE, 'a') as f:
163
+ f.write(f"- {timestamp} - User {user_hash} voted for {item}\n")
164
+ return True
165
+ except Exception as e:
166
+ print(f"Vote save flop: {e}")
167
+ return False
168
+
169
+ # Vote loader - the scorekeeper tallying the crowd’s cheers! πŸŽ‰πŸ…
170
+ def load_votes(file):
171
+ """πŸ“ˆ Counts the votes from the ledger - who’s winning the popularity contest? πŸ†"""
172
+ if not os.path.exists(file):
173
+ with open(file, 'w') as f:
174
+ f.write("# Vote Tally\n\nNo votes yet - get clicking! πŸ–±οΈ\n")
175
+ try:
176
+ with open(file, 'r') as f:
177
+ lines = f.read().strip().split('\n')
178
+ votes = {}
179
+ for line in lines[2:]: # Skip header
180
+ if line.strip() and 'voted for' in line:
181
+ item = line.split('voted for ')[1]
182
+ votes[item] = votes.get(item, 0) + 1
183
+ return votes
184
+ except Exception as e:
185
+ print(f"Vote load oopsie: {e}")
186
+ return {}
187
+
188
+ # User hash generator - the secret agent giving you a cool code! πŸ•΅οΈβ€β™‚οΈπŸ”‘
189
+ def generate_user_hash():
190
+ """πŸ•΅οΈ Crafts a snazzy 8-digit ID badge - you’re in the club now! 🎟️"""
191
+ if 'user_hash' not in st.session_state:
192
+ session_id = str(random.getrandbits(128))
193
+ hash_object = hashlib.md5(session_id.encode())
194
+ st.session_state['user_hash'] = hash_object.hexdigest()[:8]
195
+ return st.session_state['user_hash']
196
+
197
+ # Media HTML generators - IVA’s multimedia magic! πŸŽ₯πŸŽΆπŸ–ΌοΈ
198
  def get_video_html(video_path, width="100%"):
199
+ """🎬 Rolls out the red carpet for videos - autoplay and loop like a star! 🌟"""
200
  video_url = f"data:video/mp4;base64,{base64.b64encode(open(video_path, 'rb').read()).decode()}"
201
  return f'''
202
  <video width="{width}" controls autoplay muted loop>
 
205
  </video>
206
  '''
207
 
 
208
  def get_audio_html(audio_path, width="100%"):
209
+ """🎢 Drops a beat with audio - your personal DJ in action! 🎧"""
210
  audio_url = f"data:audio/mpeg;base64,{base64.b64encode(open(audio_path, 'rb').read()).decode()}"
211
  return f'''
212
  <audio controls style="width: {width};">
 
215
  </audio>
216
  '''
217
 
218
+ active_connections = {}
219
 
220
+ # WebSocket handler - the bouncer at the Sector rave, keeping it hopping! πŸŽ‰πŸšͺ
221
+ async def websocket_handler(websocket, path):
222
+ """🎧 Guards the cosmic gate, welcoming all to Sector and booting crashers! 🚨"""
223
+ try:
224
+ client_id = str(uuid.uuid4())
225
+ room_id = "chat" # Single room "Sector 🌌"
226
+ active_connections.setdefault(room_id, {})[client_id] = websocket
227
+ print(f"Client {client_id} joined the Sector party!")
228
+ # Auto-join message for every connection
229
+ username = st.session_state.get('username', random.choice(FUN_USERNAMES))
230
+ save_chat_entry("System 🌟", f"{username} has joined {START_ROOM}!")
231
 
232
+ async for message in websocket:
233
+ try:
234
+ parts = message.split('|', 1)
235
+ if len(parts) == 2:
236
+ username, content = parts
237
+ save_chat_entry(username, content)
238
+ await broadcast_message(f"{username}|{content}", room_id)
239
+ except Exception as e:
240
+ print(f"Message mishap: {e}")
241
+ await websocket.send(f"ERROR|Oops, bad message format! 😬")
242
+ except websockets.ConnectionClosed:
243
+ print(f"Client {client_id} bailed from Sector!")
244
+ save_chat_entry("System 🌟", f"{username} has left {START_ROOM}!")
245
+ finally:
246
+ if room_id in active_connections and client_id in active_connections[room_id]:
247
+ del active_connections[room_id][client_id]
248
+ if not active_connections[room_id]:
249
+ del active_connections[room_id]
250
+
251
+ # Broadcaster - the megaphone blasting Sector vibes to all! πŸ“£πŸŽΆ
252
+ async def broadcast_message(message, room_id):
253
+ """πŸ“’ Shouts the latest Sector beat to every cosmic dancer - hear it loud! 🎡"""
254
+ if room_id in active_connections:
255
+ disconnected = []
256
+ for client_id, ws in active_connections[room_id].items():
257
+ try:
258
+ await ws.send(message)
259
+ except websockets.ConnectionClosed:
260
+ disconnected.append(client_id)
261
+ for client_id in disconnected:
262
+ del active_connections[room_id][client_id]
263
+
264
+ # WebSocket starter - the DJ spinning up the Sector tunes! 🎧πŸ”₯
265
+ async def start_websocket_server(host='0.0.0.0', port=8765):
266
+ """🌐 Cranks up the WebSocket jukebox, ready to rock the Sector scene! 🎸"""
267
+ server = await websockets.serve(websocket_handler, host, port)
268
+ print(f"WebSocket server jamming on ws://{host}:{port}")
269
+ return server
270
+
271
+ # Chat interface maker - the stage builder for our Sector extravaganza! 🎭🏟️
272
+ def create_streamlit_interface(initial_username):
273
+ """πŸ–ŒοΈ Sets up the Sector stage with pulsing timers, voting, and IVA media flair! 🌟"""
274
+ # Custom CSS for a sleek chat box and timer
275
+ st.markdown("""
276
+ <style>
277
+ .chat-box {
278
+ font-family: monospace;
279
+ background: #1e1e1e;
280
+ color: #d4d4d4;
281
+ padding: 10px;
282
+ border-radius: 5px;
283
+ height: 300px;
284
+ overflow-y: auto;
285
+ }
286
+ .timer {
287
+ font-size: 24px;
288
+ color: #ffcc00;
289
+ text-align: center;
290
+ animation: pulse 1s infinite;
291
+ }
292
+ @keyframes pulse {
293
+ 0% { transform: scale(1); }
294
+ 50% { transform: scale(1.1); }
295
+ 100% { transform: scale(1); }
296
+ }
297
+ </style>
298
+ """, unsafe_allow_html=True)
299
+
300
+ # Title and intro
301
+ st.title(f"{Site_Name}")
302
+ st.markdown(f"Welcome to {START_ROOM} - chat, vote, and enjoy IVA’s media magic! πŸŽ‰")
303
+
304
+ # Session state initialization
305
+ if 'username' not in st.session_state:
306
+ st.session_state.username = initial_username
307
+ save_chat_entry("System 🌟", f"{initial_username} has joined {START_ROOM}!")
308
+ if 'refresh_rate' not in st.session_state:
309
+ st.session_state.refresh_rate = 5
310
+ if 'timer_start' not in st.session_state:
311
+ st.session_state.timer_start = time.time() # Autostart timer
312
+ if 'quote_index' not in st.session_state:
313
+ quotes = load_quotes("famous")
314
+ st.session_state.quote_index = random.randint(0, max(0, len(quotes) - 1)) if quotes else 0
315
+ if 'quote_source' not in st.session_state:
316
+ st.session_state.quote_source = "famous"
317
+
318
+ # Chat section
319
+ st.subheader(f"{START_ROOM} Chat πŸ’¬")
320
+ chat_content = load_chat()
321
+ chat_lines = chat_content.split('\n')
322
+ for i, line in enumerate(chat_lines):
323
+ if line.strip() and ': ' in line:
324
+ col1, col2 = st.columns([5, 1])
325
+ with col1:
326
+ st.markdown(line)
327
+ with col2:
328
+ if st.button(f"πŸ‘", key=f"chat_vote_{i}"):
329
+ user_hash = generate_user_hash()
330
+ save_vote(QUOTE_VOTES_FILE, line, user_hash)
331
+ st.session_state.timer_start = time.time()
332
+ st.rerun()
333
+
334
+ user_list = get_user_list(chat_content)
335
+ new_username = st.selectbox("Switch User", user_list + [st.session_state.username], index=len(user_list))
336
+ if new_username != st.session_state.username:
337
+ save_chat_entry("System 🌟", f"{st.session_state.username} switched to {new_username} in {START_ROOM}!")
338
+ st.session_state.username = new_username
339
+ st.session_state.timer_start = time.time()
340
 
341
+ message = st.text_input("Message", placeholder="Type your epic line here! ✍️")
342
+ if st.button("Send πŸš€") and message.strip():
343
+ save_chat_entry(st.session_state.username, message)
344
+ st.session_state.timer_start = time.time()
345
+ st.rerun()
346
 
347
+ # Quote section
348
+ st.subheader("Quote of the Moment πŸ“")
349
+ quotes = load_quotes(st.session_state.quote_source)
350
+ if quotes:
351
+ st.session_state.quote_index = st.session_state.quote_index % len(quotes)
352
+ quote = quotes[st.session_state.quote_index]
353
+ col1, col2 = st.columns([5, 1])
354
  with col1:
355
+ st.markdown(quote)
 
 
356
  with col2:
357
+ if st.button("πŸ‘ Upvote", key="quote_vote"):
358
+ user_hash = generate_user_hash()
359
+ save_vote(QUOTE_VOTES_FILE, quote, user_hash)
360
+ st.session_state.timer_start = time.time()
 
 
 
 
361
  st.rerun()
362
+ if time.time() - st.session_state.timer_start > 10: # 10s quote refresh
363
+ st.session_state.quote_index = (st.session_state.quote_index + 1) % len(quotes)
364
+ st.session_state.quote_source = "custom" if st.session_state.quote_source == "famous" else "famous"
365
+ quotes = load_quotes(st.session_state.quote_source)
366
+ st.session_state.quote_index = st.session_state.quote_index % len(quotes) if quotes else 0
367
+ st.session_state.timer_start = time.time()
368
+ st.rerun()
369
+ else:
370
+ st.markdown("No quotes available - check back later! πŸ“­")
371
+
372
+ # IVA Media Gallery
373
+ st.subheader("IVA Media Gallery 🎨🎢πŸŽ₯")
374
+ media_files = (
375
+ glob.glob(f"{MEDIA_DIR}/*.png") + glob.glob(f"{MEDIA_DIR}/*.jpg") + glob.glob(f"{MEDIA_DIR}/*.jpeg") +
376
+ glob.glob(f"{MEDIA_DIR}/*.mp3") + glob.glob(f"{MEDIA_DIR}/*.wav") +
377
+ glob.glob(f"{MEDIA_DIR}/*.mp4")
378
+ )
379
+ if media_files:
380
+ media_cols = st.slider("Gallery Columns", min_value=1, max_value=5, value=3)
381
+ cols = st.columns(media_cols)
382
+ for idx, media_file in enumerate(media_files):
383
+ with cols[idx % media_cols]:
384
+ if media_file.endswith(('.png', '.jpg', '.jpeg')):
385
+ st.image(media_file, use_container_width=True)
386
+ elif media_file.endswith(('.mp3', '.wav')):
387
+ st.markdown(get_audio_html(media_file, width="100%"), unsafe_allow_html=True)
388
+ elif media_file.endswith('.mp4'):
389
+ st.markdown(get_video_html(media_file, width="100%"), unsafe_allow_html=True)
390
+ if st.button(f"πŸ‘ Upvote {os.path.basename(media_file)}", key=f"media_vote_{idx}"):
391
+ user_hash = generate_user_hash()
392
+ save_vote(IMAGE_VOTES_FILE, media_file, user_hash)
393
+ st.session_state.timer_start = time.time()
394
+ st.rerun()
395
+ else:
396
+ st.error("No media files (images, audio, video) found in 'media' directory!")
397
+
398
+ # Refresh rate controls with pulsing timer
399
+ st.subheader("Set Refresh Rate ⏳")
400
+ refresh_rate = st.slider("Refresh Rate (seconds)", min_value=1, max_value=300, value=st.session_state.refresh_rate, step=1)
401
+ if refresh_rate != st.session_state.refresh_rate:
402
+ st.session_state.refresh_rate = refresh_rate
403
+ st.session_state.timer_start = time.time()
404
+
405
+ col1, col2, col3 = st.columns(3)
406
+ with col1:
407
+ if st.button("πŸ‡ Small (1s)"):
408
+ st.session_state.refresh_rate = 1
409
+ st.session_state.timer_start = time.time()
410
+ with col2:
411
+ if st.button("🐒 Medium (5s)"):
412
+ st.session_state.refresh_rate = 5
413
+ st.session_state.timer_start = time.time()
414
+ with col3:
415
+ if st.button("🐘 Large (5m)"):
416
+ st.session_state.refresh_rate = 300
417
+ st.session_state.timer_start = time.time()
418
+
419
+ # Pulsing countdown timer with emoji digits and random Unicode font
420
+ timer_placeholder = st.empty()
421
+ start_time = st.session_state.timer_start
422
+ for i in range(st.session_state.refresh_rate, -1, -1):
423
+ font_name, font_func = random.choice(UNICODE_FONTS)
424
+ countdown_str = "".join(UNICODE_DIGITS[int(d)] for d in str(i)) if i < 10 else font_func(str(i))
425
+ timer_emoji = "⏳" if i % 2 == 0 else "πŸ’“" # Pulse effect
426
+ timer_placeholder.markdown(f"<p class='timer'>{timer_emoji} {font_func('Next refresh in:')} {countdown_str} {font_func('seconds')}</p>", unsafe_allow_html=True)
427
+ time.sleep(1) # Pulse every second
428
+ st.session_state.timer_start = time.time()
429
+ st.session_state.last_refresh = time.time()
430
+ st.rerun()
431
+
432
+ # Sidebar vote stats
433
+ st.sidebar.subheader("Vote Totals")
434
+ chat_votes = load_votes(QUOTE_VOTES_FILE)
435
+ image_votes = load_votes(IMAGE_VOTES_FILE)
436
+ for item, count in chat_votes.items():
437
+ st.sidebar.write(f"{item}: {count} votes")
438
+ for image, count in image_votes.items():
439
+ st.sidebar.write(f"{image}: {count} votes")
440
+
441
+ # Main event - the ringmaster kicking off the Sector circus! πŸŽͺ🀑
442
+ async def main():
443
+ """🎀 Drops the mic and starts the Sector party - it’s showtime, folks! πŸŽ‰"""
444
+ global NODE_NAME
445
+ NODE_NAME, port = get_node_name()
446
+ await start_websocket_server()
447
+
448
+ query_params = st.query_params if hasattr(st, 'query_params') else {}
449
+ initial_username = query_params.get("username", random.choice(FUN_USERNAMES)) if query_params else random.choice(FUN_USERNAMES)
450
+ print(f"Welcoming {initial_username} to the Sector bash!")
451
 
452
+ create_streamlit_interface(initial_username)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
 
454
  if __name__ == "__main__":
455
+ asyncio.run(main())