byt-lingxiao-ai 0.2.5 → 0.2.6

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.
@@ -3746,7 +3746,7 @@ if (typeof window !== 'undefined') {
3746
3746
  var es_iterator_constructor = __webpack_require__(8111);
3747
3747
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.for-each.js
3748
3748
  var es_iterator_for_each = __webpack_require__(7588);
3749
- ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindow.vue?vue&type=template&id=62955cf4&scoped=true
3749
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindow.vue?vue&type=template&id=d604373c&scoped=true
3750
3750
  var render = function render() {
3751
3751
  var _vm = this,
3752
3752
  _c = _vm._self._c;
@@ -3764,172 +3764,44 @@ var render = function render() {
3764
3764
  "src": _vm.audioSrc,
3765
3765
  "type": "audio/mpeg"
3766
3766
  }
3767
- }), _vm._v(" 您的浏览器不支持音频元素。 ")]), _vm.robotStatus !== 'leaving' ? _c('div', {
3768
- class: ['chat-robot', _vm.robotStatus]
3769
- }) : _c('div', {
3770
- staticClass: "chat-ai",
3771
- on: {
3772
- "click": _vm.toggleWindow
3773
- }
3774
- }, [_c('div', {
3775
- class: ['chat-ai-avater', _vm.avaterStatus]
3776
- }), _c('div', {
3777
- staticClass: "chat-ai-text"
3778
- }, [_vm._v(_vm._s(_vm.avaterText))])]), _c('div', {
3779
- directives: [{
3780
- name: "show",
3781
- rawName: "v-show",
3782
- value: _vm.visible,
3783
- expression: "visible"
3784
- }],
3785
- staticClass: "chat-overlay",
3786
- on: {
3787
- "click": _vm.handleOverlayClick
3788
- }
3789
- }, [_c('div', {
3790
- staticClass: "chat-window",
3791
- on: {
3792
- "click": function ($event) {
3793
- $event.stopPropagation();
3794
- }
3795
- }
3796
- }, [_c('div', {
3797
- staticClass: "chat-window-header"
3798
- }, [_c('div', {
3799
- staticClass: "chat-window-header-title"
3800
- }, [_vm._v("凌霄大模型AI对话")]), _c('div', {
3801
- staticClass: "chat-window-header-close",
3802
- on: {
3803
- "click": function ($event) {
3804
- _vm.visible = false;
3805
- }
3806
- }
3807
- }, [_c('svg', {
3808
- attrs: {
3809
- "xmlns": "http://www.w3.org/2000/svg",
3810
- "width": "24",
3811
- "height": "24",
3812
- "viewBox": "0 0 24 24",
3813
- "fill": "none"
3814
- }
3815
- }, [_c('path', {
3767
+ }), _vm._v(" 您的浏览器不支持音频元素。 ")]), _vm.robotStatus !== 'leaving' ? _c('ChatRobot', {
3816
3768
  attrs: {
3817
- "d": "M5.50002 5.5L18.5 18.5",
3818
- "stroke": "#4E5969",
3819
- "stroke-width": "1.89404",
3820
- "stroke-linecap": "round",
3821
- "stroke-linejoin": "round"
3769
+ "status": _vm.robotStatus
3822
3770
  }
3823
- }), _c('path', {
3771
+ }) : _c('ChatAvatar', {
3824
3772
  attrs: {
3825
- "d": "M5.50002 18.5L18.5 5.5",
3826
- "stroke": "#4E5969",
3827
- "stroke-width": "1.89404",
3828
- "stroke-linecap": "round",
3829
- "stroke-linejoin": "round"
3773
+ "status": _vm.avaterStatus
3774
+ },
3775
+ on: {
3776
+ "click": _vm.toggleWindow
3830
3777
  }
3831
- })])])]), _c('div', {
3832
- ref: "chatArea",
3833
- staticClass: "chat-window-content scrollbar-hide"
3834
- }, _vm._l(_vm.messages, function (message) {
3835
- return _c('div', {
3836
- key: message.id,
3837
- staticClass: "chat-window-message"
3838
- }, [message.type === 'user' ? _c('div', {
3839
- staticClass: "chat-window-message-user"
3840
- }, [_c('div', {
3841
- staticClass: "user-message"
3842
- }, [_vm._v(_vm._s(message.content))])]) : _c('div', {
3843
- staticClass: "chat-window-message-ai"
3844
- }, [_c('div', {
3845
- staticClass: "ai-render"
3846
- }, [_c('div', {
3847
- staticClass: "ai-thinking"
3848
- }, [_c('div', {
3849
- staticClass: "ai-thinking-time"
3850
- }, [_vm._v("思考用时" + _vm._s(message.time) + "秒")]), _c('div', {
3851
- staticClass: "ai-thinking-content"
3852
- }, [_vm._v(_vm._s(message.thinking))])]), _c('div', {
3853
- staticClass: "ai-content"
3854
- }, [_vm._v(_vm._s(message.content))])])])]);
3855
- }), 0), _c('div', {
3856
- staticClass: "chat-window-footer"
3857
- }, [_c('div', {
3858
- staticClass: "chat-window-textarea"
3859
- }, [_c('el-input', {
3860
- staticClass: "chat-window-input",
3778
+ }), _c('ChatWindowDialog', {
3861
3779
  attrs: {
3862
- "type": "textarea",
3863
- "placeholder": "有什么我能帮您的吗?",
3864
- "rows": "2",
3865
- "resize": "none"
3780
+ "messages": _vm.messages,
3781
+ "input-message": _vm.inputMessage,
3782
+ "think-status": _vm.thinkStatus
3866
3783
  },
3867
3784
  on: {
3868
- "keydown": _vm.handleKeyDown
3785
+ "update:inputMessage": function ($event) {
3786
+ _vm.inputMessage = $event;
3787
+ },
3788
+ "send": _vm.handleSend,
3789
+ "thinking-click": _vm.handleThinkingClick,
3790
+ "overlay-click": _vm.handleOverlayClick
3869
3791
  },
3870
3792
  model: {
3871
- value: _vm.inputMessage,
3793
+ value: _vm.visible,
3872
3794
  callback: function ($$v) {
3873
- _vm.inputMessage = $$v;
3795
+ _vm.visible = $$v;
3874
3796
  },
3875
- expression: "inputMessage"
3876
- }
3877
- }), _c('div', {
3878
- staticClass: "chat-window-bar"
3879
- }, [_c('div', {
3880
- staticClass: "chat-window-send",
3881
- on: {
3882
- "click": _vm.handleSend
3883
- }
3884
- }, [_c('svg', {
3885
- attrs: {
3886
- "xmlns": "http://www.w3.org/2000/svg",
3887
- "width": "20",
3888
- "height": "20",
3889
- "viewBox": "0 0 20 20",
3890
- "fill": "none"
3891
- }
3892
- }, [_c('g', {
3893
- attrs: {
3894
- "clip-path": "url(#clip0_640_2107)"
3895
- }
3896
- }, [_c('path', {
3897
- attrs: {
3898
- "d": "M18.6427 2.37822C19.3253 2.47432 19.8025 3.10738 19.7065 3.79002C19.6871 3.97072 19.5381 4.41327 19.5403 4.41161L14.9673 17.8079L14.9632 17.8093C14.7858 18.3838 14.212 18.7607 13.5971 18.6744C13.4173 18.6492 13.2504 18.5862 13.1055 18.4949L13.0973 18.4977L9.83449 16.3686C9.58371 16.2584 9.4276 15.9939 9.46729 15.7115C9.5154 15.3691 9.83278 15.1317 10.1751 15.1798C10.293 15.1964 10.3988 15.2448 10.4853 15.3161L13.4054 17.2314L13.4073 17.2317C13.4452 17.2566 13.4882 17.2746 13.5364 17.2814C13.6911 17.3029 13.8371 17.2052 13.8793 17.0593L18.0469 4.89796L8.27396 14.3367L7.77435 17.8916C7.72706 18.2281 7.41369 18.464 7.07727 18.4169C6.74073 18.3696 6.50469 18.0564 6.55198 17.7198L7.07633 13.9889C7.08231 13.9464 7.09382 13.9066 7.10727 13.867C7.13549 13.7645 7.19079 13.6657 7.27291 13.5866L17.0754 4.12041L2.68514 8.17767L2.68487 8.1796C2.58481 8.21873 2.50686 8.31058 2.49042 8.42643C2.47412 8.5424 2.52417 8.65007 2.6093 8.71729L2.60903 8.71922L3.28261 9.16101L3.28013 9.16461C3.47505 9.29254 3.58819 9.52563 3.55386 9.77111C3.50575 10.1134 3.18836 10.3509 2.84602 10.3028C2.75512 10.29 2.6708 10.2584 2.59833 10.2127L2.59806 10.2147L1.37843 9.42001L1.37951 9.41227C1.02215 9.14901 0.816644 8.70195 0.882687 8.23203C0.951867 7.74096 1.29791 7.35545 1.73968 7.21445L1.73995 7.21251L17.7833 2.57104C18.0287 2.41036 18.3294 2.3342 18.6427 2.37822Z",
3899
- "fill": "#013378"
3900
- }
3901
- }), _c('path', {
3902
- attrs: {
3903
- "d": "M3.1309 10.9936C3.2178 10.5684 3.82528 10.5684 3.91218 10.9936C4.10411 11.9326 4.83794 12.6664 5.77697 12.8584C6.20213 12.9453 6.20213 13.5527 5.77697 13.6397C4.83794 13.8316 4.10411 14.5654 3.91218 15.5044C3.82528 15.9296 3.2178 15.9296 3.1309 15.5044C2.93897 14.5654 2.20513 13.8316 1.26611 13.6397C0.840944 13.5527 0.840944 12.9453 1.26611 12.8584C2.20513 12.6664 2.93897 11.9326 3.1309 10.9936Z",
3904
- "fill": "#2B80F6"
3905
- }
3906
- }), _c('path', {
3907
- attrs: {
3908
- "d": "M6.20382 8.56242C6.25596 8.30732 6.62045 8.30732 6.67259 8.56242C6.78775 9.12583 7.22805 9.56613 7.79146 9.68129C8.04656 9.73343 8.04656 10.0979 7.79146 10.1501C7.22805 10.2652 6.78775 10.7055 6.67259 11.2689C6.62045 11.524 6.25596 11.524 6.20382 11.2689C6.08866 10.7055 5.64836 10.2652 5.08495 10.1501C4.82985 10.0979 4.82985 9.73343 5.08495 9.68129C5.64836 9.56613 6.08866 9.12583 6.20382 8.56242Z",
3909
- "fill": "#2B80F6"
3910
- }
3911
- })]), _c('defs', [_c('clipPath', {
3912
- attrs: {
3913
- "id": "clip0_640_2107"
3914
- }
3915
- }, [_c('rect', {
3916
- attrs: {
3917
- "width": "20",
3918
- "height": "20",
3919
- "fill": "white"
3797
+ expression: "visible"
3920
3798
  }
3921
- })])])])])])], 1)])])])]);
3799
+ })], 1);
3922
3800
  };
3923
3801
  var staticRenderFns = [];
3924
3802
 
3925
3803
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.push.js
3926
3804
  var es_array_push = __webpack_require__(4114);
3927
- // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array-buffer.detached.js
3928
- var es_array_buffer_detached = __webpack_require__(6573);
3929
- // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array-buffer.transfer.js
3930
- var es_array_buffer_transfer = __webpack_require__(8100);
3931
- // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array-buffer.transfer-to-fixed-length.js
3932
- var es_array_buffer_transfer_to_fixed_length = __webpack_require__(7936);
3933
3805
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.difference.v2.js
3934
3806
  var es_set_difference_v2 = __webpack_require__(7642);
