Adventists - API文档
  1. TCP语音对话
Adventists - API文档
  • 总览
  • 更新日志
  • 基本配置
  • 2.5 更新
  • Quick Start
  • TCP语音对话
    • TCP接入
    • MCP协议接入
    • WebSocket快速接入
    • VAD 模式接入指南
    • Emoji 模式对接指南
    • TCP获取Token
      POST
  • 配置管理
    • 模版 与 角色
    • 名词和参数说明
    • 模板
      • 查询公开模板列表
      • 查询当前组织模板(包含公开和私有模板)
      • 创建角色模板
      • 查询角色模板信息
      • 修改角色模板
      • 删除角色模板
      • 提交角色模板记忆
    • 角色
      • 创建角色(通过模板创建)
      • 创建角色
      • 查询角色
      • 修改角色
      • 删除角色
      • 发送角色记忆
      • 读取角色记忆
      • 创建角色(通过现有角色创建)
    • 技能书
      • 查询技能书列表
      • 预创建任务书
      • 上传任务书内容
      • 完成上传任务书
      • 查询技能书创建进度
    • 音色
      • 获取音色列表
      • 试听音色
      • 提交音色
      • 查询音色状态
  • 聊天辅助
    • 上传画面(Base64)
      POST
    • 上传画面(File)
      POST
  1. TCP语音对话

Emoji 模式对接指南

📋 版本信息

  • 文档版本: v1.0
  • 更新日期: 2024-10-26
  • 适用服务版本: tcpv2.3+

🎯 概述

Emoji 模式是一个全新的功能,允许服务端根据对话内容自动匹配并发送相应的 emoji 表情标识符。客户端可以根据这些标识符显示自定义的表情动画、图片或其他视觉效果。

新增内容

  • ✨ 新增消息类型: EMOJI (类型值 = 9)
  • 🎨 三种匹配模式: false、true、dimi
  • 🚀 智能匹配: 支持情感分析和关键词匹配两种匹配算法

🔧 认证参数配置

emoji_mode 参数

在 TCP 认证消息中添加 emoji_mode 参数:

##START[AUTH][task_id][seq]your_jwt_token##emoji_mode:true##END

或者在 HTTP API 中(如果您使用的是 HTTP 接口):

{
  "emoji_mode": "true"
}

参数说明

参数值说明Prompt匹配Answer匹配匹配算法
false 或不传关闭emoji功能❌❌-
true仅对回答匹配❌✅情感分析
dimi对问题和回答都匹配✅✅关键词匹配

兼容性说明

  • ✅ 向后兼容: 旧版本客户端如不传此参数,默认为 false
  • ✅ 灵活切换: 可在每次认证时动态切换模式
  • ✅ 布尔值兼容: true/false 与 "true"/"false" 均支持

📦 消息格式

消息类型定义

MessageType.EMOJI = 9

协议格式

##START + Header + JSON_Data + ##END

Header 结构(13字节)

字段长度说明
msg_type1 byte消息类型 = 9
task_id8 bytes任务ID(UTF-8编码)
seq4 bytes序列号(固定为 "0000")

JSON_Data 结构

{
  "emoji": "emoji_key"
}

完整示例

假设 task_id = abc12345,匹配到的 emoji 为 happy:

##START[0x09][abc12345][0000]{"emoji":"happy"}##END

二进制表示:

0x23 0x23 0x53 0x54 0x41 0x52 0x54  // ##START (7 bytes)
0x09                                 // msg_type = 9 (1 byte)
0x61 0x62 0x63 0x31 0x32 0x33 0x34 0x35  // task_id = "abc12345" (8 bytes)
0x30 0x30 0x30 0x30                 // seq = "0000" (4 bytes)
{"emoji":"happy"}                    // JSON数据 (可变长度)
0x23 0x23 0x45 0x4E 0x44            // ##END (5 bytes)

🎨 Emoji 标识符说明

True 模式 - 情感类 Emoji(20种)

基于情感分析算法,返回以下20种情感标识符:

