WebSocket API リファレンス
API の概要
ASR-LLM-TTS バックエンドは WebSocket プロトコルによるリアルタイム双方向通信インターフェースを提供し、テキスト入力、音声認識、ツール呼び出しなどの機能に対応しています。すべてのメッセージは JSON 形式で、統一されたメッセージプロトコル仕様に従います。
接続情報
| 項目 | 値 |
|---|---|
| プロトコル | WebSocket |
| エンドポイント | /ws/chat |
| 完全な URL | ws://localhost:8000/ws/chat |
| サブプロトコル | なし |
| 認証 | 認証不要 |
接続例
// JavaScript客户端连接
const ws = new WebSocket('ws://localhost:8000/ws/chat');
ws.onopen = function(event) {
console.log('WebSocket连接已建立');
};
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log('收到消息:', message);
};
ws.onerror = function(error) {
console.error('WebSocket错误:', error);
};
ws.onclose = function(event) {
console.log('WebSocket连接已关闭');
};
メッセージプロトコルの形式
基本的なメッセージ構造
interface WebSocketMessage {
type: string; // 消息类型标识
payload: { // 消息载荷
[key: string]: any;
};
timestamp?: number; // 可选时间戳
}
メッセージタイプの分類
| 分類 | 用途 | メッセージ数 |
|---|---|---|
| 制御系 | ユーザー操作の制御 | 3 |
| 状態系 | システム状態の通知 | 2 |
| データ系 | データ転送 | 3 |
| ツール系 | ツール呼び出し関連 | 2 |
| セッション系 | セッション管理 | 3 |
クライアントからの送信メッセージ(C → S)
1. USER_TEXT_INPUT - ユーザーのテキスト入力
ユーザーがテキスト入力によってアシスタントと対話します。
{
"type": "USER_TEXT_INPUT",
"payload": {
"text": "你好,今天天气怎么样?"
}
}
フィールド説明:
text(string、必須):ユーザーが入力したテキスト内容- 長さの制限:1~2000 文字
- 中国語・英語および一般的な記号に対応
使用シーン:
- ユーザーがチャット画面でテキストを入力する場合
- 音声認識の結果をテキスト入力として送る場合
- プログラムからテキストを入力する場合
2. INTERRUPT_TURN - 現在の対話を中断
進行中の対話ラウンド(LLM の生成、TTS の再生など)を中断します。
{
"type": "INTERRUPT_TURN",
"payload": {}
}
フィールド説明:
- 追加フィールドは不要で、payload は空です
実行時の動作:
- 現在の LLM 生成を停止
- TTS の音声再生を停止
- ツール呼び出しの実行を停止
TURN_INTERRUPTED応答を送信
使用シーン:
- ユーザーが「停止」ボタンをクリックした場合
- 新しい音声入力が検出された場合
- 時間のかかる処理を緊急に中断する場合
3. TOGGLE_ASR_LISTENING - 音声認識の切り替え
音声認識機能のオン/オフを制御します。
{
"type": "TOGGLE_ASR_LISTENING",
"payload": {
"enabled": true
}
}
フィールド説明:
enabled(boolean、必須):ASR の聞き取りを有効にするかどうかtrue:音声認識をオンにするfalse:音声認識をオフにする
使用シーン:
- ユーザーが手動で音声入力を切り替える場合
- シーンに応じて入力モードを自動で切り替える場合
- 音声機能のデバッグやテストを行う場合
サーバーからの送信メッセージ(S → C)
1. SYSTEM_STATUS - システム状態の更新
システムまたはコンポーネントの状態変化をクライアントに通知します。
フィールド説明:
{
"type": "SYSTEM_STATUS",
"payload": {
"module": "turn_handler",
"status": "processing_started",
"message": "开始处理用户输入",
"user_input": "你好,今天天气怎么样?"
}
}
-
module(string):モジュール名 -
"turn_handler":対話マネージャー "llm_client":LLM クライアント"tts_player":TTS プレーヤー"asr_service":音声認識サービスstatus(string):状態の識別子"processing_started":処理開始"processing_finished":処理完了"error":エラー発生message(string、任意):状態の説明user_input(string、任意):関連するユーザー入力
2. TTS_STATUS - TTS 再生状態
TTS の音声合成および再生の状態変化を通知します。
フィールド説明:
{
"type": "TTS_STATUS",
"payload": {
"status": "speaking",
"text": "今天的天气很不错",
"progress": 0.6
}
}
-
status(string):TTS の状態 -
"synthesizing":合成中 "speaking":再生中"completed":再生完了"stopped":再生停止"error":合成または再生のエラーtext(string、任意):現在処理中のテキストprogress(number、任意):再生の進捗(0~1)
3. LLM_CHUNK - LLM のストリーミング応答ブロック
LLM が生成した内容のストリーミング断片で、リアルタイム表示に使用します。
フィールド説明:
{
"type": "LLM_CHUNK",
"payload": {
"content_delta": "今天",
"content_full": "今天",
"is_complete": false,
"chunk_index": 1
}
}
-
content_delta(string):新たに追加された内容の断片 -
content_full(string):累積した全内容 is_complete(boolean):応答が完了したかどうかchunk_index(number):断片の番号(1 から開始)
4. LLM_FINAL_RESPONSE - LLM の最終応答
LLM が生成した完全な最終応答の内容です。
フィールド説明:
{
"type": "LLM_FINAL_RESPONSE",
"payload": {
"content": "今天的天气很不错,气温适中,适合外出活动。",
"total_tokens": 156,
"completion_time": 2.34
}
}
-
content(string):完全な応答内容 -
total_tokens(number、任意):合計トークン数 completion_time(number、任意):生成時間(秒)
5. ASR_FINAL_RESULT - 音声認識結果
音声認識の最終結果です。
フィールド説明:
{
"type": "ASR_FINAL_RESULT",
"payload": {
"text": "你好,今天天气怎么样?",
"confidence": 0.92,
"duration": 3.2
}
}
-
text(string):認識されたテキスト内容 -
confidence(number、任意):認識の信頼度(0~1) duration(number、任意):音声の長さ(秒)
6. TOOL_CALL_START - ツール呼び出しの開始
ツール呼び出しの実行開始を通知します。
フィールド説明:
{
"type": "TOOL_CALL_START",
"payload": {
"tool": "music_player_play",
"params": {
"music_name": "彩虹",
"sample_rate": 48000
},
"round": 1,
"description": "播放音乐《彩虹》"
}
}
-
tool(string):ツール名 -
params(object):ツール呼び出しのパラメーター round(number):ツール呼び出しのラウンドdescription(string、任意):ツール呼び出しの説明
7. TOOL_CALL_RESULT - ツール呼び出しの結果
ツール呼び出しの実行結果です。
フィールド説明:
{
"type": "TOOL_CALL_RESULT",
"payload": {
"tool": "music_player_play",
"result": "已为您播放《彩虹》,祝您聆听愉快!",
"status": "success",
"round": 1,
"execution_time": 0.85
}
}
-
tool(string):ツール名 -
result(string):ツールの実行結果 status(string):実行状態"success":実行成功"error":実行失敗round(number):対応する呼び出しラウンドexecution_time(number、任意):実行時間(秒)
8. TURN_ENDED - 対話ラウンドの終了
1 ラウンドの対話処理が完了したことを通知します。
フィールド説明:
{
"type": "TURN_ENDED",
"payload": {
"status": "completed",
"duration": 5.67,
"token_usage": {
"prompt_tokens": 128,
"completion_tokens": 89,
"total_tokens": 217
}
}
}
-
status(string):終了状態 -
"completed":正常完了 "error":エラーによる終了"cancelled":キャンセル"stopped_or_interrupted":停止または中断duration(number、任意):合計処理時間(秒)token_usage(object、任意):トークン使用量の統計
9. TURN_INTERRUPTED - 対話の中断
対話ラウンドが中断されたことを確認します。
フィールド説明:
{
"type": "TURN_INTERRUPTED",
"payload": {
"message": "对话已被用户中断",
"interrupted_at": "llm_generation"
}
}
-
message(string):中断に関する説明 -
interrupted_at(string、任意):中断が発生したフェーズ "llm_generation":LLM 生成フェーズ"tts_synthesis":TTS 合成フェーズ"tool_execution":ツール実行フェーズ
10. ERROR_MESSAGE - エラーメッセージ
システムエラーまたは異常な状態を通知します。
フィールド説明:
{
"type": "ERROR_MESSAGE",
"payload": {
"source": "llm_client",
"message": "API调用失败:网络连接超时",
"error_code": "CONNECTION_TIMEOUT",
"details": "请检查网络连接后重试"
}
}
-
source(string):エラーの発生元 -
"server_setup":サーバー設定のエラー "turn_execution":対話実行のエラー"llm_client":LLM クライアントのエラー"tts_client":TTS クライアントのエラー"asr_service":ASR サービスのエラー"tool_execution":ツール実行のエラーmessage(string):エラーの説明error_code(string、任意):エラーコードdetails(string、任意):詳細なエラー情報
典型的なインタラクションの流れ
1. 基本的なテキスト対話の流れ
2. ツール呼び出しの流れ
3. 対話中断の流れ
️
クライアントの実装例
JavaScript/TypeScript クライアント
Python クライアント
interface WebSocketMessage {
type: string;
payload: any;
}
class ASRLLMTTSClient {
private ws: WebSocket | null = null;
private messageHandlers: Map<string, Function> = new Map();
constructor(private url: string) {}
connect(): Promise<void> {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('Connected to ASR-LLM-TTS server');
resolve();
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onmessage = (event) => {
const message: WebSocketMessage = JSON.parse(event.data);
this.handleMessage(message);
};
this.ws.onclose = () => {
console.log('Connection closed');
};
});
}
private handleMessage(message: WebSocketMessage) {
const handler = this.messageHandlers.get(message.type);
if (handler) {
handler(message.payload);
}
}
// 注册消息处理器
on(messageType: string, handler: Function) {
this.messageHandlers.set(messageType, handler);
}
// 发送用户文本输入
sendUserInput(text: string) {
this.send('USER_TEXT_INPUT', { text });
}
// 中断当前对话
interrupt() {
this.send('INTERRUPT_TURN', {});
}
// 切换语音识别
toggleASR(enabled: boolean) {
this.send('TOGGLE_ASR_LISTENING', { enabled });
}
private send(type: string, payload: any) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type, payload }));
}
}
disconnect() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
}
// 使用示例
const client = new ASRLLMTTSClient('ws://localhost:8000/ws/chat');
// 注册消息处理器
client.on('LLM_CHUNK', (payload) => {
console.log('LLM chunk:', payload.content_delta);
// 更新UI显示
});
client.on('TTS_STATUS', (payload) => {
console.log('TTS status:', payload.status);
// 更新播放状态指示器
});
client.on('TOOL_CALL_START', (payload) => {
console.log('Tool call started:', payload.tool);
// 显示工具执行状态
});
client.on('ERROR_MESSAGE', (payload) => {
console.error('Server error:', payload.message);
// 显示错误信息
});
// 连接并发送消息
client.connect().then(() => {
client.sendUserInput('你好,请播放一首音乐');
});
import asyncio
import websockets
import json
from typing import Dict, Callable, Any
class ASRLLMTTSClient:
def __init__(self, uri: str):
self.uri = uri
self.websocket = None
self.message_handlers: Dict[str, Callable] = {}
async def connect(self):
"""连接到WebSocket服务器"""
self.websocket = await websockets.connect(self.uri)
print(f"Connected to {self.uri}")
# 启动消息监听任务
asyncio.create_task(self._listen_messages())
async def _listen_messages(self):
"""监听WebSocket消息"""
try:
async for message in self.websocket:
data = json.loads(message)
await self._handle_message(data)
except websockets.exceptions.ConnectionClosed:
print("Connection closed")
async def _handle_message(self, message: Dict[str, Any]):
"""处理接收到的消息"""
message_type = message.get('type')
payload = message.get('payload', {})
if message_type in self.message_handlers:
handler = self.message_handlers[message_type]
if asyncio.iscoroutinefunction(handler):
await handler(payload)
else:
handler(payload)
def on(self, message_type: str, handler: Callable):
"""注册消息处理器"""
self.message_handlers[message_type] = handler
async def send_user_input(self, text: str):
"""发送用户文本输入"""
await self._send_message('USER_TEXT_INPUT', {'text': text})
async def interrupt(self):
"""中断当前对话"""
await self._send_message('INTERRUPT_TURN', {})
async def toggle_asr(self, enabled: bool):
"""切换语音识别"""
await self._send_message('TOGGLE_ASR_LISTENING', {'enabled': enabled})
async def _send_message(self, msg_type: str, payload: Dict[str, Any]):
"""发送WebSocket消息"""
if self.websocket:
message = json.dumps({'type': msg_type, 'payload': payload})
await self.websocket.send(message)
async def disconnect(self):
"""断开连接"""
if self.websocket:
await self.websocket.close()
# 使用示例
async def main():
client = ASRLLMTTSClient('ws://localhost:8000/ws/chat')
# 注册消息处理器
def on_llm_chunk(payload):
print(f"LLM: {payload.get('content_delta', '')}", end='', flush=True)
def on_tts_status(payload):
print(f"\nTTS Status: {payload.get('status')}")
def on_tool_call(payload):
print(f"Tool Call: {payload.get('tool')} - {payload.get('result')}")
client.on('LLM_CHUNK', on_llm_chunk)
client.on('TTS_STATUS', on_tts_status)
client.on('TOOL_CALL_RESULT', on_tool_call)
# 连接并交互
await client.connect()
await client.send_user_input('你好,请播放一首音乐')
# 保持连接
await asyncio.sleep(10)
await client.disconnect()
# 运行客户端
asyncio.run(main())
パフォーマンスに関する考慮事項
1. メッセージの頻度
メッセージタイプごとの目安は次のとおりです。
| メッセージタイプ | 一般的な頻度 | 推奨される処理 |
|---|---|---|
| LLM_CHUNK | 10-50/sec |
デバウンス処理、UI の一括更新 |
| TTS_STATUS | 1-5/sec |
状態をキャッシュして重複処理を回避 |
| SYSTEM_STATUS | 1-10/round |
ログ記録、表示は任意 |
2. 接続管理
3. メモリ管理
// 实现自动重连
class RobustWebSocketClient {
constructor(url, options = {}) {
this.url = url;
this.reconnectInterval = options.reconnectInterval || 5000;
this.maxReconnectAttempts = options.maxReconnectAttempts || 10;
this.reconnectAttempts = 0;
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
this.reconnectAttempts = 0;
console.log('Connected');
};
this.ws.onclose = () => {
this.attemptReconnect();
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
}
attemptReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`Reconnecting... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
setTimeout(() => {
this.connect();
}, this.reconnectInterval);
}
}
}
⚠️
// 限制消息历史记录
class MessageBuffer {
constructor(maxSize = 1000) {
this.messages = [];
this.maxSize = maxSize;
}
addMessage(message) {
this.messages.push(message);
if (this.messages.length > this.maxSize) {
this.messages.shift(); // 移除最老的消息
}
}
clear() {
this.messages = [];
}
}
エラー処理
よくあるエラーのシナリオ
主なエラーは次のとおりです。
- 接続失敗:サーバーに到達できない、またはポートが使用中
- メッセージ形式のエラー:JSON の形式が正しくない、または必須フィールドが欠けている
- 業務ロジックのエラー:API 呼び出しの失敗、またはツール実行のエラー
- ネットワークの切断:予期しない接続の切断
エラー処理のベストプラクティス
// 全面的错误处理
class ErrorHandler {
static handleWebSocketError(error, context = '') {
console.error(`WebSocket error in ${context}:`, error);
// 根据错误类型采取不同处理策略
if (error.type === 'close') {
// 连接关闭,尝试重连
this.handleConnectionClosed();
} else if (error.type === 'error') {
// 一般错误,记录并通知用户
this.notifyUser('连接出现问题,正在尝试恢复...');
}
}
static handleMessageError(message, error) {
console.error('Message handling error:', error);
// 检查是否为关键消息
const criticalTypes = ['ERROR_MESSAGE', 'TURN_ENDED'];
if (criticalTypes.includes(message.type)) {
// 关键消息处理失败,需要特殊处理
this.handleCriticalMessageError(message);
}
}
static notifyUser(message) {
// 实现用户通知逻辑
console.log('User notification:', message);
}
}
この WebSocket API リファレンスは、フロントエンド開発者向けに完全なインターフェース仕様と実装ガイドを提供し、クライアントが ASR-LLM-TTS バックエンドシステムと正しく通信できるようにするものです。
ドキュメント