dsh-live2dwaifu 1.3.1 → 2.0.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 CHANGED
@@ -380,6 +380,20 @@ curl -X POST http://127.0.0.1:<端口>/dsh-live2d/api/push \
380
380
 
381
381
  版本号怎么走:动了功能和结构就抬第二位(1.2.0),只补洞和小修就抬第三位(1.2.1)。
382
382
 
383
+ ### 2.0.0
384
+
385
+ - 修:`ISOLATION` 这个变量在 1.3.0 被误删,`/api/chat` 全部返回 500——那之后她其实一句都说不出来。这是这版最主要的问题。
386
+ - 修:补回 1.3.1 里漏掉的语料接口(之前保存语料会 404)。
387
+ - 修:调音页的下拉框改成只试听,不再顺手把正在显示的模型换掉;要换模型另点「切到这只模型」。
388
+ - 修:卡片位置存在本机,窗口缩小后可能跑到屏幕外,现在重开时自动收回可见范围。
389
+ - 修:页面切到后台时暂停轮询,不再空跑请求。
390
+ - 修:所有接受模型 id 的接口加了字符校验,避免拼出奇怪路径。
391
+ - 改:对话要求补一条——不要每句都反问,不要用「哈哈」「嗯嗯」凑字数。
392
+ - 清:删掉几个没用到的常量、开关和恒真判断。
393
+
394
+ <details>
395
+ <summary>2.0.0 之前的记录(黑历史,留着自嘲)</summary>
396
+
383
397
  ### 1.3.1
384
398
 
385
399
  - 修:语料接口整个漏掉了(页面打得开,存不进去,返回 404)。补回来。
@@ -457,6 +471,8 @@ curl -X POST http://127.0.0.1:<端口>/dsh-live2d/api/push \
457
471
  - 人设卡编辑页、音色调色页。
458
472
  - 对外接口:`/api/chat`、`/api/push`、`/api/poll`。
459
473
 
474
+ </details>
475
+
460
476
  ## 反馈
461
477
 
462
478
  遇到问题、想要新功能、觉得哪句话还是像 AI,都可以写信到 **FujiwaraReisen@outlook.com**。
@@ -147,11 +147,10 @@
147
147
  var said = unquote(m[2]);
148
148
  if (!said) continue;
149
149
  if (USERS.test(who)) { pending = said; continue; }
150
- if (HERS.test(who) || true) {
151
- pairs.push({ user: pending || '', assistant: said });
152
- pending = null;
153
- continue;
154
- }
150
+ // 不是「他/我/用户」的说话人,一律当角色
151
+ pairs.push({ user: pending || '', assistant: said });
152
+ pending = null;
153
+ continue;
155
154
  }
156
155
  var t = unquote(line);
157
156
  if (t) lines.push(t);
@@ -71,6 +71,7 @@
71
71
  // 主动开口也收着
72
72
  var seq = null;
