volcengine-api-mcp 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +93 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/ark.d.ts +28 -0
- package/dist/lib/ark.js +105 -0
- package/dist/lib/ark.js.map +1 -0
- package/dist/lib/auc.d.ts +67 -0
- package/dist/lib/auc.js +160 -0
- package/dist/lib/auc.js.map +1 -0
- package/dist/lib/client.d.ts +18 -0
- package/dist/lib/client.js +117 -0
- package/dist/lib/client.js.map +1 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.js +9 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/search.d.ts +41 -0
- package/dist/lib/search.js +160 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/signer.d.ts +17 -0
- package/dist/lib/signer.js +58 -0
- package/dist/lib/signer.js.map +1 -0
- package/dist/lib/tos.d.ts +29 -0
- package/dist/lib/tos.js +93 -0
- package/dist/lib/tos.js.map +1 -0
- package/dist/lib/tts.d.ts +59 -0
- package/dist/lib/tts.js +126 -0
- package/dist/lib/tts.js.map +1 -0
- package/dist/lib/types.d.ts +34 -0
- package/dist/lib/types.js +15 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/tools/auc.d.ts +34 -0
- package/dist/tools/auc.js +76 -0
- package/dist/tools/auc.js.map +1 -0
- package/dist/tools/image.d.ts +37 -0
- package/dist/tools/image.js +58 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/search.d.ts +38 -0
- package/dist/tools/search.js +56 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/tos.d.ts +30 -0
- package/dist/tools/tos.js +38 -0
- package/dist/tools/tos.js.map +1 -0
- package/dist/tools/tts.d.ts +43 -0
- package/dist/tools/tts.js +80 -0
- package/dist/tools/tts.js.map +1 -0
- package/package.json +48 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marvin Pan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,94 @@
|
|
|
1
|
-
#
|
|
1
|
+
# volcengine-api-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
把火山引擎 OpenAPI 封装为 [MCP](https://modelcontextprotocol.io) 服务,供 Claude / Cursor / Cline 等 Agent 直接调用。
|
|
4
|
+
|
|
5
|
+
## 项目结构
|
|
6
|
+
|
|
7
|
+
单包仓库:`src/lib/` 是火山各产品的 API 客户端,`src/tools/` 是 MCP 工具,`src/index.ts` 为 server 入口。
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
lib/ # API 客户端:ark(方舟生图)/ tts(语音合成)/ tos(对象存储)/ auc(语音识别)/ search(联网搜索)/ client + signer(V4 签名底座)
|
|
12
|
+
tools/ # MCP 工具封装(每个文件对应一类 API)
|
|
13
|
+
index.ts # MCP Server 入口(stdio 传输)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 快速开始
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm install
|
|
20
|
+
pnpm build # 构建到 dist/
|
|
21
|
+
pnpm dev # 以 tsx 直接启动 MCP server(开发)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 配置凭据
|
|
25
|
+
|
|
26
|
+
各工具独立取自己的环境变量(参考 `.env.example`),**不用哪个工具就不用配**;配置缺失只在调用对应工具时报错。
|
|
27
|
+
|
|
28
|
+
| 工具 | 必需 | 可选 |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `plan_images_generations` | `ARK_API_KEY`(`ark-` 开头,必须显式配置,不做其他回退) | — |
|
|
31
|
+
| `plan_tts_unidirectional` | 同上(复用 `ARK_API_KEY`,走方舟 Agent Plan 网关) | — |
|
|
32
|
+
| `tos_object_put` | `VOLC_TOS_ACCESS_KEY` / `VOLC_TOS_SECRET_KEY` / `VOLC_TOS_BUCKET` / `VOLC_TOS_REGION` | `VOLC_TOS_ENDPOINT`、`VOLC_TOS_PREFIX`(key 前缀,默认 `volcengine-api-mcp`) |
|
|
33
|
+
| `auc_bigmodel_transcribe` | `VOLC_ASR_API_KEY`(火山语音控制台 API Key);传本地音频时还需 TOS 四件套(同上) | — |
|
|
34
|
+
| `askecho_web_search` | `ASK_ECHO_SEARCH_INFINITY_API_KEY`(搜索 API Key)或 `VOLCENGINE_ACCESS_KEY` + `VOLCENGINE_SECRET_KEY`(V4 签名)二者其一 | — |
|
|
35
|
+
|
|
36
|
+
> `VOLCENGINE_ACCESS_KEY` / `VOLCENGINE_SECRET_KEY` 除 `askecho_web_search` 的 AK/SK 鉴权模式外,也供 core 的 V4 签名客户端后续封装其他 OpenAPI 工具使用。
|
|
37
|
+
|
|
38
|
+
### 接入 Claude Code / Cursor
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"volcengine-api": {
|
|
44
|
+
"command": "npx",
|
|
45
|
+
"args": ["-y", "volcengine-api-mcp"],
|
|
46
|
+
"env": {
|
|
47
|
+
"VOLCENGINE_ACCESS_KEY": "your-ak",
|
|
48
|
+
"VOLCENGINE_SECRET_KEY": "your-sk",
|
|
49
|
+
"VOLCENGINE_REGION": "cn-north-1",
|
|
50
|
+
"ARK_API_KEY": "ark-xxx",
|
|
51
|
+
"VOLC_TOS_ACCESS_KEY": "your-ak",
|
|
52
|
+
"VOLC_TOS_SECRET_KEY": "your-sk",
|
|
53
|
+
"VOLC_TOS_BUCKET": "your-bucket",
|
|
54
|
+
"VOLC_TOS_REGION": "cn-beijing",
|
|
55
|
+
"VOLC_ASR_API_KEY": "xxx"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> `npx volcengine-api-mcp` 要求本包已发布到 npm;发布前可临时用本地路径:
|
|
63
|
+
> `"command": "node", "args": ["/absolute/path/to/volcengine-api-mcp/dist/index.js"]`
|
|
64
|
+
|
|
65
|
+
## 提供的工具
|
|
66
|
+
|
|
67
|
+
| 工具 | 说明 |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `plan_images_generations` | 火山方舟文生图(`/api/plan/v3/images/generations`):生成图片落盘并直接返回给 Agent(抽自 nova-voyage 的 ark-image.mjs 逻辑) |
|
|
70
|
+
| `plan_tts_unidirectional` | 豆包语音合成大模型-单向流式(`/api/v3/plan/tts/unidirectional`):文本合成音频落盘并返回给 Agent |
|
|
71
|
+
| `tos_object_put` | 火山引擎 TOS 上传(Action: `PutObject`):文件落 bucket 并返回预签名下载 URL,bucket 保持私有 |
|
|
72
|
+
| `auc_bigmodel_transcribe` | 大模型录音文件识别(`/api/v3/auc/bigmodel/submit` + `query`):提交音频轮询至完成,返回全文 + 分句时间戳 + 说话人(抽自 content-forge clip 的 doubao.ts) |
|
|
73
|
+
| `askecho_web_search` | 联网搜索(豆包搜索,服务 `volc_torchlight_api` / Action `WebSearch`):网页/图片搜索,支持时间/站点/行业过滤与正文返回(移植自 mcp-server 的 askecho_search_infinity) |
|
|
74
|
+
|
|
75
|
+
## 新增具体工具
|
|
76
|
+
|
|
77
|
+
在 `src/tools/` 下新建文件,参照 [tos.ts](src/tools/tos.ts)(单 API 专用工具)或 [image.ts](src/tools/image.ts)(含图片回传的处理类工具),API 客户端放 `src/lib/`:
|
|
78
|
+
|
|
79
|
+
1. 定义 `name` / `description` / zod `inputSchema` / `handler`
|
|
80
|
+
2. 在 [index.ts](packages/mcp-server/src/index.ts) 中 `registerTool` 注册
|
|
81
|
+
|
|
82
|
+
### 工具命名约定
|
|
83
|
+
|
|
84
|
+
统一 `服务_资源_动作`(全小写下划线),从火山 API 推导,让用户一眼对上背后调的是哪个 API:
|
|
85
|
+
|
|
86
|
+
- REST 路径类:取端点路径段,如 `/api/plan/v3/images/generations` → `plan_images_generations`
|
|
87
|
+
- OpenAPI Action 类:拆 Action 名,如 TOS `PutObject` → `tos_object_put`、ECS `DescribeInstances` → `ecs_describe_instances`
|
|
88
|
+
- 语音识别放在 `auc*` 前缀下(openspeech 的 `/api/v3/auc/...` 端点)
|
|
89
|
+
|
|
90
|
+
工具 `description` 里务必写明实际端点路径或 Action 名,方便对照文档。
|
|
91
|
+
|
|
92
|
+
> `src/lib/` 自带火山 Signature V4 签名客户端([client.ts](src/lib/client.ts) + [signer.ts](src/lib/signer.ts)),
|
|
93
|
+
> 可直接调任何火山 OpenAPI(`askecho_web_search` 的 AK/SK 模式已在用);后续封装其他 OpenAPI 工具时
|
|
94
|
+
> 配合 `SERVICE_HOSTS`(已映射 ecs / vpc / iam / vod / live / tls / ces)即可。
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { generateImageTool } from './tools/image.js';
|
|
5
|
+
import { tosPutObjectTool } from './tools/tos.js';
|
|
6
|
+
import { asrTranscribeTool } from './tools/auc.js';
|
|
7
|
+
import { ttsUnidirectionalTool } from './tools/tts.js';
|
|
8
|
+
import { webSearchTool } from './tools/search.js';
|
|
9
|
+
async function main() {
|
|
10
|
+
const server = new McpServer({ name: 'volcengine-api-mcp', version: '0.1.0' }, { instructions: '通过此服务调用火山引擎 API(方舟生图 / TOS / 语音识别等)。' });
|
|
11
|
+
server.registerTool(generateImageTool.name, {
|
|
12
|
+
title: '火山方舟图片生成 plan/images/generations',
|
|
13
|
+
description: generateImageTool.description,
|
|
14
|
+
inputSchema: generateImageTool.inputSchema,
|
|
15
|
+
}, generateImageTool.handler);
|
|
16
|
+
server.registerTool(tosPutObjectTool.name, {
|
|
17
|
+
title: 'TOS 上传文件 tos/object/put',
|
|
18
|
+
description: tosPutObjectTool.description,
|
|
19
|
+
inputSchema: tosPutObjectTool.inputSchema,
|
|
20
|
+
}, tosPutObjectTool.handler);
|
|
21
|
+
server.registerTool(asrTranscribeTool.name, {
|
|
22
|
+
title: '大模型录音文件识别 auc/bigmodel',
|
|
23
|
+
description: asrTranscribeTool.description,
|
|
24
|
+
inputSchema: asrTranscribeTool.inputSchema,
|
|
25
|
+
}, asrTranscribeTool.handler);
|
|
26
|
+
server.registerTool(ttsUnidirectionalTool.name, {
|
|
27
|
+
title: '语音合成(单向流式)plan/tts/unidirectional',
|
|
28
|
+
description: ttsUnidirectionalTool.description,
|
|
29
|
+
inputSchema: ttsUnidirectionalTool.inputSchema,
|
|
30
|
+
}, ttsUnidirectionalTool.handler);
|
|
31
|
+
server.registerTool(webSearchTool.name, {
|
|
32
|
+
title: '联网搜索 askecho/WebSearch',
|
|
33
|
+
description: webSearchTool.description,
|
|
34
|
+
inputSchema: webSearchTool.inputSchema,
|
|
35
|
+
}, webSearchTool.handler);
|
|
36
|
+
const transport = new StdioServerTransport();
|
|
37
|
+
await server.connect(transport);
|
|
38
|
+
console.error('[volcengine-api-mcp] server started on stdio');
|
|
39
|
+
}
|
|
40
|
+
main().catch((err) => {
|
|
41
|
+
console.error('[volcengine-api-mcp] fatal:', err);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,EAChD,EAAE,YAAY,EAAE,sCAAsC,EAAE,CACzD,CAAC;IAEF,MAAM,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAC1C,KAAK,EAAE,kCAAkC;QACzC,WAAW,EAAE,iBAAiB,CAAC,WAAW;QAC1C,WAAW,EAAE,iBAAiB,CAAC,WAAW;KAC3C,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE9B,MAAM,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,EAAE;QACzC,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,gBAAgB,CAAC,WAAW;QACzC,WAAW,EAAE,gBAAgB,CAAC,WAAW;KAC1C,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE7B,MAAM,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAC1C,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,iBAAiB,CAAC,WAAW;QAC1C,WAAW,EAAE,iBAAiB,CAAC,WAAW;KAC3C,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE9B,MAAM,CAAC,YAAY,CAAC,qBAAqB,CAAC,IAAI,EAAE;QAC9C,KAAK,EAAE,mCAAmC;QAC1C,WAAW,EAAE,qBAAqB,CAAC,WAAW;QAC9C,WAAW,EAAE,qBAAqB,CAAC,WAAW;KAC/C,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE;QACtC,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,aAAa,CAAC,WAAW;QACtC,WAAW,EAAE,aAAa,CAAC,WAAW;KACvC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAE1B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;AAChE,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const ARK_DEFAULT_IMAGE_MODEL = "doubao-seedream-5-0-pro-260628";
|
|
2
|
+
export declare const ARK_DEFAULT_SIZE = "1728x2304";
|
|
3
|
+
export interface ArkImageOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
prompt: string;
|
|
6
|
+
model?: string;
|
|
7
|
+
/** 宽x高(如 1728x2304)或 1K/2K/4K */
|
|
8
|
+
size?: string;
|
|
9
|
+
/** 默认不加水印 */
|
|
10
|
+
watermark?: boolean;
|
|
11
|
+
seed?: number;
|
|
12
|
+
/** png / jpeg */
|
|
13
|
+
outputFormat?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ArkImageResult {
|
|
16
|
+
url: string;
|
|
17
|
+
model: string;
|
|
18
|
+
size: string;
|
|
19
|
+
outputFormat: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function validateArkSize(size: string): string;
|
|
22
|
+
/** 调火山方舟(Agent Plan)生图接口,返回图片 URL。 */
|
|
23
|
+
export declare function arkGenerateImage(opts: ArkImageOptions): Promise<ArkImageResult>;
|
|
24
|
+
/** 下载图片并落盘。仅接受 https,重定向逐次校验,最多 5 跳。 */
|
|
25
|
+
export declare function arkDownloadImage(url: string, output: string): Promise<{
|
|
26
|
+
path: string;
|
|
27
|
+
bytes: number;
|
|
28
|
+
}>;
|
package/dist/lib/ark.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { mkdirSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
const API_URL = 'https://ark.cn-beijing.volces.com/api/plan/v3/images/generations';
|
|
4
|
+
const DOWNLOAD_TIMEOUT_MS = 120_000;
|
|
5
|
+
const GENERATE_TIMEOUT_MS = 180_000;
|
|
6
|
+
const MAX_REDIRECT_HOPS = 5;
|
|
7
|
+
export const ARK_DEFAULT_IMAGE_MODEL = 'doubao-seedream-5-0-pro-260628'; // 5.0 pro,文字渲染与细节明显优于 flash
|
|
8
|
+
export const ARK_DEFAULT_SIZE = '1728x2304'; // 2K @ 3:4,与豆包 App 参考图原生分辨率一致
|
|
9
|
+
export function validateArkSize(size) {
|
|
10
|
+
if (/^(1K|2K|4K)$/i.test(size))
|
|
11
|
+
return size.toUpperCase();
|
|
12
|
+
if (!/^\d{3,4}x\d{3,4}$/.test(size)) {
|
|
13
|
+
throw new Error(`size 参数无效:${size}(应为 宽x高,如 1728x2304,或 1K/2K/4K)`);
|
|
14
|
+
}
|
|
15
|
+
const [w, h] = size.split('x').map(Number);
|
|
16
|
+
if (w < 512 || h < 512 || w > 4096 || h > 4096) {
|
|
17
|
+
throw new Error(`size 超出范围(512~4096):${size}`);
|
|
18
|
+
}
|
|
19
|
+
// 方舟接口要求图片面积 ≥ 921600 px(如 960x960),实测 512x512 会被 400 拒绝
|
|
20
|
+
if (w * h < 921_600) {
|
|
21
|
+
throw new Error(`size 面积过小(${w}x${h}=${w * h}px),要求至少 921600px(如 960x960 / 1024x1024)`);
|
|
22
|
+
}
|
|
23
|
+
return size;
|
|
24
|
+
}
|
|
25
|
+
/** 调火山方舟(Agent Plan)生图接口,返回图片 URL。 */
|
|
26
|
+
export async function arkGenerateImage(opts) {
|
|
27
|
+
if (!opts.apiKey?.trim()) {
|
|
28
|
+
throw new Error('未找到有效的方舟 API Key(ark- 开头)。请配置环境变量 ARK_API_KEY 或 ANTHROPIC_AUTH_TOKEN');
|
|
29
|
+
}
|
|
30
|
+
if (!opts.prompt?.trim()) {
|
|
31
|
+
throw new Error('缺少 prompt');
|
|
32
|
+
}
|
|
33
|
+
const model = opts.model || ARK_DEFAULT_IMAGE_MODEL;
|
|
34
|
+
const size = validateArkSize(opts.size || ARK_DEFAULT_SIZE);
|
|
35
|
+
const body = {
|
|
36
|
+
model,
|
|
37
|
+
prompt: opts.prompt,
|
|
38
|
+
size,
|
|
39
|
+
watermark: opts.watermark === true, // 默认不加水印
|
|
40
|
+
response_format: 'url',
|
|
41
|
+
output_format: opts.outputFormat || 'png', // pro 支持 png/jpeg
|
|
42
|
+
};
|
|
43
|
+
if (opts.seed !== undefined)
|
|
44
|
+
body.seed = opts.seed;
|
|
45
|
+
const res = await fetch(API_URL, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: { Authorization: `Bearer ${opts.apiKey.trim()}`, 'Content-Type': 'application/json' },
|
|
48
|
+
body: JSON.stringify(body),
|
|
49
|
+
signal: AbortSignal.timeout(GENERATE_TIMEOUT_MS),
|
|
50
|
+
});
|
|
51
|
+
const payload = (await res.json().catch(() => null));
|
|
52
|
+
if (!res.ok || !payload) {
|
|
53
|
+
throw new Error(`生图接口返回 ${res.status}:${JSON.stringify(payload ?? '响应不是 JSON')}`);
|
|
54
|
+
}
|
|
55
|
+
if (payload.error) {
|
|
56
|
+
throw new Error(`生图接口报错:${JSON.stringify(payload.error)}`);
|
|
57
|
+
}
|
|
58
|
+
const item = payload.data?.[0];
|
|
59
|
+
if (!item?.url) {
|
|
60
|
+
throw new Error(`响应中没有图片 URL:${JSON.stringify(payload).slice(0, 500)}`);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
url: item.url,
|
|
64
|
+
model: payload.model ?? model,
|
|
65
|
+
size: item.size ?? size,
|
|
66
|
+
outputFormat: item.output_format ?? body.output_format,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** 下载图片并落盘。仅接受 https,重定向逐次校验,最多 5 跳。 */
|
|
70
|
+
export async function arkDownloadImage(url, output) {
|
|
71
|
+
let current = url;
|
|
72
|
+
let buf;
|
|
73
|
+
for (let hop = 0; hop < MAX_REDIRECT_HOPS; hop++) {
|
|
74
|
+
const u = new URL(current);
|
|
75
|
+
if (u.protocol !== 'https:') {
|
|
76
|
+
throw new Error(`拒绝非 https 下载地址:${current.slice(0, 80)}`);
|
|
77
|
+
}
|
|
78
|
+
const dl = await fetch(current, {
|
|
79
|
+
signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),
|
|
80
|
+
redirect: 'manual',
|
|
81
|
+
});
|
|
82
|
+
if (dl.status >= 300 && dl.status < 400) {
|
|
83
|
+
const location = dl.headers.get('location');
|
|
84
|
+
if (!location)
|
|
85
|
+
throw new Error(`重定向缺少 location(${dl.status})`);
|
|
86
|
+
current = location;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!dl.ok)
|
|
90
|
+
throw new Error(`下载返回 ${dl.status}`);
|
|
91
|
+
buf = Buffer.from(await dl.arrayBuffer());
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
if (!buf || buf.length === 0)
|
|
95
|
+
throw new Error('下载内容为空');
|
|
96
|
+
const path = resolve(output);
|
|
97
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
98
|
+
writeFileSync(path, buf);
|
|
99
|
+
const bytes = statSync(path).size;
|
|
100
|
+
if (bytes < 1024) {
|
|
101
|
+
throw new Error(`落盘文件过小(${bytes}B),疑似异常响应`);
|
|
102
|
+
}
|
|
103
|
+
return { path, bytes };
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=ark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ark.js","sourceRoot":"","sources":["../../src/lib/ark.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doubao file-transcription ASR client (Volcano Engine speech). Submit an audio URL, poll until
|
|
3
|
+
* done, and normalize the utterances (per-sentence text + start/end + optional speaker).
|
|
4
|
+
* 抽自 content-forge clip 的 asr/doubao.ts,供 MCP 工具 auc_bigmodel_transcribe 使用。
|
|
5
|
+
* 凭据来自环境变量 VOLC_ASR_API_KEY。
|
|
6
|
+
*
|
|
7
|
+
* API(docs.volcengine.com/docs/6561/1354831 与配套结果查询):
|
|
8
|
+
* - 提交 POST https://openspeech.bytedance.com/api/v3/auc/bigmodel/submit
|
|
9
|
+
* - 查询 POST https://openspeech.bytedance.com/api/v3/auc/bigmodel/query
|
|
10
|
+
* 状态码在响应头 X-Api-Status-Code:20000000 完成;20000001/20000002 处理中/排队中;
|
|
11
|
+
* 20000003 无有效语音;其他为失败。查询需回传提交响应的 X-Tt-Logid。
|
|
12
|
+
*/
|
|
13
|
+
/** Resource id per model version: 2.0 is current, 1.0 is legacy */
|
|
14
|
+
declare const RESOURCE_IDS: {
|
|
15
|
+
readonly '2.0': "volc.seedasr.auc";
|
|
16
|
+
readonly '1.0': "volc.bigasr.auc";
|
|
17
|
+
};
|
|
18
|
+
export type AsrModelVersion = keyof typeof RESOURCE_IDS;
|
|
19
|
+
/** One normalized sentence with timing (and speaker when enabled) */
|
|
20
|
+
export interface Utterance {
|
|
21
|
+
text: string;
|
|
22
|
+
/** start time in ms from audio beginning */
|
|
23
|
+
start: number;
|
|
24
|
+
end: number;
|
|
25
|
+
speaker?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface TranscribeOptions {
|
|
28
|
+
/** X-Api-Key from the Volcano speech console */
|
|
29
|
+
apiKey: string;
|
|
30
|
+
/** Publicly fetchable audio URL (pre-signed TOS URL for local files) */
|
|
31
|
+
url: string;
|
|
32
|
+
format: string;
|
|
33
|
+
language?: string;
|
|
34
|
+
model?: AsrModelVersion;
|
|
35
|
+
enableSpeakerInfo?: boolean;
|
|
36
|
+
/** Speaker-diarization model: 200 non-meeting (≤5 speakers) / 300 voiceprint long meetings */
|
|
37
|
+
ssdVersion?: '200' | '300';
|
|
38
|
+
ssdMode?: 0 | 1;
|
|
39
|
+
enableItn?: boolean;
|
|
40
|
+
enablePunc?: boolean;
|
|
41
|
+
enableDdc?: boolean;
|
|
42
|
+
vadSegment?: boolean;
|
|
43
|
+
pollIntervalMs?: number;
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
/** Cancellation for long polls (workflow stages abort through this) */
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
/** Progress hook (e.g. workflow run-log lines) */
|
|
48
|
+
onLog?: (message: string) => void;
|
|
49
|
+
}
|
|
50
|
+
export interface TranscribeResult {
|
|
51
|
+
taskId: string;
|
|
52
|
+
/** Full plain text (joined utterances when the service omits it) */
|
|
53
|
+
text: string;
|
|
54
|
+
utterances: Utterance[];
|
|
55
|
+
raw: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
/** Infer audio format from a path/URL extension; null when unknown */
|
|
58
|
+
export declare function detectFormat(source: string): string | null;
|
|
59
|
+
/** ms → mm:ss (or h:mm:ss beyond an hour) */
|
|
60
|
+
export declare function formatClock(ms: number): string;
|
|
61
|
+
/** Human-readable transcript: one line per utterance with [clock] and optional speaker */
|
|
62
|
+
export declare function renderTranscriptMd(utterances: Utterance[]): string;
|
|
63
|
+
/** Normalize the raw utterances[] of the API result */
|
|
64
|
+
export declare function normalizeUtterances(raw: unknown): Utterance[];
|
|
65
|
+
/** Full submit → poll → normalize round-trip */
|
|
66
|
+
export declare function transcribeAudio(opts: TranscribeOptions): Promise<TranscribeResult>;
|
|
67
|
+
export {};
|
package/dist/lib/auc.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doubao file-transcription ASR client (Volcano Engine speech). Submit an audio URL, poll until
|
|
3
|
+
* done, and normalize the utterances (per-sentence text + start/end + optional speaker).
|
|
4
|
+
* 抽自 content-forge clip 的 asr/doubao.ts,供 MCP 工具 auc_bigmodel_transcribe 使用。
|
|
5
|
+
* 凭据来自环境变量 VOLC_ASR_API_KEY。
|
|
6
|
+
*
|
|
7
|
+
* API(docs.volcengine.com/docs/6561/1354831 与配套结果查询):
|
|
8
|
+
* - 提交 POST https://openspeech.bytedance.com/api/v3/auc/bigmodel/submit
|
|
9
|
+
* - 查询 POST https://openspeech.bytedance.com/api/v3/auc/bigmodel/query
|
|
10
|
+
* 状态码在响应头 X-Api-Status-Code:20000000 完成;20000001/20000002 处理中/排队中;
|
|
11
|
+
* 20000003 无有效语音;其他为失败。查询需回传提交响应的 X-Tt-Logid。
|
|
12
|
+
*/
|
|
13
|
+
const SUBMIT_URL = 'https://openspeech.bytedance.com/api/v3/auc/bigmodel/submit';
|
|
14
|
+
const QUERY_URL = 'https://openspeech.bytedance.com/api/v3/auc/bigmodel/query';
|
|
15
|
+
const STATUS_OK = '20000000';
|
|
16
|
+
const STATUS_RUNNING = new Set(['20000001', '20000002']);
|
|
17
|
+
const STATUS_SILENCE = '20000003';
|
|
18
|
+
/** Resource id per model version: 2.0 is current, 1.0 is legacy */
|
|
19
|
+
const RESOURCE_IDS = { '2.0': 'volc.seedasr.auc', '1.0': 'volc.bigasr.auc' };
|
|
20
|
+
/** Infer audio format from a path/URL extension; null when unknown */
|
|
21
|
+
export function detectFormat(source) {
|
|
22
|
+
const ext = source.split('?')[0].split('#')[0].split('.').pop()?.toLowerCase() ?? '';
|
|
23
|
+
return ['wav', 'mp3', 'ogg', 'spx', 'amr', 'aac', 'm4a'].includes(ext) ? ext : null;
|
|
24
|
+
}
|
|
25
|
+
/** ms → mm:ss (or h:mm:ss beyond an hour) */
|
|
26
|
+
export function formatClock(ms) {
|
|
27
|
+
const total = Math.round(ms / 1000);
|
|
28
|
+
const h = Math.floor(total / 3600);
|
|
29
|
+
const m = Math.floor((total % 3600) / 60);
|
|
30
|
+
const s = total % 60;
|
|
31
|
+
const mm = h > 0 ? String(m).padStart(2, '0') : String(m);
|
|
32
|
+
return `${h > 0 ? `${h}:` : ''}${mm}:${String(s).padStart(2, '0')}`;
|
|
33
|
+
}
|
|
34
|
+
/** Human-readable transcript: one line per utterance with [clock] and optional speaker */
|
|
35
|
+
export function renderTranscriptMd(utterances) {
|
|
36
|
+
return utterances
|
|
37
|
+
.map((u) => {
|
|
38
|
+
const speaker = u.speaker !== undefined ? `(说话人 ${u.speaker})` : '';
|
|
39
|
+
return `**[${formatClock(u.start)} → ${formatClock(u.end)}]**${speaker} ${u.text}`;
|
|
40
|
+
})
|
|
41
|
+
.join('\n\n');
|
|
42
|
+
}
|
|
43
|
+
/** Normalize the raw utterances[] of the API result */
|
|
44
|
+
export function normalizeUtterances(raw) {
|
|
45
|
+
if (!Array.isArray(raw))
|
|
46
|
+
return [];
|
|
47
|
+
return raw
|
|
48
|
+
.map((u) => {
|
|
49
|
+
const r = u;
|
|
50
|
+
const out = {
|
|
51
|
+
text: String(r.text ?? '').trim(),
|
|
52
|
+
start: Number(r.start_time ?? 0),
|
|
53
|
+
end: Number(r.end_time ?? 0),
|
|
54
|
+
};
|
|
55
|
+
// 说话人字段随模型版本不同:1.0 顶层 speaker_id;2.0 在 additions.speaker(字符串)
|
|
56
|
+
const additions = r.additions;
|
|
57
|
+
const speaker = r.speaker_id ?? additions?.speaker;
|
|
58
|
+
if (speaker !== undefined && speaker !== null && speaker !== '') {
|
|
59
|
+
out.speaker = Number(speaker);
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
})
|
|
63
|
+
.filter((u) => u.text.length > 0);
|
|
64
|
+
}
|
|
65
|
+
/** POST with the common headers; retries network errors, throws on HTTP failure */
|
|
66
|
+
async function apiPost(url, body, headers, signal, retries = 3) {
|
|
67
|
+
for (let i = 0;; i++) {
|
|
68
|
+
try {
|
|
69
|
+
const res = await fetch(url, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
72
|
+
body: JSON.stringify(body),
|
|
73
|
+
signal,
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 200)}`);
|
|
77
|
+
}
|
|
78
|
+
return res;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
if (signal?.aborted)
|
|
82
|
+
throw err;
|
|
83
|
+
if (i >= retries - 1)
|
|
84
|
+
throw err;
|
|
85
|
+
await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function apiError(res, what) {
|
|
90
|
+
const status = res.headers.get('X-Api-Status-Code') ?? '';
|
|
91
|
+
const message = res.headers.get('X-Api-Message') ?? '';
|
|
92
|
+
return `${what}失败:X-Api-Status-Code=${status || '缺失'},X-Api-Message=${message || '无'}`;
|
|
93
|
+
}
|
|
94
|
+
/** Submit the task and return its id plus the X-Tt-Logid needed by the query calls */
|
|
95
|
+
async function submitTask(opts, headers) {
|
|
96
|
+
const requestId = crypto.randomUUID();
|
|
97
|
+
const res = await apiPost(SUBMIT_URL, {
|
|
98
|
+
user: { uid: 'volcengine-api-mcp' },
|
|
99
|
+
audio: { url: opts.url, format: opts.format },
|
|
100
|
+
request: {
|
|
101
|
+
model_name: 'bigmodel',
|
|
102
|
+
language: opts.language,
|
|
103
|
+
show_utterances: true,
|
|
104
|
+
enable_itn: opts.enableItn,
|
|
105
|
+
enable_punc: opts.enablePunc,
|
|
106
|
+
enable_ddc: opts.enableDdc,
|
|
107
|
+
enable_speaker_info: opts.enableSpeakerInfo,
|
|
108
|
+
ssd_version: opts.ssdVersion,
|
|
109
|
+
ssd_mode: opts.ssdMode,
|
|
110
|
+
vad_segment: opts.vadSegment,
|
|
111
|
+
},
|
|
112
|
+
}, { ...headers, 'X-Api-Request-Id': requestId }, opts.signal).catch((err) => {
|
|
113
|
+
throw new Error(`提交转写任务失败:${err instanceof Error ? err.message : String(err)}`);
|
|
114
|
+
});
|
|
115
|
+
if (res.headers.get('X-Api-Status-Code') !== STATUS_OK) {
|
|
116
|
+
throw new Error(apiError(res, '提交转写任务'));
|
|
117
|
+
}
|
|
118
|
+
return { taskId: requestId, logId: res.headers.get('X-Tt-Logid') ?? '' };
|
|
119
|
+
}
|
|
120
|
+
/** Poll the task until done; 20000003 (silence) resolves to an empty result */
|
|
121
|
+
async function pollTask(opts, headers, taskId, logId) {
|
|
122
|
+
const interval = opts.pollIntervalMs ?? 3000;
|
|
123
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 600_000);
|
|
124
|
+
const log = opts.onLog ?? (() => { });
|
|
125
|
+
for (;;) {
|
|
126
|
+
if (opts.signal?.aborted)
|
|
127
|
+
throw new Error('已取消');
|
|
128
|
+
if (Date.now() > deadline) {
|
|
129
|
+
throw new Error(`转写超时(${Math.round((opts.timeoutMs ?? 600_000) / 1000)}s):任务 ${taskId} 仍未完成`);
|
|
130
|
+
}
|
|
131
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
132
|
+
const res = await apiPost(QUERY_URL, {}, { ...headers, 'X-Api-Request-Id': taskId, ...(logId ? { 'X-Tt-Logid': logId } : {}) }, opts.signal).catch((err) => {
|
|
133
|
+
throw new Error(`查询转写结果失败:${err instanceof Error ? err.message : String(err)}`);
|
|
134
|
+
});
|
|
135
|
+
const status = res.headers.get('X-Api-Status-Code') ?? '';
|
|
136
|
+
if (status === STATUS_OK)
|
|
137
|
+
return (await res.json());
|
|
138
|
+
if (status === STATUS_SILENCE)
|
|
139
|
+
return { result: {} }; // 无有效语音:空结果
|
|
140
|
+
if (!STATUS_RUNNING.has(status))
|
|
141
|
+
throw new Error(apiError(res, '查询转写结果'));
|
|
142
|
+
log(`[asr] 处理中(${status})…`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Full submit → poll → normalize round-trip */
|
|
146
|
+
export async function transcribeAudio(opts) {
|
|
147
|
+
const baseHeaders = {
|
|
148
|
+
'X-Api-Key': opts.apiKey,
|
|
149
|
+
'X-Api-Resource-Id': RESOURCE_IDS[opts.model ?? '2.0'],
|
|
150
|
+
'X-Api-Sequence': '-1',
|
|
151
|
+
};
|
|
152
|
+
const { taskId, logId } = await submitTask(opts, baseHeaders);
|
|
153
|
+
opts.onLog?.(`[asr] 任务已提交 ${taskId}`);
|
|
154
|
+
const raw = await pollTask(opts, baseHeaders, taskId, logId);
|
|
155
|
+
const inner = (raw.result ?? {});
|
|
156
|
+
const utterances = normalizeUtterances(inner.utterances);
|
|
157
|
+
const text = String(inner.text ?? utterances.map((u) => u.text).join(''));
|
|
158
|
+
return { taskId, text, utterances, raw };
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=auc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auc.js","sourceRoot":"","sources":["../../src/lib/auc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type VolcengineApiRequest, type VolcengineApiResponse, type VolcengineCredentials } from './types.js';
|
|
2
|
+
export interface VolcengineClientOptions {
|
|
3
|
+
credentials: VolcengineCredentials;
|
|
4
|
+
region?: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
}
|
|
7
|
+
/** 常见服务的默认 Host(不在此表中的服务回退为 <service>.<region>.volcengineapi.com) */
|
|
8
|
+
export declare const SERVICE_HOSTS: Record<string, string>;
|
|
9
|
+
export declare class VolcengineClient {
|
|
10
|
+
private readonly opts;
|
|
11
|
+
constructor(opts: VolcengineClientOptions);
|
|
12
|
+
private resolveHost;
|
|
13
|
+
request<T = unknown>(req: VolcengineApiRequest): Promise<VolcengineApiResponse<T>>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 把嵌套参数展开成火山 API 需要的扁平 query(如 List.1.Name=a&List.1.Id=b)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function flattenParams(params: Record<string, unknown>, prefix?: string): Record<string, string>;
|