@yfwu2020/dsh-selection-explain 0.10.6 → 0.11.1
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/README.md +13 -3
- package/lib/client.js +728 -19
- package/lib/client.js.map +3 -3
- package/lib/host/analyze.js +130 -15
- package/lib/host/analyze.js.map +1 -1
- package/lib/host/attach.js +254 -0
- package/lib/host/attach.js.map +1 -0
- package/lib/host/history-attachments.js +184 -0
- package/lib/host/history-attachments.js.map +1 -0
- package/lib/host/history-store.js +45 -14
- package/lib/host/history-store.js.map +1 -1
- package/lib/host/http.js +7 -0
- package/lib/host/http.js.map +1 -1
- package/lib/host/mic.js +51 -6
- package/lib/host/mic.js.map +1 -1
- package/lib/host/plugin.js +5 -0
- package/lib/host/plugin.js.map +1 -1
- package/lib/host/promote.js +65 -13
- package/lib/host/promote.js.map +1 -1
- package/lib/host/tools.js +28 -0
- package/lib/host/tools.js.map +1 -1
- package/lib/types/host/attach.d.ts +77 -0
- package/lib/types/host/history-attachments.d.ts +108 -0
- package/lib/types/host/http.d.ts +7 -0
- package/lib/types/host/tools.d.ts +21 -0
- package/lib/types/host/types.d.ts +7 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -117,6 +117,10 @@ var PILL_POS = "/selection-explain/api/pill";
|
|
|
117
117
|
var PANEL_SIZE = "/selection-explain/api/panel";
|
|
118
118
|
var HISTORY = "/selection-explain/api/history";
|
|
119
119
|
var MODELS = "/selection-explain/api/models";
|
|
120
|
+
var ATTACH = "/selection-explain/api/attach";
|
|
121
|
+
var ATTACHMENT = "/selection-explain/api/attachment";
|
|
122
|
+
var ATTACH_MAX_ITEMS = 10;
|
|
123
|
+
var ATTACH_MAX_ITEM_BYTES = 20 * 1024 * 1024;
|
|
120
124
|
var SETTINGS = "/selection-explain/api/settings";
|
|
121
125
|
var ROUTE = "/selection-explain/api/route";
|
|
122
126
|
var SPEECH_API = "/selection-explain/api/speech";
|
|
@@ -441,12 +445,97 @@ var CSS = [
|
|
|
441
445
|
"background:transparent;color:var(--dsw-alias-label-secondary,inherit);opacity:.5;font:inherit;font-size:11px;",
|
|
442
446
|
"line-height:1;display:inline-flex;align-items:center;justify-content:center}",
|
|
443
447
|
".dsh-sel-quotechip-x:hover{opacity:1;background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.16))}",
|
|
448
|
+
// ── 附件(composer 第一行,和引用同栏)──
|
|
449
|
+
// 引用是竖着排的卡片(有出处 + 一段文字),附件是横着一排的缩略图 —— 两种形状,
|
|
450
|
+
// 所以是**两条独立的条**、共用 ask 的第一行区域,而不是把附件塞进引用卡片里。
|
|
451
|
+
// 横向溢出就滚动(附件最多 10 件,小窗宽度装不下是常态),滚动条藏起来不占高度。
|
|
452
|
+
".dsh-sel-attach{display:none;flex-direction:row;align-items:center;gap:6px;overflow-x:auto;overflow-y:hidden;",
|
|
453
|
+
"scrollbar-width:none;padding:1px 0 0}",
|
|
454
|
+
'.dsh-sel-attach[data-show="1"]{display:flex}',
|
|
455
|
+
".dsh-sel-attach::-webkit-scrollbar{width:0;height:0;display:none}",
|
|
456
|
+
// 40px 见方:比主会话的 64px 小一圈(小窗的 composer 整体是收着的:按钮 26、输入 13px)
|
|
457
|
+
".dsh-sel-thumb{position:relative;flex:0 0 auto;width:40px;height:40px;border-radius:9px;overflow:hidden;",
|
|
458
|
+
"border:1px solid var(--dsw-alias-border-l3,rgba(140,140,140,.35));background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.14));",
|
|
459
|
+
"display:grid;place-items:center;color:var(--dsw-alias-label-secondary,inherit)}",
|
|
460
|
+
".dsh-sel-thumb img{width:100%;height:100%;object-fit:cover;display:block}",
|
|
461
|
+
".dsh-sel-thumb svg{width:15px;height:15px;opacity:.55}",
|
|
462
|
+
'.dsh-sel-thumb[data-state="error"]{border-color:color-mix(in srgb,var(--sel-bad,#e5534b) 70%,transparent)}',
|
|
463
|
+
'.dsh-sel-thumb[data-state="error"] svg{opacity:.9;color:var(--sel-bad,#e5534b)}',
|
|
464
|
+
// 转圈 + 不定态进度条:fetch 拿不到上传进度,所以**不假装知道百分比**
|
|
465
|
+
// (主会话在"首次报告字节之前"用的也是不定态)
|
|
466
|
+
".dsh-sel-attachspin{position:absolute;inset:0;display:grid;place-items:center;background:rgba(0,0,0,.42)}",
|
|
467
|
+
".dsh-sel-attachspin svg{width:16px;height:16px;opacity:1;color:var(--sel-a1,#0d9488);animation:dsh-sel-spin .9s linear infinite}",
|
|
468
|
+
".dsh-sel-attachbar{position:absolute;left:0;right:0;bottom:0;height:3px;background:rgba(140,140,140,.35);overflow:hidden}",
|
|
469
|
+
".dsh-sel-attachbar i{display:block;height:100%;width:38%;background:var(--sel-a1,#0d9488);animation:dsh-sel-indeterminate 1.1s ease-in-out infinite}",
|
|
470
|
+
"@keyframes dsh-sel-indeterminate{0%{transform:translateX(-100%)}100%{transform:translateX(280%)}}",
|
|
471
|
+
// 移除:缩略图/文件卡右上角。**常驻可见**(触摸设备上没有 hover,藏起来就删不掉了)
|
|
472
|
+
// 兜底色必须是**中性灰 + 白字**:主题变量缺席时(非 DSH 宿主 / 测试页)
|
|
473
|
+
// 原来的 `bg-layer-2 → #3a3f46` 配 `label-primary → CanvasText`(浅色方案下是黑)
|
|
474
|
+
// 会画成"深底黑叉",实拍就是一坨看不出是什么的黑点。
|
|
475
|
+
".dsh-sel-attachx{position:absolute;top:-5px;right:-5px;width:15px;height:15px;padding:0;border-radius:50%;",
|
|
476
|
+
"border:1px solid var(--dsw-alias-bg-layer-1,Canvas);background:var(--dsw-alias-bg-layer-2,rgba(120,120,120,.92));",
|
|
477
|
+
"color:var(--dsw-alias-label-primary,#fff);font:inherit;font-size:9px;line-height:1;cursor:pointer;",
|
|
478
|
+
"display:grid;place-items:center;opacity:.85}",
|
|
479
|
+
".dsh-sel-attachx:hover{opacity:1}",
|
|
480
|
+
// 文件卡:和缩略图同高(40px),名字一行、扩展名 + 字节数一行小字
|
|
481
|
+
".dsh-sel-fcard{position:relative;display:inline-flex;align-items:center;gap:7px;flex:0 0 auto;height:40px;",
|
|
482
|
+
"padding:0 7px 0 6px;border-radius:9px;border:1px solid var(--dsw-alias-border-l3,rgba(140,140,140,.35));",
|
|
483
|
+
"background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.1));font-size:11.5px;line-height:1.35}",
|
|
484
|
+
'.dsh-sel-fcard[data-state="error"]{border-color:color-mix(in srgb,var(--sel-bad,#e5534b) 70%,transparent)}',
|
|
485
|
+
".dsh-sel-fico{flex:0 0 auto;width:22px;height:22px;border-radius:6px;display:grid;place-items:center;",
|
|
486
|
+
"background:linear-gradient(160deg,#3f6ee0,#7aa2ff);color:#fff}",
|
|
487
|
+
".dsh-sel-fico svg{width:13px;height:13px;opacity:1}",
|
|
488
|
+
".dsh-sel-fname{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
489
|
+
".dsh-sel-fmeta{font-size:10.5px;opacity:.6;letter-spacing:.3px;white-space:nowrap}",
|
|
490
|
+
".dsh-sel-fretry{flex:0 0 auto;height:16px;padding:0 6px;border-radius:8px;cursor:pointer;font:inherit;font-size:10.5px;",
|
|
491
|
+
"line-height:14px;color:var(--sel-bad,#e5534b);border:1px solid color-mix(in srgb,var(--sel-bad,#e5534b) 50%,transparent);",
|
|
492
|
+
"background:transparent}",
|
|
493
|
+
".dsh-sel-fretry:hover{background:color-mix(in srgb,var(--sel-bad,#e5534b) 12%,transparent)}",
|
|
494
|
+
// 附件出错时的说明行(贴在附件条下面,一行小字)
|
|
495
|
+
".dsh-sel-attachnote{display:none;margin:0;padding:0 2px;font-size:11px;line-height:1.6;color:var(--sel-warn-fg,#b45309)}",
|
|
496
|
+
'.dsh-sel-attachnote[data-show="1"]{display:block}',
|
|
497
|
+
// + 入口:圆形浅底(和主会话 composer 的 + 同款),放在工具行**最左**
|
|
498
|
+
".dsh-sel-add{background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.14));color:var(--dsw-alias-label-primary,CanvasText)}",
|
|
499
|
+
".dsh-sel-add:hover{background:var(--dsw-alias-interactive-bg-active,rgba(140,140,140,.22))}",
|
|
500
|
+
'.dsh-sel-add[data-busy="1"]{opacity:.6}',
|
|
501
|
+
// 拖放遮罩:铺满面板(面板本身 overflow:hidden,所以内缩 6px 的圆角块正好贴住内容区)
|
|
502
|
+
".dsh-sel-drop{position:absolute;inset:6px;z-index:9;display:none;flex-direction:column;align-items:center;",
|
|
503
|
+
"justify-content:center;gap:9px;border:2px dashed var(--sel-a1,#0d9488);border-radius:13px;",
|
|
504
|
+
"background:color-mix(in srgb,var(--dsw-alias-bg-layer-1,Canvas) 88%,transparent);pointer-events:none}",
|
|
505
|
+
'.dsh-sel-panel[data-dropping="1"] .dsh-sel-drop{display:flex}',
|
|
506
|
+
".dsh-sel-drop-art{width:52px;height:52px;border-radius:14px;display:grid;place-items:center;",
|
|
507
|
+
"background:var(--sel-a1-soft);color:var(--sel-a1,#0d9488)}",
|
|
508
|
+
".dsh-sel-drop-art svg{width:25px;height:25px}",
|
|
509
|
+
".dsh-sel-drop-title{font-size:14px;font-weight:600}",
|
|
510
|
+
".dsh-sel-drop-hint{font-size:11.5px;opacity:.7}",
|
|
444
511
|
// 气泡里的引用块(用户消息):引用在上、问题在下 —— 和发出去给模型的那份顺序一致
|
|
445
512
|
".dsh-sel-bq{display:flex;flex-direction:column;gap:3px;margin-bottom:6px}",
|
|
446
513
|
".dsh-sel-bqitem{padding:3px 8px;border-radius:8px;border-left:2px solid color-mix(in srgb,var(--sel-a1,#0d9488) 45%,transparent);",
|
|
447
514
|
"background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.14));font-size:11.5px;line-height:1.55;",
|
|
448
515
|
"opacity:.82;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
449
516
|
".dsh-sel-bqitem b{font-weight:600;opacity:.75;margin-right:5px}",
|
|
517
|
+
// 气泡里的附件:图片是缩略图(点开原图),文件是一张卡(点一下下载)。
|
|
518
|
+
// 和输入框上面那条 rail 是**同一个东西的两个阶段**(发送前 / 发送后),
|
|
519
|
+
// 所以尺寸、圆角、配色都对齐:缩略图 40px、文件卡同高。
|
|
520
|
+
".dsh-sel-bqattach{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}",
|
|
521
|
+
// ⚠️ flex:0 0 auto 会让这个盒子的宽度由**图片自己**撑出来,于是图片上的 max-width:100%
|
|
522
|
+
// 变成"相对于自己"(循环引用)→ 一张 810px 宽的图会照原样渲染并溢出气泡(实测量到 810x180)。
|
|
523
|
+
// 必须允许它收缩(flex:0 1 auto + min-width:0),百分比才有一个确定的参照。
|
|
524
|
+
".dsh-sel-bqimgwrap{flex:0 1 auto;min-width:0;max-width:100%;display:block;border-radius:9px;overflow:hidden;line-height:0;",
|
|
525
|
+
"border:1px solid var(--dsw-alias-border-l3,rgba(140,140,140,.35))}",
|
|
526
|
+
// 上限 180px 高、最宽占满气泡:小窗本来就窄,缩略图不能把气泡撑爆
|
|
527
|
+
".dsh-sel-bqimg{display:block;max-width:100%;max-height:180px;width:auto;height:auto;border-radius:8px;cursor:zoom-in}",
|
|
528
|
+
".dsh-sel-bqimgfail{display:inline-block;padding:5px 9px;border-radius:8px;font-size:11.5px;opacity:.7;",
|
|
529
|
+
"background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.14))}",
|
|
530
|
+
".dsh-sel-bqfile{display:inline-flex;align-items:center;gap:7px;max-width:100%;padding:5px 9px;border-radius:9px;",
|
|
531
|
+
"text-decoration:none;color:inherit;cursor:pointer;font-size:11.5px;line-height:1.35;",
|
|
532
|
+
"border:1px solid var(--dsw-alias-border-l3,rgba(140,140,140,.35));",
|
|
533
|
+
"background:var(--dsw-alias-interactive-bg-hover,rgba(140,140,140,.1))}",
|
|
534
|
+
".dsh-sel-bqfile:hover{border-color:color-mix(in srgb,var(--sel-a1,#0d9488) 45%,transparent)}",
|
|
535
|
+
".dsh-sel-bqfileext{flex:0 0 auto;font-size:9.5px;font-weight:700;letter-spacing:.4px;padding:0 5px;",
|
|
536
|
+
"border-radius:5px;line-height:15px;background:var(--sel-fill,#0f766e);color:var(--sel-fill-fg,#fff)}",
|
|
537
|
+
".dsh-sel-bqfilename{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:190px}",
|
|
538
|
+
".dsh-sel-bqfilemeta{flex:0 0 auto;font-size:10.5px;opacity:.6}",
|
|
450
539
|
// 「引用整条」:贴在助手气泡末尾,**平时不出现**(正文优先),鼠标移到这条消息上才浮出来。
|
|
451
540
|
// 键盘 Tab 也能到(:focus-visible 同样点亮),触屏上另有浮标那条路。
|
|
452
541
|
".dsh-sel-bubquote{margin-top:7px;display:inline-flex;align-items:center;gap:4px;padding:2px 9px;",
|
|
@@ -1128,6 +1217,21 @@ function micIcon() {
|
|
|
1128
1217
|
svg.appendChild(stem);
|
|
1129
1218
|
return svg;
|
|
1130
1219
|
}
|
|
1220
|
+
function spinnerIcon() {
|
|
1221
|
+
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
1222
|
+
svg.setAttribute("viewBox", "0 0 16 16");
|
|
1223
|
+
svg.setAttribute("width", "14");
|
|
1224
|
+
svg.setAttribute("height", "14");
|
|
1225
|
+
svg.setAttribute("fill", "none");
|
|
1226
|
+
svg.setAttribute("stroke", "currentColor");
|
|
1227
|
+
svg.setAttribute("stroke-width", "1.7");
|
|
1228
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
1229
|
+
svg.setAttribute("aria-hidden", "true");
|
|
1230
|
+
var arc = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1231
|
+
arc.setAttribute("d", "M8 1.8a6.2 6.2 0 1 1-4.4 1.8");
|
|
1232
|
+
svg.appendChild(arc);
|
|
1233
|
+
return svg;
|
|
1234
|
+
}
|
|
1131
1235
|
function sendIcon() {
|
|
1132
1236
|
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
1133
1237
|
svg.setAttribute("viewBox", "0 0 16 16");
|
|
@@ -1178,6 +1282,34 @@ function quoteIcon() {
|
|
|
1178
1282
|
}
|
|
1179
1283
|
return svg;
|
|
1180
1284
|
}
|
|
1285
|
+
function plusIcon() {
|
|
1286
|
+
var svg = iconCanvas(14);
|
|
1287
|
+
iconPath(svg, "M8 3.4v9.2M3.4 8h9.2");
|
|
1288
|
+
return svg;
|
|
1289
|
+
}
|
|
1290
|
+
function docIcon() {
|
|
1291
|
+
var svg = iconCanvas(14);
|
|
1292
|
+
iconPath(svg, "M4.3 1.9h4.4l3 3v9.2H4.3z");
|
|
1293
|
+
iconPath(svg, "M8.5 1.9v3.2h3.2");
|
|
1294
|
+
return svg;
|
|
1295
|
+
}
|
|
1296
|
+
function imageIcon() {
|
|
1297
|
+
var svg = iconCanvas(14);
|
|
1298
|
+
iconPath(svg, "M2.6 3.2h10.8v9.6H2.6z");
|
|
1299
|
+
var dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
1300
|
+
dot.setAttribute("cx", "5.7");
|
|
1301
|
+
dot.setAttribute("cy", "6.3");
|
|
1302
|
+
dot.setAttribute("r", "0.9");
|
|
1303
|
+
svg.appendChild(dot);
|
|
1304
|
+
iconPath(svg, "M2.6 10.9l3.1-2.9 2.5 2.3 2.3-2.1 2.9 2.7");
|
|
1305
|
+
return svg;
|
|
1306
|
+
}
|
|
1307
|
+
function retryIcon() {
|
|
1308
|
+
var svg = iconCanvas(13);
|
|
1309
|
+
iconPath(svg, "M12.6 8a4.6 4.6 0 1 1-1.6-3.5");
|
|
1310
|
+
iconPath(svg, "M12.9 2.6v3.1h-3.1");
|
|
1311
|
+
return svg;
|
|
1312
|
+
}
|
|
1181
1313
|
|
|
1182
1314
|
// src/client/index.js
|
|
1183
1315
|
var import_react = __toESM(require("react"), 1);
|
|
@@ -3935,7 +4067,12 @@ function createQuotesController(env) {
|
|
|
3935
4067
|
function exportTurns() {
|
|
3936
4068
|
var out = [];
|
|
3937
4069
|
for (var i = 0; i < env.state.turns.length; i += 1) {
|
|
3938
|
-
|
|
4070
|
+
var turn = env.state.turns[i];
|
|
4071
|
+
out.push({
|
|
4072
|
+
role: turn.role,
|
|
4073
|
+
text: sentTextOf(turn),
|
|
4074
|
+
...turn.attachments && turn.attachments.length > 0 ? { attachments: turn.attachments } : {}
|
|
4075
|
+
});
|
|
3939
4076
|
}
|
|
3940
4077
|
return out;
|
|
3941
4078
|
}
|
|
@@ -3954,6 +4091,383 @@ function createQuotesController(env) {
|
|
|
3954
4091
|
};
|
|
3955
4092
|
}
|
|
3956
4093
|
|
|
4094
|
+
// src/client/attach.js
|
|
4095
|
+
function encodeAttachmentRef(ref) {
|
|
4096
|
+
var json = JSON.stringify(ref || {});
|
|
4097
|
+
if (typeof TextEncoder === "function") {
|
|
4098
|
+
var bytes = new TextEncoder().encode(json);
|
|
4099
|
+
var binary = "";
|
|
4100
|
+
for (var i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i]);
|
|
4101
|
+
json = binary;
|
|
4102
|
+
}
|
|
4103
|
+
return btoa(json).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
4104
|
+
}
|
|
4105
|
+
function attachmentUrl(kind, ref, download) {
|
|
4106
|
+
return ATTACHMENT + "?kind=" + (kind === "file" ? "file" : "image") + "&ref=" + encodeAttachmentRef(ref) + (download ? "&download=1" : "");
|
|
4107
|
+
}
|
|
4108
|
+
function formatBytes(bytes) {
|
|
4109
|
+
var value = typeof bytes === "number" && isFinite(bytes) ? bytes : 0;
|
|
4110
|
+
if (value < 1024) return value + " B";
|
|
4111
|
+
if (value < 1024 * 1024) return (value / 1024).toFixed(1) + " KB";
|
|
4112
|
+
return (value / 1024 / 1024).toFixed(1) + " MB";
|
|
4113
|
+
}
|
|
4114
|
+
function extensionOf(name) {
|
|
4115
|
+
var match = /\.([A-Za-z0-9]+)$/.exec(String(name || ""));
|
|
4116
|
+
return match ? match[1].toUpperCase() : "FILE";
|
|
4117
|
+
}
|
|
4118
|
+
function fileToBase64(file) {
|
|
4119
|
+
return new Promise(function(resolve, reject) {
|
|
4120
|
+
var reader = new FileReader();
|
|
4121
|
+
reader.onload = function() {
|
|
4122
|
+
var result = String(reader.result || "");
|
|
4123
|
+
var comma = result.indexOf(",");
|
|
4124
|
+
resolve(comma >= 0 ? result.slice(comma + 1) : "");
|
|
4125
|
+
};
|
|
4126
|
+
reader.onerror = function() {
|
|
4127
|
+
reject(reader.error || new Error("\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25"));
|
|
4128
|
+
};
|
|
4129
|
+
reader.readAsDataURL(file);
|
|
4130
|
+
});
|
|
4131
|
+
}
|
|
4132
|
+
function looksLikeDirectory(file) {
|
|
4133
|
+
return file && file.size === 0 && !file.type && !/\.[A-Za-z0-9]+$/.test(String(file.name || ""));
|
|
4134
|
+
}
|
|
4135
|
+
function createAttachController(env) {
|
|
4136
|
+
var seq = 0;
|
|
4137
|
+
function items() {
|
|
4138
|
+
return env.state.attachments;
|
|
4139
|
+
}
|
|
4140
|
+
function note(text) {
|
|
4141
|
+
env.state.attachNote = text || "";
|
|
4142
|
+
renderNote();
|
|
4143
|
+
}
|
|
4144
|
+
function renderNote() {
|
|
4145
|
+
if (!env.attachNote) return;
|
|
4146
|
+
env.attachNote.textContent = env.state.attachNote || "";
|
|
4147
|
+
env.attachNote.setAttribute("data-show", env.state.attachNote ? "1" : "0");
|
|
4148
|
+
}
|
|
4149
|
+
function busy() {
|
|
4150
|
+
var list = items();
|
|
4151
|
+
for (var i = 0; i < list.length; i += 1) if (list[i].status === "uploading") return true;
|
|
4152
|
+
return false;
|
|
4153
|
+
}
|
|
4154
|
+
function payload() {
|
|
4155
|
+
var out = [];
|
|
4156
|
+
var list = items();
|
|
4157
|
+
for (var i = 0; i < list.length; i += 1) {
|
|
4158
|
+
if (list[i].status === "done" && list[i].ref) out.push({ kind: list[i].kind, ref: list[i].ref });
|
|
4159
|
+
}
|
|
4160
|
+
return out;
|
|
4161
|
+
}
|
|
4162
|
+
function describe(explicit) {
|
|
4163
|
+
var list = explicit || items();
|
|
4164
|
+
var names = [];
|
|
4165
|
+
for (var i = 0; i < list.length; i += 1) {
|
|
4166
|
+
if (list[i].status !== "done" || !list[i].ref) continue;
|
|
4167
|
+
names.push(list[i].name + (list[i].kind === "image" ? "\uFF08\u56FE\u7247\uFF09" : "\uFF08\u6587\u4EF6\uFF09"));
|
|
4168
|
+
}
|
|
4169
|
+
if (names.length === 0) return "";
|
|
4170
|
+
return "\u3010\u672C\u6761\u6D88\u606F\u5E26\u4E86\u9644\u4EF6\u3011" + names.join("\u3001");
|
|
4171
|
+
}
|
|
4172
|
+
function clear() {
|
|
4173
|
+
var list = items();
|
|
4174
|
+
for (var i = 0; i < list.length; i += 1) revoke(list[i]);
|
|
4175
|
+
env.state.attachments = [];
|
|
4176
|
+
env.state.attachNote = "";
|
|
4177
|
+
render();
|
|
4178
|
+
}
|
|
4179
|
+
function revoke(item) {
|
|
4180
|
+
if (item && item.url && typeof URL !== "undefined" && URL.revokeObjectURL) {
|
|
4181
|
+
try {
|
|
4182
|
+
URL.revokeObjectURL(item.url);
|
|
4183
|
+
} catch (error) {
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
function remove(id) {
|
|
4188
|
+
var list = items();
|
|
4189
|
+
for (var i = 0; i < list.length; i += 1) {
|
|
4190
|
+
if (list[i].id === id) {
|
|
4191
|
+
revoke(list[i]);
|
|
4192
|
+
list.splice(i, 1);
|
|
4193
|
+
break;
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
env.state.attachNote = "";
|
|
4197
|
+
render();
|
|
4198
|
+
env.refreshAskState();
|
|
4199
|
+
}
|
|
4200
|
+
function addFiles(files) {
|
|
4201
|
+
var list = items();
|
|
4202
|
+
var incoming = [];
|
|
4203
|
+
for (var i = 0; i < files.length; i += 1) incoming.push(files[i]);
|
|
4204
|
+
if (incoming.length === 0) return;
|
|
4205
|
+
var rejected = [];
|
|
4206
|
+
for (var j = 0; j < incoming.length; j += 1) {
|
|
4207
|
+
var file = incoming[j];
|
|
4208
|
+
if (looksLikeDirectory(file)) {
|
|
4209
|
+
rejected.push("\u300C" + (file.name || "\u672A\u547D\u540D") + "\u300D\u662F\u6587\u4EF6\u5939\uFF0C\u4E0D\u652F\u6301");
|
|
4210
|
+
continue;
|
|
4211
|
+
}
|
|
4212
|
+
if (list.length >= ATTACH_MAX_ITEMS) {
|
|
4213
|
+
rejected.push("\u4E00\u6B21\u6700\u591A\u5E26 " + ATTACH_MAX_ITEMS + " \u4EF6\u9644\u4EF6");
|
|
4214
|
+
break;
|
|
4215
|
+
}
|
|
4216
|
+
if (file.size > ATTACH_MAX_ITEM_BYTES) {
|
|
4217
|
+
rejected.push("\u300C" + file.name + "\u300D\u8D85\u8FC7\u5355\u4EF6\u4E0A\u9650 " + formatBytes(ATTACH_MAX_ITEM_BYTES));
|
|
4218
|
+
continue;
|
|
4219
|
+
}
|
|
4220
|
+
list.push(createItem(file));
|
|
4221
|
+
}
|
|
4222
|
+
note(rejected.join("\uFF1B"));
|
|
4223
|
+
render();
|
|
4224
|
+
env.refreshAskState();
|
|
4225
|
+
var pending = list.filter(function(item) {
|
|
4226
|
+
return item.status === "uploading" && !item.started;
|
|
4227
|
+
});
|
|
4228
|
+
var chain = Promise.resolve();
|
|
4229
|
+
pending.forEach(function(item) {
|
|
4230
|
+
chain = chain.then(function() {
|
|
4231
|
+
return upload(item);
|
|
4232
|
+
});
|
|
4233
|
+
});
|
|
4234
|
+
}
|
|
4235
|
+
function createItem(file) {
|
|
4236
|
+
var isImage = /^image\//.test(String(file.type || ""));
|
|
4237
|
+
var item = {
|
|
4238
|
+
id: ++seq,
|
|
4239
|
+
kind: isImage ? "image" : "file",
|
|
4240
|
+
name: file.name || (isImage ? "\u7C98\u8D34\u7684\u56FE\u7247" : "\u672A\u547D\u540D\u6587\u4EF6"),
|
|
4241
|
+
size: typeof file.size === "number" ? file.size : 0,
|
|
4242
|
+
mediaType: file.type || "application/octet-stream",
|
|
4243
|
+
file,
|
|
4244
|
+
// 缩略图先用本地 object URL 显示(不必等上传完),失败时回落到图标
|
|
4245
|
+
url: isImage && typeof URL !== "undefined" && URL.createObjectURL ? URL.createObjectURL(file) : "",
|
|
4246
|
+
status: "uploading",
|
|
4247
|
+
started: false,
|
|
4248
|
+
ref: null,
|
|
4249
|
+
error: ""
|
|
4250
|
+
};
|
|
4251
|
+
return item;
|
|
4252
|
+
}
|
|
4253
|
+
function upload(item) {
|
|
4254
|
+
if (item.started) return Promise.resolve();
|
|
4255
|
+
item.started = true;
|
|
4256
|
+
item.status = "uploading";
|
|
4257
|
+
item.error = "";
|
|
4258
|
+
render();
|
|
4259
|
+
return fileToBase64(item.file).then(function(data) {
|
|
4260
|
+
return fetch(ATTACH, {
|
|
4261
|
+
method: "POST",
|
|
4262
|
+
headers: { "content-type": "application/json" },
|
|
4263
|
+
body: JSON.stringify({
|
|
4264
|
+
items: [{ kind: item.kind, name: item.name, mediaType: item.mediaType, data }]
|
|
4265
|
+
})
|
|
4266
|
+
});
|
|
4267
|
+
}).then(function(response) {
|
|
4268
|
+
return response.json().catch(function() {
|
|
4269
|
+
return {};
|
|
4270
|
+
}).then(function(body) {
|
|
4271
|
+
if (!response.ok || !body || body.ok !== true) {
|
|
4272
|
+
throw new Error(body && body.error || "HTTP " + response.status);
|
|
4273
|
+
}
|
|
4274
|
+
var first = body.items && body.items[0];
|
|
4275
|
+
if (!first || !first.ref) throw new Error("\u4E0A\u4F20\u540E\u6CA1\u6709\u62FF\u5230\u9644\u4EF6\u5F15\u7528");
|
|
4276
|
+
item.ref = first.ref;
|
|
4277
|
+
item.status = "done";
|
|
4278
|
+
item.file = null;
|
|
4279
|
+
if (first.ref.name) item.name = String(first.ref.name);
|
|
4280
|
+
if (typeof first.ref.bytes === "number") item.size = first.ref.bytes;
|
|
4281
|
+
if (env.state.attachNote.indexOf(item.name) >= 0) note("");
|
|
4282
|
+
});
|
|
4283
|
+
}).catch(function(error) {
|
|
4284
|
+
item.status = "error";
|
|
4285
|
+
item.error = String(error && error.message || error);
|
|
4286
|
+
note("\u300C" + item.name + "\u300D" + item.error);
|
|
4287
|
+
}).then(function() {
|
|
4288
|
+
render();
|
|
4289
|
+
env.refreshAskState();
|
|
4290
|
+
});
|
|
4291
|
+
}
|
|
4292
|
+
function retry(id) {
|
|
4293
|
+
var list = items();
|
|
4294
|
+
for (var i = 0; i < list.length; i += 1) {
|
|
4295
|
+
if (list[i].id === id && list[i].status === "error") {
|
|
4296
|
+
if (!list[i].file) {
|
|
4297
|
+
note("\u8FD9\u4E00\u4EF6\u5DF2\u7ECF\u6CA1\u6CD5\u91CD\u8BD5\u4E86\uFF0C\u8BF7\u91CD\u65B0\u6DFB\u52A0");
|
|
4298
|
+
return;
|
|
4299
|
+
}
|
|
4300
|
+
list[i].started = false;
|
|
4301
|
+
upload(list[i]);
|
|
4302
|
+
return;
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
function render() {
|
|
4307
|
+
var box = env.attachBox;
|
|
4308
|
+
if (!box) return;
|
|
4309
|
+
var list = items();
|
|
4310
|
+
box.textContent = "";
|
|
4311
|
+
box.setAttribute("data-show", list.length > 0 ? "1" : "0");
|
|
4312
|
+
for (var i = 0; i < list.length; i += 1) {
|
|
4313
|
+
box.appendChild(list[i].kind === "image" ? thumbNode(list[i]) : fileNode(list[i]));
|
|
4314
|
+
}
|
|
4315
|
+
renderNote();
|
|
4316
|
+
}
|
|
4317
|
+
function removeButton(item) {
|
|
4318
|
+
var button = el("button", "dsh-sel-attachx", "\u2715");
|
|
4319
|
+
button.type = "button";
|
|
4320
|
+
button.title = "\u79FB\u9664\u300C" + item.name + "\u300D";
|
|
4321
|
+
button.setAttribute("aria-label", "\u79FB\u9664\u9644\u4EF6 " + item.name);
|
|
4322
|
+
listen(button, "click", function(event) {
|
|
4323
|
+
event.stopPropagation();
|
|
4324
|
+
remove(item.id);
|
|
4325
|
+
});
|
|
4326
|
+
return button;
|
|
4327
|
+
}
|
|
4328
|
+
function thumbNode(item) {
|
|
4329
|
+
var node = el("span", "dsh-sel-thumb");
|
|
4330
|
+
node.setAttribute("data-state", item.status);
|
|
4331
|
+
node.title = item.name;
|
|
4332
|
+
if (item.url) {
|
|
4333
|
+
var img = document.createElement("img");
|
|
4334
|
+
img.src = item.url;
|
|
4335
|
+
img.alt = item.name;
|
|
4336
|
+
node.appendChild(img);
|
|
4337
|
+
} else {
|
|
4338
|
+
node.appendChild(imageIcon());
|
|
4339
|
+
}
|
|
4340
|
+
if (item.status === "uploading") {
|
|
4341
|
+
var spin = el("span", "dsh-sel-attachspin");
|
|
4342
|
+
spin.appendChild(spinnerIcon());
|
|
4343
|
+
node.appendChild(spin);
|
|
4344
|
+
var bar = el("span", "dsh-sel-attachbar");
|
|
4345
|
+
bar.appendChild(el("i"));
|
|
4346
|
+
node.appendChild(bar);
|
|
4347
|
+
} else if (item.status === "error") {
|
|
4348
|
+
var retryBox = el("span", "dsh-sel-attachspin");
|
|
4349
|
+
retryBox.style.background = "transparent";
|
|
4350
|
+
retryBox.title = "\u4E0A\u4F20\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5";
|
|
4351
|
+
var retryButton = el("button", "dsh-sel-attachx", "");
|
|
4352
|
+
retryButton.type = "button";
|
|
4353
|
+
retryButton.style.position = "static";
|
|
4354
|
+
retryButton.style.width = "20px";
|
|
4355
|
+
retryButton.style.height = "20px";
|
|
4356
|
+
retryButton.setAttribute("aria-label", "\u91CD\u8BD5\u4E0A\u4F20 " + item.name);
|
|
4357
|
+
retryButton.appendChild(retryIcon());
|
|
4358
|
+
listen(retryButton, "click", function(event) {
|
|
4359
|
+
event.stopPropagation();
|
|
4360
|
+
retry(item.id);
|
|
4361
|
+
});
|
|
4362
|
+
retryBox.appendChild(retryButton);
|
|
4363
|
+
node.appendChild(retryBox);
|
|
4364
|
+
}
|
|
4365
|
+
node.appendChild(removeButton(item));
|
|
4366
|
+
return node;
|
|
4367
|
+
}
|
|
4368
|
+
function fileNode(item) {
|
|
4369
|
+
var node = el("span", "dsh-sel-fcard");
|
|
4370
|
+
node.setAttribute("data-state", item.status);
|
|
4371
|
+
var icon = el("span", "dsh-sel-fico");
|
|
4372
|
+
icon.appendChild(docIcon());
|
|
4373
|
+
node.appendChild(icon);
|
|
4374
|
+
node.appendChild(el("span", "dsh-sel-fname", item.name));
|
|
4375
|
+
var meta = extensionOf(item.name) + " \xB7 " + formatBytes(item.size);
|
|
4376
|
+
if (item.status === "uploading") meta = "\u6B63\u5728\u4E0A\u4F20\u2026";
|
|
4377
|
+
node.appendChild(el("span", "dsh-sel-fmeta", meta));
|
|
4378
|
+
if (item.status === "error") {
|
|
4379
|
+
var retryButton = el("button", "dsh-sel-fretry", "\u91CD\u8BD5");
|
|
4380
|
+
retryButton.type = "button";
|
|
4381
|
+
listen(retryButton, "click", function(event) {
|
|
4382
|
+
event.stopPropagation();
|
|
4383
|
+
retry(item.id);
|
|
4384
|
+
});
|
|
4385
|
+
node.appendChild(retryButton);
|
|
4386
|
+
}
|
|
4387
|
+
node.appendChild(removeButton(item));
|
|
4388
|
+
return node;
|
|
4389
|
+
}
|
|
4390
|
+
function pick() {
|
|
4391
|
+
if (!env.attachInput) return;
|
|
4392
|
+
env.attachInput.value = "";
|
|
4393
|
+
env.attachInput.click();
|
|
4394
|
+
}
|
|
4395
|
+
function handlePaste(event) {
|
|
4396
|
+
var files = event.clipboardData && event.clipboardData.files;
|
|
4397
|
+
if (!files || files.length === 0) return;
|
|
4398
|
+
event.preventDefault();
|
|
4399
|
+
addFiles(files);
|
|
4400
|
+
env.setStatus("\u5DF2\u4ECE\u526A\u8D34\u677F\u6DFB\u52A0 " + files.length + " \u4EF6\u9644\u4EF6");
|
|
4401
|
+
}
|
|
4402
|
+
function isFileDrag(event) {
|
|
4403
|
+
var transfer = event.dataTransfer;
|
|
4404
|
+
if (!transfer) return false;
|
|
4405
|
+
var types = transfer.types;
|
|
4406
|
+
if (!types) return false;
|
|
4407
|
+
for (var i = 0; i < types.length; i += 1) {
|
|
4408
|
+
if (types[i] === "Files") return true;
|
|
4409
|
+
}
|
|
4410
|
+
return false;
|
|
4411
|
+
}
|
|
4412
|
+
function wireDrop() {
|
|
4413
|
+
var depth = 0;
|
|
4414
|
+
var panel = env.panel;
|
|
4415
|
+
if (!panel) return;
|
|
4416
|
+
function show() {
|
|
4417
|
+
panel.setAttribute("data-dropping", "1");
|
|
4418
|
+
}
|
|
4419
|
+
function hide() {
|
|
4420
|
+
depth = 0;
|
|
4421
|
+
panel.removeAttribute("data-dropping");
|
|
4422
|
+
}
|
|
4423
|
+
listen(panel, "dragenter", function(event) {
|
|
4424
|
+
if (!isFileDrag(event)) return;
|
|
4425
|
+
event.preventDefault();
|
|
4426
|
+
event.stopPropagation();
|
|
4427
|
+
depth += 1;
|
|
4428
|
+
show();
|
|
4429
|
+
});
|
|
4430
|
+
listen(panel, "dragover", function(event) {
|
|
4431
|
+
if (!isFileDrag(event)) return;
|
|
4432
|
+
event.preventDefault();
|
|
4433
|
+
event.stopPropagation();
|
|
4434
|
+
if (event.dataTransfer.dropEffect !== void 0) event.dataTransfer.dropEffect = "copy";
|
|
4435
|
+
});
|
|
4436
|
+
listen(panel, "dragleave", function(event) {
|
|
4437
|
+
if (!isFileDrag(event)) return;
|
|
4438
|
+
event.stopPropagation();
|
|
4439
|
+
depth -= 1;
|
|
4440
|
+
if (depth <= 0) hide();
|
|
4441
|
+
});
|
|
4442
|
+
listen(panel, "drop", function(event) {
|
|
4443
|
+
if (!isFileDrag(event)) return;
|
|
4444
|
+
event.preventDefault();
|
|
4445
|
+
event.stopPropagation();
|
|
4446
|
+
hide();
|
|
4447
|
+
var files = event.dataTransfer.files;
|
|
4448
|
+
if (files && files.length > 0) {
|
|
4449
|
+
addFiles(files);
|
|
4450
|
+
env.setStatus("\u5DF2\u6DFB\u52A0 " + files.length + " \u4EF6\u9644\u4EF6");
|
|
4451
|
+
}
|
|
4452
|
+
});
|
|
4453
|
+
}
|
|
4454
|
+
return {
|
|
4455
|
+
items,
|
|
4456
|
+
addFiles,
|
|
4457
|
+
remove,
|
|
4458
|
+
clear,
|
|
4459
|
+
retry,
|
|
4460
|
+
render,
|
|
4461
|
+
busy,
|
|
4462
|
+
payload,
|
|
4463
|
+
describe,
|
|
4464
|
+
note,
|
|
4465
|
+
pick,
|
|
4466
|
+
handlePaste,
|
|
4467
|
+
wireDrop
|
|
4468
|
+
};
|
|
4469
|
+
}
|
|
4470
|
+
|
|
3957
4471
|
// src/client/bridge.js
|
|
3958
4472
|
function bridgeBody() {
|
|
3959
4473
|
if (window.__dshSelBridge) return;
|
|
@@ -4501,7 +5015,7 @@ function createPanelController(env) {
|
|
|
4501
5015
|
env.state.selection = null;
|
|
4502
5016
|
}
|
|
4503
5017
|
function openPanelWithInner(text, context, label, anchor, keyContext, options) {
|
|
4504
|
-
env.state.
|
|
5018
|
+
env.state.skipInterpretation = !!(options && options.askFirst);
|
|
4505
5019
|
env.panelSessionId = currentSessionId();
|
|
4506
5020
|
env.state.payload = buildPayload(text, context, label);
|
|
4507
5021
|
env.state.kind = env.state.payload.kind;
|
|
@@ -4515,6 +5029,7 @@ function createPanelController(env) {
|
|
|
4515
5029
|
env.state.turns = [];
|
|
4516
5030
|
env.state.toolDigest = "";
|
|
4517
5031
|
env.clearQuotes();
|
|
5032
|
+
env.clearAttachments();
|
|
4518
5033
|
env.state.parts = cached && cached.parts || { translation: "", detail: "" };
|
|
4519
5034
|
env.state.stage = "";
|
|
4520
5035
|
env.state.raw = "";
|
|
@@ -4535,6 +5050,7 @@ function createPanelController(env) {
|
|
|
4535
5050
|
}
|
|
4536
5051
|
env.renderTurns();
|
|
4537
5052
|
if (cached) {
|
|
5053
|
+
env.state.skipInterpretation = false;
|
|
4538
5054
|
env.state.turns = (cached.turns || []).slice();
|
|
4539
5055
|
env.state.phase = "done";
|
|
4540
5056
|
env.state.stage = "";
|
|
@@ -4825,7 +5341,7 @@ function createPanelController(env) {
|
|
|
4825
5341
|
for (var i = 0; i < env.state.turns.length; i += 1) {
|
|
4826
5342
|
if (env.state.turns[i].role === "user") asked = true;
|
|
4827
5343
|
}
|
|
4828
|
-
env.expandButton.style.display = !hasDetail && translationReady && !asked && !env.state.
|
|
5344
|
+
env.expandButton.style.display = !hasDetail && translationReady && !asked && !env.state.skipInterpretation ? "" : "none";
|
|
4829
5345
|
env.expandButton.disabled = false;
|
|
4830
5346
|
return asked;
|
|
4831
5347
|
}
|
|
@@ -4845,9 +5361,17 @@ function createPanelController(env) {
|
|
|
4845
5361
|
var stage = env.state.stage;
|
|
4846
5362
|
var selected = env.state.payload && env.state.payload.text ? env.state.payload.text : env.state.selection ? env.state.selection.text : "";
|
|
4847
5363
|
var sections = splitSections(env.visibleRaw());
|
|
4848
|
-
env.translationSection.root.style.display = env.state.voiceAsk ? "none" : "";
|
|
4849
5364
|
var live = stripEchoPrefix(stage === "detail" ? "" : sections.translation || sections.other, selected);
|
|
4850
5365
|
var liveDetail = (sections.detail || sections.other || "").trim();
|
|
5366
|
+
var askedSoFar = false;
|
|
5367
|
+
for (var qi = 0; qi < env.state.turns.length; qi += 1) {
|
|
5368
|
+
if (env.state.turns[qi].role === "user") {
|
|
5369
|
+
askedSoFar = true;
|
|
5370
|
+
break;
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
var emptyInterpretation = !env.state.parts.translation && !env.state.parts.detail && !live.trim();
|
|
5374
|
+
env.translationSection.root.style.display = env.state.skipInterpretation || emptyInterpretation && askedSoFar ? "none" : "";
|
|
4851
5375
|
if (env.state.parts.translation) {
|
|
4852
5376
|
renderRich(env.translationSection.content, stripEchoPrefix(env.state.parts.translation, selected), { callout: true, settled: true });
|
|
4853
5377
|
} else if (stage !== "detail" && live.trim()) {
|
|
@@ -4908,7 +5432,7 @@ function createPanelController(env) {
|
|
|
4908
5432
|
var surfaceTheme = env.currentSurfaceTheme();
|
|
4909
5433
|
env.layer.setAttribute("data-theme", surfaceTheme);
|
|
4910
5434
|
env.panel.setAttribute("data-theme", surfaceTheme);
|
|
4911
|
-
env.askRow.style.display = wide || translationReady || env.state.
|
|
5435
|
+
env.askRow.style.display = wide || translationReady || env.state.skipInterpretation || env.state.quotes.length > 0 ? "" : "none";
|
|
4912
5436
|
syncExpandCta();
|
|
4913
5437
|
env.closeButton.title = "\u5173\u95ED\uFF08Esc\uFF09";
|
|
4914
5438
|
if (env.state.phase !== "error" && env.state.phase !== "paused" && env.retryButton.parentNode) {
|
|
@@ -5962,7 +6486,11 @@ function createHistoryController(env) {
|
|
|
5962
6486
|
parts: env.state.parts,
|
|
5963
6487
|
turns,
|
|
5964
6488
|
toolDigest: env.state.toolDigest,
|
|
5965
|
-
pinned: !!(options && options.pinned)
|
|
6489
|
+
pinned: !!(options && options.pinned),
|
|
6490
|
+
// 这段对话有没有解读,必须跟着条目落盘:回放时靠它决定画不画「翻译」一节。
|
|
6491
|
+
// 不落盘的话,语音卡那条"跳过翻译与详解、直接追问"的对话下次开出来,
|
|
6492
|
+
// 会顶着一张空翻译卡片("这次没有返回内容")——用户实测。
|
|
6493
|
+
skipped: env.state.skipInterpretation === true
|
|
5966
6494
|
})
|
|
5967
6495
|
}).catch(function() {
|
|
5968
6496
|
});
|
|
@@ -5972,6 +6500,16 @@ function createHistoryController(env) {
|
|
|
5972
6500
|
function applyHistoryEntry(entry, source) {
|
|
5973
6501
|
var parts = entry.parts || {};
|
|
5974
6502
|
env.state.parts = { translation: parts.translation || "", detail: parts.detail || "" };
|
|
6503
|
+
var replayTurns = Array.isArray(entry.turns) ? entry.turns : [];
|
|
6504
|
+
var hasAskTurn = false;
|
|
6505
|
+
for (var step = 0; step < replayTurns.length; step += 1) {
|
|
6506
|
+
if (replayTurns[step] && replayTurns[step].role === "user") {
|
|
6507
|
+
hasAskTurn = true;
|
|
6508
|
+
break;
|
|
6509
|
+
}
|
|
6510
|
+
}
|
|
6511
|
+
var noInterpretation = !String(parts.translation || "").trim() && !String(parts.detail || "").trim();
|
|
6512
|
+
env.state.skipInterpretation = entry.skipped === true || entry.skipped === void 0 && noInterpretation && hasAskTurn;
|
|
5975
6513
|
env.state.turns = Array.isArray(entry.turns) ? entry.turns.slice() : [];
|
|
5976
6514
|
env.clearQuotes();
|
|
5977
6515
|
env.state.toolDigest = typeof entry.toolDigest === "string" ? entry.toolDigest : "";
|
|
@@ -6339,7 +6877,9 @@ function createHistoryController(env) {
|
|
|
6339
6877
|
if (turn.role === "user") {
|
|
6340
6878
|
var usig = (turn.text || "") + "|" + (turn.quotes || []).map(function(item) {
|
|
6341
6879
|
return item.text;
|
|
6342
|
-
}).join("\0")
|
|
6880
|
+
}).join("\0") + "|" + (turn.attachments || []).map(function(item) {
|
|
6881
|
+
return (item.kind || "") + ":" + String(item.ref && item.ref.attachmentId || "");
|
|
6882
|
+
}).join(",");
|
|
6343
6883
|
if (node.__sig !== usig) {
|
|
6344
6884
|
node.__sig = usig;
|
|
6345
6885
|
fillUserBubble(node, turn);
|
|
@@ -6393,6 +6933,10 @@ function createHistoryController(env) {
|
|
|
6393
6933
|
function fillUserBubble(node, turn) {
|
|
6394
6934
|
node.textContent = "";
|
|
6395
6935
|
var quotes = turn.quotes || [];
|
|
6936
|
+
var attachments = turn.attachments || [];
|
|
6937
|
+
if (attachments.length > 0) {
|
|
6938
|
+
node.appendChild(attachmentStrip(attachments));
|
|
6939
|
+
}
|
|
6396
6940
|
if (quotes.length > 0) {
|
|
6397
6941
|
var box = el("div", "dsh-sel-bq");
|
|
6398
6942
|
for (var i = 0; i < quotes.length; i += 1) {
|
|
@@ -6404,7 +6948,57 @@ function createHistoryController(env) {
|
|
|
6404
6948
|
}
|
|
6405
6949
|
node.appendChild(box);
|
|
6406
6950
|
}
|
|
6407
|
-
|
|
6951
|
+
var display = displayTextOf(turn);
|
|
6952
|
+
if (display) node.appendChild(el("div", null, display));
|
|
6953
|
+
}
|
|
6954
|
+
function attachmentStrip(attachments) {
|
|
6955
|
+
var strip = el("div", "dsh-sel-bqattach");
|
|
6956
|
+
for (var i = 0; i < attachments.length; i += 1) {
|
|
6957
|
+
var item = attachments[i] || {};
|
|
6958
|
+
var ref = item.ref || {};
|
|
6959
|
+
if (item.kind === "image") {
|
|
6960
|
+
strip.appendChild(attachmentImage(ref));
|
|
6961
|
+
} else {
|
|
6962
|
+
strip.appendChild(attachmentFile(ref));
|
|
6963
|
+
}
|
|
6964
|
+
}
|
|
6965
|
+
return strip;
|
|
6966
|
+
}
|
|
6967
|
+
function attachmentImage(ref) {
|
|
6968
|
+
var link = document.createElement("a");
|
|
6969
|
+
link.className = "dsh-sel-bqimgwrap";
|
|
6970
|
+
link.href = attachmentUrl("image", ref);
|
|
6971
|
+
link.target = "_blank";
|
|
6972
|
+
link.rel = "noreferrer noopener";
|
|
6973
|
+
link.title = "\u70B9\u51FB\u67E5\u770B\u539F\u56FE" + (ref.name ? "\uFF1A" + ref.name : "");
|
|
6974
|
+
var img = document.createElement("img");
|
|
6975
|
+
img.className = "dsh-sel-bqimg";
|
|
6976
|
+
img.src = link.href;
|
|
6977
|
+
img.alt = ref.name || "\u56FE\u7247";
|
|
6978
|
+
img.loading = "lazy";
|
|
6979
|
+
img.addEventListener("error", function() {
|
|
6980
|
+
var box = el("span", "dsh-sel-bqimgfail", "\u56FE\u7247\u5DF2\u4E0D\u5728\u9644\u4EF6\u4ED3\u91CC");
|
|
6981
|
+
if (link.parentNode) link.parentNode.replaceChild(box, link);
|
|
6982
|
+
});
|
|
6983
|
+
link.appendChild(img);
|
|
6984
|
+
return link;
|
|
6985
|
+
}
|
|
6986
|
+
function attachmentFile(ref) {
|
|
6987
|
+
var link = document.createElement("a");
|
|
6988
|
+
link.className = "dsh-sel-bqfile";
|
|
6989
|
+
link.href = attachmentUrl("file", ref, true);
|
|
6990
|
+
link.rel = "noreferrer noopener";
|
|
6991
|
+
link.title = "\u4E0B\u8F7D\uFF1A" + (ref.name || "\u6587\u4EF6");
|
|
6992
|
+
link.appendChild(el("span", "dsh-sel-bqfileext", ref.name ? extensionOf(ref.name) : "FILE"));
|
|
6993
|
+
link.appendChild(el("span", "dsh-sel-bqfilename", ref.name || "\u6587\u4EF6"));
|
|
6994
|
+
if (typeof ref.bytes === "number") link.appendChild(el("span", "dsh-sel-bqfilemeta", formatBytes(ref.bytes)));
|
|
6995
|
+
return link;
|
|
6996
|
+
}
|
|
6997
|
+
function displayTextOf(turn) {
|
|
6998
|
+
var text = turn.text || "";
|
|
6999
|
+
if (!text) return "";
|
|
7000
|
+
if (!turn.attachments || turn.attachments.length === 0) return text;
|
|
7001
|
+
return text.replace(/^【本条消息带了附件】[^\n]*\n?/, "");
|
|
6408
7002
|
}
|
|
6409
7003
|
function bubbleFor(turn) {
|
|
6410
7004
|
var bubble = el("div", "dsh-sel-bubble " + (turn.role === "user" ? "dsh-sel-bubble-user" : "dsh-sel-bubble-bot"));
|
|
@@ -6539,7 +7133,10 @@ function createConversationController(env) {
|
|
|
6539
7133
|
env.askSend.setAttribute("aria-label", generating ? "\u505C\u6B62" : "\u53D1\u9001");
|
|
6540
7134
|
env.askSend.title = generating ? "\u505C\u6B62\u751F\u6210\uFF08\u70B9\u4E00\u4E0B\u6253\u65AD\u8FD9\u6B21\u8F93\u51FA\uFF09" : "\u53D1\u9001\uFF08Enter\uFF09";
|
|
6541
7135
|
}
|
|
6542
|
-
|
|
7136
|
+
var waitingAttachments = env.attachmentsBusy();
|
|
7137
|
+
env.askSend.disabled = generating ? false : waitingAttachments || !String(env.askBox.value || "").trim() && env.state.quotes.length === 0 && env.state.attachments.length === 0;
|
|
7138
|
+
var placeholder = env.state.attachments.length > 0 ? "\u5C31\u8FD9\u6BB5\u6587\u5B57\u7EE7\u7EED\u8FFD\u95EE\u2026\uFF08Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\uFF09" : "\u5C31\u8FD9\u6BB5\u6587\u5B57\u7EE7\u7EED\u8FFD\u95EE\u2026\uFF08\u53EF\u62D6\u5165\u56FE\u7247 / \u6587\u4EF6\uFF0C\u6216 \u2318V \u7C98\u8D34\uFF09";
|
|
7139
|
+
if (env.askBox.placeholder !== placeholder) env.askBox.placeholder = placeholder;
|
|
6543
7140
|
}
|
|
6544
7141
|
function stopCurrent() {
|
|
6545
7142
|
if (env.state.askRequest) {
|
|
@@ -6572,7 +7169,12 @@ function createConversationController(env) {
|
|
|
6572
7169
|
}
|
|
6573
7170
|
var asked = String(question || "").trim();
|
|
6574
7171
|
var quotes = env.state.quotes.slice();
|
|
6575
|
-
|
|
7172
|
+
var attachments = env.attachmentsPayload();
|
|
7173
|
+
if (!asked && quotes.length === 0 && attachments.length === 0 || !env.state.payload) return;
|
|
7174
|
+
if (env.attachmentsBusy()) {
|
|
7175
|
+
env.setStatus("\u9644\u4EF6\u8FD8\u5728\u4E0A\u4F20\uFF0C\u7A0D\u7B49\u4E00\u4E0B\u2026");
|
|
7176
|
+
return;
|
|
7177
|
+
}
|
|
6576
7178
|
if (env.state.resolvingQuotes) {
|
|
6577
7179
|
env.setStatus("\u6B63\u5728\u53D6\u5F15\u7528\u7684\u4E0A\u4E0B\u6587\u2026");
|
|
6578
7180
|
return;
|
|
@@ -6586,24 +7188,31 @@ function createConversationController(env) {
|
|
|
6586
7188
|
env.renderQuotes();
|
|
6587
7189
|
refreshAskState();
|
|
6588
7190
|
}
|
|
7191
|
+
var attachmentsNote = env.attachmentsDescribe();
|
|
7192
|
+
if (attachments.length > 0) {
|
|
7193
|
+
env.clearAttachments();
|
|
7194
|
+
refreshAskState();
|
|
7195
|
+
}
|
|
6589
7196
|
if (quotes.length === 0) {
|
|
6590
|
-
sendAsk(asked, quotes);
|
|
7197
|
+
sendAsk(asked, quotes, attachments, attachmentsNote);
|
|
6591
7198
|
return;
|
|
6592
7199
|
}
|
|
6593
7200
|
env.state.resolvingQuotes = true;
|
|
6594
7201
|
env.resolveQuoteContexts(quotes).then(function(resolved) {
|
|
6595
7202
|
env.state.resolvingQuotes = false;
|
|
6596
|
-
sendAsk(asked, resolved);
|
|
7203
|
+
sendAsk(asked, resolved, attachments, attachmentsNote);
|
|
6597
7204
|
});
|
|
6598
7205
|
}
|
|
6599
|
-
function sendAsk(asked, quotes) {
|
|
7206
|
+
function sendAsk(asked, quotes, attachments, attachmentsNote) {
|
|
6600
7207
|
var payload = env.state.payload;
|
|
6601
7208
|
if (!payload) return;
|
|
7209
|
+
var withAttachments = attachments || [];
|
|
6602
7210
|
var sent = env.composeQuestion(quotes, asked);
|
|
7211
|
+
if (attachmentsNote) sent = attachmentsNote + "\n" + sent;
|
|
6603
7212
|
if (env.state.turns.length === 0 && (env.state.raw.trim() || env.state.parts.translation || env.state.parts.detail)) {
|
|
6604
7213
|
env.state.turns.push({ role: "assistant", text: env.seedHistoryFromExplanation(), seed: true, hidden: true });
|
|
6605
7214
|
}
|
|
6606
|
-
env.state.turns.push({ role: "user", text: asked || QUOTE_ONLY_QUESTION, quotes, sent });
|
|
7215
|
+
env.state.turns.push({ role: "user", text: asked || QUOTE_ONLY_QUESTION, quotes, sent, attachments: withAttachments });
|
|
6607
7216
|
var answerTurn = {
|
|
6608
7217
|
role: "assistant",
|
|
6609
7218
|
text: "",
|
|
@@ -6636,7 +7245,11 @@ function createConversationController(env) {
|
|
|
6636
7245
|
var historyTurns = env.state.turns.slice(0, env.state.turns.length - 2);
|
|
6637
7246
|
var history = historyTurns.map(function(turn, index) {
|
|
6638
7247
|
var keepRaw = env.FOLD_HISTORY_KEEP_LATEST && index === historyTurns.length - 1;
|
|
6639
|
-
return {
|
|
7248
|
+
return {
|
|
7249
|
+
role: turn.role,
|
|
7250
|
+
text: env.historyTextOf(turn, keepRaw),
|
|
7251
|
+
...turn.attachments && turn.attachments.length > 0 ? { attachments: turn.attachments } : {}
|
|
7252
|
+
};
|
|
6640
7253
|
});
|
|
6641
7254
|
env.state.stopped = false;
|
|
6642
7255
|
var askController = new AbortController();
|
|
@@ -6683,6 +7296,8 @@ function createConversationController(env) {
|
|
|
6683
7296
|
sessionId: env.panelOrCurrentSessionId(),
|
|
6684
7297
|
question: sent,
|
|
6685
7298
|
history,
|
|
7299
|
+
// 附件只带**引用**(图片/文件都已经在 host 的附件服务里),body 不会因为一张截图胖几 MB
|
|
7300
|
+
...withAttachments.length > 0 ? { attachments: withAttachments } : {},
|
|
6686
7301
|
// 网页输出要跟着当前深浅走:深色 Harness 里给一张白底页面会很刺眼
|
|
6687
7302
|
...env.state.webAnswer ? { webAnswer: true, theme: env.currentSurfaceTheme() } : {},
|
|
6688
7303
|
...env.state.modelChoice ? { provider: env.state.modelChoice.provider, model: env.state.modelChoice.model } : {},
|
|
@@ -8556,6 +9171,14 @@ function apply(ctx) {
|
|
|
8556
9171
|
payload: null,
|
|
8557
9172
|
/** 已生成的两节内容(分阶段产出)。 */
|
|
8558
9173
|
parts: { translation: "", detail: "" },
|
|
9174
|
+
/**
|
|
9175
|
+
* 这段对话**没有解读**(语音卡那条"跳过翻译与详解、直接追问"的路):
|
|
9176
|
+
* 翻译节整节不画,追问输入框直接可见。
|
|
9177
|
+
*
|
|
9178
|
+
* 语义单位是"一段对话"而不是"一次开窗":落盘时写进历史条目的 skipped,
|
|
9179
|
+
* 回放/缓存命中时按它复原(否则同一个词再开一次,空翻译卡片又冒出来 —— 用户实测)。
|
|
9180
|
+
*/
|
|
9181
|
+
skipInterpretation: false,
|
|
8559
9182
|
/** 当前阶段:'translation' | 'detail' | 'chat'。 */
|
|
8560
9183
|
stage: "",
|
|
8561
9184
|
/** 追问轮次:[{ role: 'user' | 'assistant', text }],只活在面板/内存里(临时)。 */
|
|
@@ -8565,6 +9188,14 @@ function apply(ctx) {
|
|
|
8565
9188
|
* 只属于**下一条**提问(发送即清空);关掉面板不清 —— 回来接着写还看得见。
|
|
8566
9189
|
*/
|
|
8567
9190
|
quotes: [],
|
|
9191
|
+
/**
|
|
9192
|
+
* 待发送的附件:[{ id, kind:'image'|'file', name, size, mediaType, file, url, status, ref, error }]。
|
|
9193
|
+
* 和引用同一条规矩 —— 只属于**下一条**追问,发送即清空;
|
|
9194
|
+
* 区别是上传状态挂在每一项上(逐件上传、逐件重试,见 attach.js)。
|
|
9195
|
+
*/
|
|
9196
|
+
attachments: [],
|
|
9197
|
+
/** 附件条下面那行提示("文件夹不支持""一次最多 10 件"之类),空串就不显示。 */
|
|
9198
|
+
attachNote: "",
|
|
8568
9199
|
/** 最近一次"可以引用"的选区:[{ text, label, rect, source }](浮标据此显示)。 */
|
|
8569
9200
|
quoteSelection: null,
|
|
8570
9201
|
/** 正在取引用的会话上下文(这期间再按 Enter 不能空发一条)。 */
|
|
@@ -8685,14 +9316,25 @@ function apply(ctx) {
|
|
|
8685
9316
|
var askRow = el("div", "dsh-sel-ask");
|
|
8686
9317
|
var quotesBox = el("div", "dsh-sel-quotes");
|
|
8687
9318
|
askRow.appendChild(quotesBox);
|
|
9319
|
+
var attachBox = el("div", "dsh-sel-attach");
|
|
9320
|
+
askRow.appendChild(attachBox);
|
|
9321
|
+
var attachNote = el("p", "dsh-sel-attachnote");
|
|
9322
|
+
askRow.appendChild(attachNote);
|
|
9323
|
+
var attachInput = el("input");
|
|
9324
|
+
attachInput.type = "file";
|
|
9325
|
+
attachInput.multiple = true;
|
|
9326
|
+
attachInput.style.display = "none";
|
|
9327
|
+
attachInput.setAttribute("aria-hidden", "true");
|
|
9328
|
+
attachInput.tabIndex = -1;
|
|
9329
|
+
askRow.appendChild(attachInput);
|
|
8688
9330
|
var askBox = el("textarea", "dsh-sel-askbox");
|
|
8689
9331
|
askBox.rows = 1;
|
|
8690
9332
|
askBox.placeholder = "\u5C31\u8FD9\u6BB5\u6587\u5B57\u7EE7\u7EED\u8FFD\u95EE\u2026\uFF08Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\uFF09";
|
|
8691
9333
|
var webMode = el("span", "dsh-sel-pref");
|
|
8692
|
-
webMode.
|
|
9334
|
+
webMode.title = "\u8F93\u51FA\u504F\u597D\uFF1AMarkdown\uFF08\u9ED8\u8BA4\u6587\u5B57\u56DE\u7B54\uFF09/ \u7F51\u9875\uFF08\u590D\u6742\u95EE\u9898\u751F\u6210 HTML \u9875\u9762\uFF09";
|
|
8693
9335
|
var prefSeg = el("span", "dsh-sel-seg");
|
|
8694
9336
|
prefSeg.setAttribute("role", "radiogroup");
|
|
8695
|
-
prefSeg.setAttribute("aria-label", "\u8F93\u51FA\u504F\u597D");
|
|
9337
|
+
prefSeg.setAttribute("aria-label", "\u8F93\u51FA\u504F\u597D\uFF1AMarkdown \u6216\u7F51\u9875");
|
|
8696
9338
|
var prefPill = el("span", "dsh-sel-segpill");
|
|
8697
9339
|
var cellMd = el("button", "dsh-sel-segcell");
|
|
8698
9340
|
cellMd.type = "button";
|
|
@@ -8773,7 +9415,13 @@ function apply(ctx) {
|
|
|
8773
9415
|
captureRow.appendChild(voiceActionSlot);
|
|
8774
9416
|
captureRow.appendChild(voiceStop);
|
|
8775
9417
|
var askTools = el("div", "dsh-sel-asktools");
|
|
9418
|
+
var addButton = el("button", "dsh-sel-iconbtn dsh-sel-add");
|
|
9419
|
+
addButton.type = "button";
|
|
9420
|
+
addButton.setAttribute("aria-label", "\u6DFB\u52A0\u56FE\u7247\u6216\u6587\u4EF6");
|
|
9421
|
+
addButton.title = "\u6DFB\u52A0\u56FE\u7247\u6216\u6587\u4EF6\uFF08\u4E5F\u53EF\u4EE5\u76F4\u63A5\u7C98\u8D34\u6216\u62D6\u8FDB\u6765\uFF09";
|
|
9422
|
+
addButton.appendChild(plusIcon());
|
|
8776
9423
|
var askSpacer = el("span", "dsh-sel-askspace");
|
|
9424
|
+
askTools.appendChild(addButton);
|
|
8777
9425
|
askTools.appendChild(webMode);
|
|
8778
9426
|
askTools.appendChild(askSpacer);
|
|
8779
9427
|
askTools.appendChild(modelPill);
|
|
@@ -8837,6 +9485,14 @@ function apply(ctx) {
|
|
|
8837
9485
|
panel.appendChild(head);
|
|
8838
9486
|
panel.appendChild(body);
|
|
8839
9487
|
panel.appendChild(askRow);
|
|
9488
|
+
var dropMask = el("div", "dsh-sel-drop");
|
|
9489
|
+
dropMask.setAttribute("aria-hidden", "true");
|
|
9490
|
+
var dropArt = el("div", "dsh-sel-drop-art");
|
|
9491
|
+
dropArt.appendChild(plusIcon());
|
|
9492
|
+
dropMask.appendChild(dropArt);
|
|
9493
|
+
dropMask.appendChild(el("div", "dsh-sel-drop-title", "\u677E\u5F00\u5373\u6DFB\u52A0\u4E3A\u8FD9\u6761\u8FFD\u95EE\u7684\u9644\u4EF6"));
|
|
9494
|
+
dropMask.appendChild(el("div", "dsh-sel-drop-hint", "\u56FE\u7247\u76F4\u63A5\u7ED9\u6A21\u578B\u770B \xB7 \u6587\u4EF6\u5B58\u6210\u53EA\u8BFB\u8DEF\u5F84\u6309\u9700\u8BFB\u53D6"));
|
|
9495
|
+
panel.appendChild(dropMask);
|
|
8840
9496
|
layer.appendChild(panel);
|
|
8841
9497
|
var settingsController = createSettingsController({
|
|
8842
9498
|
get state() {
|
|
@@ -9125,6 +9781,9 @@ function apply(ctx) {
|
|
|
9125
9781
|
get clearQuotes() {
|
|
9126
9782
|
return quotesController.clearQuotes;
|
|
9127
9783
|
},
|
|
9784
|
+
get clearAttachments() {
|
|
9785
|
+
return attachController.clear;
|
|
9786
|
+
},
|
|
9128
9787
|
get renderTurns() {
|
|
9129
9788
|
return historyController.renderTurns;
|
|
9130
9789
|
},
|
|
@@ -9518,6 +10177,18 @@ function apply(ctx) {
|
|
|
9518
10177
|
get composeQuestion() {
|
|
9519
10178
|
return quotesController.composeQuestion;
|
|
9520
10179
|
},
|
|
10180
|
+
get attachmentsPayload() {
|
|
10181
|
+
return attachController.payload;
|
|
10182
|
+
},
|
|
10183
|
+
get attachmentsBusy() {
|
|
10184
|
+
return attachController.busy;
|
|
10185
|
+
},
|
|
10186
|
+
get attachmentsDescribe() {
|
|
10187
|
+
return attachController.describe;
|
|
10188
|
+
},
|
|
10189
|
+
get clearAttachments() {
|
|
10190
|
+
return attachController.clear;
|
|
10191
|
+
},
|
|
9521
10192
|
get seedHistoryFromExplanation() {
|
|
9522
10193
|
return historyController.seedHistoryFromExplanation;
|
|
9523
10194
|
},
|
|
@@ -9630,6 +10301,29 @@ function apply(ctx) {
|
|
|
9630
10301
|
return panelController.buildPayload;
|
|
9631
10302
|
}
|
|
9632
10303
|
});
|
|
10304
|
+
var attachController = createAttachController({
|
|
10305
|
+
get state() {
|
|
10306
|
+
return state;
|
|
10307
|
+
},
|
|
10308
|
+
get panel() {
|
|
10309
|
+
return panel;
|
|
10310
|
+
},
|
|
10311
|
+
get attachBox() {
|
|
10312
|
+
return attachBox;
|
|
10313
|
+
},
|
|
10314
|
+
get attachNote() {
|
|
10315
|
+
return attachNote;
|
|
10316
|
+
},
|
|
10317
|
+
get attachInput() {
|
|
10318
|
+
return attachInput;
|
|
10319
|
+
},
|
|
10320
|
+
get setStatus() {
|
|
10321
|
+
return panelController.setStatus;
|
|
10322
|
+
},
|
|
10323
|
+
get refreshAskState() {
|
|
10324
|
+
return conversationController.refreshAskState;
|
|
10325
|
+
}
|
|
10326
|
+
});
|
|
9633
10327
|
var modelsController = createModelsController({
|
|
9634
10328
|
get state() {
|
|
9635
10329
|
return state;
|
|
@@ -10162,7 +10856,7 @@ function apply(ctx) {
|
|
|
10162
10856
|
event.preventDefault();
|
|
10163
10857
|
event.stopPropagation();
|
|
10164
10858
|
var question = askBox.value;
|
|
10165
|
-
if (!question.trim() && state.quotes.length === 0) return;
|
|
10859
|
+
if (!question.trim() && state.quotes.length === 0 && state.attachments.length === 0) return;
|
|
10166
10860
|
conversationController.ask(question);
|
|
10167
10861
|
});
|
|
10168
10862
|
var offAskInput = listen(askBox, "input", function() {
|
|
@@ -10175,9 +10869,21 @@ function apply(ctx) {
|
|
|
10175
10869
|
return;
|
|
10176
10870
|
}
|
|
10177
10871
|
var question = askBox.value;
|
|
10178
|
-
if (!question.trim() && state.quotes.length === 0) return;
|
|
10872
|
+
if (!question.trim() && state.quotes.length === 0 && state.attachments.length === 0) return;
|
|
10179
10873
|
conversationController.ask(question);
|
|
10180
10874
|
});
|
|
10875
|
+
var offAttachPick = listen(attachInput, "change", function() {
|
|
10876
|
+
attachController.addFiles(attachInput.files || []);
|
|
10877
|
+
attachInput.value = "";
|
|
10878
|
+
});
|
|
10879
|
+
var offAttachButton = listen(addButton, "click", function(event) {
|
|
10880
|
+
event.stopPropagation();
|
|
10881
|
+
attachController.pick();
|
|
10882
|
+
});
|
|
10883
|
+
var offAttachPaste = listen(panel, "paste", function(event) {
|
|
10884
|
+
attachController.handlePaste(event);
|
|
10885
|
+
});
|
|
10886
|
+
attachController.wireDrop();
|
|
10181
10887
|
var offMic = listen(micButton, "click", function(event) {
|
|
10182
10888
|
event.stopPropagation();
|
|
10183
10889
|
voiceController.startVoice();
|
|
@@ -10773,6 +11479,9 @@ function apply(ctx) {
|
|
|
10773
11479
|
offAskKey();
|
|
10774
11480
|
offAskInput();
|
|
10775
11481
|
offAskSend();
|
|
11482
|
+
offAttachPick();
|
|
11483
|
+
offAttachButton();
|
|
11484
|
+
offAttachPaste();
|
|
10776
11485
|
offMic();
|
|
10777
11486
|
offVoiceCancel();
|
|
10778
11487
|
offVoiceStop();
|