@downcity/plugins 1.0.52 → 1.0.57

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.
Files changed (329) hide show
  1. package/bin/BuiltinPlugins.d.ts +2 -3
  2. package/bin/BuiltinPlugins.d.ts.map +1 -1
  3. package/bin/BuiltinPlugins.js +2 -6
  4. package/bin/BuiltinPlugins.js.map +1 -1
  5. package/bin/asr/Plugin.d.ts +67 -8
  6. package/bin/asr/Plugin.d.ts.map +1 -1
  7. package/bin/asr/Plugin.js +229 -461
  8. package/bin/asr/Plugin.js.map +1 -1
  9. package/bin/asr/types/AsrPlugin.d.ts +114 -0
  10. package/bin/asr/types/AsrPlugin.d.ts.map +1 -0
  11. package/bin/asr/types/AsrPlugin.js +10 -0
  12. package/bin/asr/types/AsrPlugin.js.map +1 -0
  13. package/bin/auth/Plugin.d.ts +1 -2
  14. package/bin/auth/Plugin.d.ts.map +1 -1
  15. package/bin/auth/Plugin.js +2 -2
  16. package/bin/auth/Plugin.js.map +1 -1
  17. package/bin/chat/ChatPlugin.d.ts +1 -2
  18. package/bin/chat/ChatPlugin.d.ts.map +1 -1
  19. package/bin/chat/ChatPlugin.js +3 -12
  20. package/bin/chat/ChatPlugin.js.map +1 -1
  21. package/bin/chat/PROMPT.direct.d.ts +1 -1
  22. package/bin/chat/PROMPT.direct.d.ts.map +1 -1
  23. package/bin/chat/PROMPT.direct.js +1 -1
  24. package/bin/chat/PROMPT.direct.js.map +1 -1
  25. package/bin/chat/channels/qq/PROMPT.direct.d.ts +1 -1
  26. package/bin/chat/channels/qq/PROMPT.direct.d.ts.map +1 -1
  27. package/bin/chat/channels/qq/PROMPT.direct.js +1 -1
  28. package/bin/chat/channels/qq/PROMPT.direct.js.map +1 -1
  29. package/bin/chat/channels/telegram/Bot.d.ts +6 -0
  30. package/bin/chat/channels/telegram/Bot.d.ts.map +1 -1
  31. package/bin/chat/channels/telegram/Bot.js +24 -0
  32. package/bin/chat/channels/telegram/Bot.js.map +1 -1
  33. package/bin/chat/channels/telegram/TelegramPlatformClient.d.ts +14 -0
  34. package/bin/chat/channels/telegram/TelegramPlatformClient.d.ts.map +1 -1
  35. package/bin/chat/channels/telegram/TelegramPlatformClient.js +39 -5
  36. package/bin/chat/channels/telegram/TelegramPlatformClient.js.map +1 -1
  37. package/bin/contact/ContactPlugin.d.ts +1 -2
  38. package/bin/contact/ContactPlugin.d.ts.map +1 -1
  39. package/bin/contact/ContactPlugin.js +2 -2
  40. package/bin/contact/ContactPlugin.js.map +1 -1
  41. package/bin/contact/PROMPT.d.ts +1 -1
  42. package/bin/contact/PROMPT.d.ts.map +1 -1
  43. package/bin/contact/PROMPT.js +1 -1
  44. package/bin/contact/PROMPT.js.map +1 -1
  45. package/bin/image/ImagePlugin.d.ts +61 -0
  46. package/bin/image/ImagePlugin.d.ts.map +1 -0
  47. package/bin/image/ImagePlugin.js +207 -0
  48. package/bin/image/ImagePlugin.js.map +1 -0
  49. package/bin/image/types/ImagePlugin.d.ts +136 -0
  50. package/bin/image/types/ImagePlugin.d.ts.map +1 -0
  51. package/bin/image/types/ImagePlugin.js +10 -0
  52. package/bin/image/types/ImagePlugin.js.map +1 -0
  53. package/bin/index.d.ts +4 -0
  54. package/bin/index.d.ts.map +1 -1
  55. package/bin/index.js +1 -0
  56. package/bin/index.js.map +1 -1
  57. package/bin/shell/ShellPlugin.d.ts +1 -2
  58. package/bin/shell/ShellPlugin.d.ts.map +1 -1
  59. package/bin/shell/ShellPlugin.js +2 -2
  60. package/bin/shell/ShellPlugin.js.map +1 -1
  61. package/bin/skill/Action.d.ts +8 -3
  62. package/bin/skill/Action.d.ts.map +1 -1
  63. package/bin/skill/Action.js +9 -11
  64. package/bin/skill/Action.js.map +1 -1
  65. package/bin/skill/Command.d.ts +1 -1
  66. package/bin/skill/Command.d.ts.map +1 -1
  67. package/bin/skill/Command.js +3 -10
  68. package/bin/skill/Command.js.map +1 -1
  69. package/bin/skill/Config.d.ts +9 -9
  70. package/bin/skill/Config.d.ts.map +1 -1
  71. package/bin/skill/Config.js +36 -24
  72. package/bin/skill/Config.js.map +1 -1
  73. package/bin/skill/PROMPT.d.ts +1 -1
  74. package/bin/skill/PROMPT.d.ts.map +1 -1
  75. package/bin/skill/PROMPT.js +1 -1
  76. package/bin/skill/PROMPT.js.map +1 -1
  77. package/bin/skill/Plugin.d.ts +2 -2
  78. package/bin/skill/Plugin.d.ts.map +1 -1
  79. package/bin/skill/Plugin.js +20 -37
  80. package/bin/skill/Plugin.js.map +1 -1
  81. package/bin/skill/runtime/Discovery.d.ts +3 -3
  82. package/bin/skill/runtime/Discovery.d.ts.map +1 -1
  83. package/bin/skill/runtime/Discovery.js +37 -14
  84. package/bin/skill/runtime/Discovery.js.map +1 -1
  85. package/bin/skill/runtime/Paths.d.ts +5 -5
  86. package/bin/skill/runtime/Paths.d.ts.map +1 -1
  87. package/bin/skill/runtime/Paths.js +23 -33
  88. package/bin/skill/runtime/Paths.js.map +1 -1
  89. package/bin/skill/runtime/Prompt.d.ts +2 -2
  90. package/bin/skill/runtime/Prompt.d.ts.map +1 -1
  91. package/bin/skill/runtime/Prompt.js +3 -8
  92. package/bin/skill/runtime/Prompt.js.map +1 -1
  93. package/bin/skill/runtime/SystemProvider.d.ts +2 -2
  94. package/bin/skill/runtime/SystemProvider.d.ts.map +1 -1
  95. package/bin/skill/runtime/SystemProvider.js +2 -2
  96. package/bin/skill/runtime/SystemProvider.js.map +1 -1
  97. package/bin/skill/types/SkillPlugin.d.ts +34 -12
  98. package/bin/skill/types/SkillPlugin.d.ts.map +1 -1
  99. package/bin/skill/types/SkillPlugin.js +2 -1
  100. package/bin/skill/types/SkillPlugin.js.map +1 -1
  101. package/bin/skill/types/SkillRoot.d.ts +1 -1
  102. package/bin/task/Action.js +2 -2
  103. package/bin/task/Action.js.map +1 -1
  104. package/bin/task/PROMPT.d.ts +1 -1
  105. package/bin/task/PROMPT.d.ts.map +1 -1
  106. package/bin/task/PROMPT.js +1 -1
  107. package/bin/task/PROMPT.js.map +1 -1
  108. package/bin/task/TaskPlugin.d.ts +1 -2
  109. package/bin/task/TaskPlugin.d.ts.map +1 -1
  110. package/bin/task/TaskPlugin.js +2 -2
  111. package/bin/task/TaskPlugin.js.map +1 -1
  112. package/bin/tts/Plugin.d.ts +53 -7
  113. package/bin/tts/Plugin.d.ts.map +1 -1
  114. package/bin/tts/Plugin.js +197 -474
  115. package/bin/tts/Plugin.js.map +1 -1
  116. package/bin/tts/types/TtsPlugin.d.ts +63 -102
  117. package/bin/tts/types/TtsPlugin.d.ts.map +1 -1
  118. package/bin/tts/types/TtsPlugin.js +4 -3
  119. package/bin/tts/types/TtsPlugin.js.map +1 -1
  120. package/bin/web/PROMPT.d.ts +1 -1
  121. package/bin/web/PROMPT.d.ts.map +1 -1
  122. package/bin/web/PROMPT.js +1 -1
  123. package/bin/web/PROMPT.js.map +1 -1
  124. package/bin/web/Plugin.d.ts +66 -6
  125. package/bin/web/Plugin.d.ts.map +1 -1
  126. package/bin/web/Plugin.js +130 -447
  127. package/bin/web/Plugin.js.map +1 -1
  128. package/bin/web/WebPromptAssets.d.ts +1 -9
  129. package/bin/web/WebPromptAssets.d.ts.map +1 -1
  130. package/bin/web/WebPromptAssets.js +1 -11
  131. package/bin/web/WebPromptAssets.js.map +1 -1
  132. package/bin/web/runtime/Install.d.ts +19 -0
  133. package/bin/web/runtime/Install.d.ts.map +1 -0
  134. package/bin/web/runtime/Install.js +178 -0
  135. package/bin/web/runtime/Install.js.map +1 -0
  136. package/bin/web/types/WebPlugin.d.ts +37 -109
  137. package/bin/web/types/WebPlugin.d.ts.map +1 -1
  138. package/bin/web/types/WebPlugin.js +5 -7
  139. package/bin/web/types/WebPlugin.js.map +1 -1
  140. package/bin/workboard/Plugin.d.ts +1 -2
  141. package/bin/workboard/Plugin.d.ts.map +1 -1
  142. package/bin/workboard/Plugin.js +2 -2
  143. package/bin/workboard/Plugin.js.map +1 -1
  144. package/package.json +2 -2
  145. package/src/BuiltinPlugins.ts +3 -10
  146. package/src/asr/Plugin.ts +264 -484
  147. package/src/asr/types/AsrPlugin.ts +118 -0
  148. package/src/auth/Plugin.ts +2 -3
  149. package/src/chat/ChatPlugin.ts +3 -14
  150. package/src/chat/PROMPT.direct.ts +1 -1
  151. package/src/chat/PROMPT.direct.ts.txt +5 -7
  152. package/src/chat/channels/qq/PROMPT.direct.ts +1 -1
  153. package/src/chat/channels/qq/PROMPT.direct.ts.txt +1 -1
  154. package/src/chat/channels/telegram/Bot.ts +22 -0
  155. package/src/chat/channels/telegram/TelegramPlatformClient.ts +42 -6
  156. package/src/contact/ContactPlugin.ts +2 -3
  157. package/src/contact/PROMPT.ts +1 -1
  158. package/src/contact/PROMPT.ts.txt +12 -12
  159. package/src/image/ImagePlugin.ts +268 -0
  160. package/src/image/types/ImagePlugin.ts +157 -0
  161. package/src/index.ts +25 -0
  162. package/src/shell/ShellPlugin.ts +2 -3
  163. package/src/skill/Action.ts +20 -9
  164. package/src/skill/Command.ts +3 -13
  165. package/src/skill/Config.ts +41 -34
  166. package/src/skill/PROMPT.ts +1 -1
  167. package/src/skill/PROMPT.ts.txt +14 -2
  168. package/src/skill/Plugin.ts +205 -214
  169. package/src/skill/runtime/Discovery.ts +43 -17
  170. package/src/skill/runtime/Paths.ts +24 -35
  171. package/src/skill/runtime/Prompt.ts +4 -10
  172. package/src/skill/runtime/SystemProvider.ts +4 -4
  173. package/src/skill/types/SkillPlugin.ts +39 -12
  174. package/src/skill/types/SkillRoot.ts +1 -1
  175. package/src/task/Action.ts +2 -2
  176. package/src/task/PROMPT.ts +1 -1
  177. package/src/task/PROMPT.ts.txt +10 -10
  178. package/src/task/TaskPlugin.ts +2 -3
  179. package/src/tts/Plugin.ts +225 -493
  180. package/src/tts/types/TtsPlugin.ts +67 -102
  181. package/src/web/PROMPT.ts +1 -1
  182. package/src/web/PROMPT.ts.txt +32 -6
  183. package/src/web/Plugin.ts +119 -454
  184. package/src/web/WebPromptAssets.ts +1 -13
  185. package/src/web/runtime/Install.ts +241 -0
  186. package/src/web/types/WebPlugin.ts +37 -113
  187. package/src/workboard/Plugin.ts +2 -3
  188. package/bin/asr/Config.d.ts +0 -43
  189. package/bin/asr/Config.d.ts.map +0 -1
  190. package/bin/asr/Config.js +0 -107
  191. package/bin/asr/Config.js.map +0 -1
  192. package/bin/asr/Dependency.d.ts +0 -77
  193. package/bin/asr/Dependency.d.ts.map +0 -1
  194. package/bin/asr/Dependency.js +0 -238
  195. package/bin/asr/Dependency.js.map +0 -1
  196. package/bin/asr/InboundAugment.d.ts +0 -17
  197. package/bin/asr/InboundAugment.d.ts.map +0 -1
  198. package/bin/asr/InboundAugment.js +0 -47
  199. package/bin/asr/InboundAugment.js.map +0 -1
  200. package/bin/asr/ModelCatalog.d.ts +0 -29
  201. package/bin/asr/ModelCatalog.d.ts.map +0 -1
  202. package/bin/asr/ModelCatalog.js +0 -25
  203. package/bin/asr/ModelCatalog.js.map +0 -1
  204. package/bin/tts/Dependency.d.ts +0 -90
  205. package/bin/tts/Dependency.d.ts.map +0 -1
  206. package/bin/tts/Dependency.js +0 -344
  207. package/bin/tts/Dependency.js.map +0 -1
  208. package/bin/tts/PluginSupport.d.ts +0 -25
  209. package/bin/tts/PluginSupport.d.ts.map +0 -1
  210. package/bin/tts/PluginSupport.js +0 -72
  211. package/bin/tts/PluginSupport.js.map +0 -1
  212. package/bin/tts/runtime/Catalog.d.ts +0 -21
  213. package/bin/tts/runtime/Catalog.d.ts.map +0 -1
  214. package/bin/tts/runtime/Catalog.js +0 -90
  215. package/bin/tts/runtime/Catalog.js.map +0 -1
  216. package/bin/tts/runtime/DependencyInstaller.d.ts +0 -143
  217. package/bin/tts/runtime/DependencyInstaller.d.ts.map +0 -1
  218. package/bin/tts/runtime/DependencyInstaller.js +0 -261
  219. package/bin/tts/runtime/DependencyInstaller.js.map +0 -1
  220. package/bin/tts/runtime/Installer.d.ts +0 -89
  221. package/bin/tts/runtime/Installer.d.ts.map +0 -1
  222. package/bin/tts/runtime/Installer.js +0 -188
  223. package/bin/tts/runtime/Installer.js.map +0 -1
  224. package/bin/tts/runtime/Paths.d.ts +0 -20
  225. package/bin/tts/runtime/Paths.d.ts.map +0 -1
  226. package/bin/tts/runtime/Paths.js +0 -32
  227. package/bin/tts/runtime/Paths.js.map +0 -1
  228. package/bin/tts/runtime/Synthesizer.d.ts +0 -44
  229. package/bin/tts/runtime/Synthesizer.d.ts.map +0 -1
  230. package/bin/tts/runtime/Synthesizer.js +0 -363
  231. package/bin/tts/runtime/Synthesizer.js.map +0 -1
  232. package/bin/tts/types/Tts.d.ts +0 -91
  233. package/bin/tts/types/Tts.d.ts.map +0 -1
  234. package/bin/tts/types/Tts.js +0 -9
  235. package/bin/tts/types/Tts.js.map +0 -1
  236. package/bin/voice/Config.d.ts +0 -43
  237. package/bin/voice/Config.d.ts.map +0 -1
  238. package/bin/voice/Config.js +0 -104
  239. package/bin/voice/Config.js.map +0 -1
  240. package/bin/voice/Dependency.d.ts +0 -77
  241. package/bin/voice/Dependency.d.ts.map +0 -1
  242. package/bin/voice/Dependency.js +0 -237
  243. package/bin/voice/Dependency.js.map +0 -1
  244. package/bin/voice/InboundAugment.d.ts +0 -17
  245. package/bin/voice/InboundAugment.d.ts.map +0 -1
  246. package/bin/voice/InboundAugment.js +0 -47
  247. package/bin/voice/InboundAugment.js.map +0 -1
  248. package/bin/voice/ModelCatalog.d.ts +0 -29
  249. package/bin/voice/ModelCatalog.d.ts.map +0 -1
  250. package/bin/voice/ModelCatalog.js +0 -25
  251. package/bin/voice/ModelCatalog.js.map +0 -1
  252. package/bin/voice/runtime/Catalog.d.ts +0 -18
  253. package/bin/voice/runtime/Catalog.d.ts.map +0 -1
  254. package/bin/voice/runtime/Catalog.js +0 -61
  255. package/bin/voice/runtime/Catalog.js.map +0 -1
  256. package/bin/voice/runtime/DependencyInstaller.d.ts +0 -145
  257. package/bin/voice/runtime/DependencyInstaller.d.ts.map +0 -1
  258. package/bin/voice/runtime/DependencyInstaller.js +0 -309
  259. package/bin/voice/runtime/DependencyInstaller.js.map +0 -1
  260. package/bin/voice/runtime/Installer.d.ts +0 -94
  261. package/bin/voice/runtime/Installer.d.ts.map +0 -1
  262. package/bin/voice/runtime/Installer.js +0 -200
  263. package/bin/voice/runtime/Installer.js.map +0 -1
  264. package/bin/voice/runtime/Paths.d.ts +0 -8
  265. package/bin/voice/runtime/Paths.d.ts.map +0 -1
  266. package/bin/voice/runtime/Paths.js +0 -26
  267. package/bin/voice/runtime/Paths.js.map +0 -1
  268. package/bin/voice/runtime/Transcriber.d.ts +0 -57
  269. package/bin/voice/runtime/Transcriber.d.ts.map +0 -1
  270. package/bin/voice/runtime/Transcriber.js +0 -329
  271. package/bin/voice/runtime/Transcriber.js.map +0 -1
  272. package/bin/voice/types/Voice.d.ts +0 -58
  273. package/bin/voice/types/Voice.d.ts.map +0 -1
  274. package/bin/voice/types/Voice.js +0 -9
  275. package/bin/voice/types/Voice.js.map +0 -1
  276. package/bin/voice/types/VoicePlugin.d.ts +0 -190
  277. package/bin/voice/types/VoicePlugin.d.ts.map +0 -1
  278. package/bin/voice/types/VoicePlugin.js +0 -9
  279. package/bin/voice/types/VoicePlugin.js.map +0 -1
  280. package/bin/web/Dependency.d.ts +0 -10
  281. package/bin/web/Dependency.d.ts.map +0 -1
  282. package/bin/web/Dependency.js +0 -10
  283. package/bin/web/Dependency.js.map +0 -1
  284. package/bin/web/PROMPT.agent-browser.d.ts +0 -7
  285. package/bin/web/PROMPT.agent-browser.d.ts.map +0 -1
  286. package/bin/web/PROMPT.agent-browser.js +0 -8
  287. package/bin/web/PROMPT.agent-browser.js.map +0 -1
  288. package/bin/web/PROMPT.web-access.d.ts +0 -7
  289. package/bin/web/PROMPT.web-access.d.ts.map +0 -1
  290. package/bin/web/PROMPT.web-access.js +0 -8
  291. package/bin/web/PROMPT.web-access.js.map +0 -1
  292. package/bin/web/runtime/Config.d.ts +0 -21
  293. package/bin/web/runtime/Config.d.ts.map +0 -1
  294. package/bin/web/runtime/Config.js +0 -79
  295. package/bin/web/runtime/Config.js.map +0 -1
  296. package/bin/web/runtime/Source.d.ts +0 -29
  297. package/bin/web/runtime/Source.d.ts.map +0 -1
  298. package/bin/web/runtime/Source.js +0 -209
  299. package/bin/web/runtime/Source.js.map +0 -1
  300. package/src/asr/Config.ts +0 -138
  301. package/src/asr/Dependency.ts +0 -336
  302. package/src/asr/InboundAugment.ts +0 -59
  303. package/src/asr/ModelCatalog.ts +0 -43
  304. package/src/tts/Dependency.ts +0 -473
  305. package/src/tts/PluginSupport.ts +0 -85
  306. package/src/tts/runtime/Catalog.ts +0 -97
  307. package/src/tts/runtime/DependencyInstaller.ts +0 -436
  308. package/src/tts/runtime/Installer.ts +0 -297
  309. package/src/tts/runtime/Paths.ts +0 -39
  310. package/src/tts/runtime/Synthesizer.ts +0 -480
  311. package/src/tts/types/Tts.ts +0 -99
  312. package/src/voice/Config.ts +0 -135
  313. package/src/voice/Dependency.ts +0 -329
  314. package/src/voice/InboundAugment.ts +0 -59
  315. package/src/voice/ModelCatalog.ts +0 -43
  316. package/src/voice/runtime/Catalog.ts +0 -68
  317. package/src/voice/runtime/DependencyInstaller.ts +0 -505
  318. package/src/voice/runtime/Installer.ts +0 -324
  319. package/src/voice/runtime/Paths.ts +0 -26
  320. package/src/voice/runtime/Transcriber.ts +0 -467
  321. package/src/voice/types/Voice.ts +0 -68
  322. package/src/voice/types/VoicePlugin.ts +0 -194
  323. package/src/web/Dependency.ts +0 -17
  324. package/src/web/PROMPT.agent-browser.ts +0 -9
  325. package/src/web/PROMPT.agent-browser.ts.txt +0 -17
  326. package/src/web/PROMPT.web-access.ts +0 -9
  327. package/src/web/PROMPT.web-access.ts.txt +0 -13
  328. package/src/web/runtime/Config.ts +0 -105
  329. package/src/web/runtime/Source.ts +0 -257
