Skip to content

Emoji → Expression Mapping

Every LLM response starts with an emoji. The xiaozhi-server parses this emoji and sends an emotion frame to the StackChan firmware, which renders the corresponding face animation.

Active Mapping

Emoji Emotion ID Face Animation Source
😊 happy Smiling face Dotty patch
😆 laughing Laughing face Upstream
😢 sad Sad face Dotty patch
😮 surprised Surprised face Dotty patch
🤔 thinking Thinking face Upstream
😠 angry Angry face Upstream
😐 neutral Neutral face Dotty patch
😍 loving Love face Upstream
😴 sleepy Sleepy face Upstream

"Dotty patch" means the emoji was added to the upstream EMOJI_MAP in custom-providers/textUtils.py. "Upstream" means it exists in the base xiaozhi-server code.

Fallback Behavior

If the LLM forgets the emoji prefix, bridge.py prepends 😐 (neutral) via _ensure_emoji_prefix(). If the emoji is not in EMOJI_MAP, the firmware receives no emotion frame and keeps its current expression.

How to Add a New Emoji

See docs/cookbook/add-emoji.md.

Where the Code Lives

Component File What it does
Emoji enforcement bridge.py ALLOWED_EMOJIS tuple, _ensure_emoji_prefix()
Emoji → emotion custom-providers/textUtils.py EMOJI_MAP dict, get_emotion()
Emotion → face StackChan firmware Avatar renderer, expression assets

Upstream Emojis Not Used by Dotty

The upstream EMOJI_MAP includes additional emojis that Dotty doesn't use in its ALLOWED_EMOJIS: 😂 😭 😲 😱 😌 😜 🙄 😶 🙂 😳 😉 😎 🤤 😘 😏. These would work if the LLM produced them (the firmware would show the face), but the bridge's emoji enforcement constrains responses to the 9 emojis in the active mapping above.