情绪感知

更新时间:2026-03-19 07:32:22LLM 副本以 Markdown 格式查看下载 PDF

概述

Emotion 模块维护基于 emoji 的统一的情绪字典,并将上游返回的 Emotion 信息转换为系统内部可识别的 Emotion 名称。模块本身不直接驱动界面或动作,而是通过事件和显示消息把 Emotion 分发到各模式和各板级 UI。按来源可以分为两类:

  • skill emotion:用户侧 ASR emotion。
  • nlg emotion:AI 侧 TTS emotion。

术语与缩写

缩写 英文全称 中文含义
ASR Automatic Speech Recognition 自动语音识别
TTS Text-to-Speech 文本转语音

目录结构

相关源码:
├── ../../wukong/skills/skill_emotion.h        # Emotion 公共 API 与数据结构
├── ../../wukong/skills/skill_emotion.c        # Emotion 字典与 Unicode 转换实现
├── ../../wukong/skills/wukong_ai_skills.c     # 解析 Skill/NLG 数据并产生 Emotion 相关事件
├── ../../wukong/wukong_ai_agent.h             # 定义 WUKONG_AI_EVENT_EMOTION 等事件
├── ../../mode/                                # 模式层接收 Emotion 事件并转成 TY_DISPLAY_TP_EMOJI
├── ../../miscs/gui/display/tuya_ai_display.c  # 显示消息统一入口
├── ../../miscs/gui/display/ui/font_emoji_64.c # EVB/EVB_PRO 的 emoji 图片映射
├── ../../boards/T5AI_BOARD_DESKTOP/ui/        # Desktop 板的 Emotion -> GIF 映射
├── ../../boards/T5AI_BOARD_ROBOT/ui/robot/    # Robot 板的 Emotion -> GIF 映射
└── ../../boards/T5AI_BOARD_EYES/ui/           # Eyes 板的 Emotion -> GIF 映射

处理流程

情绪产生

在 Agent 开发过程中,需要通过提示词来约束模型在特定的场景下,返回特定的情绪。详情请参考 平台智能体提示词开发。情绪反馈提示词参考如下:

情绪感知

情绪处理

AI 模型在处理、反馈交互时,会将结构化的情绪数据下发给设备。情绪分为两类:“用户情绪” 和 “AI 情绪”。

  • 用户侧 ASR emotion:

    • 协议语义:skill emotion 表示用户侧 Emotion,即 ASR 语义对应的情绪。
    • 协议样例:wukong_ai_skills.h 中已经给出了 code="emo" 的 Skill 样例,skillContent.emotion[]skillContent.text[] 用于描述用户 Emotion。
    • 适用场景:用于表达 “用户当前说话状态或语气” 的 Emotion。
    1. Skill emotion(用户/ASR emotion)
    ┌──────────────────────────────────────────────┐
    │ bizType = SKILL                             │
    │ code = "emo"                               │
    │ skillContent.emotion[] / text[]            │
    └──────────────────────────────────────────────┘
                        │
                        ▼
    2. wukong_ai_skills.c 解析 Skill 数据
    ┌──────────────────────────────────────────────┐
    │ __wukong_ai_skill_process()                 │
    │ 当前协议已定义,代码未单独下钻为 Emotion 事件 │
    └──────────────────────────────────────────────┘
    
  • AI 侧 TTS emotion:

    • 协议语义:nlg emotion 表示 AI 侧 Emotion,即 TTS/回复内容对应的 Emotion。
    • 当前实现:wukong_ai_skills.c__wukong_ai_nlg_process() 会读取 data.tags[0],再通过 wukong_emoji_get_name() 转为 Emotion name。
    • 适用场景:用于表达 “AI 当前回复语气或表情” 的 Emotion。
    1 . nlg emotion(AI / TTS emotion)
    ┌──────────────────────────────────────────────┐
    │ bizType = NLG                               │
    │ data.content = "..."                        │
    │ data.tags[0] = "U+1F606"                    │
    └──────────────────────────────────────────────┘
                        │
                        ▼
    2. wukong_ai_skills.c 解析 NLG tags
    ┌──────────────────────────────────────────────┐
    │ __wukong_ai_nlg_process()                   │
    │ 读取 data.tags[0]                           │
    └──────────────────────────────────────────────┘
                        │
                        ▼
    3. skill_emotion.c 做 Emotion 映射
    ┌──────────────────────────────────────────────┐
    │ wukong_emoji_get_name("U+1F606")            │
    │ -> "laughing"                               │
    └──────────────────────────────────────────────┘
                        │
                        ▼
    4. 产生 Emotion 事件
    ┌──────────────────────────────────────────────┐
    │ wukong_ai_event_notify()                    │
    │ WUKONG_AI_EVENT_EMOTION                     │
    └──────────────────────────────────────────────┘
    