Emoji Key中文说明触发示例
happy开心"太好了!"、"真棒"
laughing大笑"哈哈哈"、"笑死我了"
sad伤心"好难过"、"失望"
angry生气"气死了"、"讨厌"
crying哭泣"想哭"、"呜呜"
loving喜爱"爱你"、"喜欢"
surprised惊讶"天啊"、"哇塞"
shocked震惊"不敢相信"、"吓到"
thinking思考"?"、"考虑一下"
embarrassed尴尬"不好意思"、"害羞"
winking眨眼"你懂的"、"调皮"
cool酷"厉害"、"牛逼"
relaxed放松"舒服"、"惬意"
delicious美味"好吃"、"香"
kissy亲亲"么么哒"、"mua"
confident自信"当然"、"肯定"
sleepy困倦"晚安"、"好累"
silly傻笑"傻乎乎"、"呆萌"
confused困惑"不明白"、"疑惑"
funny搞笑"幽默"、"滑稽"

Dimi 模式 - 关键词类 Emoji(2868+种)

基于关键词匹配,支持大量场景化表情,例如:

Emoji Key关键词示例
hu_die"go for a walk", "春天散步"
sheng_bing"sore throat", "喉咙痛"
xia_yu"after the rain", "下雨"
bi_xin"比心"、"heart gesture"
kai_hua"peach blossoms", "开花"
......

💡 提示: Dimi 模式支持中英文混合匹配,优先匹配长关键词。


💻 客户端实现示例

1. 解析 Emoji 消息

Python 示例

import struct
import json

START_MARK = b'##START'
END_MARK = b'##END'

def parse_emoji_message(data):
    """解析 EMOJI 消息"""
    if data.startswith(START_MARK) and data.endswith(END_MARK):
        # 移除标记
        frame = data[len(START_MARK):-len(END_MARK)]
        
        # 解析 header
        msg_type = frame[0]
        task_id = frame[1:9].decode('utf-8')
        seq = frame[9:13].decode('utf-8')
        
        # 检查是否是 EMOJI 消息
        if msg_type == 9:
            # 解析 JSON 数据
            json_data = frame[13:].decode('utf-8')
            emoji_info = json.loads(json_data)
            
            return {
                'type': 'emoji',
                'task_id': task_id,
                'emoji_key': emoji_info['emoji']
            }
    return None

# 使用示例
data = b'##START\x09abc123450000{"emoji":"happy"}##END'
result = parse_emoji_message(data)
print(result)
# 输出: {'type': 'emoji', 'task_id': 'abc12345', 'emoji_key': 'happy'}

Unity C# 示例

using System;
using System.Text;
using Newtonsoft.Json.Linq;

public class EmojiMessage
{
    public string Type { get; set; }
    public string TaskId { get; set; }
    public string EmojiKey { get; set; }
}

public class MessageParser
{
    private static readonly byte[] START_MARK = Encoding.UTF8.GetBytes("##START");
    private static readonly byte[] END_MARK = Encoding.UTF8.GetBytes("##END");
    
    public static EmojiMessage ParseEmojiMessage(byte[] data)
    {
        // 检查起始和结束标记
        if (!StartsWith(data, START_MARK) || !EndsWith(data, END_MARK))
            return null;
        
        // 提取帧数据
        int frameStart = START_MARK.Length;
        int frameEnd = data.Length - END_MARK.Length;
        
        // 解析消息类型
        byte msgType = data[frameStart];
        if (msgType != 9) return null; // 不是 EMOJI 消息
        
        // 解析 task_id (8 bytes)
        string taskId = Encoding.UTF8.GetString(data, frameStart + 1, 8);
        
        // 解析 JSON 数据
        int jsonStart = frameStart + 13; // 1 + 8 + 4
        int jsonLength = frameEnd - jsonStart;
        string jsonData = Encoding.UTF8.GetString(data, jsonStart, jsonLength);
        
        // 解析 JSON
        JObject json = JObject.Parse(jsonData);
        
        return new EmojiMessage
        {
            Type = "emoji",
            TaskId = taskId,
            EmojiKey = json["emoji"].ToString()
        };
    }
    
