🎭 情绪小智:当AI聊天遇上表情动画,打造 "有情绪的小智"
🚀 项目背景:
没啥背景,就是看到 LOOI 项目挺有趣的,刚好上手弄一个玩儿玩儿。想做的事情其实很多,这只是个开始(希望别只是开始。。。)。其实现在这个并不是我期望的效果。但是拖延症犯了,先丢出来再说吧。
🎨 核心亮点:表情系统
表情驱动的聊天体验
系统会根据AI的回复内容,自动匹配最合适的表情:
// 根据AI回复内容智能更新表情
void updateExpressionFromAIResponse(String content) {
final expression = FaceExpressionExtension.fromAIResponse(content);
updateExpression(expression);
}
表情映射逻辑:
- 😊 开心/兴奋 - 当AI回复包含"太好了"、"真棒"等词汇
- 😮 惊讶 - 当AI回复包含"哇"、"没想到"等词汇
- 🤔 思考 - 当AI回复包含"让我想想"、"考虑一下"等词汇
- 😍 喜爱 - 当AI回复包含"喜欢"、"爱"等词汇
- 😉 眨眼 - 随机触发,增加生动感
实时动画效果
实现了多种动画效果:
1. 自动眨眼动画
void _startAutoBlinking() {
_stopAutoBlinking();
_scheduleNextBlink();
}
void _scheduleNextBlink() {
if (!state.config.autoBlinkEnabled) return;
// 随机间隔2-5秒
final delay = Duration(milliseconds: 2000 + _random.nextInt(3000));
_blinkTimer = Timer(delay, () {
if (!isClosed && state.config.autoBlinkEnabled) {
triggerBlink();
_scheduleNextBlink();
}
});
}
2. 说话动画
void startSpeaking() {
if (state.isSpeaking) return;
// 启动说话动画定时器
_speakingTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
if (!state.isSpeaking) {
timer.cancel();
return;
}
// 模拟说话时的嘴部动画
final animationValue = 0.5 + 0.5 * math.sin(timer.tick * 0.5);
emit(state.copyWith(speakingAnimationValue: animationValue));
});
}
3. 呼吸动画
// 动画大小变化,0.8 倍到 1.2 倍之间缩放
_pulseAnimation = Tween<double>(begin: 0.98, end: 1.05).animate(
CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut),
);
🎯 技术实现:Flutter + 状态管理
架构设计
采用了Bloc/Cubit + Provider的混合状态管理方案(遗留问题,后续统一优化):
class FaceAnimationCubit extends Cubit<FaceAnimationState> {
Timer? _blinkTimer;
Timer? _speakingTimer;
final math.Random _random = math.Random();
FaceAnimationCubit() : super(const FaceAnimationState()) {
_startAutoBlinking();
}
// 更新表情
void updateExpression(FaceExpression expression) {
final newConfig = state.config.copyWith(expression: expression);
emit(state.copyWith(config: newConfig));
}
}
音频处理技术栈
为了实现流畅的语音交互,使用了以下音频处理技术:
// 音频处理相关库
opus_flutter: ^3.0.3 // Opus音频编码
opus_dart: ^3.0.1 // Dart Opus实现
flutter_sound: ^9.26.0 // 音频录制和播放
flutter_pcm_player: ^0.0.1 // PCM播放器
audio_streamer: ^4.1.1 // 音频流处理
音频处理流程:
- 录音 - 使用PCM格式录制用户语音
- 编码 - 转换为Opus格式发送给服务器
- 解码 - 接收服务器返回的Opus音频流
- 播放 - 转换为PCM格式播放
WebSocket实时通信
class XiaozhiService {
// 处理WebSocket消息
void _handleTextMessage(String message) {
try {
final Map<String, dynamic> jsonData = json.decode(message);
final String type = jsonData['type'] ?? '';
switch (type) {
case 'tts':
// TTS消息处理
final String text = jsonData['text'] ?? '';
if (text.isNotEmpty) {
_dispatchEvent(
XiaozhiServiceEvent(XiaozhiServiceEventType.textMessage, text),
);
}
break;
case 'emotion':
// 处理表情消息
final String emotion = jsonData['emotion'] ?? '';
if (emotion.isNotEmpty) {
_dispatchEvent(
XiaozhiServiceEvent(
XiaozhiServiceEventType.textMessage,
'表情: $emotion',
),
);
}
break;
}
} catch (e) {
print('$TAG: 解析消息失败: $e');
}
}
}
🎪 用户体验:沉浸式动画聊天
全屏沉浸体验
设计了横屏全屏的动画聊天界面,让用户完全沉浸在对话中:
// 强制横屏
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
// 设置全屏模式,隐藏状态栏和导航栏
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
交互设计
- 点击面部 - 循环切换表情
- 长按面部 - 显示/隐藏日志区域
- 点击打断 - 中断对话内容
- 点击挂断 - 退出全屏对话
🔧 开发挑战与解决方案
挑战1:表情与内容的智能匹配
问题:如何让 AI 的表情变化更自然、更符合对话内容?
解决方案:直接让 AI 驱动动画模型生成动画,不要使用固定模式。
🎨 动画效果展示
表情动画库
预定义了多种表情状态:
enum FaceExpression {
neutral, // 中性
happy, // 开心
surprised, // 惊讶
excited, // 兴奋
love, // 喜爱
winking, // 眨眼
speaking, // 说话
thinking, // 思考
}
动画配置
class AnimationConfig {
final FaceExpression expression;
final Color eyeColor;
final Color mouthColor;
final FaceSize faceSize;
final bool autoBlinkEnabled;
final bool isSpeaking;
}
🚀 未来规划
- 优化动画过渡效果
- 增加更多表情类型
- 添加手势控制
- 支持自定义表情
- 集成更多AI平台
- 支持3D面部动画
- 添加情感分析
- 实现多语言支持
🤝 参与讨论
这个项目还有很多可以改进的地方,欢迎开发者们参与讨论:
- 表情算法优化 - 如何让表情匹配更智能?
- 动画性能提升 - 有什么更好的动画实现方案?
- 用户体验改进 - 你觉得哪些交互可以优化?
- 技术架构讨论 - 对当前的技术选型有什么建议?
项目地址:GitHub - emotionzhi
技术栈:Flutter + Dart + Opus + WebSocket + Bloc/Cubit
支持平台:Android、iOS
让AI聊天变得有温度,让技术更有趣! 🎭✨
📝 开发者笔记
项目结构
lib/
├── cubits/ # 状态管理 - FaceAnimationCubit
├── models/ # 数据模型 - AnimationConfig, Conversation
├── providers/ # 状态提供者 - ConfigProvider, ConversationProvider
├── screens/ # 界面页面 - AnimationCallScreen, HomeScreen
├── services/ # 业务服务 - XiaozhiService, WebSocketManager
├── utils/ # 工具类 - AudioUtil, DeviceUtil
└── widgets/ # 自定义组件 - RobotFaceWidget
关键依赖
dependencies:
flutter_bloc: ^8.1.3 # 状态管理
opus_flutter: ^3.0.3 # 音频编码
flutter_sound: ^9.26.0 # 音频处理
web_socket_channel: ^2.4.0 # WebSocket通信
freezed: ^2.4.6 # 代码生成
开发环境
- Flutter 3.7.0+
- Dart 3.0+
- Android SDK 21+
- iOS 11.0+
⭕️ 小结及后续
- 表情动画:需要丰富表情效果,这个是重点。现在也有一些想法了,现验证下再说。
- 表情更新:目前临时方案是关键字匹配逻辑,后续会让 AI 根据对话内容自动生成情绪模型,然后模型驱动表情动画。
- 语音效果:目前是语音对话,感觉没啥意思,后续考虑减少说话频率,或者不说话。所以这块没打算精进了。
如果你觉得这个项目有趣,欢迎Star和Fork!也欢迎在Issues中提出你的想法和建议。 🚀