UNPKG

@onedeepai/video_generator

Version:

阿里云文生视频MCP服务器

318 lines (268 loc) 9.8 kB
import axios from 'axios'; import * as readline from 'readline'; import * as fs from 'fs'; import * as path from 'path'; // 视频生成模型配置 - 醒目位置 const MODEL = 'wanx2.1-t2v-turbo'; // 配置信息 interface Config { apiKey: string; videoGenerationApi: string; taskStatusApi: string; } // 从环境变量和配置文件读取配置 let config: Config = { apiKey: process.env.DASHSCOPE_API_KEY || '', // 从环境变量读取API密钥 videoGenerationApi: 'https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis', taskStatusApi: 'https://dashscope.aliyuncs.com/api/v1/tasks/' }; // 检查是否存在配置文件并读取 const configPath = path.join(__dirname, 'config.json'); if (fs.existsSync(configPath)) { try { const configData = JSON.parse(fs.readFileSync(configPath, 'utf8')); config = { ...config, ...configData }; console.log('已加载配置文件'); } catch (error) { console.warn('配置文件读取失败,使用默认配置', error); } } // API常量 const API_KEY = config.apiKey; const VIDEO_GENERATION_API = config.videoGenerationApi; const TASK_STATUS_API = config.taskStatusApi; // API响应类型定义 interface TaskResponse { task_id?: string; output?: { task_id?: string; task_status?: string; video_url?: string; result?: { video_url?: string; }; actual_prompt?: string; }; task_status?: string; status?: string; message?: string; } // 创建命令行接口 const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // 视频参数接口 interface VideoParams { prompt: string; size?: string; duration?: number; } // 创建视频生成任务 async function generateVideo(params: VideoParams): Promise<string> { console.log('正在发送视频生成请求...'); try { const { prompt, size = '1280*720', duration = 5 } = params; // 验证提示词不能为空 if (!prompt || prompt.trim() === '') { throw new Error('提示词不能为空'); } // 创建视频生成任务 const response = await axios.post( VIDEO_GENERATION_API, { model: MODEL, input: { prompt, }, parameters: { size, duration, prompt_extend: true, // 启用提示词扩展 }, }, { headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', 'X-DashScope-Async': 'enable', }, } ); const responseData = response.data as TaskResponse; // 检查是否有扩展提示词 if (responseData.output?.actual_prompt) { console.log('系统扩展生成的提示词:'); console.log(responseData.output.actual_prompt); } console.log('视频生成请求已发送,获取任务ID:'); console.log(JSON.stringify(responseData, null, 2)); // 检查响应格式并提取任务ID if (responseData.task_id) { return responseData.task_id; } else if (responseData.output?.task_id) { return responseData.output.task_id; } else { throw new Error('无法从响应中获取任务ID'); } } catch (error: any) { console.error('视频生成请求失败:'); if (axios.isAxiosError(error) && error.response) { console.error('API错误响应:', error.response.data); throw new Error(`视频生成失败: ${error.response.data.message || '未知错误'}`); } throw new Error(`视频生成失败: ${error.message || '未知错误'}`); } } // 查询视频生成任务状态 async function checkVideoStatus(taskId: string): Promise<any> { // 不输出查询日志,保持界面简洁 try { // 查询任务状态 const response = await axios.get( `${TASK_STATUS_API}${taskId}`, { headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', }, } ); return response.data; } catch (error: any) { // 简化错误输出 throw new Error(`查询失败: ${error.message || '未知错误'}`); } } // 轮询任务状态直到完成 async function pollTaskUntilComplete(taskId: string, intervalMs: number = 5000, maxAttempts: number = 30): Promise<TaskResponse> { console.log(`开始轮询任务状态...`); let attempts = 0; let errorCount = 0; // 连续错误计数 const startTime = Date.now(); const maxWaitTimeMs = 6 * 60 * 1000; // 最多等待6分钟 // 轮询任务状态 while (attempts < maxAttempts) { attempts++; // 检查总体超时 if (Date.now() - startTime > maxWaitTimeMs) { throw new Error(`任务等待超时(${maxWaitTimeMs/60000}分钟),请稍后手动查询结果`); } try { const statusResult = await checkVideoStatus(taskId) as TaskResponse; // 重置错误计数 errorCount = 0; // 根据API响应结构获取状态 const status = statusResult.task_status || (statusResult.output && statusResult.output.task_status) || statusResult.status; // 计算已等待时间(秒) const waitedSeconds = Math.floor((Date.now() - startTime) / 1000); // 简化的状态输出 console.log(`等待中,已等待${waitedSeconds}秒...状态: ${status}`); // 如果任务完成或失败,返回结果 if (status === 'SUCCEEDED') { console.log('任务已成功完成!'); return statusResult; } else if (status === 'FAILED') { console.log('任务失败'); throw new Error(`任务失败: ${statusResult.message || '未知错误'}`); } else if (!status) { console.log('无法获取任务状态'); } // 等待指定时间后再次查询 await new Promise(resolve => setTimeout(resolve, intervalMs)); } catch (error: any) { errorCount++; const waitedSeconds = Math.floor((Date.now() - startTime) / 1000); console.log(`等待中,已等待${waitedSeconds}秒...状态: ERROR (错误 ${errorCount}/3)`); // 连续多次查询失败,抛出异常 if (errorCount >= 3) { throw new Error(`连续查询失败${errorCount}次,请检查网络或任务ID`); } await new Promise(resolve => setTimeout(resolve, intervalMs)); } } throw new Error(`达到最大轮询次数(${maxAttempts}),任务尚未完成`); } // 用户交互函数 function promptUser(question: string): Promise<string> { return new Promise((resolve) => { rl.question(question, (answer) => { resolve(answer); }); }); } // 主函数 async function main() { try { console.log('=== 阿里云视频生成工具 ==='); console.log(`当前使用的API密钥: ${API_KEY.substring(0, 5)}***${API_KEY.substring(API_KEY.length - 4)}`); // 获取用户输入并验证 let prompt = ''; while (!prompt || prompt.trim() === '') { prompt = await promptUser('请输入视频生成提示词: '); if (!prompt || prompt.trim() === '') { console.log('提示词不能为空,请重新输入'); } } // 验证视频尺寸 let size = await promptUser('请输入视频尺寸 (默认 1280*720): ') || '1280*720'; // 检查尺寸格式 if (!/^\d+\*\d+$/.test(size)) { console.log(`尺寸格式不正确,将使用默认大小 1280*720`); size = '1280*720'; } // 验证视频时长 const durationStr = await promptUser('请输入视频时长(秒) (默认 5秒): ') || '5'; let duration = parseInt(durationStr); // 检查时长是否有效 if (isNaN(duration) || duration <= 0 || duration > 60) { console.log(`输入的时长无效,使用默认时长 5秒`); duration = 5; } console.log(`\n生成视频参数:\n- 提示词: ${prompt}\n- 尺寸: ${size}\n- 时长: ${duration}秒`); // 创建视频生成任务 const taskId = await generateVideo({ prompt, size, duration }); if (!taskId) { throw new Error('未能获取有效的任务ID,请检查API响应'); } console.log(`任务已创建,ID: ${taskId}`); // 默认执行轮询任务状态 try { // 设置轮询间隔为5秒,最多30次尝试 const result = await pollTaskUntilComplete(taskId, 5000, 30); // 显示生成的视频URL if (result.output?.video_url) { console.log(`\n视频生成成功!\n视频URL: ${result.output.video_url}`); } else if (result.output?.result?.video_url) { console.log(`\n视频生成成功!\n视频URL: ${result.output.result.video_url}`); } else { console.log('\n视频生成成功,但未获取到视频URL'); console.log('完整响应数据:'); console.log(JSON.stringify(result, null, 2)); } // 显示扩展提示词(如果有) if (result.output?.actual_prompt) { console.log('\n系统扩展生成的完整提示词:'); console.log(result.output.actual_prompt); } } catch (error: any) { console.error(`\n轮询任务状态失败: ${error.message}`); console.error('请记下任务ID,稍后使用API手动查询结果'); console.log(`任务ID: ${taskId}`); } } catch (error: any) { console.error(`\n错误: ${error.message}`); if (error.response?.data) { console.error('API错误详情:'); console.error(JSON.stringify(error.response.data, null, 2)); } } finally { // 关闭readline接口 rl.close(); console.log('\n程序执行完毕'); } } // 运行主函数 main();