    private static bool StartsWith(byte[] data, byte[] prefix)
    {
        if (data.Length < prefix.Length) return false;
        for (int i = 0; i < prefix.Length; i++)
            if (data[i] != prefix[i]) return false;
        return true;
    }
    
    private static bool EndsWith(byte[] data, byte[] suffix)
    {
        if (data.Length < suffix.Length) return false;
        int offset = data.Length - suffix.Length;
        for (int i = 0; i < suffix.Length; i++)
            if (data[offset + i] != suffix[i]) return false;
        return true;
    }
}

2. 显示 Emoji 动画

示例:根据 emoji_key 显示对应动画

public class EmojiDisplay : MonoBehaviour
{
    [SerializeField] private Dictionary<string, AnimationClip> emojiAnimations;
    [SerializeField] private Animator characterAnimator;
    
    public void ShowEmoji(string emojiKey)
    {
        if (emojiAnimations.ContainsKey(emojiKey))
        {
            // 播放对应的表情动画
            characterAnimator.Play(emojiKey);
            
            // 或者显示表情图标
            ShowEmojiIcon(emojiKey);
        }
        else
        {
            Debug.LogWarning($"未找到 emoji: {emojiKey}");
        }
    }
    
    private void ShowEmojiIcon(string emojiKey)
    {
        // 在角色头顶显示表情气泡
        // 实现您自己的显示逻辑
    }
}

3. 完整接收流程

import socket
import threading

class TCPClient:
    def __init__(self, host, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))
        self.buffer = b""
        
    def receive_loop(self):
        """接收消息循环"""
        while True:
            data = self.sock.recv(1024)
            if not data:
                break
            
            self.buffer += data
            
            # 处理缓冲区中的完整消息
            while b'##END' in self.buffer:
                frame, self.buffer = self.buffer.split(b'##END', 1)
                
                if b'##START' in frame:
                    frame = frame[frame.index(b'##START'):]
                    frame += b'##END'
                    
                    # 解析消息
                    self.handle_message(frame)
    
    def handle_message(self, frame):
        """处理单条消息"""
        if len(frame) < 20:
            return
        
        msg_type = frame[7]  # 跳过 ##START
        
        if msg_type == 4:  # TEXT
            # 处理文本消息
            self.handle_text(frame)
        elif msg_type == 2:  # AUDIO_FRAME
            # 处理音频消息
            self.handle_audio(frame)
        elif msg_type == 9:  # EMOJI
            # 处理 emoji 消息
            emoji_msg = parse_emoji_message(frame)
            if emoji_msg:
                print(f"收到 emoji: {emoji_msg['emoji_key']}")
                self.show_emoji(emoji_msg['emoji_key'])
    
    def show_emoji(self, emoji_key):
        """显示 emoji(由您实现)"""
        pass

🔄 消息时序

True 模式流程

客户端                          服务端
  |                              |
  |----(1) 发送认证------------->|
  |    emoji_mode: true          |
  |                              |
  |<---(2) 发送认证成功---------|
  |                              |
  |----(3) 发送用户输入-------->|
  |    "你好呀!"                |
  |                              |
  |<---(4) TEXT: "你好!"-------|
  |<---(5) EMOJI: "happy"-------|  ← 只对回答匹配
  |<---(6) TEXT: "很高兴见到你" |
  |<---(7) EMOJI: "happy"-------|
  |<---(8) END_FRAME------------|

Dimi 模式流程

客户端                          服务端
  |                              |
  |----(1) 发送认证------------->|
  |    emoji_mode: dimi          |
  |                              |
  |<---(2) 发送认证成功---------|
  |                              |
  |----(3) 发送用户输入-------->|
  |    "今天下雨了"              |
  |                              |
  |<---(4) EMOJI: "xia_yu"------|  ← 对问题匹配
  |<---(5) TEXT: "记得带伞哦"---|
  |<---(6) EMOJI: "关心"--------|  ← 对回答匹配
  |<---(7) END_FRAME------------|

