Update app.py
Browse files
app.py
CHANGED
@@ -10,7 +10,7 @@ import sys
|
|
10 |
import os
|
11 |
import random
|
12 |
|
13 |
-
# Configure logging
|
14 |
logging.basicConfig(
|
15 |
level=logging.INFO,
|
16 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
@@ -18,7 +18,7 @@ logging.basicConfig(
|
|
18 |
)
|
19 |
logger = logging.getLogger("chat-node")
|
20 |
|
21 |
-
# Fun usernames with emojis
|
22 |
FUN_USERNAMES = [
|
23 |
"CosmicJester π", "PixelPanda πΌ", "QuantumQuack π¦", "StellarSquirrel πΏοΈ",
|
24 |
"GizmoGuru βοΈ", "NebulaNinja π ", "ByteBuster πΎ", "GalacticGopher π",
|
@@ -27,24 +27,29 @@ FUN_USERNAMES = [
|
|
27 |
"MysticMoose π¦", "GlitchGnome π§", "VortexViper π", "ChronoChimp π"
|
28 |
]
|
29 |
|
30 |
-
# Directory for logs
|
31 |
LOG_DIR = "user_logs"
|
32 |
os.makedirs(LOG_DIR, exist_ok=True)
|
33 |
|
34 |
-
# Node name
|
35 |
def get_node_name():
|
|
|
36 |
parser = argparse.ArgumentParser(description='Start a chat node with a specific name')
|
37 |
parser.add_argument('--node-name', type=str, default=None, help='Name for this chat node')
|
38 |
parser.add_argument('--port', type=int, default=7860, help='Port to run the Gradio interface on')
|
39 |
args = parser.parse_args()
|
40 |
return args.node_name or f"node-{uuid.uuid4().hex[:8]}", args.port
|
41 |
|
|
|
42 |
def get_log_file(username):
|
|
|
43 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
44 |
safe_username = username.replace(" ", "_").encode('ascii', 'ignore').decode('ascii')
|
45 |
return os.path.join(LOG_DIR, f"{safe_username}_{timestamp}.md")
|
46 |
|
|
|
47 |
def save_log_entry(username, entry):
|
|
|
48 |
log_file = get_log_file(username)
|
49 |
try:
|
50 |
with open(log_file, 'a') as f:
|
@@ -55,7 +60,9 @@ def save_log_entry(username, entry):
|
|
55 |
logger.error(f"Error saving log to {log_file}: {e}")
|
56 |
return None
|
57 |
|
|
|
58 |
def load_latest_log(username):
|
|
|
59 |
safe_username = username.replace(" ", "_").encode('ascii', 'ignore').decode('ascii')
|
60 |
log_files = [f for f in os.listdir(LOG_DIR) if f.startswith(safe_username) and f.endswith(".md")]
|
61 |
if not log_files:
|
@@ -73,7 +80,9 @@ def load_latest_log(username):
|
|
73 |
|
74 |
active_connections = {}
|
75 |
|
|
|
76 |
async def websocket_handler(websocket, path):
|
|
|
77 |
try:
|
78 |
client_id = str(uuid.uuid4())
|
79 |
room_id = "logs"
|
@@ -95,7 +104,9 @@ async def websocket_handler(websocket, path):
|
|
95 |
if not active_connections[room_id]:
|
96 |
del active_connections[room_id]
|
97 |
|
|
|
98 |
async def broadcast_message(message, room_id):
|
|
|
99 |
if room_id in active_connections:
|
100 |
disconnected = []
|
101 |
for client_id, ws in active_connections[room_id].items():
|
@@ -106,17 +117,21 @@ async def broadcast_message(message, room_id):
|
|
106 |
for client_id in disconnected:
|
107 |
del active_connections[room_id][client_id]
|
108 |
|
|
|
109 |
async def start_websocket_server(host='0.0.0.0', port=8765):
|
|
|
110 |
server = await websockets.serve(websocket_handler, host, port)
|
111 |
logger.info(f"WebSocket server started on ws://{host}:{port}")
|
112 |
return server
|
113 |
|
|
|
114 |
class LogBroadcastHandler(logging.Handler):
|
115 |
def __init__(self, username):
|
116 |
super().__init__()
|
117 |
self.username = username
|
118 |
|
119 |
def emit(self, record):
|
|
|
120 |
entry = {
|
121 |
"timestamp": datetime.now().isoformat(),
|
122 |
"level": record.levelname,
|
@@ -133,19 +148,21 @@ class LogBroadcastHandler(logging.Handler):
|
|
133 |
"username": self.username
|
134 |
}, "logs"))
|
135 |
|
|
|
136 |
def create_gradio_interface(username):
|
|
|
137 |
logger.handlers = [LogBroadcastHandler(username)]
|
138 |
def update_log_display(dummy_input):
|
|
|
139 |
return load_latest_log(username)
|
140 |
|
141 |
with gr.Blocks(title=f"Log Viewer: {NODE_NAME}", css=".code-container { font-family: monospace; background: #1e1e1e; color: #d4d4d4; padding: 10px; border-radius: 5px; }") as interface:
|
142 |
gr.Markdown(f"# Log Viewer for {username} on Node: {NODE_NAME}")
|
143 |
-
gr.Markdown("Logs update live as new entries are written
|
144 |
-
# Dummy input to trigger live updates
|
145 |
dummy_input = gr.Textbox(visible=False, value="trigger", interactive=True)
|
146 |
log_display = gr.Code(label="Your Latest Log", language="markdown", lines=20, elem_classes=["code-container"])
|
147 |
|
148 |
-
#
|
149 |
interface = gr.Interface(
|
150 |
fn=update_log_display,
|
151 |
inputs=[dummy_input],
|
@@ -153,19 +170,18 @@ def create_gradio_interface(username):
|
|
153 |
live=True,
|
154 |
title=f"Log Viewer: {NODE_NAME}"
|
155 |
)
|
156 |
-
|
157 |
return interface
|
158 |
|
|
|
159 |
async def main():
|
|
|
160 |
global NODE_NAME
|
161 |
NODE_NAME, port = get_node_name()
|
162 |
await start_websocket_server()
|
163 |
|
164 |
-
# Assign a random username
|
165 |
username = random.choice(FUN_USERNAMES)
|
166 |
logger.info(f"Assigned username: {username}")
|
167 |
|
168 |
-
# Create and run Gradio interface
|
169 |
interface = create_gradio_interface(username)
|
170 |
import uvicorn
|
171 |
await uvicorn.Server(uvicorn.Config(interface, host="0.0.0.0", port=port)).serve()
|
|
|
10 |
import os
|
11 |
import random
|
12 |
|
13 |
+
# Configure logging - the gossip queen π’π sets up the chatterbox!
|
14 |
logging.basicConfig(
|
15 |
level=logging.INFO,
|
16 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
|
18 |
)
|
19 |
logger = logging.getLogger("chat-node")
|
20 |
|
21 |
+
# Fun usernames with emojis - the VIP list of quirky characters! ππ
|
22 |
FUN_USERNAMES = [
|
23 |
"CosmicJester π", "PixelPanda πΌ", "QuantumQuack π¦", "StellarSquirrel πΏοΈ",
|
24 |
"GizmoGuru βοΈ", "NebulaNinja π ", "ByteBuster πΎ", "GalacticGopher π",
|
|
|
27 |
"MysticMoose π¦", "GlitchGnome π§", "VortexViper π", "ChronoChimp π"
|
28 |
]
|
29 |
|
30 |
+
# Directory for logs - the secret vault where tales are stashed! ποΈπ
|
31 |
LOG_DIR = "user_logs"
|
32 |
os.makedirs(LOG_DIR, exist_ok=True)
|
33 |
|
34 |
+
# Node name - the appβs codename generator, sneaky and slick! π΅οΈββοΈπΎ
|
35 |
def get_node_name():
|
36 |
+
"""π² Spins the wheel of fate to name our node - a random alias or user pick! π·οΈ"""
|
37 |
parser = argparse.ArgumentParser(description='Start a chat node with a specific name')
|
38 |
parser.add_argument('--node-name', type=str, default=None, help='Name for this chat node')
|
39 |
parser.add_argument('--port', type=int, default=7860, help='Port to run the Gradio interface on')
|
40 |
args = parser.parse_args()
|
41 |
return args.node_name or f"node-{uuid.uuid4().hex[:8]}", args.port
|
42 |
|
43 |
+
# Log file generator - crafts a shiny new logbook with a timestamp twist! π
βοΈ
|
44 |
def get_log_file(username):
|
45 |
+
"""β° Stamps the clock and names the log after our witty hero - fresh and ready! π"""
|
46 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
47 |
safe_username = username.replace(" ", "_").encode('ascii', 'ignore').decode('ascii')
|
48 |
return os.path.join(LOG_DIR, f"{safe_username}_{timestamp}.md")
|
49 |
|
50 |
+
# Log saver - the scribe that pens epic log tales into Markdown glory! ποΈπ
|
51 |
def save_log_entry(username, entry):
|
52 |
+
"""ποΈ Scribbles a log entry into a Markdown masterpiece - tales of triumph and woe! π"""
|
53 |
log_file = get_log_file(username)
|
54 |
try:
|
55 |
with open(log_file, 'a') as f:
|
|
|
60 |
logger.error(f"Error saving log to {log_file}: {e}")
|
61 |
return None
|
62 |
|
63 |
+
# Log loader - the treasure hunter digging up the latest log loot! π΄ββ οΈπ°
|
64 |
def load_latest_log(username):
|
65 |
+
"""π Hunts down the freshest log file and dresses it up with line numbers - snazzy! β¨"""
|
66 |
safe_username = username.replace(" ", "_").encode('ascii', 'ignore').decode('ascii')
|
67 |
log_files = [f for f in os.listdir(LOG_DIR) if f.startswith(safe_username) and f.endswith(".md")]
|
68 |
if not log_files:
|
|
|
80 |
|
81 |
active_connections = {}
|
82 |
|
83 |
+
# WebSocket handler - the bouncer at the log party, keeping the vibe alive! ππͺ
|
84 |
async def websocket_handler(websocket, path):
|
85 |
+
"""π§ Listens at the door, letting log fans in and kicking out crashers! π¨"""
|
86 |
try:
|
87 |
client_id = str(uuid.uuid4())
|
88 |
room_id = "logs"
|
|
|
104 |
if not active_connections[room_id]:
|
105 |
del active_connections[room_id]
|
106 |
|
107 |
+
# Broadcaster - the town crier shouting log updates to all whoβll listen! π£π
|
108 |
async def broadcast_message(message, room_id):
|
109 |
+
"""π’ Blasts the latest log scoop to every ear in the room - no one misses out! ποΈ"""
|
110 |
if room_id in active_connections:
|
111 |
disconnected = []
|
112 |
for client_id, ws in active_connections[room_id].items():
|
|
|
117 |
for client_id in disconnected:
|
118 |
del active_connections[room_id][client_id]
|
119 |
|
120 |
+
# WebSocket server starter - lights the fuse on the log-streaming rocket! ππ₯
|
121 |
async def start_websocket_server(host='0.0.0.0', port=8765):
|
122 |
+
"""π Fires up the WebSocket engine, ready to zip logs at warp speed! β‘"""
|
123 |
server = await websockets.serve(websocket_handler, host, port)
|
124 |
logger.info(f"WebSocket server started on ws://{host}:{port}")
|
125 |
return server
|
126 |
|
127 |
+
# Log handler - the sneaky spy logging every move with a witty twist! π΅οΈββοΈπ
|
128 |
class LogBroadcastHandler(logging.Handler):
|
129 |
def __init__(self, username):
|
130 |
super().__init__()
|
131 |
self.username = username
|
132 |
|
133 |
def emit(self, record):
|
134 |
+
"""π΅οΈββοΈ Catches every whisper and scribbles it into the logbook with flair! βοΈ"""
|
135 |
entry = {
|
136 |
"timestamp": datetime.now().isoformat(),
|
137 |
"level": record.levelname,
|
|
|
148 |
"username": self.username
|
149 |
}, "logs"))
|
150 |
|
151 |
+
# Interface maker - the artist painting a live log masterpiece! π¨πΌοΈ
|
152 |
def create_gradio_interface(username):
|
153 |
+
"""ποΈ Whips up a snazzy UI canvas that updates live with log magic! π"""
|
154 |
logger.handlers = [LogBroadcastHandler(username)]
|
155 |
def update_log_display(dummy_input):
|
156 |
+
"""π The puppet master pulling fresh log strings for the show! π¬"""
|
157 |
return load_latest_log(username)
|
158 |
|
159 |
with gr.Blocks(title=f"Log Viewer: {NODE_NAME}", css=".code-container { font-family: monospace; background: #1e1e1e; color: #d4d4d4; padding: 10px; border-radius: 5px; }") as interface:
|
160 |
gr.Markdown(f"# Log Viewer for {username} on Node: {NODE_NAME}")
|
161 |
+
gr.Markdown("Logs update live as new entries are written - watch the action unfold! π₯")
|
|
|
162 |
dummy_input = gr.Textbox(visible=False, value="trigger", interactive=True)
|
163 |
log_display = gr.Code(label="Your Latest Log", language="markdown", lines=20, elem_classes=["code-container"])
|
164 |
|
165 |
+
# Live interface FTW! π
|
166 |
interface = gr.Interface(
|
167 |
fn=update_log_display,
|
168 |
inputs=[dummy_input],
|
|
|
170 |
live=True,
|
171 |
title=f"Log Viewer: {NODE_NAME}"
|
172 |
)
|
|
|
173 |
return interface
|
174 |
|
175 |
+
# Main event - the ringmaster kicking off the log circus! πͺπ€‘
|
176 |
async def main():
|
177 |
+
"""π€ Drops the mic and starts the log party - itβs showtime, folks! π"""
|
178 |
global NODE_NAME
|
179 |
NODE_NAME, port = get_node_name()
|
180 |
await start_websocket_server()
|
181 |
|
|
|
182 |
username = random.choice(FUN_USERNAMES)
|
183 |
logger.info(f"Assigned username: {username}")
|
184 |
|
|
|
185 |
interface = create_gradio_interface(username)
|
186 |
import uvicorn
|
187 |
await uvicorn.Server(uvicorn.Config(interface, host="0.0.0.0", port=port)).serve()
|