@onedeepai/video_generator
Version:
阿里云文生视频MCP服务器
287 lines • 11.7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startServer = startServer;
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
const zod_1 = require("zod");
const axios_1 = __importDefault(require("axios"));
// 视频生成模型配置
const MODEL = 'wanx2.1-t2v-turbo';
// 设置API密钥和API端点
const API_KEY = process.env.DASHSCOPE_API_KEY || ''; // 从环境变量读取API密钥
const VIDEO_GENERATION_API = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis';
const TASK_STATUS_API = 'https://dashscope.aliyuncs.com/api/v1/tasks/';
// 检查API密钥是否存在
if (!API_KEY) {
console.warn('警告: DASHSCOPE_API_KEY环境变量未设置,视频生成功能将无法使用');
}
// 创建MCP服务器
const server = new mcp_js_1.McpServer({
name: "文生视频MCP服务器",
version: "1.0.0",
description: "基于阿里云的文本生成视频工具,使用环境变量 DASHSCOPE_API_KEY 设置API密钥"
});
// 添加文生视频工具
server.tool("gen_video", {
prompt: zod_1.z.string().min(1, "提示词不能为空"),
size: zod_1.z.string().regex(/^\d+\*\d+$/, "尺寸格式应为宽*高,如1280*720").optional().default("1280*720"),
duration: zod_1.z.number().min(1, "时长不能小于1秒").max(60, "时长不能超过60秒").optional().default(5)
}, async ({ prompt, size, duration }) => {
try {
// 验证API密钥
if (!API_KEY || API_KEY.trim() === '') {
return {
content: [{ type: "text", text: "错误: 缺少API密钥,请设置DASHSCOPE_API_KEY环境变量" }]
};
}
// 发送视频生成请求
const response = await axios_1.default.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;
const taskId = responseData.task_id || responseData.output?.task_id;
if (!taskId) {
throw new Error('无法从响应中获取任务ID');
}
// 每5秒检查一次任务状态,最多检查72次(最大6分钟)
const maxAttempts = 72;
const intervalMs = 5000;
let attempts = 0;
let result = null;
let errorCount = 0;
const startTime = Date.now();
while (attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, intervalMs));
attempts++;
try {
// 查询任务状态
const statusResponse = await axios_1.default.get(`${TASK_STATUS_API}${taskId}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
});
result = statusResponse.data;
const status = result?.task_status || result?.output?.task_status;
const waitedSeconds = Math.floor((Date.now() - startTime) / 1000);
if (status === 'SUCCEEDED') {
break;
}
else if (status === 'FAILED') {
throw new Error(`任务失败: ${result?.message || '未知错误'}`);
}
else if (status === 'PENDING' || status === 'RUNNING') {
// 任务还在运行中,继续等待
// 重置错误计数,因为我们成功获取了状态
errorCount = 0;
}
else if (!status) {
// 无法获取状态,但继续尝试
}
}
catch (error) {
errorCount++;
const waitedSeconds = Math.floor((Date.now() - startTime) / 1000);
// 连续多次查询失败,抛出异常
if (errorCount >= 3) {
throw new Error(`查询任务状态连续失败${errorCount}次: ${error.message || '未知错误'}`);
}
}
}
if (!result) {
throw new Error('无法获取任务结果');
}
// 检查是否达到最大尝试次数
if (attempts >= maxAttempts) {
const waitedSeconds = Math.floor((Date.now() - startTime) / 1000);
return {
content: [
{
type: "text",
text: `视频生成任务仍在处理中 • 已等待 ${waitedSeconds} 秒\n` +
`您可以稍后使用任务ID查询结果\n` +
`任务ID: ${taskId}`
}
]
};
}
// 获取视频URL
let videoUrl = result?.output?.video_url || result?.output?.result?.video_url;
if (!videoUrl) {
if (result?.status === 'SUCCEEDED' || result?.output?.task_status === 'SUCCEEDED') {
return {
content: [
{
type: "text",
text: `视频生成成功,但无法获取视频URL,请查看完整响应数据\n` +
`任务ID: ${taskId}\n` +
`完整响应数据:\n${JSON.stringify(result, null, 2)}`
}
]
};
}
throw new Error('无法获取视频URL');
}
// 获取扩展提示词(如果有)
const actualPrompt = result.output?.actual_prompt;
const waitedSeconds = Math.floor((Date.now() - startTime) / 1000);
// 构建响应内容
const content = [
{
type: "text",
text: `✅ 视频生成成功! (用时 ${waitedSeconds} 秒)\n` +
`任务ID: ${taskId}\n` +
`参数信息:\n` +
`- 提示词: ${prompt}\n` +
`- 尺寸: ${size}\n` +
`- 时长: ${duration}秒\n`
},
// 单独添加一个只包含视频URL的文本框,方便点击
{
type: "text",
text: `${videoUrl}`
}
];
// 如果有扩展提示词,添加到响应
if (actualPrompt) {
content.push({
type: "text",
text: `\n系统扩展生成的完整提示词:\n${actualPrompt}`
});
}
return { content };
}
catch (error) {
console.error('视频生成请求失败:');
let errorMessage = '';
if (axios_1.default.isAxiosError(error) && error.response) {
console.error('API错误响应:', error.response.data);
errorMessage = error.response.data.message || '未知错误';
// 展示完整错误数据
return {
content: [{
type: "text",
text: `生成视频失败: ${errorMessage}\n\n` +
`API错误详情:\n${JSON.stringify(error.response.data, null, 2)}`
}]
};
}
errorMessage = error.message || '未知错误';
return {
content: [{ type: "text", text: `生成视频失败: ${errorMessage}` }]
};
}
});
// 添加查询任务状态工具
server.tool("check_task", {
taskId: zod_1.z.string().min(1, "任务ID不能为空")
}, async ({ taskId }) => {
try {
// 验证API密钥
if (!API_KEY || API_KEY.trim() === '') {
return {
content: [{ type: "text", text: "错误: 缺少API密钥,请设置DASHSCOPE_API_KEY环境变量" }]
};
}
// 查询任务状态
const response = await axios_1.default.get(`${TASK_STATUS_API}${taskId}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
});
const result = response.data;
const status = result.task_status || result.output?.task_status;
// 获取视频URL
let videoUrl = result.output?.video_url || result.output?.result?.video_url;
// 获取扩展提示词(如果有)
const actualPrompt = result.output?.actual_prompt;
let content = [];
// 基于状态构建不同的响应
if (status === 'SUCCEEDED' && videoUrl) {
content.push({
type: "text",
text: `✅ 视频生成成功!\n` +
`任务ID: ${taskId}\n`
});
// 单独添加一个只包含视频URL的文本框,方便点击
content.push({
type: "text",
text: `${videoUrl}`
});
if (actualPrompt) {
content.push({ type: "text", text: `\n系统扩展生成的完整提示词:\n${actualPrompt}` });
}
}
else if (status === 'SUCCEEDED' && !videoUrl) {
content.push({
type: "text",
text: `任务已完成,但无法获取视频URL\n完整响应数据:\n${JSON.stringify(result, null, 2)}`
});
}
else if (status === 'FAILED') {
content.push({
type: "text",
text: `❌ 任务失败\n失败原因: ${result.message || '未知错误'}`
});
}
else if (status === 'PENDING' || status === 'RUNNING') {
content.push({
type: "text",
text: `⏳ 任务正在运行中\n状态: ${status}\n任务ID: ${taskId}`
});
}
else {
content.push({
type: "text",
text: `⚠️ 无法识别任务状态\n状态值: ${status || '无状态'}\n完整响应数据:\n${JSON.stringify(result, null, 2)}`
});
}
return { content };
}
catch (error) {
// 处理错误
const errorMessage = error.response?.data?.message || error.message || '未知错误';
if (error.response?.status === 404) {
return {
content: [{ type: "text", text: `错误: 找不到指定的任务ID (${taskId})` }]
};
}
return {
content: [{ type: "text", text: `查询任务状态失败: ${errorMessage}` }]
};
}
});
// 初始化stdin/stdout传输
const transport = new stdio_js_1.StdioServerTransport();
// 启动服务器的异步函数
async function startServer() {
console.log("文生视频MCP服务器正在启动...");
await server.connect(transport);
console.log("文生视频MCP服务器已启动,等待连接...");
}
// 如果直接运行此文件,则启动服务器
if (require.main === module) {
startServer().catch(error => {
console.error("服务器启动错误:", error);
process.exit(1);
});
}
//# sourceMappingURL=server.js.map