3935
3807
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.intersection.v2.js
@@ -3944,176 +3816,888 @@ var es_set_is_superset_of_v2 = __webpack_require__(2475);
3944
3816
  var es_set_symmetric_difference_v2 = __webpack_require__(5024);
3945
3817
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.union.v2.js
3946
3818
  var es_set_union_v2 = __webpack_require__(1698);
3947
- // EXTERNAL MODULE: ./node_modules/core-js/modules/es.typed-array.with.js
3948
- var es_typed_array_with = __webpack_require__(9577);
3949
- ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindow.vue?vue&type=script&lang=js
3819
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatRobot.vue?vue&type=template&id=3d936cb2&scoped=true
3820
+ var ChatRobotvue_type_template_id_3d936cb2_scoped_true_render = function render() {
3821
+ var _vm = this,
3822
+ _c = _vm._self._c;
3823
+ return _c('div', {
3824
+ class: ['chat-robot', _vm.status]
3825
+ });
3826
+ };
3827
+ var ChatRobotvue_type_template_id_3d936cb2_scoped_true_staticRenderFns = [];
3828
+
3829
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatRobot.vue?vue&type=script&lang=js
3830
+ /* harmony default export */ var ChatRobotvue_type_script_lang_js = ({
3831
+ name: 'ChatRobot',
3832
+ props: {
3833
+ status: {
3834
+ type: String,
3835
+ required: true,
3836
+ validator: value => ['entering', 'waiting', 'speaking'].includes(value)
3837
+ }
3838
+ }
3839
+ });
3840
+ ;// ./components/ChatRobot.vue?vue&type=script&lang=js
3841
+ /* harmony default export */ var components_ChatRobotvue_type_script_lang_js = (ChatRobotvue_type_script_lang_js);
3842
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatRobot.vue?vue&type=style&index=0&id=3d936cb2&prod&scoped=true&lang=css
3843
+ // extracted by mini-css-extract-plugin
3844
+
3845
+ ;// ./components/ChatRobot.vue?vue&type=style&index=0&id=3d936cb2&prod&scoped=true&lang=css
3846
+
3847
+ ;// ./node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js
3848
+ /* globals __VUE_SSR_CONTEXT__ */
3849
+
3850
+ // IMPORTANT: Do NOT use ES2015 features in this file (except for modules).
3851
+ // This module is a runtime utility for cleaner component module output and will
3852
+ // be included in the final webpack user bundle.
3853
+
3854
+ function normalizeComponent(
3855
+ scriptExports,
3856
+ render,
3857
+ staticRenderFns,
3858
+ functionalTemplate,
3859
+ injectStyles,
3860
+ scopeId,
3861
+ moduleIdentifier /* server only */,
3862
+ shadowMode /* vue-cli only */
3863
+ ) {
3864
+ // Vue.extend constructor export interop
3865
+ var options =
3866
+ typeof scriptExports === 'function' ? scriptExports.options : scriptExports
3867
+
3868
+ // render functions
3869
+ if (render) {
3870
+ options.render = render
3871
+ options.staticRenderFns = staticRenderFns
3872
+ options._compiled = true
3873
+ }
3950
3874
 
3875
+ // functional template
3876
+ if (functionalTemplate) {
3877
+ options.functional = true
3878
+ }
3951
3879
 
3880
+ // scopedId
3881
+ if (scopeId) {
3882
+ options._scopeId = 'data-v-' + scopeId
3883
+ }
3952
3884
 
3885
+ var hook
3886
+ if (moduleIdentifier) {
3887
+ // server build
3888
+ hook = function (context) {
3889
+ // 2.3 injection
3890
+ context =
3891
+ context || // cached call
3892
+ (this.$vnode && this.$vnode.ssrContext) || // stateful
3893
+ (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
3894
+ // 2.2 with runInNewContext: true
3895
+ if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
3896
+ context = __VUE_SSR_CONTEXT__
3897
+ }
3898
+ // inject component styles
3899
+ if (injectStyles) {
3900
+ injectStyles.call(this, context)
3901
+ }
3902
+ // register component module identifier for async chunk inferrence
3903
+ if (context && context._registeredComponents) {
3904
+ context._registeredComponents.add(moduleIdentifier)
3905
+ }
3906
+ }
3907
+ // used by ssr in case component is cached and beforeCreate
3908
+ // never gets called
3909
+ options._ssrRegister = hook
3910
+ } else if (injectStyles) {
3911
+ hook = shadowMode
3912
+ ? function () {
3913
+ injectStyles.call(
3914
+ this,
3915
+ (options.functional ? this.parent : this).$root.$options.shadowRoot
3916
+ )
3917
+ }
3918
+ : injectStyles
3919
+ }
3953
3920
 
3921
+ if (hook) {
3922
+ if (options.functional) {
3923
+ // for template-only hot-reload because in that case the render fn doesn't
3924
+ // go through the normalizer
3925
+ options._injectStyles = hook
3926
+ // register for functional component in vue file
3927
+ var originalRender = options.render
3928
+ options.render = function renderWithStyleInjection(h, context) {
3929
+ hook.call(context)
3930
+ return originalRender(h, context)
3931
+ }
3932
+ } else {
3933
+ // inject component registration as beforeCreate hook
3934
+ var existing = options.beforeCreate
3935
+ options.beforeCreate = existing ? [].concat(existing, hook) : [hook]
3936
+ }
3937
+ }
3954
3938
 
3939
+ return {
3940
+ exports: scriptExports,
3941
+ options: options
3942
+ }
3943
+ }
3955
3944
 
3945
+ ;// ./components/ChatRobot.vue
3956
3946
 
3957
3947
 
3958
3948
 
3949
+ ;
3959
3950
 
3960
3951
 
3952
+ /* normalize component */
3961
3953
 
3954
+ var component = normalizeComponent(
3955
+ components_ChatRobotvue_type_script_lang_js,
3956
+ ChatRobotvue_type_template_id_3d936cb2_scoped_true_render,
3957
+ ChatRobotvue_type_template_id_3d936cb2_scoped_true_staticRenderFns,
3958
+ false,
3959
+ null,
3960
+ "3d936cb2",
3961
+ null
3962
+
3963
+ )
3962
3964
 
3965
+ /* harmony default export */ var ChatRobot = (component.exports);
3966
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatAvatar.vue?vue&type=template&id=7b09a9c8&scoped=true
3967
+ var ChatAvatarvue_type_template_id_7b09a9c8_scoped_true_render = function render() {
3968
+ var _vm = this,
3969
+ _c = _vm._self._c;
3970
+ return _c('div', {
3971
+ staticClass: "chat-ai",
3972
+ on: {
3973
+ "click": function ($event) {
3974
+ return _vm.$emit('click');
3975
+ }
3976
+ }
3977
+ }, [_c('div', {
3978
+ class: ['chat-ai-avater', _vm.status]
3979
+ }), _c('div', {
3980
+ staticClass: "chat-ai-text"
3981
+ }, [_vm._v(_vm._s(_vm.statusText))])]);
3982
+ };
3983
+ var ChatAvatarvue_type_template_id_7b09a9c8_scoped_true_staticRenderFns = [];
3963
3984
 
