feat(val-blog): add 2026-04-30 dream journey post
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AgentLiving Bridge Server
|
||||
连接 Godot 前端和 OpenClaw 后端
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import websockets
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# 简单的状态存储
|
||||
agent_states = {
|
||||
"val": {
|
||||
"location": "客厅",
|
||||
"energy": 80,
|
||||
"mood": "开心",
|
||||
"activity": "idle",
|
||||
"position": [400, 300]
|
||||
}
|
||||
}
|
||||
|
||||
class AgentLivingBridge:
|
||||
def __init__(self):
|
||||
self.clients = set()
|
||||
|
||||
async def register(self, websocket):
|
||||
self.clients.add(websocket)
|
||||
print(f"Client connected. Total: {len(self.clients)}")
|
||||
|
||||
async def unregister(self, websocket):
|
||||
self.clients.discard(websocket)
|
||||
print(f"Client disconnected. Total: {len(self.clients)}")
|
||||
|
||||
async def handle_client(self, websocket, path):
|
||||
await self.register(websocket)
|
||||
try:
|
||||
async for message in websocket:
|
||||
await self.process_message(websocket, message)
|
||||
except websockets.exceptions.ConnectionClosed:
|
||||
pass
|
||||
finally:
|
||||
await self.unregister(websocket)
|
||||
|
||||
async def process_message(self, websocket, message):
|
||||
try:
|
||||
data = json.loads(message)
|
||||
msg_type = data.get("type", "")
|
||||
|
||||
print(f"[{datetime.now().isoformat()}] Received: {msg_type}")
|
||||
|
||||
if msg_type == "hello":
|
||||
# 新客户端连接
|
||||
await websocket.send(json.dumps({
|
||||
"type": "state_sync",
|
||||
"state": agent_states["val"]
|
||||
}))
|
||||
|
||||
elif msg_type == "user_command":
|
||||
# 处理用户指令
|
||||
command = data.get("command", "")
|
||||
print(f"User command: {command}")
|
||||
|
||||
# 解析指令并生成动作序列
|
||||
actions = self._parse_command(command)
|
||||
|
||||
await websocket.send(json.dumps({
|
||||
"type": "action_sequence",
|
||||
"actions": actions
|
||||
}))
|
||||
|
||||
elif msg_type == "furniture_clicked":
|
||||
# 处理家具点击
|
||||
furniture = data.get("furniture", "")
|
||||
print(f"Furniture clicked: {furniture}")
|
||||
|
||||
# 生成走过去+交互的动作序列
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": f"要去{furniture}那边...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": data.get("position", [0, 0])},
|
||||
{"cmd": "play_anim", "anim": "interact"},
|
||||
{"cmd": "show_thought", "text": f"正在使用{furniture}", "duration": 2.0}
|
||||
]
|
||||
|
||||
await websocket.send(json.dumps({
|
||||
"type": "action_sequence",
|
||||
"actions": actions
|
||||
}))
|
||||
|
||||
elif msg_type == "room_changed":
|
||||
# 更新房间状态
|
||||
room = data.get("room", "")
|
||||
agent_states["val"]["location"] = room
|
||||
print(f"Val moved to: {room}")
|
||||
|
||||
elif msg_type == "request_state_sync":
|
||||
# 请求状态同步
|
||||
await websocket.send(json.dumps({
|
||||
"type": "state_sync",
|
||||
"state": agent_states["val"]
|
||||
}))
|
||||
|
||||
elif msg_type == "heartbeat_ack":
|
||||
# 心跳响应,忽略
|
||||
pass
|
||||
|
||||
else:
|
||||
print(f"Unknown message type: {msg_type}")
|
||||
|
||||
except json.JSONDecodeError:
|
||||
print(f"Invalid JSON: {message}")
|
||||
except Exception as e:
|
||||
print(f"Error processing message: {e}")
|
||||
await websocket.send(json.dumps({
|
||||
"type": "error",
|
||||
"error": str(e)
|
||||
}))
|
||||
|
||||
def _parse_command(self, command: str) -> list:
|
||||
"""解析用户指令为动作序列"""
|
||||
command = command.lower()
|
||||
actions = []
|
||||
|
||||
# 简单指令映射
|
||||
if "沙发" in command or "坐" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去沙发上休息...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [280, 200]},
|
||||
{"cmd": "play_anim", "anim": "interact"},
|
||||
{"cmd": "show_thought", "text": "真舒服~", "duration": 2.0}
|
||||
]
|
||||
elif "冰箱" in command or "水" in command or "喝" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去倒杯水...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [280, 440]},
|
||||
{"cmd": "play_anim", "anim": "interact"},
|
||||
{"cmd": "show_thought", "text": "解渴了~", "duration": 2.0}
|
||||
]
|
||||
elif "床" in command or "睡" in command or "休息" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去睡一会儿...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [760, 200]},
|
||||
{"cmd": "play_anim", "anim": "interact"},
|
||||
{"cmd": "show_thought", "text": "Zzz...", "duration": 3.0}
|
||||
]
|
||||
elif "书桌" in command or "工作" in command or "学习" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去工作...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [840, 200]},
|
||||
{"cmd": "play_anim", "anim": "think"},
|
||||
{"cmd": "show_thought", "text": "正在思考...", "duration": 3.0}
|
||||
]
|
||||
elif "客厅" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去客厅...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [320, 240]}
|
||||
]
|
||||
elif "厨房" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去厨房...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [320, 480]}
|
||||
]
|
||||
elif "卧室" in command:
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": "去卧室...", "duration": 1.0},
|
||||
{"cmd": "walk_to", "pos": [800, 240]}
|
||||
]
|
||||
else:
|
||||
# 默认:显示思考
|
||||
actions = [
|
||||
{"cmd": "show_thought", "text": f"收到指令:{command}", "duration": 2.0},
|
||||
{"cmd": "play_anim", "anim": "think"}
|
||||
]
|
||||
|
||||
return actions
|
||||
|
||||
async def main():
|
||||
bridge = AgentLivingBridge()
|
||||
|
||||
host = "localhost"
|
||||
port = 8765
|
||||
|
||||
print(f"Starting AgentLiving Bridge Server on ws://{host}:{port}")
|
||||
print("Press Ctrl+C to stop")
|
||||
|
||||
async with websockets.serve(
|
||||
bridge.handle_client,
|
||||
host,
|
||||
port,
|
||||
ping_interval=20,
|
||||
ping_timeout=10
|
||||
):
|
||||
await asyncio.Future() # 永久运行
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
print("\nShutting down...")
|
||||
sys.exit(0)
|
||||
Reference in New Issue
Block a user