dsh-voice-say 0.6.0 → 0.6.2

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/client.js CHANGED
@@ -465,6 +465,7 @@ window.__ModuleLoader__.load({
465
465
  directRes.elapsedMs ? `· ${(directRes.elapsedMs / 1000).toFixed(1)} 秒` : '',
466
466
  directRes.cached ? '· 命中缓存' : '',
467
467
  directRes.transport === 'dsh' ? '· 在 DeepSeek 窗口里想的' : '',
468
+ directRes.transport === 'api-fallback' ? '· 会话没走通,已退回直连' : '',
468
469
  ].filter(Boolean).join(' ')),
469
470
  directRes.sessionId ? h('div', { 'data-vs-sub': '', 'data-vs-mono': '' }, `会话:${directRes.sessionId}`) : null,
470
471
  directRes.notes ? h('div', { 'data-vs-sub': '' }, `导演说明:${directRes.notes}`) : null,
package/index.js CHANGED
@@ -32,7 +32,7 @@ import { direct as directText, gatherContext, probeDirector, clearCache as clear
32
32
  export const name = 'dsh-voice-say'
33
33
  export const inject = ['webServer', 'tools']
34
34
 
35
- const PLUGIN_VERSION = '0.6.0'
35
+ const PLUGIN_VERSION = '0.6.2'
36
36
  const DEFAULT_INSTRUCTIONS = '说话自然一点,带点傲娇和不耐烦,别太热情。'
37
37
  const DEFAULT_PREVIEW_TEXT = '哼,才不是特意来跟你说话的呢,笨蛋。'
38
38
  const MAX_BODY = 32 * 1024 * 1024
@@ -59,6 +59,10 @@ export async function apply(ctx, config = {}) {
59
59
  const uiConfigFile = path.join(dataRoot, 'config.json')
60
60
  const outDir = ensureDir(path.join(dataRoot, 'out'))
61
61
 
62
+ // 最近一次「网页/桥接是从哪个地址访问到我的」。DSH 的端口每次重启都会变,
63
+ // 记下来就不必依赖外部配置文件去猜——导演台直接用这个地址去连自己的 GUI。
64
+ let lastSeenHost = ''
65
+
62
66
  /** 生效配置:patch config + 数据根 config.json 覆盖 */
63
67
  function cfg() {
64
68
  const base = {
@@ -106,6 +110,11 @@ export async function apply(ctx, config = {}) {
106
110
  merged.guidanceScale = Number.isFinite(g) ? Math.min(Math.max(g, 1), 3) : 1
107
111
  merged.instructions = String(merged.instructions ?? '').trim()
108
112
  merged.styles = pickStyles(merged.styles).map((s) => s.id)
113
+ // 没显式配 DSH 地址时,用「刚刚访问到我的那个地址」——这就是当前 GUI 的真实端口
114
+ if (lastSeenHost) {
115
+ const d = merged.director && typeof merged.director === 'object' ? merged.director : {}
116
+ if (!d.dshBaseUrl) merged.director = { ...d, dshBaseUrl: `http://${lastSeenHost}` }
117
+ }
109
118
  return merged
110
119
  }
111
120
 
@@ -576,6 +585,12 @@ export async function apply(ctx, config = {}) {
576
585
  path: '/api/voice-say',
577
586
  handler: async (req, res) => {
578
587
  if (!sameOrigin(req)) { sendJson(res, 403, { ok: false, error: '只接受本机同源请求' }); return }
588
+ // 顺手记下「网页是从哪个地址访问到我的」——DSH 的端口每次重启都会变,
589
+ // 有了这个就能自己去找到同进程的 GUI,不用等 QQ 桥接更新配置。
590
+ try {
591
+ const h = String(req.headers.host || '')
592
+ if (/^(127\.0\.0\.1|localhost|\[::1\]):\d+$/.test(h)) lastSeenHost = h
593
+ } catch { /* 记不下来就算了 */ }
579
594
  try {
580
595
  const url = new URL(req.url, 'http://127.0.0.1')
581
596
  const sub = url.pathname.replace(/^\/api\/voice-say\/?/, '').replace(/\/+$/, '')
package/lib/director.mjs CHANGED
@@ -453,10 +453,20 @@ async function askModel(o, key, messages, extraNote, ctx = {}) {
453
453
  const full = extraNote ? [...messages, { role: 'user', content: extraNote }] : messages
454
454
  if (o.transport === 'dsh') {
455
455
  const dsh = o.dsh
456
- if (!dsh.ready) throw new Error(dsh.baseUrl ? 'DSH 会话通道不可用(读不到会话密钥)' : '找不到 DSH 地址(桥接没记下 baseUrl,可在设置里填 dshBaseUrl)')
457
- const r = await askSession(dsh, { text: messagesToText(full), hooks: ctx.hooks })
458
- if (!r.ok) throw new Error(r.error || 'DSH 会话没回话')
459
- return { content: r.text, elapsedMs: r.elapsedMs, transport: 'dsh', sessionId: r.sessionId }
456
+ const why = !dsh.baseUrl
457
+ ? '找不到 DSH 地址(桥接没记下 baseUrl,可在设置里填 dshBaseUrl)'
458
+ : (!dsh.hasSecret ? '读不到 DSH 会话密钥(~/.dsh/.credentials.yaml)' : '')
459
+ if (!why) {
460
+ const r = await askSession(dsh, { text: messagesToText(full), hooks: ctx.hooks })
461
+ if (r.ok) return { content: r.text, elapsedMs: r.elapsedMs, transport: 'dsh', sessionId: r.sessionId }
462
+ if (!key) throw new Error(r.error || 'DSH 会话没回话')
463
+ // 会话这条走不通、但手里有 key —— 悄悄退到直连,别让人听不到声音
464
+ const out = await callModel(o, key, full)
465
+ return { ...out, transport: 'api-fallback', sessionId: '', fallbackReason: r.error || '' }
466
+ }
467
+ if (!key) throw new Error(why)
468
+ const out = await callModel(o, key, full)
469
+ return { ...out, transport: 'api-fallback', sessionId: '', fallbackReason: why }
460
470
  }
461
471
  const out = await callModel(o, key, full)
462
472
  return { ...out, transport: 'api', sessionId: '' }
@@ -527,6 +537,7 @@ export async function direct(cfg = {}, input = {}) {
527
537
  let parsed = parseReply(out.content)
528
538
  result.elapsedMs = out.elapsedMs
529
539
  if (out.transport) result.transport = out.transport
540
+ if (out.fallbackReason) result.fallbackReason = out.fallbackReason
530
541
  if (out.sessionId) {
531
542
  result.sessionId = out.sessionId
532
543
  o.dsh.sessionId = out.sessionId // 重试沿用同一个窗口,别又开一个
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "dsh-voice-say",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "type": "module",
5
- "description": "dsh-voice-say:把一句话合成语音。两条通道(本地 Breeze TTS 2 / 云端 apiKey+voiceId)共用 instructions + guidanceScale;18 个风格可叠加;合成前由「读音导演」重排标点——默认在 DeepSeek 窗口里的专用会话里想,按人设、当下情绪与对话情节断句;支持上传本地音色、自定义参考音频与试听片段。QQ 桥接会先问插件,群里发出去的语音与设置页试听同源同风格。",
5
+ "description": "dsh-voice-say:把一句话合成语音。两条通道(本地 Breeze TTS 2 / 云端 apiKey+voiceId)共用 instructions + guidanceScale;18 个风格可叠加;合成前由「读音导演」重排标点——默认在 DeepSeek 窗口里的专用会话里想,按人设、当下情绪与对话情节断句;支持上传本地音色、自定义参考音频与试听片段。QQ 桥接会先问插件,群里发出去的语音与设置页试听同源同风格。 导演台连不上时自动改用「当前访问地址」自愈。",
6
6
  "license": "MIT",
7
7
  "author": "dsh-voice-say contributors",
8
8
  "keywords": [