File size: 7,637 Bytes
b1fe0dd e2ffbc8 962f379 b1fe0dd 962f379 6862189 962f379 b1fe0dd 6862189 a58b36c 6862189 e2ffbc8 6862189 e2ffbc8 6862189 e2ffbc8 6862189 e2ffbc8 6862189 e2ffbc8 6862189 a58b36c 6862189 d597cda 6862189 d597cda b1fe0dd 6862189 962f379 6862189 962f379 b1fe0dd 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f 6862189 ca4200f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
import gradio as gr
import asyncio
import websockets
import json
import uuid
import argparse
from datetime import datetime
import logging
import sys
import os
import random
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger("chat-node")
# Fun usernames with emojis
FUN_USERNAMES = [
"CosmicJester π", "PixelPanda πΌ", "QuantumQuack π¦", "StellarSquirrel πΏοΈ",
"GizmoGuru βοΈ", "NebulaNinja π ", "ByteBuster πΎ", "GalacticGopher π",
"RocketRaccoon π", "EchoElf π§", "PhantomFox π¦", "WittyWizard π§",
"LunarLlama π", "SolarSloth βοΈ", "AstroAlpaca π¦", "CyberCoyote πΊ",
"MysticMoose π¦", "GlitchGnome π§", "VortexViper π", "ChronoChimp π"
]
# Directories
LOG_DIR = "user_logs"
os.makedirs(LOG_DIR, exist_ok=True)
# Node name
def get_node_name():
parser = argparse.ArgumentParser(description='Start a chat node with a specific name')
parser.add_argument('--node-name', type=str, default=None, help='Name for this chat node')
parser.add_argument('--port', type=int, default=7860, help='Port to run the Gradio interface on')
args = parser.parse_args()
return args.node_name or f"node-{uuid.uuid4().hex[:8]}", args.port
def get_log_file(username):
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# Replace spaces and emojis with underscores for valid filenames
safe_username = username.replace(" ", "_").encode('ascii', 'ignore').decode('ascii')
return os.path.join(LOG_DIR, f"{safe_username}_{timestamp}.md")
def save_log_entry(username, entry):
log_file = get_log_file(username)
try:
with open(log_file, 'a') as f:
# Format as Markdown with timestamp
f.write(f"```log\n[{entry['timestamp']}] {entry['level']}: {entry['message']}\n```\n")
logger.info(f"Saved log entry to {log_file}")
return log_file
except Exception as e:
logger.error(f"Error saving log to {log_file}: {e}")
return None
def load_latest_log(username):
safe_username = username.replace(" ", "_").encode('ascii', 'ignore').decode('ascii')
log_files = [f for f in os.listdir(LOG_DIR) if f.startswith(safe_username) and f.endswith(".md")]
if not log_files:
return "# No logs yet\nStart interacting to generate logs!"
latest_file = max(log_files, key=lambda f: os.path.getmtime(os.path.join(LOG_DIR, f)))
try:
with open(os.path.join(LOG_DIR, latest_file), 'r') as f:
content = f.read()
# Add line numbers to the Markdown content
lines = content.strip().split('\n')
numbered_content = "\n".join(f"{i+1}. {line}" for i, line in enumerate(lines))
return f"# Log for {username} ({latest_file})\n\n{numbered_content}"
except Exception as e:
logger.error(f"Error loading log {latest_file}: {e}")
return "# Error loading log\nCheck server logs for details."
active_connections = {}
async def websocket_handler(websocket, path):
try:
client_id = str(uuid.uuid4())
room_id = "logs" # Simplified to a single logs room
active_connections.setdefault(room_id, {})[client_id] = websocket
logger.info(f"Client {client_id} connected to logs")
async for message in websocket:
try:
data = json.loads(message)
data["timestamp"] = datetime.now().isoformat()
await broadcast_message(data, room_id)
except json.JSONDecodeError:
await websocket.send(json.dumps({"type": "error", "content": "Invalid JSON", "timestamp": datetime.now().isoformat(), "sender": "system"}))
except websockets.ConnectionClosed:
logger.info(f"Client {client_id} disconnected from logs")
finally:
if room_id in active_connections and client_id in active_connections[room_id]:
del active_connections[room_id][client_id]
if not active_connections[room_id]:
del active_connections[room_id]
async def broadcast_message(message, room_id):
if room_id in active_connections:
disconnected = []
for client_id, ws in active_connections[room_id].items():
try:
await ws.send(json.dumps(message))
except websockets.ConnectionClosed:
disconnected.append(client_id)
for client_id in disconnected:
del active_connections[room_id][client_id]
async def start_websocket_server(host='0.0.0.0', port=8765):
server = await websockets.serve(websocket_handler, host, port)
logger.info(f"WebSocket server started on ws://{host}:{port}")
return server
class LogBroadcastHandler(logging.Handler):
def __init__(self, username):
super().__init__()
self.username = username
def emit(self, record):
entry = {
"timestamp": datetime.now().isoformat(),
"level": record.levelname,
"message": self.format(record),
"name": record.name
}
log_file = save_log_entry(self.username, entry)
if log_file:
# Notify WebSocket clients of new log file
asyncio.create_task(broadcast_message({
"type": "log",
"content": f"New log entry saved to {log_file}",
"timestamp": entry["timestamp"],
"sender": "system",
"username": self.username
}, "logs"))
def create_gradio_interface(username):
logger.handlers = [LogBroadcastHandler(username)] # Replace handlers with user-specific one
with gr.Blocks(title=f"Log Viewer: {NODE_NAME}") as interface:
interface.css = """
.code-container { font-family: monospace; background: #1e1e1e; color: #d4d4d4; padding: 10px; border-radius: 5px; }
"""
interface.js = f"""
() => {{
setInterval(async () => {{
const response = await fetch('/get_log?username={username}');
const logContent = await response.text();
document.getElementById('log-display').innerText = logContent;
}}, 900); // Refresh every 0.9 seconds
}}
"""
gr.Markdown(f"# Log Viewer for {username} on Node: {NODE_NAME}")
gr.Markdown("Your logs are displayed below, auto-refreshing every 0.9 seconds.")
log_display = gr.Code(label="Your Latest Log", language="markdown", lines=20, elem_classes=["code-container"], elem_id="log-display")
# Custom endpoint to fetch log
def get_log():
return load_latest_log(username)
interface.load(get_log, [], [log_display])
return interface
async def main():
global NODE_NAME
NODE_NAME, port = get_node_name()
await start_websocket_server()
# Assign a random username on startup
username = random.choice(FUN_USERNAMES)
logger.info(f"Assigned username: {username}")
# Create and run Gradio interface
interface = create_gradio_interface(username)
from starlette.routing import Route
from starlette.responses import PlainTextResponse
async def get_log_endpoint(request):
return PlainTextResponse(load_latest_log(username))
app = gr.routes.App.create_app(interface)
app.routes.append(Route("/get_log", get_log_endpoint))
import uvicorn
await uvicorn.Server(uvicorn.Config(app, host="0.0.0.0", port=port)).serve()
if __name__ == "__main__":
asyncio.run(main()) |