ibc-ai-web-sdk 2.0.4 → 2.0.5
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.cjs.js +299 -52
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +299 -52
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +299 -52
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/index.d.ts +35 -1
- package/package.json +2 -2
package/dist/index.umd.js
CHANGED
|
@@ -386,8 +386,25 @@
|
|
|
386
386
|
if (conversationId) payload.conversationId = conversationId;
|
|
387
387
|
const attachmentIds = options.attachmentIds || this.normalizeAttachmentIds(options.attachments);
|
|
388
388
|
if (attachmentIds.length > 0) payload.attachmentIds = attachmentIds;
|
|
389
|
-
|
|
390
|
-
if (bizParams)
|
|
389
|
+
let bizParams = options.bizParams || options.extendInfo || this.config.extendInfo;
|
|
390
|
+
if (bizParams) {
|
|
391
|
+
if (typeof bizParams === 'string') {
|
|
392
|
+
try {
|
|
393
|
+
bizParams = JSON.parse(bizParams);
|
|
394
|
+
} catch (e) {
|
|
395
|
+
bizParams = {};
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
bizParams = {};
|
|
400
|
+
}
|
|
401
|
+
// P3: 将页面上下文合并到 bizParams(contextMode='bizParams' 时由 dialog 传入)
|
|
402
|
+
if (options.context) {
|
|
403
|
+
Object.assign(bizParams, options.context);
|
|
404
|
+
}
|
|
405
|
+
if (Object.keys(bizParams).length > 0) {
|
|
406
|
+
payload.bizParams = JSON.stringify(bizParams);
|
|
407
|
+
}
|
|
391
408
|
return payload;
|
|
392
409
|
}
|
|
393
410
|
normalizeAttachmentIds(attachments) {
|
|
@@ -3570,7 +3587,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
3570
3587
|
* 样式与功能完全对齐 Vue 版本(1:1 复刻)
|
|
3571
3588
|
*
|
|
3572
3589
|
* @author IBC AI Team
|
|
3573
|
-
* @version 2.
|
|
3590
|
+
* @version 2.0.5
|
|
3574
3591
|
*/
|
|
3575
3592
|
|
|
3576
3593
|
|
|
@@ -3661,6 +3678,8 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
3661
3678
|
this._runtimeEventsContainerEl = null;
|
|
3662
3679
|
this._runtimeStatusEl = null;
|
|
3663
3680
|
this._runtimeCountEl = null;
|
|
3681
|
+
// P3: 页面上下文数据(宿主页面选中的数据)
|
|
3682
|
+
this._context = {};
|
|
3664
3683
|
|
|
3665
3684
|
// ====== 默认主题配置(与 themes.js DEFAULT_THEME 完全一致) ======
|
|
3666
3685
|
this._themeVars = {
|
|
@@ -3747,6 +3766,8 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
3747
3766
|
if (this._handleOffline) window.removeEventListener('offline', this._handleOffline);
|
|
3748
3767
|
// P2-17: 清理resize监听
|
|
3749
3768
|
if (this._handleResize) window.removeEventListener('resize', this._handleResize);
|
|
3769
|
+
// P0: 清理拖拽事件监听
|
|
3770
|
+
this._cleanupDragListeners();
|
|
3750
3771
|
// 暂停后台Token刷新定时器(detach时停止,re-attach时由connectedCallback恢复)
|
|
3751
3772
|
if (this._chatClient) {
|
|
3752
3773
|
this._chatClient.stopBackgroundRefresh();
|
|
@@ -3898,6 +3919,14 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
3898
3919
|
authFn: null,
|
|
3899
3920
|
onLoad: null,
|
|
3900
3921
|
onError: null,
|
|
3922
|
+
// P3: 发送前回调 - 每发消息前调用,可返回最新页面上下文(与 setContext 合并,此回调结果优先)
|
|
3923
|
+
onBeforeSend: null,
|
|
3924
|
+
// P3: 上下文注入方式 — 'prompt'=拼到用户消息前面(默认), 'bizParams'=注入到 bizParams JSON 中
|
|
3925
|
+
contextMode: 'prompt',
|
|
3926
|
+
// P4: 调试模式 - 开启后 console 打印请求/响应/SSE/上下文合并全过程
|
|
3927
|
+
debug: false,
|
|
3928
|
+
// P4: 自定义消息操作按钮 — 返回数组 [{label, className?, onClick}] 在 AI 消息下方渲染
|
|
3929
|
+
onMessageActions: null,
|
|
3901
3930
|
suggestions: [{
|
|
3902
3931
|
label: '帮我购买一台轻量应用服务器用于部署应用',
|
|
3903
3932
|
value: '帮我购买一台轻量应用服务器用于部署应用'
|
|
@@ -3911,6 +3940,11 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
3911
3940
|
this._chatClient = new AIChatClient(this._config);
|
|
3912
3941
|
if (this._conversationId) this._chatClient.setConversationId(this._conversationId);
|
|
3913
3942
|
this.applyConfig();
|
|
3943
|
+
// P1-2 fix: 在 _config 就绪后初始化拖拽,以正确读取 enableDrag
|
|
3944
|
+
if (this._config?.enableDrag !== false && this.getAttribute('mode') !== 'inline' && !this._dragInitialized) {
|
|
3945
|
+
this.initDraggable();
|
|
3946
|
+
}
|
|
3947
|
+
this._debugLog('初始化完成', 'appId=' + this._config.appId, 'userId=' + this._config.userId, 'baseUrl=' + this._config.apiBaseUrl, 'debug=' + !!this._config.debug, 'contextMode=' + (this._config.contextMode || 'prompt'));
|
|
3914
3948
|
this.loadAppDetail();
|
|
3915
3949
|
// 触发 onLoad 回调(与Vue版一致)
|
|
3916
3950
|
if (this._config?.onLoad) this._config.onLoad(this);
|
|
@@ -3997,6 +4031,44 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
3997
4031
|
return this;
|
|
3998
4032
|
}
|
|
3999
4033
|
|
|
4034
|
+
/**
|
|
4035
|
+
* 设置页面上下文数据(宿主页面选中的数据,随每次请求发送)
|
|
4036
|
+
* @param {Object} context - 上下文数据对象,传 null 清空
|
|
4037
|
+
* @returns {this}
|
|
4038
|
+
*/
|
|
4039
|
+
setContext(context) {
|
|
4040
|
+
this._context = context && typeof context === 'object' ? {
|
|
4041
|
+
...context
|
|
4042
|
+
} : {};
|
|
4043
|
+
return this;
|
|
4044
|
+
}
|
|
4045
|
+
|
|
4046
|
+
/**
|
|
4047
|
+
* 获取当前上下文数据
|
|
4048
|
+
* @returns {Object}
|
|
4049
|
+
*/
|
|
4050
|
+
getContext() {
|
|
4051
|
+
return {
|
|
4052
|
+
...this._context
|
|
4053
|
+
};
|
|
4054
|
+
}
|
|
4055
|
+
|
|
4056
|
+
/**
|
|
4057
|
+
* 外部触发表态发送(业务层主动调用,如点击外部按钮触发 AI 请求)
|
|
4058
|
+
* @param {string} text - 要发送的消息内容
|
|
4059
|
+
* @returns {this}
|
|
4060
|
+
*/
|
|
4061
|
+
send(text) {
|
|
4062
|
+
const content = String(text || '').trim();
|
|
4063
|
+
if (!content) return this;
|
|
4064
|
+
if (this._input) this._input.value = content;
|
|
4065
|
+
this._autoResizeInput();
|
|
4066
|
+
this._updateSendButtonState();
|
|
4067
|
+
this._lastSendTime = 0; // 跳过防抖,外部触发视为独立操作
|
|
4068
|
+
this.handleSend();
|
|
4069
|
+
return this;
|
|
4070
|
+
}
|
|
4071
|
+
|
|
4000
4072
|
// ==================== 显示/隐藏 ====================
|
|
4001
4073
|
|
|
4002
4074
|
showDialog() {
|
|
@@ -4632,6 +4704,19 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
4632
4704
|
color: var(--ai-success);
|
|
4633
4705
|
background: rgba(16, 185, 129, 0.08);
|
|
4634
4706
|
}
|
|
4707
|
+
/* P4: 自定义操作按钮(文本标签型,宽度自适应) */
|
|
4708
|
+
.action-icon.custom-action-btn {
|
|
4709
|
+
width: auto;
|
|
4710
|
+
padding: 4px 10px;
|
|
4711
|
+
font-size: 12px;
|
|
4712
|
+
font-weight: 500;
|
|
4713
|
+
white-space: nowrap;
|
|
4714
|
+
}
|
|
4715
|
+
.action-icon.custom-action-btn:hover {
|
|
4716
|
+
color: #fff;
|
|
4717
|
+
background: var(--ai-primary);
|
|
4718
|
+
transform: translateY(-1px);
|
|
4719
|
+
}
|
|
4635
4720
|
|
|
4636
4721
|
/* ========== 底部输入框(与Vue .dialog-footer 一致) ========== */
|
|
4637
4722
|
.dialog-footer {
|
|
@@ -5212,8 +5297,8 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5212
5297
|
});
|
|
5213
5298
|
}
|
|
5214
5299
|
|
|
5215
|
-
//
|
|
5216
|
-
|
|
5300
|
+
// 拖拽(内嵌模式禁用)— 由 init() 在 _config 就绪后触发
|
|
5301
|
+
// initDraggable 延迟到 init() 中执行以免 _config 为空
|
|
5217
5302
|
});
|
|
5218
5303
|
}
|
|
5219
5304
|
|
|
@@ -5266,59 +5351,97 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5266
5351
|
initDraggable() {
|
|
5267
5352
|
const header = this.shadowRoot?.querySelector('.dialog-header');
|
|
5268
5353
|
if (!header) return;
|
|
5354
|
+
|
|
5355
|
+
// 清理上一次遗留的 document 级监听(SPA 路由切换场景)
|
|
5356
|
+
this._cleanupDragListeners();
|
|
5357
|
+
const self = this;
|
|
5269
5358
|
const startDrag = (clientX, clientY) => {
|
|
5270
5359
|
// P2-17: 移动端禁用拖拽(与Vue版 startTouchDrag: if(isExpanded || isMobile) return 一致)
|
|
5271
|
-
if (
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
const rect =
|
|
5275
|
-
|
|
5276
|
-
|
|
5360
|
+
if (self._isExpanded || self._isMobile) return;
|
|
5361
|
+
self._isDragging = true;
|
|
5362
|
+
self._dialog.classList.add('dragging');
|
|
5363
|
+
const rect = self._dialog.getBoundingClientRect();
|
|
5364
|
+
self._dragStartX = clientX - rect.left;
|
|
5365
|
+
self._dragStartY = clientY - rect.top;
|
|
5277
5366
|
};
|
|
5278
5367
|
const onDrag = (clientX, clientY) => {
|
|
5279
|
-
if (!
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5368
|
+
if (!self._isDragging) return;
|
|
5369
|
+
self._dialogX = clientX - self._dragStartX;
|
|
5370
|
+
self._dialogY = clientY - self._dragStartY;
|
|
5371
|
+
self._dialog.style.left = self._dialogX + 'px';
|
|
5372
|
+
self._dialog.style.right = 'auto';
|
|
5373
|
+
self._dialog.style.top = self._dialogY + 'px';
|
|
5374
|
+
self._dialog.style.bottom = 'auto';
|
|
5286
5375
|
};
|
|
5287
5376
|
const stopDrag = () => {
|
|
5288
|
-
if (
|
|
5289
|
-
|
|
5290
|
-
|
|
5377
|
+
if (self._isDragging) {
|
|
5378
|
+
self._isDragging = false;
|
|
5379
|
+
self._dialog.classList.remove('dragging');
|
|
5291
5380
|
}
|
|
5292
5381
|
};
|
|
5293
5382
|
|
|
5294
|
-
//
|
|
5295
|
-
|
|
5383
|
+
// 鼠标事件(桌面端)— 保存引用以便清理
|
|
5384
|
+
this._dragMouseDownHandler = e => {
|
|
5296
5385
|
if (e.target.closest('button, .header-icon')) return;
|
|
5297
5386
|
startDrag(e.clientX, e.clientY);
|
|
5298
5387
|
e.preventDefault();
|
|
5299
|
-
}
|
|
5300
|
-
|
|
5388
|
+
};
|
|
5389
|
+
this._dragMouseMoveHandler = e => {
|
|
5301
5390
|
onDrag(e.clientX, e.clientY);
|
|
5302
|
-
}
|
|
5303
|
-
|
|
5391
|
+
};
|
|
5392
|
+
this._dragMouseUpHandler = stopDrag;
|
|
5393
|
+
header.addEventListener('mousedown', this._dragMouseDownHandler);
|
|
5394
|
+
document.addEventListener('mousemove', this._dragMouseMoveHandler);
|
|
5395
|
+
document.addEventListener('mouseup', this._dragMouseUpHandler);
|
|
5304
5396
|
|
|
5305
5397
|
// P1-7: 触摸事件(移动端,与Vue版一致)
|
|
5306
|
-
|
|
5307
|
-
if (
|
|
5398
|
+
this._dragTouchStartHandler = e => {
|
|
5399
|
+
if (self._isExpanded) return;
|
|
5308
5400
|
if (e.target.closest('button, .header-icon')) return;
|
|
5309
5401
|
const touch = e.touches[0];
|
|
5310
5402
|
startDrag(touch.clientX, touch.clientY);
|
|
5311
|
-
}
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
document.addEventListener('touchmove', e => {
|
|
5315
|
-
if (!this._isDragging) return;
|
|
5403
|
+
};
|
|
5404
|
+
this._dragTouchMoveHandler = e => {
|
|
5405
|
+
if (!self._isDragging) return;
|
|
5316
5406
|
const touch = e.touches[0];
|
|
5317
5407
|
onDrag(touch.clientX, touch.clientY);
|
|
5318
|
-
}
|
|
5408
|
+
};
|
|
5409
|
+
this._dragTouchEndHandler = stopDrag;
|
|
5410
|
+
header.addEventListener('touchstart', this._dragTouchStartHandler, {
|
|
5319
5411
|
passive: true
|
|
5320
5412
|
});
|
|
5321
|
-
document.addEventListener('
|
|
5413
|
+
document.addEventListener('touchmove', this._dragTouchMoveHandler, {
|
|
5414
|
+
passive: true
|
|
5415
|
+
});
|
|
5416
|
+
document.addEventListener('touchend', this._dragTouchEndHandler);
|
|
5417
|
+
this._dragInitialized = true;
|
|
5418
|
+
}
|
|
5419
|
+
|
|
5420
|
+
// P0: 清理拖拽事件监听(SPA disconnectedCallback / re-init 调用)
|
|
5421
|
+
_cleanupDragListeners() {
|
|
5422
|
+
if (this._dragMouseDownHandler) {
|
|
5423
|
+
const header = this.shadowRoot?.querySelector('.dialog-header');
|
|
5424
|
+
if (header) {
|
|
5425
|
+
header.removeEventListener('mousedown', this._dragMouseDownHandler);
|
|
5426
|
+
header.removeEventListener('touchstart', this._dragTouchStartHandler, {
|
|
5427
|
+
passive: true
|
|
5428
|
+
});
|
|
5429
|
+
}
|
|
5430
|
+
this._dragMouseDownHandler = null;
|
|
5431
|
+
this._dragTouchStartHandler = null;
|
|
5432
|
+
}
|
|
5433
|
+
if (this._dragMouseMoveHandler) {
|
|
5434
|
+
document.removeEventListener('mousemove', this._dragMouseMoveHandler);
|
|
5435
|
+
document.removeEventListener('touchmove', this._dragTouchMoveHandler, {
|
|
5436
|
+
passive: true
|
|
5437
|
+
});
|
|
5438
|
+
document.removeEventListener('mouseup', this._dragMouseUpHandler);
|
|
5439
|
+
document.removeEventListener('touchend', this._dragTouchEndHandler);
|
|
5440
|
+
this._dragMouseMoveHandler = null;
|
|
5441
|
+
this._dragTouchMoveHandler = null;
|
|
5442
|
+
this._dragMouseUpHandler = null;
|
|
5443
|
+
this._dragTouchEndHandler = null;
|
|
5444
|
+
}
|
|
5322
5445
|
}
|
|
5323
5446
|
applyConfig() {
|
|
5324
5447
|
if (!this._config) return;
|
|
@@ -5483,11 +5606,12 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5483
5606
|
<div class="message-content">
|
|
5484
5607
|
${hasRuntimeEvents ? this._buildRuntimePanel(msg, idx) : ''}
|
|
5485
5608
|
${bubbleContent ? `<div class="${bubbleClass}">${bubbleContent}</div>` : ''}
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5609
|
+
${!msg._isStreaming ? `<div class="message-actions-bar">
|
|
5610
|
+
${msg.type === 'ai' ? `<div class="action-icons">
|
|
5611
|
+
<span class="action-icon copy-btn${msg.copied ? ' copied' : ''}" data-idx="${idx}" title="${msg.copied ? '已复制' : '复制'}">${msg.copied ? '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="m20 6-11 11-5-5"/></svg>' : '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'}</span>
|
|
5612
|
+
<span class="action-icon regenerate-btn" data-idx="${idx}" title="重新回答"><svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg></span>
|
|
5613
|
+
${this._buildCustomActions(msg, idx)}
|
|
5614
|
+
</div>` : ''}
|
|
5491
5615
|
</div>` : ''}
|
|
5492
5616
|
</div>
|
|
5493
5617
|
</div>`;
|
|
@@ -5517,6 +5641,24 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5517
5641
|
});
|
|
5518
5642
|
});
|
|
5519
5643
|
|
|
5644
|
+
// P4: 绑定自定义操作按钮
|
|
5645
|
+
this._body.querySelectorAll('.custom-action-btn').forEach(btn => {
|
|
5646
|
+
btn.addEventListener('click', () => {
|
|
5647
|
+
const idx = parseInt(btn.dataset.idx);
|
|
5648
|
+
const actionIdx = parseInt(btn.dataset.action);
|
|
5649
|
+
const msg = this._messages[idx];
|
|
5650
|
+
if (!msg) return;
|
|
5651
|
+
try {
|
|
5652
|
+
const actions = this._getCustomActions(msg, idx);
|
|
5653
|
+
if (actions && actions[actionIdx]) {
|
|
5654
|
+
actions[actionIdx].onClick(msg.content);
|
|
5655
|
+
}
|
|
5656
|
+
} catch (e) {
|
|
5657
|
+
console.warn('[AIChatDialog] 自定义操作按钮执行失败:', e);
|
|
5658
|
+
}
|
|
5659
|
+
});
|
|
5660
|
+
});
|
|
5661
|
+
|
|
5520
5662
|
// 绑定执行过程面板折叠/展开(Shadow DOM 下 inline onclick 不可靠)
|
|
5521
5663
|
this._body.querySelectorAll('.runtime-header').forEach(header => {
|
|
5522
5664
|
header.addEventListener('click', () => {
|
|
@@ -5769,7 +5911,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5769
5911
|
this.showToast(this._config?.emptyMessageError || '请输入消息内容');
|
|
5770
5912
|
return;
|
|
5771
5913
|
}
|
|
5772
|
-
if (this._isLoading) return;
|
|
5914
|
+
if (this._isLoading || this._streaming) return;
|
|
5773
5915
|
|
|
5774
5916
|
// P1-11: 字数限制检查
|
|
5775
5917
|
const maxLen = this._config?.maxLength ?? 500;
|
|
@@ -5825,8 +5967,47 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5825
5967
|
attachmentIds.push(res.data.attachmentId);
|
|
5826
5968
|
}
|
|
5827
5969
|
}
|
|
5828
|
-
|
|
5829
|
-
|
|
5970
|
+
|
|
5971
|
+
// P3: 收集页面上下文(setContext + onBeforeSend)
|
|
5972
|
+
let context = {
|
|
5973
|
+
...(this._context || {})
|
|
5974
|
+
};
|
|
5975
|
+
if (typeof this._config?.onBeforeSend === 'function') {
|
|
5976
|
+
try {
|
|
5977
|
+
const dynamicCtx = await this._config.onBeforeSend();
|
|
5978
|
+
if (dynamicCtx && typeof dynamicCtx === 'object') {
|
|
5979
|
+
context = {
|
|
5980
|
+
...context,
|
|
5981
|
+
...dynamicCtx
|
|
5982
|
+
};
|
|
5983
|
+
}
|
|
5984
|
+
} catch (e) {
|
|
5985
|
+
console.warn('[AIChatDialog] onBeforeSend 执行失败:', e);
|
|
5986
|
+
}
|
|
5987
|
+
}
|
|
5988
|
+
const hasContext = context && Object.keys(context).length > 0;
|
|
5989
|
+
const rawMode = this._config?.contextMode;
|
|
5990
|
+
const VALID_CONTEXT_MODES = ['prompt', 'bizParams'];
|
|
5991
|
+
const contextMode = VALID_CONTEXT_MODES.includes(rawMode) ? rawMode : rawMode ? (console.warn('[AIChatDialog] 无效的 contextMode: "' + rawMode + '",已回退为 "prompt"(有效值: ' + VALID_CONTEXT_MODES.join(', ') + ')'), 'prompt') : 'prompt';
|
|
5992
|
+
let finalPrompt = content || attachmentText;
|
|
5993
|
+
let contextForBizParams = null;
|
|
5994
|
+
if (hasContext) {
|
|
5995
|
+
this._debugLog('上下文合并', 'keys=', Object.keys(context), 'mode=', contextMode);
|
|
5996
|
+
if (contextMode === 'bizParams') {
|
|
5997
|
+
// 注入到 bizParams
|
|
5998
|
+
contextForBizParams = context;
|
|
5999
|
+
} else {
|
|
6000
|
+
// 默认:拼到 prompt 前面
|
|
6001
|
+
const ctxText = this._formatContextText(context);
|
|
6002
|
+
if (ctxText) {
|
|
6003
|
+
finalPrompt = ctxText + '\n---\n' + finalPrompt;
|
|
6004
|
+
}
|
|
6005
|
+
}
|
|
6006
|
+
}
|
|
6007
|
+
this._debugLog('发送', 'prompt=' + (finalPrompt || '').substring(0, 150) + (finalPrompt && finalPrompt.length > 150 ? '...' : ''), 'ctxKeys=' + Object.keys(contextForBizParams || context || {}).join(','), 'mode=' + contextMode);
|
|
6008
|
+
await this.sendMessageToAI(finalPrompt, {
|
|
6009
|
+
attachmentIds,
|
|
6010
|
+
context: contextForBizParams
|
|
5830
6011
|
});
|
|
5831
6012
|
} catch (err) {
|
|
5832
6013
|
console.error('[AIChatDialog] Error:', err);
|
|
@@ -5860,6 +6041,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5860
6041
|
...(options.streamOptions || {})
|
|
5861
6042
|
};
|
|
5862
6043
|
if (options.attachmentIds?.length) streamOpts.attachmentIds = options.attachmentIds;
|
|
6044
|
+
if (options.context) streamOpts.context = options.context;
|
|
5863
6045
|
await this._directApiCallStream(msgId, content, streamOpts);
|
|
5864
6046
|
}
|
|
5865
6047
|
}
|
|
@@ -5917,6 +6099,10 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
5917
6099
|
if (!this._chatClient) {
|
|
5918
6100
|
this._chatClient = new AIChatClient(this._config || {});
|
|
5919
6101
|
}
|
|
6102
|
+
if (this._config?.debug) {
|
|
6103
|
+
this._chatClient.config.debug = true;
|
|
6104
|
+
}
|
|
6105
|
+
this._debugLog('Stream开始', 'msgId=' + msgId, 'content=' + (content || '').substring(0, 80), 'opts=' + JSON.stringify(requestOptions));
|
|
5920
6106
|
if (Object.prototype.hasOwnProperty.call(requestOptions, 'conversationId')) {
|
|
5921
6107
|
this._chatClient.setConversationId(requestOptions.conversationId || null);
|
|
5922
6108
|
} else if (this._conversationId) {
|
|
@@ -6035,6 +6221,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6035
6221
|
}
|
|
6036
6222
|
}, requestOptions);
|
|
6037
6223
|
if (response?.success) {
|
|
6224
|
+
this._debugLog('Stream完成', 'ok, conversationId=' + (response.data?.conversationId || this._conversationId), 'textLen=' + streamText.length);
|
|
6038
6225
|
if (response.data?.conversationId) {
|
|
6039
6226
|
this._conversationId = response.data.conversationId;
|
|
6040
6227
|
} else if (this._chatClient.conversationId) {
|
|
@@ -6047,6 +6234,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6047
6234
|
streamText = result;
|
|
6048
6235
|
}
|
|
6049
6236
|
} else {
|
|
6237
|
+
this._finalizeMsg(msgId, streamText || '(无回复)');
|
|
6050
6238
|
return;
|
|
6051
6239
|
}
|
|
6052
6240
|
this._finalizeMsg(msgId, streamText || '(无回复)');
|
|
@@ -6057,12 +6245,14 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6057
6245
|
}));
|
|
6058
6246
|
if (this._config?.onMessageReceived) this._config.onMessageReceived(streamText);
|
|
6059
6247
|
} catch (e) {
|
|
6248
|
+
this._debugWarn('Stream异常', e.name + ': ' + (e.message || ''));
|
|
6060
6249
|
if (e.name === 'AbortError') {
|
|
6061
6250
|
this._updateMsg(msgId, '(请求超时或已取消)');
|
|
6062
6251
|
} else {
|
|
6063
6252
|
console.error('[AIChatDialog] 流式失败:', e);
|
|
6064
6253
|
this._updateMsg(msgId, '网络错误: ' + (e.message || '请检查连接'));
|
|
6065
6254
|
}
|
|
6255
|
+
this._finalizeMsg(msgId, this._messages.find(m => m.id === msgId)?.content || '(无回复)');
|
|
6066
6256
|
}
|
|
6067
6257
|
}
|
|
6068
6258
|
_getStreamTextEl() {
|
|
@@ -6186,6 +6376,27 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6186
6376
|
return this._ERROR_CONTENT_PATTERNS.some(p => content.startsWith(p));
|
|
6187
6377
|
}
|
|
6188
6378
|
|
|
6379
|
+
// P3: 将上下文对象格式化为可读文本(拼入 prompt 前缀)
|
|
6380
|
+
_formatContextText(context) {
|
|
6381
|
+
if (!context || typeof context !== 'object') return '';
|
|
6382
|
+
const lines = ['[页面上下文]'];
|
|
6383
|
+
for (const key in context) {
|
|
6384
|
+
if (!Object.prototype.hasOwnProperty.call(context, key)) continue;
|
|
6385
|
+
const val = context[key];
|
|
6386
|
+
if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'object') {
|
|
6387
|
+
lines.push(key + ':');
|
|
6388
|
+
for (const item of val) {
|
|
6389
|
+
lines.push(' - ' + Object.values(item).join(' | '));
|
|
6390
|
+
}
|
|
6391
|
+
} else if (typeof val === 'object' && val !== null) {
|
|
6392
|
+
lines.push(key + ': ' + JSON.stringify(val));
|
|
6393
|
+
} else {
|
|
6394
|
+
lines.push(key + ': ' + val);
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
return lines.join('\n');
|
|
6398
|
+
}
|
|
6399
|
+
|
|
6189
6400
|
// 运行时事件管理 – incremental DOM, no renderMessages
|
|
6190
6401
|
_addRuntimeEvent(msgId, event) {
|
|
6191
6402
|
const idx = this._messages.findIndex(m => m.id === msgId);
|
|
@@ -6280,6 +6491,30 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6280
6491
|
panel.appendChild(eventsContainer);
|
|
6281
6492
|
return panel;
|
|
6282
6493
|
}
|
|
6494
|
+
|
|
6495
|
+
// P4: 获取自定义操作按钮列表(缓存结果避免重复调用 onMessageActions)
|
|
6496
|
+
_getCustomActions(msg, idx) {
|
|
6497
|
+
const key = '_customActions_' + idx;
|
|
6498
|
+
if (!msg[key] && typeof this._config?.onMessageActions === 'function') {
|
|
6499
|
+
try {
|
|
6500
|
+
msg[key] = this._config.onMessageActions(msg, idx) || [];
|
|
6501
|
+
} catch (e) {
|
|
6502
|
+
console.warn('[AIChatDialog] onMessageActions 执行失败:', e);
|
|
6503
|
+
msg[key] = [];
|
|
6504
|
+
}
|
|
6505
|
+
}
|
|
6506
|
+
return msg[key] || [];
|
|
6507
|
+
}
|
|
6508
|
+
|
|
6509
|
+
// P4: 生成自定义操作按钮 HTML
|
|
6510
|
+
_buildCustomActions(msg, idx) {
|
|
6511
|
+
const actions = this._getCustomActions(msg, idx);
|
|
6512
|
+
if (!actions.length) return '';
|
|
6513
|
+
return actions.map((a, i) => {
|
|
6514
|
+
const cls = a.className || '';
|
|
6515
|
+
return '<span class="action-icon custom-action-btn' + (cls ? ' ' + this.escapeAttr(cls) : '') + '" data-idx="' + idx + '" data-action="' + i + '" title="' + this.escapeAttr(a.label) + '">' + this.escapeHtml(a.label) + '</span>';
|
|
6516
|
+
}).join('');
|
|
6517
|
+
}
|
|
6283
6518
|
_buildRuntimePanel(msg, msgIdx) {
|
|
6284
6519
|
const events = msg._runtimeEvents || [];
|
|
6285
6520
|
if (events.length === 0) return '';
|
|
@@ -6316,7 +6551,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6316
6551
|
// ==================== 重新生成(与Vue regenerate 一致) ====================
|
|
6317
6552
|
|
|
6318
6553
|
async regenerate(index) {
|
|
6319
|
-
if (this._isLoading) return;
|
|
6554
|
+
if (this._isLoading || this._streaming) return;
|
|
6320
6555
|
const aiMessage = this._messages[index];
|
|
6321
6556
|
if (!aiMessage || aiMessage.type !== 'ai') return;
|
|
6322
6557
|
let userQuestion = '';
|
|
@@ -6504,6 +6739,20 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6504
6739
|
const n = new Date();
|
|
6505
6740
|
return `${String(n.getHours()).padStart(2, '0')}:${String(n.getMinutes()).padStart(2, '0')}`;
|
|
6506
6741
|
}
|
|
6742
|
+
|
|
6743
|
+
/**
|
|
6744
|
+
* 调试日志(仅在 config.debug === true 时输出)
|
|
6745
|
+
*/
|
|
6746
|
+
_debugLog(tag, ...args) {
|
|
6747
|
+
if (this._config?.debug) {
|
|
6748
|
+
console.log('%c[AI-SDK]%c ' + tag, 'color:#2563eb;font-weight:600', 'color:inherit', ...args);
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
_debugWarn(tag, ...args) {
|
|
6752
|
+
if (this._config?.debug) {
|
|
6753
|
+
console.warn('%c[AI-SDK]%c ' + tag, 'color:#f59e0b;font-weight:600', 'color:inherit', ...args);
|
|
6754
|
+
}
|
|
6755
|
+
}
|
|
6507
6756
|
escapeHtml(s) {
|
|
6508
6757
|
if (!s) return '';
|
|
6509
6758
|
const d = document.createElement('div');
|
|
@@ -6594,7 +6843,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6594
6843
|
* 支持任意前端框架:Vue, React, Angular, 原生HTML等
|
|
6595
6844
|
*
|
|
6596
6845
|
* @author IBC AI Team
|
|
6597
|
-
* @version 2.0.
|
|
6846
|
+
* @version 2.0.5
|
|
6598
6847
|
*/
|
|
6599
6848
|
|
|
6600
6849
|
|
|
@@ -6811,12 +7060,10 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6811
7060
|
},
|
|
6812
7061
|
sendMessage: content => {
|
|
6813
7062
|
if (dialogRef.current) {
|
|
6814
|
-
const input = dialogRef.current.shadowRoot?.querySelector('.
|
|
7063
|
+
const input = dialogRef.current.shadowRoot?.querySelector('.message-input');
|
|
6815
7064
|
if (input) {
|
|
6816
|
-
input.value = content;
|
|
6817
|
-
input.dispatchEvent(new Event('input'));
|
|
7065
|
+
dialogRef.current.send?.(content) || (input.value = content, input.dispatchEvent(new Event('input')), dialogRef.current.shadowRoot?.querySelector('.send-btn')?.click());
|
|
6818
7066
|
}
|
|
6819
|
-
dialogRef.current.handleSend?.() || dialogRef.current.shadowRoot?.querySelector('.ai-send-btn')?.click();
|
|
6820
7067
|
}
|
|
6821
7068
|
},
|
|
6822
7069
|
clearMessages: () => {
|
|
@@ -6837,14 +7084,14 @@ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error
|
|
|
6837
7084
|
createAIChatDialog,
|
|
6838
7085
|
installVuePlugin,
|
|
6839
7086
|
useAIChat,
|
|
6840
|
-
version: '2.0.
|
|
7087
|
+
version: '2.0.5'
|
|
6841
7088
|
};
|
|
6842
7089
|
|
|
6843
7090
|
// 全局暴露(UMD/浏览器环境)
|
|
6844
7091
|
if (typeof window !== 'undefined') {
|
|
6845
7092
|
window.AICreateChatDialog = createAIChatDialog;
|
|
6846
7093
|
window.AIWebSDK = {
|
|
6847
|
-
version: '2.0.
|
|
7094
|
+
version: '2.0.5',
|
|
6848
7095
|
create: createAIChatDialog,
|
|
6849
7096
|
AIChatDialog,
|
|
6850
7097
|
AIChatClient,
|