情绪表达

目前支持两种表达情绪的方式:在屏幕上展示不同的 GIF 表情文件、控制舵机执行不同的动作。

1. 各板级 UI 渲染/动作扩展
   ┌──────────────────────────────────────────────┐
   │ emo.name 和 emo. emoji 映射和转换                            │
   │ tuya_ai_display_msg(..., TY_DISPLAY_TP_EMOJI) │
   └──────────────────────────────────────────────┘
                       │
                       ▼
2. 各板级 UI 渲染/动作扩展
   ┌──────────────────────────────────────────────┐
   │ EVB / EVB_PRO : Unicode -> emoji 图片       │
   │ Desktop        : Emotion name -> GIF        │
   │ Robot / Eyes   : Emotion name -> GIF        │
   │ Robot(可选)    : Emotion name -> action          │
   └──────────────────────────────────────────────┘

表情

  • EVB/EVB_PRO:先通过 wukong_emoji_get_by_name() 反查 Unicode,再由 font_emoji_64.c 把 Unicode 绑定到具体图片资源。
  • Desktop:在 desk_event_handle.c > s_gif_emoj_table[] 中,将 Emotion name 绑定到首页 GIF。
  • Robot/Eyes:通过 gui_emotion_find() 在各自 Emotion 表中查找并切换 GIF 资源。

动作

  • 动作目前仅在 T5AI_BOARD_ROBOT 支持。
  • 机器人动作入口是 tuya_robot_action_set(),定义在 tuya_robot_actions.h
  • tuya_robot_action_set() 会继续调用 robot_action_add_action() 入队,后续在动作线程中再进入 servo_action_map_set(),最终分发到具体舵机动作函数。
  • 如果需要 emotion -> action,建议在 Robot 板的 TY_DISPLAY_TP_EMOJI 分支增加独立映射表,而不是改动通用字典模块。
1. 收到 Emotion name
   ┌──────────────────────────────────────────────┐
   │ "happy" / "thinking" / "surprise"           │
   └──────────────────────────────────────────────┘
                       │
                       ▼
2. emotion-action 映射表
   ┌──────────────────────────────────────────────┐
   │ happy    -> ROBOT_ACTION_DANCE              │
   │ thinking -> ROBOT_ACTION_STAND              │
   │ surprise -> ROBOT_ACTION_JUMP               │
   └──────────────────────────────────────────────┘
                       │
                       ▼
3. 进入动作接口
   ┌──────────────────────────────────────────────┐
   │ tuya_robot_action_set(action)               │
   └──────────────────────────────────────────────┘
                       │
                       ▼
4. 动作入队
   ┌──────────────────────────────────────────────┐
   │ robot_action_add_action(action)             │
   └──────────────────────────────────────────────┘
                       │
                       ▼
5. 动作线程执行
   ┌──────────────────────────────────────────────┐
   │ servo_action_map_set(action)                │
   └──────────────────────────────────────────────┘
                       │
                       ▼
6. 舵机动作函数
   ┌──────────────────────────────────────────────┐
   │ servo_action_dance_set()                    │
   │ servo_action_jump_set()                     │
   │ servo_action_stand_set()                    │
   └──────────────────────────────────────────────┘

API 参考

以下仅列出 skill_emotion.h 中声明的公共接口。

查询接口

CONST CHAR_T* wukong_emoji_get_name(CONST CHAR_T* emoji);
  • 说明:通过 Unicode 形式的 emoji 字符串查询 Emotion 名称。

  • 参数

    • emoji:输入的 Unicode 字符串,例如 U+1F636
  • 返回值

    • 成功时返回 Emotion 名称字符串。
    • 失败或未命中时返回默认 Emotion neutral