73
73
  setInterval(function () {
74
+ if (document.hidden) return;
74
75
  fetch('/dsh-live2d/api/poll?since=' + (seq === null ? 0 : seq))
75
76
  .then(function (r) { return r.json(); })
76
77
  .then(function (d) {
package/assets/tone.html CHANGED
@@ -91,6 +91,7 @@
91
91
 
92
92
  <div class="foot">
93
93
  <button class="act primary" id="save">保存</button>
94
+ <button class="act" id="useModel">切到这只模型</button>
94
95
  <button class="act" id="reset">恢复默认</button>
95
96
  <span class="state" id="state"></span>
96
97
  </div>
@@ -205,21 +206,27 @@
205
206
 
206
207
  sel.addEventListener('change', function () {
207
208
  modelId = sel.value;
208
- loadVoice(true);
209
+ loadVoice();
209
210
  });
210
211
 
211
- function loadVoice(alsoSwitch) {
212
+ $('useModel').addEventListener('click', function () {
212
213
  if (!modelId) return;
213
- state.textContent = '读取中';
214
- if (alsoSwitch) {
215
- fetch('/dsh-live2d/api/select', {
216
- method: 'POST',
217
- headers: { 'content-type': 'application/json' },
218
- body: JSON.stringify({ id: modelId })
219
- }).then(function () {
214
+ state.textContent = '切换中';
215
+ fetch('/dsh-live2d/api/select', {
216
+ method: 'POST',
217
+ headers: { 'content-type': 'application/json' },
218
+ body: JSON.stringify({ id: modelId })
219
+ })
220
+ .then(function () {
220
221
  frame.src = '/dsh-live2d/viewer?embed=1&t=' + Date.now();
221
- });
222
- }
222
+ state.textContent = '已切换';
223
+ })
224
+ .catch(function (e) { state.textContent = '切换失败:' + e.message; });
225
+ });
226
+
227
+ function loadVoice() {
228
+ if (!modelId) return;
229
+ state.textContent = '读取中';
223
230
  fetch('/dsh-live2d/api/voice?id=' + encodeURIComponent(modelId))
224
231
  .then(function (r) { return r.json(); })
225
232
  .then(function (d) {
@@ -249,7 +256,7 @@
249
256
  state.textContent = '尚未导入模型';
250
257
  return;
251
258
  }
252
- loadVoice(false);
259
+ loadVoice();
253
260
  })
254
261
  .catch(function (e) { state.textContent = '读取模型列表失败:' + e.message; });
255
262
 
package/assets/viewer.js CHANGED
@@ -44358,7 +44358,6 @@ void main(void)\r
44358
44358
  follow: "\u804A\u5929\u7A97\u53E3\u51FA\u73B0\u65B0\u56DE\u590D\u65F6\uFF0C\u7531\u89D2\u8272\u5FF5\u51FA\u6765"
44359
44359
  };
44360
44360
  var SERVER_HINT = {
44361
- proactive: "\u4E00\u6BB5\u65F6\u95F4\u6CA1\u4EBA\u8BF4\u8BDD\uFF0C\u89D2\u8272\u81EA\u5DF1\u5F00\u4E00\u53E5",
44362
44361
  choices: "\u89D2\u8272\u89C9\u5F97\u9700\u8981\u9009\u62E9\u65F6\uFF0C\u6C14\u6CE1\u4E0A\u65B9\u51FA\u73B0\u53EF\u70B9\u7684\u6309\u94AE",
44363
44362
  memory: "\u4FDD\u7559\u804A\u8FC7\u7684\u5185\u5BB9\uFF0C\u4E0B\u6B21\u63A5\u7740\u804A\uFF08\u5360\u66F4\u591A\u6A21\u578B\u989D\u5EA6\uFF09"
44364
44363
  };
package/lib/client.js CHANGED
@@ -121,6 +121,16 @@
121
121
  react.useEffect(() => localStorage.setItem('dsh-l2d-bg', bg), [bg]);
122
122
  react.useEffect(() => localStorage.setItem('dsh-l2d-size', JSON.stringify(size)), [size]);
123
123
  react.useEffect(() => localStorage.setItem('dsh-l2d-pos', JSON.stringify(pos)), [pos]);
124
+ react.useEffect(() => {
125
+ setPos((p) => {
126
+ const w = size.w;
127
+ const h = open ? size.h : 38;
128
+ const x = Math.max(-w + 90, Math.min(window.innerWidth - 90, p.x));
129
+ const y = Math.max(-h + 50, Math.min(window.innerHeight - 50, p.y));
130
+ return x === p.x && y === p.y ? p : { x, y };
131
+ });
132
+ // eslint-disable-next-line react-hooks/exhaustive-deps
133
+ }, []);
124
134
  react.useEffect(() => {
125
135
  frameWin = (ref.current && ref.current.contentWindow) || null;
126
136
  }, [nonce, open]);
@@ -128,7 +138,7 @@
128
138
  let seq = null;
129
139
  let stop = false;
130
140
  const tick = () => {
131
- if (stop) return;
141
+ if (stop || document.hidden) return;
132
142
  fetch(BASE + '/api/poll?since=' + (seq === null ? 0 : seq))
133
143
  .then((r) => r.json())
134
144
  .then((d) => {
package/lib/index.js CHANGED
@@ -24,7 +24,6 @@ const MEME_TAGS = {
24
24
  };
25
25
 
26
26
  const DEFAULT_SETTINGS = {
27
- proactive: true,
28
27
  /** 多久没人说话才自己开口,单位分钟;0 = 关闭 */
29
28
  proactiveInterval: 30,
30
29
  /** off | own | both | external —— 测试功能,默认关 */
@@ -175,6 +174,13 @@ const TALK_SAMPLES = [
175
174
  '他:明天要早起 —— 你:那我今晚早点关灯。',
176
175
  ].join('\n');
177
176
 
177
+ /** 世界隔离:不说破自己在哪儿 */
178
+ const ISOLATION = [
179
+ '【世界隔离】你不知道什么是程序、界面、插件、模型、参数。',
180
+ '有人问起,你就当他就站在你身边。不要提“系统”“设置”“网页”“token”这些词。',
181
+ '你不知道他那边什么样,得他讲给你听。',
182
+ ].join('\n');
183
+
178
184
  /** 语料:lines = 她的台词,pairs = 一问一答 */
179
185
  function readCorpus(id) {
180
186
  try {
@@ -404,7 +410,6 @@ async function generate(slot, prompt, limit = 900) {
404
410
  }
405
411
 
406
412
  /* ── 主动开口:没人说话,她自己开一句 ─────────────────────── */
407
- const IDLE_MS = 12 * 60 * 1000;
408
413
  let lastAutoAt = 0;
409
414
 
410
415
  async function maybeTalk(ctx) {
@@ -523,7 +528,12 @@ function findModel3(dir) {
523
528
  return out[0];
524
529
  }
525
530
 
531
+ function validId(id) {
532
+ return /^[\w.-]+$/.test(String(id || ''));
533
+ }
534
+
526
535
  function readMeta(id) {
536
+ if (!validId(id)) return null;
527
537
  try {
528
538
  return JSON.parse(readFileSync(join(MODELS, id, 'meta.json'), 'utf8'));
529
539
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-live2dwaifu",
3
- "version": "1.3.1",
3
+ "version": "2.0.0",
4
4
  "description": "给 DSH 网页右下角请一个 Live2D 角色:会眨眼、会呼吸、视线跟着鼠标、点她有反应、说话时嘴动、心情变了眉毛跟着动。模型不用内置——谁装谁放自己的文件夹;支持自定义 .exp3.json 表情和 .motion3.json 动作,卡片能拖能缩,背景可换。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",