coze-plugin-utils
Version:
Comprehensive utility library for Coze plugins with multimedia processing, browser automation, cloud storage integration, and AI-powered video/audio generation capabilities
538 lines (420 loc) • 17.4 kB
Markdown
# Coze 插件工具函数库
这是一个为 Coze 插件开发提供实用工具函数的 TypeScript 库。该库提供了多种实用功能,帮助开发者更轻松地构建 Coze 插件。
## 功能特点
- **全局配置管理**:提供统一的配置管理机制,支持设置和获取全局配置
- **实用工具函数**:提供常用的辅助函数,如 `sleep` 延时函数
- **MIME 类型检测**:支持检测多种文件类型的 MIME 类型
- **图像处理**:支持图像获取和 Base64 转换
- **音视频处理**:
- 音频格式转换(支持 mp3、wav、ogg、flac 等格式)
- 视频与音频合并
- 视频字幕添加(ASS 格式)
- 多个视频文件合并
- **第三方 API 集成**:支持与 Vidu API 集成的视频处理功能
## 快速使用
### 准备工作
在 Coze 工作流中进行文件处理后(比如处理了图像、音频、视频等),要将重新文件上传,可以通过 Coze 自身的机制实现,在使用 SDK 前,需要先做一些准备工作。
1. 首先需要解决鉴权问题,这里我们采用服务类应用 JWT 认证。
进入 Coze 开发平台,左侧菜单切换到 API,选择"授权 > OAuth 应用 > 创建新应用”。
<img src="https://bot.hupox.com/resource/jwk52htao5/1b6addfc14004accbc1f5830b5e91e78.png" width=450>
应用创建完成后,选择“下载示例文件”,将文件中的 `private_key` 和 `public_key_id` 保存下来。
2. 切换到“工作空间 > 资源库 > 新资源 > 工作流”,创建一个工作流。
<img src="https://bot.hupox.com/resource/bgxxqktwc7/dc03fdfb903942e6a3833b4c4cd76a43.png" width=450>
编辑这个工作流,直接连接开始节点和结束节点:
- 开始节点输入参数为 file,类型是 `File<Default>`
- 结束节点输入参数为 url,直接引用开始节点的 file 参数
发布这个工作流,记录它的 workflow_id,这样就完成了准备工作。
### 安装
虽然 `coze-plugin-utils` 在本地也可以用,但它主要是为 Coze 插件准备的。
首先在资源库创建一个插件,点左侧添加依赖包,选择 `coze-plugin-utils`,等待安装完成。
### 使用示例
#### 配置管理
```typescript
import { setGlobalConfig, getGlobalConfig } from 'coze-plugin-utils';
// 设置全局配置
setGlobalConfig({
baseUrl: 'https://custom-api.coze.cn',
jwt: {
appId: 'your-app-id',
userId: 'your-user-id',
keyid: 'your-key-id',
privateKey: 'your-private-key'
}
});
// 获取配置
const config = getGlobalConfig();
console.log(`API 基础地址: ${config.baseUrl}`);
// 按键获取特定配置
const jwt = getGlobalConfig('jwt');
if (jwt) {
console.log(`应用 ID: ${jwt.appId}`);
}
```
### 基础工具函数
```typescript
import { sleep, detectMimeType } from 'coze-plugin-utils';
// 使用 sleep 函数延迟执行
async function delayedOperation() {
console.log('开始操作');
await sleep(1000); // 延迟 1 秒
console.log('延迟后继续');
}
// 检测文件 MIME 类型
const buffer = Buffer.from(/* 文件数据 */);
const mimeType = detectMimeType(buffer);
console.log(`文件类型: ${mimeType}`);
```
### 图像处理
```typescript
import { fetchImageAsBase64 } from 'coze-plugin-utils';
async function getImage() {
try {
const imageUrl = 'https://example.com/image.jpg';
const base64Image = await fetchImageAsBase64(imageUrl);
console.log('图像已转换为 Base64 格式');
// 使用 base64Image 进行后续操作
} catch (error) {
console.error('获取图像失败:', error);
}
}
```
### 音频处理
```typescript
import { convertAudio } from 'coze-plugin-utils';
async function processAudio() {
try {
// 将音频从 WAV 格式转换为 MP3 格式
const outputPath = await convertAudio('https://example.com/audio.wav', 'mp3');
console.log(`音频已转换,输出路径: ${outputPath}`);
// 自动检测源格式并转换为 OGG 格式
const oggPath = await convertAudio('https://example.com/unknown-audio', 'ogg');
console.log(`音频已转换为 OGG 格式: ${oggPath}`);
} catch (error) {
console.error('音频处理失败:', error);
}
}
```
### 视频处理
```typescript
import { mergeVideoAndAudio, burnASSSubtitleToVideo, joinVideos } from 'coze-plugin-utils';
async function processVideos() {
try {
// 合并视频和音频
const mergedPath = await mergeVideoAndAudio(
'https://example.com/video.mp4',
'https://example.com/audio.mp3'
);
console.log(`视频和音频已合并: ${mergedPath}`);
// 添加字幕到视频
const subtitledPath = await burnASSSubtitleToVideo(
'https://example.com/video.mp4',
[{ text: '这是一个示例字幕', effect: '{\\pos(960,1000)}', start: '0:00:01.00', end: '0:00:05.00' }]
);
console.log(`字幕已添加到视频: ${subtitledPath}`);
// 合并多个视频文件
const joinedPath = await joinVideos([
'https://example.com/video1.mp4',
'https://example.com/video2.mp4',
'https://example.com/video3.mp4'
]);
console.log(`多个视频已合并: ${joinedPath}`);
} catch (error) {
console.error('视频处理失败:', error);
}
}
```
### 第三方 API 集成
```typescript
import { setGlobalConfig, vidu, getViduResult } from 'coze-plugin-utils';
// 设置全局配置
setGlobalConfig('vidu', {
apiKey: 'your_vidu_api_key'
});
async function generateVideo() {
try {
// 根据文本生成视频
const textVideoResult = await vidu.textToVideo({
model: 'vidu1.5',
prompt: '一朵花开在山崖上',
bgm: true,
});
console.log('文本生成视频结果:', textVideoResult);
// 根据图片生成视频
const imageVideoResult = await vidu.imageToVideo({
model: 'vidu1.5',
prompt: '花朵绽放',
image: 'https://example.com/flower.jpg',
bgm: true,
});
console.log('图片生成视频结果:', imageVideoResult);
// 根据起始和结束图片生成视频
const startEndVideoResult = await vidu.startEndToVideo({
model: 'vidu1.5',
prompt: '花朵从含苞到绽放',
start_image: 'https://example.com/flower_bud.jpg',
end_image: 'https://example.com/flower_bloom.jpg',
bgm: true,
});
console.log('起始结束图片生成视频结果:', startEndVideoResult);
// 根据参考视频生成新视频
const referenceVideoResult = await vidu.referenceToVideo({
model: 'vidu1.5',
prompt: '花朵在风中摇曳',
reference_video: 'https://example.com/flower_video.mp4',
bgm: true,
});
console.log('参考视频生成结果:', referenceVideoResult);
// 生成音频
const audioResult = await vidu.textToAudio({
model: 'vidu_audio',
prompt: '轻柔的钢琴曲',
duration: 30, // 30秒
});
console.log('文本生成音频结果:', audioResult);
} catch (error) {
console.error('生成失败:', error);
}
}
async function checkVideoTask() {
const taskId = 'your_task_id';
try {
// 方法1:使用全局配置获取视频处理结果
const result = await getViduResult(taskId);
// 方法2:直接传入apiKey
const apiKey = 'your_vidu_api_key';
const result2 = await getViduResult(apiKey, taskId);
if (result.state === 'success') {
console.log('视频处理成功:', result.creations);
} else {
console.log('视频处理状态:', result.state);
if (result.errorMsg) {
console.error('错误信息:', result.errorMsg);
}
}
} catch (error) {
console.error('获取视频结果失败:', error);
}
}
```
## API 文档
### 配置管理 (config.ts)
配置管理模块提供了统一的全局配置管理功能,允许设置和获取全局配置,所有工具依赖的配置都可以通过该模块获取。
#### 配置结构
```typescript
interface IGlobalConfig {
baseUrl: string; // 默认值 https://api.coze.cn
workflows?: IWorkflows;
jwt?: IJWTConfig;
}
interface IJWTConfig {
appId: string;
userId: string;
keyid: string;
privateKey: string;
}
interface IWorkflows {
[key: string]: string;
fileUploader?: string; // 用来上传临时文件
}
```
#### API
- `setGlobalConfig(config: Partial<IGlobalConfig>): IGlobalConfig` - 设置全局配置,将传入的配置与现有配置合并
- `setGlobalConfig<K extends keyof IGlobalConfig>(key: K, config: ...): IGlobalConfig` - 设置特定配置项
- `getGlobalConfig(): IGlobalConfig` - 获取完整的全局配置
- `getGlobalConfig<K extends keyof IGlobalConfig>(key: K): IGlobalConfig[K]` - 获取特定配置项
- `resetGlobalConfig(): IGlobalConfig` - 重置全局配置到默认值
#### 特性
- 支持深度合并嵌套对象(如 workflows 和 jwt)
- 返回配置副本,防止直接修改
- 类型安全,提供完整的 TypeScript 类型支持
- 支持按键设置和获取特定配置项
#### 使用示例
```typescript
import { setGlobalConfig, getGlobalConfig } from 'coze-plugin-utils';
// 设置整个配置对象
setGlobalConfig({
baseUrl: 'https://custom-api.coze.cn',
jwt: {
appId: 'your-app-id',
keyid: 'your-key-id',
privateKey: 'your-private-key'
}
});
// 设置特定配置项
setGlobalConfig('baseUrl', 'https://another-api.coze.cn');
// 获取完整配置
const config = getGlobalConfig();
console.log(config.baseUrl);
// 获取特定配置项
const jwt = getGlobalConfig('jwt');
if (jwt) {
// 使用 JWT 配置进行认证
}
```
### 工具函数 (utils.ts)
- `sleep(ms: number): Promise<void>` - 延迟指定的毫秒数
- `detectMimeType(buffer: Buffer): string | null` - 通过文件头检测 MIME 类型,支持常见的图像、音频和视频格式
### 图像处理 (vendor/vidu.ts)
- `fetchImageAsBase64(url: string): Promise<string>` - 获取图像并转换为 Base64 格式
### 音频处理 (media/ffmpeg.ts)
- `convertAudio(url: string, desType: string, srcType?: string): Promise<string>` - 将音频从一种格式转换为另一种格式
- `url`: 输入音频文件网址
- `desType`: 目标音频格式 (例如: 'mp3', 'wav', 'ogg', 'flac')
- `srcType`: 可选,源音频格式。如果未提供,将通过检测文件头来确定
### 视频处理 (media/ffmpeg.ts)
- `mergeVideoAndAudio(videoUrl: string, audioUrl: string, audioType?: string): Promise<string>` - 将视频和音频合并为一个文件
- `videoUrl`: 视频文件网址
- `audioUrl`: 音频文件网址
- `audioType`: 可选,音频类型 ('wav', 'mp3', 'ogg', 'm4a', 'aac')
- `burnASSSubtitleToVideo(videoUrl: string, contents: IAssEvents[]): Promise<string>` - 将 ASS 格式字幕烧录到视频中
- `videoUrl`: 视频文件网址
- `contents`: 字幕内容数组,包含文本、效果、时间等信息
- `joinVideos(urls: string[], outputFormat?: string): Promise<string>` - 将多个视频文件按顺序合并成一个视频
- `urls`: 视频文件URL数组,按照需要合并的顺序排列
- `outputFormat`: 可选,输出视频格式,默认为 'mp4'
### 第三方 API 集成 (vendor/vidu.ts)
#### 配置 Vidu API
```typescript
import { setGlobalConfig } from 'coze-plugin-tools';
// 设置 Vidu API 密钥
setGlobalConfig('vidu', {
apiKey: 'your_vidu_api_key'
});
```
#### 视频生成 API
- `textToVideo(options: IViduCreationOptions): Promise<IViduResult | { errorMsg: unknown }>` - 根据文本提示生成视频
- `options.model`: 模型名称,如 'vidu1.5'
- `options.prompt`: 文本提示
- `options.bgm`: 是否添加背景音乐
- `options.seed`: 可选,随机种子
- `options.callback_url`: 可选,回调 URL
- `imageToVideo(options: IViduCreationOptions): Promise<IViduResult | { errorMsg: unknown }>` - 根据图片生成视频
- `options.model`: 模型名称
- `options.prompt`: 文本提示
- `options.image`: 图片 URL 或 Base64 字符串
- `options.bgm`: 可选,是否添加背景音乐
- `options.seed`: 可选,随机种子
- `options.callback_url`: 可选,回调 URL
- `startEndToVideo(options: IViduCreationOptions): Promise<IViduResult | { errorMsg: unknown }>` - 根据起始和结束图片生成视频
- `options.model`: 模型名称
- `options.prompt`: 文本提示
- `options.start_image`: 起始图片 URL 或 Base64 字符串
- `options.end_image`: 结束图片 URL 或 Base64 字符串
- `options.bgm`: 可选,是否添加背景音乐
- `options.seed`: 可选,随机种子
- `options.callback_url`: 可选,回调 URL
- `referenceToVideo(options: IViduCreationOptions): Promise<IViduResult | { errorMsg: unknown }>` - 根据参考视频生成新视频
- `options.model`: 模型名称
- `options.prompt`: 文本提示
- `options.reference_video`: 参考视频 URL
- `options.bgm`: 可选,是否添加背景音乐
- `options.seed`: 可选,随机种子
- `options.callback_url`: 可选,回调 URL
#### 音频生成 API
- `textToAudio(options: IAudioTextOptions): Promise<IViduResult | { errorMsg: unknown }>` - 根据文本生成音频
- `options.model`: 模型名称
- `options.prompt`: 文本提示
- `options.duration`: 可选,音频时长
- `options.seed`: 可选,随机种子
- `options.callback_url`: 可选,回调 URL
- `timingToAudio(options: IAudioTimingOptions): Promise<IViduResult | { errorMsg: unknown }>` - 根据时间点提示生成音频
- `options.model`: 模型名称
- `options.timing_prompts`: 时间点提示数组
- `options.duration`: 可选,音频时长
- `options.seed`: 可选,随机种子
- `options.callback_url`: 可选,回调 URL
#### 任务结果查询
- `getViduResult(taskId: string, timeout?: number): Promise<IViduResult>` - 获取 Vidu 视频处理任务的结果(使用全局配置中的apiKey)
- `taskId`: 任务 ID
- `timeout`: 可选,超时时间(毫秒),默认为 180000
- `getViduResult(apiKey: string, taskId: string, timeout?: number): Promise<IViduResult>` - 获取 Vidu 视频处理任务的结果(直接传入apiKey)
- `apiKey`: Vidu API 密钥
- `taskId`: 任务 ID
- `timeout`: 可选,超时时间(毫秒),默认为 180000
### Browser 模块 (browser.ts)
Browser 模块提供基于 Puppeteer 的浏览器自动化功能,支持 HTML 转视频和截图等功能。
#### 配置
```typescript
import { setGlobalConfig } from 'coze-plugin-tools';
// 设置 Browser API 密钥(Browserless Token)
setGlobalConfig('browser', {
apiKey: 'your_browserless_token'
});
```
#### API
- `htmlToVideo(options: ConvertOptions): Promise<string>` - 将 HTML 代码转换为视频
- `options.code`: HTML 代码字符串
- `options.duration`: 视频时长(秒)
- `options.width`: 可选,视频宽度
- `options.height`: 可选,视频高度
- `options.deviceScaleFactor`: 可选,设备缩放因子,默认为 1
- `options.sample_ratio`: 可选,采样比率,默认为 10
- 返回:视频文件的临时路径
- `htmlToScreenshot(options: ScreenshotOptions): Promise<string>` - 将 HTML 代码转换为截图
- `options.code`: HTML 代码字符串
- `options.width`: 可选,截图宽度
- `options.height`: 可选,截图高度
- `options.deviceScaleFactor`: 可选,设备缩放因子,默认为 1
- `options.delay`: 可选,延迟毫秒数,默认为 500
- 返回:图片文件的临时路径
#### 使用示例
```typescript
import { browser, setGlobalConfig } from 'coze-plugin-utils';
// 配置 Browser API Key
setGlobalConfig('browser', {
apiKey: 'your-browserless-token'
});
async function generateVideo() {
const htmlCode = `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial; background: linear-gradient(45deg, #ff6b6b, #4ecdc4); }
.container { text-align: center; padding: 50px; color: white; }
</style>
</head>
<body>
<div class="container">
<h1>Hello World!</h1>
<p>这是一个动态视频演示</p>
</div>
</body>
</html>
`;
// 生成视频
const videoPath = await browser.htmlToVideo({
code: htmlCode,
duration: 5, // 5秒视频
width: 1200,
height: 800
});
console.log('视频已生成:', videoPath);
}
async function takeScreenshot() {
const htmlCode = `
<div style="padding: 20px; background: #f0f0f0;">
<h1>截图测试</h1>
<p>这是一个截图示例</p>
</div>
`;
// 截图
const screenshotPath = await browser.htmlToScreenshot({
code: htmlCode,
width: 800,
height: 600,
delay: 1000 // 延迟1秒后截图
});
console.log('截图已保存:', screenshotPath);
}
```
## 许可证
本项目采用 MIT 许可证。查看 [LICENSE](./LICENSE) 文件了解更多详情。
这意味着您可以自由地使用、修改和分发本代码,无论是用于个人还是商业目的,但需要保留原始许可证和版权声明。
## 贡献指南
欢迎提交 Issues 和 Pull Requests 来帮助改进这个库。请确保遵循项目的代码风格和提交规范。
1. Fork 这个仓库
2. 创建您的特性分支 (`git checkout -b feature/amazing-feature`)
3. 提交您的更改 (`git commit -m 'Add some amazing feature'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 打开一个 Pull Request