Files
my_one_web/api/chat.py
小白 db5378c7e8 feat: 添加聊天会话界面
- 新增 OpenClaw Gateway 连接器 (api/openclaw_connector.py)
- 新增聊天 WebSocket 路由 (api/chat.py)
- 新增聊天界面模板 (templates/chat/index.html)
- 新增聊天样式 (static/css/chat.css)
- 修改 app.py 支持 SocketIO
- 登录后默认跳转到聊天界面

作者:小白 🐶
2026-03-14 06:12:28 +08:00

156 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
聊天 WebSocket 路由
处理前端与 OpenClaw Gateway 之间的消息转发
作者:小白 🐶
"""
from flask import request, session
from flask_login import current_user
from flask_socketio import emit, join_room, leave_room
import json
import time
from .openclaw_connector import gateway_manager
# Gateway 配置(从环境变量或配置文件读取)
GATEWAYS = {
"local": {
"url": "ws://127.0.0.1:18888",
"token": "ae4d5989ba173a01cc721200614a8a8a8226724b46d5af13a65089aa628c32b9"
}
}
def init_gateways():
"""初始化 Gateway 连接"""
for name, config in GATEWAYS.items():
connector = gateway_manager.add_gateway(
name,
config["url"],
config["token"]
)
# 设置消息回调
connector.message_callback = handle_gateway_response
gateway_manager.connect_all()
print(f"[Chat] Initialized {len(GATEWAYS)} gateway(s)")
def handle_gateway_response(gateway_name: str, data: dict):
"""处理 Gateway 响应并转发给前端"""
from app import socketio
# 获取用户房间
user_id = data.get("params", {}).get("userId", "anonymous")
room = f"user_{user_id}"
# 转发给前端
socketio.emit('agent_response', {
'gateway': gateway_name,
'data': data,
'timestamp': int(time.time() * 1000)
}, room=room, namespace='/chat')
print(f"[Chat] Forwarded response to {room}")
def register_socket_handlers(socketio):
"""注册 Socket.IO 事件处理器"""
@socketio.on('connect', namespace='/chat')
def handle_connect():
"""用户连接"""
if not current_user.is_authenticated:
print("[Chat] Unauthorized connection attempt")
return False
user_id = current_user.id
room = f"user_{user_id}"
join_room(room)
# 返回 Gateway 列表和状态
emit('connected', {
'gateways': gateway_manager.list_gateways(),
'status': gateway_manager.get_status(),
'userId': user_id
})
print(f"[Chat] User {current_user.username} connected, room: {room}")
@socketio.on('disconnect', namespace='/chat')
def handle_disconnect():
"""用户断开连接"""
if current_user.is_authenticated:
room = f"user_{current_user.id}"
leave_room(room)
print(f"[Chat] User {current_user.username} disconnected")
@socketio.on('send_message', namespace='/chat')
def handle_message(data):
"""处理用户消息"""
if not current_user.is_authenticated:
emit('error', {'message': '未授权'})
return
gateway_name = data.get('gateway', 'local')
message = data.get('message', '').strip()
if not message:
emit('error', {'message': '消息不能为空'})
return
connector = gateway_manager.get_gateway(gateway_name)
if connector and connector.connected:
# 构造会话 key
session_key = f"webchat:user_{current_user.id}"
# 发送到 Gateway
success = connector.send_message(message, session_key)
if success:
# 确认收到
emit('message_sent', {
'gateway': gateway_name,
'message': message,
'timestamp': int(time.time() * 1000)
})
print(f"[Chat] User {current_user.username} sent message to {gateway_name}")
else:
emit('error', {'message': f'发送失败Gateway {gateway_name} 连接异常'})
else:
emit('error', {'message': f'Gateway {gateway_name} 未连接'})
@socketio.on('switch_gateway', namespace='/chat')
def handle_switch(data):
"""切换 Gateway"""
if not current_user.is_authenticated:
return
gateway_name = data.get('gateway')
connector = gateway_manager.get_gateway(gateway_name)
if connector:
emit('gateway_changed', {
'gateway': gateway_name,
'connected': connector.connected,
'status': gateway_manager.get_status()
})
print(f"[Chat] User {current_user.username} switched to {gateway_name}")
else:
emit('error', {'message': f'Gateway {gateway_name} 不存在'})
@socketio.on('get_status', namespace='/chat')
def handle_get_status():
"""获取 Gateway 状态"""
emit('status_update', {
'status': gateway_manager.get_status()
})
print("[Chat] Socket handlers registered")