Metadata-Version: 2.3
Name: embodia-robot-agent
Version: 0.0.1
Summary: EmbodiaRobotAgent — embeddable end-to-end conversational robot SDK 
Author: Xmov
License: Proprietary
Requires-Python: >=3.10
Requires-Dist: aiohttp>=3.10.11
Requires-Dist: av>=12.0.0
Requires-Dist: msgpack>=1.0.7
Requires-Dist: numpy>=1.24.4
Requires-Dist: protobuf>=4.25.0
Requires-Dist: python-socketio>=5.10.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: websockets>=12.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio<0.24,>=0.23.0; extra == 'dev'
Requires-Dist: pytest<8,>=7.4.3; extra == 'dev'
Provides-Extra: mic
Requires-Dist: scipy>=1.10.0; extra == 'mic'
Requires-Dist: sounddevice>=0.4.6; extra == 'mic'
Provides-Extra: mujoco
Requires-Dist: mujoco>=3.0.0; extra == 'mujoco'
Description-Content-Type: text/markdown

# embodia_robot_agent

**EmbodiaRobotAgent** — 可嵌入、可插拔、单进程的机器人端到端对话 SDK。

把 `语音 / 文本 → ASR / Brain → TTSA → 机器人本体（骨骼 / 音频 / 表情）` 封装成统一 SDK，渲染目标为物理机器人本体，本体驱动以 `RobotAdapter` 可插拔接入。

## 定位

在星云「驱动 SDK」（接收骨骼/音频/表情帧并按时序下发）之上叠加端到端编排，形成可被第三方嵌入的机器人对话 SDK。与既有紧耦合整机方案（Avatar 驱动 + 音频路由 + 本地桥接）的区别：单进程、无本地桥接、本体可插拔、ASR/Brain 由星云后端编排。

## 两条连接（核心）

SDK 同时持有：

1. **E2E WebSocket**（`E2EMPServer /ws/session`）— 麦克风音频上行 + `ask/speak/interrupt/voice_end/audio_input_on/off` + `asr_result/llm_response/speak_state_change` 事件。
2. **TTSA Socket.IO**（复用清洗后的驱动核心）— `pure_player` 线上默认路径，接收已调度的 bone/audio/expression/event 帧和清除信号。

`ask/speak/interrupt` 走 E2E WS 的 JSON 消息（不是 TTSA `send_text`）；机器人渲染帧仍由 TTSA 直出。

TTSA `event_data.voice_end` 必须由 Agent 转发到 E2E WS，用于释放旧播报结束后的新回答门控。文本模式首次连接 E2E 时追加 `audio_input_off=1`，直到显式调用 `start_asr()`。

## 目标用法

```python
from embodia_robot_agent import EmbodiaRobotAgent, AgentConfig
from embodia_robot_agent.asr import SoundDeviceAudioSource
from embodia_robot_agent.robot import RobotProfile
from embodia_robot_agent.robot.mujoco_visualizer import MuJoCoVisualizerAdapter

# 客户交付：wire 布局 (g1.json) + MJCF (g1/scene.xml，含 freejoint)；profile 是构造期数据，不进 AgentConfig
profile = RobotProfile.from_file("g1.json")
adapter = MuJoCoVisualizerAdapter.from_profile(profile, model_path="g1/scene.xml")

agent = EmbodiaRobotAgent(AgentConfig(
    app_id="app_xxx", app_secret="...",
    gateway_server="https://nebula.example.com",
    fps=24, raw_audio=True,
    # 可选注入：session_client / audio_input_off / 自定义 AudioUplinkEncoder
    adapter=adapter,                          # 真机则替换为厂商 RobotAdapter
    audio_source=SoundDeviceAudioSource(),  # 也可由 adapter.audio_source 提供
))
agent.on_asr_result(lambda text, is_final: print("asr", text, is_final))
await agent.init(); await agent.start()
await agent.speak("欢迎。")
await agent.start_asr()
await agent.stop_asr()
await agent.stop()
```
