byt-lingxiao-ai 0.3.5 → 0.3.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
@@ -28460,7 +28460,7 @@ if (typeof window !== 'undefined') {
28460
28460
  var es_iterator_constructor = __webpack_require__(8111);
28461
28461
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.for-each.js
28462
28462
  var es_iterator_for_each = __webpack_require__(7588);
28463
- ;// ./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=0e3e6d50&scoped=true
28463
+ ;// ./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=244aa1c1&scoped=true
28464
28464
  var render = function render() {
28465
28465
  var _vm = this,
28466
28466
  _c = _vm._self._c;
@@ -29027,8 +29027,8 @@ var UserMessage_component = normalizeComponent(
29027
29027
  )
29028
29028
 
29029
29029
  /* harmony default export */ var UserMessage = (UserMessage_component.exports);
29030
- ;// ./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=2422d7c0&scoped=true
29031
- var AiMessagevue_type_template_id_2422d7c0_scoped_true_render = function render() {
29030
+ ;// ./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=6cbccb01&scoped=true
29031
+ var AiMessagevue_type_template_id_6cbccb01_scoped_true_render = function render() {
29032
29032
  var _vm = this,
29033
29033
  _c = _vm._self._c;
29034
29034
  return _c('div', {
@@ -29061,10 +29061,8 @@ var AiMessagevue_type_template_id_2422d7c0_scoped_true_render = function render(
29061
29061
  }
29062
29062
  })])]);
29063
29063
  };
29064
- var AiMessagevue_type_template_id_2422d7c0_scoped_true_staticRenderFns = [];
29064
+ var AiMessagevue_type_template_id_6cbccb01_scoped_true_staticRenderFns = [];
29065
29065
 
29066
- // EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.filter.js
29067
- var es_iterator_filter = __webpack_require__(2489);
29068
29066
  ;// ./node_modules/@babel/runtime/helpers/esm/typeof.js
29069
29067
  function _typeof(o) {
29070
29068
  "@babel/helpers - typeof";
@@ -29108,6 +29106,8 @@ function _defineProperty(e, r, t) {
29108
29106
  }) : e[r] = t, e;
29109
29107
  }
29110
29108
 
29109
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.filter.js
29110
+ var es_iterator_filter = __webpack_require__(2489);
29111
29111
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.map.js
29112
29112
  var es_iterator_map = __webpack_require__(1701);
29113
29113
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.some.js
@@ -30837,10 +30837,6 @@ var lib = __webpack_require__(336);
30837
30837
 
30838
30838
 
30839
30839
 
