@siact/sime-x-vue 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sime-x-vue.mjs +1264 -54
- package/dist/sime-x-vue.mjs.map +1 -1
- package/dist/sime-x-vue.umd.js +1263 -52
- package/dist/sime-x-vue.umd.js.map +1 -1
- package/dist/style.css +412 -83
- package/package.json +1 -1
- package/types/components/sime-provider.vue.d.ts +4 -4
- package/types/components/tool-card.vue.d.ts +28 -0
- package/types/components/voice-assistant.vue.d.ts +44 -0
- package/types/composables/index.d.ts +6 -0
- package/types/composables/use-agent-invoke.d.ts +79 -0
- package/types/composables/use-bubble.d.ts +39 -0
- package/types/composables/use-tts.d.ts +17 -0
- package/types/composables/use-voice-recognition.d.ts +28 -0
- package/types/index.d.ts +1 -0
- package/types/lib/data-stream-parser.d.ts +84 -0
- package/types/types.d.ts +11 -1
package/dist/sime-x-vue.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sime-x-vue.mjs","sources":["../src/injection-key.ts","../src/types.ts","../src/components/sime-provider.vue","../src/components/voice-status.vue","../src/components/execution-status.vue","../src/lib/utils.ts","../src/components/sime-x.vue"],"sourcesContent":["import type { InjectionKey } from 'vue'\r\nimport type { AiChatbotXContext } from './types'\r\nimport { inject } from 'vue'\r\n\r\nexport const AiChatbotXKey: InjectionKey<AiChatbotXContext> = Symbol('sime-x')\r\n\r\nexport function injectStrict<T>(key: InjectionKey<T>): T\r\nexport function injectStrict<T>(key: InjectionKey<T>, defaultValue: T, treatDefaultAsFactory?: false): T\r\nexport function injectStrict<T>(key: InjectionKey<T>, defaultValue: T | (() => T), treatDefaultAsFactory: true): T\r\nexport function injectStrict<T>(key: InjectionKey<T>, defaultValue?: T | (() => T), treatDefaultAsFactory?: boolean): T {\r\n let result: T | undefined\r\n\r\n if (defaultValue === undefined) {\r\n result = inject(key) as T | undefined\r\n }\r\n else if (treatDefaultAsFactory === true) {\r\n result = inject(key, defaultValue as T | (() => T), true)\r\n }\r\n else {\r\n result = inject(key, defaultValue as T, false)\r\n }\r\n\r\n if (!result) {\r\n throw new Error(`Could not resolve ${key.description}`)\r\n }\r\n return result\r\n}\r\n","import type { CommandDefinition, DiscoveredCommand } from \"@siact/sime-bridge\";\r\n\r\nexport enum clientCommandKey {\r\n SET_THEME = \"SiMeAgent_setTheme\",\r\n APPEND_MESSAGE = \"SiMeAgent_appendMessage\",\r\n WAKE = \"SiMeAgent_wake\",\r\n TRANSITION = \"SiMeAgent_transition\",\r\n TRANSITION_END = \"SiMeAgent_transition_end\",\r\n START_NEW_CONVERSATION = \"SiMeAgent_startNewConversation\",\r\n RECOGNITION = 'SiMeAgent_recognition'\r\n}\r\n\r\nexport interface VoiceConfig {\r\n appId: string;\r\n apiKey: string;\r\n websocketUrl: string;\r\n}\r\n\r\nexport interface AiChatbotXContext {\r\n chatbotUrl: () => string;\r\n appId: () => string;\r\n appToken: () => string;\r\n voiceConfig: () => VoiceConfig;\r\n registerCommand: (cmd: CommandDefinition) => void;\r\n unregisterCommand: (name: string) => void;\r\n clientCommand: () => Promise<DiscoveredCommand[]>;\r\n hostCommads: () => Promise<DiscoveredCommand[]>;\r\n appendMessage: (message: string) => Promise<void>;\r\n setTheme: (theme: string) => Promise<void>;\r\n weak: () => Promise<void>;\r\n startListening: () => Promise<void>;\r\n stopListening: () => Promise<void>;\r\n toggleCollapse: () => Promise<void>;\r\n openDialog: () => Promise<void>;\r\n closeDialog: () => Promise<void>;\r\n registerVoiceMethods: (methods: {\r\n start: () => Promise<void>;\r\n stop: () => Promise<void>;\r\n toggleCollapse: () => Promise<void>;\r\n openDialog: () => Promise<void>;\r\n closeDialog: () => Promise<void>;\r\n }) => void;\r\n startNewConversation: () => Promise<void>;\r\n setIframeElement: (iframe: HTMLIFrameElement) => void;\r\n recognition: (message: string, commands: DiscoveredCommand[]) => Promise<any>;\r\n executeCommand: (commandName: string, args?: any[]) => Promise<any>;\r\n}\r\n","<template>\r\n <slot></slot>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { provide, shallowRef } from 'vue';\r\nimport { HostBridge, CommandDefinition } from '@siact/sime-bridge';\r\nimport { AiChatbotXKey } from '../injection-key';\r\nimport { clientCommandKey, VoiceConfig } from '../types';\r\n\r\nconst props = defineProps<{\r\n /** 项目名称 */\r\n project: string;\r\n /** 项目描述 */\r\n description?: string;\r\n /** 是否开启调试模式 */\r\n debug?: boolean;\r\n /** iframeUrl */\r\n chatbotUrl: string;\r\n /** appId */\r\n appId: string;\r\n /** appToken */\r\n appToken: string;\r\n /** 语音配置 */\r\n voiceConfig: VoiceConfig;\r\n}>();\r\n\r\nconst hostBridge = shallowRef<HostBridge>(new HostBridge());\r\n\r\nconst startListeningRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst stopListeningRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst toggleCollapseRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst openDialogRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst closeDialogRef = shallowRef<() => Promise<void>>(async () => {});\r\n\r\nprovide(AiChatbotXKey, {\r\n chatbotUrl: () => props.chatbotUrl,\r\n appId: () => props.appId,\r\n appToken: () => props.appToken,\r\n voiceConfig: () => props.voiceConfig,\r\n startListening: () => startListeningRef.value(),\r\n stopListening: () => stopListeningRef.value(),\r\n toggleCollapse: () => toggleCollapseRef.value(),\r\n openDialog: () => openDialogRef.value(),\r\n closeDialog: () => closeDialogRef.value(),\r\n registerVoiceMethods: (methods: {\r\n start: () => Promise<void>;\r\n stop: () => Promise<void>;\r\n toggleCollapse: () => Promise<void>;\r\n openDialog: () => Promise<void>;\r\n closeDialog: () => Promise<void>;\r\n }) => {\r\n startListeningRef.value = methods.start;\r\n stopListeningRef.value = methods.stop;\r\n toggleCollapseRef.value = methods.toggleCollapse;\r\n openDialogRef.value = methods.openDialog;\r\n closeDialogRef.value = methods.closeDialog;\r\n },\r\n clientCommand: () => hostBridge.value.clientCommands(),\r\n hostCommads: () => hostBridge.value.hostCommands(),\r\n registerCommand: (cmd: CommandDefinition) => {\r\n hostBridge.value.registerCommand(cmd);\r\n },\r\n unregisterCommand: (name) => {\r\n hostBridge.value.unregisterCommand(name);\r\n },\r\n async appendMessage(message) {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.APPEND_MESSAGE, [message]);\r\n },\r\n async setTheme(theme) {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.SET_THEME, [theme]);\r\n },\r\n async weak() {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.WAKE);\r\n },\r\n async startNewConversation() {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.START_NEW_CONVERSATION);\r\n },\r\n setIframeElement(iframe) {\r\n hostBridge.value.setIframe(iframe);\r\n },\r\n async recognition(message, commands) {\r\n return await hostBridge.value.executeClientCommand(clientCommandKey.RECOGNITION, [message, commands]);\r\n },\r\n async executeCommand(commandName, args = []) {\r\n return await hostBridge.value.executeCommand(commandName, args);\r\n },\r\n});\r\n</script>\r\n","<template>\r\n <transition name=\"voice-panel\">\r\n <!-- Main Container -->\r\n <div v-if=\"status === 'wake' || isTranscribing\" class=\"voice-status-wrapper\" :class=\"currentMode\">\r\n <!-- Visual Indicator Section -->\r\n <div class=\"indicator-container\">\r\n <!-- Ambient Glow (Background) -->\r\n <div class=\"ambient-glow\"></div>\r\n\r\n <!-- Animated Ripples -->\r\n <div class=\"ripple-layer\">\r\n <div class=\"ripple delay-1\"></div>\r\n <div class=\"ripple delay-2\"></div>\r\n <div class=\"ripple delay-3\"></div>\r\n </div>\r\n\r\n <!-- Core Icon Circle -->\r\n <div class=\"icon-core\">\r\n <!-- Unified Microphone Icon -->\r\n <svg\r\n class=\"mic-icon\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <!-- Microphone Capsule (Animates on voice) -->\r\n <rect x=\"9\" y=\"2\" width=\"6\" height=\"12\" rx=\"3\" class=\"mic-capsule\" />\r\n <!-- Stand/Base -->\r\n <path d=\"M5 10C5 13.866 8.13401 17 12 17C15.866 17 19 13.866 19 10\" class=\"mic-stand\" />\r\n <path d=\"M12 17V21M8 21H16\" class=\"mic-base\" />\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <!-- Content Section -->\r\n <div class=\"content-container\">\r\n <!-- Status Header -->\r\n <div class=\"status-header\">\r\n <span class=\"status-text\">{{ statusLabel }}</span>\r\n </div>\r\n\r\n <!-- Transcription Text (Animated Entry) -->\r\n <div class=\"text-window\" :class=\"{ 'has-text': !!transcriptionText }\">\r\n <transition name=\"fade-slide\" mode=\"out-in\">\r\n <p v-if=\"transcriptionText\" class=\"transcription-content\">\r\n {{ transcriptionText }}\r\n </p>\r\n <p v-else-if=\"status === 'wake'\" class=\"placeholder-text\">Listening...</p>\r\n </transition>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from 'vue';\r\ntype VoiceStatus = 'wake' | 'listening' | 'standby';\r\n\r\nconst props = defineProps<{\r\n status: VoiceStatus;\r\n transcriptionText?: string;\r\n isTranscribing?: boolean;\r\n}>();\r\n\r\n// Determine the current visual mode\r\nconst currentMode = computed(() => {\r\n if (props.isTranscribing) return 'mode-transcribing';\r\n if (props.status === 'wake') return 'mode-wake';\r\n return 'mode-standby';\r\n});\r\n\r\n// Dynamic label text\r\nconst statusLabel = computed(() => {\r\n if (props.isTranscribing) return '正在聆听您的问题...';\r\n if (props.status === 'wake') return '您好,有什么可以帮助您的吗?';\r\n return 'Standby';\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use 'sass:color';\r\n\r\n/* --- Design Tokens --- */\r\n$c-wake: #10b981; // Emerald for Wake\r\n$c-transcribe: #3b82f6; // Blue for Transcribing\r\n$bg-glass: rgba(15, 23, 42, 0.85);\r\n$border-glass: rgba(255, 255, 255, 0.1);\r\n$ease-smooth: cubic-bezier(0.25, 0.8, 0.25, 1);\r\n$ease-elastic: cubic-bezier(0.34, 1.56, 0.64, 1);\r\n\r\n/* --- Main Container --- */\r\n.voice-status-wrapper {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 20px;\r\n padding: 24px;\r\n background: $bg-glass;\r\n backdrop-filter: blur(16px);\r\n -webkit-backdrop-filter: blur(16px);\r\n border: 1px solid $border-glass;\r\n border-radius: 24px;\r\n box-shadow:\r\n 0 10px 40px -10px rgba(0, 0, 0, 0.5),\r\n inset 0 1px 0 rgba(255, 255, 255, 0.1);\r\n transition: all 0.4s $ease-smooth;\r\n max-width: 480px;\r\n width: 100%;\r\n}\r\n\r\n/* --- Indicator Section --- */\r\n.indicator-container {\r\n position: relative;\r\n width: 64px;\r\n height: 64px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n}\r\n\r\n.ambient-glow {\r\n position: absolute;\r\n inset: -20px;\r\n border-radius: 50%;\r\n opacity: 0;\r\n filter: blur(20px);\r\n transition: all 0.5s ease;\r\n}\r\n\r\n.icon-core {\r\n position: relative;\r\n width: 52px;\r\n height: 52px;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.05);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: 1px solid rgba(255, 255, 255, 0.1);\r\n z-index: 10;\r\n transition: all 0.4s $ease-elastic;\r\n overflow: hidden;\r\n\r\n .mic-icon {\r\n width: 24px;\r\n height: 24px;\r\n color: rgba(255, 255, 255, 0.9);\r\n transition: all 0.3s ease;\r\n\r\n .mic-capsule {\r\n transition: transform 0.2s ease;\r\n transform-origin: center center;\r\n }\r\n }\r\n}\r\n\r\n/* --- Ripple Effects --- */\r\n.ripple-layer {\r\n position: absolute;\r\n inset: 0;\r\n pointer-events: none;\r\n}\r\n\r\n.ripple {\r\n position: absolute;\r\n inset: 0;\r\n border-radius: 50%;\r\n border: 2px solid transparent;\r\n opacity: 0;\r\n}\r\n\r\n/* --- Content Section --- */\r\n.content-container {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n min-width: 0; /* Prevent flex text overflow */\r\n padding-top: 4px;\r\n}\r\n\r\n.status-header {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n margin-bottom: 8px;\r\n}\r\n\r\n.status-dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: currentColor;\r\n box-shadow: 0 0 8px currentColor;\r\n transition: color 0.3s ease;\r\n}\r\n\r\n.status-text {\r\n font-size: 13px;\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n letter-spacing: 0.05em;\r\n color: rgba(255, 255, 255, 0.6);\r\n}\r\n\r\n.text-window {\r\n min-height: 24px;\r\n position: relative;\r\n}\r\n\r\n.transcription-content {\r\n font-size: 16px;\r\n line-height: 1.5;\r\n color: #fff;\r\n font-weight: 500;\r\n margin: 0;\r\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\r\n}\r\n\r\n.placeholder-text {\r\n font-size: 16px;\r\n color: rgba(255, 255, 255, 0.3);\r\n font-style: italic;\r\n margin: 0;\r\n}\r\n\r\n/* --- State: Wake --- */\r\n.mode-wake {\r\n border-color: rgba($c-wake, 0.3);\r\n\r\n .ambient-glow {\r\n background: $c-wake;\r\n opacity: 0.2;\r\n }\r\n\r\n .icon-core {\r\n background: linear-gradient(135deg, rgba($c-wake, 0.2), rgba($c-wake, 0.1));\r\n border-color: rgba($c-wake, 0.4);\r\n box-shadow: 0 0 15px rgba($c-wake, 0.2);\r\n\r\n .mic-icon {\r\n color: color.adjust($c-wake, $lightness: 10%);\r\n }\r\n }\r\n\r\n .status-dot {\r\n color: $c-wake;\r\n animation: pulse-dot 2s infinite;\r\n }\r\n\r\n .ripple {\r\n border-color: $c-wake;\r\n animation: ripple-out 3s infinite;\r\n\r\n &.delay-1 {\r\n animation-delay: 0s;\r\n }\r\n &.delay-2 {\r\n animation-delay: 1s;\r\n }\r\n &.delay-3 {\r\n animation-delay: 2s;\r\n }\r\n }\r\n}\r\n\r\n/* --- State: Transcribing --- */\r\n.mode-transcribing {\r\n border-color: rgba($c-transcribe, 0.3);\r\n\r\n .ambient-glow {\r\n background: $c-transcribe;\r\n opacity: 0.3;\r\n animation: glow-breathe 1.5s ease-in-out infinite alternate;\r\n }\r\n\r\n .icon-core {\r\n background: linear-gradient(135deg, rgba($c-transcribe, 0.3), rgba($c-transcribe, 0.1));\r\n border-color: rgba($c-transcribe, 0.5);\r\n box-shadow: 0 0 20px rgba($c-transcribe, 0.3);\r\n transform: scale(1.1);\r\n\r\n .mic-icon {\r\n color: #fff;\r\n\r\n .mic-capsule {\r\n animation: mic-bounce 0.6s ease-in-out infinite alternate;\r\n }\r\n }\r\n }\r\n\r\n .status-dot {\r\n color: $c-transcribe;\r\n }\r\n\r\n .ripple {\r\n border-color: $c-transcribe;\r\n animation: ripple-rapid 1.5s infinite;\r\n\r\n &.delay-1 {\r\n animation-delay: 0s;\r\n }\r\n &.delay-2 {\r\n animation-delay: 0.3s;\r\n }\r\n &.delay-3 {\r\n animation-delay: 0.6s;\r\n }\r\n }\r\n}\r\n\r\n/* --- Animations --- */\r\n@keyframes ripple-out {\r\n 0% {\r\n transform: scale(0.8);\r\n opacity: 0;\r\n border-width: 2px;\r\n }\r\n 20% {\r\n opacity: 0.5;\r\n }\r\n 100% {\r\n transform: scale(2.2);\r\n opacity: 0;\r\n border-width: 0px;\r\n }\r\n}\r\n\r\n@keyframes ripple-rapid {\r\n 0% {\r\n transform: scale(0.9);\r\n opacity: 0;\r\n }\r\n 50% {\r\n opacity: 0.4;\r\n }\r\n 100% {\r\n transform: scale(1.6);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n@keyframes pulse-dot {\r\n 0%,\r\n 100% {\r\n opacity: 1;\r\n transform: scale(1);\r\n }\r\n 50% {\r\n opacity: 0.5;\r\n transform: scale(0.8);\r\n }\r\n}\r\n\r\n@keyframes glow-breathe {\r\n 0% {\r\n opacity: 0.2;\r\n transform: scale(0.9);\r\n }\r\n 100% {\r\n opacity: 0.4;\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n@keyframes mic-bounce {\r\n 0% {\r\n transform: scaleY(1);\r\n }\r\n 100% {\r\n transform: scaleY(0.7);\r\n }\r\n}\r\n\r\n/* --- Vue Transitions --- */\r\n.voice-panel-enter-active,\r\n.voice-panel-leave-active {\r\n transition: all 0.4s $ease-elastic;\r\n}\r\n.voice-panel-enter-from,\r\n.voice-panel-leave-to {\r\n opacity: 0;\r\n transform: translateY(20px) scale(0.95);\r\n}\r\n\r\n.fade-slide-enter-active,\r\n.fade-slide-leave-active {\r\n transition: all 0.3s ease;\r\n}\r\n.fade-slide-enter-from {\r\n opacity: 0;\r\n transform: translateY(10px);\r\n}\r\n.fade-slide-leave-to {\r\n opacity: 0;\r\n transform: translateY(-10px);\r\n}\r\n</style>\r\n","<template>\r\n <transition name=\"exec-bubble\">\r\n <div v-if=\"visible\" class=\"execution-bubble\">\r\n <!-- 文本内容 -->\r\n <span class=\"exec-text\">{{ text || '执行中' }}</span>\r\n <!-- 三点加载动画 -->\r\n <div class=\"loading-dots\">\r\n <span class=\"dot\"></span>\r\n <span class=\"dot\"></span>\r\n <span class=\"dot\"></span>\r\n </div>\r\n </div>\r\n </transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\ndefineProps<{\r\n visible: boolean;\r\n text?: string;\r\n}>();\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n$c-exec: #a855f7;\r\n$c-exec-light: #c084fc;\r\n$bg-glass: rgba(15, 23, 42, 0.9);\r\n$ease-smooth: cubic-bezier(0.25, 0.8, 0.25, 1);\r\n\r\n.execution-bubble {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 12px 20px;\r\n background: $bg-glass;\r\n backdrop-filter: blur(16px);\r\n -webkit-backdrop-filter: blur(16px);\r\n border: 1px solid rgba($c-exec, 0.35);\r\n border-radius: 20px;\r\n box-shadow:\r\n 0 4px 20px rgba(0, 0, 0, 0.3),\r\n 0 0 20px -5px rgba($c-exec, 0.3),\r\n inset 0 1px 0 rgba(255, 255, 255, 0.08);\r\n}\r\n\r\n/* 文本样式 */\r\n.exec-text {\r\n font-size: 14px;\r\n font-weight: 500;\r\n color: rgba(255, 255, 255, 0.9);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n max-width: 300px;\r\n}\r\n\r\n/* 三点加载动画 */\r\n.loading-dots {\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n margin-left: 10px;\r\n}\r\n\r\n.dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: $c-exec-light;\r\n animation: dot-bounce 1.4s ease-in-out infinite;\r\n\r\n &:nth-child(1) {\r\n animation-delay: 0s;\r\n }\r\n &:nth-child(2) {\r\n animation-delay: 0.2s;\r\n }\r\n &:nth-child(3) {\r\n animation-delay: 0.4s;\r\n }\r\n}\r\n\r\n@keyframes dot-bounce {\r\n 0%,\r\n 80%,\r\n 100% {\r\n transform: scale(0.6);\r\n opacity: 0.4;\r\n }\r\n 40% {\r\n transform: scale(1);\r\n opacity: 1;\r\n box-shadow: 0 0 8px rgba($c-exec-light, 0.6);\r\n }\r\n}\r\n\r\n/* Vue 过渡动画 */\r\n.exec-bubble-enter-active {\r\n transition: all 0.3s $ease-smooth;\r\n}\r\n\r\n.exec-bubble-leave-active {\r\n transition: all 0.2s $ease-smooth;\r\n}\r\n\r\n.exec-bubble-enter-from {\r\n opacity: 0;\r\n transform: scale(0.8);\r\n}\r\n\r\n.exec-bubble-leave-to {\r\n opacity: 0;\r\n transform: scale(0.8);\r\n}\r\n</style>\r\n","import { DiscoveredCommand } from '@siact/sime-bridge'\r\n\r\nexport const ensureMicrophonePermission = async () => {\r\n // 检查浏览器环境\r\n if (typeof navigator === 'undefined' || typeof window === 'undefined') {\r\n console.log('当前环境不支持麦克风访问');\r\n return false;\r\n }\r\n\r\n // 检查 MediaDevices API 支持\r\n if (!navigator.mediaDevices?.getUserMedia || !navigator.mediaDevices?.enumerateDevices) {\r\n console.log('当前环境不支持麦克风访问');\r\n return false;\r\n }\r\n\r\n try {\r\n // 1. 首先枚举设备,检查是否有音频输入设备\r\n const devices = await navigator.mediaDevices.enumerateDevices();\r\n const audioInputDevices = devices.filter((device) => device.kind === 'audioinput');\r\n\r\n if (audioInputDevices.length === 0) {\r\n console.log('未检测到麦克风设备,请连接麦克风后重试。');\r\n return false;\r\n }\r\n\r\n // 2. 检查权限状态(如果浏览器支持)\r\n if ('permissions' in navigator && navigator.permissions?.query) {\r\n try {\r\n const status = await navigator.permissions.query({ name: 'microphone' as PermissionName });\r\n\r\n if (status.state === 'denied') {\r\n console.log('麦克风权限被禁用,请在浏览器设置中开启。');\r\n return false;\r\n }\r\n } catch (e) {\r\n // 某些浏览器可能不支持 microphone 权限查询,继续执行\r\n console.warn('Permission query not supported:', e);\r\n }\r\n }\r\n\r\n // 3. 尝试获取麦克风流以确认权限和设备可用性\r\n let stream: MediaStream | null = null;\r\n try {\r\n stream = await navigator.mediaDevices.getUserMedia({\r\n audio: {\r\n echoCancellation: true,\r\n noiseSuppression: true,\r\n autoGainControl: true,\r\n },\r\n });\r\n\r\n // 检查流是否有活动的音频轨道\r\n const audioTracks = stream.getAudioTracks();\r\n if (audioTracks.length === 0) {\r\n console.log('无法获取麦克风音频轨道。');\r\n return false;\r\n }\r\n\r\n // 检查音频轨道是否启用且可读\r\n const activeTrack = audioTracks[0];\r\n if (!activeTrack.enabled || activeTrack.readyState !== 'live') {\r\n console.log('麦克风设备不可用,请检查设备连接。');\r\n return false;\r\n }\r\n\r\n return true;\r\n } finally {\r\n // 确保释放流资源\r\n if (stream) {\r\n stream.getTracks().forEach((track) => track.stop());\r\n }\r\n }\r\n } catch (error: any) {\r\n console.error('Microphone permission check failed', error);\r\n\r\n // 根据错误类型提供更具体的提示\r\n if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {\r\n console.log('未检测到麦克风设备,请连接麦克风后重试。');\r\n } else if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {\r\n console.log('麦克风权限被拒绝,请在浏览器设置中允许访问。');\r\n } else if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {\r\n console.log('麦克风被其他应用占用或无法访问。');\r\n } else {\r\n console.log('无法访问麦克风,请检查设备连接和浏览器权限。');\r\n }\r\n\r\n return false;\r\n }\r\n};\r\n\r\n\r\n/**\r\n * 语音命令匹配函数\r\n * @param {string} userInput - 用户输入的原始语音文本\r\n * @param {Array} commandList - 命令列表对象数组\r\n * @param {number} threshold - 相似度阈值 (0-1),默认 0.5\r\n */\r\nexport function matchVoiceCommand(userInput: string, commandList: DiscoveredCommand[], threshold = 0.5) {\r\n if (!userInput || typeof userInput !== 'string') return null;\r\n\r\n // 1. 预处理:转小写、去空格、去标点、去语气词\r\n const cleanInput = userInput\r\n .trim()\r\n .toLowerCase()\r\n // 1. 去除所有标点符号及特殊字符\r\n .replace(/[,。?!;:、“”()()<>《》\\s\\.\\,\\?\\!]/g, '')\r\n // 2. 去除常见的前缀 (增加“给我”、“能不能”等)\r\n .replace(/^(请帮我|我想|帮我|麻烦|我要|你好|您好|帮我把|给我|能不能帮我|请问|那个)/g, '')\r\n // 3. 去除中间的动作虚词 (如“把...给...”)\r\n .replace(/给(?=(打开|开启|关闭|停止))/g, '')\r\n // 4. 去除常见的后缀 (增加“就可以了”、“就行”、“模式”)\r\n .replace(/(一下|了|吧|输出|就可以了|就行|模式|操作|功能)$/g, '');\r\n\r\n let bestMatch = null;\r\n let maxScore = 0;\r\n\r\n // 编辑距离算法 (Levenshtein Distance)\r\n const getSimilarity = (s1: string, s2: string) => {\r\n const [l1, l2] = [s1.length, s2.length];\r\n const matrix = Array.from({ length: l1 + 1 }, () => Array(l2 + 1).fill(0));\r\n for (let i = 0; i <= l1; i++) matrix[i][0] = i;\r\n for (let j = 0; j <= l2; j++) matrix[0][j] = j;\r\n\r\n for (let i = 1; i <= l1; i++) {\r\n for (let j = 1; j <= l2; j++) {\r\n const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;\r\n matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);\r\n }\r\n }\r\n return 1 - matrix[l1][l2] / Math.max(l1, l2);\r\n };\r\n\r\n // 2. 遍历命令列表进行比对\r\n for (const cmd of commandList) {\r\n const target = cmd.description.toLowerCase();\r\n let currentScore = 0;\r\n\r\n // 策略 A:直接包含 (如输入“帮我开启漫游吧”,描述是“开启漫游”)\r\n if (cleanInput.includes(target) || target.includes(cleanInput)) {\r\n // 计算包含关系的得分,越接近 1 分越高\r\n currentScore = Math.min(target.length, cleanInput.length) / Math.max(target.length, cleanInput.length);\r\n // 给予包含匹配更高的基础权重\r\n currentScore = 0.8 + currentScore * 0.2;\r\n }\r\n // 策略 B:模糊匹配 (处理同音字错误,如“开启慢游”)\r\n else {\r\n currentScore = getSimilarity(cleanInput, target);\r\n }\r\n\r\n // 更新最高分项\r\n if (currentScore > maxScore) {\r\n maxScore = currentScore;\r\n bestMatch = { ...cmd, confidence: maxScore };\r\n }\r\n }\r\n\r\n // 3. 结果过滤\r\n return maxScore >= threshold ? bestMatch : null;\r\n}","<template>\r\n <div class=\"sime-x\" :data-theme=\"currentTheme\">\r\n <!-- 悬浮按钮(最小化状态) -->\r\n <transition name=\"fade\">\r\n <div ref=\"fabRef\" class=\"assistant-fab\" @click=\"toggleDialog(!visible)\">\r\n <VoiceStatus\r\n v-if=\"!isProcessing\"\r\n class=\"voice-status\"\r\n :status=\"voiceStatus\"\r\n :transcription-text=\"transcriptionText\"\r\n :is-transcribing=\"isTranscribing\"\r\n style=\"width: 480px\"\r\n />\r\n <ExecutionStatus v-else class=\"voice-status\" :visible=\"isProcessing\" :text=\"transcriptionText\" />\r\n <div class=\"fab-avatar-wrapper\">\r\n <img\r\n :src=\"xLogo ? xLogo : '/sime.png'\"\r\n alt=\"assistant\"\r\n :style=\"{\r\n width: xSize?.width + 'px',\r\n }\"\r\n />\r\n <!-- 优化后的监听状态指示器 -->\r\n <transition name=\"indicator-fade\">\r\n <div v-if=\"voiceStatus === 'listening'\" class=\"listening-badge\" :class=\"{ 'wake-active': wakeAnimating }\">\r\n <div class=\"listening-waves\">\r\n <div class=\"wave wave-1\"></div>\r\n <div class=\"wave wave-2\"></div>\r\n <div class=\"wave wave-3\"></div>\r\n </div>\r\n <div class=\"listening-icon\">\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z\"\r\n fill=\"currentColor\"\r\n />\r\n <path\r\n d=\"M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n <div class=\"fab-pulse\" :class=\"{ active: voiceStatus === 'listening' }\"></div>\r\n </div>\r\n </transition>\r\n\r\n <!-- 弹窗 -->\r\n <transition name=\"dialog-fade\">\r\n <div\r\n ref=\"dialogRef\"\r\n class=\"x-dialog-container\"\r\n :class=\"{\r\n collapsed: isCollapsed,\r\n 'is-hidden': !visible,\r\n 'position-ready': positionReady,\r\n }\"\r\n :style=\"{\r\n width: containerWidth + 'px',\r\n height: isCollapsed ? 'auto' : containerHeight + 'px',\r\n border: currentTheme === 'light' && !isCollapsed ? '1px solid var(--border-color)' : 'none',\r\n '--dialog-x': position.x + 'px',\r\n '--dialog-y': position.y + 'px',\r\n }\"\r\n @mousedown=\"startDrag\"\r\n >\r\n <div class=\"x-dialog-header\" @mousedown.stop=\"startDrag\">\r\n <div class=\"header-left\">\r\n <div class=\"logo-icon\">\r\n <img :src=\"xLogo ? xLogo : '/sime.png'\" alt=\"assistant\" class=\"logo\" />\r\n </div>\r\n <span class=\"title\">{{ xTitle }}</span>\r\n </div>\r\n <div class=\"actions\">\r\n <button class=\"action-btn theme-btn\" title=\"开启新对话\" @click=\"startNewConversation\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M12 5v14M5 12h14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </button>\r\n <button\r\n class=\"action-btn theme-btn\"\r\n :class=\"{\r\n active: voiceStatus !== 'standby',\r\n listening: voiceStatus === 'listening',\r\n woke: voiceStatus === 'wake',\r\n }\"\r\n @click.stop=\"() => toggleVoiceMode()\"\r\n :title=\"voiceButtonTooltip\"\r\n >\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n d=\"M12 15C13.6569 15 15 13.6569 15 12V7C15 5.34315 13.6569 4 12 4C10.3431 4 9 5.34315 9 7V12C9 13.6569 10.3431 15 12 15Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M18 11C18 14.3137 15.3137 17 12 17C8.68629 17 6 14.3137 6 11\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M12 19V17\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M9 21H15\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n <span class=\"voice-indicator\" v-if=\"voiceStatus !== 'standby'\"></span>\r\n </button>\r\n <button class=\"action-btn theme-btn\" @click.stop=\"cycleTheme\" :title=\"themeTooltip\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <circle cx=\"12\" cy=\"12\" r=\"7\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n <path d=\"M12 5A7 7 0 1 1 12 19\" fill=\"currentColor\" />\r\n </svg>\r\n </button>\r\n <button class=\"action-btn collapse-btn\" @click.stop=\"toggleCollapse\" :title=\"isCollapsed ? '展开' : '折叠'\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n :d=\"isCollapsed ? 'M18 15L12 9L6 15' : 'M6 9L12 15L18 9'\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n <button class=\"action-btn minimize-btn\" @click.stop=\"toggleDialog(false)\" title=\"最小化\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M5 12H19\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n <div :class=\"['x-dialog-content', { 'is-hidden': isCollapsed }]\" :style=\"{ opacity: isCollapsed ? 0 : 1 }\">\r\n <iframe\r\n ref=\"iframeRef\"\r\n :src=\"chatbotUrl\"\r\n class=\"x-iframe\"\r\n allow=\"microphone *\"\r\n frameborder=\"0\"\r\n @load=\"handleIframeLoad\"\r\n ></iframe>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, onBeforeUnmount, computed, nextTick, watch } from 'vue';\r\nimport VoiceStatus from './voice-status.vue';\r\nimport ExecutionStatus from './execution-status.vue';\r\nimport { injectStrict, AiChatbotXKey } from '../injection-key';\r\nimport { WakeWordDetectorStandalone, SpeechTranscriberStandalone } from 'web-voice-kit';\r\nimport { ensureMicrophonePermission, matchVoiceCommand } from '../lib/utils';\r\n\r\ninterface XSize {\r\n width: number;\r\n height: number;\r\n}\r\ninterface xDialogSize {\r\n width: number;\r\n height: number;\r\n}\r\n\r\nconst props = defineProps<{\r\n xLogo?: string;\r\n xSize?: XSize;\r\n xTitle?: string;\r\n xTheme?: 'light' | 'dark' | 'system';\r\n xDialogSize?: xDialogSize;\r\n wakeWords?: string[];\r\n modelPath?: string;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n (e: 'start-transcribing'): void;\r\n (e: 'stop-transcribing'): void;\r\n (e: 'wakeUp', isWake: boolean): void;\r\n}>();\r\n\r\nconst aiChatbotX = injectStrict(AiChatbotXKey);\r\n\r\nconst chatbotUrl = ref('');\r\nconst voiceStatus = ref<'wake' | 'listening' | 'standby'>('standby');\r\nconst wakeAnimating = ref(false);\r\nconst wakeResponses = ['在呢', '在的', '我在', '您好', '在呢,请说'];\r\nconst transcriptionText = ref<string>('');\r\nconst isTranscribing = ref(false);\r\nconst isProcessing = ref(false);\r\nconst visible = ref(false);\r\nconst isCollapsed = ref(false);\r\nconst fabRef = ref<HTMLElement | null>(null);\r\nconst positionReady = ref(false);\r\n\r\nlet detector: WakeWordDetectorStandalone | null = null;\r\nlet transcriber: SpeechTranscriberStandalone | null = null;\r\n\r\nconst isInitializing = ref(false);\r\nconst initError = ref<string>('');\r\n\r\n// 获取系统主题\r\nconst getSystemTheme = (): 'light' | 'dark' => {\r\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n};\r\nconst currentTheme = ref<'light' | 'dark'>(props.xTheme === 'system' ? getSystemTheme() : props.xTheme || 'light');\r\n\r\n// 切换主题\r\nconst cycleTheme = async () => {\r\n currentTheme.value = currentTheme.value === 'light' ? 'dark' : 'light';\r\n aiChatbotX.setTheme(currentTheme.value);\r\n};\r\n\r\n// 开启新对话\r\nconst startNewConversation = () => {\r\n aiChatbotX.startNewConversation();\r\n};\r\n\r\nconst themeTooltip = computed(() => (currentTheme.value === 'light' ? '切换到深色模式' : '切换到浅色模式'));\r\n\r\nconst voiceButtonTooltip = computed(() => {\r\n if (isInitializing.value) return '初始化中...';\r\n if (initError.value) return `错误: ${initError.value}`;\r\n\r\n switch (voiceStatus.value) {\r\n case 'standby':\r\n return '开启语音监听';\r\n case 'listening':\r\n return '监听中,等待唤醒词...';\r\n case 'wake':\r\n return '已唤醒!';\r\n default:\r\n return '语音监听';\r\n }\r\n});\r\n\r\nif (props.xTheme === 'system') {\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n const handleThemeChange = (e: MediaQueryListEvent) => {\r\n currentTheme.value = e.matches ? 'dark' : 'light';\r\n };\r\n mediaQuery.addEventListener('change', handleThemeChange);\r\n onBeforeUnmount(() => {\r\n mediaQuery.removeEventListener('change', handleThemeChange);\r\n });\r\n}\r\n\r\n// 初始化语音监听器\r\nconst initVoiceDetector = () => {\r\n if (detector || isInitializing.value) return;\r\n\r\n isInitializing.value = true;\r\n initError.value = '';\r\n\r\n if (!props.modelPath) {\r\n initError.value = '未提供语音模型文件';\r\n isInitializing.value = false;\r\n return;\r\n }\r\n\r\n try {\r\n detector = new WakeWordDetectorStandalone({\r\n modelPath: props.modelPath,\r\n sampleRate: 16000,\r\n usePartial: true,\r\n autoReset: {\r\n enabled: true,\r\n resetDelayMs: 5000,\r\n },\r\n });\r\n\r\n const wakeWords = props.wakeWords || ['你好', '您好'];\r\n detector.setWakeWords(wakeWords);\r\n\r\n detector.onWake(() => {\r\n console.log('[VoiceDetector] 检测到唤醒词');\r\n // 触发唤醒动画\r\n wakeAnimating.value = true;\r\n // 语音播报回应\r\n playWakeResponse();\r\n // 通知 web 端\r\n emit('wakeUp', true);\r\n aiChatbotX.weak();\r\n aiChatbotX.openDialog();\r\n // 动画结束后恢复\r\n setTimeout(() => {\r\n wakeAnimating.value = false;\r\n }, 1500);\r\n // 保持 listening 状态,继续后台唤醒监听\r\n voiceStatus.value = 'listening';\r\n });\r\n\r\n detector.onError((error: any) => {\r\n console.error('[VoiceDetector] 错误:', error);\r\n initError.value = error.message;\r\n voiceStatus.value = 'standby';\r\n isTranscribing.value = false;\r\n\r\n if (error.message.includes('permission')) {\r\n transcriptionText.value = '需要麦克风权限';\r\n } else if (error.message.includes('model')) {\r\n transcriptionText.value = '模型加载失败';\r\n } else {\r\n transcriptionText.value = '初始化失败';\r\n }\r\n\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n }, 3000);\r\n });\r\n\r\n console.log('[VoiceDetector] 初始化成功');\r\n } catch (error) {\r\n console.error('[VoiceDetector] 初始化失败:', error);\r\n initError.value = error instanceof Error ? error.message : '初始化失败';\r\n voiceStatus.value = 'standby';\r\n isTranscribing.value = false;\r\n } finally {\r\n isInitializing.value = false;\r\n }\r\n};\r\n\r\n// 语音播报唤醒回应(使用 Web Speech Synthesis API,无需音频文件)\r\nconst playWakeResponse = () => {\r\n try {\r\n if (typeof window === 'undefined' || !window.speechSynthesis) {\r\n console.warn('[TTS] SpeechSynthesis API 不可用');\r\n return;\r\n }\r\n const text = wakeResponses[Math.floor(Math.random() * wakeResponses.length)];\r\n const utterance = new SpeechSynthesisUtterance(text);\r\n utterance.lang = 'zh-CN';\r\n utterance.rate = 1.0;\r\n utterance.pitch = 0.8;\r\n utterance.volume = 0.9;\r\n // 优先选择中文男声\r\n const voices = window.speechSynthesis.getVoices();\r\n const maleVoice = voices.find((v) => v.lang.startsWith('zh') && /male|男/i.test(v.name));\r\n const zhVoice = maleVoice || voices.find((v) => v.lang.startsWith('zh'));\r\n if (zhVoice) {\r\n utterance.voice = zhVoice;\r\n }\r\n window.speechSynthesis.speak(utterance);\r\n } catch (error) {\r\n console.error('[TTS] 播报失败:', error);\r\n }\r\n};\r\n\r\n// 初始化转写器\r\nfunction initTranscriber() {\r\n if (transcriber) return;\r\n\r\n try {\r\n const { appId, apiKey, websocketUrl } = aiChatbotX.voiceConfig();\r\n if (!appId || !apiKey || !websocketUrl) {\r\n initError.value = '未配置语音配置';\r\n voiceStatus.value = 'standby';\r\n isTranscribing.value = false;\r\n return;\r\n }\r\n transcriber = new SpeechTranscriberStandalone({\r\n appId,\r\n apiKey,\r\n websocketUrl,\r\n autoStop: {\r\n enabled: true,\r\n silenceTimeoutMs: 3000,\r\n noSpeechTimeoutMs: 5000,\r\n maxDurationMs: 60000,\r\n },\r\n });\r\n\r\n transcriber.onResult((result) => {\r\n transcriptionText.value = result.transcript;\r\n });\r\n\r\n transcriber.onAutoStop(async () => {\r\n console.log('[Transcriber] Auto Stop');\r\n\r\n // 保存当前转写文本,用于后续处理\r\n const currentText = transcriptionText.value;\r\n\r\n // 停止转写\r\n await stopTranscribing();\r\n\r\n // 如果没有转写内容,直接返回后台监听\r\n if (!currentText || !currentText.trim()) {\r\n console.log('[Transcriber] No transcription text, returning to listening');\r\n transcriptionText.value = '';\r\n voiceStatus.value = 'listening';\r\n return;\r\n }\r\n\r\n // 进入处理中状态,显示优雅的等待动画\r\n isProcessing.value = true;\r\n transcriptionText.value = currentText; // 保持显示用户说的内容\r\n\r\n try {\r\n const commands = await aiChatbotX.hostCommads();\r\n const result = await aiChatbotX.recognition(currentText, commands);\r\n\r\n // 如果是命令类型,执行匹配的命令\r\n if (result?.data?.intent === 'command' && result?.data?.matchedCommands) {\r\n const matchedCommands = result.data.matchedCommands;\r\n\r\n for (const cmd of matchedCommands) {\r\n try {\r\n // 将参数对象转换为参数数组\r\n const args = cmd.parameters ? Object.values(cmd.parameters) : [];\r\n\r\n // 执行宿主命令\r\n const cmdResult = await aiChatbotX.executeCommand(cmd.name, args);\r\n console.log(`Command ${cmd.name} executed successfully:`, cmdResult);\r\n } catch (error) {\r\n console.error(`Failed to execute command ${cmd.name}:`, error);\r\n }\r\n }\r\n } else {\r\n aiChatbotX.appendMessage(currentText);\r\n toggleDialog(true);\r\n }\r\n } finally {\r\n // 处理完成,返回后台监听状态\r\n isProcessing.value = false;\r\n transcriptionText.value = '';\r\n voiceStatus.value = 'listening';\r\n }\r\n });\r\n\r\n transcriber.onError((error) => {\r\n console.error('[Transcriber] Error:', error);\r\n stopTranscribing();\r\n transcriptionText.value = '转写错误';\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n voiceStatus.value = 'listening';\r\n }, 2000);\r\n });\r\n\r\n console.log('[Transcriber] 初始化成功');\r\n } catch (error) {\r\n console.error('[Transcriber] 初始化失败:', error);\r\n voiceStatus.value = 'standby';\r\n initError.value = error instanceof Error ? error.message : '转写初始化失败';\r\n }\r\n}\r\n\r\nconst startTranscribing = async () => {\r\n if (!transcriber) {\r\n initTranscriber();\r\n if (!transcriber) return;\r\n }\r\n\r\n try {\r\n emit('start-transcribing');\r\n await transcriber.start();\r\n isTranscribing.value = true;\r\n transcriptionText.value = '';\r\n } catch (error) {\r\n console.error('[Transcriber] 启动失败:', error);\r\n transcriptionText.value = '转写启动失败';\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n }, 2000);\r\n }\r\n};\r\n\r\nconst stopTranscribing = async () => {\r\n if (transcriber && transcriber.isActive()) {\r\n try {\r\n await transcriber.stop();\r\n isTranscribing.value = false;\r\n emit('stop-transcribing');\r\n } catch (error) {\r\n console.error('[Transcriber] 停止失败:', error);\r\n }\r\n }\r\n};\r\n\r\nconst toggleVoiceMode = async (targetState?: boolean) => {\r\n const permission = await ensureMicrophonePermission();\r\n if (!permission) return;\r\n\r\n if (isInitializing.value) return;\r\n\r\n if (!detector) {\r\n await initVoiceDetector();\r\n if (!detector) return;\r\n }\r\n\r\n // 核心逻辑:如果传了参数,目标就是参数值;如果不传,目标就是当前状态的反值\r\n // 假设 \"listening\" 为开启状态,其余(如 \"standby\")为关闭状态\r\n const isCurrentlyListening = voiceStatus.value === 'listening';\r\n const shouldStart = targetState !== undefined ? targetState : !isCurrentlyListening;\r\n\r\n // 如果当前状态已经符合目标状态,直接返回(防止重复开启或关闭)\r\n if (shouldStart === isCurrentlyListening) return;\r\n\r\n try {\r\n if (shouldStart) {\r\n // 执行开启逻辑\r\n console.log('[VoiceDetector] 强制/自动启动监听...');\r\n await detector.start();\r\n voiceStatus.value = 'listening';\r\n transcriptionText.value = '';\r\n isTranscribing.value = false;\r\n } else {\r\n // 执行关闭逻辑\r\n console.log('[VoiceDetector] 强制/自动停止监听...');\r\n await detector.stop();\r\n stopTranscribing();\r\n voiceStatus.value = 'standby';\r\n transcriptionText.value = '';\r\n isTranscribing.value = false;\r\n }\r\n } catch (error) {\r\n console.error('[VoiceDetector] 操作失败:', error);\r\n voiceStatus.value = 'standby';\r\n transcriptionText.value = '操作失败';\r\n isTranscribing.value = false;\r\n\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n }, 2000);\r\n }\r\n};\r\n\r\nconst position = reactive({ x: 0, y: 0 });\r\nconst containerWidth = ref(props.xDialogSize?.width || 420);\r\nconst containerHeight = ref(props.xDialogSize?.height || 600);\r\nconst isFirstOpen = ref(true);\r\nconst FAB_SAFE_GAP = 24;\r\n\r\nconst validatePosition = (x: number, y: number, width: number, height: number) => {\r\n const margin = 20;\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n\r\n const maxX = viewportWidth - width - margin;\r\n const maxY = viewportHeight - height - margin;\r\n\r\n return {\r\n x: Math.max(margin, Math.min(x, maxX)),\r\n y: Math.max(margin, Math.min(y, maxY)),\r\n };\r\n};\r\n\r\nconst getOverlapArea = (\r\n rectA: { left: number; right: number; top: number; bottom: number },\r\n rectB: { left: number; right: number; top: number; bottom: number },\r\n) => {\r\n const overlapX = Math.max(0, Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left));\r\n const overlapY = Math.max(0, Math.min(rectA.bottom, rectB.bottom) - Math.max(rectA.top, rectB.top));\r\n return overlapX * overlapY;\r\n};\r\n\r\nconst keepDistanceFromFab = (x: number, y: number, width: number, height: number) => {\r\n if (!fabRef.value) return { x, y };\r\n\r\n const fabRect = fabRef.value.getBoundingClientRect();\r\n const safeFabRect = {\r\n left: fabRect.left - FAB_SAFE_GAP,\r\n right: fabRect.right + FAB_SAFE_GAP,\r\n top: fabRect.top - FAB_SAFE_GAP,\r\n bottom: fabRect.bottom + FAB_SAFE_GAP,\r\n };\r\n\r\n const candidates = [\r\n { x, y },\r\n { x: safeFabRect.left - width - FAB_SAFE_GAP, y },\r\n { x: safeFabRect.right + FAB_SAFE_GAP, y },\r\n { x, y: safeFabRect.top - height - FAB_SAFE_GAP },\r\n { x, y: safeFabRect.bottom + FAB_SAFE_GAP },\r\n ];\r\n\r\n let best = validatePosition(candidates[0].x, candidates[0].y, width, height);\r\n let bestOverlap = getOverlapArea(\r\n { left: best.x, right: best.x + width, top: best.y, bottom: best.y + height },\r\n safeFabRect,\r\n );\r\n\r\n for (let i = 1; i < candidates.length; i++) {\r\n const validated = validatePosition(candidates[i].x, candidates[i].y, width, height);\r\n const overlap = getOverlapArea(\r\n { left: validated.x, right: validated.x + width, top: validated.y, bottom: validated.y + height },\r\n safeFabRect,\r\n );\r\n\r\n if (overlap < bestOverlap) {\r\n best = validated;\r\n bestOverlap = overlap;\r\n if (overlap === 0) break;\r\n }\r\n }\r\n\r\n return best;\r\n};\r\n\r\nconst calculateInitialPosition = () => {\r\n if (!fabRef.value) return;\r\n\r\n const fabRect = fabRef.value.getBoundingClientRect();\r\n const dialogWidth = containerWidth.value;\r\n const dialogHeight = containerHeight.value;\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n const margin = 20; // 增加间距,确保不遮挡\r\n const minMargin = 20; // 最小边距\r\n\r\n let x = 0;\r\n let y = 0;\r\n\r\n // 优先尝试在 FAB 左侧定位\r\n const leftX = fabRect.left - dialogWidth - margin;\r\n\r\n if (leftX >= minMargin) {\r\n // 左侧有足够空间\r\n x = leftX;\r\n // Y 轴对齐 FAB 顶部,但确保不超出视口\r\n y = fabRect.top;\r\n\r\n // 如果对话框底部超出视口,向上调整\r\n if (y + dialogHeight > viewportHeight - minMargin) {\r\n y = viewportHeight - dialogHeight - minMargin;\r\n }\r\n // 确保顶部不超出\r\n if (y < minMargin) {\r\n y = minMargin;\r\n }\r\n } else {\r\n // 左侧空间不足,尝试右侧\r\n const rightX = fabRect.right + margin;\r\n\r\n if (rightX + dialogWidth <= viewportWidth - minMargin) {\r\n // 右侧有足够空间\r\n x = rightX;\r\n y = fabRect.top;\r\n\r\n // Y 轴调整\r\n if (y + dialogHeight > viewportHeight - minMargin) {\r\n y = viewportHeight - dialogHeight - minMargin;\r\n }\r\n if (y < minMargin) {\r\n y = minMargin;\r\n }\r\n } else {\r\n // 左右都不够,居中显示,并确保不遮挡 FAB\r\n x = (viewportWidth - dialogWidth) / 2;\r\n\r\n // 尝试在 FAB 上方\r\n const aboveY = fabRect.top - dialogHeight - margin;\r\n if (aboveY >= minMargin) {\r\n y = aboveY;\r\n } else {\r\n // 在 FAB 下方\r\n const belowY = fabRect.bottom + margin;\r\n if (belowY + dialogHeight <= viewportHeight - minMargin) {\r\n y = belowY;\r\n } else {\r\n // 垂直居中\r\n y = (viewportHeight - dialogHeight) / 2;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 最终验证位置\r\n const validated = validatePosition(x, y, dialogWidth, dialogHeight);\r\n const separated = keepDistanceFromFab(validated.x, validated.y, dialogWidth, dialogHeight);\r\n position.x = separated.x;\r\n position.y = separated.y;\r\n};\r\n\r\nconst toggleCollapse = async () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n\r\n nextTick(() => {\r\n const currentHeight = isCollapsed.value ? 60 : containerHeight.value;\r\n const validated = validatePosition(position.x, position.y, containerWidth.value, currentHeight);\r\n const separated = keepDistanceFromFab(validated.x, validated.y, containerWidth.value, currentHeight);\r\n position.x = separated.x;\r\n position.y = separated.y;\r\n });\r\n};\r\n\r\nconst drag = reactive({\r\n isDragging: false,\r\n startX: 0,\r\n startY: 0,\r\n offsetX: 0,\r\n offsetY: 0,\r\n});\r\n\r\nconst startDrag = (e: MouseEvent) => {\r\n drag.isDragging = true;\r\n drag.startX = e.clientX;\r\n drag.startY = e.clientY;\r\n drag.offsetX = position.x;\r\n drag.offsetY = position.y;\r\n document.addEventListener('mousemove', onDrag);\r\n document.addEventListener('mouseup', stopDrag);\r\n};\r\n\r\nconst onDrag = (e: MouseEvent) => {\r\n if (!drag.isDragging) return;\r\n\r\n const newX = drag.offsetX + (e.clientX - drag.startX);\r\n const newY = drag.offsetY + (e.clientY - drag.startY);\r\n\r\n const validated = validatePosition(newX, newY, containerWidth.value, isCollapsed.value ? 60 : containerHeight.value);\r\n\r\n position.x = validated.x;\r\n position.y = validated.y;\r\n};\r\n\r\nconst stopDrag = () => {\r\n drag.isDragging = false;\r\n document.removeEventListener('mousemove', onDrag);\r\n document.removeEventListener('mouseup', stopDrag);\r\n};\r\n\r\nconst toggleDialog = async (state: boolean) => {\r\n if (state) {\r\n visible.value = true;\r\n positionReady.value = false;\r\n emit('wakeUp', true);\r\n await nextTick();\r\n\r\n if (isFirstOpen.value) {\r\n calculateInitialPosition();\r\n isFirstOpen.value = false;\r\n } else {\r\n const validated = validatePosition(\r\n position.x,\r\n position.y,\r\n containerWidth.value,\r\n isCollapsed.value ? 60 : containerHeight.value,\r\n );\r\n const separated = keepDistanceFromFab(\r\n validated.x,\r\n validated.y,\r\n containerWidth.value,\r\n isCollapsed.value ? 60 : containerHeight.value,\r\n );\r\n position.x = separated.x;\r\n position.y = separated.y;\r\n }\r\n\r\n await nextTick();\r\n positionReady.value = true;\r\n } else {\r\n positionReady.value = false;\r\n visible.value = false;\r\n isCollapsed.value = false;\r\n emit('wakeUp', false);\r\n }\r\n};\r\n\r\nconst handleIframeLoad = (event: Event) => {\r\n aiChatbotX.setIframeElement(event.target as HTMLIFrameElement);\r\n aiChatbotX.setTheme('dark');\r\n};\r\n\r\nwatch(\r\n () => [aiChatbotX.chatbotUrl()],\r\n ([url]) => {\r\n console.log('[AiChatbotX] 初始化', url);\r\n if (url) {\r\n chatbotUrl.value = `${url}/app/${aiChatbotX.appId()}?token=${aiChatbotX.appToken()}`;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\nonBeforeUnmount(async () => {\r\n if (detector) {\r\n try {\r\n if (detector.isActive()) {\r\n await detector.stop();\r\n }\r\n detector = null;\r\n } catch (error) {\r\n console.error('[VoiceDetector] 清理失败:', error);\r\n }\r\n }\r\n if (transcriber) {\r\n try {\r\n if (transcriber.isActive()) {\r\n await transcriber.stop();\r\n }\r\n transcriber = null;\r\n } catch (error) {\r\n console.error('[Transcriber] 清理失败:', error);\r\n }\r\n }\r\n});\r\n\r\naiChatbotX?.registerVoiceMethods({\r\n start: () => toggleVoiceMode(true),\r\n stop: () => toggleVoiceMode(false),\r\n openDialog: () => toggleDialog(true),\r\n closeDialog: () => toggleDialog(false),\r\n toggleCollapse: () => toggleCollapse(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.sime-x {\r\n --bg-primary: #ffffff;\r\n --bg-secondary: #f8fafc;\r\n --bg-header: #0f172a;\r\n --text-primary: #0f172a;\r\n --text-secondary: #64748b;\r\n --text-header: #ffffff;\r\n --border-color: #e2e8f0;\r\n --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);\r\n --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.15);\r\n --accent-color: #3b82f6;\r\n --hover-bg: rgba(0, 0, 0, 0.05);\r\n\r\n &[data-theme='dark'] {\r\n --bg-primary: #1e293b;\r\n --bg-secondary: #0f172a;\r\n --bg-header: #0f172a;\r\n --text-primary: #f1f5f9;\r\n --text-secondary: #94a3b8;\r\n --text-header: #f1f5f9;\r\n --border-color: #334155;\r\n --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);\r\n --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);\r\n --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);\r\n --accent-color: #60a5fa;\r\n --hover-bg: rgba(255, 255, 255, 0.1);\r\n }\r\n}\r\n\r\n.is-hidden {\r\n height: 0;\r\n opacity: 0 !important;\r\n pointer-events: none !important;\r\n visibility: hidden !important;\r\n}\r\n\r\n.assistant-fab {\r\n position: relative;\r\n cursor: pointer;\r\n overflow: visible;\r\n filter: drop-shadow(var(--shadow-md));\r\n opacity: 1;\r\n pointer-events: auto;\r\n transition: all 0.3s ease;\r\n\r\n &:hover {\r\n transform: scale(1.05);\r\n }\r\n\r\n &:active {\r\n transform: scale(0.95);\r\n }\r\n\r\n .voice-status {\r\n position: absolute;\r\n right: 100%;\r\n margin-right: 20px;\r\n }\r\n\r\n img {\r\n display: block;\r\n position: relative;\r\n object-fit: contain;\r\n }\r\n\r\n .fab-pulse {\r\n position: absolute;\r\n inset: -4px;\r\n border-radius: 50%;\r\n border: 2px solid var(--accent-color);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n@keyframes pulse {\r\n 0%,\r\n 100% {\r\n opacity: 0;\r\n transform: scale(1);\r\n }\r\n 50% {\r\n opacity: 0.5;\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n.x-dialog-container {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n transform: translate(var(--dialog-x), var(--dialog-y));\r\n border-radius: 16px;\r\n display: flex;\r\n flex-direction: column;\r\n cursor: grab;\r\n overflow: hidden;\r\n z-index: 1100;\r\n opacity: 0;\r\n pointer-events: none;\r\n\r\n &.position-ready {\r\n opacity: 1;\r\n pointer-events: auto;\r\n }\r\n\r\n &:active {\r\n cursor: grabbing;\r\n }\r\n\r\n &.collapsed {\r\n .x-dialog-header {\r\n border-radius: 16px;\r\n }\r\n }\r\n\r\n .x-dialog-header {\r\n position: relative;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n background: var(--bg-header);\r\n padding: 12px 16px;\r\n cursor: move;\r\n user-select: none;\r\n border-bottom: 1px solid var(--border-color);\r\n\r\n .header-left {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n\r\n .logo-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 36px;\r\n height: 36px;\r\n transition: transform 0.2s ease;\r\n\r\n .logo {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: contain;\r\n }\r\n }\r\n\r\n .title {\r\n font-weight: 600;\r\n font-size: 15px;\r\n color: var(--text-header);\r\n letter-spacing: -0.01em;\r\n }\r\n }\r\n\r\n .actions {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n\r\n .action-btn {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 32px;\r\n height: 32px;\r\n border: none;\r\n background: transparent;\r\n cursor: pointer;\r\n color: var(--text-secondary);\r\n transition: all 0.2s ease;\r\n border-radius: 8px;\r\n\r\n &:hover {\r\n color: var(--text-header);\r\n background: var(--hover-bg);\r\n transform: translateY(-1px);\r\n }\r\n\r\n &:active {\r\n transform: translateY(0);\r\n }\r\n\r\n svg {\r\n transition: transform 0.2s ease;\r\n }\r\n\r\n &.collapse-btn:hover svg {\r\n transform: scale(1.1);\r\n }\r\n }\r\n }\r\n }\r\n\r\n .voice-container {\r\n width: 100%;\r\n opacity: 1;\r\n pointer-events: auto;\r\n }\r\n\r\n .x-dialog-content {\r\n flex: 1;\r\n display: flex;\r\n overflow: hidden;\r\n background: var(--bg-secondary);\r\n opacity: 1;\r\n pointer-events: auto;\r\n }\r\n\r\n .x-iframe {\r\n flex: 1;\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n }\r\n\r\n .resize-handle {\r\n position: absolute;\r\n bottom: 0;\r\n right: 0;\r\n width: 40px;\r\n height: 40px;\r\n cursor: nwse-resize;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: var(--text-secondary);\r\n transition: all 0.2s ease;\r\n background: linear-gradient(135deg, transparent 50%, var(--bg-primary) 50%);\r\n border-bottom-right-radius: 16px;\r\n z-index: 10;\r\n\r\n &:hover {\r\n color: var(--accent-color);\r\n background: linear-gradient(135deg, transparent 50%, var(--hover-bg) 50%);\r\n }\r\n\r\n svg {\r\n width: 16px;\r\n height: 16px;\r\n transform: rotate(0deg);\r\n transition: transform 0.2s ease;\r\n }\r\n\r\n &:hover svg {\r\n transform: scale(1.2);\r\n }\r\n }\r\n}\r\n/* 语音按钮状态样式 */\r\n.action-btn.theme-btn {\r\n position: relative;\r\n transition: all 0.3s ease;\r\n}\r\n\r\n.action-btn.theme-btn.active {\r\n background: rgba(59, 130, 246, 0.1);\r\n color: #3b82f6;\r\n}\r\n\r\n.action-btn.theme-btn.listening {\r\n animation: pulse-listening 2s ease-in-out infinite;\r\n}\r\n\r\n.action-btn.theme-btn.woke {\r\n background: rgba(34, 197, 94, 0.2);\r\n color: #22c55e;\r\n animation: pulse-wake 0.6s ease-in-out;\r\n}\r\n\r\n@keyframes pulse-listening {\r\n 0%,\r\n 100% {\r\n box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);\r\n }\r\n 50% {\r\n box-shadow: 0 0 0 8px rgba(59, 130, 246, 0);\r\n }\r\n}\r\n\r\n@keyframes pulse-wake {\r\n 0%,\r\n 100% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n/* 语音指示器 */\r\n.voice-indicator {\r\n position: absolute;\r\n top: 4px;\r\n right: 4px;\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: #3b82f6;\r\n}\r\n\r\n.action-btn.theme-btn.listening .voice-indicator {\r\n animation: blink 1.5s ease-in-out infinite;\r\n}\r\n\r\n.action-btn.theme-btn.woke .voice-indicator {\r\n background: #22c55e;\r\n animation: none;\r\n}\r\n\r\n@keyframes blink {\r\n 0%,\r\n 100% {\r\n opacity: 1;\r\n }\r\n 50% {\r\n opacity: 0.3;\r\n }\r\n}\r\n\r\n/* 麦克风唤醒动画 */\r\n.listening-badge.wake-active {\r\n background-color: rgba(34, 197, 94, 0.85);\r\n animation: wake-badge-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\r\n\r\n .listening-icon {\r\n animation: wake-icon-flash 1.5s ease-in-out;\r\n }\r\n\r\n &::after {\r\n content: '';\r\n position: absolute;\r\n inset: -3px;\r\n border-radius: 50%;\r\n border: 2px solid #22c55e;\r\n animation: wake-mic-ring 1.2s ease-out forwards;\r\n pointer-events: none;\r\n }\r\n}\r\n\r\n@keyframes wake-badge-pop {\r\n 0% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.4);\r\n }\r\n 100% {\r\n transform: scale(1);\r\n }\r\n}\r\n\r\n@keyframes wake-icon-flash {\r\n 0%,\r\n 100% {\r\n color: #ffffff;\r\n }\r\n 25% {\r\n color: #bbf7d0;\r\n }\r\n 50% {\r\n color: #ffffff;\r\n }\r\n 75% {\r\n color: #bbf7d0;\r\n }\r\n}\r\n\r\n@keyframes wake-mic-ring {\r\n 0% {\r\n transform: scale(1);\r\n opacity: 0.8;\r\n }\r\n 100% {\r\n transform: scale(2.2);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n/* FAB 头像容器 */\r\n.fab-avatar-wrapper {\r\n position: relative;\r\n display: flex; /* 改用 flex 可以消除图片底部的行高间隙 */\r\n align-items: center;\r\n justify-content: center;\r\n width: fit-content; /* 宽度随内容自适应 */\r\n margin: 0 auto;\r\n}\r\n\r\n/* 2. 修正图片样式 */\r\n.fab-avatar-wrapper img {\r\n display: block;\r\n max-width: 100%;\r\n height: auto;\r\n /* 移除原本 style 里的 width/height 可能造成的拉伸,保持比例 */\r\n}\r\n\r\n/* 3. 优化徽章定位 */\r\n.listening-badge {\r\n position: absolute;\r\n /* 强制定位到容器边缘 */\r\n top: 0;\r\n right: 0;\r\n /* 使用 transform 偏移,让徽章中心点落在图片的右上角顶点上 */\r\n transform: translate(30%, -30%);\r\n\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background-color: rgba(0, 0, 0, 0.75); /* 稍微加深一点 */\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 10;\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\r\n\r\n /* 继承你原有的动画 */\r\n animation: badge-float 5s ease-in-out infinite;\r\n pointer-events: none; /* 防止遮挡头像点击 */\r\n}\r\n\r\n/* 4. 调整声波扩散的基准 */\r\n.wave {\r\n position: absolute;\r\n /* 确保声波从徽章中心扩散,而不是从容器左上角 */\r\n inset: -2px;\r\n border-radius: 50%;\r\n border: 2px solid rgba(59, 130, 246, 0.6); /* 声波颜色建议跟主题色一致 */\r\n animation: wave-expand 3s ease-out infinite;\r\n}\r\n\r\n/* 优化后的监听状态徽章 */\r\n.listening-badge {\r\n position: absolute;\r\n top: -8px;\r\n right: -8px;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background-color: rgba(0, 0, 0, 0.651);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 10;\r\n animation: badge-float 5s ease-in-out infinite;\r\n}\r\n\r\n/* 徽章浮动动画 */\r\n@keyframes badge-float {\r\n 0%,\r\n 100% {\r\n transform: translateY(0) scale(1);\r\n }\r\n 50% {\r\n transform: translateY(-2px) scale(1.05);\r\n }\r\n}\r\n\r\n/* 声波容器 */\r\n.listening-waves {\r\n position: absolute;\r\n inset: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n/* 声波动画 */\r\n.wave {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n border-radius: 50%;\r\n border: 2px solid rgba(255, 255, 255, 0.6);\r\n animation: wave-expand 3s ease-out infinite;\r\n}\r\n\r\n.wave-1 {\r\n animation-delay: 0s;\r\n}\r\n\r\n.wave-2 {\r\n animation-delay: 0.6s;\r\n}\r\n\r\n.wave-3 {\r\n animation-delay: 1.2s;\r\n}\r\n\r\n@keyframes wave-expand {\r\n 0% {\r\n transform: scale(0.8);\r\n opacity: 0.8;\r\n }\r\n 100% {\r\n transform: scale(1.2);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n/* 麦克风图标 */\r\n.listening-icon {\r\n position: relative;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: #ffffff;\r\n z-index: 1;\r\n animation: icon-pulse 2.5s ease-in-out infinite;\r\n}\r\n\r\n@keyframes icon-pulse {\r\n 0%,\r\n 100% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n/* 徽章淡入淡出动画 */\r\n.indicator-fade-enter-active {\r\n transition: all 1s cubic-bezier(0.34, 1.56, 0.64, 1);\r\n}\r\n\r\n.indicator-fade-leave-active {\r\n transition: all 1s ease;\r\n}\r\n\r\n.indicator-fade-enter-from {\r\n opacity: 0;\r\n transform: scale(0.3) rotate(-180deg);\r\n}\r\n\r\n.indicator-fade-leave-to {\r\n opacity: 0;\r\n transform: scale(0.5) rotate(180deg);\r\n}\r\n\r\n/* FAB 脉冲效果 */\r\n.fab-pulse {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n border-radius: 50%;\r\n pointer-events: none;\r\n}\r\n\r\n.fab-pulse.active {\r\n animation: fab-pulse 2s ease-in-out infinite;\r\n}\r\n\r\n@keyframes fab-pulse {\r\n 0%,\r\n 100% {\r\n box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);\r\n }\r\n 50% {\r\n box-shadow: 0 0 0 20px rgba(59, 130, 246, 0);\r\n }\r\n}\r\n\r\n/* 深色模式适配 */\r\n[data-theme='dark'] .action-btn.theme-btn.active {\r\n background: rgba(59, 130, 246, 0.2);\r\n}\r\n\r\n[data-theme='dark'] .action-btn.theme-btn.woke {\r\n background: rgba(34, 197, 94, 0.3);\r\n}\r\n</style>\r\n"],"names":["clientCommandKey","_renderSlot","_createBlock","_Transition","_createElementBlock","_normalizeClass","_createElementVNode","_hoisted_1","_hoisted_2","_hoisted_3","_toDisplayString","_createVNode","_hoisted_4","_hoisted_5","_openBlock","_normalizeStyle"],"mappings":";;;;AAIO,MAAM,aAAA,GAAiD,OAAO,QAAQ;AAKtE,SAAS,YAAA,CAAgB,GAAA,EAAsB,YAAA,EAA8B,qBAAA,EAAoC;AACtH,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,MAAA,GAAS,OAAO,GAAG,CAAA;AAAA,EACrB,CAAA,MAAA,IACS,0BAA0B,IAAA,EAAM;AACvC,IAAA,MAAA,GAAS,MAAA,CAAO,GAAA,EAAK,YAAA,EAA+B,IAAI,CAAA;AAAA,EAC1D,CAAA,MACK;AACH,IAAA,MAAA,GAAS,MAAA,CAAO,GAAA,EAAK,YAAA,EAAmB,KAAK,CAAA;AAAA,EAC/C;AAEA,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,GAAA,CAAI,WAAW,CAAA,CAAE,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,MAAA;AACT;;ACxBO,IAAK,gBAAA,qBAAAA,iBAAAA,KAAL;AACL,EAAAA,kBAAA,WAAA,CAAA,GAAY,oBAAA;AACZ,EAAAA,kBAAA,gBAAA,CAAA,GAAiB,yBAAA;AACjB,EAAAA,kBAAA,MAAA,CAAA,GAAO,gBAAA;AACP,EAAAA,kBAAA,YAAA,CAAA,GAAa,sBAAA;AACb,EAAAA,kBAAA,gBAAA,CAAA,GAAiB,0BAAA;AACjB,EAAAA,kBAAA,wBAAA,CAAA,GAAyB,gCAAA;AACzB,EAAAA,kBAAA,aAAA,CAAA,GAAc,uBAAA;AAPJ,EAAA,OAAAA,iBAAAA;AAAA,CAAA,EAAA,gBAAA,IAAA,EAAA;;;;;;;;;;;;;;ACQZ,IAAA,MAAM,KAAA,GAAQ,OAAA;AAiBd,IAAA,MAAM,UAAA,GAAa,UAAA,CAAuB,IAAI,UAAA,EAAY,CAAA;AAE1D,IAAA,MAAM,iBAAA,GAAoB,WAAgC,YAAY;AAAA,IAAC,CAAC,CAAA;AACxE,IAAA,MAAM,gBAAA,GAAmB,WAAgC,YAAY;AAAA,IAAC,CAAC,CAAA;AACvE,IAAA,MAAM,iBAAA,GAAoB,WAAgC,YAAY;AAAA,IAAC,CAAC,CAAA;AACxE,IAAA,MAAM,aAAA,GAAgB,WAAgC,YAAY;AAAA,IAAC,CAAC,CAAA;AACpE,IAAA,MAAM,cAAA,GAAiB,WAAgC,YAAY;AAAA,IAAC,CAAC,CAAA;AAErE,IAAA,OAAA,CAAQ,aAAA,EAAe;AAAA,MACrB,UAAA,EAAY,MAAM,KAAA,CAAM,UAAA;AAAA,MACxB,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA;AAAA,MACnB,QAAA,EAAU,MAAM,KAAA,CAAM,QAAA;AAAA,MACtB,WAAA,EAAa,MAAM,KAAA,CAAM,WAAA;AAAA,MACzB,cAAA,EAAgB,MAAM,iBAAA,CAAkB,KAAA,EAAM;AAAA,MAC9C,aAAA,EAAe,MAAM,gBAAA,CAAiB,KAAA,EAAM;AAAA,MAC5C,cAAA,EAAgB,MAAM,iBAAA,CAAkB,KAAA,EAAM;AAAA,MAC9C,UAAA,EAAY,MAAM,aAAA,CAAc,KAAA,EAAM;AAAA,MACtC,WAAA,EAAa,MAAM,cAAA,CAAe,KAAA,EAAM;AAAA,MACxC,oBAAA,EAAsB,CAAC,OAAA,KAMjB;AACJ,QAAA,iBAAA,CAAkB,QAAQ,OAAA,CAAQ,KAAA;AAClC,QAAA,gBAAA,CAAiB,QAAQ,OAAA,CAAQ,IAAA;AACjC,QAAA,iBAAA,CAAkB,QAAQ,OAAA,CAAQ,cAAA;AAClC,QAAA,aAAA,CAAc,QAAQ,OAAA,CAAQ,UAAA;AAC9B,QAAA,cAAA,CAAe,QAAQ,OAAA,CAAQ,WAAA;AAAA,MACjC,CAAA;AAAA,MACA,aAAA,EAAe,MAAM,UAAA,CAAW,KAAA,CAAM,cAAA,EAAe;AAAA,MACrD,WAAA,EAAa,MAAM,UAAA,CAAW,KAAA,CAAM,YAAA,EAAa;AAAA,MACjD,eAAA,EAAiB,CAAC,GAAA,KAA2B;AAC3C,QAAA,UAAA,CAAW,KAAA,CAAM,gBAAgB,GAAG,CAAA;AAAA,MACtC,CAAA;AAAA,MACA,iBAAA,EAAmB,CAAC,IAAA,KAAS;AAC3B,QAAA,UAAA,CAAW,KAAA,CAAM,kBAAkB,IAAI,CAAA;AAAA,MACzC,CAAA;AAAA,MACA,MAAM,cAAc,OAAA,EAAS;AAC3B,QAAA,MAAM,WAAW,KAAA,CAAM,oBAAA,CAAqB,iBAAiB,cAAA,EAAgB,CAAC,OAAO,CAAC,CAAA;AAAA,MACxF,CAAA;AAAA,MACA,MAAM,SAAS,KAAA,EAAO;AACpB,QAAA,MAAM,WAAW,KAAA,CAAM,oBAAA,CAAqB,iBAAiB,SAAA,EAAW,CAAC,KAAK,CAAC,CAAA;AAAA,MACjF,CAAA;AAAA,MACA,MAAM,IAAA,GAAO;AACX,QAAA,MAAM,UAAA,CAAW,KAAA,CAAM,oBAAA,CAAqB,gBAAA,CAAiB,IAAI,CAAA;AAAA,MACnE,CAAA;AAAA,MACA,MAAM,oBAAA,GAAuB;AAC3B,QAAA,MAAM,UAAA,CAAW,KAAA,CAAM,oBAAA,CAAqB,gBAAA,CAAiB,sBAAsB,CAAA;AAAA,MACrF,CAAA;AAAA,MACA,iBAAiB,MAAA,EAAQ;AACvB,QAAA,UAAA,CAAW,KAAA,CAAM,UAAU,MAAM,CAAA;AAAA,MACnC,CAAA;AAAA,MACA,MAAM,WAAA,CAAY,OAAA,EAAS,QAAA,EAAU;AACnC,QAAA,OAAO,MAAM,WAAW,KAAA,CAAM,oBAAA,CAAqB,iBAAiB,WAAA,EAAa,CAAC,OAAA,EAAS,QAAQ,CAAC,CAAA;AAAA,MACtG,CAAA;AAAA,MACA,MAAM,cAAA,CAAe,WAAA,EAAa,IAAA,GAAO,EAAC,EAAG;AAC3C,QAAA,OAAO,MAAM,UAAA,CAAW,KAAA,CAAM,cAAA,CAAe,aAAa,IAAI,CAAA;AAAA,MAChE;AAAA,KACD,CAAA;;aAtFCC,UAAA,CAAa,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;AC6Df,IAAA,MAAM,KAAA,GAAQ,OAAA;AAOd,IAAA,MAAM,WAAA,GAAc,SAAS,MAAM;AACjC,MAAA,IAAI,KAAA,CAAM,gBAAgB,OAAO,mBAAA;AACjC,MAAA,IAAI,KAAA,CAAM,MAAA,KAAW,MAAA,EAAQ,OAAO,WAAA;AACpC,MAAA,OAAO,cAAA;AAAA,IACT,CAAC,CAAA;AAGD,IAAA,MAAM,WAAA,GAAc,SAAS,MAAM;AACjC,MAAA,IAAI,KAAA,CAAM,gBAAgB,OAAO,aAAA;AACjC,MAAA,IAAI,KAAA,CAAM,MAAA,KAAW,MAAA,EAAQ,OAAO,gBAAA;AACpC,MAAA,OAAO,SAAA;AAAA,IACT,CAAC,CAAA;;0BA/ECC,WAAA,CAsDaC,YAAA,EAtDD,IAAA,EAAK,eAAa,EAAA;AAAA,yBAE5B,MAmDM;AAAA,UAnDK,OAAA,CAAA,qBAAqB,OAAA,CAAA,+BAAhCC,mBAmDM,KAAA,EAAA;AAAA;YAnD0C,OAAKC,cAAA,CAAA,CAAC,sBAAA,EAA+B,WAAA,CAAA,KAAW,CAAA;AAAA;sCAE9FC,kBAAA,CA8BM,KAAA,EAAA,EA9BD,KAAA,EAAM,qBAAA,EAAqB,EAAA;AAAA,cAE9BA,kBAAA,CAAgC,KAAA,EAAA,EAA3B,KAAA,EAAM,gBAAc,CAAA;AAAA,cAGzBA,kBAAA,CAIM,KAAA,EAAA,EAJD,KAAA,EAAM,gBAAc,EAAA;AAAA,gBACvBA,kBAAA,CAAkC,KAAA,EAAA,EAA7B,KAAA,EAAM,kBAAgB,CAAA;AAAA,gBAC3BA,kBAAA,CAAkC,KAAA,EAAA,EAA7B,KAAA,EAAM,kBAAgB,CAAA;AAAA,gBAC3BA,kBAAA,CAAkC,KAAA,EAAA,EAA7B,KAAA,EAAM,kBAAgB;AAAA;cAI7BA,kBAAA,CAiBM,KAAA,EAAA,EAjBD,KAAA,EAAM,aAAW,EAAA;AAAA,gBAEpBA,mBAcM,KAAA,EAAA;AAAA,kBAbJ,KAAA,EAAM,UAAA;AAAA,kBACN,OAAA,EAAQ,WAAA;AAAA,kBACR,IAAA,EAAK,MAAA;AAAA,kBACL,MAAA,EAAO,cAAA;AAAA,kBACP,cAAA,EAAa,GAAA;AAAA,kBACb,gBAAA,EAAe,OAAA;AAAA,kBACf,iBAAA,EAAgB;AAAA;kBAGhBA,mBAAqE,MAAA,EAAA;AAAA,oBAA/D,CAAA,EAAE,GAAA;AAAA,oBAAI,CAAA,EAAE,GAAA;AAAA,oBAAI,KAAA,EAAM,GAAA;AAAA,oBAAI,MAAA,EAAO,IAAA;AAAA,oBAAK,EAAA,EAAG,GAAA;AAAA,oBAAI,KAAA,EAAM;AAAA;kBAErDA,mBAAwF,MAAA,EAAA;AAAA,oBAAlF,CAAA,EAAE,2DAAA;AAAA,oBAA4D,KAAA,EAAM;AAAA;kBAC1EA,mBAA+C,MAAA,EAAA;AAAA,oBAAzC,CAAA,EAAE,mBAAA;AAAA,oBAAoB,KAAA,EAAM;AAAA;;;;YAMxCA,kBAAA,CAeM,OAfNC,YAAA,EAeM;AAAA,cAbJD,kBAAA,CAEM,OAFNE,YAAA,EAEM;AAAA,gBADJF,mBAAkD,MAAA,EAAlDG,YAAA,EAAkDC,gBAArB,WAAA,CAAA,KAAW,GAAA,CAAA;AAAA;cAI1CJ,mBAOM,KAAA,EAAA;AAAA,gBAPD,KAAA,EAAKD,cAAA,CAAA,CAAC,aAAA,EAAa,EAAA,UAAA,EAAA,CAAA,CAAyB,OAAA,CAAA,iBAAA,EAAiB,CAAA;AAAA;gBAChEM,YAKaR,UAAA,EAAA;AAAA,kBALD,IAAA,EAAK,YAAA;AAAA,kBAAa,IAAA,EAAK;AAAA;mCACjC,MAEI;AAAA,oBAFK,OAAA,CAAA,iBAAA,iBAATC,kBAAA,CAEI,KAFJQ,YAAA,EAEIF,eAAA,CADC,OAAA,CAAA,iBAAiB,CAAA,EAAA,CAAA,KAER,OAAA,CAAA,MAAA,KAAM,MAAA,iBAApBN,kBAAA,CAA0E,GAAA,EAA1ES,YAAA,EAA0D,cAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BCjDhFX,WAAA,CAWaC,YAAA,EAXD,IAAA,EAAK,eAAa,EAAA;AAAA,yBAC5B,MASM;AAAA,UATK,QAAA,OAAA,IAAXW,SAAA,EAAA,EAAAV,kBAAA,CASM,OATNG,YAAA,EASM;AAAA,YAPJD,kBAAA,CAAkD,QAAlDE,YAAA,EAAkDE,eAAA,CAAvB,QAAA,IAAA,IAAI,KAAA,GAAA,CAAA,CAAA;AAAA,sCAE/BJ,kBAAA,CAIM,KAAA,EAAA,EAJD,KAAA,EAAM,cAAA,EAAc,EAAA;AAAA,cACvBA,kBAAA,CAAyB,MAAA,EAAA,EAAnB,KAAA,EAAM,OAAK,CAAA;AAAA,cACjBA,kBAAA,CAAyB,MAAA,EAAA,EAAnB,KAAA,EAAM,OAAK,CAAA;AAAA,cACjBA,kBAAA,CAAyB,MAAA,EAAA,EAAnB,KAAA,EAAM,OAAK;AAAA;;;;;;;;;;;ACPlB,MAAM,6BAA6B,YAAY;AAEpD,EAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,OAAO,WAAW,WAAA,EAAa;AACrE,IAAA,OAAA,CAAQ,IAAI,cAAc,CAAA;AAC1B,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,IAAI,CAAC,SAAA,CAAU,YAAA,EAAc,gBAAgB,CAAC,SAAA,CAAU,cAAc,gBAAA,EAAkB;AACtF,IAAA,OAAA,CAAQ,IAAI,cAAc,CAAA;AAC1B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI;AAEF,IAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,YAAA,CAAa,gBAAA,EAAiB;AAC9D,IAAA,MAAM,oBAAoB,OAAA,CAAQ,MAAA,CAAO,CAAC,MAAA,KAAW,MAAA,CAAO,SAAS,YAAY,CAAA;AAEjF,IAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,EAAG;AAClC,MAAA,OAAA,CAAQ,IAAI,sBAAsB,CAAA;AAClC,MAAA,OAAO,KAAA;AAAA,IACT;AAGA,IAAA,IAAI,aAAA,IAAiB,SAAA,IAAa,SAAA,CAAU,WAAA,EAAa,KAAA,EAAO;AAC9D,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,WAAA,CAAY,MAAM,EAAE,IAAA,EAAM,cAAgC,CAAA;AAEzF,QAAA,IAAI,MAAA,CAAO,UAAU,QAAA,EAAU;AAC7B,UAAA,OAAA,CAAQ,IAAI,sBAAsB,CAAA;AAClC,UAAA,OAAO,KAAA;AAAA,QACT;AAAA,MACF,SAAS,CAAA,EAAG;AAEV,QAAA,OAAA,CAAQ,IAAA,CAAK,mCAAmC,CAAC,CAAA;AAAA,MACnD;AAAA,IACF;AAGA,IAAA,IAAI,MAAA,GAA6B,IAAA;AACjC,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,MAAM,SAAA,CAAU,YAAA,CAAa,YAAA,CAAa;AAAA,QACjD,KAAA,EAAO;AAAA,UACL,gBAAA,EAAkB,IAAA;AAAA,UAClB,gBAAA,EAAkB,IAAA;AAAA,UAClB,eAAA,EAAiB;AAAA;AACnB,OACD,CAAA;AAGD,MAAA,MAAM,WAAA,GAAc,OAAO,cAAA,EAAe;AAC1C,MAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,QAAA,OAAA,CAAQ,IAAI,cAAc,CAAA;AAC1B,QAAA,OAAO,KAAA;AAAA,MACT;AAGA,MAAA,MAAM,WAAA,GAAc,YAAY,CAAC,CAAA;AACjC,MAAA,IAAI,CAAC,WAAA,CAAY,OAAA,IAAW,WAAA,CAAY,eAAe,MAAA,EAAQ;AAC7D,QAAA,OAAA,CAAQ,IAAI,mBAAmB,CAAA;AAC/B,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,SAAE;AAEA,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,MAAA,CAAO,WAAU,CAAE,OAAA,CAAQ,CAAC,KAAA,KAAU,KAAA,CAAM,MAAM,CAAA;AAAA,MACpD;AAAA,IACF;AAAA,EACF,SAAS,KAAA,EAAY;AACnB,IAAA,OAAA,CAAQ,KAAA,CAAM,sCAAsC,KAAK,CAAA;AAGzD,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,eAAA,IAAmB,KAAA,CAAM,SAAS,sBAAA,EAAwB;AAC3E,MAAA,OAAA,CAAQ,IAAI,sBAAsB,CAAA;AAAA,IACpC,WAAW,KAAA,CAAM,IAAA,KAAS,iBAAA,IAAqB,KAAA,CAAM,SAAS,uBAAA,EAAyB;AACrF,MAAA,OAAA,CAAQ,IAAI,wBAAwB,CAAA;AAAA,IACtC,WAAW,KAAA,CAAM,IAAA,KAAS,kBAAA,IAAsB,KAAA,CAAM,SAAS,iBAAA,EAAmB;AAChF,MAAA,OAAA,CAAQ,IAAI,kBAAkB,CAAA;AAAA,IAChC,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,IAAI,wBAAwB,CAAA;AAAA,IACtC;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AACF,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;AC2cA,MAAM,YAAA,GAAe,EAAA;;;;;;;;;;;;;;AA9WrB,IAAA,MAAM,KAAA,GAAQ,OAAA;AAUd,IAAA,MAAM,IAAA,GAAO,MAAA;AAMb,IAAA,MAAM,UAAA,GAAa,aAAa,aAAa,CAAA;AAE7C,IAAA,MAAM,UAAA,GAAa,IAAI,EAAE,CAAA;AACzB,IAAA,MAAM,WAAA,GAAc,IAAsC,SAAS,CAAA;AACnE,IAAA,MAAM,aAAA,GAAgB,IAAI,KAAK,CAAA;AAC/B,IAAA,MAAM,gBAAgB,CAAC,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,MAAM,OAAO,CAAA;AACtD,IAAA,MAAM,iBAAA,GAAoB,IAAY,EAAE,CAAA;AACxC,IAAA,MAAM,cAAA,GAAiB,IAAI,KAAK,CAAA;AAChC,IAAA,MAAM,YAAA,GAAe,IAAI,KAAK,CAAA;AAC9B,IAAA,MAAM,OAAA,GAAU,IAAI,KAAK,CAAA;AACzB,IAAA,MAAM,WAAA,GAAc,IAAI,KAAK,CAAA;AAC7B,IAAA,MAAM,MAAA,GAAS,IAAwB,IAAI,CAAA;AAC3C,IAAA,MAAM,aAAA,GAAgB,IAAI,KAAK,CAAA;AAE/B,IAAA,IAAI,QAAA,GAA8C,IAAA;AAGlD,IAAA,MAAM,cAAA,GAAiB,IAAI,KAAK,CAAA;AAChC,IAAA,MAAM,SAAA,GAAY,IAAY,EAAE,CAAA;AAGhC,IAAA,MAAM,iBAAiB,MAAwB;AAC7C,MAAA,OAAO,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,CAAE,UAAU,MAAA,GAAS,OAAA;AAAA,IAC9E,CAAA;AACA,IAAA,MAAM,YAAA,GAAe,IAAsB,KAAA,CAAM,MAAA,KAAW,WAAW,cAAA,EAAe,GAAI,KAAA,CAAM,MAAA,IAAU,OAAO,CAAA;AAGjH,IAAA,MAAM,aAAa,YAAY;AAC7B,MAAA,YAAA,CAAa,KAAA,GAAQ,YAAA,CAAa,KAAA,KAAU,OAAA,GAAU,MAAA,GAAS,OAAA;AAC/D,MAAA,UAAA,CAAW,QAAA,CAAS,aAAa,KAAK,CAAA;AAAA,IACxC,CAAA;AAGA,IAAA,MAAM,uBAAuB,MAAM;AACjC,MAAA,UAAA,CAAW,oBAAA,EAAqB;AAAA,IAClC,CAAA;AAEA,IAAA,MAAM,eAAe,QAAA,CAAS,MAAO,aAAa,KAAA,KAAU,OAAA,GAAU,YAAY,SAAU,CAAA;AAE5F,IAAA,MAAM,kBAAA,GAAqB,SAAS,MAAM;AACxC,MAAA,IAAI,cAAA,CAAe,OAAO,OAAO,SAAA;AACjC,MAAA,IAAI,SAAA,CAAU,KAAA,EAAO,OAAO,CAAA,IAAA,EAAO,UAAU,KAAK,CAAA,CAAA;AAElD,MAAA,QAAQ,YAAY,KAAA;AAAO,QACzB,KAAK,SAAA;AACH,UAAA,OAAO,QAAA;AAAA,QACT,KAAK,WAAA;AACH,UAAA,OAAO,cAAA;AAAA,QACT,KAAK,MAAA;AACH,UAAA,OAAO,MAAA;AAAA,QACT;AACE,UAAA,OAAO,MAAA;AAAA;AACX,IACF,CAAC,CAAA;AAED,IAAA,IAAI,KAAA,CAAM,WAAW,QAAA,EAAU;AAC7B,MAAA,MAAM,UAAA,GAAa,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA;AACnE,MAAA,MAAM,iBAAA,GAAoB,CAAC,CAAA,KAA2B;AACpD,QAAA,YAAA,CAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,MAAA,GAAS,OAAA;AAAA,MAC5C,CAAA;AACA,MAAA,UAAA,CAAW,gBAAA,CAAiB,UAAU,iBAAiB,CAAA;AACvD,MAAA,eAAA,CAAgB,MAAM;AACpB,QAAA,UAAA,CAAW,mBAAA,CAAoB,UAAU,iBAAiB,CAAA;AAAA,MAC5D,CAAC,CAAA;AAAA,IACH;AAGA,IAAA,MAAM,oBAAoB,MAAM;AAC9B,MAAA,IAAI,QAAA,IAAY,eAAe,KAAA,EAAO;AAEtC,MAAA,cAAA,CAAe,KAAA,GAAQ,IAAA;AACvB,MAAA,SAAA,CAAU,KAAA,GAAQ,EAAA;AAElB,MAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AACpB,QAAA,SAAA,CAAU,KAAA,GAAQ,WAAA;AAClB,QAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AACvB,QAAA;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,IAAI,0BAAA,CAA2B;AAAA,UACxC,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,UAAA,EAAY,IAAA;AAAA,UACZ,UAAA,EAAY,IAAA;AAAA,UACZ,SAAA,EAAW;AAAA,YACT,OAAA,EAAS,IAAA;AAAA,YACT,YAAA,EAAc;AAAA;AAChB,SACD,CAAA;AAED,QAAA,MAAM,SAAA,GAAY,KAAA,CAAM,SAAA,IAAa,CAAC,MAAM,IAAI,CAAA;AAChD,QAAA,QAAA,CAAS,aAAa,SAAS,CAAA;AAE/B,QAAA,QAAA,CAAS,OAAO,MAAM;AACpB,UAAA,OAAA,CAAQ,IAAI,wBAAwB,CAAA;AAEpC,UAAA,aAAA,CAAc,KAAA,GAAQ,IAAA;AAEtB,UAAA,gBAAA,EAAiB;AAEjB,UAAA,IAAA,CAAK,UAAU,IAAI,CAAA;AACnB,UAAA,UAAA,CAAW,IAAA,EAAK;AAChB,UAAA,UAAA,CAAW,UAAA,EAAW;AAEtB,UAAA,UAAA,CAAW,MAAM;AACf,YAAA,aAAA,CAAc,KAAA,GAAQ,KAAA;AAAA,UACxB,GAAG,IAAI,CAAA;AAEP,UAAA,WAAA,CAAY,KAAA,GAAQ,WAAA;AAAA,QACtB,CAAC,CAAA;AAED,QAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,KAAe;AAC/B,UAAA,OAAA,CAAQ,KAAA,CAAM,uBAAuB,KAAK,CAAA;AAC1C,UAAA,SAAA,CAAU,QAAQ,KAAA,CAAM,OAAA;AACxB,UAAA,WAAA,CAAY,KAAA,GAAQ,SAAA;AACpB,UAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AAEvB,UAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AACxC,YAAA,iBAAA,CAAkB,KAAA,GAAQ,SAAA;AAAA,UAC5B,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA,EAAG;AAC1C,YAAA,iBAAA,CAAkB,KAAA,GAAQ,QAAA;AAAA,UAC5B,CAAA,MAAO;AACL,YAAA,iBAAA,CAAkB,KAAA,GAAQ,OAAA;AAAA,UAC5B;AAEA,UAAA,UAAA,CAAW,MAAM;AACf,YAAA,iBAAA,CAAkB,KAAA,GAAQ,EAAA;AAAA,UAC5B,GAAG,GAAI,CAAA;AAAA,QACT,CAAC,CAAA;AAED,QAAA,OAAA,CAAQ,IAAI,uBAAuB,CAAA;AAAA,MACrC,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,0BAA0B,KAAK,CAAA;AAC7C,QAAA,SAAA,CAAU,KAAA,GAAQ,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAA;AAC3D,QAAA,WAAA,CAAY,KAAA,GAAQ,SAAA;AACpB,QAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AAAA,MACzB,CAAA,SAAE;AACA,QAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AAAA,MACzB;AAAA,IACF,CAAA;AAGA,IAAA,MAAM,mBAAmB,MAAM;AAC7B,MAAA,IAAI;AACF,QAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,OAAO,eAAA,EAAiB;AAC5D,UAAA,OAAA,CAAQ,KAAK,+BAA+B,CAAA;AAC5C,UAAA;AAAA,QACF;AACA,QAAA,MAAM,IAAA,GAAO,cAAc,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,GAAI,aAAA,CAAc,MAAM,CAAC,CAAA;AAC3E,QAAA,MAAM,SAAA,GAAY,IAAI,wBAAA,CAAyB,IAAI,CAAA;AACnD,QAAA,SAAA,CAAU,IAAA,GAAO,OAAA;AACjB,QAAA,SAAA,CAAU,IAAA,GAAO,CAAA;AACjB,QAAA,SAAA,CAAU,KAAA,GAAQ,GAAA;AAClB,QAAA,SAAA,CAAU,MAAA,GAAS,GAAA;AAEnB,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,eAAA,CAAgB,SAAA,EAAU;AAChD,QAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA,IAAK,SAAA,CAAU,IAAA,CAAK,CAAA,CAAE,IAAI,CAAC,CAAA;AACtF,QAAA,MAAM,OAAA,GAAU,SAAA,IAAa,MAAA,CAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,CAAK,UAAA,CAAW,IAAI,CAAC,CAAA;AACvE,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,SAAA,CAAU,KAAA,GAAQ,OAAA;AAAA,QACpB;AACA,QAAA,MAAA,CAAO,eAAA,CAAgB,MAAM,SAAS,CAAA;AAAA,MACxC,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,eAAe,KAAK,CAAA;AAAA,MACpC;AAAA,IACF,CAAA;AAyHA,IAAA,MAAM,mBAAmB,YAAY;AASnC,IACF,CAAA;AAEA,IAAA,MAAM,eAAA,GAAkB,OAAO,WAAA,KAA0B;AACvD,MAAA,MAAM,UAAA,GAAa,MAAM,0BAAA,EAA2B;AACpD,MAAA,IAAI,CAAC,UAAA,EAAY;AAEjB,MAAA,IAAI,eAAe,KAAA,EAAO;AAE1B,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,MAAM,iBAAA,EAAkB;AACxB,QAAA,IAAI,CAAC,QAAA,EAAU;AAAA,MACjB;AAIA,MAAA,MAAM,oBAAA,GAAuB,YAAY,KAAA,KAAU,WAAA;AACnD,MAAA,MAAM,WAAA,GAAc,WAAA,KAAgB,MAAA,GAAY,WAAA,GAAc,CAAC,oBAAA;AAG/D,MAAA,IAAI,gBAAgB,oBAAA,EAAsB;AAE1C,MAAA,IAAI;AACF,QAAA,IAAI,WAAA,EAAa;AAEf,UAAA,OAAA,CAAQ,IAAI,8BAA8B,CAAA;AAC1C,UAAA,MAAM,SAAS,KAAA,EAAM;AACrB,UAAA,WAAA,CAAY,KAAA,GAAQ,WAAA;AACpB,UAAA,iBAAA,CAAkB,KAAA,GAAQ,EAAA;AAC1B,UAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AAAA,QACzB,CAAA,MAAO;AAEL,UAAA,OAAA,CAAQ,IAAI,8BAA8B,CAAA;AAC1C,UAAA,MAAM,SAAS,IAAA,EAAK;AACpB,UAAA,gBAAA,EAAiB;AACjB,UAAA,WAAA,CAAY,KAAA,GAAQ,SAAA;AACpB,UAAA,iBAAA,CAAkB,KAAA,GAAQ,EAAA;AAC1B,UAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AAAA,QACzB;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,KAAK,CAAA;AAC5C,QAAA,WAAA,CAAY,KAAA,GAAQ,SAAA;AACpB,QAAA,iBAAA,CAAkB,KAAA,GAAQ,MAAA;AAC1B,QAAA,cAAA,CAAe,KAAA,GAAQ,KAAA;AAEvB,QAAA,UAAA,CAAW,MAAM;AACf,UAAA,iBAAA,CAAkB,KAAA,GAAQ,EAAA;AAAA,QAC5B,GAAG,GAAI,CAAA;AAAA,MACT;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,WAAW,QAAA,CAAS,EAAE,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA;AACxC,IAAA,MAAM,cAAA,GAAiB,GAAA,CAAI,KAAA,CAAM,WAAA,EAAa,SAAS,GAAG,CAAA;AAC1D,IAAA,MAAM,eAAA,GAAkB,GAAA,CAAI,KAAA,CAAM,WAAA,EAAa,UAAU,GAAG,CAAA;AAC5D,IAAA,MAAM,WAAA,GAAc,IAAI,IAAI,CAAA;AAG5B,IAAA,MAAM,gBAAA,GAAmB,CAAC,CAAA,EAAW,CAAA,EAAW,OAAe,MAAA,KAAmB;AAChF,MAAA,MAAM,MAAA,GAAS,EAAA;AACf,MAAA,MAAM,gBAAgB,MAAA,CAAO,UAAA;AAC7B,MAAA,MAAM,iBAAiB,MAAA,CAAO,WAAA;AAE9B,MAAA,MAAM,IAAA,GAAO,gBAAgB,KAAA,GAAQ,MAAA;AACrC,MAAA,MAAM,IAAA,GAAO,iBAAiB,MAAA,GAAS,MAAA;AAEvC,MAAA,OAAO;AAAA,QACL,CAAA,EAAG,KAAK,GAAA,CAAI,MAAA,EAAQ,KAAK,GAAA,CAAI,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,QACrC,CAAA,EAAG,KAAK,GAAA,CAAI,MAAA,EAAQ,KAAK,GAAA,CAAI,CAAA,EAAG,IAAI,CAAC;AAAA,OACvC;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,cAAA,GAAiB,CACrB,KAAA,EACA,KAAA,KACG;AACH,MAAA,MAAM,WAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,KAAA,CAAM,KAAA,EAAO,KAAA,CAAM,KAAK,IAAI,IAAA,CAAK,GAAA,CAAI,MAAM,IAAA,EAAM,KAAA,CAAM,IAAI,CAAC,CAAA;AAClG,MAAA,MAAM,WAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,KAAA,CAAM,MAAA,EAAQ,KAAA,CAAM,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,MAAM,GAAA,EAAK,KAAA,CAAM,GAAG,CAAC,CAAA;AAClG,MAAA,OAAO,QAAA,GAAW,QAAA;AAAA,IACpB,CAAA;AAEA,IAAA,MAAM,mBAAA,GAAsB,CAAC,CAAA,EAAW,CAAA,EAAW,OAAe,MAAA,KAAmB;AACnF,MAAA,IAAI,CAAC,MAAA,CAAO,KAAA,EAAO,OAAO,EAAE,GAAG,CAAA,EAAE;AAEjC,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAA,CAAM,qBAAA,EAAsB;AACnD,MAAA,MAAM,WAAA,GAAc;AAAA,QAClB,IAAA,EAAM,QAAQ,IAAA,GAAO,YAAA;AAAA,QACrB,KAAA,EAAO,QAAQ,KAAA,GAAQ,YAAA;AAAA,QACvB,GAAA,EAAK,QAAQ,GAAA,GAAM,YAAA;AAAA,QACnB,MAAA,EAAQ,QAAQ,MAAA,GAAS;AAAA,OAC3B;AAEA,MAAA,MAAM,UAAA,GAAa;AAAA,QACjB,EAAE,GAAG,CAAA,EAAE;AAAA,QACP,EAAE,CAAA,EAAG,WAAA,CAAY,IAAA,GAAO,KAAA,GAAQ,cAAc,CAAA,EAAE;AAAA,QAChD,EAAE,CAAA,EAAG,WAAA,CAAY,KAAA,GAAQ,cAAc,CAAA,EAAE;AAAA,QACzC,EAAE,CAAA,EAAG,CAAA,EAAG,WAAA,CAAY,GAAA,GAAM,SAAS,YAAA,EAAa;AAAA,QAChD,EAAE,CAAA,EAAG,CAAA,EAAG,WAAA,CAAY,SAAS,YAAA;AAAa,OAC5C;AAEA,MAAA,IAAI,IAAA,GAAO,gBAAA,CAAiB,UAAA,CAAW,CAAC,CAAA,CAAE,CAAA,EAAG,UAAA,CAAW,CAAC,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,MAAM,CAAA;AAC3E,MAAA,IAAI,WAAA,GAAc,cAAA;AAAA,QAChB,EAAE,IAAA,EAAM,IAAA,CAAK,CAAA,EAAG,OAAO,IAAA,CAAK,CAAA,GAAI,KAAA,EAAO,GAAA,EAAK,IAAA,CAAK,CAAA,EAAG,MAAA,EAAQ,IAAA,CAAK,IAAI,MAAA,EAAO;AAAA,QAC5E;AAAA,OACF;AAEA,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,UAAA,CAAW,QAAQ,CAAA,EAAA,EAAK;AAC1C,QAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,UAAA,CAAW,CAAC,CAAA,CAAE,CAAA,EAAG,UAAA,CAAW,CAAC,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,MAAM,CAAA;AAClF,QAAA,MAAM,OAAA,GAAU,cAAA;AAAA,UACd,EAAE,IAAA,EAAM,SAAA,CAAU,CAAA,EAAG,OAAO,SAAA,CAAU,CAAA,GAAI,KAAA,EAAO,GAAA,EAAK,SAAA,CAAU,CAAA,EAAG,MAAA,EAAQ,SAAA,CAAU,IAAI,MAAA,EAAO;AAAA,UAChG;AAAA,SACF;AAEA,QAAA,IAAI,UAAU,WAAA,EAAa;AACzB,UAAA,IAAA,GAAO,SAAA;AACP,UAAA,WAAA,GAAc,OAAA;AACd,UAAA,IAAI,YAAY,CAAA,EAAG;AAAA,QACrB;AAAA,MACF;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,2BAA2B,MAAM;AACrC,MAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AAEnB,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAA,CAAM,qBAAA,EAAsB;AACnD,MAAA,MAAM,cAAc,cAAA,CAAe,KAAA;AACnC,MAAA,MAAM,eAAe,eAAA,CAAgB,KAAA;AACrC,MAAA,MAAM,gBAAgB,MAAA,CAAO,UAAA;AAC7B,MAAA,MAAM,iBAAiB,MAAA,CAAO,WAAA;AAC9B,MAAA,MAAM,MAAA,GAAS,EAAA;AACf,MAAA,MAAM,SAAA,GAAY,EAAA;AAElB,MAAA,IAAI,CAAA,GAAI,CAAA;AACR,MAAA,IAAI,CAAA,GAAI,CAAA;AAGR,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,IAAA,GAAO,WAAA,GAAc,MAAA;AAE3C,MAAA,IAAI,SAAS,SAAA,EAAW;AAEtB,QAAA,CAAA,GAAI,KAAA;AAEJ,QAAA,CAAA,GAAI,OAAA,CAAQ,GAAA;AAGZ,QAAA,IAAI,CAAA,GAAI,YAAA,GAAe,cAAA,GAAiB,SAAA,EAAW;AACjD,UAAA,CAAA,GAAI,iBAAiB,YAAA,GAAe,SAAA;AAAA,QACtC;AAEA,QAAA,IAAI,IAAI,SAAA,EAAW;AACjB,UAAA,CAAA,GAAI,SAAA;AAAA,QACN;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,MAAM,MAAA,GAAS,QAAQ,KAAA,GAAQ,MAAA;AAE/B,QAAA,IAAI,MAAA,GAAS,WAAA,IAAe,aAAA,GAAgB,SAAA,EAAW;AAErD,UAAA,CAAA,GAAI,MAAA;AACJ,UAAA,CAAA,GAAI,OAAA,CAAQ,GAAA;AAGZ,UAAA,IAAI,CAAA,GAAI,YAAA,GAAe,cAAA,GAAiB,SAAA,EAAW;AACjD,YAAA,CAAA,GAAI,iBAAiB,YAAA,GAAe,SAAA;AAAA,UACtC;AACA,UAAA,IAAI,IAAI,SAAA,EAAW;AACjB,YAAA,CAAA,GAAI,SAAA;AAAA,UACN;AAAA,QACF,CAAA,MAAO;AAEL,UAAA,CAAA,GAAA,CAAK,gBAAgB,WAAA,IAAe,CAAA;AAGpC,UAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,GAAM,YAAA,GAAe,MAAA;AAC5C,UAAA,IAAI,UAAU,SAAA,EAAW;AACvB,YAAA,CAAA,GAAI,MAAA;AAAA,UACN,CAAA,MAAO;AAEL,YAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,GAAS,MAAA;AAChC,YAAA,IAAI,MAAA,GAAS,YAAA,IAAgB,cAAA,GAAiB,SAAA,EAAW;AACvD,cAAA,CAAA,GAAI,MAAA;AAAA,YACN,CAAA,MAAO;AAEL,cAAA,CAAA,GAAA,CAAK,iBAAiB,YAAA,IAAgB,CAAA;AAAA,YACxC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,MAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,aAAa,YAAY,CAAA;AAClE,MAAA,MAAM,YAAY,mBAAA,CAAoB,SAAA,CAAU,GAAG,SAAA,CAAU,CAAA,EAAG,aAAa,YAAY,CAAA;AACzF,MAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AACvB,MAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AAAA,IACzB,CAAA;AAEA,IAAA,MAAM,iBAAiB,YAAY;AACjC,MAAA,WAAA,CAAY,KAAA,GAAQ,CAAC,WAAA,CAAY,KAAA;AAEjC,MAAA,QAAA,CAAS,MAAM;AACb,QAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,KAAA,GAAQ,EAAA,GAAK,eAAA,CAAgB,KAAA;AAC/D,QAAA,MAAM,SAAA,GAAY,iBAAiB,QAAA,CAAS,CAAA,EAAG,SAAS,CAAA,EAAG,cAAA,CAAe,OAAO,aAAa,CAAA;AAC9F,QAAA,MAAM,SAAA,GAAY,oBAAoB,SAAA,CAAU,CAAA,EAAG,UAAU,CAAA,EAAG,cAAA,CAAe,OAAO,aAAa,CAAA;AACnG,QAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AACvB,QAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AAAA,MACzB,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,MAAM,OAAO,QAAA,CAAS;AAAA,MACpB,UAAA,EAAY,KAAA;AAAA,MACZ,MAAA,EAAQ,CAAA;AAAA,MACR,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,CAAA;AAAA,MACT,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAAkB;AACnC,MAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,MAAA,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA;AAChB,MAAA,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA;AAChB,MAAA,IAAA,CAAK,UAAU,QAAA,CAAS,CAAA;AACxB,MAAA,IAAA,CAAK,UAAU,QAAA,CAAS,CAAA;AACxB,MAAA,QAAA,CAAS,gBAAA,CAAiB,aAAa,MAAM,CAAA;AAC7C,MAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,QAAQ,CAAA;AAAA,IAC/C,CAAA;AAEA,IAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAkB;AAChC,MAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AAEtB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,IAAW,CAAA,CAAE,UAAU,IAAA,CAAK,MAAA,CAAA;AAC9C,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,IAAW,CAAA,CAAE,UAAU,IAAA,CAAK,MAAA,CAAA;AAE9C,MAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,IAAA,EAAM,IAAA,EAAM,cAAA,CAAe,OAAO,WAAA,CAAY,KAAA,GAAQ,EAAA,GAAK,eAAA,CAAgB,KAAK,CAAA;AAEnH,MAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AACvB,MAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AAAA,IACzB,CAAA;AAEA,IAAA,MAAM,WAAW,MAAM;AACrB,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAClB,MAAA,QAAA,CAAS,mBAAA,CAAoB,aAAa,MAAM,CAAA;AAChD,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,QAAQ,CAAA;AAAA,IAClD,CAAA;AAEA,IAAA,MAAM,YAAA,GAAe,OAAO,KAAA,KAAmB;AAC7C,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,OAAA,CAAQ,KAAA,GAAQ,IAAA;AAChB,QAAA,aAAA,CAAc,KAAA,GAAQ,KAAA;AACtB,QAAA,IAAA,CAAK,UAAU,IAAI,CAAA;AACnB,QAAA,MAAM,QAAA,EAAS;AAEf,QAAA,IAAI,YAAY,KAAA,EAAO;AACrB,UAAA,wBAAA,EAAyB;AACzB,UAAA,WAAA,CAAY,KAAA,GAAQ,KAAA;AAAA,QACtB,CAAA,MAAO;AACL,UAAA,MAAM,SAAA,GAAY,gBAAA;AAAA,YAChB,QAAA,CAAS,CAAA;AAAA,YACT,QAAA,CAAS,CAAA;AAAA,YACT,cAAA,CAAe,KAAA;AAAA,YACf,WAAA,CAAY,KAAA,GAAQ,EAAA,GAAK,eAAA,CAAgB;AAAA,WAC3C;AACA,UAAA,MAAM,SAAA,GAAY,mBAAA;AAAA,YAChB,SAAA,CAAU,CAAA;AAAA,YACV,SAAA,CAAU,CAAA;AAAA,YACV,cAAA,CAAe,KAAA;AAAA,YACf,WAAA,CAAY,KAAA,GAAQ,EAAA,GAAK,eAAA,CAAgB;AAAA,WAC3C;AACA,UAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AACvB,UAAA,QAAA,CAAS,IAAI,SAAA,CAAU,CAAA;AAAA,QACzB;AAEA,QAAA,MAAM,QAAA,EAAS;AACf,QAAA,aAAA,CAAc,KAAA,GAAQ,IAAA;AAAA,MACxB,CAAA,MAAO;AACL,QAAA,aAAA,CAAc,KAAA,GAAQ,KAAA;AACtB,QAAA,OAAA,CAAQ,KAAA,GAAQ,KAAA;AAChB,QAAA,WAAA,CAAY,KAAA,GAAQ,KAAA;AACpB,QAAA,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,MACtB;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAiB;AACzC,MAAA,UAAA,CAAW,gBAAA,CAAiB,MAAM,MAA2B,CAAA;AAC7D,MAAA,UAAA,CAAW,SAAS,MAAM,CAAA;AAAA,IAC5B,CAAA;AAEA,IAAA,KAAA;AAAA,MACE,MAAM,CAAC,UAAA,CAAW,UAAA,EAAY,CAAA;AAAA,MAC9B,CAAC,CAAC,GAAG,CAAA,KAAM;AACT,QAAA,OAAA,CAAQ,GAAA,CAAI,oBAAoB,GAAG,CAAA;AACnC,QAAA,IAAI,GAAA,EAAK;AACP,UAAA,UAAA,CAAW,KAAA,GAAQ,CAAA,EAAG,GAAG,CAAA,KAAA,EAAQ,UAAA,CAAW,OAAO,CAAA,OAAA,EAAU,UAAA,CAAW,QAAA,EAAU,CAAA,CAAA;AAAA,QACpF;AAAA,MACF,CAAA;AAAA,MACA,EAAE,WAAW,IAAA;AAAK,KACpB;AAEA,IAAA,eAAA,CAAgB,YAAY;AAC1B,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,IAAI;AACF,UAAA,IAAI,QAAA,CAAS,UAAS,EAAG;AACvB,YAAA,MAAM,SAAS,IAAA,EAAK;AAAA,UACtB;AACA,UAAA,QAAA,GAAW,IAAA;AAAA,QACb,SAAS,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,KAAK,CAAA;AAAA,QAC9C;AAAA,MACF;AAUA,IACF,CAAC,CAAA;AAED,IAAA,UAAA,EAAY,oBAAA,CAAqB;AAAA,MAC/B,KAAA,EAAO,MAAM,eAAA,CAAgB,IAAI,CAAA;AAAA,MACjC,IAAA,EAAM,MAAM,eAAA,CAAgB,KAAK,CAAA;AAAA,MACjC,UAAA,EAAY,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,MACnC,WAAA,EAAa,MAAM,YAAA,CAAa,KAAK,CAAA;AAAA,MACrC,cAAA,EAAgB,MAAM,cAAA;AAAe,KACtC,CAAA;;0BAlzBCF,kBAAA,CAgKM,KAAA,EAAA;AAAA,QAhKD,KAAA,EAAM,QAAA;AAAA,QAAU,cAAY,YAAA,CAAA;AAAA;QAE/BO,WAAA,CA8CaR,UAAA,EAAA,EA9CD,IAAA,EAAK,QAAM,EAAA;AAAA,2BACrB,MA4CM;AAAA,YA5CNG,mBA4CM,KAAA,EAAA;AAAA,uBA5CG,QAAA;AAAA,cAAJ,GAAA,EAAI,MAAA;AAAA,cAAS,KAAA,EAAM,eAAA;AAAA,cAAiB,OAAA,EAAK,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAAA,KAAE,YAAA,CAAY,CAAE,OAAA,CAAA,KAAO,CAAA;AAAA;eAE1D,YAAA,CAAA,KAAA,iBADTJ,YAOE,WAAA,EAAA;AAAA;gBALA,KAAA,EAAM,cAAA;AAAA,gBACL,QAAQ,WAAA,CAAA,KAAA;AAAA,gBACR,sBAAoB,iBAAA,CAAA,KAAA;AAAA,gBACpB,mBAAiB,cAAA,CAAA,KAAA;AAAA,gBAClB,KAAA,EAAA,EAAA,OAAA,EAAA,OAAA;AAAA,gGAEFA,WAAA,CAAiG,eAAA,EAAA;AAAA;gBAAzE,KAAA,EAAM,cAAA;AAAA,gBAAgB,SAAS,YAAA,CAAA,KAAA;AAAA,gBAAe,MAAM,iBAAA,CAAA;AAAA;cAC5EI,kBAAA,CAgCM,OAhCN,UAAA,EAgCM;AAAA,gBA/BJA,mBAME,KAAA,EAAA;AAAA,kBALC,GAAA,EAAK,OAAA,CAAA,KAAA,GAAQ,OAAA,CAAA,KAAA,GAAK,WAAA;AAAA,kBACnB,GAAA,EAAI,WAAA;AAAA,kBACH,OAAKS,cAAA,CAAA;AAAA,oBAA0B,KAAA,EAAA,OAAA,CAAA,KAAA,EAAO,KAAA,GAAK;AAAA;;gBAK9CJ,WAAA,CAsBaR,UAAA,EAAA,EAtBD,IAAA,EAAK,kBAAgB,EAAA;AAAA,mCAC/B,MAoBM;AAAA,oBApBK,YAAA,KAAA,KAAW,WAAA,iBAAtBC,mBAoBM,KAAA,EAAA;AAAA;sBApBkC,KAAA,EAAKC,eAAA,CAAC,iBAAA,EAAiB,EAAA,aAAA,EAA0B,aAAA,CAAA,KAAA,EAAa,CAAA;AAAA;sBACpGC,kBAAA,CAIM,KAAA,EAAA,EAJD,KAAA,EAAM,mBAAiB,EAAA;AAAA,wBAC1BA,kBAAA,CAA+B,KAAA,EAAA,EAA1B,KAAA,EAAM,eAAa,CAAA;AAAA,wBACxBA,kBAAA,CAA+B,KAAA,EAAA,EAA1B,KAAA,EAAM,eAAa,CAAA;AAAA,wBACxBA,kBAAA,CAA+B,KAAA,EAAA,EAA1B,KAAA,EAAM,eAAa;AAAA;sBAE1BA,kBAAA,CAaM,KAAA,EAAA,EAbD,KAAA,EAAM,kBAAgB,EAAA;AAAA,wBACzBA,mBAWM,KAAA,EAAA;AAAA,0BAXD,KAAA,EAAM,IAAA;AAAA,0BAAK,MAAA,EAAO,IAAA;AAAA,0BAAK,OAAA,EAAQ,WAAA;AAAA,0BAAY,IAAA,EAAK;AAAA;0BACnDA,mBAGE,MAAA,EAAA;AAAA,4BAFA,CAAA,EAAE,8EAAA;AAAA,4BACF,IAAA,EAAK;AAAA;0BAEPA,mBAKE,MAAA,EAAA;AAAA,4BAJA,CAAA,EAAE,sCAAA;AAAA,4BACF,MAAA,EAAO,cAAA;AAAA,4BACP,cAAA,EAAa,GAAA;AAAA,4BACb,gBAAA,EAAe;AAAA;;;;;;;;cAO3BA,mBAA8E,KAAA,EAAA;AAAA,gBAAzE,KAAA,EAAKD,cAAA,CAAA,CAAC,WAAA,EAAW,EAAA,QAAmB,WAAA,CAAA,KAAA,KAAW,WAAA,EAAA,CAAA;AAAA;;;;;QAKxDM,WAAA,CA4GaR,UAAA,EAAA,EA5GD,IAAA,EAAK,eAAa,EAAA;AAAA,2BAC5B,MA0GM;AAAA,YA1GNG,mBA0GM,KAAA,EAAA;AAAA,cAzGJ,GAAA,EAAI,WAAA;AAAA,cACJ,KAAA,kBAAM,oBAAA,EAAoB;AAAA,2BACM,WAAA,CAAA,KAAA;AAAA,8BAAsC,OAAA,CAAA,KAAA;AAAA,kCAAsC,aAAA,CAAA;AAAA;cAK3G,OAAKS,cAAA,CAAA;AAAA,uBAAsB,eAAA,KAAA,GAAc,IAAA;AAAA,gBAA4B,MAAA,EAAA,WAAA,CAAA,KAAA,YAAuB,gBAAA,KAAA,GAAe,IAAA;AAAA,gBAA4B,QAAA,YAAA,CAAA,KAAA,iBAA6B,WAAA,CAAA,QAAW,+BAAA,GAAA,MAAA;AAAA,gBAAsE,YAAA,EAAA,SAAS,CAAA,GAAC,IAAA;AAAA,gBAAkC,YAAA,EAAA,SAAS,CAAA,GAAC;AAAA;cAO3S,WAAA,EAAW;AAAA;cAEZT,mBA8EM,KAAA,EAAA;AAAA,gBA9ED,KAAA,EAAM,iBAAA;AAAA,gBAAmB,WAAA,gBAAgB,SAAA,EAAS,CAAA,MAAA,CAAA;AAAA;gBACrDA,kBAAA,CAKM,OALN,UAAA,EAKM;AAAA,kBAJJA,kBAAA,CAEM,OAFN,UAAA,EAEM;AAAA,oBADJA,mBAAuE,KAAA,EAAA;AAAA,sBAAjE,GAAA,EAAK,OAAA,CAAA,KAAA,GAAQ,OAAA,CAAA,KAAA,GAAK,WAAA;AAAA,sBAAgB,GAAA,EAAI,WAAA;AAAA,sBAAY,KAAA,EAAM;AAAA;;kBAEhEA,mBAAuC,MAAA,EAAvC,UAAA,EAAuCI,gBAAhB,OAAA,CAAA,MAAM,GAAA,CAAA;AAAA;gBAE/BJ,kBAAA,CAsEM,OAtEN,UAAA,EAsEM;AAAA,kBArEJA,mBAIS,QAAA,EAAA;AAAA,oBAJD,KAAA,EAAM,sBAAA;AAAA,oBAAuB,KAAA,EAAM,OAAA;AAAA,oBAAS,OAAA,EAAO;AAAA;oBACzDA,mBAEM,KAAA,EAAA;AAAA,sBAFD,KAAA,EAAM,IAAA;AAAA,sBAAK,MAAA,EAAO,IAAA;AAAA,sBAAK,OAAA,EAAQ,WAAA;AAAA,sBAAY,IAAA,EAAK;AAAA;sBACnDA,mBAA2F,MAAA,EAAA;AAAA,wBAArF,CAAA,EAAE,kBAAA;AAAA,wBAAmB,MAAA,EAAO,cAAA;AAAA,wBAAe,cAAA,EAAa,GAAA;AAAA,wBAAI,gBAAA,EAAe;AAAA;;;kBAGrFA,mBAyCS,QAAA,EAAA;AAAA,oBAxCP,KAAA,kBAAM,sBAAA,EAAsB;AAAA,8BACO,YAAA,KAAA,KAAW,SAAA;AAAA,iCAA4C,YAAA,KAAA,KAAW,WAAA;AAAA,4BAAyC,YAAA,KAAA,KAAW;AAAA;oBAKxJ,OAAA,gDAAkB,eAAA,EAAe,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,oBACjC,OAAO,kBAAA,CAAA;AAAA;8CAERA,mBA6BM,KAAA,EAAA;AAAA,sBA7BD,KAAA,EAAM,IAAA;AAAA,sBAAK,MAAA,EAAO,IAAA;AAAA,sBAAK,OAAA,EAAQ,WAAA;AAAA,sBAAY,IAAA,EAAK;AAAA;sBACnDA,mBAME,MAAA,EAAA;AAAA,wBALA,CAAA,EAAE,uHAAA;AAAA,wBACF,MAAA,EAAO,cAAA;AAAA,wBACP,cAAA,EAAa,GAAA;AAAA,wBACb,gBAAA,EAAe,OAAA;AAAA,wBACf,iBAAA,EAAgB;AAAA;sBAElBA,mBAME,MAAA,EAAA;AAAA,wBALA,CAAA,EAAE,8DAAA;AAAA,wBACF,MAAA,EAAO,cAAA;AAAA,wBACP,cAAA,EAAa,GAAA;AAAA,wBACb,gBAAA,EAAe,OAAA;AAAA,wBACf,iBAAA,EAAgB;AAAA;sBAElBA,mBAME,MAAA,EAAA;AAAA,wBALA,CAAA,EAAE,WAAA;AAAA,wBACF,MAAA,EAAO,cAAA;AAAA,wBACP,cAAA,EAAa,GAAA;AAAA,wBACb,gBAAA,EAAe,OAAA;AAAA,wBACf,iBAAA,EAAgB;AAAA;sBAElBA,mBAME,MAAA,EAAA;AAAA,wBALA,CAAA,EAAE,UAAA;AAAA,wBACF,MAAA,EAAO,cAAA;AAAA,wBACP,cAAA,EAAa,GAAA;AAAA,wBACb,gBAAA,EAAe,OAAA;AAAA,wBACf,iBAAA,EAAgB;AAAA;;oBAGgB,WAAA,CAAA,KAAA,KAAW,SAAA,IAA/CQ,SAAA,EAAA,EAAAV,kBAAA,CAAsE,MAAA,EAAtE,WAAsE,CAAA;;kBAExEE,mBAKS,QAAA,EAAA;AAAA,oBALD,KAAA,EAAM,sBAAA;AAAA,oBAAwB,OAAA,gBAAY,UAAA,EAAU,CAAA,MAAA,CAAA,CAAA;AAAA,oBAAG,OAAO,YAAA,CAAA;AAAA;oBACpEA,mBAGM,KAAA,EAAA;AAAA,sBAHD,KAAA,EAAM,IAAA;AAAA,sBAAK,MAAA,EAAO,IAAA;AAAA,sBAAK,OAAA,EAAQ,WAAA;AAAA,sBAAY,IAAA,EAAK;AAAA;sBACnDA,mBAAuE,QAAA,EAAA;AAAA,wBAA/D,EAAA,EAAG,IAAA;AAAA,wBAAK,EAAA,EAAG,IAAA;AAAA,wBAAK,CAAA,EAAE,GAAA;AAAA,wBAAI,MAAA,EAAO,cAAA;AAAA,wBAAe,cAAA,EAAa;AAAA;sBACjEA,mBAAsD,MAAA,EAAA;AAAA,wBAAhD,CAAA,EAAE,uBAAA;AAAA,wBAAwB,IAAA,EAAK;AAAA;;;kBAGzCA,mBAUS,QAAA,EAAA;AAAA,oBAVD,KAAA,EAAM,yBAAA;AAAA,oBAA2B,OAAA,gBAAY,cAAA,EAAc,CAAA,MAAA,CAAA,CAAA;AAAA,oBAAG,KAAA,EAAO,WAAA,CAAA,KAAA,GAAW,IAAA,GAAA;AAAA;qBACtFQ,SAAA,EAAA,EAAAV,kBAAA,CAQM,KAAA,EARN,WAAA,EAQM;AAAA,sBAPJE,mBAME,MAAA,EAAA;AAAA,wBALC,CAAA,EAAG,WAAA,CAAA,KAAA,GAAW,kBAAA,GAAA,iBAAA;AAAA,wBACf,MAAA,EAAO,cAAA;AAAA,wBACP,cAAA,EAAa,GAAA;AAAA,wBACb,gBAAA,EAAe,OAAA;AAAA,wBACf,iBAAA,EAAgB;AAAA;;;kBAItBA,mBAIS,QAAA,EAAA;AAAA,oBAJD,KAAA,EAAM,yBAAA;AAAA,oBAA2B,OAAA,sDAAY,YAAA,CAAY,KAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,oBAAS,KAAA,EAAM;AAAA;oBAC9EA,mBAEM,KAAA,EAAA;AAAA,sBAFD,KAAA,EAAM,IAAA;AAAA,sBAAK,MAAA,EAAO,IAAA;AAAA,sBAAK,OAAA,EAAQ,WAAA;AAAA,sBAAY,IAAA,EAAK;AAAA;sBACnDA,mBAAmF,MAAA,EAAA;AAAA,wBAA7E,CAAA,EAAE,UAAA;AAAA,wBAAW,MAAA,EAAO,cAAA;AAAA,wBAAe,cAAA,EAAa,GAAA;AAAA,wBAAI,gBAAA,EAAe;AAAA;;;;;cAKjFA,mBASM,KAAA,EAAA;AAAA,gBATA,KAAA,qDAA2C,WAAA,CAAA,KAAA,EAAW,CAAA,CAAA;AAAA,gBAAM,KAAA,4BAAkB,YAAA,KAAA,GAAW,CAAA,GAAA,GAAA;AAAA;gBAC7FA,mBAOU,QAAA,EAAA;AAAA,kBANR,GAAA,EAAI,WAAA;AAAA,kBACH,KAAK,UAAA,CAAA,KAAA;AAAA,kBACN,KAAA,EAAM,UAAA;AAAA,kBACN,KAAA,EAAM,cAAA;AAAA,kBACN,WAAA,EAAY,GAAA;AAAA,kBACX,MAAA,EAAM;AAAA;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"sime-x-vue.mjs","sources":["../src/injection-key.ts","../src/types.ts","../src/components/sime-provider.vue","../src/components/voice-status.vue","../src/components/execution-status.vue","../src/lib/utils.ts","../src/components/sime-x.vue","../src/composables/use-tts.ts","../src/composables/use-bubble.ts","../src/composables/use-voice-recognition.ts","../src/lib/data-stream-parser.ts","../src/composables/use-agent-invoke.ts","../src/components/voice-assistant.vue"],"sourcesContent":["import type { InjectionKey } from 'vue'\r\nimport type { AiChatbotXContext } from './types'\r\nimport { inject } from 'vue'\r\n\r\nexport const AiChatbotXKey: InjectionKey<AiChatbotXContext> = Symbol('sime-x')\r\n\r\nexport function injectStrict<T>(key: InjectionKey<T>): T\r\nexport function injectStrict<T>(key: InjectionKey<T>, defaultValue: T, treatDefaultAsFactory?: false): T\r\nexport function injectStrict<T>(key: InjectionKey<T>, defaultValue: T | (() => T), treatDefaultAsFactory: true): T\r\nexport function injectStrict<T>(key: InjectionKey<T>, defaultValue?: T | (() => T), treatDefaultAsFactory?: boolean): T {\r\n let result: T | undefined\r\n\r\n if (defaultValue === undefined) {\r\n result = inject(key) as T | undefined\r\n }\r\n else if (treatDefaultAsFactory === true) {\r\n result = inject(key, defaultValue as T | (() => T), true)\r\n }\r\n else {\r\n result = inject(key, defaultValue as T, false)\r\n }\r\n\r\n if (!result) {\r\n throw new Error(`Could not resolve ${key.description}`)\r\n }\r\n return result\r\n}\r\n","import type { CommandDefinition, DiscoveredCommand } from '@siact/sime-bridge';\r\n\r\nexport enum clientCommandKey {\r\n SET_THEME = 'SiMeAgent_setTheme',\r\n APPEND_MESSAGE = 'SiMeAgent_appendMessage',\r\n WAKE = 'SiMeAgent_wake',\r\n TRANSITION = 'SiMeAgent_transition',\r\n TRANSITION_END = 'SiMeAgent_transition_end',\r\n START_NEW_CONVERSATION = 'SiMeAgent_startNewConversation',\r\n RECOGNITION = 'SiMeAgent_recognition',\r\n}\r\n\r\nexport interface VoiceConfig {\r\n appId: string;\r\n /** STT(语音转写)apiKey */\r\n apiKey: string;\r\n /** apiSecret,TTS 鉴权必需 */\r\n apiSecret?: string;\r\n /** STT(语音转写)WebSocket 地址 */\r\n websocketUrl: string;\r\n /** TTS apiKey(可选,不填则复用 apiKey) */\r\n ttsApiKey?: string;\r\n /** TTS(语音合成)WebSocket 地址 */\r\n ttsWebsocketUrl?: string;\r\n /** TTS 发音人,默认 xiaoyan */\r\n ttsVcn?: string;\r\n}\r\n\r\nexport interface AiChatbotXContext {\r\n chatbotUrl: () => string;\r\n appId: () => string;\r\n appToken: () => string;\r\n voiceConfig: () => VoiceConfig;\r\n registerCommand: (cmd: CommandDefinition) => void;\r\n unregisterCommand: (name: string) => void;\r\n clientCommand: () => Promise<DiscoveredCommand[]>;\r\n hostCommads: () => Promise<DiscoveredCommand[]>;\r\n appendMessage: (message: string) => Promise<void>;\r\n setTheme: (theme: string) => Promise<void>;\r\n weak: () => Promise<void>;\r\n startListening: () => Promise<void>;\r\n stopListening: () => Promise<void>;\r\n toggleCollapse: () => Promise<void>;\r\n openDialog: () => Promise<void>;\r\n closeDialog: () => Promise<void>;\r\n registerVoiceMethods: (methods: {\r\n start: () => Promise<void>;\r\n stop: () => Promise<void>;\r\n toggleCollapse: () => Promise<void>;\r\n openDialog: () => Promise<void>;\r\n closeDialog: () => Promise<void>;\r\n }) => void;\r\n startNewConversation: () => Promise<void>;\r\n setIframeElement: (iframe: HTMLIFrameElement) => void;\r\n recognition: (message: string, commands: DiscoveredCommand[]) => Promise<any>;\r\n executeCommand: (commandName: string, args?: any[]) => Promise<any>;\r\n}\r\n","<template>\r\n <slot></slot>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { provide, shallowRef } from 'vue';\r\nimport { HostBridge, CommandDefinition } from '@siact/sime-bridge';\r\nimport { AiChatbotXKey } from '../injection-key';\r\nimport { clientCommandKey, VoiceConfig } from '../types';\r\n\r\nconst props = defineProps<{\r\n /** 项目名称 */\r\n project: string;\r\n /** 项目描述 */\r\n description?: string;\r\n /** 是否开启调试模式 */\r\n debug?: boolean;\r\n /** iframeUrl */\r\n chatbotUrl: string;\r\n /** appId */\r\n appId: string;\r\n /** appToken */\r\n appToken: string;\r\n /** 语音配置(可选,也可直接在 voiceAssistant 组件上传入) */\r\n voiceConfig?: VoiceConfig;\r\n}>();\r\n\r\nconst hostBridge = shallowRef<HostBridge>(new HostBridge({ debug: false }));\r\n\r\nconst startListeningRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst stopListeningRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst toggleCollapseRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst openDialogRef = shallowRef<() => Promise<void>>(async () => {});\r\nconst closeDialogRef = shallowRef<() => Promise<void>>(async () => {});\r\n\r\nprovide(AiChatbotXKey, {\r\n chatbotUrl: () => props.chatbotUrl,\r\n appId: () => props.appId,\r\n appToken: () => props.appToken,\r\n voiceConfig: () => props.voiceConfig || { appId: '', apiKey: '', websocketUrl: '' },\r\n startListening: () => startListeningRef.value(),\r\n stopListening: () => stopListeningRef.value(),\r\n toggleCollapse: () => toggleCollapseRef.value(),\r\n openDialog: () => openDialogRef.value(),\r\n closeDialog: () => closeDialogRef.value(),\r\n registerVoiceMethods: (methods: {\r\n start: () => Promise<void>;\r\n stop: () => Promise<void>;\r\n toggleCollapse: () => Promise<void>;\r\n openDialog: () => Promise<void>;\r\n closeDialog: () => Promise<void>;\r\n }) => {\r\n startListeningRef.value = methods.start;\r\n stopListeningRef.value = methods.stop;\r\n toggleCollapseRef.value = methods.toggleCollapse;\r\n openDialogRef.value = methods.openDialog;\r\n closeDialogRef.value = methods.closeDialog;\r\n },\r\n clientCommand: () => hostBridge.value.clientCommands(),\r\n hostCommads: () => hostBridge.value.hostCommands(),\r\n registerCommand: (cmd: CommandDefinition) => {\r\n hostBridge.value.registerCommand(cmd);\r\n },\r\n unregisterCommand: (name) => {\r\n hostBridge.value.unregisterCommand(name);\r\n },\r\n async appendMessage(message) {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.APPEND_MESSAGE, [message]);\r\n },\r\n async setTheme(theme) {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.SET_THEME, [theme]);\r\n },\r\n async weak() {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.WAKE);\r\n },\r\n async startNewConversation() {\r\n await hostBridge.value.executeClientCommand(clientCommandKey.START_NEW_CONVERSATION);\r\n },\r\n setIframeElement(iframe) {\r\n hostBridge.value.setIframe(iframe);\r\n },\r\n async recognition(message, commands) {\r\n return await hostBridge.value.executeClientCommand(clientCommandKey.RECOGNITION, [message, commands]);\r\n },\r\n async executeCommand(commandName, args = []) {\r\n return await hostBridge.value.executeCommand(commandName, args);\r\n },\r\n});\r\n</script>\r\n","<template>\r\n <transition name=\"voice-panel\">\r\n <!-- Main Container -->\r\n <div v-if=\"status === 'wake' || isTranscribing\" class=\"voice-status-wrapper\" :class=\"currentMode\">\r\n <!-- Visual Indicator Section -->\r\n <div class=\"indicator-container\">\r\n <!-- Ambient Glow (Background) -->\r\n <div class=\"ambient-glow\"></div>\r\n\r\n <!-- Animated Ripples -->\r\n <div class=\"ripple-layer\">\r\n <div class=\"ripple delay-1\"></div>\r\n <div class=\"ripple delay-2\"></div>\r\n <div class=\"ripple delay-3\"></div>\r\n </div>\r\n\r\n <!-- Core Icon Circle -->\r\n <div class=\"icon-core\">\r\n <!-- Unified Microphone Icon -->\r\n <svg\r\n class=\"mic-icon\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <!-- Microphone Capsule (Animates on voice) -->\r\n <rect x=\"9\" y=\"2\" width=\"6\" height=\"12\" rx=\"3\" class=\"mic-capsule\" />\r\n <!-- Stand/Base -->\r\n <path d=\"M5 10C5 13.866 8.13401 17 12 17C15.866 17 19 13.866 19 10\" class=\"mic-stand\" />\r\n <path d=\"M12 17V21M8 21H16\" class=\"mic-base\" />\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <!-- Content Section -->\r\n <div class=\"content-container\">\r\n <!-- Status Header -->\r\n <div class=\"status-header\">\r\n <span class=\"status-text\">{{ statusLabel }}</span>\r\n </div>\r\n\r\n <!-- Transcription Text (Animated Entry) -->\r\n <div class=\"text-window\" :class=\"{ 'has-text': !!transcriptionText }\">\r\n <transition name=\"fade-slide\" mode=\"out-in\">\r\n <p v-if=\"transcriptionText\" class=\"transcription-content\">\r\n {{ transcriptionText }}\r\n </p>\r\n <p v-else-if=\"status === 'wake'\" class=\"placeholder-text\">Listening...</p>\r\n </transition>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from 'vue';\r\ntype VoiceStatus = 'wake' | 'listening' | 'standby';\r\n\r\nconst props = defineProps<{\r\n status: VoiceStatus;\r\n transcriptionText?: string;\r\n isTranscribing?: boolean;\r\n}>();\r\n\r\n// Determine the current visual mode\r\nconst currentMode = computed(() => {\r\n if (props.isTranscribing) return 'mode-transcribing';\r\n if (props.status === 'wake') return 'mode-wake';\r\n return 'mode-standby';\r\n});\r\n\r\n// Dynamic label text\r\nconst statusLabel = computed(() => {\r\n if (props.isTranscribing) return '正在聆听您的问题...';\r\n if (props.status === 'wake') return '您好,有什么可以帮助您的吗?';\r\n return 'Standby';\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use 'sass:color';\r\n\r\n/* --- Design Tokens --- */\r\n$c-wake: #10b981; // Emerald for Wake\r\n$c-transcribe: #3b82f6; // Blue for Transcribing\r\n$bg-glass: rgba(15, 23, 42, 0.85);\r\n$border-glass: rgba(255, 255, 255, 0.1);\r\n$ease-smooth: cubic-bezier(0.25, 0.8, 0.25, 1);\r\n$ease-elastic: cubic-bezier(0.34, 1.56, 0.64, 1);\r\n\r\n/* --- Main Container --- */\r\n.voice-status-wrapper {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 20px;\r\n padding: 24px;\r\n background: $bg-glass;\r\n backdrop-filter: blur(16px);\r\n -webkit-backdrop-filter: blur(16px);\r\n border: 1px solid $border-glass;\r\n border-radius: 24px;\r\n box-shadow:\r\n 0 10px 40px -10px rgba(0, 0, 0, 0.5),\r\n inset 0 1px 0 rgba(255, 255, 255, 0.1);\r\n transition: all 0.4s $ease-smooth;\r\n max-width: 480px;\r\n width: 100%;\r\n}\r\n\r\n/* --- Indicator Section --- */\r\n.indicator-container {\r\n position: relative;\r\n width: 64px;\r\n height: 64px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n}\r\n\r\n.ambient-glow {\r\n position: absolute;\r\n inset: -20px;\r\n border-radius: 50%;\r\n opacity: 0;\r\n filter: blur(20px);\r\n transition: all 0.5s ease;\r\n}\r\n\r\n.icon-core {\r\n position: relative;\r\n width: 52px;\r\n height: 52px;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.05);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: 1px solid rgba(255, 255, 255, 0.1);\r\n z-index: 10;\r\n transition: all 0.4s $ease-elastic;\r\n overflow: hidden;\r\n\r\n .mic-icon {\r\n width: 24px;\r\n height: 24px;\r\n color: rgba(255, 255, 255, 0.9);\r\n transition: all 0.3s ease;\r\n\r\n .mic-capsule {\r\n transition: transform 0.2s ease;\r\n transform-origin: center center;\r\n }\r\n }\r\n}\r\n\r\n/* --- Ripple Effects --- */\r\n.ripple-layer {\r\n position: absolute;\r\n inset: 0;\r\n pointer-events: none;\r\n}\r\n\r\n.ripple {\r\n position: absolute;\r\n inset: 0;\r\n border-radius: 50%;\r\n border: 2px solid transparent;\r\n opacity: 0;\r\n}\r\n\r\n/* --- Content Section --- */\r\n.content-container {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n min-width: 0; /* Prevent flex text overflow */\r\n padding-top: 4px;\r\n}\r\n\r\n.status-header {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n margin-bottom: 8px;\r\n}\r\n\r\n.status-dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: currentColor;\r\n box-shadow: 0 0 8px currentColor;\r\n transition: color 0.3s ease;\r\n}\r\n\r\n.status-text {\r\n font-size: 13px;\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n letter-spacing: 0.05em;\r\n color: rgba(255, 255, 255, 0.6);\r\n}\r\n\r\n.text-window {\r\n min-height: 24px;\r\n position: relative;\r\n}\r\n\r\n.transcription-content {\r\n font-size: 16px;\r\n line-height: 1.5;\r\n color: #fff;\r\n font-weight: 500;\r\n margin: 0;\r\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\r\n}\r\n\r\n.placeholder-text {\r\n font-size: 16px;\r\n color: rgba(255, 255, 255, 0.3);\r\n font-style: italic;\r\n margin: 0;\r\n}\r\n\r\n/* --- State: Wake --- */\r\n.mode-wake {\r\n border-color: rgba($c-wake, 0.3);\r\n\r\n .ambient-glow {\r\n background: $c-wake;\r\n opacity: 0.2;\r\n }\r\n\r\n .icon-core {\r\n background: linear-gradient(135deg, rgba($c-wake, 0.2), rgba($c-wake, 0.1));\r\n border-color: rgba($c-wake, 0.4);\r\n box-shadow: 0 0 15px rgba($c-wake, 0.2);\r\n\r\n .mic-icon {\r\n color: color.adjust($c-wake, $lightness: 10%);\r\n }\r\n }\r\n\r\n .status-dot {\r\n color: $c-wake;\r\n animation: pulse-dot 2s infinite;\r\n }\r\n\r\n .ripple {\r\n border-color: $c-wake;\r\n animation: ripple-out 3s infinite;\r\n\r\n &.delay-1 {\r\n animation-delay: 0s;\r\n }\r\n &.delay-2 {\r\n animation-delay: 1s;\r\n }\r\n &.delay-3 {\r\n animation-delay: 2s;\r\n }\r\n }\r\n}\r\n\r\n/* --- State: Transcribing --- */\r\n.mode-transcribing {\r\n border-color: rgba($c-transcribe, 0.3);\r\n\r\n .ambient-glow {\r\n background: $c-transcribe;\r\n opacity: 0.3;\r\n animation: glow-breathe 1.5s ease-in-out infinite alternate;\r\n }\r\n\r\n .icon-core {\r\n background: linear-gradient(135deg, rgba($c-transcribe, 0.3), rgba($c-transcribe, 0.1));\r\n border-color: rgba($c-transcribe, 0.5);\r\n box-shadow: 0 0 20px rgba($c-transcribe, 0.3);\r\n transform: scale(1.1);\r\n\r\n .mic-icon {\r\n color: #fff;\r\n\r\n .mic-capsule {\r\n animation: mic-bounce 0.6s ease-in-out infinite alternate;\r\n }\r\n }\r\n }\r\n\r\n .status-dot {\r\n color: $c-transcribe;\r\n }\r\n\r\n .ripple {\r\n border-color: $c-transcribe;\r\n animation: ripple-rapid 1.5s infinite;\r\n\r\n &.delay-1 {\r\n animation-delay: 0s;\r\n }\r\n &.delay-2 {\r\n animation-delay: 0.3s;\r\n }\r\n &.delay-3 {\r\n animation-delay: 0.6s;\r\n }\r\n }\r\n}\r\n\r\n/* --- Animations --- */\r\n@keyframes ripple-out {\r\n 0% {\r\n transform: scale(0.8);\r\n opacity: 0;\r\n border-width: 2px;\r\n }\r\n 20% {\r\n opacity: 0.5;\r\n }\r\n 100% {\r\n transform: scale(2.2);\r\n opacity: 0;\r\n border-width: 0px;\r\n }\r\n}\r\n\r\n@keyframes ripple-rapid {\r\n 0% {\r\n transform: scale(0.9);\r\n opacity: 0;\r\n }\r\n 50% {\r\n opacity: 0.4;\r\n }\r\n 100% {\r\n transform: scale(1.6);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n@keyframes pulse-dot {\r\n 0%,\r\n 100% {\r\n opacity: 1;\r\n transform: scale(1);\r\n }\r\n 50% {\r\n opacity: 0.5;\r\n transform: scale(0.8);\r\n }\r\n}\r\n\r\n@keyframes glow-breathe {\r\n 0% {\r\n opacity: 0.2;\r\n transform: scale(0.9);\r\n }\r\n 100% {\r\n opacity: 0.4;\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n@keyframes mic-bounce {\r\n 0% {\r\n transform: scaleY(1);\r\n }\r\n 100% {\r\n transform: scaleY(0.7);\r\n }\r\n}\r\n\r\n/* --- Vue Transitions --- */\r\n.voice-panel-enter-active,\r\n.voice-panel-leave-active {\r\n transition: all 0.4s $ease-elastic;\r\n}\r\n.voice-panel-enter-from,\r\n.voice-panel-leave-to {\r\n opacity: 0;\r\n transform: translateY(20px) scale(0.95);\r\n}\r\n\r\n.fade-slide-enter-active,\r\n.fade-slide-leave-active {\r\n transition: all 0.3s ease;\r\n}\r\n.fade-slide-enter-from {\r\n opacity: 0;\r\n transform: translateY(10px);\r\n}\r\n.fade-slide-leave-to {\r\n opacity: 0;\r\n transform: translateY(-10px);\r\n}\r\n</style>\r\n","<template>\r\n <transition name=\"exec-bubble\">\r\n <div v-if=\"visible\" class=\"execution-bubble\">\r\n <!-- 文本内容 -->\r\n <span class=\"exec-text\">{{ text || '执行中' }}</span>\r\n <!-- 三点加载动画 -->\r\n <div class=\"loading-dots\">\r\n <span class=\"dot\"></span>\r\n <span class=\"dot\"></span>\r\n <span class=\"dot\"></span>\r\n </div>\r\n </div>\r\n </transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\ndefineProps<{\r\n visible: boolean;\r\n text?: string;\r\n}>();\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n$c-exec: #a855f7;\r\n$c-exec-light: #c084fc;\r\n$bg-glass: rgba(15, 23, 42, 0.9);\r\n$ease-smooth: cubic-bezier(0.25, 0.8, 0.25, 1);\r\n\r\n.execution-bubble {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 12px 20px;\r\n background: $bg-glass;\r\n backdrop-filter: blur(16px);\r\n -webkit-backdrop-filter: blur(16px);\r\n border: 1px solid rgba($c-exec, 0.35);\r\n border-radius: 20px;\r\n box-shadow:\r\n 0 4px 20px rgba(0, 0, 0, 0.3),\r\n 0 0 20px -5px rgba($c-exec, 0.3),\r\n inset 0 1px 0 rgba(255, 255, 255, 0.08);\r\n}\r\n\r\n/* 文本样式 */\r\n.exec-text {\r\n font-size: 14px;\r\n font-weight: 500;\r\n color: rgba(255, 255, 255, 0.9);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n max-width: 300px;\r\n}\r\n\r\n/* 三点加载动画 */\r\n.loading-dots {\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n margin-left: 10px;\r\n}\r\n\r\n.dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: $c-exec-light;\r\n animation: dot-bounce 1.4s ease-in-out infinite;\r\n\r\n &:nth-child(1) {\r\n animation-delay: 0s;\r\n }\r\n &:nth-child(2) {\r\n animation-delay: 0.2s;\r\n }\r\n &:nth-child(3) {\r\n animation-delay: 0.4s;\r\n }\r\n}\r\n\r\n@keyframes dot-bounce {\r\n 0%,\r\n 80%,\r\n 100% {\r\n transform: scale(0.6);\r\n opacity: 0.4;\r\n }\r\n 40% {\r\n transform: scale(1);\r\n opacity: 1;\r\n box-shadow: 0 0 8px rgba($c-exec-light, 0.6);\r\n }\r\n}\r\n\r\n/* Vue 过渡动画 */\r\n.exec-bubble-enter-active {\r\n transition: all 0.3s $ease-smooth;\r\n}\r\n\r\n.exec-bubble-leave-active {\r\n transition: all 0.2s $ease-smooth;\r\n}\r\n\r\n.exec-bubble-enter-from {\r\n opacity: 0;\r\n transform: scale(0.8);\r\n}\r\n\r\n.exec-bubble-leave-to {\r\n opacity: 0;\r\n transform: scale(0.8);\r\n}\r\n</style>\r\n","import { DiscoveredCommand } from '@siact/sime-bridge'\r\n\r\nexport const ensureMicrophonePermission = async () => {\r\n // 检查浏览器环境\r\n if (typeof navigator === 'undefined' || typeof window === 'undefined') {\r\n console.log('当前环境不支持麦克风访问');\r\n return false;\r\n }\r\n\r\n // 检查 MediaDevices API 支持\r\n if (!navigator.mediaDevices?.getUserMedia || !navigator.mediaDevices?.enumerateDevices) {\r\n console.log('当前环境不支持麦克风访问');\r\n return false;\r\n }\r\n\r\n try {\r\n // 1. 首先枚举设备,检查是否有音频输入设备\r\n const devices = await navigator.mediaDevices.enumerateDevices();\r\n const audioInputDevices = devices.filter((device) => device.kind === 'audioinput');\r\n\r\n if (audioInputDevices.length === 0) {\r\n console.log('未检测到麦克风设备,请连接麦克风后重试。');\r\n return false;\r\n }\r\n\r\n // 2. 检查权限状态(如果浏览器支持)\r\n if ('permissions' in navigator && navigator.permissions?.query) {\r\n try {\r\n const status = await navigator.permissions.query({ name: 'microphone' as PermissionName });\r\n\r\n if (status.state === 'denied') {\r\n console.log('麦克风权限被禁用,请在浏览器设置中开启。');\r\n return false;\r\n }\r\n } catch (e) {\r\n // 某些浏览器可能不支持 microphone 权限查询,继续执行\r\n console.warn('Permission query not supported:', e);\r\n }\r\n }\r\n\r\n // 3. 尝试获取麦克风流以确认权限和设备可用性\r\n let stream: MediaStream | null = null;\r\n try {\r\n stream = await navigator.mediaDevices.getUserMedia({\r\n audio: {\r\n echoCancellation: true,\r\n noiseSuppression: true,\r\n autoGainControl: true,\r\n },\r\n });\r\n\r\n // 检查流是否有活动的音频轨道\r\n const audioTracks = stream.getAudioTracks();\r\n if (audioTracks.length === 0) {\r\n console.log('无法获取麦克风音频轨道。');\r\n return false;\r\n }\r\n\r\n // 检查音频轨道是否启用且可读\r\n const activeTrack = audioTracks[0];\r\n if (!activeTrack.enabled || activeTrack.readyState !== 'live') {\r\n console.log('麦克风设备不可用,请检查设备连接。');\r\n return false;\r\n }\r\n\r\n return true;\r\n } finally {\r\n // 确保释放流资源\r\n if (stream) {\r\n stream.getTracks().forEach((track) => track.stop());\r\n }\r\n }\r\n } catch (error: any) {\r\n console.error('Microphone permission check failed', error);\r\n\r\n // 根据错误类型提供更具体的提示\r\n if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {\r\n console.log('未检测到麦克风设备,请连接麦克风后重试。');\r\n } else if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {\r\n console.log('麦克风权限被拒绝,请在浏览器设置中允许访问。');\r\n } else if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {\r\n console.log('麦克风被其他应用占用或无法访问。');\r\n } else {\r\n console.log('无法访问麦克风,请检查设备连接和浏览器权限。');\r\n }\r\n\r\n return false;\r\n }\r\n};\r\n\r\n\r\n/**\r\n * 语音命令匹配函数\r\n * @param {string} userInput - 用户输入的原始语音文本\r\n * @param {Array} commandList - 命令列表对象数组\r\n * @param {number} threshold - 相似度阈值 (0-1),默认 0.5\r\n */\r\nexport function matchVoiceCommand(userInput: string, commandList: DiscoveredCommand[], threshold = 0.5) {\r\n if (!userInput || typeof userInput !== 'string') return null;\r\n\r\n // 1. 预处理:转小写、去空格、去标点、去语气词\r\n const cleanInput = userInput\r\n .trim()\r\n .toLowerCase()\r\n // 1. 去除所有标点符号及特殊字符\r\n .replace(/[,。?!;:、“”()()<>《》\\s\\.\\,\\?\\!]/g, '')\r\n // 2. 去除常见的前缀 (增加“给我”、“能不能”等)\r\n .replace(/^(请帮我|我想|帮我|麻烦|我要|你好|您好|帮我把|给我|能不能帮我|请问|那个)/g, '')\r\n // 3. 去除中间的动作虚词 (如“把...给...”)\r\n .replace(/给(?=(打开|开启|关闭|停止))/g, '')\r\n // 4. 去除常见的后缀 (增加“就可以了”、“就行”、“模式”)\r\n .replace(/(一下|了|吧|输出|就可以了|就行|模式|操作|功能)$/g, '');\r\n\r\n let bestMatch = null;\r\n let maxScore = 0;\r\n\r\n // 编辑距离算法 (Levenshtein Distance)\r\n const getSimilarity = (s1: string, s2: string) => {\r\n const [l1, l2] = [s1.length, s2.length];\r\n const matrix = Array.from({ length: l1 + 1 }, () => Array(l2 + 1).fill(0));\r\n for (let i = 0; i <= l1; i++) matrix[i][0] = i;\r\n for (let j = 0; j <= l2; j++) matrix[0][j] = j;\r\n\r\n for (let i = 1; i <= l1; i++) {\r\n for (let j = 1; j <= l2; j++) {\r\n const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;\r\n matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);\r\n }\r\n }\r\n return 1 - matrix[l1][l2] / Math.max(l1, l2);\r\n };\r\n\r\n // 2. 遍历命令列表进行比对\r\n for (const cmd of commandList) {\r\n const target = cmd.description.toLowerCase();\r\n let currentScore = 0;\r\n\r\n // 策略 A:直接包含 (如输入“帮我开启漫游吧”,描述是“开启漫游”)\r\n if (cleanInput.includes(target) || target.includes(cleanInput)) {\r\n // 计算包含关系的得分,越接近 1 分越高\r\n currentScore = Math.min(target.length, cleanInput.length) / Math.max(target.length, cleanInput.length);\r\n // 给予包含匹配更高的基础权重\r\n currentScore = 0.8 + currentScore * 0.2;\r\n }\r\n // 策略 B:模糊匹配 (处理同音字错误,如“开启慢游”)\r\n else {\r\n currentScore = getSimilarity(cleanInput, target);\r\n }\r\n\r\n // 更新最高分项\r\n if (currentScore > maxScore) {\r\n maxScore = currentScore;\r\n bestMatch = { ...cmd, confidence: maxScore };\r\n }\r\n }\r\n\r\n // 3. 结果过滤\r\n return maxScore >= threshold ? bestMatch : null;\r\n}","<template>\r\n <div class=\"sime-x\" :data-theme=\"currentTheme\">\r\n <!-- 悬浮按钮(最小化状态) -->\r\n <transition name=\"fade\">\r\n <div ref=\"fabRef\" class=\"assistant-fab\" @click=\"toggleDialog(!visible)\">\r\n <VoiceStatus\r\n v-if=\"!isProcessing\"\r\n class=\"voice-status\"\r\n :status=\"voiceStatus\"\r\n :transcription-text=\"transcriptionText\"\r\n :is-transcribing=\"isTranscribing\"\r\n style=\"width: 480px\"\r\n />\r\n <ExecutionStatus v-else class=\"voice-status\" :visible=\"isProcessing\" :text=\"transcriptionText\" />\r\n <div class=\"fab-avatar-wrapper\">\r\n <img\r\n :src=\"xLogo ? xLogo : '/sime.png'\"\r\n alt=\"assistant\"\r\n :style=\"{\r\n width: xSize?.width + 'px',\r\n }\"\r\n />\r\n <!-- 优化后的监听状态指示器 -->\r\n <transition name=\"indicator-fade\">\r\n <div v-if=\"voiceStatus === 'listening'\" class=\"listening-badge\" :class=\"{ 'wake-active': wakeAnimating }\">\r\n <div class=\"listening-waves\">\r\n <div class=\"wave wave-1\"></div>\r\n <div class=\"wave wave-2\"></div>\r\n <div class=\"wave wave-3\"></div>\r\n </div>\r\n <div class=\"listening-icon\">\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z\"\r\n fill=\"currentColor\"\r\n />\r\n <path\r\n d=\"M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n <div class=\"fab-pulse\" :class=\"{ active: voiceStatus === 'listening' }\"></div>\r\n </div>\r\n </transition>\r\n\r\n <!-- 弹窗 -->\r\n <transition name=\"dialog-fade\">\r\n <div\r\n ref=\"dialogRef\"\r\n class=\"x-dialog-container\"\r\n :class=\"{\r\n collapsed: isCollapsed,\r\n 'is-hidden': !visible,\r\n 'position-ready': positionReady,\r\n }\"\r\n :style=\"{\r\n width: containerWidth + 'px',\r\n height: isCollapsed ? 'auto' : containerHeight + 'px',\r\n border: currentTheme === 'light' && !isCollapsed ? '1px solid var(--border-color)' : 'none',\r\n '--dialog-x': position.x + 'px',\r\n '--dialog-y': position.y + 'px',\r\n }\"\r\n @mousedown=\"startDrag\"\r\n >\r\n <div class=\"x-dialog-header\" @mousedown.stop=\"startDrag\">\r\n <div class=\"header-left\">\r\n <div class=\"logo-icon\">\r\n <img :src=\"xLogo ? xLogo : '/sime.png'\" alt=\"assistant\" class=\"logo\" />\r\n </div>\r\n <span class=\"title\">{{ xTitle }}</span>\r\n </div>\r\n <div class=\"actions\">\r\n <button class=\"action-btn theme-btn\" title=\"开启新对话\" @click=\"startNewConversation\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M12 5v14M5 12h14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </button>\r\n <button\r\n class=\"action-btn theme-btn\"\r\n :class=\"{\r\n active: voiceStatus !== 'standby',\r\n listening: voiceStatus === 'listening',\r\n woke: voiceStatus === 'wake',\r\n }\"\r\n @click.stop=\"() => toggleVoiceMode()\"\r\n :title=\"voiceButtonTooltip\"\r\n >\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n d=\"M12 15C13.6569 15 15 13.6569 15 12V7C15 5.34315 13.6569 4 12 4C10.3431 4 9 5.34315 9 7V12C9 13.6569 10.3431 15 12 15Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M18 11C18 14.3137 15.3137 17 12 17C8.68629 17 6 14.3137 6 11\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M12 19V17\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M9 21H15\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n <span class=\"voice-indicator\" v-if=\"voiceStatus !== 'standby'\"></span>\r\n </button>\r\n <button class=\"action-btn theme-btn\" @click.stop=\"cycleTheme\" :title=\"themeTooltip\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <circle cx=\"12\" cy=\"12\" r=\"7\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n <path d=\"M12 5A7 7 0 1 1 12 19\" fill=\"currentColor\" />\r\n </svg>\r\n </button>\r\n <button class=\"action-btn collapse-btn\" @click.stop=\"toggleCollapse\" :title=\"isCollapsed ? '展开' : '折叠'\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n :d=\"isCollapsed ? 'M18 15L12 9L6 15' : 'M6 9L12 15L18 9'\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n <button class=\"action-btn minimize-btn\" @click.stop=\"toggleDialog(false)\" title=\"最小化\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M5 12H19\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n <div :class=\"['x-dialog-content', { 'is-hidden': isCollapsed }]\" :style=\"{ opacity: isCollapsed ? 0 : 1 }\">\r\n <iframe\r\n ref=\"iframeRef\"\r\n :src=\"chatbotUrl\"\r\n class=\"x-iframe\"\r\n allow=\"microphone *; storage-access *; camera *\"\r\n frameborder=\"0\"\r\n @load=\"handleIframeLoad\"\r\n ></iframe>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, onBeforeUnmount, computed, nextTick, watch } from 'vue';\r\nimport VoiceStatus from './voice-status.vue';\r\nimport ExecutionStatus from './execution-status.vue';\r\nimport { injectStrict, AiChatbotXKey } from '../injection-key';\r\nimport { WakeWordDetectorStandalone, SpeechTranscriberStandalone } from 'web-voice-kit';\r\nimport { ensureMicrophonePermission, matchVoiceCommand } from '../lib/utils';\r\n\r\ninterface XSize {\r\n width: number;\r\n height: number;\r\n}\r\ninterface xDialogSize {\r\n width: number;\r\n height: number;\r\n}\r\n\r\nconst props = defineProps<{\r\n xLogo?: string;\r\n xSize?: XSize;\r\n xTitle?: string;\r\n xTheme?: 'light' | 'dark' | 'system';\r\n xDialogSize?: xDialogSize;\r\n wakeWords?: string[];\r\n modelPath?: string;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n (e: 'start-transcribing'): void;\r\n (e: 'stop-transcribing'): void;\r\n (e: 'wakeUp', isWake: boolean): void;\r\n}>();\r\n\r\nconst aiChatbotX = injectStrict(AiChatbotXKey);\r\n\r\nconst chatbotUrl = ref('');\r\nconst voiceStatus = ref<'wake' | 'listening' | 'standby'>('standby');\r\nconst wakeAnimating = ref(false);\r\nconst wakeResponses = ['在呢', '在的', '我在', '您好', '在呢,请说'];\r\nconst transcriptionText = ref<string>('');\r\nconst isTranscribing = ref(false);\r\nconst isProcessing = ref(false);\r\nconst visible = ref(false);\r\nconst isCollapsed = ref(false);\r\nconst fabRef = ref<HTMLElement | null>(null);\r\nconst positionReady = ref(false);\r\n\r\nlet detector: WakeWordDetectorStandalone | null = null;\r\nlet transcriber: SpeechTranscriberStandalone | null = null;\r\n\r\nconst isInitializing = ref(false);\r\nconst initError = ref<string>('');\r\n\r\n// 获取系统主题\r\nconst getSystemTheme = (): 'light' | 'dark' => {\r\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n};\r\nconst currentTheme = ref<'light' | 'dark'>(props.xTheme === 'system' ? getSystemTheme() : props.xTheme || 'light');\r\n\r\n// 切换主题\r\nconst cycleTheme = async () => {\r\n currentTheme.value = currentTheme.value === 'light' ? 'dark' : 'light';\r\n aiChatbotX.setTheme(currentTheme.value);\r\n};\r\n\r\n// 开启新对话\r\nconst startNewConversation = () => {\r\n aiChatbotX.startNewConversation();\r\n};\r\n\r\nconst themeTooltip = computed(() => (currentTheme.value === 'light' ? '切换到深色模式' : '切换到浅色模式'));\r\n\r\nconst voiceButtonTooltip = computed(() => {\r\n if (isInitializing.value) return '初始化中...';\r\n if (initError.value) return `错误: ${initError.value}`;\r\n\r\n switch (voiceStatus.value) {\r\n case 'standby':\r\n return '开启语音监听';\r\n case 'listening':\r\n return '监听中,等待唤醒词...';\r\n case 'wake':\r\n return '已唤醒!';\r\n default:\r\n return '语音监听';\r\n }\r\n});\r\n\r\nif (props.xTheme === 'system') {\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n const handleThemeChange = (e: MediaQueryListEvent) => {\r\n currentTheme.value = e.matches ? 'dark' : 'light';\r\n };\r\n mediaQuery.addEventListener('change', handleThemeChange);\r\n onBeforeUnmount(() => {\r\n mediaQuery.removeEventListener('change', handleThemeChange);\r\n });\r\n}\r\n\r\n// 初始化语音监听器\r\nconst initVoiceDetector = () => {\r\n if (detector || isInitializing.value) return;\r\n\r\n isInitializing.value = true;\r\n initError.value = '';\r\n\r\n if (!props.modelPath) {\r\n initError.value = '未提供语音模型文件';\r\n isInitializing.value = false;\r\n return;\r\n }\r\n\r\n try {\r\n detector = new WakeWordDetectorStandalone({\r\n modelPath: props.modelPath,\r\n sampleRate: 16000,\r\n usePartial: true,\r\n autoReset: {\r\n enabled: true,\r\n resetDelayMs: 5000,\r\n },\r\n });\r\n\r\n const wakeWords = props.wakeWords || ['你好', '您好'];\r\n detector.setWakeWords(wakeWords);\r\n\r\n detector.onWake(() => {\r\n console.log('[VoiceDetector] 检测到唤醒词');\r\n // 触发唤醒动画\r\n wakeAnimating.value = true;\r\n // 语音播报回应\r\n playWakeResponse();\r\n // 通知 web 端\r\n emit('wakeUp', true);\r\n aiChatbotX.weak();\r\n aiChatbotX.openDialog();\r\n // 动画结束后恢复\r\n setTimeout(() => {\r\n wakeAnimating.value = false;\r\n }, 1500);\r\n // 保持 listening 状态,继续后台唤醒监听\r\n voiceStatus.value = 'listening';\r\n });\r\n\r\n detector.onError((error: any) => {\r\n console.error('[VoiceDetector] 错误:', error);\r\n initError.value = error.message;\r\n voiceStatus.value = 'standby';\r\n isTranscribing.value = false;\r\n\r\n if (error.message.includes('permission')) {\r\n transcriptionText.value = '需要麦克风权限';\r\n } else if (error.message.includes('model')) {\r\n transcriptionText.value = '模型加载失败';\r\n } else {\r\n transcriptionText.value = '初始化失败';\r\n }\r\n\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n }, 3000);\r\n });\r\n\r\n console.log('[VoiceDetector] 初始化成功');\r\n } catch (error) {\r\n console.error('[VoiceDetector] 初始化失败:', error);\r\n initError.value = error instanceof Error ? error.message : '初始化失败';\r\n voiceStatus.value = 'standby';\r\n isTranscribing.value = false;\r\n } finally {\r\n isInitializing.value = false;\r\n }\r\n};\r\n\r\n// 语音播报唤醒回应(使用 Web Speech Synthesis API,无需音频文件)\r\nconst playWakeResponse = () => {\r\n try {\r\n if (typeof window === 'undefined' || !window.speechSynthesis) {\r\n console.warn('[TTS] SpeechSynthesis API 不可用');\r\n return;\r\n }\r\n const text = wakeResponses[Math.floor(Math.random() * wakeResponses.length)];\r\n const utterance = new SpeechSynthesisUtterance(text);\r\n utterance.lang = 'zh-CN';\r\n utterance.rate = 1.0;\r\n utterance.pitch = 0.8;\r\n utterance.volume = 0.9;\r\n // 优先选择中文男声\r\n const voices = window.speechSynthesis.getVoices();\r\n const maleVoice = voices.find((v) => v.lang.startsWith('zh') && /male|男/i.test(v.name));\r\n const zhVoice = maleVoice || voices.find((v) => v.lang.startsWith('zh'));\r\n if (zhVoice) {\r\n utterance.voice = zhVoice;\r\n }\r\n window.speechSynthesis.speak(utterance);\r\n } catch (error) {\r\n console.error('[TTS] 播报失败:', error);\r\n }\r\n};\r\n\r\n// 初始化转写器\r\nfunction initTranscriber() {\r\n if (transcriber) return;\r\n\r\n try {\r\n const { appId, apiKey, websocketUrl } = aiChatbotX.voiceConfig();\r\n if (!appId || !apiKey || !websocketUrl) {\r\n initError.value = '未配置语音配置';\r\n voiceStatus.value = 'standby';\r\n isTranscribing.value = false;\r\n return;\r\n }\r\n transcriber = new SpeechTranscriberStandalone({\r\n appId,\r\n apiKey,\r\n websocketUrl,\r\n autoStop: {\r\n enabled: true,\r\n silenceTimeoutMs: 3000,\r\n noSpeechTimeoutMs: 5000,\r\n maxDurationMs: 60000,\r\n },\r\n });\r\n\r\n transcriber.onResult((result) => {\r\n transcriptionText.value = result.transcript;\r\n });\r\n\r\n transcriber.onAutoStop(async () => {\r\n console.log('[Transcriber] Auto Stop');\r\n\r\n // 保存当前转写文本,用于后续处理\r\n const currentText = transcriptionText.value;\r\n\r\n // 停止转写\r\n await stopTranscribing();\r\n\r\n // 如果没有转写内容,直接返回后台监听\r\n if (!currentText || !currentText.trim()) {\r\n console.log('[Transcriber] No transcription text, returning to listening');\r\n transcriptionText.value = '';\r\n voiceStatus.value = 'listening';\r\n return;\r\n }\r\n\r\n // 进入处理中状态,显示优雅的等待动画\r\n isProcessing.value = true;\r\n transcriptionText.value = currentText; // 保持显示用户说的内容\r\n\r\n try {\r\n const commands = await aiChatbotX.hostCommads();\r\n const result = await aiChatbotX.recognition(currentText, commands);\r\n\r\n // 如果是命令类型,执行匹配的命令\r\n if (result?.data?.intent === 'command' && result?.data?.matchedCommands) {\r\n const matchedCommands = result.data.matchedCommands;\r\n\r\n for (const cmd of matchedCommands) {\r\n try {\r\n // 将参数对象转换为参数数组\r\n const args = cmd.parameters ? Object.values(cmd.parameters) : [];\r\n\r\n // 执行宿主命令\r\n const cmdResult = await aiChatbotX.executeCommand(cmd.name, args);\r\n console.log(`Command ${cmd.name} executed successfully:`, cmdResult);\r\n } catch (error) {\r\n console.error(`Failed to execute command ${cmd.name}:`, error);\r\n }\r\n }\r\n } else {\r\n aiChatbotX.appendMessage(currentText);\r\n toggleDialog(true);\r\n }\r\n } finally {\r\n // 处理完成,返回后台监听状态\r\n isProcessing.value = false;\r\n transcriptionText.value = '';\r\n voiceStatus.value = 'listening';\r\n }\r\n });\r\n\r\n transcriber.onError((error) => {\r\n console.error('[Transcriber] Error:', error);\r\n stopTranscribing();\r\n transcriptionText.value = '转写错误';\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n voiceStatus.value = 'listening';\r\n }, 2000);\r\n });\r\n\r\n console.log('[Transcriber] 初始化成功');\r\n } catch (error) {\r\n console.error('[Transcriber] 初始化失败:', error);\r\n voiceStatus.value = 'standby';\r\n initError.value = error instanceof Error ? error.message : '转写初始化失败';\r\n }\r\n}\r\n\r\nconst startTranscribing = async () => {\r\n if (!transcriber) {\r\n initTranscriber();\r\n if (!transcriber) return;\r\n }\r\n\r\n try {\r\n emit('start-transcribing');\r\n await transcriber.start();\r\n isTranscribing.value = true;\r\n transcriptionText.value = '';\r\n } catch (error) {\r\n console.error('[Transcriber] 启动失败:', error);\r\n transcriptionText.value = '转写启动失败';\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n }, 2000);\r\n }\r\n};\r\n\r\nconst stopTranscribing = async () => {\r\n if (transcriber && transcriber.isActive()) {\r\n try {\r\n await transcriber.stop();\r\n isTranscribing.value = false;\r\n emit('stop-transcribing');\r\n } catch (error) {\r\n console.error('[Transcriber] 停止失败:', error);\r\n }\r\n }\r\n};\r\n\r\nconst toggleVoiceMode = async (targetState?: boolean) => {\r\n const permission = await ensureMicrophonePermission();\r\n if (!permission) return;\r\n\r\n if (isInitializing.value) return;\r\n\r\n if (!detector) {\r\n await initVoiceDetector();\r\n if (!detector) return;\r\n }\r\n\r\n // 核心逻辑:如果传了参数,目标就是参数值;如果不传,目标就是当前状态的反值\r\n // 假设 \"listening\" 为开启状态,其余(如 \"standby\")为关闭状态\r\n const isCurrentlyListening = voiceStatus.value === 'listening';\r\n const shouldStart = targetState !== undefined ? targetState : !isCurrentlyListening;\r\n\r\n // 如果当前状态已经符合目标状态,直接返回(防止重复开启或关闭)\r\n if (shouldStart === isCurrentlyListening) return;\r\n\r\n try {\r\n if (shouldStart) {\r\n // 执行开启逻辑\r\n console.log('[VoiceDetector] 强制/自动启动监听...');\r\n await detector.start();\r\n voiceStatus.value = 'listening';\r\n transcriptionText.value = '';\r\n isTranscribing.value = false;\r\n } else {\r\n // 执行关闭逻辑\r\n console.log('[VoiceDetector] 强制/自动停止监听...');\r\n await detector.stop();\r\n stopTranscribing();\r\n voiceStatus.value = 'standby';\r\n transcriptionText.value = '';\r\n isTranscribing.value = false;\r\n }\r\n } catch (error) {\r\n console.error('[VoiceDetector] 操作失败:', error);\r\n voiceStatus.value = 'standby';\r\n transcriptionText.value = '操作失败';\r\n isTranscribing.value = false;\r\n\r\n setTimeout(() => {\r\n transcriptionText.value = '';\r\n }, 2000);\r\n }\r\n};\r\n\r\nconst position = reactive({ x: 0, y: 0 });\r\nconst containerWidth = ref(props.xDialogSize?.width || 420);\r\nconst containerHeight = ref(props.xDialogSize?.height || 600);\r\nconst isFirstOpen = ref(true);\r\nconst FAB_SAFE_GAP = 24;\r\n\r\nconst validatePosition = (x: number, y: number, width: number, height: number) => {\r\n const margin = 20;\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n\r\n const maxX = viewportWidth - width - margin;\r\n const maxY = viewportHeight - height - margin;\r\n\r\n return {\r\n x: Math.max(margin, Math.min(x, maxX)),\r\n y: Math.max(margin, Math.min(y, maxY)),\r\n };\r\n};\r\n\r\nconst getOverlapArea = (\r\n rectA: { left: number; right: number; top: number; bottom: number },\r\n rectB: { left: number; right: number; top: number; bottom: number },\r\n) => {\r\n const overlapX = Math.max(0, Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left));\r\n const overlapY = Math.max(0, Math.min(rectA.bottom, rectB.bottom) - Math.max(rectA.top, rectB.top));\r\n return overlapX * overlapY;\r\n};\r\n\r\nconst keepDistanceFromFab = (x: number, y: number, width: number, height: number) => {\r\n if (!fabRef.value) return { x, y };\r\n\r\n const fabRect = fabRef.value.getBoundingClientRect();\r\n const safeFabRect = {\r\n left: fabRect.left - FAB_SAFE_GAP,\r\n right: fabRect.right + FAB_SAFE_GAP,\r\n top: fabRect.top - FAB_SAFE_GAP,\r\n bottom: fabRect.bottom + FAB_SAFE_GAP,\r\n };\r\n\r\n const candidates = [\r\n { x, y },\r\n { x: safeFabRect.left - width - FAB_SAFE_GAP, y },\r\n { x: safeFabRect.right + FAB_SAFE_GAP, y },\r\n { x, y: safeFabRect.top - height - FAB_SAFE_GAP },\r\n { x, y: safeFabRect.bottom + FAB_SAFE_GAP },\r\n ];\r\n\r\n let best = validatePosition(candidates[0].x, candidates[0].y, width, height);\r\n let bestOverlap = getOverlapArea(\r\n { left: best.x, right: best.x + width, top: best.y, bottom: best.y + height },\r\n safeFabRect,\r\n );\r\n\r\n for (let i = 1; i < candidates.length; i++) {\r\n const validated = validatePosition(candidates[i].x, candidates[i].y, width, height);\r\n const overlap = getOverlapArea(\r\n { left: validated.x, right: validated.x + width, top: validated.y, bottom: validated.y + height },\r\n safeFabRect,\r\n );\r\n\r\n if (overlap < bestOverlap) {\r\n best = validated;\r\n bestOverlap = overlap;\r\n if (overlap === 0) break;\r\n }\r\n }\r\n\r\n return best;\r\n};\r\n\r\nconst calculateInitialPosition = () => {\r\n if (!fabRef.value) return;\r\n\r\n const fabRect = fabRef.value.getBoundingClientRect();\r\n const dialogWidth = containerWidth.value;\r\n const dialogHeight = containerHeight.value;\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n const margin = 20; // 增加间距,确保不遮挡\r\n const minMargin = 20; // 最小边距\r\n\r\n let x = 0;\r\n let y = 0;\r\n\r\n // 优先尝试在 FAB 左侧定位\r\n const leftX = fabRect.left - dialogWidth - margin;\r\n\r\n if (leftX >= minMargin) {\r\n // 左侧有足够空间\r\n x = leftX;\r\n // Y 轴对齐 FAB 顶部,但确保不超出视口\r\n y = fabRect.top;\r\n\r\n // 如果对话框底部超出视口,向上调整\r\n if (y + dialogHeight > viewportHeight - minMargin) {\r\n y = viewportHeight - dialogHeight - minMargin;\r\n }\r\n // 确保顶部不超出\r\n if (y < minMargin) {\r\n y = minMargin;\r\n }\r\n } else {\r\n // 左侧空间不足,尝试右侧\r\n const rightX = fabRect.right + margin;\r\n\r\n if (rightX + dialogWidth <= viewportWidth - minMargin) {\r\n // 右侧有足够空间\r\n x = rightX;\r\n y = fabRect.top;\r\n\r\n // Y 轴调整\r\n if (y + dialogHeight > viewportHeight - minMargin) {\r\n y = viewportHeight - dialogHeight - minMargin;\r\n }\r\n if (y < minMargin) {\r\n y = minMargin;\r\n }\r\n } else {\r\n // 左右都不够,居中显示,并确保不遮挡 FAB\r\n x = (viewportWidth - dialogWidth) / 2;\r\n\r\n // 尝试在 FAB 上方\r\n const aboveY = fabRect.top - dialogHeight - margin;\r\n if (aboveY >= minMargin) {\r\n y = aboveY;\r\n } else {\r\n // 在 FAB 下方\r\n const belowY = fabRect.bottom + margin;\r\n if (belowY + dialogHeight <= viewportHeight - minMargin) {\r\n y = belowY;\r\n } else {\r\n // 垂直居中\r\n y = (viewportHeight - dialogHeight) / 2;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 最终验证位置\r\n const validated = validatePosition(x, y, dialogWidth, dialogHeight);\r\n const separated = keepDistanceFromFab(validated.x, validated.y, dialogWidth, dialogHeight);\r\n position.x = separated.x;\r\n position.y = separated.y;\r\n};\r\n\r\nconst toggleCollapse = async () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n\r\n nextTick(() => {\r\n const currentHeight = isCollapsed.value ? 60 : containerHeight.value;\r\n const validated = validatePosition(position.x, position.y, containerWidth.value, currentHeight);\r\n const separated = keepDistanceFromFab(validated.x, validated.y, containerWidth.value, currentHeight);\r\n position.x = separated.x;\r\n position.y = separated.y;\r\n });\r\n};\r\n\r\nconst drag = reactive({\r\n isDragging: false,\r\n startX: 0,\r\n startY: 0,\r\n offsetX: 0,\r\n offsetY: 0,\r\n});\r\n\r\nconst startDrag = (e: MouseEvent) => {\r\n drag.isDragging = true;\r\n drag.startX = e.clientX;\r\n drag.startY = e.clientY;\r\n drag.offsetX = position.x;\r\n drag.offsetY = position.y;\r\n document.addEventListener('mousemove', onDrag);\r\n document.addEventListener('mouseup', stopDrag);\r\n};\r\n\r\nconst onDrag = (e: MouseEvent) => {\r\n if (!drag.isDragging) return;\r\n\r\n const newX = drag.offsetX + (e.clientX - drag.startX);\r\n const newY = drag.offsetY + (e.clientY - drag.startY);\r\n\r\n const validated = validatePosition(newX, newY, containerWidth.value, isCollapsed.value ? 60 : containerHeight.value);\r\n\r\n position.x = validated.x;\r\n position.y = validated.y;\r\n};\r\n\r\nconst stopDrag = () => {\r\n drag.isDragging = false;\r\n document.removeEventListener('mousemove', onDrag);\r\n document.removeEventListener('mouseup', stopDrag);\r\n};\r\n\r\nconst toggleDialog = async (state: boolean) => {\r\n if (state) {\r\n visible.value = true;\r\n positionReady.value = false;\r\n emit('wakeUp', true);\r\n await nextTick();\r\n\r\n if (isFirstOpen.value) {\r\n calculateInitialPosition();\r\n isFirstOpen.value = false;\r\n } else {\r\n const validated = validatePosition(\r\n position.x,\r\n position.y,\r\n containerWidth.value,\r\n isCollapsed.value ? 60 : containerHeight.value,\r\n );\r\n const separated = keepDistanceFromFab(\r\n validated.x,\r\n validated.y,\r\n containerWidth.value,\r\n isCollapsed.value ? 60 : containerHeight.value,\r\n );\r\n position.x = separated.x;\r\n position.y = separated.y;\r\n }\r\n\r\n await nextTick();\r\n positionReady.value = true;\r\n } else {\r\n positionReady.value = false;\r\n visible.value = false;\r\n isCollapsed.value = false;\r\n emit('wakeUp', false);\r\n }\r\n};\r\n\r\nconst handleIframeLoad = async (event: Event) => {\r\n aiChatbotX.setIframeElement(event.target as HTMLIFrameElement);\r\n // setTheme 会被排队,等握手完成后自动发送,不需要手动等待\r\n aiChatbotX.setTheme(currentTheme.value);\r\n};\r\n\r\nwatch(\r\n () => [aiChatbotX.chatbotUrl()],\r\n ([url]) => {\r\n console.log('[AiChatbotX] 初始化', url);\r\n if (url) {\r\n chatbotUrl.value = `${url}/app/${aiChatbotX.appId()}?token=${aiChatbotX.appToken()}`;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\nonBeforeUnmount(async () => {\r\n if (detector) {\r\n try {\r\n if (detector.isActive()) {\r\n await detector.stop();\r\n }\r\n detector = null;\r\n } catch (error) {\r\n console.error('[VoiceDetector] 清理失败:', error);\r\n }\r\n }\r\n if (transcriber) {\r\n try {\r\n if (transcriber.isActive()) {\r\n await transcriber.stop();\r\n }\r\n transcriber = null;\r\n } catch (error) {\r\n console.error('[Transcriber] 清理失败:', error);\r\n }\r\n }\r\n});\r\n\r\naiChatbotX?.registerVoiceMethods({\r\n start: () => toggleVoiceMode(true),\r\n stop: () => toggleVoiceMode(false),\r\n openDialog: () => toggleDialog(true),\r\n closeDialog: () => toggleDialog(false),\r\n toggleCollapse: () => toggleCollapse(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.sime-x {\r\n --bg-primary: #ffffff;\r\n --bg-secondary: #f8fafc;\r\n --bg-header: #0f172a;\r\n --text-primary: #0f172a;\r\n --text-secondary: #64748b;\r\n --text-header: #ffffff;\r\n --border-color: #e2e8f0;\r\n --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);\r\n --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.15);\r\n --accent-color: #3b82f6;\r\n --hover-bg: rgba(0, 0, 0, 0.05);\r\n\r\n &[data-theme='dark'] {\r\n --bg-primary: #1e293b;\r\n --bg-secondary: #0f172a;\r\n --bg-header: #0f172a;\r\n --text-primary: #f1f5f9;\r\n --text-secondary: #94a3b8;\r\n --text-header: #f1f5f9;\r\n --border-color: #334155;\r\n --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);\r\n --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);\r\n --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);\r\n --accent-color: #60a5fa;\r\n --hover-bg: rgba(255, 255, 255, 0.1);\r\n }\r\n}\r\n\r\n.is-hidden {\r\n height: 0;\r\n opacity: 0 !important;\r\n pointer-events: none !important;\r\n visibility: hidden !important;\r\n}\r\n\r\n.assistant-fab {\r\n position: relative;\r\n cursor: pointer;\r\n overflow: visible;\r\n filter: drop-shadow(var(--shadow-md));\r\n opacity: 1;\r\n pointer-events: auto;\r\n transition: all 0.3s ease;\r\n\r\n &:hover {\r\n transform: scale(1.05);\r\n }\r\n\r\n &:active {\r\n transform: scale(0.95);\r\n }\r\n\r\n .voice-status {\r\n position: absolute;\r\n right: 100%;\r\n margin-right: 20px;\r\n }\r\n\r\n img {\r\n display: block;\r\n position: relative;\r\n object-fit: contain;\r\n }\r\n\r\n .fab-pulse {\r\n position: absolute;\r\n inset: -4px;\r\n border-radius: 50%;\r\n border: 2px solid var(--accent-color);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n@keyframes pulse {\r\n 0%,\r\n 100% {\r\n opacity: 0;\r\n transform: scale(1);\r\n }\r\n 50% {\r\n opacity: 0.5;\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n.x-dialog-container {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n transform: translate(var(--dialog-x), var(--dialog-y));\r\n border-radius: 16px;\r\n display: flex;\r\n flex-direction: column;\r\n cursor: grab;\r\n overflow: hidden;\r\n z-index: 1100;\r\n opacity: 0;\r\n pointer-events: none;\r\n\r\n &.position-ready {\r\n opacity: 1;\r\n pointer-events: auto;\r\n }\r\n\r\n &:active {\r\n cursor: grabbing;\r\n }\r\n\r\n &.collapsed {\r\n .x-dialog-header {\r\n border-radius: 16px;\r\n }\r\n }\r\n\r\n .x-dialog-header {\r\n position: relative;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n background: var(--bg-header);\r\n padding: 12px 16px;\r\n cursor: move;\r\n user-select: none;\r\n border-bottom: 1px solid var(--border-color);\r\n\r\n .header-left {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n\r\n .logo-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 36px;\r\n height: 36px;\r\n transition: transform 0.2s ease;\r\n\r\n .logo {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: contain;\r\n }\r\n }\r\n\r\n .title {\r\n font-weight: 600;\r\n font-size: 15px;\r\n color: var(--text-header);\r\n letter-spacing: -0.01em;\r\n }\r\n }\r\n\r\n .actions {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n\r\n .action-btn {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 32px;\r\n height: 32px;\r\n border: none;\r\n background: transparent;\r\n cursor: pointer;\r\n color: var(--text-secondary);\r\n transition: all 0.2s ease;\r\n border-radius: 8px;\r\n\r\n &:hover {\r\n color: var(--text-header);\r\n background: var(--hover-bg);\r\n transform: translateY(-1px);\r\n }\r\n\r\n &:active {\r\n transform: translateY(0);\r\n }\r\n\r\n svg {\r\n transition: transform 0.2s ease;\r\n }\r\n\r\n &.collapse-btn:hover svg {\r\n transform: scale(1.1);\r\n }\r\n }\r\n }\r\n }\r\n\r\n .voice-container {\r\n width: 100%;\r\n opacity: 1;\r\n pointer-events: auto;\r\n }\r\n\r\n .x-dialog-content {\r\n flex: 1;\r\n display: flex;\r\n overflow: hidden;\r\n background: var(--bg-secondary);\r\n opacity: 1;\r\n pointer-events: auto;\r\n }\r\n\r\n .x-iframe {\r\n flex: 1;\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n }\r\n\r\n .resize-handle {\r\n position: absolute;\r\n bottom: 0;\r\n right: 0;\r\n width: 40px;\r\n height: 40px;\r\n cursor: nwse-resize;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: var(--text-secondary);\r\n transition: all 0.2s ease;\r\n background: linear-gradient(135deg, transparent 50%, var(--bg-primary) 50%);\r\n border-bottom-right-radius: 16px;\r\n z-index: 10;\r\n\r\n &:hover {\r\n color: var(--accent-color);\r\n background: linear-gradient(135deg, transparent 50%, var(--hover-bg) 50%);\r\n }\r\n\r\n svg {\r\n width: 16px;\r\n height: 16px;\r\n transform: rotate(0deg);\r\n transition: transform 0.2s ease;\r\n }\r\n\r\n &:hover svg {\r\n transform: scale(1.2);\r\n }\r\n }\r\n}\r\n/* 语音按钮状态样式 */\r\n.action-btn.theme-btn {\r\n position: relative;\r\n transition: all 0.3s ease;\r\n}\r\n\r\n.action-btn.theme-btn.active {\r\n background: rgba(59, 130, 246, 0.1);\r\n color: #3b82f6;\r\n}\r\n\r\n.action-btn.theme-btn.listening {\r\n animation: pulse-listening 2s ease-in-out infinite;\r\n}\r\n\r\n.action-btn.theme-btn.woke {\r\n background: rgba(34, 197, 94, 0.2);\r\n color: #22c55e;\r\n animation: pulse-wake 0.6s ease-in-out;\r\n}\r\n\r\n@keyframes pulse-listening {\r\n 0%,\r\n 100% {\r\n box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);\r\n }\r\n 50% {\r\n box-shadow: 0 0 0 8px rgba(59, 130, 246, 0);\r\n }\r\n}\r\n\r\n@keyframes pulse-wake {\r\n 0%,\r\n 100% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n/* 语音指示器 */\r\n.voice-indicator {\r\n position: absolute;\r\n top: 4px;\r\n right: 4px;\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: #3b82f6;\r\n}\r\n\r\n.action-btn.theme-btn.listening .voice-indicator {\r\n animation: blink 1.5s ease-in-out infinite;\r\n}\r\n\r\n.action-btn.theme-btn.woke .voice-indicator {\r\n background: #22c55e;\r\n animation: none;\r\n}\r\n\r\n@keyframes blink {\r\n 0%,\r\n 100% {\r\n opacity: 1;\r\n }\r\n 50% {\r\n opacity: 0.3;\r\n }\r\n}\r\n\r\n/* 麦克风唤醒动画 */\r\n.listening-badge.wake-active {\r\n background-color: rgba(34, 197, 94, 0.85);\r\n animation: wake-badge-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\r\n\r\n .listening-icon {\r\n animation: wake-icon-flash 1.5s ease-in-out;\r\n }\r\n\r\n &::after {\r\n content: '';\r\n position: absolute;\r\n inset: -3px;\r\n border-radius: 50%;\r\n border: 2px solid #22c55e;\r\n animation: wake-mic-ring 1.2s ease-out forwards;\r\n pointer-events: none;\r\n }\r\n}\r\n\r\n@keyframes wake-badge-pop {\r\n 0% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.4);\r\n }\r\n 100% {\r\n transform: scale(1);\r\n }\r\n}\r\n\r\n@keyframes wake-icon-flash {\r\n 0%,\r\n 100% {\r\n color: #ffffff;\r\n }\r\n 25% {\r\n color: #bbf7d0;\r\n }\r\n 50% {\r\n color: #ffffff;\r\n }\r\n 75% {\r\n color: #bbf7d0;\r\n }\r\n}\r\n\r\n@keyframes wake-mic-ring {\r\n 0% {\r\n transform: scale(1);\r\n opacity: 0.8;\r\n }\r\n 100% {\r\n transform: scale(2.2);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n/* FAB 头像容器 */\r\n.fab-avatar-wrapper {\r\n position: relative;\r\n display: flex; /* 改用 flex 可以消除图片底部的行高间隙 */\r\n align-items: center;\r\n justify-content: center;\r\n width: fit-content; /* 宽度随内容自适应 */\r\n margin: 0 auto;\r\n}\r\n\r\n/* 2. 修正图片样式 */\r\n.fab-avatar-wrapper img {\r\n display: block;\r\n max-width: 100%;\r\n height: auto;\r\n /* 移除原本 style 里的 width/height 可能造成的拉伸,保持比例 */\r\n}\r\n\r\n/* 3. 优化徽章定位 */\r\n.listening-badge {\r\n position: absolute;\r\n /* 强制定位到容器边缘 */\r\n top: 0;\r\n right: 0;\r\n /* 使用 transform 偏移,让徽章中心点落在图片的右上角顶点上 */\r\n transform: translate(30%, -30%);\r\n\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background-color: rgba(0, 0, 0, 0.75); /* 稍微加深一点 */\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 10;\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\r\n\r\n /* 继承你原有的动画 */\r\n animation: badge-float 5s ease-in-out infinite;\r\n pointer-events: none; /* 防止遮挡头像点击 */\r\n}\r\n\r\n/* 4. 调整声波扩散的基准 */\r\n.wave {\r\n position: absolute;\r\n /* 确保声波从徽章中心扩散,而不是从容器左上角 */\r\n inset: -2px;\r\n border-radius: 50%;\r\n border: 2px solid rgba(59, 130, 246, 0.6); /* 声波颜色建议跟主题色一致 */\r\n animation: wave-expand 3s ease-out infinite;\r\n}\r\n\r\n/* 优化后的监听状态徽章 */\r\n.listening-badge {\r\n position: absolute;\r\n top: -8px;\r\n right: -8px;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background-color: rgba(0, 0, 0, 0.651);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 10;\r\n animation: badge-float 5s ease-in-out infinite;\r\n}\r\n\r\n/* 徽章浮动动画 */\r\n@keyframes badge-float {\r\n 0%,\r\n 100% {\r\n transform: translateY(0) scale(1);\r\n }\r\n 50% {\r\n transform: translateY(-2px) scale(1.05);\r\n }\r\n}\r\n\r\n/* 声波容器 */\r\n.listening-waves {\r\n position: absolute;\r\n inset: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n/* 声波动画 */\r\n.wave {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n border-radius: 50%;\r\n border: 2px solid rgba(255, 255, 255, 0.6);\r\n animation: wave-expand 3s ease-out infinite;\r\n}\r\n\r\n.wave-1 {\r\n animation-delay: 0s;\r\n}\r\n\r\n.wave-2 {\r\n animation-delay: 0.6s;\r\n}\r\n\r\n.wave-3 {\r\n animation-delay: 1.2s;\r\n}\r\n\r\n@keyframes wave-expand {\r\n 0% {\r\n transform: scale(0.8);\r\n opacity: 0.8;\r\n }\r\n 100% {\r\n transform: scale(1.2);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n/* 麦克风图标 */\r\n.listening-icon {\r\n position: relative;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: #ffffff;\r\n z-index: 1;\r\n animation: icon-pulse 2.5s ease-in-out infinite;\r\n}\r\n\r\n@keyframes icon-pulse {\r\n 0%,\r\n 100% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.1);\r\n }\r\n}\r\n\r\n/* 徽章淡入淡出动画 */\r\n.indicator-fade-enter-active {\r\n transition: all 1s cubic-bezier(0.34, 1.56, 0.64, 1);\r\n}\r\n\r\n.indicator-fade-leave-active {\r\n transition: all 1s ease;\r\n}\r\n\r\n.indicator-fade-enter-from {\r\n opacity: 0;\r\n transform: scale(0.3) rotate(-180deg);\r\n}\r\n\r\n.indicator-fade-leave-to {\r\n opacity: 0;\r\n transform: scale(0.5) rotate(180deg);\r\n}\r\n\r\n/* FAB 脉冲效果 */\r\n.fab-pulse {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n border-radius: 50%;\r\n pointer-events: none;\r\n}\r\n\r\n.fab-pulse.active {\r\n animation: fab-pulse 2s ease-in-out infinite;\r\n}\r\n\r\n@keyframes fab-pulse {\r\n 0%,\r\n 100% {\r\n box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);\r\n }\r\n 50% {\r\n box-shadow: 0 0 0 20px rgba(59, 130, 246, 0);\r\n }\r\n}\r\n\r\n/* 深色模式适配 */\r\n[data-theme='dark'] .action-btn.theme-btn.active {\r\n background: rgba(59, 130, 246, 0.2);\r\n}\r\n\r\n[data-theme='dark'] .action-btn.theme-btn.woke {\r\n background: rgba(34, 197, 94, 0.3);\r\n}\r\n</style>\r\n","import { ref } from 'vue';\r\nimport { SpeechSynthesizerStandalone } from 'web-voice-kit';\r\nimport type { VoiceConfig } from '../types';\r\n\r\n/**\r\n * TTS 语音播报 composable\r\n *\r\n * 管理讯飞 SpeechSynthesizerStandalone 的生命周期、\r\n * 句子级缓冲、Markdown 清理、AudioContext 预热。\r\n */\r\nexport function useTTS(getVoiceConfig: () => VoiceConfig | null) {\r\n const isSpeaking = ref(false);\r\n\r\n let instance: SpeechSynthesizerStandalone | null = null;\r\n let initPromise: Promise<SpeechSynthesizerStandalone | null> | null = null;\r\n let audioCtx: AudioContext | null = null;\r\n\r\n // 句子缓冲\r\n let sentenceBuffer = '';\r\n const sentenceDelimiters = /[。!?;\\n.!?;]/;\r\n\r\n // ── helpers ──\r\n\r\n const stripMarkdown = (text: string): string =>\r\n text\r\n .replace(/```[\\s\\S]*?```/g, '')\r\n .replace(/\\|[^\\n]*\\|/g, '')\r\n .replace(/#{1,6}\\s*/g, '')\r\n .replace(/\\*\\*(.*?)\\*\\*/g, '$1')\r\n .replace(/\\*(.*?)\\*/g, '$1')\r\n .replace(/`([^`]*)`/g, '$1')\r\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\r\n .replace(/[-*+]\\s+/g, '')\r\n .replace(/>\\s+/g, '')\r\n .replace(/\\n{2,}/g, '。')\r\n .replace(/\\n/g, ',')\r\n .trim();\r\n\r\n // ── AudioContext 预热 ──\r\n\r\n const warmUpAudio = () => {\r\n if (!audioCtx || audioCtx.state === 'closed') {\r\n try {\r\n audioCtx = new AudioContext();\r\n } catch {\r\n return;\r\n }\r\n }\r\n if (audioCtx.state === 'suspended') {\r\n audioCtx.resume();\r\n }\r\n };\r\n\r\n // ── 懒初始化 ──\r\n\r\n /** 回调:TTS 队列清空时触发(外部可监听) */\r\n let onQueueEmptyCb: (() => void) | null = null;\r\n\r\n const ensureInstance = async (): Promise<SpeechSynthesizerStandalone | null> => {\r\n if (instance) return instance;\r\n if (initPromise) return initPromise;\r\n\r\n const vc = getVoiceConfig();\r\n if (!vc || !vc.apiSecret) {\r\n console.warn('[TTS] 缺少 voiceConfig 或 apiSecret,语音播报已禁用');\r\n return null;\r\n }\r\n\r\n initPromise = (async () => {\r\n try {\r\n const tts = new SpeechSynthesizerStandalone({\r\n appId: vc.appId,\r\n apiKey: vc.ttsApiKey || vc.apiKey,\r\n apiSecret: vc.apiSecret!,\r\n websocketUrl: vc.ttsWebsocketUrl || 'wss://tts-api.xfyun.cn/v2/tts',\r\n vcn: vc.ttsVcn || 'xiaoyan',\r\n speed: 60,\r\n volume: 50,\r\n pitch: 50,\r\n aue: 'raw',\r\n auf: 'audio/L16;rate=16000',\r\n tte: 'UTF8',\r\n autoPlay: true,\r\n });\r\n\r\n tts.onStart(() => {\r\n isSpeaking.value = true;\r\n });\r\n\r\n tts.onEnd(() => {\r\n // 每段文本结束,队列可能还有后续\r\n });\r\n\r\n tts.onQueueEmpty(() => {\r\n isSpeaking.value = false;\r\n onQueueEmptyCb?.();\r\n });\r\n\r\n tts.onError((err: any) => {\r\n console.error('[TTS] Error:', err);\r\n isSpeaking.value = false;\r\n });\r\n\r\n // 注入预热的 AudioContext\r\n if (audioCtx && audioCtx.state === 'running') {\r\n (tts as any).audioContext = audioCtx;\r\n (tts as any).gainNode = audioCtx.createGain();\r\n (tts as any).gainNode.connect(audioCtx.destination);\r\n }\r\n\r\n instance = tts;\r\n initPromise = null;\r\n return tts;\r\n } catch (err) {\r\n console.error('[TTS] 初始化失败:', err);\r\n initPromise = null;\r\n return null;\r\n }\r\n })();\r\n\r\n return initPromise;\r\n };\r\n\r\n // ── 公开方法 ──\r\n\r\n const speak = async (text: string) => {\r\n const clean = stripMarkdown(text);\r\n if (!clean.trim()) return;\r\n const tts = await ensureInstance();\r\n if (!tts) return;\r\n try {\r\n tts.speak(clean);\r\n } catch (err) {\r\n console.error('[TTS] speak 失败:', err);\r\n }\r\n };\r\n\r\n const feed = (delta: string) => {\r\n sentenceBuffer += delta;\r\n while (true) {\r\n const match = sentenceBuffer.match(sentenceDelimiters);\r\n if (!match || match.index === undefined) break;\r\n const sentence = sentenceBuffer.slice(0, match.index + 1).trim();\r\n sentenceBuffer = sentenceBuffer.slice(match.index + 1);\r\n if (sentence.length > 0) speak(sentence);\r\n }\r\n };\r\n\r\n const flush = () => {\r\n const remaining = sentenceBuffer.trim();\r\n sentenceBuffer = '';\r\n if (remaining.length > 0) speak(remaining);\r\n };\r\n\r\n const stop = () => {\r\n sentenceBuffer = '';\r\n isSpeaking.value = false;\r\n if (instance) {\r\n try {\r\n instance.stop();\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n };\r\n\r\n const setOnQueueEmpty = (cb: () => void) => {\r\n onQueueEmptyCb = cb;\r\n };\r\n\r\n const destroy = () => {\r\n stop();\r\n if (instance) {\r\n try {\r\n instance.destroy();\r\n } catch {\r\n // ignore\r\n }\r\n instance = null;\r\n }\r\n if (audioCtx) {\r\n try {\r\n audioCtx.close();\r\n } catch {\r\n // ignore\r\n }\r\n audioCtx = null;\r\n }\r\n };\r\n\r\n return {\r\n isSpeaking,\r\n warmUpAudio,\r\n speak,\r\n feed,\r\n flush,\r\n stop,\r\n destroy,\r\n setOnQueueEmpty,\r\n };\r\n}\r\n","import { computed, nextTick, ref } from 'vue';\r\nimport type { Ref } from 'vue';\r\n\r\nexport interface BubbleSize {\r\n /** 气泡最大宽度,如 '380px' 或 '86vw' */\r\n width?: string;\r\n /** 气泡最大高度,如 '520px' 或 '58vh' */\r\n maxHeight?: string;\r\n}\r\n\r\nexport interface UseBubbleOptions {\r\n /** 自动消失延迟 (ms),默认 4000 */\r\n dismissDelay?: number;\r\n /** 外部 isSpeaking 引用,TTS 播报期间阻止消失 */\r\n isSpeaking?: Ref<boolean>;\r\n /** 外部 isInvoking 引用,调用期间阻止消失 */\r\n isInvoking?: Ref<boolean>;\r\n /** 气泡尺寸 */\r\n bubbleSize?: BubbleSize;\r\n}\r\n\r\n/**\r\n * 气泡生命周期 composable\r\n *\r\n * 管理气泡显示/隐藏、自动消失倒计时、滚动。\r\n * 核心保证:TTS 播报期间气泡绝不消失。\r\n */\r\nexport function useBubble(options: UseBubbleOptions = {}) {\r\n const visible = ref(false);\r\n const fadingOut = ref(false);\r\n const stackRef = ref<HTMLElement | null>(null);\r\n let dismissTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n const show = computed(() => visible.value && !fadingOut.value);\r\n\r\n const style = computed(() => ({\r\n width: options.bubbleSize?.width || undefined,\r\n maxHeight: options.bubbleSize?.maxHeight || undefined,\r\n }));\r\n\r\n // ── 打开气泡(取消任何挂起的消失计时器) ──\r\n\r\n const open = () => {\r\n cancelDismiss();\r\n fadingOut.value = false;\r\n visible.value = true;\r\n };\r\n\r\n // ── 取消消失计时器 ──\r\n\r\n const cancelDismiss = () => {\r\n if (dismissTimer) {\r\n clearTimeout(dismissTimer);\r\n dismissTimer = null;\r\n }\r\n };\r\n\r\n // ── 安排消失(严格检查 TTS 和调用状态) ──\r\n\r\n const scheduleDismiss = () => {\r\n cancelDismiss();\r\n\r\n // TTS 还在播报 → 不启动倒计时,由 TTS onQueueEmpty 再次触发\r\n if (options.isSpeaking?.value) return;\r\n // 还在调用中 → 不启动倒计时\r\n if (options.isInvoking?.value) return;\r\n\r\n const delay = options.dismissDelay ?? 4000;\r\n dismissTimer = setTimeout(() => {\r\n fadingOut.value = true;\r\n // CSS transition 完成后真正隐藏\r\n setTimeout(() => {\r\n visible.value = false;\r\n fadingOut.value = false;\r\n }, 400);\r\n }, delay);\r\n };\r\n\r\n // ── 立即隐藏(中断场景) ──\r\n\r\n const hide = () => {\r\n cancelDismiss();\r\n fadingOut.value = false;\r\n visible.value = false;\r\n };\r\n\r\n // ── 滚动到底部 ──\r\n\r\n const scrollToBottom = () => {\r\n nextTick(() => {\r\n if (stackRef.value) {\r\n stackRef.value.scrollTop = stackRef.value.scrollHeight;\r\n }\r\n });\r\n };\r\n\r\n // ── 清理 ──\r\n\r\n const destroy = () => {\r\n cancelDismiss();\r\n };\r\n\r\n return {\r\n visible,\r\n fadingOut,\r\n show,\r\n style,\r\n stackRef,\r\n open,\r\n hide,\r\n cancelDismiss,\r\n scheduleDismiss,\r\n scrollToBottom,\r\n destroy,\r\n };\r\n}\r\n","import { ref } from 'vue';\r\nimport { SpeechTranscriberStandalone, WakeWordDetectorStandalone } from 'web-voice-kit';\r\nimport type { VoiceConfig } from '../types';\r\nimport { ensureMicrophonePermission } from '../lib/utils';\r\n\r\nexport type VoiceStatus = 'standby' | 'listening';\r\n\r\nexport interface UseVoiceRecognitionOptions {\r\n modelPath?: string;\r\n wakeWords?: string[];\r\n getVoiceConfig: () => VoiceConfig | null;\r\n /** 唤醒时回调 */\r\n onWake?: () => void;\r\n /** 转写完成(autoStop)时回调 */\r\n onTranscriptionDone?: (text: string) => void;\r\n}\r\n\r\n/**\r\n * 语音识别 composable\r\n *\r\n * 管理唤醒词检测器 + 语音转写器的生命周期。\r\n */\r\nexport function useVoiceRecognition(options: UseVoiceRecognitionOptions) {\r\n const voiceStatus = ref<VoiceStatus>('standby');\r\n const isTranscribing = ref(false);\r\n const isInitializing = ref(false);\r\n const transcriptionText = ref('');\r\n const wakeAnimating = ref(false);\r\n\r\n let detector: WakeWordDetectorStandalone | null = null;\r\n let transcriber: SpeechTranscriberStandalone | null = null;\r\n\r\n // ── 转写器 ──\r\n\r\n const initTranscriber = () => {\r\n if (transcriber) return;\r\n\r\n const vc = options.getVoiceConfig();\r\n if (!vc || !vc.appId || !vc.apiKey || !vc.websocketUrl) {\r\n console.error('[VoiceRecognition] 缺少 voiceConfig,无法初始化转写器');\r\n return;\r\n }\r\n\r\n transcriber = new SpeechTranscriberStandalone({\r\n appId: vc.appId,\r\n apiKey: vc.apiKey,\r\n websocketUrl: vc.websocketUrl,\r\n autoStop: {\r\n enabled: true,\r\n silenceTimeoutMs: 2000,\r\n noSpeechTimeoutMs: 5000,\r\n maxDurationMs: 45000,\r\n },\r\n });\r\n\r\n transcriber.onResult((result) => {\r\n transcriptionText.value = result.transcript || '';\r\n });\r\n\r\n transcriber.onAutoStop(async () => {\r\n const finalText = transcriptionText.value;\r\n await stopTranscribing();\r\n transcriptionText.value = '';\r\n if (finalText.trim()) {\r\n options.onTranscriptionDone?.(finalText);\r\n }\r\n });\r\n\r\n transcriber.onError((error: any) => {\r\n console.error('[VoiceRecognition] 转写错误:', error);\r\n stopTranscribing();\r\n transcriptionText.value = '';\r\n });\r\n };\r\n\r\n const startTranscribing = async () => {\r\n if (isTranscribing.value) return;\r\n if (!transcriber) initTranscriber();\r\n if (!transcriber) return;\r\n\r\n try {\r\n await transcriber.start();\r\n isTranscribing.value = true;\r\n transcriptionText.value = '';\r\n } catch (error) {\r\n console.error('[VoiceRecognition] 启动转写失败:', error);\r\n }\r\n };\r\n\r\n const stopTranscribing = async () => {\r\n if (!transcriber || !transcriber.isActive()) {\r\n isTranscribing.value = false;\r\n return;\r\n }\r\n try {\r\n await transcriber.stop();\r\n } catch (error) {\r\n console.error('[VoiceRecognition] 停止转写失败:', error);\r\n } finally {\r\n isTranscribing.value = false;\r\n }\r\n };\r\n\r\n // ── 唤醒词检测器 ──\r\n\r\n const initDetector = () => {\r\n if (detector || isInitializing.value) return;\r\n if (!options.modelPath) {\r\n console.error('[VoiceRecognition] 未传入 modelPath,无法启用唤醒词');\r\n return;\r\n }\r\n\r\n isInitializing.value = true;\r\n try {\r\n detector = new WakeWordDetectorStandalone({\r\n modelPath: options.modelPath,\r\n sampleRate: 16000,\r\n usePartial: true,\r\n autoReset: {\r\n enabled: true,\r\n resetDelayMs: 4000,\r\n },\r\n });\r\n\r\n detector.setWakeWords(options.wakeWords || ['你好', '您好']);\r\n detector.onWake(async () => {\r\n wakeAnimating.value = true;\r\n options.onWake?.();\r\n await startTranscribing();\r\n setTimeout(() => {\r\n wakeAnimating.value = false;\r\n }, 1200);\r\n });\r\n\r\n detector.onError((error: any) => {\r\n console.error('[VoiceRecognition] 唤醒监听错误:', error);\r\n voiceStatus.value = 'standby';\r\n stopTranscribing();\r\n });\r\n } finally {\r\n isInitializing.value = false;\r\n }\r\n };\r\n\r\n // ── 切换语音模式 ──\r\n\r\n const toggleVoiceMode = async (targetState?: boolean) => {\r\n const permission = await ensureMicrophonePermission();\r\n if (!permission || isInitializing.value) return;\r\n\r\n if (!detector) {\r\n initDetector();\r\n if (!detector) return;\r\n }\r\n\r\n const isListening = voiceStatus.value === 'listening';\r\n const shouldStart = targetState !== undefined ? targetState : !isListening;\r\n if (isListening === shouldStart) return;\r\n\r\n try {\r\n if (shouldStart) {\r\n await detector.start();\r\n voiceStatus.value = 'listening';\r\n } else {\r\n await detector.stop();\r\n voiceStatus.value = 'standby';\r\n transcriptionText.value = '';\r\n await stopTranscribing();\r\n }\r\n } catch (error) {\r\n console.error('[VoiceRecognition] 监听切换失败:', error);\r\n voiceStatus.value = 'standby';\r\n }\r\n };\r\n\r\n // ── 中断当前转写(唤醒中断场景) ──\r\n\r\n const abortTranscription = async () => {\r\n transcriptionText.value = '';\r\n await stopTranscribing();\r\n };\r\n\r\n // ── 清理 ──\r\n\r\n const destroy = async () => {\r\n if (detector) {\r\n try {\r\n if (detector.isActive()) await detector.stop();\r\n } catch {\r\n // ignore\r\n }\r\n detector = null;\r\n }\r\n if (transcriber) {\r\n try {\r\n if (transcriber.isActive()) await transcriber.stop();\r\n } catch {\r\n // ignore\r\n }\r\n transcriber = null;\r\n }\r\n };\r\n\r\n return {\r\n voiceStatus,\r\n isTranscribing,\r\n isInitializing,\r\n transcriptionText,\r\n wakeAnimating,\r\n startTranscribing,\r\n stopTranscribing,\r\n abortTranscription,\r\n toggleVoiceMode,\r\n destroy,\r\n };\r\n}\r\n","/**\r\n * AI SDK Stream Protocol Parser for Vue\r\n *\r\n * Handles THREE possible response formats from the agent/chat service:\r\n *\r\n * Format A – UI Message Stream Protocol (pipeUIMessageStreamToResponse) ★ PRIMARY\r\n * SSE format with JSON objects containing a \"type\" field:\r\n * data: {\"type\":\"start\",\"messageId\":\"...\"}\r\n * data: {\"type\":\"text-delta\",\"id\":\"...\",\"delta\":\"Hello\"}\r\n * data: {\"type\":\"tool-input-start\",\"toolCallId\":\"...\",\"toolName\":\"...\"}\r\n * data: {\"type\":\"tool-input-delta\",\"toolCallId\":\"...\",\"inputTextDelta\":\"...\"}\r\n * data: {\"type\":\"tool-input-available\",\"toolCallId\":\"...\",\"toolName\":\"...\",\"input\":{...}}\r\n * data: {\"type\":\"tool-output-available\",\"toolCallId\":\"...\",\"output\":{...}}\r\n * data: {\"type\":\"finish-step\"}\r\n * data: {\"type\":\"finish\"}\r\n * data: [DONE]\r\n *\r\n * Format B – Legacy Data Stream Protocol (pipeDataStreamToResponse)\r\n * Each line: CODE:JSON_VALUE\\n\r\n * 0:\"text\" 9:{toolCallId,toolName} c:{toolCallId,toolName,args} a:{toolCallId,result}\r\n *\r\n * Format C – Plain text stream (pipeTextStreamToResponse fallback)\r\n * Raw UTF-8 text chunks with no protocol framing.\r\n *\r\n * The parser auto-detects the format from the first chunk.\r\n */\r\n\r\n// ── Part types (mirrors AI SDK UIMessage.parts) ──────────────────────\r\n\r\nexport type ToolState =\r\n | 'partial-call' // streaming tool call args\r\n | 'call' // tool call complete, waiting for result\r\n | 'result' // tool result received\r\n | 'error'; // tool call errored\r\n\r\nexport interface TextPart {\r\n type: 'text';\r\n text: string;\r\n}\r\n\r\nexport interface ToolCallPart {\r\n type: 'tool-call';\r\n toolCallId: string;\r\n toolName: string;\r\n args: any;\r\n state: ToolState;\r\n}\r\n\r\nexport interface ToolResultPart {\r\n type: 'tool-result';\r\n toolCallId: string;\r\n toolName: string;\r\n args: any;\r\n result: any;\r\n state: ToolState;\r\n}\r\n\r\nexport type MessagePart = TextPart | ToolCallPart | ToolResultPart;\r\n\r\nexport interface StreamMessage {\r\n id: string;\r\n role: 'user' | 'assistant';\r\n parts: MessagePart[];\r\n createdAt: number;\r\n}\r\n\r\n// ── Internal tracking for tool calls ─────────────────────────────────\r\n\r\ninterface ToolCallTracker {\r\n toolCallId: string;\r\n toolName: string;\r\n argsText: string;\r\n args: any;\r\n result?: any;\r\n state: ToolState;\r\n}\r\n\r\n// ── Stream event types ───────────────────────────────────────────────\r\n\r\nexport type StreamEventType =\r\n | 'text-delta'\r\n | 'tool-call-start'\r\n | 'tool-call-delta'\r\n | 'tool-call-complete'\r\n | 'tool-result'\r\n | 'step-finish'\r\n | 'finish'\r\n | 'error';\r\n\r\nexport interface StreamEvent {\r\n type: StreamEventType;\r\n data: any;\r\n}\r\n\r\n// ── Parser callbacks ─────────────────────────────────────────────────\r\n\r\nexport interface DataStreamCallbacks {\r\n onTextDelta?: (text: string) => void;\r\n onToolCallStart?: (toolCallId: string, toolName: string) => void;\r\n onToolCallDelta?: (toolCallId: string, argsTextDelta: string) => void;\r\n onToolCallComplete?: (toolCallId: string, toolName: string, args: any) => void;\r\n onToolResult?: (toolCallId: string, result: any) => void;\r\n onStepFinish?: (data: any) => void;\r\n onFinish?: (data: any) => void;\r\n onError?: (error: string) => void;\r\n}\r\n\r\n// ── Format detection ─────────────────────────────────────────────────\r\n\r\ntype StreamFormat = 'ui-message-stream' | 'data-stream' | 'plain-text';\r\n\r\nconst DATA_STREAM_LINE_RE = /^[0-9a-f]:/;\r\n\r\nfunction detectFormat(firstChunk: string): StreamFormat {\r\n const trimmed = firstChunk.trimStart();\r\n\r\n // UI Message Stream (SSE with JSON type objects) — this is the primary format\r\n // from pipeUIMessageStreamToResponse\r\n if (trimmed.startsWith('data:')) {\r\n // Try to parse the first data line to check if it's UI Message Stream\r\n const firstLine = trimmed.split('\\n')[0];\r\n const payload = firstLine.slice(5).trim();\r\n try {\r\n const parsed = JSON.parse(payload);\r\n if (parsed && typeof parsed.type === 'string') {\r\n return 'ui-message-stream';\r\n }\r\n } catch {\r\n // Not JSON with type → could be old data stream inside SSE, or [DONE]\r\n }\r\n // SSE with old data stream lines inside (e.g., data: 0:\"text\")\r\n if (DATA_STREAM_LINE_RE.test(payload)) {\r\n return 'data-stream';\r\n }\r\n // SSE but unknown content — treat as UI message stream (most likely)\r\n return 'ui-message-stream';\r\n }\r\n\r\n // Legacy data stream protocol: lines like 0:\"text\"\\n\r\n if (DATA_STREAM_LINE_RE.test(trimmed)) {\r\n return 'data-stream';\r\n }\r\n\r\n // Fallback: plain text\r\n return 'plain-text';\r\n}\r\n\r\n// ── UI Message Stream Protocol parser ────────────────────────────────\r\n\r\nfunction processUIMessageStreamEvent(payload: string, callbacks: DataStreamCallbacks): void {\r\n const trimmed = payload.trim();\r\n if (!trimmed || trimmed === '[DONE]') {\r\n callbacks.onFinish?.({});\r\n return;\r\n }\r\n\r\n let parsed: any;\r\n try {\r\n parsed = JSON.parse(trimmed);\r\n } catch {\r\n // Not valid JSON — ignore\r\n console.warn('[DataStreamParser] failed to parse UI message stream event:', trimmed.slice(0, 100));\r\n return;\r\n }\r\n\r\n const type = parsed?.type;\r\n if (!type) return;\r\n\r\n switch (type) {\r\n case 'text-delta':\r\n // {\"type\":\"text-delta\",\"id\":\"...\",\"delta\":\"Hello\"}\r\n if (typeof parsed.delta === 'string') {\r\n callbacks.onTextDelta?.(parsed.delta);\r\n }\r\n break;\r\n\r\n case 'tool-input-start':\r\n // {\"type\":\"tool-input-start\",\"toolCallId\":\"...\",\"toolName\":\"...\"}\r\n callbacks.onToolCallStart?.(parsed.toolCallId, parsed.toolName);\r\n break;\r\n\r\n case 'tool-input-delta':\r\n // {\"type\":\"tool-input-delta\",\"toolCallId\":\"...\",\"inputTextDelta\":\"...\"}\r\n callbacks.onToolCallDelta?.(parsed.toolCallId, parsed.inputTextDelta);\r\n break;\r\n\r\n case 'tool-input-available':\r\n // {\"type\":\"tool-input-available\",\"toolCallId\":\"...\",\"toolName\":\"...\",\"input\":{...}}\r\n callbacks.onToolCallComplete?.(parsed.toolCallId, parsed.toolName, parsed.input);\r\n break;\r\n\r\n case 'tool-output-available':\r\n // {\"type\":\"tool-output-available\",\"toolCallId\":\"...\",\"output\":{...}}\r\n callbacks.onToolResult?.(parsed.toolCallId, parsed.output);\r\n break;\r\n\r\n case 'finish-step':\r\n callbacks.onStepFinish?.(parsed);\r\n break;\r\n\r\n case 'finish':\r\n callbacks.onFinish?.(parsed);\r\n break;\r\n\r\n case 'error':\r\n callbacks.onError?.(parsed.errorText || parsed.error || 'Unknown error');\r\n break;\r\n\r\n // Parts we acknowledge but don't need to act on:\r\n case 'start':\r\n case 'text-start':\r\n case 'text-end':\r\n case 'start-step':\r\n case 'reasoning-start':\r\n case 'reasoning-delta':\r\n case 'reasoning-end':\r\n case 'source-url':\r\n case 'source-document':\r\n case 'file':\r\n case 'abort':\r\n // No-op for voice assistant\r\n break;\r\n\r\n default:\r\n // Unknown type — log and ignore\r\n if (type.startsWith('data-')) {\r\n // Custom data parts — ignore\r\n } else {\r\n console.log('[DataStreamParser] unhandled UI message stream type:', type);\r\n }\r\n break;\r\n }\r\n}\r\n\r\n// ── Legacy Data Stream Protocol parser ───────────────────────────────\r\n\r\nfunction parseLegacyProtocolLine(line: string, callbacks: DataStreamCallbacks): void {\r\n if (!line || !DATA_STREAM_LINE_RE.test(line)) return;\r\n\r\n const code = line[0];\r\n const rawValue = line.slice(2);\r\n\r\n let value: any;\r\n try {\r\n value = JSON.parse(rawValue);\r\n } catch {\r\n value = rawValue;\r\n }\r\n\r\n switch (code) {\r\n case '0':\r\n callbacks.onTextDelta?.(value);\r\n break;\r\n case '9':\r\n callbacks.onToolCallStart?.(value.toolCallId, value.toolName);\r\n break;\r\n case 'b':\r\n callbacks.onToolCallDelta?.(value.toolCallId, value.argsTextDelta);\r\n break;\r\n case 'c':\r\n callbacks.onToolCallComplete?.(value.toolCallId, value.toolName, value.args);\r\n break;\r\n case 'a':\r\n callbacks.onToolResult?.(value.toolCallId, value.result);\r\n break;\r\n case 'e':\r\n callbacks.onStepFinish?.(value);\r\n break;\r\n case 'd':\r\n callbacks.onFinish?.(value);\r\n break;\r\n case '3':\r\n callbacks.onError?.(value);\r\n break;\r\n }\r\n}\r\n\r\n// ── Read and parse a stream response (auto-detecting format) ─────────\r\n\r\nexport async function readDataStream(response: Response, callbacks: DataStreamCallbacks): Promise<void> {\r\n if (!response.body) return;\r\n\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n let format: StreamFormat | null = null;\r\n\r\n while (true) {\r\n const { value, done } = await reader.read();\r\n if (done) break;\r\n\r\n const chunk = decoder.decode(value, { stream: true });\r\n buffer += chunk;\r\n\r\n // Auto-detect format from the first meaningful content\r\n if (format === null && buffer.trim().length > 0) {\r\n format = detectFormat(buffer);\r\n console.log('[DataStreamParser] detected format:', format, '| first 200 chars:', buffer.slice(0, 200));\r\n }\r\n\r\n if (format === 'plain-text') {\r\n const text = buffer;\r\n buffer = '';\r\n if (text) callbacks.onTextDelta?.(text);\r\n continue;\r\n }\r\n\r\n if (format === 'ui-message-stream') {\r\n // SSE format: events separated by \\n\\n\r\n while (true) {\r\n const eventEnd = buffer.indexOf('\\n\\n');\r\n if (eventEnd === -1) break;\r\n\r\n const eventBlock = buffer.slice(0, eventEnd);\r\n buffer = buffer.slice(eventEnd + 2);\r\n\r\n // Extract data lines from SSE event block\r\n const dataLines = eventBlock\r\n .split(/\\r?\\n/)\r\n .filter((l) => l.startsWith('data:'))\r\n .map((l) => l.slice(5).trimStart());\r\n\r\n for (const dataLine of dataLines) {\r\n processUIMessageStreamEvent(dataLine, callbacks);\r\n }\r\n }\r\n continue;\r\n }\r\n\r\n if (format === 'data-stream') {\r\n // Legacy data stream or SSE-wrapped legacy\r\n // Check if it looks like SSE (data: prefix)\r\n const isSSEWrapped = buffer.trimStart().startsWith('data:');\r\n\r\n if (isSSEWrapped) {\r\n while (true) {\r\n const eventEnd = buffer.indexOf('\\n\\n');\r\n if (eventEnd === -1) break;\r\n\r\n const eventBlock = buffer.slice(0, eventEnd);\r\n buffer = buffer.slice(eventEnd + 2);\r\n\r\n const dataLines = eventBlock\r\n .split(/\\r?\\n/)\r\n .filter((l) => l.startsWith('data:'))\r\n .map((l) => l.slice(5).trimStart());\r\n\r\n for (const dl of dataLines) {\r\n const t = dl.trim();\r\n if (!t || t === '[DONE]') {\r\n if (t === '[DONE]') callbacks.onFinish?.({});\r\n continue;\r\n }\r\n parseLegacyProtocolLine(t, callbacks);\r\n }\r\n }\r\n } else {\r\n // Raw data stream lines separated by \\n\r\n while (true) {\r\n const newlineIdx = buffer.indexOf('\\n');\r\n if (newlineIdx === -1) break;\r\n\r\n const line = buffer.slice(0, newlineIdx).trim();\r\n buffer = buffer.slice(newlineIdx + 1);\r\n\r\n if (line) parseLegacyProtocolLine(line, callbacks);\r\n }\r\n }\r\n continue;\r\n }\r\n }\r\n\r\n // Process remaining buffer\r\n const tail = decoder.decode();\r\n if (tail) buffer += tail;\r\n\r\n if (buffer.trim()) {\r\n if (format === 'plain-text') {\r\n callbacks.onTextDelta?.(buffer);\r\n } else if (format === 'ui-message-stream') {\r\n const dataLines = buffer\r\n .split(/\\r?\\n/)\r\n .filter((l) => l.startsWith('data:'))\r\n .map((l) => l.slice(5).trimStart());\r\n for (const dl of dataLines) {\r\n processUIMessageStreamEvent(dl, callbacks);\r\n }\r\n } else if (format === 'data-stream') {\r\n parseLegacyProtocolLine(buffer.trim(), callbacks);\r\n }\r\n }\r\n\r\n callbacks.onFinish?.({});\r\n}\r\n\r\n// ── High-level: parse stream into MessageParts ───────────────────────\r\n\r\nexport interface StreamParseResult {\r\n textContent: string;\r\n parts: MessagePart[];\r\n toolCalls: Map<string, ToolCallTracker>;\r\n}\r\n\r\nexport async function parseDataStreamToMessage(\r\n response: Response,\r\n onUpdate: (result: StreamParseResult) => void,\r\n): Promise<StreamParseResult> {\r\n let textContent = '';\r\n const parts: MessagePart[] = [];\r\n const toolCalls = new Map<string, ToolCallTracker>();\r\n\r\n const ensureTextPart = (): TextPart => {\r\n for (let i = parts.length - 1; i >= 0; i--) {\r\n if (parts[i].type === 'text') {\r\n return parts[i] as TextPart;\r\n }\r\n }\r\n const textPart: TextPart = { type: 'text', text: '' };\r\n parts.push(textPart);\r\n return textPart;\r\n };\r\n\r\n const findToolPartIndex = (toolCallId: string): number => {\r\n return parts.findIndex((p) => (p.type === 'tool-call' || p.type === 'tool-result') && p.toolCallId === toolCallId);\r\n };\r\n\r\n const emitUpdate = () => {\r\n onUpdate({ textContent, parts: [...parts], toolCalls: new Map(toolCalls) });\r\n };\r\n\r\n await readDataStream(response, {\r\n onTextDelta(text) {\r\n textContent += text;\r\n const textPart = ensureTextPart();\r\n textPart.text = textContent;\r\n emitUpdate();\r\n },\r\n\r\n onToolCallStart(toolCallId, toolName) {\r\n const tracker: ToolCallTracker = {\r\n toolCallId,\r\n toolName,\r\n argsText: '',\r\n args: undefined,\r\n state: 'partial-call',\r\n };\r\n toolCalls.set(toolCallId, tracker);\r\n\r\n const part: ToolCallPart = {\r\n type: 'tool-call',\r\n toolCallId,\r\n toolName,\r\n args: undefined,\r\n state: 'partial-call',\r\n };\r\n parts.push(part);\r\n emitUpdate();\r\n },\r\n\r\n onToolCallDelta(toolCallId, argsTextDelta) {\r\n const tracker = toolCalls.get(toolCallId);\r\n if (tracker) {\r\n tracker.argsText += argsTextDelta;\r\n try {\r\n tracker.args = JSON.parse(tracker.argsText);\r\n } catch {\r\n // Not valid JSON yet\r\n }\r\n const idx = findToolPartIndex(toolCallId);\r\n if (idx !== -1 && parts[idx].type === 'tool-call') {\r\n (parts[idx] as ToolCallPart).args = tracker.args;\r\n }\r\n emitUpdate();\r\n }\r\n },\r\n\r\n onToolCallComplete(toolCallId, toolName, args) {\r\n const tracker = toolCalls.get(toolCallId);\r\n if (tracker) {\r\n tracker.state = 'call';\r\n tracker.args = typeof args === 'string' ? safeJsonParse(args) : args;\r\n } else {\r\n toolCalls.set(toolCallId, {\r\n toolCallId,\r\n toolName,\r\n argsText: typeof args === 'string' ? args : JSON.stringify(args),\r\n args: typeof args === 'string' ? safeJsonParse(args) : args,\r\n state: 'call',\r\n });\r\n }\r\n\r\n const idx = findToolPartIndex(toolCallId);\r\n if (idx !== -1) {\r\n (parts[idx] as ToolCallPart).state = 'call';\r\n (parts[idx] as ToolCallPart).toolName = toolName;\r\n (parts[idx] as ToolCallPart).args = toolCalls.get(toolCallId)!.args;\r\n } else {\r\n parts.push({\r\n type: 'tool-call',\r\n toolCallId,\r\n toolName,\r\n args: toolCalls.get(toolCallId)!.args,\r\n state: 'call',\r\n });\r\n }\r\n emitUpdate();\r\n },\r\n\r\n onToolResult(toolCallId, result) {\r\n const tracker = toolCalls.get(toolCallId);\r\n if (tracker) {\r\n tracker.result = result;\r\n tracker.state = 'result';\r\n }\r\n\r\n const idx = findToolPartIndex(toolCallId);\r\n if (idx !== -1) {\r\n const existing = parts[idx] as ToolCallPart;\r\n const resultPart: ToolResultPart = {\r\n type: 'tool-result',\r\n toolCallId,\r\n toolName: existing.toolName,\r\n args: existing.args,\r\n result,\r\n state: 'result',\r\n };\r\n parts[idx] = resultPart;\r\n } else {\r\n parts.push({\r\n type: 'tool-result',\r\n toolCallId,\r\n toolName: tracker?.toolName || 'unknown',\r\n args: tracker?.args,\r\n result,\r\n state: 'result',\r\n });\r\n }\r\n emitUpdate();\r\n },\r\n\r\n onError(error) {\r\n console.error('[DataStreamParser] stream error:', error);\r\n },\r\n\r\n onStepFinish(_data) {\r\n emitUpdate();\r\n },\r\n\r\n onFinish(_data) {\r\n emitUpdate();\r\n },\r\n });\r\n\r\n return { textContent, parts, toolCalls };\r\n}\r\n\r\n// ── Utilities ────────────────────────────────────────────────────────\r\n\r\nfunction safeJsonParse(str: string): any {\r\n try {\r\n return JSON.parse(str);\r\n } catch {\r\n return str;\r\n }\r\n}\r\n","import type { Ref } from 'vue';\r\nimport { computed, ref } from 'vue';\r\nimport {\r\n parseDataStreamToMessage,\r\n type StreamParseResult,\r\n type ToolCallPart,\r\n type ToolResultPart,\r\n} from '../lib/data-stream-parser';\r\nimport type { AiChatbotXContext } from '../types';\r\n\r\nexport interface UseAgentInvokeOptions {\r\n endpoint: Ref<string>;\r\n projectId?: string;\r\n aiChatbotX: AiChatbotXContext;\r\n /** TTS 控制 */\r\n tts: {\r\n speak: (text: string) => void;\r\n feed: (delta: string) => void;\r\n flush: () => void;\r\n stop: () => void;\r\n };\r\n /** 气泡控制 */\r\n bubble: {\r\n open: () => void;\r\n scheduleDismiss: () => void;\r\n scrollToBottom: () => void;\r\n };\r\n /** 会话记忆超时(ms),超过此时间未发起新对话则自动清空历史,默认 120000(2分钟) */\r\n sessionTimeoutMs?: number;\r\n /** 最大保留历史轮数(一轮 = user + assistant),默认 10 */\r\n maxHistoryTurns?: number;\r\n}\r\n\r\n// ── 工具名称映射 ──\r\nconst toolDisplayNames: Record<string, string> = {\r\n generateReport: '生成报告',\r\n searchKnowledge: '知识库检索',\r\n resolveInstanceTargets: '解析实例目标',\r\n getHistoryMetrics: '历史数据查询',\r\n getRealtimeMetrics: '实时数据查询',\r\n queryBitableData: '多维表格查询',\r\n searchUser: '搜索用户',\r\n createBitableRecord: '创建表格记录',\r\n timeTool: '时间工具',\r\n loadSkill: '加载技能',\r\n executeCommand: '执行命令',\r\n dataAnalyzer: '数据分析',\r\n dataPredictor: '数据预测',\r\n};\r\n\r\n/**\r\n * Agent 调用 composable\r\n *\r\n * 管理 Agent 调用、流式解析、工具执行、文本/工具状态。\r\n * 支持中断(abort)以便在唤醒时取消正在进行的调用。\r\n */\r\nexport function useAgentInvoke(options: UseAgentInvokeOptions) {\r\n const { aiChatbotX, tts, bubble } = options;\r\n\r\n const sessionTimeoutMs = options.sessionTimeoutMs ?? 120_000;\r\n const maxHistoryTurns = options.maxHistoryTurns ?? 10;\r\n\r\n const isInvoking = ref(false);\r\n const currentTextContent = ref('');\r\n const currentToolParts = ref<(ToolCallPart | ToolResultPart)[]>([]);\r\n const executingTools = ref<Set<string>>(new Set());\r\n\r\n // ── 对话历史 ──\r\n type HistoryMessage = { role: 'user' | 'assistant'; content: string };\r\n const conversationHistory = ref<HistoryMessage[]>([]);\r\n let lastInteractionTime = 0;\r\n\r\n /** 检查会话是否超时,超时则自动清空历史 */\r\n const checkSessionTimeout = () => {\r\n if (lastInteractionTime > 0 && Date.now() - lastInteractionTime > sessionTimeoutMs) {\r\n conversationHistory.value = [];\r\n }\r\n };\r\n\r\n /** 追加消息到历史(自动裁剪超出 maxHistoryTurns 的旧记录) */\r\n const appendToHistory = (role: 'user' | 'assistant', content: string) => {\r\n conversationHistory.value.push({ role, content });\r\n // 一轮 = 2 条消息(user + assistant),裁剪到 maxHistoryTurns * 2\r\n const maxLen = maxHistoryTurns * 2;\r\n if (conversationHistory.value.length > maxLen) {\r\n conversationHistory.value = conversationHistory.value.slice(-maxLen);\r\n }\r\n };\r\n\r\n /** 手动清空对话历史 */\r\n const clearHistory = () => {\r\n conversationHistory.value = [];\r\n };\r\n\r\n // AbortController 用于中断正在进行的请求\r\n let abortController: AbortController | null = null;\r\n\r\n const hasAnyContent = computed(() => {\r\n return !!(currentTextContent.value || currentToolParts.value.length > 0);\r\n });\r\n\r\n const toolDisplayName = (name: string) => toolDisplayNames[name] || name;\r\n\r\n // ── 重置状态 ──\r\n\r\n const resetState = () => {\r\n currentTextContent.value = '';\r\n currentToolParts.value = [];\r\n executingTools.value = new Set();\r\n };\r\n\r\n // ── 宿主命令执行 ──\r\n\r\n const executeHostCommands = async (toolCallId: string, result: any) => {\r\n if (!result || typeof result !== 'object') return;\r\n const commands = result.commands;\r\n if (!Array.isArray(commands) || commands.length === 0) return;\r\n\r\n try {\r\n executingTools.value = new Set([...executingTools.value, toolCallId]);\r\n for (const cmd of commands) {\r\n const args = Array.isArray(cmd.args) ? cmd.args : [];\r\n try {\r\n await aiChatbotX.executeCommand(cmd.name, args);\r\n } catch (cmdErr) {\r\n console.error(`[AgentInvoke] 执行命令 ${cmd.name} 失败:`, cmdErr);\r\n }\r\n }\r\n } finally {\r\n const next = new Set(executingTools.value);\r\n next.delete(toolCallId);\r\n executingTools.value = next;\r\n }\r\n };\r\n\r\n // ── JSON 响应解析 ──\r\n\r\n const parseAssistantText = (payload: unknown): string => {\r\n if (!payload) return '';\r\n if (typeof payload === 'string') return payload;\r\n if (typeof payload === 'object') {\r\n const data = payload as Record<string, any>;\r\n const directText = data.output || data.answer || data.message || data.result;\r\n if (typeof directText === 'string' && directText.trim()) return directText;\r\n if (data.data && typeof data.data === 'object') {\r\n const nested = data.data as Record<string, any>;\r\n const nestedText = nested.output || nested.answer || nested.message || nested.result;\r\n if (typeof nestedText === 'string' && nestedText.trim()) return nestedText;\r\n }\r\n return JSON.stringify(payload);\r\n }\r\n return String(payload);\r\n };\r\n\r\n // ── 核心调用 ──\r\n\r\n const invoke = async (question: string) => {\r\n const content = question.trim();\r\n if (!content) return;\r\n\r\n // 如果有正在进行的调用,先中断\r\n abort();\r\n\r\n // 检查会话超时,必要时清空历史\r\n checkSessionTimeout();\r\n\r\n resetState();\r\n tts.stop();\r\n isInvoking.value = true;\r\n bubble.open();\r\n\r\n let prevTextLength = 0;\r\n const processedToolResults = new Set<string>();\r\n abortController = new AbortController();\r\n\r\n const commands = await aiChatbotX.hostCommads();\r\n\r\n // 构造请求体:包含历史消息\r\n const historyToSend = conversationHistory.value.length > 0 ? [...conversationHistory.value] : undefined;\r\n\r\n try {\r\n const response = await fetch(options.endpoint.value, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n input: content,\r\n projectId: options.projectId || '',\r\n commands: commands.length > 0 ? commands : undefined,\r\n messages: historyToSend,\r\n }),\r\n signal: abortController.signal,\r\n });\r\n\r\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\r\n\r\n const contentType = response.headers.get('content-type') || '';\r\n const isJsonResponse = contentType.includes('application/json');\r\n\r\n if (isJsonResponse) {\r\n const data = await response.json();\r\n const reply = parseAssistantText(data) || '已收到,但没有返回可展示的文本内容。';\r\n currentTextContent.value = reply;\r\n tts.speak(reply);\r\n\r\n // 追加到对话历史\r\n appendToHistory('user', content);\r\n appendToHistory('assistant', reply);\r\n\r\n if (data.toolResults && Array.isArray(data.toolResults)) {\r\n for (const tr of data.toolResults) {\r\n const toolPart: ToolResultPart = {\r\n type: 'tool-result',\r\n toolCallId: `invoke-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\r\n toolName: tr.toolName,\r\n args: tr.args,\r\n result: tr.result,\r\n state: 'result',\r\n };\r\n currentToolParts.value = [...currentToolParts.value, toolPart];\r\n if (tr.toolName === 'executeCommand') {\r\n executeHostCommands(toolPart.toolCallId, tr.result);\r\n }\r\n }\r\n }\r\n } else {\r\n await parseDataStreamToMessage(response, (result: StreamParseResult) => {\r\n currentTextContent.value = result.textContent;\r\n\r\n if (result.textContent.length > prevTextLength) {\r\n const delta = result.textContent.slice(prevTextLength);\r\n prevTextLength = result.textContent.length;\r\n tts.feed(delta);\r\n }\r\n\r\n const toolParts: (ToolCallPart | ToolResultPart)[] = result.parts.filter(\r\n (p): p is ToolCallPart | ToolResultPart => p.type === 'tool-call' || p.type === 'tool-result',\r\n );\r\n currentToolParts.value = toolParts;\r\n\r\n for (const part of toolParts) {\r\n if (part.toolName === 'executeCommand' && !processedToolResults.has(part.toolCallId)) {\r\n if (part.type === 'tool-call' && part.state === 'call' && part.args) {\r\n processedToolResults.add(part.toolCallId);\r\n executeHostCommands(part.toolCallId, part.args);\r\n } else if (part.type === 'tool-result' && part.result) {\r\n processedToolResults.add(part.toolCallId);\r\n executeHostCommands(part.toolCallId, part.result);\r\n }\r\n }\r\n }\r\n\r\n bubble.scrollToBottom();\r\n });\r\n\r\n tts.flush();\r\n\r\n // 流式响应完成后,追加到对话历史\r\n const assistantReply = currentTextContent.value.trim();\r\n appendToHistory('user', content);\r\n if (assistantReply) {\r\n appendToHistory('assistant', assistantReply);\r\n }\r\n\r\n if (!assistantReply && currentToolParts.value.length === 0) {\r\n currentTextContent.value = '已收到,但没有返回可展示的文本内容。';\r\n }\r\n }\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n // 被中断,静默处理\r\n return;\r\n }\r\n console.error('[AgentInvoke] invoke failed:', error);\r\n tts.stop();\r\n currentTextContent.value = '请求失败,请检查服务地址或稍后重试。';\r\n } finally {\r\n isInvoking.value = false;\r\n abortController = null;\r\n lastInteractionTime = Date.now();\r\n bubble.scheduleDismiss();\r\n }\r\n };\r\n\r\n // ── 中断当前调用 ──\r\n\r\n const abort = () => {\r\n if (abortController) {\r\n abortController.abort();\r\n abortController = null;\r\n }\r\n tts.stop();\r\n isInvoking.value = false;\r\n };\r\n\r\n return {\r\n isInvoking,\r\n currentTextContent,\r\n currentToolParts,\r\n executingTools,\r\n hasAnyContent,\r\n conversationHistory,\r\n toolDisplayName,\r\n invoke,\r\n abort,\r\n resetState,\r\n clearHistory,\r\n };\r\n}\r\n","<template>\r\n <div class=\"voice-assistant\" :data-theme=\"currentTheme\">\r\n <!-- ── 气泡区域:仅渲染 agent 回复 ── -->\r\n <transition name=\"bubble-fade\">\r\n <div class=\"bubble-stack\" v-if=\"showBubble\" ref=\"bubbleStackRef\" :style=\"bubbleStyle\">\r\n <div class=\"agent-bubble\">\r\n <!-- 工具执行步骤(内联紧凑样式) -->\r\n <div v-if=\"currentToolParts.length > 0\" class=\"tool-steps\">\r\n <div\r\n v-for=\"toolPart in currentToolParts\"\r\n :key=\"toolPart.toolCallId\"\r\n class=\"tool-step\"\r\n :class=\"{\r\n 'tool-step--loading': toolPart.state === 'partial-call' || toolPart.state === 'call',\r\n 'tool-step--done': toolPart.state === 'result',\r\n 'tool-step--error': toolPart.state === 'error',\r\n 'tool-step--executing': executingTools.has(toolPart.toolCallId),\r\n }\"\r\n >\r\n <!-- 状态图标 -->\r\n <span class=\"tool-step__icon\">\r\n <svg\r\n v-if=\"toolPart.state === 'partial-call' || toolPart.state === 'call'\"\r\n class=\"tool-step__spinner\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n >\r\n <circle\r\n cx=\"12\"\r\n cy=\"12\"\r\n r=\"10\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"\r\n stroke-dasharray=\"31.4 31.4\"\r\n />\r\n </svg>\r\n <svg v-else-if=\"toolPart.state === 'result'\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n d=\"M20 6L9 17l-5-5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n <svg v-else-if=\"toolPart.state === 'error'\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n <path d=\"M15 9l-6 6M9 9l6 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </span>\r\n <span class=\"tool-step__name\">{{ toolDisplayName(toolPart.toolName) }}</span>\r\n <span v-if=\"executingTools.has(toolPart.toolCallId)\" class=\"tool-step__tag tool-step__tag--exec\"\r\n >命令执行中</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <!-- 思考中动画(无工具、无文本时显示) -->\r\n <div v-if=\"isInvoking && !hasAnyContent\" class=\"thinking-dots\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n\r\n <!-- 文本内容 -->\r\n <div v-if=\"currentTextContent\" class=\"agent-text\">{{ currentTextContent }}</div>\r\n </div>\r\n </div>\r\n </transition>\r\n\r\n <!-- ── FAB 按钮 ── -->\r\n <div class=\"assistant-fab\" @click=\"toggleVoiceMode()\">\r\n <div v-if=\"transcriptionText || isInvoking\" class=\"status-pill\">\r\n {{ isInvoking ? '正在思考中...' : transcriptionText }}\r\n </div>\r\n\r\n <div class=\"fab-avatar-wrapper\">\r\n <img\r\n :src=\"xLogo ? xLogo : '/sime.png'\"\r\n alt=\"voice assistant\"\r\n :style=\"{\r\n width: `${xSize?.width || 88}px`,\r\n }\"\r\n />\r\n\r\n <transition name=\"indicator-fade\">\r\n <div v-if=\"voiceStatus === 'listening'\" class=\"listening-badge\" :class=\"{ 'wake-active': wakeAnimating }\">\r\n <div class=\"listening-waves\">\r\n <div class=\"wave wave-1\"></div>\r\n <div class=\"wave wave-2\"></div>\r\n <div class=\"wave wave-3\"></div>\r\n </div>\r\n <div class=\"listening-icon\">\r\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path\r\n d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z\"\r\n fill=\"currentColor\"\r\n />\r\n <path\r\n d=\"M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { computed, onBeforeUnmount } from 'vue';\r\nimport { injectStrict, AiChatbotXKey } from '../injection-key';\r\nimport type { VoiceConfig } from '../types';\r\nimport { useTTS } from '../composables/use-tts';\r\nimport { useBubble } from '../composables/use-bubble';\r\nimport { useVoiceRecognition } from '../composables/use-voice-recognition';\r\nimport { useAgentInvoke } from '../composables/use-agent-invoke';\r\n\r\ninterface XSize {\r\n width: number;\r\n height: number;\r\n}\r\n\r\ninterface BubbleSize {\r\n width?: string;\r\n maxHeight?: string;\r\n}\r\n\r\nconst props = defineProps<{\r\n xLogo?: string;\r\n xTitle?: string;\r\n xSize?: XSize;\r\n xTheme?: 'light' | 'dark' | 'system';\r\n wakeWords?: string[];\r\n modelPath?: string;\r\n projectId?: string;\r\n invokeUrl?: string;\r\n voiceConfig?: VoiceConfig;\r\n bubbleSize?: BubbleSize;\r\n bubbleDismissDelay?: number;\r\n}>();\r\n\r\nconst aiChatbotX = injectStrict(AiChatbotXKey);\r\n\r\nconst getVoiceConfig = (): VoiceConfig | null => {\r\n if (props.voiceConfig) return props.voiceConfig;\r\n try {\r\n return aiChatbotX.voiceConfig();\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\nconst currentTheme = 'dark' as const;\r\n\r\nconst endpoint = computed(() => {\r\n return props.invokeUrl || 'http://localhost:3001/agent/zyy55sw40nrl801056m0o/stream-invoke';\r\n});\r\n\r\nconst wakeResponses = ['您好'];\r\n\r\n// ── 1. TTS ──\r\n\r\nconst tts = useTTS(getVoiceConfig);\r\n\r\n// ── 2. Agent 调用(先创建,以获取 isInvoking ref) ──\r\n\r\n// 先声明 bubble 方法引用,后面绑定到真实 bubble 实例\r\nconst bubbleBridge = {\r\n open: () => {},\r\n scheduleDismiss: () => {},\r\n scrollToBottom: () => {},\r\n};\r\n\r\nconst agent = useAgentInvoke({\r\n endpoint,\r\n projectId: props.projectId,\r\n aiChatbotX,\r\n tts: {\r\n speak: tts.speak,\r\n feed: tts.feed,\r\n flush: tts.flush,\r\n stop: tts.stop,\r\n },\r\n bubble: {\r\n open: () => bubbleBridge.open(),\r\n scheduleDismiss: () => bubbleBridge.scheduleDismiss(),\r\n scrollToBottom: () => bubbleBridge.scrollToBottom(),\r\n },\r\n});\r\n\r\n// ── 3. 气泡(用 agent.isInvoking + tts.isSpeaking 保证气泡不会提前消失) ──\r\n\r\nconst bubble = useBubble({\r\n dismissDelay: props.bubbleDismissDelay,\r\n isSpeaking: tts.isSpeaking,\r\n isInvoking: agent.isInvoking,\r\n bubbleSize: props.bubbleSize,\r\n});\r\n\r\n// 绑定真实 bubble 方法\r\nbubbleBridge.open = bubble.open;\r\nbubbleBridge.scheduleDismiss = bubble.scheduleDismiss;\r\nbubbleBridge.scrollToBottom = bubble.scrollToBottom;\r\n\r\nconst { show: showBubble, style: bubbleStyle, stackRef: bubbleStackRef } = bubble;\r\n\r\n// TTS 队列清空后,如果调用已结束,触发气泡消失\r\ntts.setOnQueueEmpty(() => {\r\n if (!agent.isInvoking.value) {\r\n bubble.scheduleDismiss();\r\n }\r\n});\r\n\r\n// ── 4. 中断回复:唤醒时中断当前播报和调用 ──\r\n\r\nconst interruptCurrentResponse = () => {\r\n agent.abort();\r\n agent.resetState();\r\n tts.stop();\r\n bubble.hide();\r\n};\r\n\r\n// ── 5. 语音识别 ──\r\n\r\nconst voice = useVoiceRecognition({\r\n modelPath: props.modelPath,\r\n wakeWords: props.wakeWords,\r\n getVoiceConfig,\r\n onWake: () => {\r\n interruptCurrentResponse();\r\n tts.warmUpAudio();\r\n const text = wakeResponses[Math.floor(Math.random() * wakeResponses.length)];\r\n tts.speak(text);\r\n },\r\n onTranscriptionDone: (text) => {\r\n agent.invoke(text);\r\n },\r\n});\r\n\r\n// ── 切换语音模式(点击 FAB) ──\r\n\r\nconst toggleVoiceMode = async (targetState?: boolean) => {\r\n tts.warmUpAudio();\r\n await voice.toggleVoiceMode(targetState);\r\n};\r\n\r\n// ── 模板暴露 ──\r\n\r\nconst { voiceStatus, transcriptionText, wakeAnimating } = voice;\r\nconst { isInvoking, currentTextContent, currentToolParts, executingTools, hasAnyContent, toolDisplayName } = agent;\r\n\r\n// ── 外部方法注册 ──\r\n\r\naiChatbotX?.registerVoiceMethods({\r\n start: () => toggleVoiceMode(true),\r\n stop: () => toggleVoiceMode(false),\r\n openDialog: async () => Promise.resolve(),\r\n closeDialog: async () => Promise.resolve(),\r\n toggleCollapse: async () => Promise.resolve(),\r\n});\r\n\r\n// ── 清理 ──\r\n\r\nonBeforeUnmount(async () => {\r\n bubble.destroy();\r\n agent.abort();\r\n tts.destroy();\r\n await voice.destroy();\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.voice-assistant {\r\n --text-primary: #e6edf7;\r\n --text-secondary: #95a8c8;\r\n --glass-bg: rgba(8, 16, 32, 0.72);\r\n --glass-border: rgba(125, 160, 220, 0.28);\r\n --shadow-md: 0 18px 36px rgba(1, 6, 20, 0.56);\r\n --color-success: #4ade80;\r\n --color-error: #f87171;\r\n --color-accent: #818cf8;\r\n\r\n position: relative;\r\n display: inline-flex;\r\n flex-direction: column;\r\n align-items: flex-end;\r\n gap: 12px;\r\n}\r\n\r\n/* ── FAB 按钮 ── */\r\n.assistant-fab {\r\n position: relative;\r\n cursor: pointer;\r\n transition:\r\n transform 0.2s ease,\r\n filter 0.2s ease;\r\n\r\n &:hover {\r\n transform: translateY(-1px) scale(1.03);\r\n filter: brightness(1.06);\r\n }\r\n}\r\n\r\n.status-pill {\r\n position: absolute;\r\n right: calc(100% + 12px);\r\n top: 50%;\r\n transform: translateY(-50%);\r\n max-width: 280px;\r\n background: var(--glass-bg);\r\n color: var(--text-primary);\r\n font-size: 12px;\r\n line-height: 1.45;\r\n padding: 8px 13px;\r\n border-radius: 999px;\r\n border: 1px solid var(--glass-border);\r\n backdrop-filter: blur(10px);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n box-shadow: 0 10px 20px rgba(2, 8, 24, 0.38);\r\n}\r\n\r\n.fab-avatar-wrapper {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n\r\n img {\r\n display: block;\r\n height: auto;\r\n object-fit: contain;\r\n filter: drop-shadow(var(--shadow-md)) saturate(1.05);\r\n }\r\n}\r\n\r\n/* ── 气泡容器 ── */\r\n.bubble-stack {\r\n position: absolute;\r\n right: 0;\r\n bottom: calc(100% + 16px);\r\n width: min(380px, 86vw);\r\n max-height: min(58vh, 520px);\r\n overflow: auto;\r\n\r\n &::-webkit-scrollbar {\r\n width: 4px;\r\n }\r\n\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(126, 155, 204, 0.3);\r\n border-radius: 999px;\r\n }\r\n}\r\n\r\n/* ── 统一 agent 气泡 ── */\r\n.agent-bubble {\r\n border-radius: 16px;\r\n padding: 12px 14px;\r\n background:\r\n radial-gradient(circle at 12% 10%, rgba(80, 122, 255, 0.14), transparent 50%),\r\n linear-gradient(155deg, rgba(24, 42, 72, 0.96), rgba(14, 24, 46, 0.97));\r\n border: 1px solid rgba(108, 141, 204, 0.2);\r\n box-shadow:\r\n 0 12px 32px rgba(1, 6, 20, 0.5),\r\n inset 0 1px 0 rgba(255, 255, 255, 0.04);\r\n backdrop-filter: blur(16px);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 0;\r\n animation: bubble-appear 0.3s cubic-bezier(0.16, 1, 0.3, 1);\r\n}\r\n\r\n@keyframes bubble-appear {\r\n from {\r\n opacity: 0;\r\n transform: translateY(8px) scale(0.97);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateY(0) scale(1);\r\n }\r\n}\r\n\r\n/* ── 工具执行步骤(内联紧凑) ── */\r\n.tool-steps {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n margin-bottom: 6px;\r\n padding-bottom: 8px;\r\n border-bottom: 1px solid rgba(125, 160, 220, 0.1);\r\n}\r\n\r\n.tool-step {\r\n display: flex;\r\n align-items: center;\r\n gap: 7px;\r\n padding: 4px 6px;\r\n border-radius: 8px;\r\n transition: background 0.2s ease;\r\n animation: step-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);\r\n\r\n &--loading {\r\n .tool-step__icon {\r\n color: var(--color-accent);\r\n }\r\n .tool-step__name {\r\n color: rgba(200, 215, 240, 0.85);\r\n }\r\n }\r\n\r\n &--done {\r\n .tool-step__icon {\r\n color: var(--color-success);\r\n }\r\n .tool-step__name {\r\n color: rgba(200, 215, 240, 0.55);\r\n }\r\n }\r\n\r\n &--error {\r\n .tool-step__icon {\r\n color: var(--color-error);\r\n }\r\n .tool-step__name {\r\n color: rgba(248, 113, 113, 0.8);\r\n }\r\n }\r\n\r\n &--executing {\r\n background: rgba(129, 140, 248, 0.06);\r\n .tool-step__icon {\r\n color: var(--color-accent);\r\n }\r\n }\r\n}\r\n\r\n@keyframes step-in {\r\n from {\r\n opacity: 0;\r\n transform: translateX(-6px);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateX(0);\r\n }\r\n}\r\n\r\n.tool-step__icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 18px;\r\n height: 18px;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tool-step__spinner {\r\n animation: tool-spin 0.8s linear infinite;\r\n}\r\n\r\n@keyframes tool-spin {\r\n from {\r\n transform: rotate(0deg);\r\n }\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n}\r\n\r\n.tool-step__name {\r\n font-size: 12px;\r\n font-weight: 500;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.tool-step__tag {\r\n font-size: 10px;\r\n font-weight: 500;\r\n padding: 1px 6px;\r\n border-radius: 4px;\r\n white-space: nowrap;\r\n flex-shrink: 0;\r\n\r\n &--exec {\r\n background: rgba(129, 140, 248, 0.12);\r\n color: var(--color-accent);\r\n }\r\n}\r\n\r\n/* ── 思考中动画 ── */\r\n.thinking-dots {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 5px;\r\n padding: 2px 0;\r\n\r\n span {\r\n width: 5px;\r\n height: 5px;\r\n border-radius: 50%;\r\n background: var(--text-secondary);\r\n animation: thinking-bounce 1s infinite ease-in-out;\r\n }\r\n\r\n span:nth-child(2) {\r\n animation-delay: 0.15s;\r\n }\r\n\r\n span:nth-child(3) {\r\n animation-delay: 0.3s;\r\n }\r\n}\r\n\r\n@keyframes thinking-bounce {\r\n 0%,\r\n 100% {\r\n transform: translateY(0);\r\n opacity: 0.3;\r\n }\r\n 50% {\r\n transform: translateY(-3px);\r\n opacity: 1;\r\n }\r\n}\r\n\r\n/* ── 文本内容 ── */\r\n.agent-text {\r\n font-size: 14px;\r\n line-height: 1.55;\r\n color: var(--text-primary);\r\n white-space: pre-wrap;\r\n word-break: break-word;\r\n}\r\n\r\n/* ── 气泡淡入淡出过渡 ── */\r\n.bubble-fade-enter-active {\r\n transition: all 0.35s cubic-bezier(0.16, 1, 0.3, 1);\r\n}\r\n\r\n.bubble-fade-leave-active {\r\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.bubble-fade-enter-from {\r\n opacity: 0;\r\n transform: translateY(12px) scale(0.95);\r\n}\r\n\r\n.bubble-fade-leave-to {\r\n opacity: 0;\r\n transform: translateY(8px) scale(0.97);\r\n}\r\n\r\n/* ── 监听状态指示器 ── */\r\n.listening-badge {\r\n position: absolute;\r\n top: -8px;\r\n right: -8px;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background-color: rgba(0, 0, 0, 0.72);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.listening-waves {\r\n position: absolute;\r\n inset: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.wave {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n border-radius: 50%;\r\n border: 2px solid rgba(255, 255, 255, 0.65);\r\n animation: wave-expand 3s ease-out infinite;\r\n}\r\n\r\n.wave-1 {\r\n animation-delay: 0s;\r\n}\r\n\r\n.wave-2 {\r\n animation-delay: 0.6s;\r\n}\r\n\r\n.wave-3 {\r\n animation-delay: 1.2s;\r\n}\r\n\r\n.listening-icon {\r\n position: relative;\r\n color: #fff;\r\n}\r\n\r\n.listening-badge.wake-active {\r\n background-color: rgba(34, 197, 94, 0.9);\r\n animation: wake-badge-pop 0.35s ease;\r\n}\r\n\r\n.indicator-fade-enter-active,\r\n.indicator-fade-leave-active {\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.indicator-fade-enter-from,\r\n.indicator-fade-leave-to {\r\n opacity: 0;\r\n transform: translateY(6px);\r\n}\r\n\r\n@media (max-width: 768px) {\r\n .bubble-stack {\r\n width: min(320px, 88vw);\r\n max-height: min(54vh, 420px);\r\n }\r\n\r\n .status-pill {\r\n max-width: 220px;\r\n }\r\n}\r\n\r\n@keyframes wave-expand {\r\n 0% {\r\n transform: scale(0.8);\r\n opacity: 0.8;\r\n }\r\n 100% {\r\n transform: scale(1.2);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n@keyframes wake-badge-pop {\r\n 0% {\r\n transform: scale(1);\r\n }\r\n 50% {\r\n transform: scale(1.35);\r\n }\r\n 100% {\r\n transform: scale(1);\r\n }\r\n}\r\n</style>\r\n"],"names":["clientCommandKey","_renderSlot","_createBlock","_Transition","_createElementBlock","_normalizeClass","_createElementVNode","_hoisted_1","_hoisted_2","_hoisted_3","_toDisplayString","_createVNode","_hoisted_4","_hoisted_5","_openBlock","_normalizeStyle","_hoisted_7","_hoisted_8","_hoisted_10","_hoisted_13","_unref","_Fragment","_renderList"],"mappings":"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"}
|