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
167 lines • 6.27 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyToken = applyToken;
exports.getTempPath = getTempPath;
exports.uploadFile = uploadFile;
exports.createTempDir = createTempDir;
exports.downloadFile = downloadFile;
exports.downloadFiles = downloadFiles;
const node_path_1 = __importDefault(require("node:path"));
const node_fs_1 = __importDefault(require("node:fs"));
const api_1 = require("@coze/api");
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const mime_1 = __importDefault(require("mime"));
const uuid_1 = require("uuid");
const config_1 = require("./config");
let tokenBuffer = null;
async function applyToken() {
const now = Date.now();
if (tokenBuffer && tokenBuffer.expires_in * 1000 > now) {
return tokenBuffer;
}
const config = (0, config_1.getGlobalConfig)('jwt');
const baseUrl = (0, config_1.getGlobalConfig)('baseUrl');
if (!config) {
throw new Error('JWT 配置不存在');
}
const payload = {
baseURL: baseUrl,
appId: config.appId,
aud: new URL(baseUrl).host,
keyid: config.keyid,
privateKey: config.privateKey,
sessionName: config.userId,
};
// 如果缓存不存在或即将过期,获取新 token
tokenBuffer = await (0, api_1.getJWTToken)(payload);
return tokenBuffer;
}
function getTempPath(tmpPath) {
const match = tmpPath.match(/^(\/tmp\/.*?)\//);
if (!match) {
throw new Error('无法找到目录,这个文件不是临时文件');
}
const tmpDir = match[1];
return tmpDir;
}
async function uploadFile(tmpFile, autoClear = true) {
try {
const jwtToken = (await applyToken()).access_token;
const buffer = node_fs_1.default.readFileSync(tmpFile);
const parsedFile = node_path_1.default.parse(tmpFile);
const ext = parsedFile.ext || '';
// 构建 form-data
const form = new form_data_1.default();
form.append('file', buffer, {
filename: parsedFile.name + ext,
contentType: mime_1.default.getType(ext) || 'application/octet-stream',
});
const baseURL = (0, config_1.getGlobalConfig)('baseUrl');
// 提交请求
const response = await axios_1.default.post(`${baseURL}/v1/files/upload`, form, {
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${jwtToken}`,
},
});
const data = response.data;
const file_id = data.data.id;
const workflowApi = 'https://api.coze.cn/v1/workflow/run';
const headers = {
Authorization: `Bearer ${jwtToken}`,
'Content-Type': 'application/json',
};
const workflows = (0, config_1.getGlobalConfig)('workflows');
if (!workflows) {
throw new Error('workflows 配置不存在');
}
const body = {
workflow_id: workflows?.fileUploader,
parameters: {
file: JSON.stringify({ file_id }),
},
};
const ret = await fetch(workflowApi, {
method: 'POST',
headers,
body: JSON.stringify(body),
});
try {
const resData = await ret.json();
if (resData.code > 299) {
throw new Error(resData.msg);
}
const { url } = JSON.parse(resData.data);
return {
url,
};
}
catch (ex) {
throw ex;
}
}
finally {
// 上传完成后删掉整个目录
if (autoClear) {
const tmpDir = getTempPath(tmpFile);
console.log('removing tmp dir...', tmpDir);
node_fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
}
}
}
function createTempDir() {
const tempDir = node_path_1.default.join('/', 'tmp', (0, uuid_1.v4)());
node_fs_1.default.mkdirSync(tempDir, { recursive: true });
return tempDir;
}
async function downloadFile(url, filename, tempDir = createTempDir()) {
if (url.startsWith('/tmp')) {
// 这是本地文件,直接返回,这样的话才能允许ffmpeg的几个方法串行使用
return {
file: url,
createOutput: (filename) => {
const tmpDir = node_path_1.default.join(getTempPath(url), (0, uuid_1.v4)());
node_fs_1.default.mkdirSync(tmpDir, { recursive: true });
return node_path_1.default.join(tmpDir, filename);
},
};
}
const filePath = node_path_1.default.join(tempDir, filename);
try {
const response = await (0, axios_1.default)({ url, method: 'GET', responseType: 'stream' });
const writer = node_fs_1.default.createWriteStream(filePath);
response.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on('finish', resolve);
writer.on('error', (err) => reject(err));
});
const ret = {
file: filePath,
// 用 createOutput 创建的文件可以随着 output 上传自动删除,不会留在 tmp 目录下
// 确保不会重名
createOutput: (filename) => {
const tmpDir = node_path_1.default.join(getTempPath(filePath), (0, uuid_1.v4)());
node_fs_1.default.mkdirSync(tmpDir, { recursive: true });
return node_path_1.default.join(tmpDir, filename);
},
};
const contentType = response.headers['content-type'];
if (contentType)
ret.contentType = contentType;
return ret;
}
catch (ex) {
await node_fs_1.default.rmSync(tempDir, { recursive: true, force: true });
throw ex;
}
}
async function downloadFiles(files) {
const tempDir = createTempDir();
const ret = await Promise.all(files.map((file) => downloadFile(file.url, file.filename, tempDir)));
return ret;
}
//# sourceMappingURL=coze.js.map