30840
-
30841
-
30842
-
30843
-
30844
30840
  d.setOptions({
30845
30841
  highlight: function (code, lang) {
30846
30842
  if (lang && es.getLanguage(lang)) {
@@ -30853,115 +30849,6 @@ d.setOptions({
30853
30849
  breaks: true,
30854
30850
  gfm: true
30855
30851
  });
30856
- function parseMarkdown(text) {
30857
- if (!text) return '';
30858
- let html = text;
30859
- html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
30860
- return `<pre><code class="language-${lang || 'text'}">${escapeHtml(code.trim())}</code></pre>`;
30861
- });
30862
- html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
30863
- html = parseTable(html);
30864
- html = html.replace(/^#### (.*$)/gm, '<h4>$1</h4>');
30865
- html = html.replace(/^### (.*$)/gm, '<h3>$1</h3>');
30866
- html = html.replace(/^## (.*$)/gm, '<h2>$1</h2>');
30867
- html = html.replace(/^# (.*$)/gm, '<h1>$1</h1>');
30868
- html = html.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
30869
- html = html.replace(/\*(.*?)\*/g, '<em>$1</em>');
30870
- html = html.replace(/~~(.*?)~~/g, '<del>$1</del>');
30871
- html = html.replace(/^\s*[-*+]\s+(.+)$/gm, '<li>$1</li>');
30872
- html = html.replace(/(<li>.*?<\/li>)/gs, '<ul>$1</ul>');
30873
- html = html.replace(/^\s*\d+\.\s+(.+)$/gm, '<li>$1</li>');
30874
- html = html.replace(/^>\s+(.+)$/gm, '<blockquote>$1</blockquote>');
30875
- // 解析Markdown链接
30876
- html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" aria-current="page">$1</a>');
30877
- html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1" />');
30878
- html = html.replace(/^-{3,}$/gm, '<hr>');
30879
- // 解析简单URL
30880
- // const simpleUrlRegex = /(https?:\/\/[^\s<>"']+)/g;
30881
- // html = html.replace(simpleUrlRegex, (match) => {
30882
- // return `<a href="${match}" aria-current="page">${match}</a>`;
30883
- // });
30884
-
30885
- // html = html.replace(/\n/g, '<br>');
30886
-
30887
- return html;
30888
- }
30889
- // 解析表格
30890
- function parseTable(text) {
30891
- const lines = text.split('\n');
30892
- let result = [];
30893
- let inTable = false;
30894
- let tableRows = [];
30895
- for (let i = 0; i < lines.length; i++) {
30896
- const line = lines[i].trim();
30897
-
30898
- // 检测表格行
30899
- if (line.includes('|') && line.split('|').length >= 3) {
30900
- if (!inTable) {
30901
- inTable = true;
30902
- tableRows = [];
30903
- }
30904
- tableRows.push(line);
30905
-
30906
- // 检查下一行是否还是表格
30907
- if (i === lines.length - 1 || !lines[i + 1].includes('|')) {
30908
- // 表格结束
30909
- result.push(renderTable(tableRows));
30910
- inTable = false;
30911
- tableRows = [];
30912
- }
30913
- } else {
30914
- if (inTable) {
30915
- // 表格意外结束
30916
- result.push(renderTable(tableRows));
30917
- inTable = false;
30918
- tableRows = [];
30919
- }
30920
- result.push(line);
30921
- }
30922
- }
30923
- return result.join('\n');
30924
- }
30925
- // 渲染表格
30926
- function renderTable(rows) {
30927
- if (rows.length < 2) return rows.join('\n');
30928
- let html = '<div class="table-wrapper"><table class="markdown-table">';
30929
-
30930
- // 表头
30931
- const headerCells = rows[0].split('|').filter(cell => cell.trim());
30932
- html += '<thead><tr>';
30933
- headerCells.forEach(cell => {
30934
- html += `<th>${cell.trim()}</th>`;
30935
- });
30936
- html += '</tr></thead>';
30937
-
30938
- // 表体(跳过分隔行)
30939
- html += '<tbody>';
30940
- for (let i = 2; i < rows.length; i++) {
30941
- const cells = rows[i].split('|').filter(cell => cell.trim());
30942
- if (cells.length > 0) {
30943
- html += '<tr>';
30944
- cells.forEach(cell => {
30945
- html += `<td><div class="table-cell">${cell.trim()}</div></td>`;
30946
- });
30947
- html += '</tr>';
30948
- }
30949
- }
30950
- html += '</tbody>';
30951
- html += '</table></div>';
30952
- return html;
30953
- }
30954
- // HTML 转义
30955
- function escapeHtml(text) {
30956
- const map = {
30957
- '&': '&amp;',
30958
- '<': '&lt;',
30959
- '>': '&gt;',
30960
- '"': '&quot;',
30961
- "'": '&#039;'
30962
- };
30963
- return text.replace(/[&<>"']/g, m => map[m]);
30964
- }
30965
30852
  /* harmony default export */ var AiMessagevue_type_script_lang_js = ({
30966
30853
  name: 'AiMessage',
30967
30854
  props: {
@@ -30975,7 +30862,7 @@ function escapeHtml(text) {
30975
30862
  return this.message.thinkingExpanded !== false;
30976
30863
  },
30977
30864
  renderedContent() {
30978
- return parseMarkdown(this.message.content);
30865
+ return d.parse(this.message.content || '');
30979
30866
  },
30980
30867
  isLoading() {
30981
30868
  return this.message.loading === true;
@@ -30989,10 +30876,10 @@ function escapeHtml(text) {
30989
30876
  });
30990
30877
  ;// ./components/AiMessage.vue?vue&type=script&lang=js
30991
30878
  /* harmony default export */ var components_AiMessagevue_type_script_lang_js = (AiMessagevue_type_script_lang_js);
30992
- ;// ./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=2422d7c0&prod&scoped=true&lang=css
30879
+ ;// ./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=6cbccb01&prod&scoped=true&lang=css
30993
30880
  // extracted by mini-css-extract-plugin
30994
30881
 
30995
- ;// ./components/AiMessage.vue?vue&type=style&index=0&id=2422d7c0&prod&scoped=true&lang=css
30882
+ ;// ./components/AiMessage.vue?vue&type=style&index=0&id=6cbccb01&prod&scoped=true&lang=css
30996
30883
 
30997
30884
  ;// ./components/AiMessage.vue
30998
30885
 
@@ -31005,11 +30892,11 @@ function escapeHtml(text) {
31005
30892
 
31006
30893
  var AiMessage_component = normalizeComponent(
31007
30894
  components_AiMessagevue_type_script_lang_js,
31008
- AiMessagevue_type_template_id_2422d7c0_scoped_true_render,
31009
- AiMessagevue_type_template_id_2422d7c0_scoped_true_staticRenderFns,
30895
+ AiMessagevue_type_template_id_6cbccb01_scoped_true_render,
30896
+ AiMessagevue_type_template_id_6cbccb01_scoped_true_staticRenderFns,
31010
30897
  false,
31011
30898
  null,
31012
- "2422d7c0",
30899
+ "6cbccb01",
31013
30900
  null
31014
30901
 
31015
30902
  )
@@ -31307,9 +31194,7 @@ var es_typed_array_with = __webpack_require__(9577);
31307
31194
  audioContext: null,
31308
31195
  microphone: null,
31309
31196
  processor: null,
31310
- audioBuffer: new Float32Array(0),
31311
- // 优化
31312
- int16Buffer: null
31197
+ audioBuffer: new Float32Array(0)
31313
31198
  };
31314
31199
  },
31315
31200
  methods: {
@@ -31321,21 +31206,16 @@ var es_typed_array_with = __webpack_require__(9577);
31321
31206
  audio: {
31322
31207
  sampleRate: this.SAMPLE_RATE,
31323
31208
  channelCount: 1,
31324
- noiseSuppression: true,
31325
- echoCancellation: true
31209
+ noiseSuppression: false,
31210
+ echoCancellation: false,
31211
+ autoGainControl: false
31326
31212
  }
31327
31213
  });
31328
31214
  this.audioContext = new AudioContext({
31329
31215
  sampleRate: this.SAMPLE_RATE
31330
31216
  });
31331
-
31332
- // 优化 处理 AudioContext 挂起
31333
- if (this.audioContext.state === 'suspended') {
31334
- await this.audioContext.resume();
31335
- }
31336
31217
  this.microphone = this.audioContext.createMediaStreamSource(stream);
31337
31218
  this.processor = this.audioContext.createScriptProcessor(this.FRAME_SIZE, 1, 1);
31338
- this.int16Buffer = new Int16Array(this.FRAME_SIZE);
31339
31219
  this.processor.onaudioprocess = this.processAudio;
31340
31220
  this.microphone.connect(this.processor);
31341
31221
  this.processor.connect(this.audioContext.destination);
@@ -31350,19 +31230,17 @@ var es_typed_array_with = __webpack_require__(9577);
31350
31230
  processAudio(event) {
31351
31231
  if (!this.isRecording) return;
31352
31232
  const inputData = event.inputBuffer.getChannelData(0);
31353
- if (this.ws && this.ws.readyState === this.ws.OPEN) {
31354
- if (inputData.length !== this.int16Buffer.length) {
31355
- this.int16Buffer = new Int16Array(inputData.length);
31233
+ const tempBuffer = new Float32Array(this.audioBuffer.length + inputData.length);
31234
+ tempBuffer.set(this.audioBuffer, 0);
31235
+ tempBuffer.set(inputData, this.audioBuffer.length);
31236
+ this.audioBuffer = tempBuffer;
31237
+ while (this.audioBuffer.length >= this.FRAME_SIZE) {
31238
+ const frame = this.audioBuffer.slice(0, this.FRAME_SIZE);
31239
+ this.audioBuffer = this.audioBuffer.slice(this.FRAME_SIZE);
31240
+ const pcmData = this.floatTo16BitPCM(frame);
31241
+ if (this.ws && this.ws.readyState === this.ws.OPEN) {
31242
+ this.ws.send(pcmData);
31356
31243
  }
31357
- for (let i = 0; i < inputData.length; i++) {
31358
- let s = inputData[i];
31359
- // 简单的 clamp
31360
- s = s < -1 ? -1 : s > 1 ? 1 : s;
31361
- this.int16Buffer[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
31362
- }
31363
-
31364
- // 4. 发送数据
31365
- this.ws.send(this.int16Buffer.buffer);
31366
31244
  }
31367
31245
  },
31368
31246
  floatTo16BitPCM(input) {
@@ -31390,6 +31268,7 @@ var es_typed_array_with = __webpack_require__(9577);
31390
31268
  this.$refs.audioPlayer.play();
31391
31269
  },
31392
31270
  pause() {
31271
+ console.log('暂停播放');
31393
31272
  this.robotStatus = 'waiting';
31394
31273
  this.$refs.audioPlayer.pause();
31395
31274
  },
@@ -31415,17 +31294,21 @@ var es_typed_array_with = __webpack_require__(9577);
31415
31294
  this.pause();
31416
31295
  } else if (command === 'C6') {
31417
31296
  this.robotStatus = 'leaving';
31297
+ this.avaterStatus = 'normal';
31418
31298
  this.stop();
31419
31299
  }
31420
31300
  }
31421
31301
  }
31422
31302
  });
31423
31303
  ;// ./components/config/index.js
31424
- const baseUrl = window.location.protocol + '//' + window.location.hostname;
31304
+ const protocol = window.location.protocol;
31305
+ const host = window.location.hostname;
31306
+ const baseUrl = `${protocol}//${host}`;
31425
31307
  const chatPort = '3100';
31308
+ const voicePort = '3101';
31426
31309
  console.log(baseUrl, chatPort);
31427
31310
  const API_URL = `${baseUrl}:${chatPort}/lingxiao-byt/api/v1/mcp/ask`;
31428
- const WS_URL = 'ws://192.168.8.9:9999/ai_model/ws/voice-stream';
31311
+ const WS_URL = `ws://${host}:${voicePort}/ai_model/ws/voice-stream`;
31429
31312
  const AUDIO_URL = '/minio/lingxiaoai/byt.mp3';
31430
31313
  const TIME_JUMP_POINTS_URL = '/minio/lingxiaoai/timeJumpPoints.json';
31431
31314
  ;// ./components/mixins/webSocketMixin.js
@@ -31501,6 +31384,10 @@ const TIME_JUMP_POINTS_URL = '/minio/lingxiaoai/timeJumpPoints.json';
31501
31384
  handleWebSocketMessage(data) {
31502
31385
  if (data.type === 'detection') {
31503
31386
  console.log('检测到唤醒词');
31387
+ console.log('当前状态:', this.avaterStatus);
31388
+ if (this.robotStatus === 'speaking') {
31389
+ this.robotStatus = 'waiting';
31390
+ }
31504
31391
  this.avaterStatus = 'normal';
31505
31392
 
31506
31393
  // 性能检测起点
@@ -31521,6 +31408,8 @@ const TIME_JUMP_POINTS_URL = '/minio/lingxiaoai/timeJumpPoints.json';
31521
31408
  this.analyzeAudioCommand(data.category);
31522
31409
  } else {
31523
31410
  console.log('状态: 其他');
31411
+ this.avaterStatus = 'normal';
31412
+ this.robotStatus = 'leaving';
31524
31413
  }
31525
31414
  },
31526
31415
  closeWebSocket() {
@@ -31532,222 +31421,99 @@ const TIME_JUMP_POINTS_URL = '/minio/lingxiaoai/timeJumpPoints.json';
31532
31421
  });
31533
31422
  ;// ./components/utils/StreamParser.js
31534
31423
 
31535
-
31536
31424
  class StreamParser {
31537
31425
  constructor(options = {}) {
31538
31426
  this.options = {
31539
31427
  updateInterval: 16,
31540
- // 更新间隔(ms),默认约60fps
31541
- batchSize: 100,
31542
- // 批处理大小
31428
+ // 每16ms刷新一次(约60fps
31543
31429
  debug: false,
31544
- // 是否开启调试
31545
31430
  ...options
31546
31431
  };
31547
31432
  this.reset();
31548
31433
  }
31549
31434
 
31550
- /**
31551
- * 重置解析器状态
31552
- */
31435
+ // 重置解析器状态
31553
31436
  reset() {
31554
31437
  this.buffer = '';
31555
- this.contentBuffer = []; // 使用数组缓冲,避免频繁字符串拼接
31438
+ this.contentBuffer = [];
31556
31439
  this.thinkingBuffer = [];
31557
31440
  this.inTag = false;
31558
31441
  this.tagBuffer = '';
31559
31442
  this.updateTimer = null;
31560
31443
  this.status = 'output'; // thinking | output
31561
- this.metrics = {
31562
- startTime: Date.now(),
31563
- chunks: 0,
31564
- events: 0,
31565
- chars: 0
31566
- };
31567
31444
  }
31568
31445
 
31569
- /**
31570
- * 处理流数据块
31571
- * @param {string} chunk - 接收到的数据块
31572
- * @param {Function} callback - 更新回调函数
31573
- */
31446
+ // 处理接收到的流数据块
31574
31447
  processChunk(chunk, callback) {
31575
- this.metrics.chunks++;
31576
- this.buffer += chunk;
31577
- if (this.options.debug) {
31578
- console.log('[StreamParser] 收到chunk:', chunk.substring(0, 100));
31579
- }
31580
- if (!this.buffer.includes('data:') && !this.buffer.includes('\n\n')) {
31581
- // 纯文本流,直接处理
31582
- if (this.options.debug) {
31583
- console.log('[StreamParser] 检测到纯文本流');
31584
- }
31585
- this.processPlainText(callback);
31586
- return;
31587
- }
31588
-
31589
- // 尝试解析为 SSE 格式
31590
- if (this.buffer.includes('data:')) {
31591
- this.processSSEFormat(callback);
31592
- } else {
31593
- // 直接处理纯文本流
31594
- this.processPlainText(callback);
31595
- }
31596
- }
31597
-
31598
- /**
31599
- * 处理标准 SSE 格式
31600
- */
31601
- processSSEFormat(callback) {
31602
- // SSE 格式:事件由双换行符分隔
31603
- const events = this.buffer.split('\n\n');
31604
-
31605
- // 保留最后一个可能不完整的事件
31606
- this.buffer = events.pop() || '';
31607
-
31608
- // 处理完整的事件
31609
- for (const event of events) {
31610
- if (event.trim()) {
31611
- this.metrics.events++;
31612
- this.processSSEEvent(event, callback);
31613
- }
31614
- }
31448
+ if (!chunk) return;
31449
+ this.parseContent(chunk, callback);
31615
31450
  }
31616
31451
 
31617
- /**
31618
- * 处理纯文本流格式
31619
- */
31620
- processPlainText(callback) {
31621
- const content = this.buffer;
31622
- this.buffer = ''; // 清空缓冲区
31623
-
31624
- if (content) {
31625
- this.metrics.chars += content.length;
31626
- if (this.options.debug) {
31627
- console.log('[StreamParser] 处理纯文本:', content);
31628
- }
31629
- this.parseContent(content, callback);
31630
- }
31631
- }
31632
-
31633
- /**
31634
- * 处理单个SSE事件
31635
- */
31636
- processSSEEvent(eventStr, callback) {
31637
- const lines = eventStr.split('\n');
31638
- for (const line of lines) {
31639
- // 解析 data: 行
31640
- if (line.startsWith('data:')) {
31641
- const data = line.substring(5).trim();
31642
- if (data === '[DONE]') {
31643
- this.flush(callback);
31644
- return;
31645
- }
31646
- try {
31647
- const parsed = JSON.parse(data);
31648
- const content = parsed?.choices?.[0]?.delta?.content;
31649
- if (content) {
31650
- this.metrics.chars += content.length;
31651
- if (this.options.debug) {
31652
- console.log('[StreamParser] 解析SSE内容:', content);
31653
- }
31654
- this.parseContent(content, callback);
31655
- }
31656
- } catch (error) {
31657
- if (this.options.debug) {
31658
- console.warn('[StreamParser] JSON解析失败:', data, error);
31659
- }
31660
- }
31661
- }
31662
- }
31663
- }
31664
-
31665
- /**
31666
- * 使用状态机解析内容和标签
31667
- */
31452
+ // 核心内容解析,支持 <think> 标签
31668
31453
  parseContent(content, callback) {
31669
31454
  let i = 0;
31670
31455
  while (i < content.length) {
31671
31456
  if (this.inTag) {
31672
- // 在标签内部,查找标签结束
31673
31457
  const endIndex = content.indexOf('>', i);
31674
31458
  if (endIndex !== -1) {
31675
- // 找到标签结束
31676
31459
  this.tagBuffer += content.substring(i, endIndex + 1);
31677
31460
  this.handleTag(this.tagBuffer);
31678
31461
  this.tagBuffer = '';
31679
31462
  this.inTag = false;
31680
31463
  i = endIndex + 1;
31681
31464
  } else {
31682
- // 标签未结束,缓存剩余部分
31465
+ // 标签未闭合,超过50字符强制输出,防止阻塞
31683
31466
  this.tagBuffer += content.substring(i);
31467
+ if (this.tagBuffer.length > 50) {
31468
+ this.appendText(this.tagBuffer);
31469
+ this.tagBuffer = '';
31470
+ this.inTag = false;
31471
+ }
31684
31472
  break;
31685
31473
  }
31686
31474
  } else {
31687
- // 不在标签内,查找标签开始
31688
31475
  const startIndex = content.indexOf('<', i);
31689
31476
  if (startIndex !== -1) {
31690
- // 找到标签开始,先处理前面的文本
31691
- if (startIndex > i) {
31692
- this.appendText(content.substring(i, startIndex));
31693
- }
31694
-
31695
- // 检查是否是完整标签
31477
+ if (startIndex > i) this.appendText(content.substring(i, startIndex));
31696
31478
  const endIndex = content.indexOf('>', startIndex);
31697
31479
  if (endIndex !== -1) {
31698
- // 完整标签
31699
31480
  const tag = content.substring(startIndex, endIndex + 1);
31700
31481
  this.handleTag(tag);
31701
31482
  i = endIndex + 1;
31702
31483
  } else {
31703
- // 不完整标签,标记进入标签状态
31704
- this.inTag = true;
31705
- this.tagBuffer = content.substring(startIndex);
31706
- break;
31484
+ const nextChar = content[startIndex + 1];
31485
+ if (!/[a-zA-Z/]/.test(nextChar)) {
31486
+ // 很可能不是标签,直接当文本输出
31487
+ this.appendText('<');
31488
+ i = startIndex + 1;
31489
+ } else {
31490
+ this.inTag = true;
31491
+ this.tagBuffer = content.substring(startIndex);
31492
+ break;
31493
+ }
31707
31494
  }
31708
31495
  } else {
31709
- // 没有标签,全部是文本
31710
31496
  this.appendText(content.substring(i));
31711
31497
  break;
31712
31498
  }
31713
31499
  }
31714
31500
  }
31715
-
31716
- // 定时批量更新
31717
31501
  this.scheduleUpdate(callback);
31718
31502
  }
31719
31503
 
31720
- /**
31721
- * 处理标签
31722
- */
31504
+ // 处理标签
31723
31505
  handleTag(tag) {
31724
- const tagName = tag.toLowerCase();
31725
- if (this.options.debug) {
31726
- console.log('[StreamParser] 处理标签:', tag);
31727
- }
31728
- if (tagName === '<think>') {
31729
- this.status = 'thinking';
31730
- } else if (tagName === '</think>') {
31731
- this.status = 'output';
31732
- }
31733
- // 可扩展:支持更多标签类型
31506
+ const t = tag.toLowerCase();
31507
+ if (t === '<think>') this.status = 'thinking';else if (t === '</think>') this.status = 'output';
31734
31508
  }
31735
31509
 
31736
- /**
31737
- * 添加文本到缓冲区
31738
- */
31510
+ // 添加文本到缓冲区
31739
31511
  appendText(text) {
31740
31512
  if (!text) return;
31741
- if (this.status === 'thinking') {
31742
- this.thinkingBuffer.push(text);
31743
- } else {
31744
- this.contentBuffer.push(text);
31745
- }
31513
+ if (this.status === 'thinking') this.thinkingBuffer.push(text);else this.contentBuffer.push(text);
31746
31514
  }
31747
31515
 
31748
- /**
31749
- * 计划更新(防抖)
31750
- */
31516
+ // 防抖刷新
31751
31517
  scheduleUpdate(callback) {
31752
31518
  if (this.updateTimer) return;
31753
31519
  this.updateTimer = setTimeout(() => {
@@ -31756,74 +31522,33 @@ class StreamParser {
31756
31522
  }, this.options.updateInterval);
31757
31523
  }
31758
31524
 
31759
- /**
31760
- * 立即刷新缓冲区
31761
- */
31525
+ // 刷新缓冲区
31762
31526
  flush(callback) {
31763
- if (!callback) {
31764
- console.warn('[StreamParser] flush: callback 为空');
31765
- return;
31766
- }
31767
- const hasThinking = this.thinkingBuffer.length > 0;
31768
- const hasContent = this.contentBuffer.length > 0;
31769
- if (!hasThinking && !hasContent) return;
31770
-
31771
- // 使用 join 比字符串拼接性能更好
31527
+ if (!callback) return;
31772
31528
  const result = {
31773
- thinking: hasThinking ? this.thinkingBuffer.join('') : null,
31774
- content: hasContent ? this.contentBuffer.join('') : null,
31529
+ thinking: this.thinkingBuffer.length ? this.thinkingBuffer.join('') : null,
31530
+ content: this.contentBuffer.length ? this.contentBuffer.join('') : null,
31775
31531
  status: this.status
31776
31532
  };
31777
- if (this.options.debug) {
31778
- console.log('[StreamParser] 刷新缓冲区:', {
31779
- thinking: result.thinking?.length || 0,
31780
- content: result.content?.length || 0,
31781
- status: result.status,
31782
- thinkingPreview: result.thinking?.substring(0, 50),
31783
- contentPreview: result.content?.substring(0, 50)
31784
- });
31785
- }
31786
-
31787
- // 清空缓冲区
31788
31533
  this.thinkingBuffer = [];
31789
31534
  this.contentBuffer = [];
31790
-
31791
- // 回调更新
31792
- try {
31793
- callback(result);
31794
- } catch (error) {
31795
- console.error('[StreamParser] 回调执行错误:', error);
31796
- }
31535
+ callback(result);
31797
31536
  }
31798
31537
 
31799
- /**
31800
- * 完成解析
31801
- */
31538
+ // 完成解析
31802
31539
  finish(callback) {
31803
- this.flush(callback);
31804
- if (this.updateTimer) {
31805
- clearTimeout(this.updateTimer);
31806
- this.updateTimer = null;
31807
- }
31808
- if (this.options.debug) {
31809
- const duration = Date.now() - this.metrics.startTime;
31810
- console.log('[StreamParser] 解析完成:', {
31811
- 耗时: `${duration}ms`,
31812
- 数据块: this.metrics.chunks,
31813
- 事件数: this.metrics.events,
31814
- 字符数: this.metrics.chars,
31815
- 平均速度: `${(this.metrics.chars / duration * 1000).toFixed(0)} chars/s`
31816
- });
31540
+ if (this.inTag && this.tagBuffer) {
31541
+ this.appendText(this.tagBuffer);
31542
+ this.tagBuffer = '';
31543
+ this.inTag = false;
31817
31544
  }
31545
+ this.flush(callback);
31546
+ if (this.updateTimer) clearTimeout(this.updateTimer);
31818
31547
  }
31819
31548
 
31820
- /**
31821
- * 销毁解析器
31822
- */
31549
+ // 销毁解析器
31823
31550
  destroy() {
31824
- if (this.updateTimer) {
31825
- clearTimeout(this.updateTimer);
31826
- }
31551
+ if (this.updateTimer) clearTimeout(this.updateTimer);
31827
31552
  this.reset();
31828
31553
  }
31829
31554
  }
@@ -31905,7 +31630,7 @@ const getCookie = cname => {
31905
31630
  this.streamParser.reset();
31906
31631
  try {
31907
31632
  const startTime = Date.now();
31908
- const token = getCookie('bonyear-access_token') || `e298f087-85bc-48c2-afb9-7c69ffc911aa`;
31633
+ const token = getCookie('bonyear-access_token') || `44e7f112-63f3-429d-908d-2c97ec380de2`;
31909
31634
  const response = await fetch(API_URL, {
31910
31635
  method: 'POST',
31911
31636
  headers: {
@@ -31914,7 +31639,7 @@ const getCookie = cname => {
31914
31639
  },
31915
31640
  body: JSON.stringify({
31916
31641
  content: message,
31917
- chatId: this.chatId
31642
+ chat_id: this.chatId
31918
31643
  })
31919
31644
  });
31920
31645
  if (!response.ok) {
@@ -31968,9 +31693,10 @@ const getCookie = cname => {
31968
31693
  const chunk = decoder.decode(value, {
31969
31694
  stream: true
31970
31695
  });
31971
-
31696
+ console.log('收到数据块:', chunk);
31972
31697
  // 使用解析器处理数据块,确保this指向正确
31973
31698
  this.streamParser.processChunk(chunk, function (result) {
31699
+ console.log('处理数据块:', result);
31974
31700
  self.handleStreamUpdate(result);
31975
31701
  });
31976
31702
  }
@@ -31993,6 +31719,7 @@ const getCookie = cname => {
31993
31719
  }
31994
31720
 
31995
31721
  // 更新回复内容
31722
+ console.log('更新回复内容:', result.content);
31996
31723
  if (result.content) {
31997
31724
  this.currentMessage.content += result.content;
31998
31725
  }
@@ -32127,6 +31854,7 @@ const startTime = null;
32127
31854
  },
32128
31855
  methods: {
32129
31856
  toggleWindow() {
31857
+ if (this.avaterStatus === 'thinking') return;
32130
31858
  this.visible = !this.visible;
32131
31859
  if (this.visible) {
32132
31860
  this.currentX = this.initialX;
@@ -32247,10 +31975,10 @@ const startTime = null;
32247
31975
  });
32248
31976
  ;// ./components/ChatWindow.vue?vue&type=script&lang=js
32249
31977
  /* harmony default export */ var components_ChatWindowvue_type_script_lang_js = (ChatWindowvue_type_script_lang_js);
32250
- ;// ./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=0e3e6d50&prod&scoped=true&lang=css
31978
+ ;// ./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=244aa1c1&prod&scoped=true&lang=css
32251
31979
  // extracted by mini-css-extract-plugin
32252
31980
 
32253
- ;// ./components/ChatWindow.vue?vue&type=style&index=0&id=0e3e6d50&prod&scoped=true&lang=css
31981
+ ;// ./components/ChatWindow.vue?vue&type=style&index=0&id=244aa1c1&prod&scoped=true&lang=css
32254
31982
 
32255
31983
  ;// ./components/ChatWindow.vue
32256
31984
 
@@ -32267,7 +31995,7 @@ var ChatWindow_component = normalizeComponent(
32267
31995
  staticRenderFns,
32268
31996
  false,
32269
31997
  null,
32270
- "0e3e6d50",
31998
+ "244aa1c1",
32271
31999
  null
32272
32000
 
32273
32001
  )