dsh-dafeiyu-emotion 0.3.1 → 0.3.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/CHANGELOG.md +5 -0
- package/README.md +4 -3
- package/cordis.patch.yml +1 -0
- package/docs/MARKETPLACE.md +1 -1
- package/docs/RELEASE-0.3.2.md +15 -0
- package/lib/client.js +12 -1
- package/package.json +1 -1
- package/src/index.js +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
- Added `ttsOnlyAfterVoice` (default `true`): spoken replies are limited to assistant messages within two minutes of a voice input, so normal coding chats do not read every answer aloud.
|
|
6
|
+
- Added the matching settings toggle.
|
|
7
|
+
|
|
3
8
|
## 0.3.1
|
|
4
9
|
|
|
5
10
|
- Added spoken assistant replies. The host now forwards `assistant/message` text over `/plugins/dsh-dafeiyu-emotion/events`; the client plays it with TTS.
|
package/README.md
CHANGED
|
@@ -116,9 +116,9 @@ dsh plugin --profile desktop add github:LiDu-china/dsh-dafeiyu-emotion
|
|
|
116
116
|
### 通过 Release tarball
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
curl -L -o dsh-dafeiyu-emotion-0.3.
|
|
120
|
-
https://github.com/LiDu-china/dsh-dafeiyu-emotion/releases/download/v0.3.
|
|
121
|
-
dsh plugin --profile desktop add "D:/path/to/dsh-dafeiyu-emotion-0.3.
|
|
119
|
+
curl -L -o dsh-dafeiyu-emotion-0.3.2.tgz \
|
|
120
|
+
https://github.com/LiDu-china/dsh-dafeiyu-emotion/releases/download/v0.3.2/dsh-dafeiyu-emotion-0.3.2.tgz
|
|
121
|
+
dsh plugin --profile desktop add "D:/path/to/dsh-dafeiyu-emotion-0.3.2.tgz"
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
> DSH Desktop 的 profile 由 Electron 应用管理;命令行安装请使用桌面应用自带的 `dsh` 命令。
|
|
@@ -213,6 +213,7 @@ python -m pip install piper-tts
|
|
|
213
213
|
| `language` | `zh` | 识别语言:`zh` / `en` / `auto` |
|
|
214
214
|
| `empathyStyle` | `gentle` | 共情策略:`gentle` / `direct` / `humorous` / `concise` |
|
|
215
215
|
| `ttsEnabled` | `true` | 是否朗读大肥鱼回复 |
|
|
216
|
+
| `ttsOnlyAfterVoice` | `true` | 只朗读录音后两分钟内的回复 |
|
|
216
217
|
| `ttsEngine` | `piper` | `piper` 本地 / `edge` 在线 / `browser` 系统语音 |
|
|
217
218
|
| `ttsVoice` | `zh-CN-XiaoyiNeural` | Edge TTS 音色 |
|
|
218
219
|
| `ttsRate` | `+6%` | Piper/Edge 语速 |
|
package/cordis.patch.yml
CHANGED
package/docs/MARKETPLACE.md
CHANGED
|
@@ -72,7 +72,7 @@ https://github.com/LiDu-china/dsh-dafeiyu-emotion/releases/download/v0.2.3/dsh-d
|
|
|
72
72
|
dsh plugin --profile desktop add dsh-dafeiyu-emotion
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
Published as `dsh-dafeiyu-emotion@0.3.
|
|
75
|
+
Published as `dsh-dafeiyu-emotion@0.3.2` on npm. The 1024Store entry refreshes its one-click install automatically. GitHub-source and Release-tarball installs remain available as fallbacks.
|
|
76
76
|
|
|
77
77
|
## Privacy
|
|
78
78
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## 0.3.2
|
|
2
|
+
|
|
3
|
+
语音回复的体验收口。
|
|
4
|
+
|
|
5
|
+
- 新增 `ttsOnlyAfterVoice`,默认开启:只在录音后两分钟内的助手回复朗读。
|
|
6
|
+
- 普通代码对话、没有录音触发的回复不再自动朗读。
|
|
7
|
+
- 设置页新增「只朗读语音触发的回复」开关。
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
dsh plugin --profile desktop add dsh-dafeiyu-emotion
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
升级后请完全退出并重新启动 the agent harness。
|
package/lib/client.js
CHANGED
|
@@ -826,6 +826,7 @@ window.__ModuleLoader__.load({
|
|
|
826
826
|
|| draft.language !== config.language
|
|
827
827
|
|| draft.empathyStyle !== config.empathyStyle
|
|
828
828
|
|| draft.ttsEnabled !== config.ttsEnabled
|
|
829
|
+
|| draft.ttsOnlyAfterVoice !== config.ttsOnlyAfterVoice
|
|
829
830
|
|| draft.ttsEngine !== config.ttsEngine
|
|
830
831
|
|| draft.ttsVoice !== config.ttsVoice
|
|
831
832
|
|| draft.ttsRate !== config.ttsRate
|
|
@@ -839,7 +840,7 @@ window.__ModuleLoader__.load({
|
|
|
839
840
|
const save = async () => {
|
|
840
841
|
if (!config || !draft || saving) return
|
|
841
842
|
const patch = {}
|
|
842
|
-
for (const key of ['enabled', 'backendRoot', 'pythonPath', 'language', 'empathyStyle', 'ttsEnabled', 'ttsEngine', 'ttsVoice', 'ttsRate', 'ttsPitch', 'ttsPiperModel', 'maxAudioBytes', 'startupTimeoutMs', 'requestTimeoutMs']) {
|
|
843
|
+
for (const key of ['enabled', 'backendRoot', 'pythonPath', 'language', 'empathyStyle', 'ttsEnabled', 'ttsOnlyAfterVoice', 'ttsEngine', 'ttsVoice', 'ttsRate', 'ttsPitch', 'ttsPiperModel', 'maxAudioBytes', 'startupTimeoutMs', 'requestTimeoutMs']) {
|
|
843
844
|
if (draft[key] !== config[key]) patch[key] = draft[key]
|
|
844
845
|
}
|
|
845
846
|
if (Object.keys(patch).length === 0) return
|
|
@@ -1264,6 +1265,16 @@ window.__ModuleLoader__.load({
|
|
|
1264
1265
|
label: '朗读大肥鱼回复',
|
|
1265
1266
|
onChange: (value) => update('ttsEnabled', value),
|
|
1266
1267
|
})),
|
|
1268
|
+
h(SettingsField, {
|
|
1269
|
+
icon: 'spark',
|
|
1270
|
+
label: '只朗读语音触发的回复',
|
|
1271
|
+
hint: '开启后只朗读录音后两分钟内的回复;关闭后所有助手回复都会朗读。',
|
|
1272
|
+
}, h(SettingsSwitch, {
|
|
1273
|
+
checked: draft.ttsOnlyAfterVoice !== false,
|
|
1274
|
+
disabled: disabled || draft.ttsEnabled !== true,
|
|
1275
|
+
label: '只朗读语音触发的回复',
|
|
1276
|
+
onChange: (value) => update('ttsOnlyAfterVoice', value),
|
|
1277
|
+
})),
|
|
1267
1278
|
h(SettingsField, {
|
|
1268
1279
|
icon: 'spark',
|
|
1269
1280
|
label: '合成引擎',
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -31,6 +31,7 @@ const DEFAULTS = Object.freeze({
|
|
|
31
31
|
requestTimeoutMs: 180000,
|
|
32
32
|
empathyStyle: 'gentle',
|
|
33
33
|
ttsEnabled: true,
|
|
34
|
+
ttsOnlyAfterVoice: true,
|
|
34
35
|
ttsEngine: 'piper',
|
|
35
36
|
ttsVoice: 'zh-CN-XiaoyiNeural',
|
|
36
37
|
ttsRate: '+6%',
|
|
@@ -80,6 +81,7 @@ export const Config = Schema.object({
|
|
|
80
81
|
Schema.const('concise').description('简洁'),
|
|
81
82
|
]).default('gentle').description('共情策略').volatile(),
|
|
82
83
|
ttsEnabled: Schema.boolean().default(true).description('朗读大肥鱼回复').volatile(),
|
|
84
|
+
ttsOnlyAfterVoice: Schema.boolean().default(true).description('只朗读语音触发的回复').volatile(),
|
|
83
85
|
ttsEngine: Schema.union([
|
|
84
86
|
Schema.const('piper').description('Piper 本地模型(推荐)'),
|
|
85
87
|
Schema.const('edge').description('Edge TTS(更好听,需要网络)'),
|
|
@@ -464,6 +466,7 @@ function resolveOptions(raw = {}) {
|
|
|
464
466
|
? value.empathyStyle
|
|
465
467
|
: DEFAULTS.empathyStyle,
|
|
466
468
|
ttsEnabled: value.ttsEnabled === true,
|
|
469
|
+
ttsOnlyAfterVoice: value.ttsOnlyAfterVoice !== false,
|
|
467
470
|
ttsEngine: ['piper', 'edge', 'browser'].includes(value.ttsEngine) ? value.ttsEngine : DEFAULTS.ttsEngine,
|
|
468
471
|
ttsVoice: String(value.ttsVoice || DEFAULTS.ttsVoice).trim(),
|
|
469
472
|
ttsRate: String(value.ttsRate || DEFAULTS.ttsRate).trim(),
|
|
@@ -485,6 +488,7 @@ function publicConfig(options, writable = false) {
|
|
|
485
488
|
language: options.language || DEFAULTS.language,
|
|
486
489
|
empathyStyle: options.empathyStyle || DEFAULTS.empathyStyle,
|
|
487
490
|
ttsEnabled: options.ttsEnabled === true,
|
|
491
|
+
ttsOnlyAfterVoice: options.ttsOnlyAfterVoice !== false,
|
|
488
492
|
ttsEngine: options.ttsEngine || DEFAULTS.ttsEngine,
|
|
489
493
|
ttsVoice: options.ttsVoice || DEFAULTS.ttsVoice,
|
|
490
494
|
ttsRate: options.ttsRate || DEFAULTS.ttsRate,
|
|
@@ -530,6 +534,11 @@ function normalizeConfigPatch(value) {
|
|
|
530
534
|
patch.ttsEnabled = next
|
|
531
535
|
continue
|
|
532
536
|
}
|
|
537
|
+
if (key === 'ttsOnlyAfterVoice') {
|
|
538
|
+
if (typeof next !== 'boolean') throw new HttpError(400, 'ttsOnlyAfterVoice 必须是布尔值')
|
|
539
|
+
patch.ttsOnlyAfterVoice = next
|
|
540
|
+
continue
|
|
541
|
+
}
|
|
533
542
|
if (key === 'ttsEngine') {
|
|
534
543
|
const engine = String(next || '').trim().toLowerCase()
|
|
535
544
|
if (!['piper', 'edge', 'browser'].includes(engine)) {
|
|
@@ -1358,6 +1367,7 @@ function createAnalyzeHandler(runtime, backend, getSpeechToText) {
|
|
|
1358
1367
|
}
|
|
1359
1368
|
runtime.lastAudioBytes = buffer.length
|
|
1360
1369
|
runtime.lastAnalysisAt = runtime.lastAnalysis.at
|
|
1370
|
+
runtime.lastVoiceAt = Date.now()
|
|
1361
1371
|
jsonResponse(res, 200, analysis)
|
|
1362
1372
|
} catch (error) {
|
|
1363
1373
|
if (controller?.signal.aborted || res.writableEnded) return
|
|
@@ -1390,6 +1400,7 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
1390
1400
|
// shared runtime object and settings.update persists it for the next boot.
|
|
1391
1401
|
options: resolveOptions(rawConfig),
|
|
1392
1402
|
lastAnalysis: null,
|
|
1403
|
+
lastVoiceAt: null,
|
|
1393
1404
|
lastAudioBytes: 0,
|
|
1394
1405
|
lastAnalysisAt: null,
|
|
1395
1406
|
lastCleanupAt: null,
|
|
@@ -1413,6 +1424,8 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
1413
1424
|
try {
|
|
1414
1425
|
const off = sessionCtx.on?.('session/event', (session, event) => {
|
|
1415
1426
|
if (event?.type !== 'assistant/message' || !runtime.options.ttsEnabled) return
|
|
1427
|
+
if (runtime.options.ttsOnlyAfterVoice
|
|
1428
|
+
&& (!runtime.lastVoiceAt || Date.now() - runtime.lastVoiceAt > 120000)) return
|
|
1416
1429
|
const text = cleanForSpeech(assistantTextFromEvent(event))
|
|
1417
1430
|
if (!text) return
|
|
1418
1431
|
speechStream.broadcast({
|
|
@@ -1453,6 +1466,7 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
1453
1466
|
language: options.language,
|
|
1454
1467
|
empathyStyle: options.empathyStyle,
|
|
1455
1468
|
ttsEnabled: options.ttsEnabled,
|
|
1469
|
+
ttsOnlyAfterVoice: options.ttsOnlyAfterVoice,
|
|
1456
1470
|
ttsEngine: options.ttsEngine,
|
|
1457
1471
|
ttsVoice: options.ttsVoice,
|
|
1458
1472
|
ttsReady: ttsReady(options),
|
|
@@ -1471,6 +1485,7 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
1471
1485
|
privacy: {
|
|
1472
1486
|
lastAudioBytes: runtime.lastAudioBytes,
|
|
1473
1487
|
lastAnalysisAt: runtime.lastAnalysisAt,
|
|
1488
|
+
lastVoiceAt: runtime.lastVoiceAt,
|
|
1474
1489
|
lastCleanupAt: runtime.lastCleanupAt,
|
|
1475
1490
|
workerPid: backendStatus.pid,
|
|
1476
1491
|
modelLoadMs: backendStatus.modelLoadMs,
|