dsh-live2dwaifu 2.0.1 → 2.2.0
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 +22 -10
- package/assets/viewer.html +17 -1
- package/assets/viewer.js +102 -7
- package/lib/index.js +1069 -943
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,6 +231,7 @@ python tools/export-dsh-meme.py
|
|
|
231
231
|
| 自动播放动作 | 本机 | 开 | 模型带动作文件时,隔一会儿播一个 |
|
|
232
232
|
| 说话带电子音 | 本机 | 开 | 每个字一声短音 |
|
|
233
233
|
| 复述聊天内容 | 本机 | 开 | 聊天窗口出现新回复时,由她念出来 |
|
|
234
|
+
| 表情包出现的位置 | 本机 | 文字左边 | 文字左边 / 文字上方 / 卡片左上角 / 说话不配图 |
|
|
234
235
|
| 闲置主动说话的间隔 | 服务端 | 30 分钟 | 关闭 / 30 分钟 / 1 小时 / 2 小时 / 4 小时 |
|
|
235
236
|
| 回复附带选项按钮 | 服务端 | 开 | 她觉得需要选择时,气泡上方出现可点按钮 |
|
|
236
237
|
| 记住聊过的内容 | 服务端 | 开 | 关掉就不带记忆、不压缩 |
|
|
@@ -238,16 +239,7 @@ python tools/export-dsh-meme.py
|
|
|
238
239
|
|
|
239
240
|
「本机」存 localStorage,只影响这一台浏览器;「服务端」存 `~/.dsh/dsh-live2d/config.json`,换浏览器也一样。
|
|
240
241
|
|
|
241
|
-
|
|
242
|
-
| 眼睛跟着鼠标 | 本机 | 开 | 关掉她就不看鼠标了 |
|
|
243
|
-
| 点她有反应 | 本机 | 开 | 摸头害羞、戳身上瞪你 |
|
|
244
|
-
| 自己播动作 | 本机 | 开 | 有动作文件的模型才会动 |
|
|
245
|
-
| 出声 | 本机 | 开 | 电子音 |
|
|
246
|
-
| 跟着聊天念 | 本机 | 开 | 助手每说一句她念一句 |
|
|
247
|
-
| 没人理就自己开口 | 她那边 | 开 | 十几分钟没人说话她说一句 |
|
|
248
|
-
| 给选项让他挑 | 她那边 | 开 | 气泡上方冒出可点的按钮 |
|
|
249
|
-
| 记住之前说的 | 她那边 | 开 | 关掉就不带记忆、不压缩 |
|
|
250
|
-
| 表情包(四档) | 她那边 | 不使用 | 测试功能,见上 |
|
|
242
|
+
主动开口那根滑轴给的是基准时长,实际会在这个数前后浮动,不是准点报到;夜里 0 点到 7 点她不出声。想看效果不用等,⚙ 里有一句「让她现在说一句」,点一下马上说一句。
|
|
251
243
|
|
|
252
244
|
---
|
|
253
245
|
|
|
@@ -380,6 +372,26 @@ curl -X POST http://127.0.0.1:<端口>/dsh-live2d/api/push \
|
|
|
380
372
|
|
|
381
373
|
版本号怎么走:动了功能和结构就抬第二位(1.2.0),只补洞和小修就抬第三位(1.2.1)。
|
|
382
374
|
|
|
375
|
+
### 2.2.0
|
|
376
|
+
|
|
377
|
+
- 加:表情包出在哪儿可以选。默认「文字左边」——图跟文字并排,图不再把文字往下顶。另有三档:「文字上方」(旧样子)、「卡片左上角」(单独浮一张,不挤气泡)、「说话不配图」。⚙ 第一栏就能改,改完正在显示的那张也会挪过去。
|
|
378
|
+
- 修:气泡每 9 秒会被固定台词(「嗯。」「在的。」「今天还行。」)顶掉,她刚说的话、配的图都会被盖没。现在 45 秒内有过新话、或者气泡还挂着,就不插嘴。
|
|
379
|
+
- 修:答题式的固定台词也换成只在她确实安静的时候才冒一句。
|
|
380
|
+
|
|
381
|
+
### 2.1.0
|
|
382
|
+
|
|
383
|
+
「随机主动消息」这一块基本重做了。之前那版有两个毛病,都是真的。
|
|
384
|
+
|
|
385
|
+
- 修:**间隔根本不受设置管**。计时器只存在内存里,每次重启 DSH 归零,于是「闲置 1 小时才说一句」实际变成「重启后 1 小时说一句」。你重启三次,她就说三次,看着像 12 分钟、23 分钟一次。现在计时落到 `~/.dsh/dsh-live2d/auto.json`,锚点取聊天记录里最后一条的时间,重启不影响。
|
|
386
|
+
- 改:间隔改成浮动。设定值只当基准,每轮在 0.8~1.4 倍之间重新抽一次,不再准点报到。
|
|
387
|
+
- 加:夜里 0 点到 7 点不主动开口,白天再补。
|
|
388
|
+
- 修:**主动开口的样式是照着问答样例生成的**,所以每句都像在回答一个不存在的问题,结尾固定挂「你饿不饿」。现在换成开口样例(短句、不起头就是一句陈述),每轮随机指定一种开口方式:说手上的事、想起他一句、抱怨一句、只丢两三个字、说一件变化、提一件打算做的事。
|
|
389
|
+
- 加:主动开口会读自己最近六句,撞了就不说——同一个道具(粥、袖口、手凉)不会连着出现。两次都撞就这轮作罢,宁可不说。
|
|
390
|
+
- 加:主动开口也带情绪和配图(按表情包设置),并且会清掉上一次没点的选项按钮。
|
|
391
|
+
- 修:`guessMood` 用单字匹配,「了」被算进「无语」,导致「番茄藤绑好了」这类正常句子一律判成无语、连表情都选错。改成按词判断。
|
|
392
|
+
- 加:⚙ 里多一个「让她现在说一句」,不等时间,点了就看效果。
|
|
393
|
+
- 修:README 开关表里混进来一段旧表格残块。
|
|
394
|
+
|
|
383
395
|
### 2.0.1
|
|
384
396
|
|
|
385
397
|
- 修:拖动时没限制边界,卡片能被推到屏幕外,标题栏抓不回来。现在拖动过程中就夹住,标题栏永远露在视口里。
|
package/assets/viewer.html
CHANGED
|
@@ -20,7 +20,18 @@
|
|
|
20
20
|
opacity: 0; transition: opacity .35s ease; cursor: grab; user-select: none;
|
|
21
21
|
max-height: 42%; overflow: hidden; touch-action: none; }
|
|
22
22
|
#bubble:active { cursor: grabbing; }
|
|
23
|
-
|
|
23
|
+
/* 图跟文字并排:图在左,文字右,文字不被顶下去 */
|
|
24
|
+
#bubble.img-side { display: flex; align-items: flex-start; gap: 9px; }
|
|
25
|
+
#bubble.img-above { display: flex; flex-direction: column; gap: 7px; }
|
|
26
|
+
.bub-txt { flex: 1 1 auto; min-width: 0; }
|
|
27
|
+
.bub-img { display: block; border-radius: 10px; object-fit: contain; flex: none; }
|
|
28
|
+
#bubble.img-side .bub-img { max-width: 45%; max-height: 96px; }
|
|
29
|
+
#bubble.img-above .bub-img { max-width: 70%; max-height: 88px; }
|
|
30
|
+
/* 单独浮一张,不占气泡 */
|
|
31
|
+
#sticker { position: absolute; left: 10px; top: 10px; max-width: 38%; max-height: 32%;
|
|
32
|
+
opacity: 0; transition: opacity .35s ease; pointer-events: none; }
|
|
33
|
+
#sticker .stk-img { display: block; max-width: 100%; max-height: 100%; border-radius: 12px;
|
|
34
|
+
box-shadow: 0 8px 22px rgba(0,0,0,.45); object-fit: contain; }
|
|
24
35
|
#hint { position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
|
|
25
36
|
text-align: center; padding: 24px; color: #98a0ad; }
|
|
26
37
|
#hint.show { display: flex; }
|
|
@@ -57,6 +68,10 @@
|
|
|
57
68
|
.opt-col input[type=range] { width: 100%; accent-color: #6aa9ff; }
|
|
58
69
|
.opt-lab { font-size: 12px; color: #e2e8f1; margin-top: 2px; }
|
|
59
70
|
.opt-note { font-size: 10.5px; line-height: 1.65; color: #6f7783; margin-top: 5px; }
|
|
71
|
+
.opt-btn { margin-top: 7px; padding: 6px 12px; border-radius: 9px; cursor: pointer; font: inherit; font-size: 12px;
|
|
72
|
+
background: rgba(255,255,255,.07); color: #dfe4ec; border: 1px solid rgba(255,255,255,.12); transition: background .15s; }
|
|
73
|
+
.opt-btn:hover { background: rgba(255,255,255,.14); }
|
|
74
|
+
.opt-btn:disabled { opacity: .55; cursor: default; }
|
|
60
75
|
#actions { display: flex; gap: 8px; flex: none; }
|
|
61
76
|
#actions button { flex: 1; padding: 9px; border-radius: 10px; cursor: pointer; font: inherit;
|
|
62
77
|
background: rgba(255,255,255,.07); color: #dfe4ec; border: 1px solid rgba(255,255,255,.1); transition: background .15s; }
|
|
@@ -66,6 +81,7 @@
|
|
|
66
81
|
</head>
|
|
67
82
|
<body>
|
|
68
83
|
<canvas id="stage"></canvas>
|
|
84
|
+
<div id="sticker"></div>
|
|
69
85
|
<div id="bottom">
|
|
70
86
|
<div id="choices"></div>
|
|
71
87
|
<div id="bubble"></div>
|
package/assets/viewer.js
CHANGED
|
@@ -44316,6 +44316,7 @@ void main(void)\r
|
|
|
44316
44316
|
var gazeY = 0;
|
|
44317
44317
|
var pokeAt = 0;
|
|
44318
44318
|
var sayFade = 0;
|
|
44319
|
+
var lastSayAt = 0;
|
|
44319
44320
|
var motionGroups = [];
|
|
44320
44321
|
var nextMotionAt = 0;
|
|
44321
44322
|
var POKE_HEAD = ["\u5514\u3002", "\u522B\u6478\u3002", "\u5934\u53D1\u4E71\u4E86\u3002", "\u55EF\u2026\u2026", "\u4F60\u624B\u51C9\u3002"];
|
|
@@ -44383,6 +44384,40 @@ void main(void)\r
|
|
|
44383
44384
|
row.appendChild(document.createTextNode(label));
|
|
44384
44385
|
box.appendChild(row);
|
|
44385
44386
|
}
|
|
44387
|
+
const hp = document.createElement("h3");
|
|
44388
|
+
hp.textContent = "\u8868\u60C5\u5305\u51FA\u73B0\u7684\u4F4D\u7F6E";
|
|
44389
|
+
box.appendChild(hp);
|
|
44390
|
+
const posWrap = document.createElement("div");
|
|
44391
|
+
posWrap.className = "opt-col";
|
|
44392
|
+
const posSlider = document.createElement("input");
|
|
44393
|
+
posSlider.type = "range";
|
|
44394
|
+
posSlider.min = "0";
|
|
44395
|
+
posSlider.max = String(IMG_POS.length - 1);
|
|
44396
|
+
posSlider.step = "1";
|
|
44397
|
+
const curPos = Math.max(0, IMG_POS.indexOf(imgPos()));
|
|
44398
|
+
posSlider.value = String(curPos);
|
|
44399
|
+
const posLab = document.createElement("div");
|
|
44400
|
+
posLab.className = "opt-lab";
|
|
44401
|
+
posLab.textContent = IMG_POS_LABELS[curPos];
|
|
44402
|
+
posSlider.oninput = () => {
|
|
44403
|
+
posLab.textContent = IMG_POS_LABELS[Number(posSlider.value)];
|
|
44404
|
+
};
|
|
44405
|
+
posSlider.onchange = () => {
|
|
44406
|
+
setImgPos(IMG_POS[Number(posSlider.value)]);
|
|
44407
|
+
const bubble = $2("bubble");
|
|
44408
|
+
const shown = bubble ? bubble.querySelector(".bub-img") : null;
|
|
44409
|
+
const pushed = $2("sticker") ? $2("sticker").querySelector(".stk-img") : null;
|
|
44410
|
+
const src = shown && shown.src || pushed && pushed.src || "";
|
|
44411
|
+
if (shown && shown.parentNode) shown.parentNode.removeChild(shown);
|
|
44412
|
+
if (src && bubble) placeImage(bubble, src);
|
|
44413
|
+
};
|
|
44414
|
+
const posNote = document.createElement("div");
|
|
44415
|
+
posNote.className = "opt-note";
|
|
44416
|
+
posNote.textContent = "\u8BF4\u8BDD\u65F6\u914D\u56FE\u51FA\u5728\u54EA\u513F\u3002\u8D34\u5728\u6587\u5B57\u5DE6\u8FB9\u6216\u4E0A\u65B9\u90FD\u8DDF\u6C14\u6CE1\u4E00\u8D77\u8D70\uFF1B\u5361\u7247\u5DE6\u4E0A\u89D2\u662F\u5355\u72EC\u6D6E\u4E00\u5F20\uFF0C\u4E0D\u6324\u6C14\u6CE1\u3002";
|
|
44417
|
+
posWrap.appendChild(posSlider);
|
|
44418
|
+
posWrap.appendChild(posLab);
|
|
44419
|
+
posWrap.appendChild(posNote);
|
|
44420
|
+
box.appendChild(posWrap);
|
|
44386
44421
|
const h2 = document.createElement("h3");
|
|
44387
44422
|
h2.textContent = "\u5BF9\u8BDD\u4E0E\u884C\u4E3A\uFF08\u5B58\u670D\u52A1\u7AEF\uFF09";
|
|
44388
44423
|
box.appendChild(h2);
|
|
@@ -44448,10 +44483,28 @@ void main(void)\r
|
|
|
44448
44483
|
};
|
|
44449
44484
|
const gapNote = document.createElement("div");
|
|
44450
44485
|
gapNote.className = "opt-note";
|
|
44451
|
-
gapNote.textContent = "\u591A\u4E45\u6CA1\u6709\u5BF9\u8BDD\u4E4B\u540E\uFF0C\u89D2\u8272\u4E3B\u52A8\u8BF4\u4E00\u53E5\u3002\u9009\u300C\u5173\u95ED\u300D\u5C31\u4E0D\u4F1A\u81EA\u5DF1\u5F00\u53E3\u3002";
|
|
44486
|
+
gapNote.textContent = "\u591A\u4E45\u6CA1\u6709\u5BF9\u8BDD\u4E4B\u540E\uFF0C\u89D2\u8272\u4E3B\u52A8\u8BF4\u4E00\u53E5\u3002\u5B9E\u9645\u4F1A\u6309\u8FD9\u4E2A\u6570\u4E0A\u4E0B\u6D6E\u52A8\uFF0C\u4E0D\u662F\u51C6\u70B9\uFF1B\u591C\u91CC 0 \u70B9\u5230 7 \u70B9\u4E0D\u5F00\u53E3\u3002\u9009\u300C\u5173\u95ED\u300D\u5C31\u4E0D\u4F1A\u81EA\u5DF1\u5F00\u53E3\u3002";
|
|
44487
|
+
const gapTry = document.createElement("button");
|
|
44488
|
+
gapTry.className = "opt-btn";
|
|
44489
|
+
gapTry.textContent = "\u8BA9\u5979\u73B0\u5728\u8BF4\u4E00\u53E5";
|
|
44490
|
+
gapTry.onclick = () => {
|
|
44491
|
+
gapTry.disabled = true;
|
|
44492
|
+
gapTry.textContent = "\u5728\u60F3\u2026";
|
|
44493
|
+
fetch(BASE + "/api/talk", { method: "POST" }).then((r2) => r2.json()).then((d2) => {
|
|
44494
|
+
gapTry.textContent = d2 && d2.ok ? "\u8BF4\u4E86" : "\u6CA1\u8BF4\u8BDD";
|
|
44495
|
+
}).catch(() => {
|
|
44496
|
+
gapTry.textContent = "\u6CA1\u8BF4\u8BDD";
|
|
44497
|
+
}).then(() => {
|
|
44498
|
+
setTimeout(() => {
|
|
44499
|
+
gapTry.disabled = false;
|
|
44500
|
+
gapTry.textContent = "\u8BA9\u5979\u73B0\u5728\u8BF4\u4E00\u53E5";
|
|
44501
|
+
}, 2400);
|
|
44502
|
+
});
|
|
44503
|
+
};
|
|
44452
44504
|
gapWrap.appendChild(gapSlider);
|
|
44453
44505
|
gapWrap.appendChild(gapLab);
|
|
44454
44506
|
gapWrap.appendChild(gapNote);
|
|
44507
|
+
gapWrap.appendChild(gapTry);
|
|
44455
44508
|
box.appendChild(gapWrap);
|
|
44456
44509
|
const h3 = document.createElement("h3");
|
|
44457
44510
|
h3.textContent = "\u8868\u60C5\u5305\uFF08\u6D4B\u8BD5\u529F\u80FD\uFF09";
|
|
@@ -44686,6 +44739,47 @@ void main(void)\r
|
|
|
44686
44739
|
await refresh(true);
|
|
44687
44740
|
$2("drawer").classList.remove("show");
|
|
44688
44741
|
}
|
|
44742
|
+
var IMG_POS = ["side", "above", "corner", "off"];
|
|
44743
|
+
var IMG_POS_LABELS = ["\u6587\u5B57\u5DE6\u8FB9", "\u6587\u5B57\u4E0A\u65B9", "\u5361\u7247\u5DE6\u4E0A\u89D2", "\u8BF4\u8BDD\u4E0D\u914D\u56FE"];
|
|
44744
|
+
function imgPos() {
|
|
44745
|
+
let v2 = "";
|
|
44746
|
+
try {
|
|
44747
|
+
v2 = localStorage.getItem("dsh-l2d-imgpos") || "";
|
|
44748
|
+
} catch {
|
|
44749
|
+
v2 = "";
|
|
44750
|
+
}
|
|
44751
|
+
return IMG_POS.indexOf(v2) >= 0 ? v2 : "side";
|
|
44752
|
+
}
|
|
44753
|
+
function setImgPos(v2) {
|
|
44754
|
+
try {
|
|
44755
|
+
localStorage.setItem("dsh-l2d-imgpos", v2);
|
|
44756
|
+
} catch {
|
|
44757
|
+
}
|
|
44758
|
+
}
|
|
44759
|
+
function hideSticker() {
|
|
44760
|
+
const st = $2("sticker");
|
|
44761
|
+
if (st) st.style.opacity = "0";
|
|
44762
|
+
}
|
|
44763
|
+
function placeImage(bubble, image) {
|
|
44764
|
+
const pos = imgPos();
|
|
44765
|
+
hideSticker();
|
|
44766
|
+
bubble.classList.toggle("img-above", pos === "above");
|
|
44767
|
+
bubble.classList.toggle("img-side", pos === "side");
|
|
44768
|
+
if (!image || pos === "off") return;
|
|
44769
|
+
const img = document.createElement("img");
|
|
44770
|
+
img.src = String(image);
|
|
44771
|
+
if (pos === "corner") {
|
|
44772
|
+
const st = $2("sticker");
|
|
44773
|
+
if (!st) return;
|
|
44774
|
+
img.className = "stk-img";
|
|
44775
|
+
st.innerHTML = "";
|
|
44776
|
+
st.appendChild(img);
|
|
44777
|
+
st.style.opacity = "1";
|
|
44778
|
+
return;
|
|
44779
|
+
}
|
|
44780
|
+
img.className = "bub-img";
|
|
44781
|
+
bubble.insertBefore(img, bubble.firstChild);
|
|
44782
|
+
}
|
|
44689
44783
|
function say(text, m2, image) {
|
|
44690
44784
|
if (m2) applyMood(m2);
|
|
44691
44785
|
const bubble = $2("bubble");
|
|
@@ -44693,14 +44787,11 @@ void main(void)\r
|
|
|
44693
44787
|
if (s2.length > 180) s2 = s2.slice(0, 178) + "\u2026";
|
|
44694
44788
|
bubble.textContent = "";
|
|
44695
44789
|
bubble.style.opacity = "1";
|
|
44790
|
+
lastSayAt = Date.now();
|
|
44696
44791
|
clearTimeout(sayFade);
|
|
44697
|
-
|
|
44698
|
-
const img = document.createElement("img");
|
|
44699
|
-
img.className = "bub-img";
|
|
44700
|
-
img.src = String(image);
|
|
44701
|
-
bubble.appendChild(img);
|
|
44702
|
-
}
|
|
44792
|
+
placeImage(bubble, image);
|
|
44703
44793
|
const holder = document.createElement("div");
|
|
44794
|
+
holder.className = "bub-txt";
|
|
44704
44795
|
bubble.appendChild(holder);
|
|
44705
44796
|
const chars = Array.from(s2);
|
|
44706
44797
|
let i2 = 0;
|
|
@@ -44711,6 +44802,7 @@ void main(void)\r
|
|
|
44711
44802
|
if (chars.length) blip(tone.base * 0.82, tone.dur * 1.6, tone.type);
|
|
44712
44803
|
sayFade = setTimeout(() => {
|
|
44713
44804
|
bubble.style.opacity = "0";
|
|
44805
|
+
hideSticker();
|
|
44714
44806
|
}, Math.min(14e3, 4e3 + chars.length * 110));
|
|
44715
44807
|
return;
|
|
44716
44808
|
}
|
|
@@ -44725,6 +44817,9 @@ void main(void)\r
|
|
|
44725
44817
|
}
|
|
44726
44818
|
var idleIdx = 0;
|
|
44727
44819
|
function idleTick() {
|
|
44820
|
+
const bubble = $2("bubble");
|
|
44821
|
+
if (Date.now() - lastSayAt < 45e3) return;
|
|
44822
|
+
if (bubble && bubble.style.opacity !== "0" && bubble.textContent.trim()) return;
|
|
44728
44823
|
const line = IDLE_LINES[idleIdx++ % IDLE_LINES.length];
|
|
44729
44824
|
if (line) say(line, mood);
|
|
44730
44825
|
}
|