AnimatedCharacter.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import React, { useEffect, useState } from 'react';
  2. import type { EmotionType, AnimationState } from '@/types';
  3. interface AnimatedCharacterProps {
  4. emotion: EmotionType;
  5. state: AnimationState;
  6. }
  7. // Emoji配置映射
  8. interface EmojiConfig {
  9. emoji: string;
  10. description: string;
  11. speech: string;
  12. }
  13. const EMOJI_MAP: Record<string, EmojiConfig> = {
  14. // 基础状态
  15. idle: {
  16. emoji: '😐',
  17. description: '待机中',
  18. speech: '您好!我是您的语音助手,请问有什么可以帮您?',
  19. },
  20. listening: {
  21. emoji: '👂',
  22. description: '正在倾听',
  23. speech: '正在聆听您的指令...',
  24. },
  25. thinking: {
  26. emoji: '🤔',
  27. description: '正在思考',
  28. speech: '让我思考一下...',
  29. },
  30. error: {
  31. emoji: '😵',
  32. description: '出错了',
  33. speech: '抱歉,出现了一些问题',
  34. },
  35. // 情感 - 说话状态
  36. speaking_neutral: {
  37. emoji: '😐',
  38. description: '平静回应',
  39. speech: '根据您的要求...',
  40. },
  41. speaking_happy: {
  42. emoji: '😊',
  43. description: '开心回应',
  44. speech: '太好了!',
  45. },
  46. speaking_sad: {
  47. emoji: '😢',
  48. description: '难过回应',
  49. speech: '听到这个我也很难过',
  50. },
  51. speaking_excited: {
  52. emoji: '😄',
  53. description: '兴奋回应',
  54. speech: '太棒了!',
  55. },
  56. speaking_angry: {
  57. emoji: '😠',
  58. description: '生气回应',
  59. speech: '这确实让人生气',
  60. },
  61. speaking_surprised: {
  62. emoji: '😲',
  63. description: '惊讶回应',
  64. speech: '哇!真没想到',
  65. },
  66. speaking_thoughtful: {
  67. emoji: '🤔',
  68. description: '深思回应',
  69. speech: '这是个值得深思的问题',
  70. },
  71. speaking_encouraging: {
  72. emoji: '💪',
  73. description: '鼓励回应',
  74. speech: '加油!你可以的',
  75. },
  76. speaking_confused: {
  77. emoji: '😕',
  78. description: '困惑回应',
  79. speech: '抱歉,我不太明白您的意思',
  80. },
  81. speaking_worried: {
  82. emoji: '😟',
  83. description: '担忧回应',
  84. speech: '这确实需要注意',
  85. },
  86. speaking_satisfied: {
  87. emoji: '😌',
  88. description: '满意回应',
  89. speech: '操作成功完成!',
  90. },
  91. speaking_friendly: {
  92. emoji: '😄',
  93. description: '友好回应',
  94. speech: '很高兴为您服务!',
  95. },
  96. speaking_sorry: {
  97. emoji: '😔',
  98. description: '抱歉回应',
  99. speech: '对不起,我无法完成这个请求',
  100. },
  101. };
  102. /**
  103. * 动画IP组件 - Emoji版本
  104. * 根据状态和情感显示对应的Emoji表情
  105. */
  106. export const AnimatedCharacter: React.FC<AnimatedCharacterProps> = ({ emotion, state }) => {
  107. const [currentEmoji, setCurrentEmoji] = useState('😐');
  108. const [statusText, setStatusText] = useState('待机中');
  109. const [speechText, setSpeechText] = useState('您好!我是您的语音助手');
  110. const [isAnimating, setIsAnimating] = useState(false);
  111. useEffect(() => {
  112. // 根据状态和情感获取对应的emoji配置
  113. let key = state;
  114. if (state === 'speaking') {
  115. key = `speaking_${emotion}`;
  116. }
  117. const config = EMOJI_MAP[key] || EMOJI_MAP.idle;
  118. // 添加切换动画效果
  119. setIsAnimating(true);
  120. setTimeout(() => {
  121. setCurrentEmoji(config.emoji);
  122. setStatusText(config.description);
  123. setSpeechText(config.speech);
  124. setIsAnimating(false);
  125. }, 150);
  126. }, [emotion, state]);
  127. return (
  128. <div className="animated-character" style={{
  129. position: 'relative',
  130. width: '100%',
  131. height: '100%',
  132. display: 'flex',
  133. flexDirection: 'column',
  134. alignItems: 'center',
  135. justifyContent: 'center',
  136. }}>
  137. {/* 状态指示器 */}
  138. <div style={{
  139. position: 'absolute',
  140. top: '-30px',
  141. padding: '8px 16px',
  142. backgroundColor: 'rgba(255, 255, 255, 0.2)',
  143. borderRadius: '20px',
  144. fontSize: '0.9rem',
  145. color: 'white',
  146. zIndex: 10,
  147. }}>
  148. {statusText}
  149. </div>
  150. {/* Emoji角色容器 */}
  151. <div style={{
  152. width: '200px',
  153. height: '200px',
  154. display: 'flex',
  155. alignItems: 'center',
  156. justifyContent: 'center',
  157. marginBottom: '40px',
  158. position: 'relative',
  159. zIndex: 5,
  160. }}>
  161. <div
  162. className="emoji-character"
  163. style={{
  164. fontSize: '100px',
  165. transition: 'all 0.3s ease',
  166. transform: isAnimating ? 'scale(0.8)' : 'scale(1)',
  167. filter: 'drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2))',
  168. }}
  169. >
  170. {currentEmoji}
  171. </div>
  172. </div>
  173. {/* 对话气泡 */}
  174. <div style={{
  175. position: 'relative',
  176. background: 'rgba(255, 255, 255, 0.9)',
  177. borderRadius: '15px',
  178. padding: '15px 20px',
  179. color: '#333',
  180. maxWidth: '80%',
  181. boxShadow: '0 4px 10px rgba(0, 0, 0, 0.1)',
  182. textAlign: 'center',
  183. fontSize: '14px',
  184. lineHeight: '1.5',
  185. zIndex: 10,
  186. }}>
  187. <div style={{
  188. position: 'absolute',
  189. bottom: '100%',
  190. left: '50%',
  191. marginLeft: '-10px',
  192. width: 0,
  193. height: 0,
  194. borderLeft: '10px solid transparent',
  195. borderRight: '10px solid transparent',
  196. borderBottom: '10px solid rgba(255, 255, 255, 0.9)',
  197. }} />
  198. {speechText}
  199. </div>
  200. </div>
  201. );
  202. };