@@ -1,188 +0,0 @@
1
- /**
2
- * TTS 模型安装器。
3
- *
4
- * 关键点(中文)
5
- * - 统一把 HuggingFace 资源下载到本地模型目录。
6
- * - 支持“整仓下载”与“仅下载指定文件”两种模式。
7
- */
8
- import fs from "node:fs";
9
- import path from "node:path";
10
- import { Readable } from "node:stream";
11
- import { pipeline } from "node:stream/promises";
12
- import fsExtra from "fs-extra";
13
- const HUGGINGFACE_HOST = "https://huggingface.co";
14
- const TTS_INSTALL_MANIFEST = "downcity.tts.install.json";
15
- function encodePathSegments(input) {
16
- return input
17
- .split("/")
18
- .map((segment) => encodeURIComponent(segment))
19
- .join("/");
20
- }
21
- function buildAuthHeaders(token) {
22
- const t = String(token || "").trim();
23
- if (!t)
24
- return undefined;
25
- return { Authorization: `Bearer ${t}` };
26
- }
27
- function resolveSafeTargetPath(baseDir, relativePath) {
28
- const normalized = relativePath.replace(/\\/g, "/");
29
- const target = path.resolve(baseDir, normalized);
30
- const base = path.resolve(baseDir);
31
- if (target !== base && !target.startsWith(`${base}${path.sep}`)) {
32
- throw new Error(`Unsafe file path from HuggingFace: ${relativePath}`);
33
- }
34
- return target;
35
- }
36
- async function readRepoFiles(input) {
37
- const repoUrlPath = encodePathSegments(input.repoId);
38
- const metadataUrl = `${HUGGINGFACE_HOST}/api/models/${repoUrlPath}`;
39
- const response = await fetch(metadataUrl, {
40
- headers: {
41
- Accept: "application/json",
42
- ...(buildAuthHeaders(input.hfToken) || {}),
43
- },
44
- });
45
- if (!response.ok) {
46
- const responseText = await response.text().catch(() => "");
47
- throw new Error(`Failed to fetch model metadata (${input.repoId}): HTTP ${response.status}${responseText ? ` ${responseText.slice(0, 300)}` : ""}`);
48
- }
49
- const payload = (await response.json());
50
- const files = (Array.isArray(payload.siblings) ? payload.siblings : [])
51
- .map((item) => String(item?.rfilename || "").trim())
52
- .filter(Boolean)
53
- .filter((item) => item !== ".gitattributes");
54
- if (files.length === 0) {
55
- throw new Error(`No downloadable files found in repo: ${input.repoId}`);
56
- }
57
- return files;
58
- }
59
- async function downloadModelFile(input) {
60
- const repoPath = encodePathSegments(input.repoId);
61
- const revision = encodeURIComponent(input.revision);
62
- const filePath = encodePathSegments(input.filePath);
63
- const url = `${HUGGINGFACE_HOST}/${repoPath}/resolve/${revision}/${filePath}?download=1`;
64
- const response = await fetch(url, {
65
- headers: {
66
- ...(buildAuthHeaders(input.hfToken) || {}),
67
- },
68
- });
69
- if (!response.ok) {
70
- const responseText = await response.text().catch(() => "");
71
- throw new Error(`Failed to download ${input.filePath}: HTTP ${response.status}${responseText ? ` ${responseText.slice(0, 300)}` : ""}`);
72
- }
73
- if (!response.body) {
74
- throw new Error(`Empty response body for file: ${input.filePath}`);
75
- }
76
- const tempPath = `${input.targetPath}.downloading`;
77
- await fsExtra.ensureDir(path.dirname(input.targetPath));
78
- try {
79
- const body = Readable.fromWeb(response.body);
80
- await pipeline(body, fs.createWriteStream(tempPath));
81
- await fsExtra.move(tempPath, input.targetPath, { overwrite: true });
82
- }
83
- catch (error) {
84
- await fsExtra.remove(tempPath).catch(() => undefined);
85
- throw error;
86
- }
87
- }
88
- /**
89
- * 判断模型在本地是否已安装。
90
- *
91
- * 关键点(中文)
92
- * - 优先识别安装清单 `downcity.tts.install.json`。
93
- * - 若无清单但目录非空,也视为已存在模型,避免重复下载。
94
- */
95
- export async function detectLocalTtsModelInstallState(input) {
96
- const modelDir = path.resolve(input.modelsRootDir, input.modelId);
97
- const manifestPath = path.join(modelDir, TTS_INSTALL_MANIFEST);
98
- const hasManifest = await fsExtra.pathExists(manifestPath);
99
- if (hasManifest) {
100
- return {
101
- modelDir,
102
- installed: true,
103
- source: "manifest",
104
- };
105
- }
106
- const hasModelDir = await fsExtra.pathExists(modelDir);
107
- if (!hasModelDir) {
108
- return {
109
- modelDir,
110
- installed: false,
111
- };
112
- }
113
- const entries = await fsExtra.readdir(modelDir).catch(() => []);
114
- const hasPersistedFiles = entries.some((entry) => !String(entry).endsWith(".downloading"));
115
- if (!hasPersistedFiles) {
116
- return {
117
- modelDir,
118
- installed: false,
119
- };
120
- }
121
- return {
122
- modelDir,
123
- installed: true,
124
- source: "directory",
125
- };
126
- }
127
- /**
128
- * 安装指定 TTS 模型到本地目录。
129
- *
130
- * 关键点(中文)
131
- * - 使用 HTTP 文件级下载,不依赖 git-lfs。
132
- * - 默认复用已有文件;`force=true` 时覆盖重下。
133
- */
134
- export async function installTtsModelFromHuggingFace(input) {
135
- const modelDir = path.resolve(input.modelsRootDir, input.model.id);
136
- await fsExtra.ensureDir(modelDir);
137
- let downloadedFiles = 0;
138
- let skippedFiles = 0;
139
- const downloadedFilePaths = [];
140
- const skippedFilePaths = [];
141
- for (const asset of input.model.assets) {
142
- const assetFiles = Array.isArray(asset.files) && asset.files.length > 0
143
- ? asset.files
144
- : await readRepoFiles({
145
- repoId: asset.repoId,
146
- hfToken: input.hfToken,
147
- });
148
- const assetBaseDir = asset.targetSubdir
149
- ? path.resolve(modelDir, asset.targetSubdir)
150
- : modelDir;
151
- await fsExtra.ensureDir(assetBaseDir);
152
- for (const filePath of assetFiles) {
153
- const relativeToModel = asset.targetSubdir
154
- ? path.posix.join(asset.targetSubdir.replace(/\\/g, "/"), filePath)
155
- : filePath;
156
- const targetPath = resolveSafeTargetPath(assetBaseDir, filePath);
157
- const exists = await fsExtra.pathExists(targetPath);
158
- if (exists && input.force !== true) {
159
- skippedFiles += 1;
160
- skippedFilePaths.push(relativeToModel);
161
- continue;
162
- }
163
- await downloadModelFile({
164
- repoId: asset.repoId,
165
- revision: asset.revision,
166
- filePath,
167
- targetPath,
168
- hfToken: input.hfToken,
169
- });
170
- downloadedFiles += 1;
171
- downloadedFilePaths.push(relativeToModel);
172
- }
173
- }
174
- const manifestPath = path.join(modelDir, TTS_INSTALL_MANIFEST);
175
- await fsExtra.writeJson(manifestPath, {
176
- modelId: input.model.id,
177
- installedAt: new Date().toISOString(),
178
- assets: input.model.assets,
179
- }, { spaces: 2 });
180
- return {
181
- modelDir,
182
- downloadedFiles,
183
- skippedFiles,
184
- downloadedFilePaths,
185
- skippedFilePaths,
186
- };
187
- }
188
- //# sourceMappingURL=Installer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Installer.js","sourceRoot":"","sources":["../../../src/tts/runtime/Installer.ts"],"names":[],"mappings":"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"}
@@ -1,20 +0,0 @@
1
- /**
2
- * TTS 模型目录路径辅助。
3
- *
4
- * 关键点(中文)
5
- * - 统一把相对路径、`~` 与默认目录解析成绝对路径。
6
- */
7
- /**
8
- * 将相对路径解析为绝对路径;空值时回退默认目录。
9
- */
10
- export declare function resolveTtsModelsRootDir(input: {
11
- /**
12
- * 项目根目录。
13
- */
14
- projectRoot: string;
15
- /**
16
- * 用户显式配置的模型目录(可选)。
17
- */
18
- modelsDir?: string;
19
- }): string;
20
- //# sourceMappingURL=Paths.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Paths.d.ts","sourceRoot":"","sources":["../../../src/tts/runtime/Paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAMT"}
@@ -1,32 +0,0 @@
1
- /**
2
- * TTS 模型目录路径辅助。
3
- *
4
- * 关键点(中文)
5
- * - 统一把相对路径、`~` 与默认目录解析成绝对路径。
6
- */
7
- import os from "node:os";
8
- import path from "node:path";
9
- function expandHomePath(inputPath) {
10
- const raw = String(inputPath || "").trim();
11
- if (!raw)
12
- return raw;
13
- if (raw === "~")
14
- return os.homedir();
15
- if (raw.startsWith("~/")) {
16
- return path.join(os.homedir(), raw.slice(2));
17
- }
18
- return raw;
19
- }
20
- /**
21
- * 将相对路径解析为绝对路径;空值时回退默认目录。
22
- */
23
- export function resolveTtsModelsRootDir(input) {
24
- const fallback = path.join(os.homedir(), ".downcity", "models", "tts");
25
- const raw = expandHomePath(String(input.modelsDir || fallback).trim());
26
- if (!raw)
27
- return path.resolve(fallback);
28
- if (path.isAbsolute(raw))
29
- return path.resolve(raw);
30
- return path.resolve(input.projectRoot, raw);
31
- }
32
- //# sourceMappingURL=Paths.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Paths.js","sourceRoot":"","sources":["../../../src/tts/runtime/Paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,SAAS,cAAc,CAAC,SAAiB;IACvC,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IACrB,IAAI,GAAG,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IACrC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,KASvC;IACC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AAC9C,CAAC"}
@@ -1,44 +0,0 @@
1
- /**
2
- * TTS 语音合成 runtime。
3
- *
4
- * 关键点(中文)
5
- * - 读取本地模型目录,不再依赖 console 模型池。
6
- * - 根据模型族选择对应 Python runner,并把输出落到本地文件。
7
- */
8
- import type { TtsPluginConfig, TtsSynthesizeInput } from "../../tts/types/TtsPlugin.js";
9
- import type { PluginCommandContext } from "@downcity/agent/internal/plugin/types/Plugin.js";
10
- /**
11
- * 执行一次 TTS 合成,并写出音频文件。
12
- */
13
- export declare function synthesizeSpeechFile(params: {
14
- /**
15
- * 当前执行上下文。
16
- */
17
- context: PluginCommandContext;
18
- /**
19
- * 当前 plugin 配置。
20
- */
21
- config: TtsPluginConfig;
22
- /**
23
- * 本次合成输入。
24
- */
25
- input: TtsSynthesizeInput;
26
- }): Promise<{
27
- /**
28
- * 输出相对路径。
29
- */
30
- outputPath: string;
31
- /**
32
- * 可发送文件标签。
33
- */
34
- fileTag: string;
35
- /**
36
- * 文件字节数。
37
- */
38
- bytes: number;
39
- /**
40
- * Python runner stderr 摘要(可选)。
41
- */
42
- stderrSummary?: string;
43
- }>;
44
- //# sourceMappingURL=Synthesizer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Synthesizer.d.ts","sourceRoot":"","sources":["../../../src/tts/runtime/Synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AAuW5F;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD;;OAEG;IACH,OAAO,EAAE,oBAAoB,CAAC;IAC9B;;OAEG;IACH,MAAM,EAAE,eAAe,CAAC;IACxB;;OAEG;IACH,KAAK,EAAE,kBAAkB,CAAC;CAC3B,GAAG,OAAO,CAAC;IACV;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAyED"}
@@ -1,363 +0,0 @@
1
- /**
2
- * TTS 语音合成 runtime。
3
- *
4
- * 关键点(中文)
5
- * - 读取本地模型目录,不再依赖 console 模型池。
6
- * - 根据模型族选择对应 Python runner,并把输出落到本地文件。
7
- */
8
- import { execFile as execFileCb } from "node:child_process";
9
- import path from "node:path";
10
- import { promisify } from "node:util";
11
- import fs from "fs-extra";
12
- import { renderChatMessageFileTag } from "@downcity/agent/internal/executor/messages/ChatMessageMarkup.js";
13
- import { getTtsModelCatalogItem, resolveTtsModelId } from "../../tts/runtime/Catalog.js";
14
- import { resolveTtsModelsRootDir } from "../../tts/runtime/Paths.js";
15
- const execFileAsync = promisify(execFileCb);
16
- const DEFAULT_TTS_TIMEOUT_MS = 300_000;
17
- function normalizeText(value) {
18
- return String(value || "").trim();
19
- }
20
- function normalizeFormat(value) {
21
- return normalizeText(value).toLowerCase() === "flac" ? "flac" : "wav";
22
- }
23
- function normalizeSpeed(value) {
24
- if (typeof value !== "number" || !Number.isFinite(value) || Number.isNaN(value)) {
25
- return 1;
26
- }
27
- const next = Math.max(0.5, Math.min(2, value));
28
- return Number(next.toFixed(2));
29
- }
30
- function normalizeTimeoutMs(value) {
31
- if (typeof value !== "number" || !Number.isFinite(value) || Number.isNaN(value)) {
32
- return DEFAULT_TTS_TIMEOUT_MS;
33
- }
34
- if (value < 5_000)
35
- return 5_000;
36
- if (value > 900_000)
37
- return 900_000;
38
- return Math.floor(value);
39
- }
40
- function sanitizeFileStem(value) {
41
- return value
42
- .replace(/[^A-Za-z0-9_-]+/g, "-")
43
- .replace(/-+/g, "-")
44
- .replace(/^-+|-+$/g, "")
45
- .slice(0, 48) || "tts";
46
- }
47
- function toProjectRelativePath(projectRoot, targetPath) {
48
- const relative = path.relative(projectRoot, targetPath);
49
- if (!relative)
50
- return null;
51
- if (relative.startsWith(".."))
52
- return null;
53
- if (path.isAbsolute(relative))
54
- return null;
55
- return relative.split(path.sep).join("/");
56
- }
57
- function resolveOutputTarget(params) {
58
- const output = normalizeText(params.output);
59
- const defaultDir = path.join(params.context.paths.getCacheDirPath(), "tts");
60
- const target = output
61
- ? (path.isAbsolute(output)
62
- ? path.normalize(output)
63
- : path.resolve(params.context.rootPath, output))
64
- : defaultDir;
65
- const ext = `.${params.format}`;
66
- const hasExplicitFile = Boolean(path.extname(target));
67
- const filePath = hasExplicitFile
68
- ? target
69
- : path.join(target, `${Date.now()}-${sanitizeFileStem(params.modelId)}${ext}`);
70
- const relativePath = toProjectRelativePath(params.context.rootPath, filePath);
71
- if (!relativePath) {
72
- throw new Error(`TTS output must stay inside project root: ${filePath}`);
73
- }
74
- return {
75
- absPath: filePath,
76
- relativePath,
77
- };
78
- }
79
- function pickLastNonEmptyLine(value) {
80
- const lines = String(value || "")
81
- .split(/\r?\n/)
82
- .map((line) => line.trim())
83
- .filter(Boolean);
84
- return lines.length > 0 ? lines[lines.length - 1] : "";
85
- }
86
- /**
87
- * 判断一条 stderr 是否属于可忽略的 Python 推理提示。
88
- *
89
- * 关键点(中文)
90
- * - 某些第三方库会把 warning / info 打到 stderr,但并不影响音频文件生成。
91
- * - 这里只过滤已知的非致命提示,避免把真实错误静默吞掉。
92
- */
93
- function isIgnorablePythonStderrLine(value) {
94
- const line = normalizeText(value);
95
- if (!line)
96
- return true;
97
- if (/^Setting `pad_token_id` to `eos_token_id`/u.test(line))
98
- return true;
99
- if (/^`torch_dtype` is deprecated!/u.test(line))
100
- return true;
101
- if (/^Warning: flash-attn is not installed\./u.test(line))
102
- return true;
103
- return false;
104
- }
105
- /**
106
- * 提取 stderr 中真正需要上抛的错误文本。
107
- *
108
- * 关键点(中文)
109
- * - 去掉空行与已知 warning 后,只要还有剩余内容,就按真实错误处理。
110
- * - 返回最后一条非 warning 行,方便 CLI 给出更稳定的错误摘要。
111
- */
112
- function pickUnexpectedPythonStderr(value) {
113
- const lines = String(value || "")
114
- .split(/\r?\n/)
115
- .map((line) => line.trim())
116
- .filter((line) => Boolean(line) && !isIgnorablePythonStderrLine(line));
117
- return lines.length > 0 ? lines[lines.length - 1] : "";
118
- }
119
- /**
120
- * 归一化 Python stderr 摘要。
121
- *
122
- * 关键点(中文)
123
- * - 某些 runner 会把非致命提示打印到 stderr。
124
- * - 这里保留最后一条真正有意义的内容,供上层作为说明返回。
125
- */
126
- function normalizePythonStderrSummary(value) {
127
- const lines = String(value || "")
128
- .split(/\r?\n/)
129
- .map((line) => line.trim())
130
- .filter(Boolean);
131
- if (lines.length === 0) {
132
- return undefined;
133
- }
134
- return lines[lines.length - 1];
135
- }
136
- function detectLanguageHint(input) {
137
- return /[\u3400-\u9fff]/u.test(input) ? "zh" : "en";
138
- }
139
- function resolveKokoroVoicePath(params) {
140
- const voicesDir = path.join(params.modelDir, "voices");
141
- const requested = normalizeText(params.voice);
142
- if (requested) {
143
- const requestedPath = requested.endsWith(".pt")
144
- ? path.resolve(voicesDir, requested)
145
- : path.resolve(voicesDir, `${requested}.pt`);
146
- if (fs.existsSync(requestedPath)) {
147
- return requestedPath;
148
- }
149
- }
150
- const preferred = params.language === "zh"
151
- ? ["zf_xiaoni.pt", "af_heart.pt"]
152
- : ["af_heart.pt", "zf_xiaoni.pt"];
153
- for (const fileName of preferred) {
154
- const candidate = path.join(voicesDir, fileName);
155
- if (fs.existsSync(candidate)) {
156
- return candidate;
157
- }
158
- }
159
- const entries = fs.readdirSync(voicesDir).filter((item) => item.endsWith(".pt"));
160
- if (entries.length === 0) {
161
- throw new Error(`kokoro voice assets are missing: ${voicesDir}`);
162
- }
163
- return path.join(voicesDir, entries[0]);
164
- }
165
- function buildPythonExecEnv(pythonBin) {
166
- const env = { ...process.env };
167
- const raw = String(pythonBin || "").trim();
168
- if (!raw || (!raw.includes("/") && !raw.includes("\\"))) {
169
- return env;
170
- }
171
- const pythonDir = path.dirname(path.resolve(raw));
172
- const currentPath = String(env.PATH || "");
173
- const segments = currentPath
174
- .split(path.delimiter)
175
- .map((item) => item.trim())
176
- .filter(Boolean);
177
- if (!segments.includes(pythonDir)) {
178
- env.PATH = [pythonDir, ...segments].join(path.delimiter);
179
- }
180
- return env;
181
- }
182
- async function runPythonInline(params) {
183
- let stdout = "";
184
- let stderr = "";
185
- try {
186
- const output = await execFileAsync(params.pythonBin, ["-c", params.script, ...params.args], {
187
- timeout: params.timeoutMs,
188
- maxBuffer: 8 * 1024 * 1024,
189
- env: buildPythonExecEnv(params.pythonBin),
190
- });
191
- stdout = String(output.stdout || "");
192
- stderr = String(output.stderr || "");
193
- }
194
- catch (error) {
195
- const errorLike = error;
196
- stdout = String(errorLike.stdout || "");
197
- stderr = String(errorLike.stderr || "");
198
- const err = pickLastNonEmptyLine(stderr) || pickLastNonEmptyLine(stdout);
199
- if (err) {
200
- throw new Error(`python runner failed: ${err}`);
201
- }
202
- throw new Error(`python runner failed: ${String(errorLike.message || error)}`);
203
- }
204
- const err = pickUnexpectedPythonStderr(stderr);
205
- return {
206
- stderrSummary: err || normalizePythonStderrSummary(stderr),
207
- };
208
- }
209
- const KOKORO_INLINE_SCRIPT = [
210
- "import numpy as np",
211
- "import soundfile as sf",
212
- "import torch",
213
- "from kokoro import KModel, KPipeline",
214
- "config_path = __import__('sys').argv[1]",
215
- "model_path = __import__('sys').argv[2]",
216
- "voice_path = __import__('sys').argv[3]",
217
- "lang_code = __import__('sys').argv[4]",
218
- "text = __import__('sys').argv[5]",
219
- "output_path = __import__('sys').argv[6]",
220
- "speed = float(__import__('sys').argv[7])",
221
- "device = 'cuda' if torch.cuda.is_available() else 'cpu'",
222
- "model = KModel(config=config_path, model=model_path).to(device).eval()",
223
- "pipeline = KPipeline(lang_code=lang_code, model=model, device=device)",
224
- "chunks = []",
225
- "for _, _, audio in pipeline(text, voice=voice_path, speed=speed):",
226
- " if audio is None:",
227
- " continue",
228
- " chunks.append(audio.cpu().numpy() if hasattr(audio, 'cpu') else np.asarray(audio))",
229
- "if not chunks:",
230
- " raise RuntimeError('kokoro returned empty audio')",
231
- "wave = np.concatenate(chunks)",
232
- "sf.write(output_path, wave, 24000)",
233
- "print(output_path)",
234
- ].join("\n");
235
- const QWEN3_INLINE_SCRIPT = [
236
- "import soundfile as sf",
237
- "import torch",
238
- "from qwen_tts import Qwen3TTSModel",
239
- "model_path = __import__('sys').argv[1]",
240
- "text = __import__('sys').argv[2]",
241
- "voice = __import__('sys').argv[3]",
242
- "language = __import__('sys').argv[4]",
243
- "output_path = __import__('sys').argv[5]",
244
- "speed = float(__import__('sys').argv[6])",
245
- "device = 'cuda' if torch.cuda.is_available() else 'cpu'",
246
- "dtype = torch.bfloat16 if torch.cuda.is_available() else torch.float32",
247
- "model = Qwen3TTSModel.from_pretrained(model_path, device_map=device, dtype=dtype)",
248
- "speakers = model.get_supported_speakers() or []",
249
- "speaker = voice if voice and voice in speakers else (speakers[0] if speakers else voice)",
250
- "if not speaker:",
251
- " raise RuntimeError('qwen3 supported speaker list is empty')",
252
- "languages = model.get_supported_languages() or []",
253
- "resolved_language = language if language and language in languages else ('Auto' if 'Auto' in languages else (languages[0] if languages else 'Auto'))",
254
- "wavs, sample_rate = model.generate_custom_voice(text=text, speaker=speaker, language=resolved_language, non_streaming_mode=True, do_sample=True, top_p=0.9, temperature=0.7, repetition_penalty=1.05)",
255
- "wave = wavs[0] if isinstance(wavs, list) else wavs",
256
- "sf.write(output_path, wave, sample_rate)",
257
- "print(output_path)",
258
- ].join("\n");
259
- async function runKokoroSynthesizer(params) {
260
- const voicePath = resolveKokoroVoicePath({
261
- modelDir: params.modelDir,
262
- voice: params.voice,
263
- language: params.language,
264
- });
265
- const configPath = path.join(params.modelDir, "config.json");
266
- const modelPath = path.join(params.modelDir, "kokoro-v1_0.pth");
267
- return runPythonInline({
268
- pythonBin: params.pythonBin,
269
- script: KOKORO_INLINE_SCRIPT,
270
- args: [
271
- configPath,
272
- modelPath,
273
- voicePath,
274
- params.language === "zh" ? "z" : "a",
275
- params.text,
276
- params.outputPath,
277
- String(params.speed),
278
- ],
279
- timeoutMs: params.timeoutMs,
280
- });
281
- }
282
- async function runQwen3Synthesizer(params) {
283
- return runPythonInline({
284
- pythonBin: params.pythonBin,
285
- script: QWEN3_INLINE_SCRIPT,
286
- args: [
287
- params.modelDir,
288
- params.text,
289
- normalizeText(params.voice),
290
- params.language === "zh" ? "Chinese" : params.language === "en" ? "English" : "Auto",
291
- params.outputPath,
292
- String(params.speed),
293
- ],
294
- timeoutMs: params.timeoutMs,
295
- });
296
- }
297
- /**
298
- * 执行一次 TTS 合成,并写出音频文件。
299
- */
300
- export async function synthesizeSpeechFile(params) {
301
- const text = normalizeText(params.input.text);
302
- if (!text) {
303
- throw new Error("tts synthesize requires text");
304
- }
305
- const modelId = resolveTtsModelId(normalizeText(params.input.modelId || params.config.modelId));
306
- if (!modelId) {
307
- throw new Error("tts modelId is missing");
308
- }
309
- const model = getTtsModelCatalogItem(modelId);
310
- if (!model) {
311
- throw new Error(`Unsupported tts model: ${modelId}`);
312
- }
313
- const format = normalizeFormat(params.input.format || params.config.format);
314
- const speed = normalizeSpeed(typeof params.input.speed === "number" ? params.input.speed : params.config.speed);
315
- const language = normalizeText(params.input.language || params.config.language) ||
316
- detectLanguageHint(text);
317
- const pythonBin = normalizeText(params.config.pythonBin) || "python3";
318
- const timeoutMs = normalizeTimeoutMs(params.config.timeoutMs);
319
- const modelsRootDir = resolveTtsModelsRootDir({
320
- projectRoot: params.context.rootPath,
321
- modelsDir: params.config.modelsDir,
322
- });
323
- const modelDir = path.join(modelsRootDir, modelId);
324
- const output = resolveOutputTarget({
325
- context: params.context,
326
- format,
327
- output: normalizeText(params.input.output || params.config.outputDir),
328
- modelId,
329
- });
330
- await fs.ensureDir(path.dirname(output.absPath));
331
- const runResult = model.family === "kokoro"
332
- ? await runKokoroSynthesizer({
333
- pythonBin,
334
- modelDir,
335
- text,
336
- voice: params.input.voice || params.config.voice,
337
- language,
338
- outputPath: output.absPath,
339
- speed,
340
- timeoutMs,
341
- })
342
- : await runQwen3Synthesizer({
343
- pythonBin,
344
- modelDir,
345
- text,
346
- voice: params.input.voice || params.config.voice,
347
- language,
348
- outputPath: output.absPath,
349
- speed,
350
- timeoutMs,
351
- });
352
- const stats = await fs.stat(output.absPath);
353
- return {
354
- outputPath: output.relativePath,
355
- fileTag: renderChatMessageFileTag({
356
- type: "audio",
357
- path: output.relativePath,
358
- }),
359
- bytes: stats.size,
360
- ...(runResult.stderrSummary ? { stderrSummary: runResult.stderrSummary } : {}),
361
- };
362
- }
363
- //# sourceMappingURL=Synthesizer.js.map