3964
- const SAMPLE_RATE = 16000;
3965
- const FRAME_SIZE = 512;
3966
- /* harmony default export */ var ChatWindowvue_type_script_lang_js = ({
3967
- name: 'ChatWindow',
3985
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatAvatar.vue?vue&type=script&lang=js
3986
+ /* harmony default export */ var ChatAvatarvue_type_script_lang_js = ({
3987
+ name: 'ChatAvatar',
3968
3988
  props: {
3969
- appendToBody: {
3970
- type: Boolean,
3971
- default: true
3989
+ status: {
3990
+ type: String,
3991
+ required: true,
3992
+ validator: value => ['normal', 'thinking', 'output'].includes(value)
3972
3993
  }
3973
3994
  },
3974
- data() {
3975
- return {
3976
- audioSrc: '/minio/lingxiaoai/byt.mp3',
3977
- // 音频URL
3978
- inputMessage: '',
3979
- // 输入消息
3980
- visible: false,
3981
- // 窗口是否可见
3982
- messages: [{
3983
- id: 1,
3984
- type: 'user',
3985
- sender: '',
3986
- time: '',
3987
- content: '你好,欢迎来到凌霄大模型AI对话。'
3988
- }, {
3989
- id: 2,
3990
- type: 'ai',
3991
- sender: 'AI',
3992
- time: '',
3993
- thinking: '嗯,用户问的是回转窑的工业应用。首先,我需要回忆一下之前对话的内容。用户之前让我解释了水泥的制作流程,特别是提到了回转窑在高温煅烧熟料中的作用。',
3994
- charts: [{
3995
- title: '',
3996
- options: {}
3997
- }],
3998
- content: '回转窑(Rotary Kiln)是一种长筒形旋转煅烧设备(类似倾斜安装的大管子),因其独特的旋转运动和高温耐火衬里设计,在多个工业领域都有广泛应用'
3999
- }],
4000
- // 消息列表
4001
- isRecording: false,
4002
- // 正在录制
4003
- isMicAvailable: false,
4004
- // 麦克风是否可用
4005
- mediaRecorder: null,
4006
- // 媒体录制器
4007
- ws: null,
4008
- // WebSocket连接
4009
- // wsUrl: 'wss://mes.shnfonline.top:8316/ai_model/ws/voice-stream', // WebSocket URL
4010
- wsUrl: 'ws://192.168.8.9:9999/ai_model/ws/voice-stream',
4011
- // WebSocket URL
4012
- isConnected: false,
4013
- // WebSocket是否已连接
4014
- audioContext: null,
4015
- // 音频上下文
4016
- microphone: null,
4017
- // 麦克风输入节点
4018
- processor: null,
4019
- // 音频处理节点
4020
- robotStatus: 'leaving',
4021
- // 机器人状态 waiting, speaking, leaving, entering
4022
- avaterStatus: 'normal',
4023
- // 头像状态 normal output thinking
4024
- buffer: '',
4025
- // 音频缓冲区
4026
- currentMessage: null,
4027
- // 当前消息
4028
- inTag: false,
4029
- // 是否在标签页
4030
- tagBuilder: '',
4031
- // 标签构建器
4032
- audioBuffer: new Float32Array(0) // 音频缓冲区
4033
- };
4034
- },
4035
3995
  computed: {
4036
- avaterText() {
3996
+ statusText() {
4037
3997
  const textMap = {
4038
3998
  'normal': '凌霄AI',
4039
3999
  'thinking': '思考中',
4040
4000
  'output': '语音中'
4041
4001
  };
4042
- return textMap[this.avaterStatus];
4002
+ return textMap[this.status];
4043
4003
  }
4044
- },
4045
- mounted() {
4046
- this.initWebSocket();
4004
+ }
4005
+ });
4006
+ ;// ./components/ChatAvatar.vue?vue&type=script&lang=js
4007
+ /* harmony default export */ var components_ChatAvatarvue_type_script_lang_js = (ChatAvatarvue_type_script_lang_js);
4008
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatAvatar.vue?vue&type=style&index=0&id=7b09a9c8&prod&scoped=true&lang=css
4009
+ // extracted by mini-css-extract-plugin
4047
4010
 
4048
- // 处理append-to-body逻辑
4049
- if (this.appendToBody) {
4050
- this.appendToBodyHandler();
4011
+ ;// ./components/ChatAvatar.vue?vue&type=style&index=0&id=7b09a9c8&prod&scoped=true&lang=css
4012
+
4013
+ ;// ./components/ChatAvatar.vue
4014
+
4015
+
4016
+
4017
+ ;
4018
+
4019
+
4020
+ /* normalize component */
4021
+
4022
+ var ChatAvatar_component = normalizeComponent(
4023
+ components_ChatAvatarvue_type_script_lang_js,
4024
+ ChatAvatarvue_type_template_id_7b09a9c8_scoped_true_render,
4025
+ ChatAvatarvue_type_template_id_7b09a9c8_scoped_true_staticRenderFns,
4026
+ false,
4027
+ null,
4028
+ "7b09a9c8",
4029
+ null
4030
+
4031
+ )
4032
+
4033
+ /* harmony default export */ var ChatAvatar = (ChatAvatar_component.exports);
4034
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindowDialog.vue?vue&type=template&id=5eca994a&scoped=true
4035
+ var ChatWindowDialogvue_type_template_id_5eca994a_scoped_true_render = function render() {
4036
+ var _vm = this,
4037
+ _c = _vm._self._c;
4038
+ return _c('div', {
4039
+ directives: [{
4040
+ name: "show",
4041
+ rawName: "v-show",
4042
+ value: _vm.value,
4043
+ expression: "value"
4044
+ }],
4045
+ staticClass: "chat-overlay",
4046
+ on: {
4047
+ "click": function ($event) {
4048
+ return _vm.$emit('overlay-click');
4049
+ }
4050
+ }
4051
+ }, [_c('div', {
4052
+ staticClass: "chat-window",
4053
+ on: {
4054
+ "click": function ($event) {
4055
+ $event.stopPropagation();
4056
+ }
4057
+ }
4058
+ }, [_c('ChatWindowHeader', {
4059
+ on: {
4060
+ "close": function ($event) {
4061
+ return _vm.$emit('input', false);
4062
+ }
4063
+ }
4064
+ }), _c('ChatMessageList', {
4065
+ ref: "messageList",
4066
+ attrs: {
4067
+ "messages": _vm.messages,
4068
+ "think-status": _vm.thinkStatus
4069
+ },
4070
+ on: {
4071
+ "thinking-click": function ($event) {
4072
+ return _vm.$emit('thinking-click');
4073
+ }
4074
+ }
4075
+ }), _c('ChatInputBox', {
4076
+ attrs: {
4077
+ "value": _vm.inputMessage
4078
+ },
4079
+ on: {
4080
+ "input": function ($event) {
4081
+ return _vm.$emit('update:inputMessage', $event);
4082
+ },
4083
+ "send": function ($event) {
4084
+ return _vm.$emit('send');
4085
+ }
4086
+ }
4087
+ })], 1)]);
4088
+ };
4089
+ var ChatWindowDialogvue_type_template_id_5eca994a_scoped_true_staticRenderFns = [];
4090
+
4091
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindowHeader.vue?vue&type=template&id=6518e4ca&scoped=true
4092
+ var ChatWindowHeadervue_type_template_id_6518e4ca_scoped_true_render = function render() {
4093
+ var _vm = this,
4094
+ _c = _vm._self._c;
4095
+ return _c('div', {
4096
+ staticClass: "chat-window-header"
4097
+ }, [_c('div', {
4098
+ staticClass: "chat-window-header-title"
4099
+ }, [_vm._v("凌霄大模型AI123对话")]), _c('div', {
4100
+ staticClass: "chat-window-header-open",
4101
+ on: {
4102
+ "click": _vm.handleOpen
4103
+ }
4104
+ }, [_c('svg', {
4105
+ attrs: {
4106
+ "xmlns": "http://www.w3.org/2000/svg",
4107
+ "width": "24",
4108
+ "height": "24",
4109
+ "viewBox": "0 0 24 24",
4110
+ "fill": "none"
4111
+ }
4112
+ }, [_c('path', {
4113
+ attrs: {
4114
+ "d": "M14.5 4.5H19.5V9.5",
4115
+ "stroke": "#4E5969",
4116
+ "stroke-width": "1.66667",
4117
+ "stroke-linecap": "round",
4118
+ "stroke-linejoin": "round"
4119
+ }
4120
+ }), _c('path', {
4121
+ attrs: {
4122
+ "d": "M9.5 19.5H4.5V14.5",
4123
+ "stroke": "#4E5969",
4124
+ "stroke-width": "1.66667",
4125
+ "stroke-linecap": "round",
4126
+ "stroke-linejoin": "round"
4127
+ }
4128
+ }), _c('path', {
4129
+ attrs: {
4130
+ "d": "M19.5 4.5L14.0833 9.91667",
4131
+ "stroke": "#4E5969",
4132
+ "stroke-width": "1.66667",
4133
+ "stroke-linecap": "round",
4134
+ "stroke-linejoin": "round"
4135
+ }
4136
+ }), _c('path', {
4137
+ attrs: {
4138
+ "d": "M9.91667 14.083L4.5 19.4997",
4139
+ "stroke": "#4E5969",
4140
+ "stroke-width": "1.66667",
4141
+ "stroke-linecap": "round",
4142
+ "stroke-linejoin": "round"
4143
+ }
4144
+ })])]), _c('div', {
4145
+ staticClass: "chat-window-header-close",
4146
+ on: {
4147
+ "click": function ($event) {
4148
+ return _vm.$emit('close');
4149
+ }
4150
+ }
4151
+ }, [_c('svg', {
4152
+ attrs: {
4153
+ "xmlns": "http://www.w3.org/2000/svg",
4154
+ "width": "24",
4155
+ "height": "24",
4156
+ "viewBox": "0 0 24 24",
4157
+ "fill": "none"
4158
+ }
4159
+ }, [_c('path', {
4160
+ attrs: {
4161
+ "d": "M5.50002 5.5L18.5 18.5",
4162
+ "stroke": "#4E5969",
4163
+ "stroke-width": "1.89404",
4164
+ "stroke-linecap": "round",
4165
+ "stroke-linejoin": "round"
4166
+ }
4167
+ }), _c('path', {
4168
+ attrs: {
4169
+ "d": "M5.50002 18.5L18.5 5.5",
4170
+ "stroke": "#4E5969",
4171
+ "stroke-width": "1.89404",
4172
+ "stroke-linecap": "round",
4173
+ "stroke-linejoin": "round"
4174
+ }
4175
+ })])])]);
4176
+ };
4177
+ var ChatWindowHeadervue_type_template_id_6518e4ca_scoped_true_staticRenderFns = [];
4178
+
4179
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindowHeader.vue?vue&type=script&lang=js
4180
+ /* harmony default export */ var ChatWindowHeadervue_type_script_lang_js = ({
4181
+ name: 'ChatWindowHeader',
4182
+ methods: {
4183
+ handleOpen() {
4184
+ const path = this.$router.resolve({
4185
+ name: '/chat'
4186
+ });
4187
+ window.open(path.href, '_blank');
4188
+ }
4189
+ }
4190
+ });
4191
+ ;// ./components/ChatWindowHeader.vue?vue&type=script&lang=js
4192
+ /* harmony default export */ var components_ChatWindowHeadervue_type_script_lang_js = (ChatWindowHeadervue_type_script_lang_js);
4193
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindowHeader.vue?vue&type=style&index=0&id=6518e4ca&prod&scoped=true&lang=css
4194
+ // extracted by mini-css-extract-plugin
4195
+
4196
+ ;// ./components/ChatWindowHeader.vue?vue&type=style&index=0&id=6518e4ca&prod&scoped=true&lang=css
4197
+
4198
+ ;// ./components/ChatWindowHeader.vue
4199
+
4200
+
4201
+
4202
+ ;
4203
+
4204
+
4205
+ /* normalize component */
4206
+
4207
+ var ChatWindowHeader_component = normalizeComponent(
4208
+ components_ChatWindowHeadervue_type_script_lang_js,
4209
+ ChatWindowHeadervue_type_template_id_6518e4ca_scoped_true_render,
4210
+ ChatWindowHeadervue_type_template_id_6518e4ca_scoped_true_staticRenderFns,
4211
+ false,
4212
+ null,
4213
+ "6518e4ca",
4214
+ null
4215
+
4216
+ )
4217
+
4218
+ /* harmony default export */ var ChatWindowHeader = (ChatWindowHeader_component.exports);
4219
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatMessageList.vue?vue&type=template&id=ba7356ea&scoped=true
4220
+ var ChatMessageListvue_type_template_id_ba7356ea_scoped_true_render = function render() {
4221
+ var _vm = this,
4222
+ _c = _vm._self._c;
4223
+ return _c('div', {
4224
+ ref: "chatArea",
4225
+ staticClass: "chat-window-content scrollbar-hide"
4226
+ }, _vm._l(_vm.messages, function (message) {
4227
+ return _c('div', {
4228
+ key: message.id,
4229
+ staticClass: "chat-window-message"
4230
+ }, [message.type === 'user' ? _c('UserMessage', {
4231
+ attrs: {
4232
+ "content": message.content
4233
+ }
4234
+ }) : _c('AiMessage', {
4235
+ attrs: {
4236
+ "message": message,
4237
+ "think-status": _vm.thinkStatus
4238
+ },
4239
+ on: {
4240
+ "thinking-click": function ($event) {
4241
+ return _vm.$emit('thinking-click');
4242
+ }
4243
+ }
4244
+ })], 1);
4245
+ }), 0);
4246
+ };
4247
+ var ChatMessageListvue_type_template_id_ba7356ea_scoped_true_staticRenderFns = [];
4248
+
4249
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/UserMessage.vue?vue&type=template&id=6a2b6167&scoped=true
4250
+ var UserMessagevue_type_template_id_6a2b6167_scoped_true_render = function render() {
4251
+ var _vm = this,
4252
+ _c = _vm._self._c;
4253
+ return _c('div', {
4254
+ staticClass: "chat-window-message-user"
4255
+ }, [_c('div', {
4256
+ staticClass: "user-message"
4257
+ }, [_vm._v(_vm._s(_vm.content))])]);
4258
+ };
4259
+ var UserMessagevue_type_template_id_6a2b6167_scoped_true_staticRenderFns = [];
4260
+
4261
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/UserMessage.vue?vue&type=script&lang=js
4262
+ /* harmony default export */ var UserMessagevue_type_script_lang_js = ({
4263
+ name: 'UserMessage',
4264
+ props: {
4265
+ content: {
4266
+ type: String,
4267
+ required: true
4268
+ }
4269
+ }
4270
+ });
4271
+ ;// ./components/UserMessage.vue?vue&type=script&lang=js
4272
+ /* harmony default export */ var components_UserMessagevue_type_script_lang_js = (UserMessagevue_type_script_lang_js);
4273
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/UserMessage.vue?vue&type=style&index=0&id=6a2b6167&prod&scoped=true&lang=css
4274
+ // extracted by mini-css-extract-plugin
4275
+
4276
+ ;// ./components/UserMessage.vue?vue&type=style&index=0&id=6a2b6167&prod&scoped=true&lang=css
4277
+
4278
+ ;// ./components/UserMessage.vue
4279
+
4280
+
4281
+
4282
+ ;
4283
+
4284
+
4285
+ /* normalize component */
4286
+
4287
+ var UserMessage_component = normalizeComponent(
4288
+ components_UserMessagevue_type_script_lang_js,
4289
+ UserMessagevue_type_template_id_6a2b6167_scoped_true_render,
4290
+ UserMessagevue_type_template_id_6a2b6167_scoped_true_staticRenderFns,
4291
+ false,
4292
+ null,
4293
+ "6a2b6167",
4294
+ null
4295
+
4296
+ )
4297
+
4298
+ /* harmony default export */ var UserMessage = (UserMessage_component.exports);
4299
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/AiMessage.vue?vue&type=template&id=3347daf6&scoped=true
4300
+ var AiMessagevue_type_template_id_3347daf6_scoped_true_render = function render() {
4301
+ var _vm = this,
4302
+ _c = _vm._self._c;
4303
+ return _c('div', {
4304
+ staticClass: "chat-window-message-ai"
4305
+ }, [_c('div', {
4306
+ staticClass: "ai-render"
4307
+ }, [_c('div', {
4308
+ staticClass: "ai-thinking",
4309
+ on: {
4310
+ "click": function ($event) {
4311
+ return _vm.$emit('thinking-click');
4312
+ }
4313
+ }
4314
+ }, [_c('div', {
4315
+ staticClass: "ai-thinking-time"
4316
+ }, [_vm._v("思考用时" + _vm._s(_vm.message.time) + "秒")]), _vm.thinkStatus ? _c('div', {
4317
+ staticClass: "ai-thinking-content"
4318
+ }, [_vm._v(_vm._s(_vm.message.thinking))]) : _vm._e()]), _c('div', {
4319
+ staticClass: "ai-content"
4320
+ }, [_vm._v(_vm._s(_vm.message.content))])])]);
4321
+ };
4322
+ var AiMessagevue_type_template_id_3347daf6_scoped_true_staticRenderFns = [];
4323
+
4324
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/AiMessage.vue?vue&type=script&lang=js
4325
+ /* harmony default export */ var AiMessagevue_type_script_lang_js = ({
4326
+ name: 'AiMessage',
4327
+ props: {
4328
+ message: {
4329
+ type: Object,
4330
+ required: true
4331
+ },
4332
+ thinkStatus: {
4333
+ type: Boolean,
4334
+ default: true
4051
4335
  }
4336
+ }
4337
+ });
4338
+ ;// ./components/AiMessage.vue?vue&type=script&lang=js
4339
+ /* harmony default export */ var components_AiMessagevue_type_script_lang_js = (AiMessagevue_type_script_lang_js);
4340
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/AiMessage.vue?vue&type=style&index=0&id=3347daf6&prod&scoped=true&lang=css
4341
+ // extracted by mini-css-extract-plugin
4342
+
4343
+ ;// ./components/AiMessage.vue?vue&type=style&index=0&id=3347daf6&prod&scoped=true&lang=css
4344
+
4345
+ ;// ./components/AiMessage.vue
4346
+
4347
+
4348
+
4349
+ ;
4350
+
4351
+
4352
+ /* normalize component */
4353
+
4354
+ var AiMessage_component = normalizeComponent(
4355
+ components_AiMessagevue_type_script_lang_js,
4356
+ AiMessagevue_type_template_id_3347daf6_scoped_true_render,
4357
+ AiMessagevue_type_template_id_3347daf6_scoped_true_staticRenderFns,
4358
+ false,
4359
+ null,
4360
+ "3347daf6",
4361
+ null
4362
+
4363
+ )
4364
+
4365
+ /* harmony default export */ var AiMessage = (AiMessage_component.exports);
4366
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatMessageList.vue?vue&type=script&lang=js
4367
+
4368
+
4369
+ /* harmony default export */ var ChatMessageListvue_type_script_lang_js = ({
4370
+ name: 'ChatMessageList',
4371
+ components: {
4372
+ UserMessage: UserMessage,
4373
+ AiMessage: AiMessage
4052
4374
  },
4053
- unmounted() {
4054
- this.closeWebSocket();
4055
- this.stopRecording();
4375
+ props: {
4376
+ messages: {
4377
+ type: Array,
4378
+ required: true
4379
+ },
4380
+ thinkStatus: {
4381
+ type: Boolean,
4382
+ default: true
4383
+ }
4056
4384
  },
4057
- beforeDestroy() {
4058
- // 组件销毁前,如果元素被移动到body中,需要移除
4059
- if (this.appendToBody && this.$el.parentElement === document.body) {
4060
- document.body.removeChild(this.$el);
4385
+ methods: {
4386
+ scrollToBottom() {
4387
+ this.$nextTick(() => {
4388
+ const chatArea = this.$refs.chatArea;
4389
+ if (chatArea) {
4390
+ chatArea.scrollTop = chatArea.scrollHeight;
4391
+ }
4392
+ });
4393
+ }
4394
+ },
4395
+ watch: {
4396
+ messages: {
4397
+ handler() {
4398
+ this.scrollToBottom();
4399
+ },
4400
+ deep: true
4401
+ }
4402
+ }
4403
+ });
4404
+ ;// ./components/ChatMessageList.vue?vue&type=script&lang=js
4405
+ /* harmony default export */ var components_ChatMessageListvue_type_script_lang_js = (ChatMessageListvue_type_script_lang_js);
4406
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatMessageList.vue?vue&type=style&index=0&id=ba7356ea&prod&scoped=true&lang=css
4407
+ // extracted by mini-css-extract-plugin
4408
+
4409
+ ;// ./components/ChatMessageList.vue?vue&type=style&index=0&id=ba7356ea&prod&scoped=true&lang=css
4410
+
4411
+ ;// ./components/ChatMessageList.vue
4412
+
4413
+
4414
+
4415
+ ;
4416
+
4417
+
4418
+ /* normalize component */
4419
+
4420
+ var ChatMessageList_component = normalizeComponent(
4421
+ components_ChatMessageListvue_type_script_lang_js,
4422
+ ChatMessageListvue_type_template_id_ba7356ea_scoped_true_render,
4423
+ ChatMessageListvue_type_template_id_ba7356ea_scoped_true_staticRenderFns,
4424
+ false,
4425
+ null,
4426
+ "ba7356ea",
4427
+ null
4428
+
4429
+ )
4430
+
4431
+ /* harmony default export */ var ChatMessageList = (ChatMessageList_component.exports);
4432
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatInputBox.vue?vue&type=template&id=6f416073&scoped=true
4433
+ var ChatInputBoxvue_type_template_id_6f416073_scoped_true_render = function render() {
4434
+ var _vm = this,
4435
+ _c = _vm._self._c;
4436
+ return _c('div', {
4437
+ staticClass: "chat-window-footer"
4438
+ }, [_c('div', {
4439
+ staticClass: "chat-window-textarea"
4440
+ }, [_c('el-input', {
4441
+ staticClass: "chat-window-input",
4442
+ attrs: {
4443
+ "type": "textarea",
4444
+ "placeholder": "有什么我能帮您的吗?",
4445
+ "rows": "2",
4446
+ "resize": "none",
4447
+ "value": _vm.value
4448
+ },
4449
+ on: {
4450
+ "input": function ($event) {
4451
+ return _vm.$emit('input', $event);
4452
+ }
4453
+ },
4454
+ nativeOn: {
4455
+ "keydown": function ($event) {
4456
+ return _vm.handleKeyDown.apply(null, arguments);
4457
+ }
4458
+ }
4459
+ }), _c('div', {
4460
+ staticClass: "chat-window-bar"
4461
+ }, [_c('div', {
4462
+ staticClass: "chat-window-send",
4463
+ on: {
4464
+ "click": function ($event) {
4465
+ return _vm.$emit('send');
4466
+ }
4467
+ }
4468
+ }, [_c('svg', {
4469
+ attrs: {
4470
+ "xmlns": "http://www.w3.org/2000/svg",
4471
+ "width": "20",
4472
+ "height": "20",
4473
+ "viewBox": "0 0 20 20",
4474
+ "fill": "none"
4475
+ }
4476
+ }, [_c('g', {
4477
+ attrs: {
4478
+ "clip-path": "url(#clip0_640_2107)"
4479
+ }
4480
+ }, [_c('path', {
4481
+ attrs: {
4482
+ "d": "M18.6427 2.37822C19.3253 2.47432 19.8025 3.10738 19.7065 3.79002C19.6871 3.97072 19.5381 4.41327 19.5403 4.41161L14.9673 17.8079L14.9632 17.8093C14.7858 18.3838 14.212 18.7607 13.5971 18.6744C13.4173 18.6492 13.2504 18.5862 13.1055 18.4949L13.0973 18.4977L9.83449 16.3686C9.58371 16.2584 9.4276 15.9939 9.46729 15.7115C9.5154 15.3691 9.83278 15.1317 10.1751 15.1798C10.293 15.1964 10.3988 15.2448 10.4853 15.3161L13.4054 17.2314L13.4073 17.2317C13.4452 17.2566 13.4882 17.2746 13.5364 17.2814C13.6911 17.3029 13.8371 17.2052 13.8793 17.0593L18.0469 4.89796L8.27396 14.3367L7.77435 17.8916C7.72706 18.2281 7.41369 18.464 7.07727 18.4169C6.74073 18.3696 6.50469 18.0564 6.55198 17.7198L7.07633 13.9889C7.08231 13.9464 7.09382 13.9066 7.10727 13.867C7.13549 13.7645 7.19079 13.6657 7.27291 13.5866L17.0754 4.12041L2.68514 8.17767L2.68487 8.1796C2.58481 8.21873 2.50686 8.31058 2.49042 8.42643C2.47412 8.5424 2.52417 8.65007 2.6093 8.71729L2.60903 8.71922L3.28261 9.16101L3.28013 9.16461C3.47505 9.29254 3.58819 9.52563 3.55386 9.77111C3.50575 10.1134 3.18836 10.3509 2.84602 10.3028C2.75512 10.29 2.6708 10.2584 2.59833 10.2127L2.59806 10.2147L1.37843 9.42001L1.37951 9.41227C1.02215 9.14901 0.816644 8.70195 0.882687 8.23203C0.951867 7.74096 1.29791 7.35545 1.73968 7.21445L1.73995 7.21251L17.7833 2.57104C18.0287 2.41036 18.3294 2.3342 18.6427 2.37822Z",
4483
+ "fill": "#013378"
4484
+ }
4485
+ }), _c('path', {
4486
+ attrs: {
4487
+ "d": "M3.1309 10.9936C3.2178 10.5684 3.82528 10.5684 3.91218 10.9936C4.10411 11.9326 4.83794 12.6664 5.77697 12.8584C6.20213 12.9453 6.20213 13.5527 5.77697 13.6397C4.83794 13.8316 4.10411 14.5654 3.91218 15.5044C3.82528 15.9296 3.2178 15.9296 3.1309 15.5044C2.93897 14.5654 2.20513 13.8316 1.26611 13.6397C0.840944 13.5527 0.840944 12.9453 1.26611 12.8584C2.20513 12.6664 2.93897 11.9326 3.1309 10.9936Z",
4488
+ "fill": "#2B80F6"
4489
+ }
4490
+ }), _c('path', {
4491
+ attrs: {
4492
+ "d": "M6.20382 8.56242C6.25596 8.30732 6.62045 8.30732 6.67259 8.56242C6.78775 9.12583 7.22805 9.56613 7.79146 9.68129C8.04656 9.73343 8.04656 10.0979 7.79146 10.1501C7.22805 10.2652 6.78775 10.7055 6.67259 11.2689C6.62045 11.524 6.25596 11.524 6.20382 11.2689C6.08866 10.7055 5.64836 10.2652 5.08495 10.1501C4.82985 10.0979 4.82985 9.73343 5.08495 9.68129C5.64836 9.56613 6.08866 9.12583 6.20382 8.56242Z",
4493
+ "fill": "#2B80F6"
4494
+ }
4495
+ })]), _c('defs', [_c('clipPath', {
4496
+ attrs: {
4497
+ "id": "clip0_640_2107"
4498
+ }
4499
+ }, [_c('rect', {
4500
+ attrs: {
4501
+ "width": "20",
4502
+ "height": "20",
4503
+ "fill": "white"
4504
+ }
4505
+ })])])])])])], 1)]);
4506
+ };
4507
+ var ChatInputBoxvue_type_template_id_6f416073_scoped_true_staticRenderFns = [];
4508
+
4509
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatInputBox.vue?vue&type=script&lang=js
4510
+ /* harmony default export */ var ChatInputBoxvue_type_script_lang_js = ({
4511
+ name: 'ChatInputBox',
4512
+ props: {
4513
+ value: {
4514
+ type: String,
4515
+ default: ''
4061
4516
  }
4062
- this.closeWebSocket();
4063
- this.stopRecording();
4064
4517
  },
4065
4518
  methods: {
4066
- // 处理音频播放结束事件
4067
- onAudioEnded() {
4068
- this.robotStatus = 'leaving';
4069
- this.jumpedTimePoints.clear();
4519
+ handleKeyDown(e) {
4520
+ if (e.key === 'Enter' && !e.shiftKey) {
4521
+ e.preventDefault();
4522
+ this.$emit('send');
4523
+ }
4524
+ }
4525
+ }
4526
+ });
4527
+ ;// ./components/ChatInputBox.vue?vue&type=script&lang=js
4528
+ /* harmony default export */ var components_ChatInputBoxvue_type_script_lang_js = (ChatInputBoxvue_type_script_lang_js);
4529
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatInputBox.vue?vue&type=style&index=0&id=6f416073&prod&scoped=true&lang=css
4530
+ // extracted by mini-css-extract-plugin
4531
+
4532
+ ;// ./components/ChatInputBox.vue?vue&type=style&index=0&id=6f416073&prod&scoped=true&lang=css
4533
+
4534
+ ;// ./components/ChatInputBox.vue
4535
+
4536
+
4537
+
4538
+ ;
4539
+
4540
+
4541
+ /* normalize component */
4542
+
4543
+ var ChatInputBox_component = normalizeComponent(
4544
+ components_ChatInputBoxvue_type_script_lang_js,
4545
+ ChatInputBoxvue_type_template_id_6f416073_scoped_true_render,
4546
+ ChatInputBoxvue_type_template_id_6f416073_scoped_true_staticRenderFns,
4547
+ false,
4548
+ null,
4549
+ "6f416073",
4550
+ null
4551
+
4552
+ )
4553
+
4554
+ /* harmony default export */ var ChatInputBox = (ChatInputBox_component.exports);
4555
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindowDialog.vue?vue&type=script&lang=js
4556
+
4557
+
4558
+
4559
+ /* harmony default export */ var ChatWindowDialogvue_type_script_lang_js = ({
4560
+ name: 'ChatWindowDialog',
4561
+ components: {
4562
+ ChatWindowHeader: ChatWindowHeader,
4563
+ ChatMessageList: ChatMessageList,
4564
+ ChatInputBox: ChatInputBox
4565
+ },
4566
+ props: {
4567
+ value: {
4568
+ type: Boolean,
4569
+ required: true
4070
4570
  },
4071
- // 处理音频播放时间更新事件
4072
- onTimeUpdate() {
4073
- const audio = this.$refs.audioPlayer;
4074
- const currentTime = audio.currentTime;
4075
- if (!this.jumpedTimePoints) {
4076
- this.jumpedTimePoints = new Set();
4571
+ messages: {
4572
+ type: Array,
4573
+ required: true
4574
+ },
4575
+ inputMessage: {
4576
+ type: String,
4577
+ default: ''
4578
+ },
4579
+ thinkStatus: {
4580
+ type: Boolean,
4581
+ default: true
4582
+ }
4583
+ }
4584
+ });
4585
+ ;// ./components/ChatWindowDialog.vue?vue&type=script&lang=js
4586
+ /* harmony default export */ var components_ChatWindowDialogvue_type_script_lang_js = (ChatWindowDialogvue_type_script_lang_js);
4587
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindowDialog.vue?vue&type=style&index=0&id=5eca994a&prod&scoped=true&lang=css
4588
+ // extracted by mini-css-extract-plugin
4589
+
4590
+ ;// ./components/ChatWindowDialog.vue?vue&type=style&index=0&id=5eca994a&prod&scoped=true&lang=css
4591
+
4592
+ ;// ./components/ChatWindowDialog.vue
4593
+
4594
+
4595
+
4596
+ ;
4597
+
4598
+
4599
+ /* normalize component */
4600
+
4601
+ var ChatWindowDialog_component = normalizeComponent(
4602
+ components_ChatWindowDialogvue_type_script_lang_js,
4603
+ ChatWindowDialogvue_type_template_id_5eca994a_scoped_true_render,
4604
+ ChatWindowDialogvue_type_template_id_5eca994a_scoped_true_staticRenderFns,
4605
+ false,
4606
+ null,
4607
+ "5eca994a",
4608
+ null
4609
+
4610
+ )
4611
+
4612
+ /* harmony default export */ var ChatWindowDialog = (ChatWindowDialog_component.exports);
4613
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array-buffer.detached.js
4614
+ var es_array_buffer_detached = __webpack_require__(6573);
4615
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array-buffer.transfer.js
4616
+ var es_array_buffer_transfer = __webpack_require__(8100);
4617
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array-buffer.transfer-to-fixed-length.js
4618
+ var es_array_buffer_transfer_to_fixed_length = __webpack_require__(7936);
4619
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.typed-array.with.js
4620
+ var es_typed_array_with = __webpack_require__(9577);
4621
+ ;// ./components/mixins/audioMixin.js
4622
+
4623
+
4624
+
4625
+
4626
+ /* harmony default export */ var audioMixin = ({
4627
+ data() {
4628
+ return {
4629
+ isRecording: false,
4630
+ isMicAvailable: false,
4631
+ audioContext: null,
4632
+ microphone: null,
4633
+ processor: null,
4634
+ audioBuffer: new Float32Array(0)
4635
+ };
4636
+ },
4637
+ methods: {
4638
+ async initAudio() {
4639
+ if (this.isRecording) return;
4640
+ try {
4641
+ this.isMicAvailable = true;
4642
+ const stream = await navigator.mediaDevices.getUserMedia({
4643
+ audio: {
4644
+ sampleRate: this.SAMPLE_RATE,
4645
+ channelCount: 1,
4646
+ noiseSuppression: true,
4647
+ echoCancellation: true
4648
+ }
4649
+ });
4650
+ this.audioContext = new AudioContext({
4651
+ sampleRate: this.SAMPLE_RATE
4652
+ });
4653
+ this.microphone = this.audioContext.createMediaStreamSource(stream);
4654
+ this.processor = this.audioContext.createScriptProcessor(this.FRAME_SIZE, 1, 1);
4655
+ this.processor.onaudioprocess = this.processAudio;
4656
+ this.microphone.connect(this.processor);
4657
+ this.processor.connect(this.audioContext.destination);
4658
+ this.isRecording = true;
4659
+ console.log(`录音中 (采样率: ${this.audioContext.sampleRate}Hz)`);
4660
+ } catch (error) {
4661
+ console.error("音频初始化失败:", error);
4662
+ this.isRecording = false;
4663
+ this.isMicAvailable = false;
4077
4664
  }
4078
- const timeJumpPoints = [{
4079
- time: 40,
4080
- url: '/permission/user',
4081
- name: 'permission_user',
4082
- title: '用户管理'
4083
- }, {
4084
- time: 65,
4085
- url: '/permission/menu',
4086
- name: 'permission_menu',
4087
- title: '菜单管理'
4088
- }, {
4089
- time: 75,
4090
- url: '/permission/role',
4091
- name: 'permission_role',
4092
- title: '角色管理'
4093
- }];
4094
- // 检查当前时间是否达到跳转点
4095
- timeJumpPoints.forEach(point => {
4096
- // 使用一定的误差范围,确保不会因为播放进度的微小差异而错过跳转点
4097
- if (currentTime >= point.time && currentTime < point.time + 0.5 && !this.jumpedTimePoints.has(point.time)) {
4098
- this.jumpedTimePoints.add(point.time);
4099
- console.log(`到达时间点 ${point.time} 秒,跳转到 ${point.title}`);
4100
- this.$appOptions.store.dispatch('tags/addTagview', {
4101
- path: point.url,
4102
- fullPath: point.url,
4103
- label: point.title,
4104
- name: point.title,
4105
- meta: {
4106
- title: point.title
4107
- },
4108
- query: {},
4109
- params: {}
4110
- });
4111
- this.$appOptions.router.push({
4112
- path: point.url
4113
- });
4665
+ },
4666
+ processAudio(event) {
4667
+ if (!this.isRecording) return;
4668
+ const inputData = event.inputBuffer.getChannelData(0);
4669
+ const tempBuffer = new Float32Array(this.audioBuffer.length + inputData.length);
4670
+ tempBuffer.set(this.audioBuffer, 0);
4671
+ tempBuffer.set(inputData, this.audioBuffer.length);
4672
+ this.audioBuffer = tempBuffer;
4673
+ while (this.audioBuffer.length >= this.FRAME_SIZE) {
4674
+ const frame = this.audioBuffer.slice(0, this.FRAME_SIZE);
4675
+ this.audioBuffer = this.audioBuffer.slice(this.FRAME_SIZE);
4676
+ const pcmData = this.floatTo16BitPCM(frame);
4677
+ if (this.ws && this.ws.readyState === this.ws.OPEN) {
4678
+ this.ws.send(pcmData);
4114
4679
  }
4115
- });
4116
- console.log('当前播放时间:', currentTime);
4680
+ }
4681
+ },
4682
+ floatTo16BitPCM(input) {
4683
+ const output = new Int16Array(input.length);
4684
+ for (let i = 0; i < input.length; i++) {
4685
+ const s = Math.max(-1, Math.min(1, input[i]));
4686
+ output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
4687
+ }
4688
+ return output.buffer;
4689
+ },
4690
+ stopRecording() {
4691
+ if (!this.isRecording) return;
4692
+ if (this.microphone) this.microphone.disconnect();
4693
+ if (this.processor) this.processor.disconnect();
4694
+ if (this.analyser) this.analyser.disconnect();
4695
+ if (this.audioContext) {
4696
+ this.audioContext.close().catch(e => {
4697
+ console.error("关闭音频上下文失败:", e);
4698
+ });
4699
+ }
4700
+ this.isRecording = false;
4117
4701
  },
4118
4702
  play() {
4119
4703
  this.robotStatus = 'speaking';
@@ -4129,42 +4713,62 @@ const FRAME_SIZE = 512;
4129
4713
  this.$refs.audioPlayer.currentTime = 0;
4130
4714
  this.jumpedTimePoints.clear();
4131
4715
  },
4716
+ analyzeAudioCommand(command) {
4717
+ console.log('分析音频命令:', command);
4718
+ if (command === 'C5') {
4719
+ this.robotStatus = 'entering';
4720
+ setTimeout(() => {
4721
+ this.robotStatus = 'speaking';
4722
+ this.play();
4723
+ }, 3000);
4724
+ } else if (command === 'C8') {
4725
+ this.robotStatus = 'speaking';
4726
+ this.play();
4727
+ } else if (command === 'C7') {
4728
+ this.robotStatus = 'waiting';
4729
+ this.pause();
4730
+ } else if (command === 'C6') {
4731
+ this.robotStatus = 'leaving';
4732
+ this.stop();
4733
+ }
4734
+ }
4735
+ }
4736
+ });
4737
+ ;// ./components/mixins/webSocketMixin.js
4738
+
4739
+
4740
+
4741
+ /* harmony default export */ var webSocketMixin = ({
4742
+ data() {
4743
+ return {
4744
+ ws: null,
4745
+ wsUrl: 'ws://192.168.8.9:9999/ai_model/ws/voice-stream',
4746
+ isConnected: false
4747
+ };
4748
+ },
4749
+ methods: {
4132
4750
  initWebSocket() {
4133
4751
  try {
4134
4752
  this.ws = new WebSocket(this.wsUrl);
4135
4753
  this.ws.binaryType = 'arraybuffer';
4136
4754
  this.ws.onopen = async () => {
4137
- console.log('连接成功');
4755
+ console.log('WebSocket 连接成功');
4138
4756
  this.isConnected = true;
4139
4757
  this.initAudio();
4140
4758
  };
4141
4759
  this.ws.onmessage = event => {
4142
4760
  try {
4143
4761
  console.log("收到原始消息:", event.data);
4144
- // 二进制数据直接返回
4145
4762
  if (event.data instanceof ArrayBuffer) {
4146
4763
  console.log("收到二进制音频数据");
4147
4764
  return;
4148
4765
  }
4149
- // 解析JSON数据
4150
4766
  const data = JSON.parse(event.data);
4151
4767
  console.log("解析后的数据:", data);
4152
4768
  if (data.type === 'config') {
4153
4769
  console.log('配置信息:', data);
4154
4770
  } else if (data.code === 0) {
4155
- if (data.data.type === 'detection') {
4156
- console.log('检测到唤醒词...');
4157
- this.avaterStatus = 'normal';
4158
- } else if (data.data.type === 'Collecting') {
4159
- console.log('状态: 采集中...');
4160
- this.avaterStatus = 'thinking';
4161
- } else if (data.data.type === 'command') {
4162
- // 根据指令改变机器人的状态
4163
- console.log('状态: 处理中...');
4164
- this.analyzeAudioCommand(data.data.category);
4165
- } else {
4166
- console.log('状态: 其他...');
4167
- }
4771
+ this.handleWebSocketMessage(data.data);
4168
4772
  } else {
4169
4773
  console.error("服务器返回错误:", data.msg);
4170
4774
  }
@@ -4173,7 +4777,7 @@ const FRAME_SIZE = 512;
4173
4777
  }
4174
4778
  };
4175
4779
  this.ws.onclose = () => {
4176
- console.log('连接关闭');
4780
+ console.log('WebSocket 连接关闭');
4177
4781
  this.isConnected = false;
4178
4782
  if (this.isRecording) {
4179
4783
  this.stopRecording();
@@ -4181,20 +4785,324 @@ const FRAME_SIZE = 512;
4181
4785
  setTimeout(() => {
4182
4786
  console.log('尝试重新建立连接');
4183
4787
  if (!this.isConnected) {
4184
- // 尝试重连
4185
4788
  this.initWebSocket();
4186
4789
  }
4187
4790
  }, 3000);
4188
4791
  };
4792
+ this.ws.onerror = error => {
4793
+ console.error('WebSocket 错误:', error);
4794
+ };
4189
4795
  } catch (error) {
4190
4796
  console.error('WebSocket连接失败:', error);
4191
4797
  }
4192
4798
  },
4799
+ handleWebSocketMessage(data) {
4800
+ if (data.type === 'detection') {
4801
+ console.log('检测到唤醒词');
4802
+ this.avaterStatus = 'normal';
4803
+ } else if (data.type === 'Collecting') {
4804
+ console.log('状态: 采集中');
4805
+ this.avaterStatus = 'thinking';
4806
+ } else if (data.type === 'command') {
4807
+ console.log('状态: 处理中');
4808
+ this.analyzeAudioCommand(data.category);
4809
+ } else {
4810
+ console.log('状态: 其他');
4811
+ }
4812
+ },
4193
4813
  closeWebSocket() {
4194
4814
  if (this.ws) {
4195
4815
  this.ws.close();
4196
4816
  }
4197
- },
4817
+ }
4818
+ }
4819
+ });
4820
+ ;// ./components/utils/StreamParser.js
4821
+
4822
+
4823
+ /**
4824
+ * SSE (Server-Sent Events) 流解析器
4825
+ * 优化点:
4826
+ * 1. 使用状态机模式处理标签解析
4827
+ * 2. 批量更新减少DOM操作
4828
+ * 3. 内存优化:避免频繁字符串拼接
4829
+ * 4. 可配置的更新频率
4830
+ */
4831
+ class StreamParser {
4832
+ constructor(options = {}) {
4833
+ this.options = {
4834
+ updateInterval: 16,
4835
+ // 更新间隔(ms),默认约60fps
4836
+ batchSize: 100,
4837
+ // 批处理大小
4838
+ debug: false,
4839
+ // 是否开启调试
4840
+ ...options
4841
+ };
4842
+ this.reset();
4843
+ }
4844
+
4845
+ /**
4846
+ * 重置解析器状态
4847
+ */
4848
+ reset() {
4849
+ this.buffer = '';
4850
+ this.contentBuffer = []; // 使用数组缓冲,避免频繁字符串拼接
4851
+ this.thinkingBuffer = [];
4852
+ this.inTag = false;
4853
+ this.tagBuffer = '';
4854
+ this.updateTimer = null;
4855
+ this.status = 'output'; // thinking | output
4856
+ this.metrics = {
4857
+ startTime: Date.now(),
4858
+ chunks: 0,
4859
+ events: 0,
4860
+ chars: 0
4861
+ };
4862
+ }
4863
+
4864
+ /**
4865
+ * 处理流数据块
4866
+ * @param {string} chunk - 接收到的数据块
4867
+ * @param {Function} callback - 更新回调函数
4868
+ */
4869
+ processChunk(chunk, callback) {
4870
+ this.metrics.chunks++;
4871
+ this.buffer += chunk;
4872
+
4873
+ // SSE 格式:事件由双换行符分隔
4874
+ const events = this.buffer.split('\n\n');
4875
+
4876
+ // 保留最后一个可能不完整的事件
4877
+ this.buffer = events.pop() || '';
4878
+
4879
+ // 处理完整的事件
4880
+ for (const event of events) {
4881
+ if (event.trim()) {
4882
+ this.metrics.events++;
4883
+ this.processEvent(event, callback);
4884
+ }
4885
+ }
4886
+ }
4887
+
4888
+ /**
4889
+ * 处理单个SSE事件
4890
+ */
4891
+ processEvent(eventStr, callback) {
4892
+ const lines = eventStr.split('\n');
4893
+ for (const line of lines) {
4894
+ // 解析 data: 行
4895
+ if (line.startsWith('data:')) {
4896
+ const data = line.substring(5).trim();
4897
+ if (data === '[DONE]') {
4898
+ this.flush(callback);
4899
+ return;
4900
+ }
4901
+ try {
4902
+ const parsed = JSON.parse(data);
4903
+ const content = parsed?.choices?.[0]?.delta?.content;
4904
+ if (content) {
4905
+ this.metrics.chars += content.length;
4906
+ this.parseContent(content, callback);
4907
+ }
4908
+ } catch (error) {
4909
+ if (this.options.debug) {
4910
+ console.warn('[StreamParser] JSON解析失败:', data);
4911
+ }
4912
+ }
4913
+ }
4914
+ }
4915
+ }
4916
+
4917
+ /**
4918
+ * 使用状态机解析内容和标签
4919
+ */
4920
+ parseContent(content, callback) {
4921
+ let i = 0;
4922
+ while (i < content.length) {
4923
+ if (this.inTag) {
4924
+ // 在标签内部,查找标签结束
4925
+ const endIndex = content.indexOf('>', i);
4926
+ if (endIndex !== -1) {
4927
+ // 找到标签结束
4928
+ this.tagBuffer += content.substring(i, endIndex + 1);
4929
+ this.handleTag(this.tagBuffer);
4930
+ this.tagBuffer = '';
4931
+ this.inTag = false;
4932
+ i = endIndex + 1;
4933
+ } else {
4934
+ // 标签未结束,缓存剩余部分
4935
+ this.tagBuffer += content.substring(i);
4936
+ break;
4937
+ }
4938
+ } else {
4939
+ // 不在标签内,查找标签开始
4940
+ const startIndex = content.indexOf('<', i);
4941
+ if (startIndex !== -1) {
4942
+ // 找到标签开始,先处理前面的文本
4943
+ if (startIndex > i) {
4944
+ this.appendText(content.substring(i, startIndex));
4945
+ }
4946
+
4947
+ // 检查是否是完整标签
4948
+ const endIndex = content.indexOf('>', startIndex);
4949
+ if (endIndex !== -1) {
4950
+ // 完整标签
4951
+ const tag = content.substring(startIndex, endIndex + 1);
4952
+ this.handleTag(tag);
4953
+ i = endIndex + 1;
4954
+ } else {
4955
+ // 不完整标签,标记进入标签状态
4956
+ this.inTag = true;
4957
+ this.tagBuffer = content.substring(startIndex);
4958
+ break;
4959
+ }
4960
+ } else {
4961
+ // 没有标签,全部是文本
4962
+ this.appendText(content.substring(i));
4963
+ break;
4964
+ }
4965
+ }
4966
+ }
4967
+
4968
+ // 定时批量更新
4969
+ this.scheduleUpdate(callback);
4970
+ }
4971
+
4972
+ /**
4973
+ * 处理标签
4974
+ */
4975
+ handleTag(tag) {
4976
+ const tagName = tag.toLowerCase();
4977
+ if (tagName === '<think>') {
4978
+ this.status = 'thinking';
4979
+ } else if (tagName === '</think>') {
4980
+ this.status = 'output';
4981
+ }
4982
+ // 可扩展:支持更多标签类型
4983
+ // else if (tagName.startsWith('<code')) {
4984
+ // this.status = 'code';
4985
+ // }
4986
+ }
4987
+
4988
+ /**
4989
+ * 添加文本到缓冲区
4990
+ */
4991
+ appendText(text) {
4992
+ if (!text) return;
4993
+ if (this.status === 'thinking') {
4994
+ this.thinkingBuffer.push(text);
4995
+ } else {
4996
+ this.contentBuffer.push(text);
4997
+ }
4998
+ }
4999
+
5000
+ /**
5001
+ * 计划更新(防抖)
5002
+ */
5003
+ scheduleUpdate(callback) {
5004
+ if (this.updateTimer) return;
5005
+ this.updateTimer = setTimeout(() => {
5006
+ this.flush(callback);
5007
+ this.updateTimer = null;
5008
+ }, this.options.updateInterval);
5009
+ }
5010
+
5011
+ /**
5012
+ * 立即刷新缓冲区
5013
+ */
5014
+ flush(callback) {
5015
+ if (!callback) return;
5016
+ const hasThinking = this.thinkingBuffer.length > 0;
5017
+ const hasContent = this.contentBuffer.length > 0;
5018
+ if (!hasThinking && !hasContent) return;
5019
+
5020
+ // 使用 join 比字符串拼接性能更好
5021
+ const result = {
5022
+ thinking: hasThinking ? this.thinkingBuffer.join('') : null,
5023
+ content: hasContent ? this.contentBuffer.join('') : null,
5024
+ status: this.status
5025
+ };
5026
+
5027
+ // 清空缓冲区
5028
+ this.thinkingBuffer = [];
5029
+ this.contentBuffer = [];
5030
+
5031
+ // 回调更新
5032
+ callback(result);
5033
+ }
5034
+
5035
+ /**
5036
+ * 完成解析
5037
+ */
5038
+ finish(callback) {
5039
+ this.flush(callback);
5040
+ if (this.updateTimer) {
5041
+ clearTimeout(this.updateTimer);
5042
+ this.updateTimer = null;
5043
+ }
5044
+ if (this.options.debug) {
5045
+ const duration = Date.now() - this.metrics.startTime;
5046
+ console.log('[StreamParser] 解析完成:', {
5047
+ 耗时: `${duration}ms`,
5048
+ 数据块: this.metrics.chunks,
5049
+ 事件数: this.metrics.events,
5050
+ 字符数: this.metrics.chars,
5051
+ 平均速度: `${(this.metrics.chars / duration * 1000).toFixed(0)} chars/s`
5052
+ });
5053
+ }
5054
+ }
5055
+
5056
+ /**
5057
+ * 销毁解析器
5058
+ */
5059
+ destroy() {
5060
+ if (this.updateTimer) {
5061
+ clearTimeout(this.updateTimer);
5062
+ }
5063
+ this.reset();
5064
+ }
5065
+ }
5066
+
5067
+ /**
5068
+ * 使用示例:
5069
+ *
5070
+ * const parser = new StreamParser({ debug: true });
5071
+ *
5072
+ * // 处理流
5073
+ * for await (const chunk of stream) {
5074
+ * parser.processChunk(chunk, (result) => {
5075
+ * if (result.thinking) {
5076
+ * message.thinking += result.thinking;
5077
+ * }
5078
+ * if (result.content) {
5079
+ * message.content += result.content;
5080
+ * }
5081
+ * this.$forceUpdate();
5082
+ * });
5083
+ * }
5084
+ *
5085
+ * // 完成
5086
+ * parser.finish();
5087
+ */
5088
+ ;// ./components/mixins/messageMixin.js
5089
+
5090
+
5091
+ /* harmony default export */ var messageMixin = ({
5092
+ data() {
5093
+ return {
5094
+ streamParser: null
5095
+ };
5096
+ },
5097
+ created() {
5098
+ // 初始化流解析器
5099
+ this.streamParser = new StreamParser({
5100
+ updateInterval: 16,
5101
+ // 约60fps
5102
+ debug: "production" === 'development'
5103
+ });
5104
+ },
5105
+ methods: {
4198
5106
  createAiMessage() {
4199
5107
  const message = {
4200
5108
  id: this.messages.length + 1,
@@ -4221,59 +5129,21 @@ const FRAME_SIZE = 512;
4221
5129
  this.inputMessage = '';
4222
5130
  return message;
4223
5131
  },
4224
- async initAudio() {
4225
- if (this.isRecording) return;
4226
- try {
4227
- this.isMicAvailable = true;
4228
- // 2. 获取麦克风权限
4229
- const stream = await navigator.mediaDevices.getUserMedia({
4230
- audio: {
4231
- sampleRate: SAMPLE_RATE,
4232
- // 请求指定采样率
4233
- channelCount: 1,
4234
- // 单声道
4235
- noiseSuppression: true,
4236
- echoCancellation: true
4237
- }
4238
- });
4239
-
4240
- // 3. 创建音频处理环境
4241
- this.audioContext = new AudioContext({
4242
- sampleRate: SAMPLE_RATE
4243
- });
4244
- const actualSampleRate = this.audioContext.sampleRate;
4245
- this.microphone = this.audioContext.createMediaStreamSource(stream);
4246
-
4247
- // 4. 创建音频处理器
4248
- this.processor = this.audioContext.createScriptProcessor(FRAME_SIZE, 1, 1);
4249
- this.processor.onaudioprocess = this.processAudio;
4250
- // 连接处理链
4251
- this.microphone.connect(this.processor);
4252
- this.processor.connect(this.audioContext.destination);
4253
- this.isRecording = true;
4254
- console.log(`状态: 录音中 (采样率: ${actualSampleRate}Hz)`);
4255
- } catch (error) {
4256
- console.error("音频初始化失败:", error);
4257
- this.isRecording = false;
4258
- this.isMicAvailable = false;
4259
- }
4260
- },
4261
5132
  async handleSend() {
4262
5133
  if (!this.inputMessage.trim()) {
4263
5134
  return;
4264
5135
  }
4265
5136
  const message = this.inputMessage.trim();
4266
- // 初始化信息
4267
- this.initState();
4268
- // 发送消息
4269
5137
  this.createUserMessage(message);
4270
- // 创建AI消息
4271
5138
  this.createAiMessage();
5139
+
5140
+ // 重置解析器
5141
+ this.streamParser.reset();
4272
5142
  try {
5143
+ const startTime = Date.now();
4273
5144
  const controller = new AbortController();
4274
- const token = `Bearer e298f087-85bc-48c2-afb9-7c69ffc911aa`;
5145
+ const token = `Bearer ac627d0a-8346-4ae9-b93a-f37ff6210adc`;
4275
5146
  const response = await fetch('/bytserver/api-model/chat/stream', {
4276
- timeout: 30000,
4277
5147
  method: 'POST',
4278
5148
  signal: controller.signal,
4279
5149
  headers: {
@@ -4285,337 +5155,236 @@ const FRAME_SIZE = 512;
4285
5155
  })
4286
5156
  });
4287
5157
  if (!response.ok) {
4288
- throw new Error(`${response.status}`);
5158
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4289
5159
  }
4290
- const render = response.body.getReader();
4291
- const decoder = new TextDecoder();
4292
5160
 
5161
+ // 使用优化的流处理
5162
+ await this.consumeStream(response.body);
5163
+
5164
+ // 完成解析
5165
+ this.streamParser.finish(this.handleStreamUpdate);
5166
+
5167
+ // 记录耗时
5168
+ const duration = Date.now() - startTime;
5169
+ if (this.currentMessage) {
5170
+ this.currentMessage.time = (duration / 1000).toFixed(2);
5171
+ }
5172
+ console.log(`流处理完成,总耗时: ${duration}ms`);
5173
+ } catch (error) {
5174
+ console.error('发送消息失败:', error);
5175
+ if (this.currentMessage) {
5176
+ this.currentMessage.content = '抱歉,发生了错误,请重试。';
5177
+ this.$forceUpdate();
5178
+ }
5179
+ }
5180
+ },
5181
+ /**
5182
+ * 消费流数据
5183
+ */
5184
+ async consumeStream(readableStream) {
5185
+ const reader = readableStream.getReader();
5186
+ const decoder = new TextDecoder('utf-8');
5187
+ try {
4293
5188
  // eslint-disable-next-line no-constant-condition
4294
5189
  while (true) {
4295
5190
  const {
4296
5191
  done,
4297
5192
  value
4298
- } = await render.read();
5193
+ } = await reader.read();
4299
5194
  if (done) break;
4300
5195
  const chunk = decoder.decode(value, {
4301
5196
  stream: true
4302
5197
  });
4303
- this.processStreamChunk(chunk);
5198
+
5199
+ // 使用解析器处理数据块
5200
+ this.streamParser.processChunk(chunk, this.handleStreamUpdate);
4304
5201
  }
4305
- } catch (error) {
4306
- console.error('发送消息失败:', error);
5202
+ } finally {
5203
+ reader.releaseLock();
4307
5204
  }
4308
5205
  },
4309
- initState() {},
4310
- // 分析音频命令
4311
- analyzeAudioCommand(command) {
4312
- console.log('分析音频命令:', command);
4313
- // 解析到开始导览,执行机器人进入动画
4314
- if (command === 'C5') {
4315
- this.robotStatus = 'entering';
4316
- setTimeout(() => {
4317
- this.robotStatus = 'speaking';
4318
- this.play();
4319
- }, 3000);
4320
- }
4321
- // 继续导览
4322
- else if (command === 'C8') {
4323
- this.robotStatus = 'speaking';
4324
- this.play();
5206
+ /**
5207
+ * 处理流更新回调
5208
+ */
5209
+ handleStreamUpdate(result) {
5210
+ if (!this.currentMessage) return;
5211
+
5212
+ // 更新思考内容
5213
+ if (result.thinking) {
5214
+ this.currentMessage.thinking += result.thinking;
4325
5215
  }
4326
- // 解析到暂停导览,执行机器人暂停动画
4327
- else if (command === 'C7') {
4328
- this.robotStatus = 'waiting';
4329
- this.pause();
4330
- }
4331
- // 解析到结束导览,执行机器人离开动画
4332
- else if (command === 'C6') {
4333
- this.robotStatus = 'leaving';
4334
- this.stop();
4335
- }
4336
- },
4337
- processStreamChunk(chunk) {
4338
- console.log('原始数据:', chunk);
4339
- try {
4340
- this.buffer += chunk;
4341
5216
 
4342
- // eslint-disable-next-line no-constant-condition
4343
- while (true) {
4344
- const eventEnd = this.buffer.indexOf('\n\n');
4345
- if (eventEnd === -1) break;
4346
- const eventData = this.buffer.slice(0, eventEnd);
4347
- this.buffer = this.buffer.slice(eventEnd + 2);
4348
- console.log('解析数据:', eventData);
4349
- this.processEventData(eventData);
4350
- }
4351
- } catch (error) {
4352
- console.error('流数据处理异常:', error);
4353
- this.streaming = false;
4354
- this.response = this.$t('3d.chat.dataFormatError');
4355
- this.$forceUpdate();
5217
+ // 更新回复内容
5218
+ if (result.content) {
5219
+ this.currentMessage.content += result.content;
4356
5220
  }
4357
- },
4358
- processEventData(data) {
4359
- data.split('\n').forEach(line => {
4360
- console.log('原始数据:', line);
4361
- if (!line.startsWith('data:')) return;
4362
- const jsonStr = line.replace(/^data:\s*/, '').trim();
4363
- if (jsonStr === '[DONE]') return;
4364
- try {
4365
- const data = this.safeJsonParse(jsonStr);
4366
- this.processContentDelta(data.choices[0].delta);
4367
- } catch (e) {
4368
- console.warn('JSON解析跳过:', e.message);
4369
- }
4370
- });
4371
- },
4372
- safeJsonParse(jsonStr) {
4373
- try {
4374
- return JSON.parse(jsonStr);
4375
- } catch (error) {
4376
- console.warn('JSON parse failed:', jsonStr);
4377
- return null;
5221
+
5222
+ // 更新状态
5223
+ if (result.status === 'thinking') {
5224
+ this.avaterStatus = 'thinking';
5225
+ } else {
5226
+ this.avaterStatus = 'output';
4378
5227
  }
4379
- },
4380
- processContentDelta(delta) {
4381
- const content = delta.content || '';
4382
- if (!content || !this.currentMessage) return;
4383
- for (let i = 0; i < content.length; i++) {
4384
- const char = content[i];
4385
-
4386
- // 处理正在拼接的标签
4387
- if (this.inTag) {
4388
- this.tagBuilder += char;
4389
- if (char === '>') {
4390
- const tag = this.tagBuilder;
4391
- if (tag === '<think>') {
4392
- this.avaterStatus = 'thinking';
4393
- } else if (tag === '</think>') {
4394
- this.avaterStatus = 'output';
4395
- } else {
4396
- console.log('无效标签:', tag);
4397
- }
4398
5228
 
4399
- // 重置
4400
- this.inTag = false;
4401
- this.tagBuilder = '';
4402
- }
4403
- continue;
4404
- }
5229
+ // 触发视图更新
5230
+ this.$forceUpdate();
5231
+ }
5232
+ },
5233
+ beforeDestroy() {
5234
+ // 清理解析器
5235
+ if (this.streamParser) {
5236
+ this.streamParser.destroy();
5237
+ }
5238
+ }
5239
+ });
5240
+ ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindow.vue?vue&type=script&lang=js
5241
+
5242
+
5243
+
5244
+
5245
+
5246
+
5247
+
4405
5248
 
4406
- // 检测是否是标签开始
4407
- if (char === '<') {
4408
- this.inTag = true;
4409
- this.tagBuilder = '<';
4410
- continue;
4411
- }
4412
5249
 
4413
- // 正常字符处理
4414
- if (this.avaterStatus === 'thinking') {
4415
- this.currentMessage.thinking += char;
4416
- } else {
4417
- this.currentMessage.content += char;
4418
- }
4419
- }
4420
- this.$forceUpdate();
4421
- },
4422
- processAudio(event) {
4423
- if (!this.isRecording) return;
4424
- // 5. 获取音频数据并处理
4425
- const inputData = event.inputBuffer.getChannelData(0);
4426
5250
 
4427
- // 累积音频数据
4428
- const tempBuffer = new Float32Array(this.audioBuffer.length + inputData.length);
4429
- tempBuffer.set(this.audioBuffer, 0);
4430
- tempBuffer.set(inputData, this.audioBuffer.length);
4431
- this.audioBuffer = tempBuffer;
4432
5251
 
4433
- // 当累积足够一帧时发送
4434
- while (this.audioBuffer.length >= FRAME_SIZE) {
4435
- const frame = this.audioBuffer.slice(0, FRAME_SIZE);
4436
- this.audioBuffer = this.audioBuffer.slice(FRAME_SIZE);
4437
5252
 
4438
- // 转换为16位PCM
4439
- const pcmData = this.floatTo16BitPCM(frame);
4440
5253
 
4441
- // 通过WebSocket发送
4442
- if (this.ws && this.ws.readyState === this.ws.OPEN) {
4443
- this.ws.send(pcmData);
4444
- }
4445
- }
4446
- },
4447
- floatTo16BitPCM(input) {
4448
- const output = new Int16Array(input.length);
4449
- for (let i = 0; i < input.length; i++) {
4450
- const s = Math.max(-1, Math.min(1, input[i]));
4451
- output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
4452
- }
4453
- return output.buffer;
4454
- },
5254
+
5255
+ const SAMPLE_RATE = 16000;
5256
+ const FRAME_SIZE = 512;
5257
+ /* harmony default export */ var ChatWindowvue_type_script_lang_js = ({
5258
+ name: 'ChatWindow',
5259
+ components: {
5260
+ ChatRobot: ChatRobot,
5261
+ ChatAvatar: ChatAvatar,
5262
+ ChatWindowDialog: ChatWindowDialog
5263
+ },
5264
+ mixins: [audioMixin, webSocketMixin, messageMixin],
5265
+ props: {
5266
+ appendToBody: {
5267
+ type: Boolean,
5268
+ default: true
5269
+ }
5270
+ },
5271
+ data() {
5272
+ return {
5273
+ audioSrc: '/minio/lingxiaoai/byt.mp3',
5274
+ inputMessage: '',
5275
+ visible: false,
5276
+ messages: [{
5277
+ id: 1,
5278
+ type: 'user',
5279
+ sender: '',
5280
+ time: '',
5281
+ content: '你好,欢迎来到凌霄大模型AI对话。'
5282
+ }, {
5283
+ id: 2,
5284
+ type: 'ai',
5285
+ sender: 'AI',
5286
+ time: '',
5287
+ thinking: '嗯,用户问的是回转窑的工业应用。首先,我需要回忆一下之前对话的内容。用户之前让我解释了水泥的制作流程,特别是提到了回转窑在高温煅烧熟料中的作用。',
5288
+ charts: [{
5289
+ title: '',
5290
+ options: {}
5291
+ }],
5292
+ content: '回转窑(Rotary Kiln)是一种长筒形旋转煅烧设备(类似倾斜安装的大管子),因其独特的旋转运动和高温耐火衬里设计,在多个工业领域都有广泛应用'
5293
+ }],
5294
+ robotStatus: 'leaving',
5295
+ avaterStatus: 'normal',
5296
+ currentMessage: null,
5297
+ thinkStatus: true,
5298
+ jumpedTimePoints: new Set(),
5299
+ SAMPLE_RATE,
5300
+ FRAME_SIZE
5301
+ };
5302
+ },
5303
+ mounted() {
5304
+ this.initWebSocket();
5305
+ if (this.appendToBody) {
5306
+ this.appendToBodyHandler();
5307
+ }
5308
+ },
5309
+ beforeDestroy() {
5310
+ if (this.appendToBody && this.$el.parentElement === document.body) {
5311
+ document.body.removeChild(this.$el);
5312
+ }
5313
+ this.closeWebSocket();
5314
+ this.stopRecording();
5315
+ },
5316
+ methods: {
4455
5317
  toggleWindow() {
4456
5318
  this.visible = !this.visible;
4457
5319
  },
4458
- showWindow() {
4459
- this.visible = true;
5320
+ handleThinkingClick() {
5321
+ this.thinkStatus = !this.thinkStatus;
4460
5322
  },
4461
- hideWindow() {
5323
+ handleOverlayClick() {
4462
5324
  this.visible = false;
4463
5325
  },
4464
- scrollToBottom() {
5326
+ appendToBodyHandler() {
4465
5327
  this.$nextTick(() => {
4466
- const chatArea = this.$refs.chatArea;
4467
- if (chatArea) {
4468
- chatArea.scrollTop = chatArea.scrollHeight;
5328
+ if (this.$el.parentElement !== document.body) {
5329
+ document.body.appendChild(this.$el);
4469
5330
  }
4470
5331
  });
4471
5332
  },
4472
- handleKeyDown(e) {
4473
- if (e.key === 'Enter' && !e.shiftKey) {
4474
- e.preventDefault();
4475
- this.handleSend();
4476
- }
4477
- },
4478
- stopRecording() {
4479
- if (!this.isRecording) return;
4480
- if (this.microphone) this.microphone.disconnect();
4481
- if (this.processor) this.processor.disconnect();
4482
- if (this.analyser) this.analyser.disconnect();
4483
- if (this.audioContext) {
4484
- this.audioContext.close().catch(e => {
4485
- console.error("关闭音频上下文失败:", e);
4486
- });
5333
+ // 音频时间更新处理
5334
+ onTimeUpdate() {
5335
+ const audio = this.$refs.audioPlayer;
5336
+ const currentTime = audio.currentTime;
5337
+ if (!this.jumpedTimePoints) {
5338
+ this.jumpedTimePoints = new Set();
4487
5339
  }
4488
- this.isRecording = false;
4489
- },
4490
- // 添加到body的处理函数
4491
- appendToBodyHandler() {
4492
- // 确保DOM已经渲染完成
4493
- this.$nextTick(() => {
4494
- // 检查元素是否已经在body中
4495
- if (this.$el.parentElement !== document.body) {
4496
- // 将组件的根元素移动到body中
4497
- document.body.appendChild(this.$el);
5340
+ const timeJumpPoints = [{
5341
+ time: 40,
5342
+ url: '/permission/user',
5343
+ name: 'permission_user',
5344
+ title: '用户管理'
5345
+ }, {
5346
+ time: 65,
5347
+ url: '/permission/menu',
5348
+ name: 'permission_menu',
5349
+ title: '菜单管理'
5350
+ }, {
5351
+ time: 75,
5352
+ url: '/permission/role',
5353
+ name: 'permission_role',
5354
+ title: '角色管理'
5355
+ }];
5356
+ timeJumpPoints.forEach(point => {
5357
+ if (currentTime >= point.time && currentTime < point.time + 0.5 && !this.jumpedTimePoints.has(point.time)) {
5358
+ this.jumpedTimePoints.add(point.time);
5359
+ this.$appOptions.store.dispatch('tags/addTagview', {
5360
+ path: point.url,
5361
+ fullPath: point.url,
5362
+ label: point.title,
5363
+ name: point.title,
5364
+ meta: {
5365
+ title: point.title
5366
+ },
5367
+ query: {},
5368
+ params: {}
5369
+ });
5370
+ this.$appOptions.router.push({
5371
+ path: point.url
5372
+ });
4498
5373
  }
4499
5374
  });
4500
5375
  },
4501
- // 处理点击遮罩层事件
4502
- handleOverlayClick() {
4503
- this.visible = false;
4504
- }
4505
- },
4506
- watch: {
4507
- messages: {
4508
- handler() {
4509
- this.scrollToBottom();
4510
- },
4511
- deep: true
5376
+ onAudioEnded() {
5377
+ this.robotStatus = 'leaving';
5378
+ this.jumpedTimePoints.clear();
4512
5379
  }
4513
5380
  }
4514
5381
  });
4515
5382
  ;// ./components/ChatWindow.vue?vue&type=script&lang=js
4516
5383
  /* harmony default export */ var components_ChatWindowvue_type_script_lang_js = (ChatWindowvue_type_script_lang_js);
4517
- ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindow.vue?vue&type=style&index=0&id=62955cf4&prod&scoped=true&lang=css
5384
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./components/ChatWindow.vue?vue&type=style&index=0&id=d604373c&prod&scoped=true&lang=css
4518
5385
  // extracted by mini-css-extract-plugin
4519
5386
 
4520
- ;// ./components/ChatWindow.vue?vue&type=style&index=0&id=62955cf4&prod&scoped=true&lang=css
4521
-
4522
- ;// ./node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js
4523
- /* globals __VUE_SSR_CONTEXT__ */
4524
-
4525
- // IMPORTANT: Do NOT use ES2015 features in this file (except for modules).
4526
- // This module is a runtime utility for cleaner component module output and will
4527
- // be included in the final webpack user bundle.
4528
-
4529
- function normalizeComponent(
4530
- scriptExports,
4531
- render,
4532
- staticRenderFns,
4533
- functionalTemplate,
4534
- injectStyles,
4535
- scopeId,
4536
- moduleIdentifier /* server only */,
4537
- shadowMode /* vue-cli only */
4538
- ) {
4539
- // Vue.extend constructor export interop
4540
- var options =
4541
- typeof scriptExports === 'function' ? scriptExports.options : scriptExports
4542
-
4543
- // render functions
4544
- if (render) {
4545
- options.render = render
4546
- options.staticRenderFns = staticRenderFns
4547
- options._compiled = true
4548
- }
4549
-
4550
- // functional template
4551
- if (functionalTemplate) {
4552
- options.functional = true
4553
- }
4554
-
4555
- // scopedId
4556
- if (scopeId) {
4557
- options._scopeId = 'data-v-' + scopeId
4558
- }
4559
-
4560
- var hook
4561
- if (moduleIdentifier) {
4562
- // server build
4563
- hook = function (context) {
4564
- // 2.3 injection
4565
- context =
4566
- context || // cached call
4567
- (this.$vnode && this.$vnode.ssrContext) || // stateful
4568
- (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
4569
- // 2.2 with runInNewContext: true
4570
- if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
4571
- context = __VUE_SSR_CONTEXT__
4572
- }
4573
- // inject component styles
4574
- if (injectStyles) {
4575
- injectStyles.call(this, context)
4576
- }
4577
- // register component module identifier for async chunk inferrence
4578
- if (context && context._registeredComponents) {
4579
- context._registeredComponents.add(moduleIdentifier)
4580
- }
4581
- }
4582
- // used by ssr in case component is cached and beforeCreate
4583
- // never gets called
4584
- options._ssrRegister = hook
4585
- } else if (injectStyles) {
4586
- hook = shadowMode
4587
- ? function () {
4588
- injectStyles.call(
4589
- this,
4590
- (options.functional ? this.parent : this).$root.$options.shadowRoot
4591
- )
4592
- }
4593
- : injectStyles
4594
- }
4595
-
4596
- if (hook) {
4597
- if (options.functional) {
4598
- // for template-only hot-reload because in that case the render fn doesn't
4599
- // go through the normalizer
4600
- options._injectStyles = hook
4601
- // register for functional component in vue file
4602
- var originalRender = options.render
4603
- options.render = function renderWithStyleInjection(h, context) {
4604
- hook.call(context)
4605
- return originalRender(h, context)
4606
- }
4607
- } else {
4608
- // inject component registration as beforeCreate hook
4609
- var existing = options.beforeCreate
4610
- options.beforeCreate = existing ? [].concat(existing, hook) : [hook]
4611
- }
4612
- }
4613
-
4614
- return {
4615
- exports: scriptExports,
4616
- options: options
4617
- }
4618
- }
5387
+ ;// ./components/ChatWindow.vue?vue&type=style&index=0&id=d604373c&prod&scoped=true&lang=css
4619
5388
 
4620
5389
  ;// ./components/ChatWindow.vue
4621
5390
 
@@ -4626,18 +5395,18 @@ function normalizeComponent(
4626
5395
 
4627
5396
  /* normalize component */
4628
5397
 
4629
- var component = normalizeComponent(
5398
+ var ChatWindow_component = normalizeComponent(
4630
5399
  components_ChatWindowvue_type_script_lang_js,
4631
5400
  render,
4632
5401
  staticRenderFns,
4633
5402
  false,
4634
5403
  null,
4635
- "62955cf4",
5404
+ "d604373c",
4636
5405
  null
4637
5406
 
4638
5407
  )
4639
5408
 
4640
- /* harmony default export */ var ChatWindow = (component.exports);
5409
+ /* harmony default export */ var ChatWindow = (ChatWindow_component.exports);
4641
5410
  ;// ./components/index.js
4642
5411
 
4643
5412