输入必须与字典表中的 Unicode 字符串完全一致。

未命中不会返回 NULL,而是回退到默认 Emotion。调用方如果需要区分 “未命中” 和 "neutral",应额外增加校验逻辑。

CONST CHAR_T* wukong_emoji_get_by_name(CONST CHAR_T* name);
  • 说明:通过 Emotion 名称反查 Unicode 形式的 emoji 字符串。

  • 参数

    • name:Emotion 名称,例如 happy
  • 返回值

    • 成功时返回 Unicode 字符串。
    • 失败或未命中时返回默认 Unicode U+1F636

Emotion name 由 g_emotions[] 统一维护,建议全部使用小写名称。

未命中同样会回退到默认 Emotion,对板级显示来说可能表现为 “静默显示默认表情”。

编码转换接口

INT_T wukong_emoji_unicode_to_utf8(CONST CHAR_T* unicode_str, CHAR_T* utf8_buf, size_t buf_size);
  • 说明:将 U+XXXXU+XXXXXX 形式的 Unicode 字符串转换为 UTF-8 字节流。

  • 参数

    • unicode_str:输入 Unicode 字符串,例如 U+1F606
    • utf8_buf:输出缓冲区。
    • buf_size:输出缓冲区大小。
  • 返回值

    • 成功时返回写入的 UTF-8 字节长度。
    • 失败时返回 -1

当前实现要求 buf_size >= 5,以兼容 4 字节 UTF-8 加结尾 \0

输入格式必须满足 U+ 前缀,否则直接失败。

使用示例

示例一:通过 Unicode 获取 Emotion name

#include "skill_emotion.h"
#include "tal_log.h"

VOID demo_lookup_emotion_name(VOID)
{
    CONST CHAR_T *name = wukong_emoji_get_name("U+1F606");
    TAL_PR_NOTICE("emotion name: %s", name);
}

示例二:通过 Emotion name 显示 emoji

#include "skill_emotion.h"
#include "tal_log.h"

VOID demo_show_emotion_utf8(VOID)
{
    CONST CHAR_T *unicode = wukong_emoji_get_by_name("happy");
    CHAR_T utf8_buf[5] = {0};
    INT_T len = 0;

    len = wukong_emoji_unicode_to_utf8(unicode, utf8_buf, sizeof(utf8_buf));
    if (len > 0) {
        TAL_PR_NOTICE("utf8 emoji: %s", utf8_buf);
    }
}

示例三:新增一个 Emotion

skill_emotion.cg_emotions[] 中增加一项:

{"U+1F973", "celebrating"}

之后按目标板补充绑定:

  • EVB/EVB_PRO:补充 font_emoji_64.c 映射和 emoji 图片资源。
  • Desktop:补充 s_gif_emoj_table[]
  • Robot/Eyes:补充各自 Emotion 表和资源。

示例四:把 Emotion 绑定到机器人动作

#include "tuya_robot_actions.h"

typedef struct {
    CONST CHAR_T *emotion;
    TUYA_ROBOT_ACTION_E action;
} EMOTION_ACTION_MAP_T;

STATIC CONST EMOTION_ACTION_MAP_T s_emotion_action_map[] = {
    {"happy", ROBOT_ACTION_DANCE},
    {"thinking", ROBOT_ACTION_STAND},
    {"surprise", ROBOT_ACTION_JUMP},
};

STATIC VOID robot_emotion_action_trigger(CONST CHAR_T *emotion)
{
    UINT_T i = 0;

    if (emotion == NULL) {
        return;
    }

    for (i = 0; i < CNTSOF(s_emotion_action_map); i++) {
        if (strcmp(s_emotion_action_map[i].emotion, emotion) == 0) {
            tuya_robot_action_set(s_emotion_action_map[i].action);
            break;
        }
    }
}

建议把这段逻辑放在 Robot 板级 UI 层,而非 skill_emotion.c 或通用 Mode 层。

支持

在开发过程遇到问题,可以到 TuyaOS 开发者论坛 > 联网单品开发版块 发帖咨询。