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