@downcity/plugins 1.0.56 → 1.0.59
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/bin/BuiltinPlugins.d.ts.map +1 -1
- package/bin/BuiltinPlugins.js +0 -6
- package/bin/BuiltinPlugins.js.map +1 -1
- package/bin/asr/Plugin.d.ts +67 -7
- package/bin/asr/Plugin.d.ts.map +1 -1
- package/bin/asr/Plugin.js +229 -461
- package/bin/asr/Plugin.js.map +1 -1
- package/bin/asr/types/AsrPlugin.d.ts +114 -0
- package/bin/asr/types/AsrPlugin.d.ts.map +1 -0
- package/bin/asr/types/AsrPlugin.js +10 -0
- package/bin/asr/types/AsrPlugin.js.map +1 -0
- package/bin/auth/types/AuthPlugin.d.ts +12 -16
- package/bin/auth/types/AuthPlugin.d.ts.map +1 -1
- package/bin/auth/types/AuthPlugin.js +9 -13
- package/bin/auth/types/AuthPlugin.js.map +1 -1
- package/bin/chat/ChatPlugin.d.ts +37 -6
- package/bin/chat/ChatPlugin.d.ts.map +1 -1
- package/bin/chat/ChatPlugin.js +58 -80
- package/bin/chat/ChatPlugin.js.map +1 -1
- package/bin/chat/Index.d.ts +4 -1
- package/bin/chat/Index.d.ts.map +1 -1
- package/bin/chat/Index.js +2 -1
- package/bin/chat/Index.js.map +1 -1
- package/bin/chat/channels/Configuration.d.ts +1 -1
- package/bin/chat/channels/Configuration.js +1 -1
- package/bin/chat/channels/RuntimeChannel.d.ts +145 -0
- package/bin/chat/channels/RuntimeChannel.d.ts.map +1 -0
- package/bin/chat/channels/RuntimeChannel.js +148 -0
- package/bin/chat/channels/RuntimeChannel.js.map +1 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.d.ts +22 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.d.ts.map +1 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.js +189 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.js.map +1 -0
- package/bin/chat/runtime/ChatChannelActions.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelActions.js +19 -9
- package/bin/chat/runtime/ChatChannelActions.js.map +1 -1
- package/bin/chat/runtime/ChatChannelConfig.d.ts +2 -18
- package/bin/chat/runtime/ChatChannelConfig.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelConfig.js +2 -73
- package/bin/chat/runtime/ChatChannelConfig.js.map +1 -1
- package/bin/chat/runtime/ChatChannelCore.d.ts +22 -1
- package/bin/chat/runtime/ChatChannelCore.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelCore.js +5 -5
- package/bin/chat/runtime/ChatChannelCore.js.map +1 -1
- package/bin/chat/runtime/ChatPluginActionRegistry.js +1 -1
- package/bin/chat/runtime/ChatPluginActionRegistry.js.map +1 -1
- package/bin/chat/runtime/PluginPoints.d.ts +3 -3
- package/bin/chat/runtime/PluginPoints.js +3 -3
- package/bin/chat/types/ChannelStatus.d.ts +1 -1
- package/bin/chat/types/ChatPluginOptions.d.ts +76 -0
- package/bin/chat/types/ChatPluginOptions.d.ts.map +1 -0
- package/bin/chat/types/ChatPluginOptions.js +10 -0
- package/bin/chat/types/ChatPluginOptions.js.map +1 -0
- package/bin/image/ImagePlugin.d.ts +1 -1
- package/bin/image/ImagePlugin.d.ts.map +1 -1
- package/bin/image/ImagePlugin.js +23 -5
- package/bin/image/ImagePlugin.js.map +1 -1
- package/bin/index.d.ts +6 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +2 -2
- package/bin/index.js.map +1 -1
- package/bin/skill/Action.d.ts.map +1 -1
- package/bin/skill/Action.js +2 -2
- package/bin/skill/Action.js.map +1 -1
- package/bin/skill/Command.js +5 -5
- package/bin/skill/Command.js.map +1 -1
- package/bin/skill/Plugin.js +1 -1
- package/bin/skill/Plugin.js.map +1 -1
- package/bin/skill/runtime/Discovery.d.ts +4 -4
- package/bin/skill/runtime/Discovery.d.ts.map +1 -1
- package/bin/skill/runtime/Discovery.js +5 -5
- package/bin/skill/runtime/Discovery.js.map +1 -1
- package/bin/skill/runtime/Paths.d.ts +1 -5
- package/bin/skill/runtime/Paths.d.ts.map +1 -1
- package/bin/skill/runtime/Paths.js +1 -9
- package/bin/skill/runtime/Paths.js.map +1 -1
- package/bin/skill/runtime/Prompt.d.ts +2 -2
- package/bin/skill/runtime/Prompt.d.ts.map +1 -1
- package/bin/skill/runtime/Prompt.js +3 -3
- package/bin/skill/runtime/Prompt.js.map +1 -1
- package/bin/skill/runtime/Store.d.ts +2 -2
- package/bin/skill/runtime/Store.d.ts.map +1 -1
- package/bin/skill/runtime/Store.js.map +1 -1
- package/bin/skill/runtime/SystemProvider.js +4 -4
- package/bin/skill/runtime/SystemProvider.js.map +1 -1
- package/bin/skill/runtime/Types.d.ts +3 -3
- package/bin/skill/runtime/Types.d.ts.map +1 -1
- package/bin/skill/types/{ClaudeSkill.d.ts → SkillDefinition.d.ts} +4 -4
- package/bin/skill/types/SkillDefinition.d.ts.map +1 -0
- package/bin/skill/types/{ClaudeSkill.js → SkillDefinition.js} +2 -2
- package/bin/skill/types/SkillDefinition.js.map +1 -0
- package/bin/skill/types/SkillPlugin.d.ts +2 -2
- package/bin/skill/types/SkillPlugin.d.ts.map +1 -1
- package/bin/tts/Plugin.d.ts +53 -6
- package/bin/tts/Plugin.d.ts.map +1 -1
- package/bin/tts/Plugin.js +197 -474
- package/bin/tts/Plugin.js.map +1 -1
- package/bin/tts/types/TtsPlugin.d.ts +63 -102
- package/bin/tts/types/TtsPlugin.d.ts.map +1 -1
- package/bin/tts/types/TtsPlugin.js +4 -3
- package/bin/tts/types/TtsPlugin.js.map +1 -1
- package/bin/web/PROMPT.d.ts +1 -1
- package/bin/web/PROMPT.d.ts.map +1 -1
- package/bin/web/PROMPT.js +1 -1
- package/bin/web/PROMPT.js.map +1 -1
- package/bin/web/Plugin.d.ts +66 -5
- package/bin/web/Plugin.d.ts.map +1 -1
- package/bin/web/Plugin.js +126 -450
- package/bin/web/Plugin.js.map +1 -1
- package/bin/web/WebPromptAssets.d.ts +1 -9
- package/bin/web/WebPromptAssets.d.ts.map +1 -1
- package/bin/web/WebPromptAssets.js +1 -11
- package/bin/web/WebPromptAssets.js.map +1 -1
- package/bin/web/runtime/Install.d.ts +19 -0
- package/bin/web/runtime/Install.d.ts.map +1 -0
- package/bin/web/runtime/Install.js +178 -0
- package/bin/web/runtime/Install.js.map +1 -0
- package/bin/web/types/WebPlugin.d.ts +38 -109
- package/bin/web/types/WebPlugin.d.ts.map +1 -1
- package/bin/web/types/WebPlugin.js +5 -7
- package/bin/web/types/WebPlugin.js.map +1 -1
- package/bin/workboard/Plugin.d.ts +23 -3
- package/bin/workboard/Plugin.d.ts.map +1 -1
- package/bin/workboard/Plugin.js +66 -85
- package/bin/workboard/Plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/BuiltinPlugins.ts +0 -6
- package/src/asr/Plugin.ts +264 -483
- package/src/asr/types/AsrPlugin.ts +118 -0
- package/src/auth/types/AuthPlugin.ts +12 -17
- package/src/chat/ChatPlugin.ts +92 -89
- package/src/chat/Index.ts +18 -1
- package/src/chat/channels/Configuration.ts +1 -1
- package/src/chat/channels/RuntimeChannel.ts +264 -0
- package/src/chat/runtime/ChatAuthorizationRuntime.ts +229 -0
- package/src/chat/runtime/ChatChannelActions.ts +24 -9
- package/src/chat/runtime/ChatChannelConfig.ts +2 -100
- package/src/chat/runtime/ChatChannelCore.ts +20 -8
- package/src/chat/runtime/ChatPluginActionRegistry.ts +1 -1
- package/src/chat/runtime/PluginPoints.ts +3 -3
- package/src/chat/types/ChannelStatus.ts +1 -1
- package/src/chat/types/ChatPluginOptions.ts +79 -0
- package/src/image/ImagePlugin.ts +23 -5
- package/src/index.ts +29 -6
- package/src/skill/Action.ts +10 -7
- package/src/skill/Command.ts +5 -5
- package/src/skill/Plugin.ts +1 -1
- package/src/skill/runtime/Discovery.ts +14 -11
- package/src/skill/runtime/Paths.ts +1 -13
- package/src/skill/runtime/Prompt.ts +5 -5
- package/src/skill/runtime/Store.ts +6 -3
- package/src/skill/runtime/SystemProvider.ts +4 -4
- package/src/skill/runtime/Types.ts +3 -3
- package/src/skill/types/{ClaudeSkill.ts → SkillDefinition.ts} +3 -3
- package/src/skill/types/SkillPlugin.ts +2 -2
- package/src/tts/Plugin.ts +225 -492
- package/src/tts/types/TtsPlugin.ts +67 -102
- package/src/web/PROMPT.ts +1 -1
- package/src/web/PROMPT.ts.txt +32 -6
- package/src/web/Plugin.ts +119 -453
- package/src/web/WebPromptAssets.ts +1 -13
- package/src/web/runtime/Install.ts +241 -0
- package/src/web/types/WebPlugin.ts +38 -114
- package/src/workboard/Plugin.ts +80 -95
- package/bin/asr/Config.d.ts +0 -43
- package/bin/asr/Config.d.ts.map +0 -1
- package/bin/asr/Config.js +0 -107
- package/bin/asr/Config.js.map +0 -1
- package/bin/asr/Dependency.d.ts +0 -77
- package/bin/asr/Dependency.d.ts.map +0 -1
- package/bin/asr/Dependency.js +0 -238
- package/bin/asr/Dependency.js.map +0 -1
- package/bin/asr/InboundAugment.d.ts +0 -17
- package/bin/asr/InboundAugment.d.ts.map +0 -1
- package/bin/asr/InboundAugment.js +0 -47
- package/bin/asr/InboundAugment.js.map +0 -1
- package/bin/asr/ModelCatalog.d.ts +0 -29
- package/bin/asr/ModelCatalog.d.ts.map +0 -1
- package/bin/asr/ModelCatalog.js +0 -25
- package/bin/asr/ModelCatalog.js.map +0 -1
- package/bin/auth/Plugin.d.ts +0 -17
- package/bin/auth/Plugin.d.ts.map +0 -1
- package/bin/auth/Plugin.js +0 -199
- package/bin/auth/Plugin.js.map +0 -1
- package/bin/chat/ChatPluginTypes.d.ts +0 -122
- package/bin/chat/ChatPluginTypes.d.ts.map +0 -1
- package/bin/chat/ChatPluginTypes.js +0 -10
- package/bin/chat/ChatPluginTypes.js.map +0 -1
- package/bin/skill/types/ClaudeSkill.d.ts.map +0 -1
- package/bin/skill/types/ClaudeSkill.js.map +0 -1
- package/bin/tts/Dependency.d.ts +0 -90
- package/bin/tts/Dependency.d.ts.map +0 -1
- package/bin/tts/Dependency.js +0 -344
- package/bin/tts/Dependency.js.map +0 -1
- package/bin/tts/PluginSupport.d.ts +0 -25
- package/bin/tts/PluginSupport.d.ts.map +0 -1
- package/bin/tts/PluginSupport.js +0 -72
- package/bin/tts/PluginSupport.js.map +0 -1
- package/bin/tts/runtime/Catalog.d.ts +0 -21
- package/bin/tts/runtime/Catalog.d.ts.map +0 -1
- package/bin/tts/runtime/Catalog.js +0 -90
- package/bin/tts/runtime/Catalog.js.map +0 -1
- package/bin/tts/runtime/DependencyInstaller.d.ts +0 -143
- package/bin/tts/runtime/DependencyInstaller.d.ts.map +0 -1
- package/bin/tts/runtime/DependencyInstaller.js +0 -261
- package/bin/tts/runtime/DependencyInstaller.js.map +0 -1
- package/bin/tts/runtime/Installer.d.ts +0 -89
- package/bin/tts/runtime/Installer.d.ts.map +0 -1
- package/bin/tts/runtime/Installer.js +0 -188
- package/bin/tts/runtime/Installer.js.map +0 -1
- package/bin/tts/runtime/Paths.d.ts +0 -20
- package/bin/tts/runtime/Paths.d.ts.map +0 -1
- package/bin/tts/runtime/Paths.js +0 -32
- package/bin/tts/runtime/Paths.js.map +0 -1
- package/bin/tts/runtime/Synthesizer.d.ts +0 -44
- package/bin/tts/runtime/Synthesizer.d.ts.map +0 -1
- package/bin/tts/runtime/Synthesizer.js +0 -363
- package/bin/tts/runtime/Synthesizer.js.map +0 -1
- package/bin/tts/types/Tts.d.ts +0 -91
- package/bin/tts/types/Tts.d.ts.map +0 -1
- package/bin/tts/types/Tts.js +0 -9
- package/bin/tts/types/Tts.js.map +0 -1
- package/bin/voice/Config.d.ts +0 -43
- package/bin/voice/Config.d.ts.map +0 -1
- package/bin/voice/Config.js +0 -104
- package/bin/voice/Config.js.map +0 -1
- package/bin/voice/Dependency.d.ts +0 -77
- package/bin/voice/Dependency.d.ts.map +0 -1
- package/bin/voice/Dependency.js +0 -237
- package/bin/voice/Dependency.js.map +0 -1
- package/bin/voice/InboundAugment.d.ts +0 -17
- package/bin/voice/InboundAugment.d.ts.map +0 -1
- package/bin/voice/InboundAugment.js +0 -47
- package/bin/voice/InboundAugment.js.map +0 -1
- package/bin/voice/ModelCatalog.d.ts +0 -29
- package/bin/voice/ModelCatalog.d.ts.map +0 -1
- package/bin/voice/ModelCatalog.js +0 -25
- package/bin/voice/ModelCatalog.js.map +0 -1
- package/bin/voice/runtime/Catalog.d.ts +0 -18
- package/bin/voice/runtime/Catalog.d.ts.map +0 -1
- package/bin/voice/runtime/Catalog.js +0 -61
- package/bin/voice/runtime/Catalog.js.map +0 -1
- package/bin/voice/runtime/DependencyInstaller.d.ts +0 -145
- package/bin/voice/runtime/DependencyInstaller.d.ts.map +0 -1
- package/bin/voice/runtime/DependencyInstaller.js +0 -309
- package/bin/voice/runtime/DependencyInstaller.js.map +0 -1
- package/bin/voice/runtime/Installer.d.ts +0 -94
- package/bin/voice/runtime/Installer.d.ts.map +0 -1
- package/bin/voice/runtime/Installer.js +0 -200
- package/bin/voice/runtime/Installer.js.map +0 -1
- package/bin/voice/runtime/Paths.d.ts +0 -8
- package/bin/voice/runtime/Paths.d.ts.map +0 -1
- package/bin/voice/runtime/Paths.js +0 -26
- package/bin/voice/runtime/Paths.js.map +0 -1
- package/bin/voice/runtime/Transcriber.d.ts +0 -57
- package/bin/voice/runtime/Transcriber.d.ts.map +0 -1
- package/bin/voice/runtime/Transcriber.js +0 -329
- package/bin/voice/runtime/Transcriber.js.map +0 -1
- package/bin/voice/types/Voice.d.ts +0 -58
- package/bin/voice/types/Voice.d.ts.map +0 -1
- package/bin/voice/types/Voice.js +0 -9
- package/bin/voice/types/Voice.js.map +0 -1
- package/bin/voice/types/VoicePlugin.d.ts +0 -190
- package/bin/voice/types/VoicePlugin.d.ts.map +0 -1
- package/bin/voice/types/VoicePlugin.js +0 -9
- package/bin/voice/types/VoicePlugin.js.map +0 -1
- package/bin/web/Dependency.d.ts +0 -10
- package/bin/web/Dependency.d.ts.map +0 -1
- package/bin/web/Dependency.js +0 -10
- package/bin/web/Dependency.js.map +0 -1
- package/bin/web/PROMPT.agent-browser.d.ts +0 -7
- package/bin/web/PROMPT.agent-browser.d.ts.map +0 -1
- package/bin/web/PROMPT.agent-browser.js +0 -8
- package/bin/web/PROMPT.agent-browser.js.map +0 -1
- package/bin/web/PROMPT.web-access.d.ts +0 -7
- package/bin/web/PROMPT.web-access.d.ts.map +0 -1
- package/bin/web/PROMPT.web-access.js +0 -8
- package/bin/web/PROMPT.web-access.js.map +0 -1
- package/bin/web/runtime/Config.d.ts +0 -21
- package/bin/web/runtime/Config.d.ts.map +0 -1
- package/bin/web/runtime/Config.js +0 -79
- package/bin/web/runtime/Config.js.map +0 -1
- package/bin/web/runtime/Source.d.ts +0 -29
- package/bin/web/runtime/Source.d.ts.map +0 -1
- package/bin/web/runtime/Source.js +0 -209
- package/bin/web/runtime/Source.js.map +0 -1
- package/src/asr/Config.ts +0 -138
- package/src/asr/Dependency.ts +0 -336
- package/src/asr/InboundAugment.ts +0 -59
- package/src/asr/ModelCatalog.ts +0 -43
- package/src/auth/Plugin.ts +0 -237
- package/src/chat/ChatPluginTypes.ts +0 -126
- package/src/tts/Dependency.ts +0 -473
- package/src/tts/PluginSupport.ts +0 -85
- package/src/tts/runtime/Catalog.ts +0 -97
- package/src/tts/runtime/DependencyInstaller.ts +0 -436
- package/src/tts/runtime/Installer.ts +0 -297
- package/src/tts/runtime/Paths.ts +0 -39
- package/src/tts/runtime/Synthesizer.ts +0 -480
- package/src/tts/types/Tts.ts +0 -99
- package/src/voice/Config.ts +0 -135
- package/src/voice/Dependency.ts +0 -329
- package/src/voice/InboundAugment.ts +0 -59
- package/src/voice/ModelCatalog.ts +0 -43
- package/src/voice/runtime/Catalog.ts +0 -68
- package/src/voice/runtime/DependencyInstaller.ts +0 -505
- package/src/voice/runtime/Installer.ts +0 -324
- package/src/voice/runtime/Paths.ts +0 -26
- package/src/voice/runtime/Transcriber.ts +0 -467
- package/src/voice/types/Voice.ts +0 -68
- package/src/voice/types/VoicePlugin.ts +0 -194
- package/src/web/Dependency.ts +0 -17
- package/src/web/PROMPT.agent-browser.ts +0 -9
- package/src/web/PROMPT.agent-browser.ts.txt +0 -17
- package/src/web/PROMPT.web-access.ts +0 -9
- package/src/web/PROMPT.web-access.ts.txt +0 -13
- package/src/web/runtime/Config.ts +0 -105
- package/src/web/runtime/Source.ts +0 -257
package/src/tts/Plugin.ts
CHANGED
|
@@ -1,517 +1,250 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* TtsPlugin:文本转语音插件。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* - TTS
|
|
6
|
-
* -
|
|
5
|
+
* - TTS 能力通过 constructor 注入,推荐传入 `city.ai.tts`。
|
|
6
|
+
* - plugin 不负责本地模型、Python 依赖、provider 或项目配置。
|
|
7
|
+
* - action 返回 AI SDK UIMessage,音频 file part 会由 plugin tool bridge 统一落盘到资源目录。
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { BasePlugin } from "@downcity/agent/internal/plugin/core/BasePlugin.js";
|
|
10
|
-
import type {
|
|
11
|
+
import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
|
|
12
|
+
import type {
|
|
13
|
+
JsonObject,
|
|
14
|
+
JsonValue,
|
|
15
|
+
} from "@downcity/agent/internal/types/common/Json.js";
|
|
11
16
|
import type {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
TtsPluginInput,
|
|
18
|
+
TtsPluginOptions,
|
|
19
|
+
TtsPluginResult,
|
|
20
|
+
TtsPluginSimpleAudioResult,
|
|
21
|
+
TtsPluginUiMessageResult,
|
|
15
22
|
} from "@/tts/types/TtsPlugin.js";
|
|
16
|
-
import { isPluginEnabled } from "@downcity/agent/internal/plugin/core/Activation.js";
|
|
17
|
-
import { writeProjectPluginEnabled } from "@downcity/agent/internal/plugin/core/ProjectConfigStore.js";
|
|
18
|
-
import {
|
|
19
|
-
checkTtsSynthesizer,
|
|
20
|
-
installTtsSynthesizer,
|
|
21
|
-
listTtsModelOptions,
|
|
22
|
-
readTtsPluginConfig,
|
|
23
|
-
writeTtsPluginConfig,
|
|
24
|
-
} from "@/tts/Dependency.js";
|
|
25
|
-
import { resolveTtsModelId } from "@/tts/runtime/Catalog.js";
|
|
26
|
-
import { synthesizeSpeechFile } from "@/tts/runtime/Synthesizer.js";
|
|
27
|
-
import {
|
|
28
|
-
getBooleanOpt,
|
|
29
|
-
getNumberOpt,
|
|
30
|
-
getStringOpt,
|
|
31
|
-
toJsonObject,
|
|
32
|
-
} from "@/tts/PluginSupport.js";
|
|
33
23
|
|
|
34
|
-
|
|
24
|
+
const DEFAULT_TTS_PLUGIN_NAME = "tts";
|
|
25
|
+
const DEFAULT_TTS_PLUGIN_TITLE = "TTS";
|
|
26
|
+
const DEFAULT_TTS_PLUGIN_DESCRIPTION =
|
|
27
|
+
"Synthesize speech through an injected TTS function and return assistant audio file parts.";
|
|
28
|
+
const DEFAULT_MEDIA_TYPE = "audio/wav";
|
|
29
|
+
const DEFAULT_FILENAME = "speech.wav";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 判断值是否为普通对象。
|
|
33
|
+
*/
|
|
34
|
+
function to_record(value: unknown): Record<string, unknown> | null {
|
|
35
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
36
|
+
return value as Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 归一化 action payload。
|
|
41
|
+
*/
|
|
42
|
+
function normalize_tts_payload(payload: JsonValue | undefined): TtsPluginInput {
|
|
43
|
+
const record = to_record(payload ?? {});
|
|
44
|
+
if (!record) {
|
|
45
|
+
throw new TypeError("TtsPlugin.synthesize payload must be an object");
|
|
46
|
+
}
|
|
47
|
+
const text = typeof record.text === "string" ? record.text.trim() : "";
|
|
48
|
+
if (!text) {
|
|
49
|
+
throw new Error("TtsPlugin.synthesize requires text");
|
|
50
|
+
}
|
|
35
51
|
return {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
key: "speed",
|
|
99
|
-
label: "默认语速",
|
|
100
|
-
type: "number",
|
|
101
|
-
placeholder: "1",
|
|
102
|
-
description: "1 为正常语速,可按需要设置为 0.8、1.2 等。",
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
key: "language",
|
|
106
|
-
label: "默认语言提示",
|
|
107
|
-
type: "string",
|
|
108
|
-
placeholder: "auto / zh / en",
|
|
109
|
-
},
|
|
52
|
+
...(record as TtsPluginInput),
|
|
53
|
+
text,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 判断返回值是否已经是 AI SDK UIMessage。
|
|
59
|
+
*/
|
|
60
|
+
function is_ui_message_result(value: TtsPluginResult): value is TtsPluginUiMessageResult {
|
|
61
|
+
const record = to_record(value);
|
|
62
|
+
return Boolean(record && Array.isArray(record.parts));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 读取简单音频结果中的 URL。
|
|
67
|
+
*/
|
|
68
|
+
function read_audio_url(record: Record<string, unknown>): string {
|
|
69
|
+
const url =
|
|
70
|
+
typeof record.url === "string"
|
|
71
|
+
? record.url.trim()
|
|
72
|
+
: typeof record.data_url === "string"
|
|
73
|
+
? record.data_url.trim()
|
|
74
|
+
: typeof record.audio_path === "string"
|
|
75
|
+
? record.audio_path.trim()
|
|
76
|
+
: "";
|
|
77
|
+
if (!url) {
|
|
78
|
+
throw new TypeError(
|
|
79
|
+
"TtsPlugin tts function must return a UIMessage or { url | data_url | audio_path }",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return url;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 把简单音频结果归一为 UIMessage。
|
|
87
|
+
*/
|
|
88
|
+
function simple_audio_to_ui_message(
|
|
89
|
+
result: TtsPluginSimpleAudioResult,
|
|
90
|
+
): TtsPluginUiMessageResult {
|
|
91
|
+
const record = to_record(result);
|
|
92
|
+
if (!record) {
|
|
93
|
+
throw new TypeError("TtsPlugin tts function returned an invalid result");
|
|
94
|
+
}
|
|
95
|
+
const url = read_audio_url(record);
|
|
96
|
+
const media_type =
|
|
97
|
+
typeof record.media_type === "string" && record.media_type.trim()
|
|
98
|
+
? record.media_type.trim()
|
|
99
|
+
: DEFAULT_MEDIA_TYPE;
|
|
100
|
+
const filename =
|
|
101
|
+
typeof record.filename === "string" && record.filename.trim()
|
|
102
|
+
? record.filename.trim()
|
|
103
|
+
: DEFAULT_FILENAME;
|
|
104
|
+
const text = typeof record.text === "string" ? record.text.trim() : "";
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
id: `tts:${Date.now()}`,
|
|
108
|
+
role: "assistant",
|
|
109
|
+
parts: [
|
|
110
|
+
...(text ? [{ type: "text" as const, text }] : []),
|
|
110
111
|
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
type: "file" as const,
|
|
113
|
+
mediaType: media_type,
|
|
114
|
+
filename,
|
|
115
|
+
url,
|
|
115
116
|
},
|
|
116
117
|
],
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 校验并归一化 TTS 返回结果。
|
|
123
|
+
*/
|
|
124
|
+
function normalize_tts_result(result: TtsPluginResult): TtsPluginUiMessageResult {
|
|
125
|
+
if (is_ui_message_result(result)) {
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
return simple_audio_to_ui_message(result);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Agent TTS 插件。
|
|
133
|
+
*/
|
|
134
|
+
export class TtsPlugin extends BasePlugin {
|
|
135
|
+
/**
|
|
136
|
+
* 当前 plugin 稳定名称。
|
|
137
|
+
*/
|
|
138
|
+
readonly name: string;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 插件标题。
|
|
142
|
+
*/
|
|
143
|
+
readonly title: string;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 插件说明。
|
|
147
|
+
*/
|
|
148
|
+
readonly description: string;
|
|
149
|
+
|
|
150
|
+
private readonly tts: TtsPluginOptions["tts"];
|
|
151
|
+
private readonly language?: string;
|
|
152
|
+
private readonly voice?: string;
|
|
153
|
+
private readonly format?: string;
|
|
154
|
+
|
|
155
|
+
constructor(options: TtsPluginOptions) {
|
|
156
|
+
super();
|
|
157
|
+
const name = String(options.name || DEFAULT_TTS_PLUGIN_NAME).trim();
|
|
158
|
+
if (!name) {
|
|
159
|
+
throw new Error("TtsPlugin requires a non-empty name");
|
|
127
160
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
data: {
|
|
198
|
-
options: listTtsModelOptions(),
|
|
199
|
-
},
|
|
200
|
-
};
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
install: {
|
|
204
|
-
allowWhenDisabled: true,
|
|
205
|
-
command: {
|
|
206
|
-
description: "安装 tts 语音合成依赖",
|
|
207
|
-
configure(command) {
|
|
208
|
-
command
|
|
209
|
-
.argument("[models...]")
|
|
210
|
-
.option("--active-model <modelId>", "安装完成后设为当前模型")
|
|
211
|
-
.option("--models-dir <path>", "模型目录(可选)")
|
|
212
|
-
.option("--python <bin>", "Python 可执行文件(默认 python3)")
|
|
213
|
-
.option("--no-install-deps", "跳过依赖安装")
|
|
214
|
-
.option("--force", "强制覆盖已存在资源")
|
|
215
|
-
.option("--hf-token <token>", "HuggingFace token(可选)")
|
|
216
|
-
.option("--format <format>", "默认输出格式(wav/flac)");
|
|
217
|
-
},
|
|
218
|
-
mapInput({ args, opts }) {
|
|
219
|
-
return {
|
|
220
|
-
modelIds: args,
|
|
221
|
-
...(getStringOpt(opts, "activeModel")
|
|
222
|
-
? { activeModel: getStringOpt(opts, "activeModel") }
|
|
223
|
-
: {}),
|
|
224
|
-
...(getStringOpt(opts, "modelsDir")
|
|
225
|
-
? { modelsDir: getStringOpt(opts, "modelsDir") }
|
|
226
|
-
: {}),
|
|
227
|
-
...(getStringOpt(opts, "python")
|
|
228
|
-
? { pythonBin: getStringOpt(opts, "python") }
|
|
229
|
-
: {}),
|
|
230
|
-
installDeps: getBooleanOpt(opts, "installDeps", true),
|
|
231
|
-
force: getBooleanOpt(opts, "force", false),
|
|
232
|
-
...(getStringOpt(opts, "hfToken")
|
|
233
|
-
? { hfToken: getStringOpt(opts, "hfToken") }
|
|
234
|
-
: {}),
|
|
235
|
-
...(getStringOpt(opts, "format")
|
|
236
|
-
? { format: getStringOpt(opts, "format") }
|
|
237
|
-
: {}),
|
|
238
|
-
};
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
execute: async ({ context, payload }) => {
|
|
242
|
-
const result = await installTtsSynthesizer({
|
|
243
|
-
context,
|
|
244
|
-
input:
|
|
245
|
-
payload && typeof payload === "object" && !Array.isArray(payload)
|
|
246
|
-
? (payload as TtsInstallInput)
|
|
247
|
-
: undefined,
|
|
248
|
-
});
|
|
249
|
-
return {
|
|
250
|
-
success: result.success,
|
|
251
|
-
...(result.message ? { message: result.message } : {}),
|
|
252
|
-
...(result.details !== undefined ? { data: result.details } : {}),
|
|
253
|
-
...(result.success ? {} : { error: result.message || "install failed" }),
|
|
254
|
-
};
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
configure: {
|
|
258
|
-
allowWhenDisabled: true,
|
|
259
|
-
execute: async ({ context, payload }) => {
|
|
260
|
-
const payloadObject =
|
|
261
|
-
payload && typeof payload === "object" && !Array.isArray(payload)
|
|
262
|
-
? (payload as Partial<TtsPluginConfig> & Record<string, unknown>)
|
|
263
|
-
: {};
|
|
264
|
-
const { enabled: _ignoredEnabled, ...patch } = payloadObject;
|
|
265
|
-
const current = readTtsPluginConfig(context);
|
|
266
|
-
const next = {
|
|
267
|
-
...current,
|
|
268
|
-
...(patch as Partial<TtsPluginConfig>),
|
|
269
|
-
} satisfies TtsPluginConfig;
|
|
270
|
-
await writeTtsPluginConfig({
|
|
271
|
-
context,
|
|
272
|
-
value: next,
|
|
273
|
-
});
|
|
274
|
-
return {
|
|
275
|
-
success: true,
|
|
276
|
-
data: {
|
|
277
|
-
plugin: toJsonObject(next) || {},
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
on: {
|
|
283
|
-
allowWhenDisabled: true,
|
|
284
|
-
command: {
|
|
285
|
-
description: "启用 tts plugin,并可选安装本地依赖",
|
|
286
|
-
configure(command) {
|
|
287
|
-
command
|
|
288
|
-
.argument("[models...]")
|
|
289
|
-
.option("--active-model <modelId>", "安装完成后设为当前模型")
|
|
290
|
-
.option("--models-dir <path>", "模型目录(可选)")
|
|
291
|
-
.option("--python <bin>", "Python 可执行文件(默认 python3)")
|
|
292
|
-
.option("--no-install", "仅启用 plugin,不安装依赖")
|
|
293
|
-
.option("--no-install-deps", "跳过依赖安装")
|
|
294
|
-
.option("--force", "强制覆盖已存在资源")
|
|
295
|
-
.option("--hf-token <token>", "HuggingFace token(可选)")
|
|
296
|
-
.option("--format <format>", "默认输出格式(wav/flac)");
|
|
297
|
-
},
|
|
298
|
-
mapInput({ args, opts }) {
|
|
299
|
-
return {
|
|
300
|
-
modelIds: args,
|
|
301
|
-
...(getStringOpt(opts, "activeModel")
|
|
302
|
-
? { activeModel: getStringOpt(opts, "activeModel") }
|
|
303
|
-
: {}),
|
|
304
|
-
...(getStringOpt(opts, "modelsDir")
|
|
305
|
-
? { modelsDir: getStringOpt(opts, "modelsDir") }
|
|
306
|
-
: {}),
|
|
307
|
-
...(getStringOpt(opts, "python")
|
|
308
|
-
? { pythonBin: getStringOpt(opts, "python") }
|
|
309
|
-
: {}),
|
|
310
|
-
install: getBooleanOpt(opts, "install", true),
|
|
311
|
-
installDeps: getBooleanOpt(opts, "installDeps", true),
|
|
312
|
-
force: getBooleanOpt(opts, "force", false),
|
|
313
|
-
...(getStringOpt(opts, "hfToken")
|
|
314
|
-
? { hfToken: getStringOpt(opts, "hfToken") }
|
|
315
|
-
: {}),
|
|
316
|
-
...(getStringOpt(opts, "format")
|
|
317
|
-
? { format: getStringOpt(opts, "format") }
|
|
318
|
-
: {}),
|
|
319
|
-
};
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
execute: async ({ context, payload }) => {
|
|
323
|
-
await writeProjectPluginEnabled({
|
|
324
|
-
pluginName: "tts",
|
|
325
|
-
enabled: true,
|
|
326
|
-
context,
|
|
327
|
-
});
|
|
328
|
-
if ((payload as { install?: unknown }).install !== false) {
|
|
329
|
-
const installResult = await installTtsSynthesizer({
|
|
330
|
-
context,
|
|
331
|
-
input:
|
|
332
|
-
payload && typeof payload === "object" && !Array.isArray(payload)
|
|
333
|
-
? (payload as TtsInstallInput)
|
|
334
|
-
: undefined,
|
|
335
|
-
});
|
|
336
|
-
if (!installResult.success) {
|
|
337
|
-
return {
|
|
338
|
-
success: false,
|
|
339
|
-
error: installResult.message || "tts dependency install failed",
|
|
340
|
-
message: installResult.message || "tts dependency install failed",
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return {
|
|
345
|
-
success: true,
|
|
346
|
-
data: {
|
|
347
|
-
plugin: toJsonObject(readTtsPluginConfig(context) as Record<string, unknown>) || {},
|
|
348
|
-
},
|
|
349
|
-
};
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
off: {
|
|
353
|
-
command: {
|
|
354
|
-
description: "关闭 tts plugin",
|
|
355
|
-
mapInput() {
|
|
356
|
-
return {};
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
execute: async ({ context }) => {
|
|
360
|
-
await writeProjectPluginEnabled({
|
|
361
|
-
pluginName: "tts",
|
|
362
|
-
enabled: false,
|
|
363
|
-
context,
|
|
364
|
-
});
|
|
365
|
-
return {
|
|
366
|
-
success: true,
|
|
367
|
-
data: {
|
|
368
|
-
plugin: toJsonObject(readTtsPluginConfig(context) as Record<string, unknown>) || {},
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
use: {
|
|
374
|
-
allowWhenDisabled: true,
|
|
375
|
-
command: {
|
|
376
|
-
description: "切换 tts 当前模型",
|
|
377
|
-
configure(command) {
|
|
378
|
-
command.argument("<modelId>");
|
|
379
|
-
},
|
|
380
|
-
mapInput({ args }) {
|
|
381
|
-
const modelId = String(args[0] || "").trim();
|
|
382
|
-
if (!modelId) {
|
|
383
|
-
throw new Error("modelId is required");
|
|
384
|
-
}
|
|
385
|
-
return {
|
|
386
|
-
modelId,
|
|
387
|
-
};
|
|
388
|
-
},
|
|
389
|
-
},
|
|
390
|
-
execute: async ({ context, payload }) => {
|
|
391
|
-
const modelId = String((payload as { modelId?: unknown }).modelId || "").trim();
|
|
392
|
-
const resolvedModelId = resolveTtsModelId(modelId);
|
|
393
|
-
if (!resolvedModelId) {
|
|
394
|
-
return {
|
|
395
|
-
success: false,
|
|
396
|
-
error: `Unsupported tts model: ${modelId}`,
|
|
397
|
-
message: `Unsupported tts model: ${modelId}`,
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
const nextConfig = await writeTtsPluginConfig({
|
|
401
|
-
context,
|
|
402
|
-
value: {
|
|
403
|
-
...readTtsPluginConfig(context),
|
|
404
|
-
modelId: resolvedModelId,
|
|
405
|
-
},
|
|
406
|
-
});
|
|
407
|
-
return {
|
|
408
|
-
success: true,
|
|
409
|
-
data: {
|
|
410
|
-
plugin: toJsonObject(nextConfig as Record<string, unknown>) || {},
|
|
411
|
-
},
|
|
412
|
-
};
|
|
413
|
-
},
|
|
414
|
-
},
|
|
161
|
+
if (typeof options.tts !== "function") {
|
|
162
|
+
throw new Error("TtsPlugin requires a tts function");
|
|
163
|
+
}
|
|
164
|
+
this.name = name;
|
|
165
|
+
this.title = String(options.title || DEFAULT_TTS_PLUGIN_TITLE).trim();
|
|
166
|
+
this.description = String(
|
|
167
|
+
options.description || DEFAULT_TTS_PLUGIN_DESCRIPTION,
|
|
168
|
+
).trim();
|
|
169
|
+
this.tts = options.tts;
|
|
170
|
+
this.language =
|
|
171
|
+
typeof options.language === "string" && options.language.trim()
|
|
172
|
+
? options.language.trim()
|
|
173
|
+
: undefined;
|
|
174
|
+
this.voice =
|
|
175
|
+
typeof options.voice === "string" && options.voice.trim()
|
|
176
|
+
? options.voice.trim()
|
|
177
|
+
: undefined;
|
|
178
|
+
this.format =
|
|
179
|
+
typeof options.format === "string" && options.format.trim()
|
|
180
|
+
? options.format.trim()
|
|
181
|
+
: undefined;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* TTS 插件给模型的使用说明。
|
|
186
|
+
*/
|
|
187
|
+
system(_context: AgentContext): string {
|
|
188
|
+
return [
|
|
189
|
+
"# TTS Plugin",
|
|
190
|
+
"",
|
|
191
|
+
"Use this plugin when the user asks to create spoken audio, voice output, narration, or a reusable audio file.",
|
|
192
|
+
"Do not call it for ordinary text replies unless the user explicitly wants audio.",
|
|
193
|
+
"",
|
|
194
|
+
"Call through `plugin_call`:",
|
|
195
|
+
"",
|
|
196
|
+
"```ts",
|
|
197
|
+
"plugin_call({",
|
|
198
|
+
` plugin: "${this.name}",`,
|
|
199
|
+
' action: "synthesize",',
|
|
200
|
+
" payload: {",
|
|
201
|
+
' text: "...",',
|
|
202
|
+
" },",
|
|
203
|
+
"});",
|
|
204
|
+
"```",
|
|
205
|
+
"",
|
|
206
|
+
"Payload rules:",
|
|
207
|
+
"- `text` is required.",
|
|
208
|
+
"- Optional fields: `language`, `voice`, `format`, `speed`, `provider_options`.",
|
|
209
|
+
"- The returned audio file part is saved under project `.downcity/resources` and attached to the final assistant message automatically.",
|
|
210
|
+
].join("\n");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 执行一次 TTS 合成。
|
|
215
|
+
*/
|
|
216
|
+
private async synthesize(input: TtsPluginInput): Promise<TtsPluginUiMessageResult> {
|
|
217
|
+
const result = await this.tts({
|
|
218
|
+
...(this.language ? { language: this.language } : {}),
|
|
219
|
+
...(this.voice ? { voice: this.voice } : {}),
|
|
220
|
+
...(this.format ? { format: this.format } : {}),
|
|
221
|
+
...input,
|
|
222
|
+
});
|
|
223
|
+
return normalize_tts_result(result);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 显式 action 集合。
|
|
228
|
+
*/
|
|
229
|
+
readonly actions = {
|
|
415
230
|
synthesize: {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
.argument("<text>")
|
|
421
|
-
.option("--model <modelId>", "语音模型 ID")
|
|
422
|
-
.option("--language <language>", "语言提示(可选,例如 zh / en)")
|
|
423
|
-
.option("--voice <voice>", "音色 ID(可选)")
|
|
424
|
-
.option("--format <format>", "输出格式(wav/flac)")
|
|
425
|
-
.option("--speed <speed>", "语速倍率", Number)
|
|
426
|
-
.option("--output <path>", "输出文件路径或目录(可选)");
|
|
427
|
-
},
|
|
428
|
-
mapInput({ args, opts }) {
|
|
429
|
-
const text = String(args[0] || "").trim();
|
|
430
|
-
if (!text) {
|
|
431
|
-
throw new Error("text is required");
|
|
432
|
-
}
|
|
231
|
+
execute: async ({ payload }: { payload: JsonValue }) => {
|
|
232
|
+
try {
|
|
233
|
+
const input = normalize_tts_payload(payload);
|
|
234
|
+
const message = await this.synthesize(input);
|
|
433
235
|
return {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
: {}),
|
|
438
|
-
...(getStringOpt(opts, "language")
|
|
439
|
-
? { language: getStringOpt(opts, "language") }
|
|
440
|
-
: {}),
|
|
441
|
-
...(getStringOpt(opts, "voice")
|
|
442
|
-
? { voice: getStringOpt(opts, "voice") }
|
|
443
|
-
: {}),
|
|
444
|
-
...(getStringOpt(opts, "format")
|
|
445
|
-
? { format: getStringOpt(opts, "format") }
|
|
446
|
-
: {}),
|
|
447
|
-
...(typeof getNumberOpt(opts, "speed") === "number"
|
|
448
|
-
? { speed: getNumberOpt(opts, "speed") }
|
|
449
|
-
: {}),
|
|
450
|
-
...(getStringOpt(opts, "output")
|
|
451
|
-
? { output: getStringOpt(opts, "output") }
|
|
452
|
-
: {}),
|
|
236
|
+
success: true,
|
|
237
|
+
data: message as unknown as JsonObject,
|
|
238
|
+
message: "speech synthesized",
|
|
453
239
|
};
|
|
454
|
-
}
|
|
455
|
-
},
|
|
456
|
-
execute: async ({ context, payload }) => {
|
|
457
|
-
const pluginStatus = await plugin.availability!(context);
|
|
458
|
-
if (!pluginStatus.enabled || !pluginStatus.available) {
|
|
240
|
+
} catch (error) {
|
|
459
241
|
return {
|
|
460
242
|
success: false,
|
|
461
|
-
error:
|
|
462
|
-
message:
|
|
243
|
+
error: String(error),
|
|
244
|
+
message: String(error),
|
|
463
245
|
};
|
|
464
246
|
}
|
|
465
|
-
|
|
466
|
-
const input =
|
|
467
|
-
payload && typeof payload === "object" && !Array.isArray(payload)
|
|
468
|
-
? (payload as TtsSynthesizeInput)
|
|
469
|
-
: {};
|
|
470
|
-
const result = await synthesizeSpeechFile({
|
|
471
|
-
context,
|
|
472
|
-
config: readTtsPluginConfig(context),
|
|
473
|
-
input,
|
|
474
|
-
});
|
|
475
|
-
return {
|
|
476
|
-
success: true,
|
|
477
|
-
data: {
|
|
478
|
-
outputPath: result.outputPath,
|
|
479
|
-
fileTag: result.fileTag,
|
|
480
|
-
bytes: result.bytes,
|
|
481
|
-
...(result.stderrSummary ? { stderr: result.stderrSummary } : {}),
|
|
482
|
-
},
|
|
483
|
-
};
|
|
484
247
|
},
|
|
485
248
|
},
|
|
486
|
-
},
|
|
487
|
-
system(context) {
|
|
488
|
-
if (!isPluginEnabled({ plugin, context })) {
|
|
489
|
-
return "";
|
|
490
|
-
}
|
|
491
|
-
return [
|
|
492
|
-
"# TTS Plugin",
|
|
493
|
-
"The agent can call the tts plugin to synthesize speech audio from plain text.",
|
|
494
|
-
"Typical usage flow:",
|
|
495
|
-
"1. Check availability with the `status` action when you need to confirm whether the plugin and model are ready.",
|
|
496
|
-
"2. Generate audio with the `synthesize` action.",
|
|
497
|
-
"3. Optionally override synthesis parameters in the action payload: `voice`, `language`, `format`, `speed`, and `output`.",
|
|
498
|
-
"Use the `tts.synthesize` action when the user asks to generate spoken audio or a reusable audio file tag.",
|
|
499
|
-
"A successful synthesis returns a local output path and a reusable `<file type=\"audio\">...</file>` tag for downstream sending.",
|
|
500
|
-
"If the Python runner prints non-fatal stderr, the command still succeeds and returns that stderr summary as extra context.",
|
|
501
|
-
"Example: `plugin_call({ plugin: \"tts\", action: \"synthesize\", payload: { text: \"你好,欢迎来到 Downcity\", format: \"wav\" } })`",
|
|
502
|
-
].join("\n");
|
|
503
|
-
},
|
|
504
249
|
};
|
|
505
250
|
}
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* TtsPlugin:文本转语音插件。
|
|
509
|
-
*/
|
|
510
|
-
export class TtsPlugin extends BasePlugin {
|
|
511
|
-
readonly name = "tts";
|
|
512
|
-
|
|
513
|
-
constructor() {
|
|
514
|
-
super();
|
|
515
|
-
Object.assign(this, createTtsPluginDefinition(this));
|
|
516
|
-
}
|
|
517
|
-
}
|