⚠️ 注意事项

1. 性能考虑

  • ✅ Emoji 匹配在服务端完成,客户端只需接收
  • ✅ 匹配算法已优化,对性能影响极小(<1ms)
  • ⚠️ Dimi 模式会发送更多 emoji 消息,注意消息处理

2. 消息顺序

  • 📌 EMOJI 消息紧跟在对应的 TEXT 消息之后
  • 📌 一个 TEXT 消息可能对应 0 或 1 个 EMOJI 消息
  • 📌 EMOJI 消息的 task_id 与当前对话的 task_id 一致

3. 错误处理

try:
    emoji_msg = parse_emoji_message(frame)
    if emoji_msg:
        show_emoji(emoji_msg['emoji_key'])
except Exception as e:
    logging.warning(f"解析 emoji 消息失败: {e}")
    # 忽略错误,继续处理其他消息

4. 向后兼容

  • 如果客户端不支持 EMOJI 消息,可以直接忽略 msg_type == 9 的消息
  • 不影响其他消息类型的正常接收

📊 测试建议

1. 功能测试

# 测试用例
test_cases = [
    ("false", "你好", 0),  # 期望收到 0 个 emoji
    ("true", "哈哈哈,太好笑了!", 1),  # 期望收到 1 个 emoji
    ("dimi", "今天666啊", 2),  # 期望收到 2 个 emoji(问题+回答)
]

for emoji_mode, input_text, expected_emoji_count in test_cases:
    # 发送认证(设置 emoji_mode)
    # 发送输入
    # 统计收到的 EMOJI 消息数量
    # 验证是否符合预期

2. 压力测试

  • 测试高并发场景下的 emoji 消息接收
  • 验证消息不会丢失或乱序

3. 边界测试

  • 空文本
  • 超长文本
  • 特殊字符
  • 多语言混合

🆘 常见问题

Q1: 为什么我收不到 EMOJI 消息?

A: 检查以下几点:

  1. 确认认证时传递了 emoji_mode 参数且不为 false
  2. 确认消息解析逻辑正确处理了 msg_type == 9
  3. 确认缓冲区处理正确,没有截断消息

Q2: EMOJI 消息和 TEXT 消息的顺序是怎样的?

A:

  • TEXT 消息先发送
  • EMOJI 消息紧随其后
  • 顺序保证:TEXT → EMOJI → TEXT → EMOJI → ... → END_FRAME

Q3: True 和 Dimi 模式应该选择哪个?

A:

  • True 模式: 适合通用场景,20种情感表情足够表达基本情绪
  • Dimi 模式: 适合特定场景,需要更丰富的表情(如游戏、互动剧本)

Q4: 如何自定义 emoji 映射?

A:
客户端维护一个 emoji_key → 动画/图片 的映射表:

{
  "happy": "happy_animation.anim",
  "laughing": "laugh_animation.anim",
  "xia_yu": "rain_icon.png"
}

Q5: emoji_key 会包含什么字符?

A:

  • 仅包含:小写字母 (a-z)、数字 (0-9)、下划线 (_)
  • 示例:happy、xia_yu、tai_hao_xiao
  • 最大长度:通常 ≤ 20 字符

📖 相关文档

  • V2.md - TCP 协议完整文档
  • VAD模式接入指南.md - VAD 模式说明
  • mcp_protocal.md - MCP 工具调用协议

📝 更新日志

v1.0 (2024-10-26)

  • ✨ 初始版本
  • 新增三种 emoji 模式(false/true/dimi)
  • 新增 EMOJI 消息类型
  • 支持情感分析和关键词匹配两种算法

💬 技术支持

如有问题,请联系技术支持团队或查阅完整协议文档。

修改于 2025-10-27 03:15:11
上一页
VAD 模式接入指南
下一页
TCP获取Token
Built with