Update app.py
Browse files
app.py
CHANGED
@@ -22,11 +22,22 @@ active_connections = {}
|
|
22 |
# Dictionary to store message history for each chat room (in-memory cache)
|
23 |
chat_history = {}
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
# Directory to store persistent chat history
|
26 |
HISTORY_DIR = "chat_history"
|
27 |
import os
|
28 |
import shutil
|
29 |
from pathlib import Path
|
|
|
30 |
|
31 |
# Create history directory if it doesn't exist
|
32 |
os.makedirs(HISTORY_DIR, exist_ok=True)
|
@@ -55,52 +66,169 @@ def get_node_name():
|
|
55 |
|
56 |
def get_room_history_file(room_id):
|
57 |
"""Get the filename for a room's history."""
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
def load_room_history(room_id):
|
61 |
-
"""Load chat history for a room from persistent storage."""
|
62 |
if room_id not in chat_history:
|
63 |
chat_history[room_id] = []
|
64 |
|
65 |
-
#
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
try:
|
69 |
with open(history_file, 'r') as f:
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
75 |
except Exception as e:
|
76 |
-
logger.error(f"Error loading history
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
|
78 |
return chat_history[room_id]
|
79 |
|
80 |
-
def
|
81 |
-
"""Save
|
82 |
-
|
|
|
|
|
|
|
|
|
83 |
history_file = get_room_history_file(room_id)
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
-
def
|
92 |
-
"""
|
93 |
-
|
|
|
|
|
94 |
for file in os.listdir(HISTORY_DIR):
|
95 |
-
if file.endswith(".
|
96 |
file_path = os.path.join(HISTORY_DIR, file)
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
-
|
102 |
-
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
async def clear_all_history():
|
106 |
"""Clear all chat history for all rooms."""
|
@@ -143,19 +271,37 @@ async def websocket_handler(websocket, path):
|
|
143 |
|
144 |
active_connections[room_id][client_id] = websocket
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
# Load or initialize chat history
|
147 |
room_history = load_room_history(room_id)
|
148 |
|
149 |
# Send welcome message
|
150 |
welcome_msg = {
|
151 |
"type": "system",
|
152 |
-
"content": f"Welcome to room '{room_id}'! Connected from node '{NODE_NAME}'",
|
153 |
"timestamp": datetime.now().isoformat(),
|
154 |
"sender": "system",
|
155 |
"room_id": room_id
|
156 |
}
|
157 |
await websocket.send(json.dumps(welcome_msg))
|
158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
# Send chat history
|
160 |
for msg in room_history:
|
161 |
await websocket.send(json.dumps(msg))
|
@@ -163,14 +309,15 @@ async def websocket_handler(websocket, path):
|
|
163 |
# Broadcast join notification
|
164 |
join_msg = {
|
165 |
"type": "system",
|
166 |
-
"content": f"User joined the room",
|
167 |
"timestamp": datetime.now().isoformat(),
|
168 |
"sender": "system",
|
169 |
"room_id": room_id
|
170 |
}
|
171 |
await broadcast_message(join_msg, room_id)
|
|
|
172 |
|
173 |
-
logger.info(f"New client {client_id} connected to room {room_id}")
|
174 |
|
175 |
# Handle messages from this client
|
176 |
async for message in websocket:
|
@@ -182,6 +329,18 @@ async def websocket_handler(websocket, path):
|
|
182 |
result = await clear_all_history()
|
183 |
continue
|
184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
# Add metadata to the message
|
186 |
data["timestamp"] = datetime.now().isoformat()
|
187 |
data["sender_node"] = NODE_NAME
|
@@ -193,7 +352,7 @@ async def websocket_handler(websocket, path):
|
|
193 |
chat_history[room_id] = chat_history[room_id][-500:]
|
194 |
|
195 |
# Save to persistent storage
|
196 |
-
|
197 |
|
198 |
# Broadcast to all clients in the room
|
199 |
await broadcast_message(data, room_id)
|
@@ -215,15 +374,23 @@ async def websocket_handler(websocket, path):
|
|
215 |
if room_id in active_connections and client_id in active_connections[room_id]:
|
216 |
del active_connections[room_id][client_id]
|
217 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
# Broadcast leave notification
|
219 |
leave_msg = {
|
220 |
"type": "system",
|
221 |
-
"content": f"User left the room",
|
222 |
"timestamp": datetime.now().isoformat(),
|
223 |
"sender": "system",
|
224 |
"room_id": room_id
|
225 |
}
|
226 |
await broadcast_message(leave_msg, room_id)
|
|
|
227 |
|
228 |
# Clean up empty rooms (but keep history)
|
229 |
if not active_connections[room_id]:
|
@@ -347,19 +514,32 @@ def create_gradio_interface():
|
|
347 |
with gr.Column(scale=1):
|
348 |
clear_button = gr.Button("🧹 Clear All Chat History", variant="stop")
|
349 |
|
350 |
-
# Join room controls
|
351 |
with gr.Row():
|
352 |
-
|
353 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
354 |
|
355 |
-
# Chat area
|
356 |
chat_history_output = gr.Textbox(label="Chat History", lines=20, max_lines=20)
|
357 |
|
358 |
-
# Message controls
|
359 |
with gr.Row():
|
360 |
username_input = gr.Textbox(label="Username", placeholder="Enter your username", value="User")
|
361 |
-
|
362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
363 |
|
364 |
# Current room display
|
365 |
current_room_display = gr.Textbox(label="Current Room", value="Not joined any room yet")
|
@@ -377,6 +557,22 @@ def create_gradio_interface():
|
|
377 |
outputs=[room_list]
|
378 |
)
|
379 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
join_button.click(
|
381 |
join_room,
|
382 |
inputs=[room_id_input, chat_history_output],
|
@@ -388,7 +584,16 @@ def create_gradio_interface():
|
|
388 |
return "Please join a room first", message
|
389 |
|
390 |
actual_room_id = room_id.replace("Joined room: ", "").strip()
|
391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
392 |
|
393 |
if formatted_msg:
|
394 |
return "", formatted_msg
|
@@ -400,9 +605,25 @@ def create_gradio_interface():
|
|
400 |
outputs=[message_input, chat_history_output]
|
401 |
)
|
402 |
|
403 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
404 |
message_input.submit(
|
405 |
-
|
406 |
inputs=[message_input, username_input, current_room_display],
|
407 |
outputs=[message_input, chat_history_output]
|
408 |
)
|
|
|
22 |
# Dictionary to store message history for each chat room (in-memory cache)
|
23 |
chat_history = {}
|
24 |
|
25 |
+
# Dictionary to track file modification times
|
26 |
+
file_modification_times = {}
|
27 |
+
|
28 |
+
# Dictionary to track users in each room/sector
|
29 |
+
sector_users = {}
|
30 |
+
|
31 |
+
# Grid dimensions for 2D sector map
|
32 |
+
GRID_WIDTH = 10
|
33 |
+
GRID_HEIGHT = 10
|
34 |
+
|
35 |
# Directory to store persistent chat history
|
36 |
HISTORY_DIR = "chat_history"
|
37 |
import os
|
38 |
import shutil
|
39 |
from pathlib import Path
|
40 |
+
import time
|
41 |
|
42 |
# Create history directory if it doesn't exist
|
43 |
os.makedirs(HISTORY_DIR, exist_ok=True)
|
|
|
66 |
|
67 |
def get_room_history_file(room_id):
|
68 |
"""Get the filename for a room's history."""
|
69 |
+
# Create timestamp-based log files
|
70 |
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
71 |
+
return os.path.join(HISTORY_DIR, f"{room_id}_{timestamp}.jsonl")
|
72 |
+
|
73 |
+
def get_all_room_history_files(room_id):
|
74 |
+
"""Get all history files for a specific room."""
|
75 |
+
files = []
|
76 |
+
for file in os.listdir(HISTORY_DIR):
|
77 |
+
if file.startswith(f"{room_id}_") and file.endswith(".jsonl"):
|
78 |
+
files.append(os.path.join(HISTORY_DIR, file))
|
79 |
+
# Sort by modification time (newest first)
|
80 |
+
files.sort(key=lambda x: os.path.getmtime(x), reverse=True)
|
81 |
+
return files
|
82 |
|
83 |
def load_room_history(room_id):
|
84 |
+
"""Load chat history for a room from all persistent storage files."""
|
85 |
if room_id not in chat_history:
|
86 |
chat_history[room_id] = []
|
87 |
|
88 |
+
# Get all history files for this room
|
89 |
+
history_files = get_all_room_history_files(room_id)
|
90 |
+
|
91 |
+
# Track file modification times
|
92 |
+
for file in history_files:
|
93 |
+
if file not in file_modification_times:
|
94 |
+
file_modification_times[file] = os.path.getmtime(file)
|
95 |
+
|
96 |
+
# Load messages from all files
|
97 |
+
messages = []
|
98 |
+
for history_file in history_files:
|
99 |
try:
|
100 |
with open(history_file, 'r') as f:
|
101 |
+
for line in f:
|
102 |
+
line = line.strip()
|
103 |
+
if line: # Skip empty lines
|
104 |
+
try:
|
105 |
+
data = json.loads(line)
|
106 |
+
messages.append(data)
|
107 |
+
except json.JSONDecodeError:
|
108 |
+
logger.error(f"Error parsing JSON line in {history_file}")
|
109 |
except Exception as e:
|
110 |
+
logger.error(f"Error loading history from {history_file}: {e}")
|
111 |
+
|
112 |
+
# Sort by timestamp
|
113 |
+
messages.sort(key=lambda x: x.get("timestamp", ""), reverse=False)
|
114 |
+
chat_history[room_id] = messages
|
115 |
+
|
116 |
+
logger.info(f"Loaded {len(messages)} messages from {len(history_files)} files for room {room_id}")
|
117 |
+
|
118 |
+
# Track users in this sector
|
119 |
+
if room_id not in sector_users:
|
120 |
+
sector_users[room_id] = set()
|
121 |
|
122 |
return chat_history[room_id]
|
123 |
|
124 |
+
def save_message_to_history(room_id, message):
|
125 |
+
"""Save a single message to the newest history file for a room."""
|
126 |
+
# Get the newest history file or create a new one
|
127 |
+
history_files = get_all_room_history_files(room_id)
|
128 |
+
|
129 |
+
if not history_files:
|
130 |
+
# Create a new file
|
131 |
history_file = get_room_history_file(room_id)
|
132 |
+
else:
|
133 |
+
# Use the newest file if it's less than 1 MB, otherwise create a new one
|
134 |
+
newest_file = history_files[0]
|
135 |
+
if os.path.getsize(newest_file) > 1024 * 1024: # 1 MB
|
136 |
+
history_file = get_room_history_file(room_id)
|
137 |
+
else:
|
138 |
+
history_file = newest_file
|
139 |
+
|
140 |
+
try:
|
141 |
+
# Append the message as a single line of JSON
|
142 |
+
with open(history_file, 'a') as f:
|
143 |
+
f.write(json.dumps(message) + '\n')
|
144 |
+
|
145 |
+
# Update modification time
|
146 |
+
file_modification_times[history_file] = os.path.getmtime(history_file)
|
147 |
+
|
148 |
+
logger.debug(f"Saved message to {history_file}")
|
149 |
+
except Exception as e:
|
150 |
+
logger.error(f"Error saving message to {history_file}: {e}")
|
151 |
|
152 |
+
def check_for_new_messages():
|
153 |
+
"""Check for new messages in all history files."""
|
154 |
+
updated_rooms = set()
|
155 |
+
|
156 |
+
# Check all files in the history directory
|
157 |
for file in os.listdir(HISTORY_DIR):
|
158 |
+
if file.endswith(".jsonl"):
|
159 |
file_path = os.path.join(HISTORY_DIR, file)
|
160 |
+
current_mtime = os.path.getmtime(file_path)
|
161 |
+
|
162 |
+
# Check if this file is new or has been modified
|
163 |
+
if file_path not in file_modification_times or current_mtime > file_modification_times[file_path]:
|
164 |
+
# Extract room_id from filename
|
165 |
+
parts = file.split('_', 1)
|
166 |
+
if len(parts) > 0:
|
167 |
+
room_id = parts[0]
|
168 |
+
updated_rooms.add(room_id)
|
169 |
+
|
170 |
+
# Update tracked modification time
|
171 |
+
file_modification_times[file_path] = current_mtime
|
172 |
+
|
173 |
+
# Reload history for updated rooms
|
174 |
+
for room_id in updated_rooms:
|
175 |
+
if room_id in chat_history:
|
176 |
+
# Remember we had this room loaded
|
177 |
+
old_history_len = len(chat_history[room_id])
|
178 |
+
# Clear and reload
|
179 |
+
chat_history[room_id] = []
|
180 |
+
load_room_history(room_id)
|
181 |
+
new_history_len = len(chat_history[room_id])
|
182 |
+
|
183 |
+
if new_history_len > old_history_len:
|
184 |
+
logger.info(f"Found {new_history_len - old_history_len} new messages for room {room_id}")
|
185 |
|
186 |
+
return updated_rooms
|
187 |
+
|
188 |
+
def get_sector_coordinates(room_id):
|
189 |
+
"""Convert a room ID to grid coordinates, or assign new ones."""
|
190 |
+
try:
|
191 |
+
# Try to parse room ID as "x,y"
|
192 |
+
if ',' in room_id:
|
193 |
+
x, y = map(int, room_id.split(','))
|
194 |
+
return max(0, min(x, GRID_WIDTH-1)), max(0, min(y, GRID_HEIGHT-1))
|
195 |
+
except:
|
196 |
+
pass
|
197 |
+
|
198 |
+
# Hash the room_id string to get stable coordinates
|
199 |
+
hash_val = hash(room_id)
|
200 |
+
x = abs(hash_val) % GRID_WIDTH
|
201 |
+
y = abs(hash_val >> 8) % GRID_HEIGHT
|
202 |
+
|
203 |
+
return x, y
|
204 |
+
|
205 |
+
def generate_sector_map():
|
206 |
+
"""Generate an ASCII representation of the sector map."""
|
207 |
+
# Initialize empty grid
|
208 |
+
grid = [[' ' for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
|
209 |
+
|
210 |
+
# Place active rooms with user counts
|
211 |
+
for room_id, users in sector_users.items():
|
212 |
+
if users: # Only show rooms with users
|
213 |
+
x, y = get_sector_coordinates(room_id)
|
214 |
+
user_count = len(users)
|
215 |
+
grid[y][x] = str(min(user_count, 9)) if user_count < 10 else '+'
|
216 |
+
|
217 |
+
# Create ASCII representation
|
218 |
+
header = ' ' + ''.join([str(i % 10) for i in range(GRID_WIDTH)])
|
219 |
+
map_str = header + '\n'
|
220 |
+
|
221 |
+
for y in range(GRID_HEIGHT):
|
222 |
+
row = f"{y % 10}|"
|
223 |
+
for x in range(GRID_WIDTH):
|
224 |
+
row += grid[y][x]
|
225 |
+
row += '|'
|
226 |
+
map_str += row + '\n'
|
227 |
+
|
228 |
+
footer = ' ' + ''.join([str(i % 10) for i in range(GRID_WIDTH)])
|
229 |
+
map_str += footer
|
230 |
+
|
231 |
+
return f"```\n{map_str}\n```\n\nLegend: Number indicates users in sector. '+' means 10+ users."
|
232 |
|
233 |
async def clear_all_history():
|
234 |
"""Clear all chat history for all rooms."""
|
|
|
271 |
|
272 |
active_connections[room_id][client_id] = websocket
|
273 |
|
274 |
+
# Add user to sector map
|
275 |
+
if room_id not in sector_users:
|
276 |
+
sector_users[room_id] = set()
|
277 |
+
sector_users[room_id].add(client_id)
|
278 |
+
|
279 |
+
# Get sector coordinates
|
280 |
+
x, y = get_sector_coordinates(room_id)
|
281 |
+
|
282 |
# Load or initialize chat history
|
283 |
room_history = load_room_history(room_id)
|
284 |
|
285 |
# Send welcome message
|
286 |
welcome_msg = {
|
287 |
"type": "system",
|
288 |
+
"content": f"Welcome to room '{room_id}' (Sector {x},{y})! Connected from node '{NODE_NAME}'",
|
289 |
"timestamp": datetime.now().isoformat(),
|
290 |
"sender": "system",
|
291 |
"room_id": room_id
|
292 |
}
|
293 |
await websocket.send(json.dumps(welcome_msg))
|
294 |
|
295 |
+
# Send sector map
|
296 |
+
map_msg = {
|
297 |
+
"type": "system",
|
298 |
+
"content": f"Sector Map:\n{generate_sector_map()}",
|
299 |
+
"timestamp": datetime.now().isoformat(),
|
300 |
+
"sender": "system",
|
301 |
+
"room_id": room_id
|
302 |
+
}
|
303 |
+
await websocket.send(json.dumps(map_msg))
|
304 |
+
|
305 |
# Send chat history
|
306 |
for msg in room_history:
|
307 |
await websocket.send(json.dumps(msg))
|
|
|
309 |
# Broadcast join notification
|
310 |
join_msg = {
|
311 |
"type": "system",
|
312 |
+
"content": f"User joined the room (Sector {x},{y}) - {len(sector_users[room_id])} users now present",
|
313 |
"timestamp": datetime.now().isoformat(),
|
314 |
"sender": "system",
|
315 |
"room_id": room_id
|
316 |
}
|
317 |
await broadcast_message(join_msg, room_id)
|
318 |
+
save_message_to_history(room_id, join_msg)
|
319 |
|
320 |
+
logger.info(f"New client {client_id} connected to room {room_id} (Sector {x},{y})")
|
321 |
|
322 |
# Handle messages from this client
|
323 |
async for message in websocket:
|
|
|
329 |
result = await clear_all_history()
|
330 |
continue
|
331 |
|
332 |
+
# Check for map request
|
333 |
+
if data.get("type") == "command" and data.get("command") == "show_map":
|
334 |
+
map_msg = {
|
335 |
+
"type": "system",
|
336 |
+
"content": f"Sector Map:\n{generate_sector_map()}",
|
337 |
+
"timestamp": datetime.now().isoformat(),
|
338 |
+
"sender": "system",
|
339 |
+
"room_id": room_id
|
340 |
+
}
|
341 |
+
await websocket.send(json.dumps(map_msg))
|
342 |
+
continue
|
343 |
+
|
344 |
# Add metadata to the message
|
345 |
data["timestamp"] = datetime.now().isoformat()
|
346 |
data["sender_node"] = NODE_NAME
|
|
|
352 |
chat_history[room_id] = chat_history[room_id][-500:]
|
353 |
|
354 |
# Save to persistent storage
|
355 |
+
save_message_to_history(room_id, data)
|
356 |
|
357 |
# Broadcast to all clients in the room
|
358 |
await broadcast_message(data, room_id)
|
|
|
374 |
if room_id in active_connections and client_id in active_connections[room_id]:
|
375 |
del active_connections[room_id][client_id]
|
376 |
|
377 |
+
# Remove user from sector map
|
378 |
+
if room_id in sector_users and client_id in sector_users[room_id]:
|
379 |
+
sector_users[room_id].remove(client_id)
|
380 |
+
|
381 |
+
# Get sector coordinates
|
382 |
+
x, y = get_sector_coordinates(room_id)
|
383 |
+
|
384 |
# Broadcast leave notification
|
385 |
leave_msg = {
|
386 |
"type": "system",
|
387 |
+
"content": f"User left the room (Sector {x},{y}) - {len(sector_users.get(room_id, set()))} users remaining",
|
388 |
"timestamp": datetime.now().isoformat(),
|
389 |
"sender": "system",
|
390 |
"room_id": room_id
|
391 |
}
|
392 |
await broadcast_message(leave_msg, room_id)
|
393 |
+
save_message_to_history(room_id, leave_msg)
|
394 |
|
395 |
# Clean up empty rooms (but keep history)
|
396 |
if not active_connections[room_id]:
|
|
|
514 |
with gr.Column(scale=1):
|
515 |
clear_button = gr.Button("🧹 Clear All Chat History", variant="stop")
|
516 |
|
517 |
+
# Join room controls with 2D grid input
|
518 |
with gr.Row():
|
519 |
+
with gr.Column(scale=2):
|
520 |
+
room_id_input = gr.Textbox(label="Room ID", placeholder="Enter room ID or use x,y coordinates")
|
521 |
+
join_button = gr.Button("Join Room")
|
522 |
+
with gr.Column(scale=1):
|
523 |
+
with gr.Row():
|
524 |
+
x_coord = gr.Number(label="X", value=0, minimum=0, maximum=GRID_WIDTH-1, step=1)
|
525 |
+
y_coord = gr.Number(label="Y", value=0, minimum=0, maximum=GRID_HEIGHT-1, step=1)
|
526 |
+
grid_join_button = gr.Button("Join by Coordinates")
|
527 |
|
528 |
+
# Chat area with multiline support
|
529 |
chat_history_output = gr.Textbox(label="Chat History", lines=20, max_lines=20)
|
530 |
|
531 |
+
# Message controls with multiline support
|
532 |
with gr.Row():
|
533 |
username_input = gr.Textbox(label="Username", placeholder="Enter your username", value="User")
|
534 |
+
with gr.Column(scale=3):
|
535 |
+
message_input = gr.Textbox(
|
536 |
+
label="Message",
|
537 |
+
placeholder="Type your message here. Press Shift+Enter for new line, Enter to send.",
|
538 |
+
lines=3
|
539 |
+
)
|
540 |
+
with gr.Column(scale=1):
|
541 |
+
send_button = gr.Button("Send")
|
542 |
+
map_button = gr.Button("🗺️ Show Map")
|
543 |
|
544 |
# Current room display
|
545 |
current_room_display = gr.Textbox(label="Current Room", value="Not joined any room yet")
|
|
|
557 |
outputs=[room_list]
|
558 |
)
|
559 |
|
560 |
+
def join_by_coordinates(x, y):
|
561 |
+
"""Join a room using grid coordinates."""
|
562 |
+
room_id = f"{int(x)},{int(y)}"
|
563 |
+
return room_id
|
564 |
+
|
565 |
+
# Link grid coordinates to room ID
|
566 |
+
grid_join_button.click(
|
567 |
+
join_by_coordinates,
|
568 |
+
inputs=[x_coord, y_coord],
|
569 |
+
outputs=[room_id_input]
|
570 |
+
).then(
|
571 |
+
join_room,
|
572 |
+
inputs=[room_id_input, chat_history_output],
|
573 |
+
outputs=[current_room_display, chat_history_output]
|
574 |
+
)
|
575 |
+
|
576 |
join_button.click(
|
577 |
join_room,
|
578 |
inputs=[room_id_input, chat_history_output],
|
|
|
584 |
return "Please join a room first", message
|
585 |
|
586 |
actual_room_id = room_id.replace("Joined room: ", "").strip()
|
587 |
+
|
588 |
+
# Support for multi-line messages
|
589 |
+
message_lines = message.strip().split("\n")
|
590 |
+
formatted_msg = ""
|
591 |
+
|
592 |
+
for line in message_lines:
|
593 |
+
if line.strip(): # Skip empty lines
|
594 |
+
sent_msg = send_message(line.strip(), username, actual_room_id)
|
595 |
+
if sent_msg:
|
596 |
+
formatted_msg += sent_msg + "\n"
|
597 |
|
598 |
if formatted_msg:
|
599 |
return "", formatted_msg
|
|
|
605 |
outputs=[message_input, chat_history_output]
|
606 |
)
|
607 |
|
608 |
+
def show_sector_map(room_id):
|
609 |
+
if not room_id.startswith("Joined room:"):
|
610 |
+
return "Please join a room first to view the map"
|
611 |
+
|
612 |
+
return generate_sector_map()
|
613 |
+
|
614 |
+
map_button.click(
|
615 |
+
show_sector_map,
|
616 |
+
inputs=[current_room_display],
|
617 |
+
outputs=[chat_history_output]
|
618 |
+
)
|
619 |
+
|
620 |
+
# Handle Enter key for sending, Shift+Enter for new line
|
621 |
+
def on_message_submit(message, username, room_id):
|
622 |
+
# Simply call send_and_clear
|
623 |
+
return send_and_clear(message, username, room_id)
|
624 |
+
|
625 |
message_input.submit(
|
626 |
+
on_message_submit,
|
627 |
inputs=[message_input, username_input, current_room_display],
|
628 |
outputs=[message_input, chat_history_output]
|
629 |
)
|