st-comp 0.0.251 → 0.0.253

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "st-comp",
3
3
  "public": true,
4
- "version": "0.0.251",
4
+ "version": "0.0.253",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -1,10 +1,13 @@
1
1
  <script setup>
2
2
  import dayjs from "dayjs";
3
3
  import { ElMessage } from "element-plus";
4
- import { ref, nextTick, watch, onMounted } from "vue";
4
+ import { getUserData } from "st-func";
5
+ import { inject, ref, nextTick, watch, reactive } from "vue";
5
6
  import { sendToBaiLianAppStreaming } from "../../public/aiTools";
6
7
  import { UserFilled, Service, Promotion } from "@element-plus/icons-vue";
7
8
 
9
+ const stConfig = inject("stConfig");
10
+ const userData = reactive(getUserData());
8
11
  const emit = defineEmits(["callBack"]);
9
12
  const props = defineProps({
10
13
  defaultMessage: {
@@ -14,114 +17,188 @@ const props = defineProps({
14
17
  });
15
18
 
16
19
  const visible = ref(false);
17
- const isSending = ref(false); // 发送按钮
18
- const isThinking = ref(false); // AI思考状态
20
+ const isSending = ref(false);
21
+ const isThinking = ref(false);
19
22
 
20
- // 消息列表
21
23
  const messageListRef = ref(null);
22
- const messages = ref([]);
24
+ const messages = ref([
25
+ {
26
+ role: "assistant", // AI-assistant, 用户-user
27
+ content: props.defaultMessage,
28
+ userContent: null,
29
+ showFeedback: false, // 是否展示反馈按钮(默认信息不用展示)
30
+ hasFeedback: false, // 是否已进行过反馈
31
+ createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // 消息发起时间
32
+ resTime: 0, // 响应总耗时
33
+ firstPackageTime: 0, // 首包响应耗时
34
+ },
35
+ ]);
23
36
  const inputMessage = ref("");
24
37
 
25
- // 当前正在接收的AI消息(用于流式更新)
26
- const currentAssistantMessage = ref(null);
27
- const currentAssistantIndex = ref(-1);
38
+ // 反馈弹窗相关
39
+ const feedbackDialogVisible = ref(false);
40
+ const feedbackContent = ref("");
41
+ const feedbackMessageIndex = ref({}); // 当前点击要反馈的message的索引
42
+
43
+ // 反馈弹窗相关函数处理
44
+ const handleFeedbackAction = async (action, messageIndex) => {
45
+ switch (action) {
46
+ // 窗口: 提交(满意)
47
+ case "satisfied": {
48
+ const message = messages.value[messageIndex];
49
+ const params = {
50
+ userName: userData.username,
51
+ userContent: message.userContent,
52
+ aiContent: message.content,
53
+ type: 1,
54
+ createTime: message.createTime,
55
+ resTime: message.resTime,
56
+ firstPackageTime: message.firstPackageTime,
57
+ };
58
+ await stConfig.request.post("/alarm/deliversign/addVarietyAiHelperLog", params);
59
+ ElMessage.success("感谢您的评价!");
60
+ messages.value[messageIndex].hasFeedback = true;
61
+ break;
62
+ }
63
+ // 窗口: 打开
64
+ case "open": {
65
+ feedbackMessageIndex.value = messageIndex;
66
+ feedbackDialogVisible.value = true;
67
+ break;
68
+ }
69
+ // 窗口: 提交(不满意)
70
+ case "unsatisfied": {
71
+ const message = messages.value[messageIndex];
72
+ const params = {
73
+ userName: userData.username,
74
+ userContent: message.userContent,
75
+ userSuggestion: feedbackContent.value,
76
+ aiContent: message.content,
77
+ type: 2,
78
+ resTime: message.resTime,
79
+ createTime: message.createTime,
80
+ firstPackageTime: message.firstPackageTime
81
+ };
82
+ await stConfig.request.post("/alarm/deliversign/addVarietyAiHelperLog", params);
83
+ ElMessage.success("感谢您的反馈!我们将持续跟踪并进行优化");
84
+ feedbackDialogVisible.value = false;
85
+ messages.value[messageIndex].hasFeedback = true;
86
+ break;
87
+ }
88
+ // 自动提交记录跟踪日志
89
+ case "default": {
90
+ const message = messages.value[messageIndex];
91
+ const params = {
92
+ userName: userData.username,
93
+ userContent: message.userContent,
94
+ userSuggestion: feedbackContent.value,
95
+ aiContent: message.content,
96
+ type: null,
97
+ resTime: message.resTime,
98
+ createTime: message.createTime,
99
+ firstPackageTime: message.firstPackageTime
100
+ };
101
+ await stConfig.request.post("/alarm/deliversign/addVarietyAiHelperLog", params);
102
+ }
103
+ }
104
+ };
28
105
 
29
106
  // 发送消息
30
107
  const sendMessage = async () => {
31
- // 校验输入内容是否为空
32
108
  const content = inputMessage.value.trim();
33
109
  if (!content) return ElMessage.warning("请输入消息内容");
34
- // 校验是否正在处理消息
35
110
  if (isSending.value) return;
36
111
 
37
112
  // 记录用户消息
38
113
  messages.value.push({
39
114
  role: "user",
40
- time: dayjs().format("HH:mm"),
41
115
  content: content,
116
+ createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
42
117
  });
43
118
  inputMessage.value = "";
44
119
  await scrollToBottom();
45
120
 
46
- // 创建一个临时的AI消息占位符
47
- const assistantMessage = {
121
+ // 创建AI消息占位符,记录对应的用户输入
122
+ messages.value.push({
48
123
  role: "assistant",
49
- time: dayjs().format("HH:mm"),
50
124
  content: "",
51
- };
52
- messages.value.push(assistantMessage);
53
- currentAssistantIndex.value = messages.value.length - 1;
54
- currentAssistantMessage.value = assistantMessage;
125
+ userContent: content,
126
+ showFeedback: false,
127
+ hasFeedback: false,
128
+ createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
129
+ resTime: 0,
130
+ firstPackageTime: 0,
131
+ });
55
132
  await scrollToBottom();
56
133
 
57
- // 发送请求至百炼应用AI(流式)
58
134
  isSending.value = true;
59
135
  isThinking.value = true;
60
-
136
+
61
137
  let fullResponse = "";
62
-
138
+ let resTime = new Date().getTime();
63
139
  try {
64
140
  const appId = "9e54d112acfe4531bd1fc4fee8827fef";
65
141
  const apiKey = "sk-d995eb26a4334bdeb2ccb4cbfaf51de8";
66
-
67
142
  await sendToBaiLianAppStreaming({
68
143
  appId,
69
144
  apiKey,
70
145
  value: content,
71
146
  callback: (type, data) => {
72
147
  if (type === "message") {
73
- // 实时更新消息内容
74
148
  fullResponse += data;
75
- if (currentAssistantMessage.value) {
76
- currentAssistantMessage.value.content = fullResponse;
77
- // 实时滚动到底部
149
+ // 直接更新最后一条AI消息
150
+ const lastMessage = messages.value[messages.value.length - 1];
151
+ if (lastMessage && lastMessage.role === "assistant") {
152
+ lastMessage.content = fullResponse;
78
153
  scrollToBottom();
79
154
  }
155
+ // 记录首包响应耗时
156
+ if (lastMessage.firstPackageTime === 0) {
157
+ lastMessage.firstPackageTime = new Date().getTime() - resTime;
158
+ }
80
159
  } else if (type === "finish") {
81
- // 流式传输完成
82
160
  isThinking.value = false;
83
161
  isSending.value = false;
84
- console.log(fullResponse)
162
+
163
+ // 显示反馈按钮
164
+ const lastMessage = messages.value[messages.value.length - 1];
165
+ if (lastMessage && lastMessage.role === "assistant") {
166
+ lastMessage.showFeedback = true;
167
+ lastMessage.resTime = new Date().getTime() - resTime;
168
+ handleFeedbackAction("default", messages.value.length - 1);
169
+ }
170
+
85
171
  // 触发回调
86
172
  try {
87
- // 尝试解析完整的响应为JSON
88
173
  const jsonResponse = JSON.parse(fullResponse);
89
174
  emit("callBack", jsonResponse);
90
175
  } catch (error) {
91
- // 如果不是JSON格式,直接返回文本
92
176
  emit("callBack", fullResponse);
93
177
  }
94
-
95
- // 清空当前消息引用
96
- currentAssistantMessage.value = null;
97
- currentAssistantIndex.value = -1;
98
178
  }
99
- }
179
+ },
100
180
  });
101
181
  } catch (error) {
102
182
  ElMessage.error(`AI响应异常: ${error}`);
103
- console.error("AI响应异常:", error);
104
-
105
- // 如果出错,移除占位消息并显示错误
106
- if (currentAssistantIndex.value !== -1) {
107
- messages.value.splice(currentAssistantIndex.value, 1);
108
- currentAssistantMessage.value = null;
109
- currentAssistantIndex.value = -1;
110
- }
111
-
183
+ // 移除占位的AI消息
184
+ messages.value.pop();
112
185
  // 添加错误提示消息
113
186
  messages.value.push({
114
187
  role: "assistant",
115
- time: dayjs().format("HH:mm"),
188
+ userContent: content,
116
189
  content: "抱歉,AI服务响应异常,请稍后重试。",
190
+ showFeedback: true,
191
+ hasFeedback: false,
192
+ createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
193
+ resTime: new Date().getTime() - resTime,
194
+ firstPackageTime: 0,
117
195
  });
196
+ handleFeedbackAction("default", messages.value.length - 1);
118
197
  await scrollToBottom();
119
-
120
198
  isSending.value = false;
121
199
  isThinking.value = false;
122
200
  }
123
201
  };
124
-
125
202
  // 滚动到底部
126
203
  const scrollToBottom = async () => {
127
204
  await nextTick();
@@ -130,14 +207,6 @@ const scrollToBottom = async () => {
130
207
  }
131
208
  };
132
209
 
133
- onMounted(() => {
134
- messages.value.push({
135
- role: "assistant",
136
- time: dayjs().format("HH:mm"),
137
- content: props.defaultMessage,
138
- });
139
- });
140
-
141
210
  watch(
142
211
  () => messages.value,
143
212
  () => {
@@ -145,11 +214,9 @@ watch(
145
214
  },
146
215
  { deep: true },
147
216
  );
148
-
149
217
  defineExpose({
150
- open: (data) => {
218
+ open: () => {
151
219
  visible.value = true;
152
- // 自动滚动到底部
153
220
  nextTick(() => {
154
221
  scrollToBottom();
155
222
  });
@@ -170,7 +237,6 @@ defineExpose({
170
237
  :modal-penetrable="true"
171
238
  >
172
239
  <div class="chat-container">
173
- <!-- 消息列表 -->
174
240
  <div
175
241
  ref="messageListRef"
176
242
  class="message-list"
@@ -178,26 +244,54 @@ defineExpose({
178
244
  <div
179
245
  v-for="(message, index) in messages"
180
246
  :key="index"
181
- class="message-item"
182
- :class="message.role"
247
+ class="message-item-wrapper"
183
248
  >
184
- <template v-if="message.content">
185
- <div class="avatar">
186
- <el-avatar
187
- :size="32"
188
- :icon="message.role === 'user' ? UserFilled : Service"
189
- />
190
- </div>
191
- <div class="message-content">
192
- <div class="message-text">{{ message.content }}</div>
193
- <div class="message-time">{{ message.time }}</div>
194
- </div>
195
- </template>
249
+ <div
250
+ class="message-item"
251
+ :class="message.role"
252
+ >
253
+ <template v-if="message.content">
254
+ <div class="avatar">
255
+ <el-avatar
256
+ :size="32"
257
+ :icon="message.role === 'user' ? UserFilled : Service"
258
+ />
259
+ </div>
260
+ <div class="message-content">
261
+ <div class="message-text">{{ message.content }}</div>
262
+ <div class="message-createTime">{{ message.createTime }}</div>
263
+ <!-- 反馈按钮(仅AI侧展示) -->
264
+ <template v-if="message.role === 'assistant'">
265
+ <template v-if="message.showFeedback && !message.hasFeedback">
266
+ <div class="message-createTime">请问对本轮查询结果是否满意?</div>
267
+ <div class="feedback-buttons">
268
+ <button
269
+ class="feedback-btn satisfied-btn"
270
+ @click="handleFeedbackAction('satisfied', index)"
271
+ >
272
+ <span class="btn-emoji">👍</span>
273
+ <span class="btn-text">满意</span>
274
+ </button>
275
+ <button
276
+ class="feedback-btn unsatisfied-btn"
277
+ @click="handleFeedbackAction('open', index)"
278
+ >
279
+ <span class="btn-emoji">👎</span>
280
+ <span class="btn-text">不满意</span>
281
+ </button>
282
+ </div>
283
+ </template>
284
+ <template v-if="message.showFeedback && message.hasFeedback">
285
+ <div class="message-createTime">感谢您进行的评价反馈</div>
286
+ </template>
287
+ </template>
288
+ </div>
289
+ </template>
290
+ </div>
196
291
  </div>
197
292
 
198
- <!-- AI 思考状态(仅在未开始接收流式消息时显示) -->
199
293
  <div
200
- v-if="isThinking && !currentAssistantMessage?.content"
294
+ v-if="isThinking && !messages[messages.length - 1]?.content"
201
295
  class="message-item assistant"
202
296
  >
203
297
  <div class="avatar">
@@ -215,7 +309,7 @@ defineExpose({
215
309
  </div>
216
310
  </div>
217
311
  </div>
218
- <!-- 输入区域 -->
312
+
219
313
  <div class="input-area">
220
314
  <el-input
221
315
  class="message-input"
@@ -244,9 +338,38 @@ defineExpose({
244
338
  </div>
245
339
  </div>
246
340
  </el-dialog>
341
+
342
+ <!-- 窗口: 反馈意见 -->
343
+ <el-dialog
344
+ v-model="feedbackDialogVisible"
345
+ title="📝 反馈意见"
346
+ width="400px"
347
+ >
348
+ <div class="feedback-dialog-content">
349
+ <div class="feedback-emoji">😟</div>
350
+ <p class="feedback-tip">很抱歉没能帮到您,请告诉我们哪里需要改进:</p>
351
+ <el-input
352
+ v-model="feedbackContent"
353
+ type="textarea"
354
+ :rows="4"
355
+ placeholder="[非必填]例如:回答不够准确、查询结果有误、界面体验不佳..."
356
+ />
357
+ </div>
358
+ <template #footer>
359
+ <span class="dialog-footer">
360
+ <el-button @click="feedbackDialogVisible = false">取消</el-button>
361
+ <el-button
362
+ type="primary"
363
+ @click="handleFeedbackAction('unsatisfied', feedbackMessageIndex)"
364
+ >提交反馈</el-button
365
+ >
366
+ </span>
367
+ </template>
368
+ </el-dialog>
247
369
  </template>
248
370
 
249
371
  <style lang="scss" scoped>
372
+ /* 样式保持不变,和之前一样 */
250
373
  .ai-dialog {
251
374
  :deep(.el-dialog) {
252
375
  border-radius: 24px;
@@ -280,12 +403,14 @@ defineExpose({
280
403
  }
281
404
  }
282
405
  }
406
+
283
407
  .chat-container {
284
408
  display: flex;
285
409
  flex-direction: column;
286
- height: 380px;
410
+ height: 480px;
287
411
  background: transparent;
288
412
  }
413
+
289
414
  .message-list {
290
415
  flex: 1;
291
416
  overflow-y: auto;
@@ -310,9 +435,13 @@ defineExpose({
310
435
  }
311
436
  }
312
437
  }
438
+
439
+ .message-item-wrapper {
440
+ margin-bottom: 20px;
441
+ }
442
+
313
443
  .message-item {
314
444
  display: flex;
315
- margin-bottom: 20px;
316
445
  animation: fadeInUp 0.3s ease-out;
317
446
 
318
447
  &.user {
@@ -332,7 +461,7 @@ defineExpose({
332
461
  border-radius: 18px 18px 4px 18px;
333
462
  }
334
463
 
335
- .message-time {
464
+ .message-createTime {
336
465
  text-align: right;
337
466
  }
338
467
  }
@@ -383,14 +512,80 @@ defineExpose({
383
512
  white-space: pre-wrap;
384
513
  }
385
514
 
386
- .message-time {
515
+ .message-createTime {
387
516
  font-size: 11px;
388
517
  color: #9ca3af;
389
518
  margin-top: 6px;
390
519
  padding: 0 4px;
391
520
  }
521
+
522
+ .feedback-buttons {
523
+ display: flex;
524
+ gap: 12px;
525
+ margin-top: 12px;
526
+ .feedback-btn {
527
+ display: flex;
528
+ align-items: center;
529
+ gap: 6px;
530
+ padding: 4px 10px;
531
+ border: none;
532
+ border-radius: 20px;
533
+ font-size: 13px;
534
+ font-weight: 500;
535
+ cursor: pointer;
536
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
537
+ background: rgba(255, 255, 255, 0.9);
538
+ backdrop-filter: blur(10px);
539
+
540
+ .btn-emoji {
541
+ font-size: 16px;
542
+ transition: transform 0.2s ease;
543
+ }
544
+
545
+ .btn-text {
546
+ font-size: 13px;
547
+ }
548
+
549
+ &:hover {
550
+ transform: translateY(-2px);
551
+
552
+ .btn-emoji {
553
+ transform: scale(1.1);
554
+ }
555
+ }
556
+
557
+ &:active {
558
+ transform: translateY(0);
559
+ }
560
+ }
561
+ .satisfied-btn {
562
+ background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
563
+ color: #1890ff;
564
+ border: 1px solid rgba(24, 144, 255, 0.2);
565
+ box-shadow: 0 2px 8px rgba(24, 144, 255, 0.1);
566
+
567
+ &:hover {
568
+ background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
569
+ border-color: #1890ff;
570
+ box-shadow: 0 4px 12px rgba(24, 144, 255, 0.2);
571
+ }
572
+ }
573
+ .unsatisfied-btn {
574
+ background: linear-gradient(135deg, #fff1f0 0%, #ffe7e5 100%);
575
+ color: #ff4d4f;
576
+ border: 1px solid rgba(255, 77, 79, 0.2);
577
+ box-shadow: 0 2px 8px rgba(255, 77, 79, 0.1);
578
+
579
+ &:hover {
580
+ background: linear-gradient(135deg, #ffe7e5 0%, #ffccc7 100%);
581
+ border-color: #ff4d4f;
582
+ box-shadow: 0 4px 12px rgba(255, 77, 79, 0.2);
583
+ }
584
+ }
585
+ }
392
586
  }
393
587
  }
588
+
394
589
  .typing-indicator {
395
590
  display: flex;
396
591
  gap: 4px;
@@ -416,6 +611,7 @@ defineExpose({
416
611
  }
417
612
  }
418
613
  }
614
+
419
615
  .input-area {
420
616
  padding: 16px 24px 24px;
421
617
  border-top: 1px solid rgba(102, 126, 234, 0.1);
@@ -478,6 +674,36 @@ defineExpose({
478
674
  }
479
675
  }
480
676
  }
677
+
678
+ .feedback-dialog-content {
679
+ text-align: center;
680
+ padding: 12px 0;
681
+
682
+ .feedback-emoji {
683
+ font-size: 48px;
684
+ margin-bottom: 16px;
685
+ animation: shake 0.5s ease-in-out;
686
+ }
687
+
688
+ .feedback-tip {
689
+ font-size: 14px;
690
+ color: #666;
691
+ margin-bottom: 20px;
692
+ line-height: 1.6;
693
+ }
694
+
695
+ :deep(.el-textarea__inner) {
696
+ border-radius: 12px;
697
+ border: 1px solid rgba(102, 126, 234, 0.2);
698
+ font-size: 14px;
699
+
700
+ &:focus {
701
+ border-color: #667eea;
702
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
703
+ }
704
+ }
705
+ }
706
+
481
707
  @keyframes fadeInUp {
482
708
  from {
483
709
  opacity: 0;
@@ -500,4 +726,16 @@ defineExpose({
500
726
  opacity: 1;
501
727
  }
502
728
  }
503
- </style>
729
+ @keyframes shake {
730
+ 0%,
731
+ 100% {
732
+ transform: translateX(0);
733
+ }
734
+ 25% {
735
+ transform: translateX(-5px);
736
+ }
737
+ 75% {
738
+ transform: translateX(5px);
739
+ }
740
+ }
741
+ </style>
package/public/aiTools.js CHANGED
@@ -30,40 +30,80 @@ export const sendToBaiLianAppNonStreaming = async ({ appId, apiKey, value }) =>
30
30
  // 流式返回
31
31
  export const sendToBaiLianAppStreaming = async ({ appId, apiKey, value, callback }) => {
32
32
  try {
33
- const res = await fetch(`https://dashscope.aliyuncs.com/api/v1/apps/${appId}/completion`, {
33
+ const response = await fetch(`https://dashscope.aliyuncs.com/api/v1/apps/${appId}/completion`, {
34
34
  method: "POST",
35
35
  body: JSON.stringify({
36
36
  input: { prompt: value },
37
- parameters: {
38
- incremental_output: "true", // 流式返回
39
- },
37
+ parameters: { incremental_output: "true" },
40
38
  debug: {},
41
39
  }),
42
40
  headers: {
43
41
  Authorization: `Bearer ${apiKey}`,
44
42
  "Content-Type": "application/json",
45
- "X-DashScope-SSE": "enable", // 流式输出
43
+ "X-DashScope-SSE": "enable",
46
44
  },
47
45
  });
48
- if (!res.ok || !res.body) throw new Error("请求失败");
49
-
50
- const reader = res.body.getReader();
46
+
47
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
48
+
49
+ const reader = response.body.getReader();
51
50
  const decoder = new TextDecoder();
52
-
51
+ let buffer = "";
52
+
53
53
  while (true) {
54
54
  const { done, value } = await reader.read();
55
- if (done && callback) {
55
+ if (done) {
56
+ // 处理最后可能遗留的数据
57
+ if (buffer.trim()) {
58
+ tryProcessBuffer(buffer, callback);
59
+ }
56
60
  callback("finish", "");
57
61
  break;
58
62
  }
59
- try {
60
- const data = decoder.decode(value, { stream: true });
61
- const resData = JSON.parse(data.split("\n")[3].substr(5));
62
- const resText = resData?.output?.text;
63
- if (resText && callback) callback("message", resText);
64
- } catch (error) {}
63
+
64
+ buffer += decoder.decode(value, { stream: true });
65
+
66
+ let newlineIndex;
67
+ while ((newlineIndex = buffer.indexOf("\n")) !== -1) {
68
+ const line = buffer.substring(0, newlineIndex).trim();
69
+ buffer = buffer.substring(newlineIndex + 1);
70
+
71
+ if (line.startsWith("data:")) {
72
+ const data = line.substring(5).trim();
73
+ if (data && data !== "[DONE]") {
74
+ try {
75
+ const parsed = JSON.parse(data);
76
+ const text = parsed?.output?.text;
77
+ if (text && callback) {
78
+ callback("message", text);
79
+ }
80
+ } catch (e) {
81
+ // 可能是部分数据,继续等待
82
+ console.debug("等待完整数据...");
83
+ }
84
+ }
85
+ }
86
+ }
65
87
  }
66
88
  } catch (error) {
67
- console.error(error);
89
+ console.error("流式请求失败:", error);
90
+ callback("error", error.message);
68
91
  }
69
92
  };
93
+
94
+ // 辅助函数:处理缓冲区剩余数据
95
+ function tryProcessBuffer(buffer, callback) {
96
+ const lines = buffer.split("\n");
97
+ for (const line of lines) {
98
+ if (line.startsWith("data:")) {
99
+ const data = line.substring(5).trim();
100
+ if (data && data !== "[DONE]") {
101
+ try {
102
+ const parsed = JSON.parse(data);
103
+ const text = parsed?.output?.text;
104
+ if (text && callback) callback("message", text);
105
+ } catch (e) {}
106
+ }
107
+ }
108
+ }
109
+ }