mirror of
https://github.com/Wan-Video/Wan2.1.git
synced 2025-06-07 07:44:53 +00:00
232 lines
7.7 KiB
JavaScript
232 lines
7.7 KiB
JavaScript
const express = require('express');
|
|
const path = require('path');
|
|
const multer = require('multer');
|
|
const { exec } = require('child_process');
|
|
const fs = require('fs');
|
|
const { v4: uuidv4 } = require('uuid');
|
|
const bodyParser = require('body-parser');
|
|
const session = require('express-session');
|
|
const flash = require('connect-flash');
|
|
|
|
// Initialize app
|
|
const app = express();
|
|
const port = process.env.PORT || 3000;
|
|
|
|
// Configure middleware
|
|
app.use(bodyParser.urlencoded({ extended: false }));
|
|
app.use(bodyParser.json());
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
app.use(session({
|
|
secret: 'wan-video-secret',
|
|
resave: false,
|
|
saveUninitialized: true
|
|
}));
|
|
app.use(flash());
|
|
|
|
// Set up EJS as view engine
|
|
app.set('view engine', 'ejs');
|
|
app.set('views', path.join(__dirname, 'views'));
|
|
|
|
// Configure multer for file uploads
|
|
const storage = multer.diskStorage({
|
|
destination: function (req, file, cb) {
|
|
cb(null, path.join(__dirname, 'public/uploads/'));
|
|
},
|
|
filename: function (req, file, cb) {
|
|
const uniqueFilename = `${uuidv4()}${path.extname(file.originalname)}`;
|
|
cb(null, uniqueFilename);
|
|
}
|
|
});
|
|
|
|
const upload = multer({
|
|
storage: storage,
|
|
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
|
|
fileFilter: function (req, file, cb) {
|
|
// Accept images only
|
|
if (!file.originalname.match(/\.(jpg|jpeg|png|JPG|JPEG|PNG)$/)) {
|
|
return cb(new Error('Only image files are allowed!'), false);
|
|
}
|
|
cb(null, true);
|
|
}
|
|
});
|
|
|
|
// Routes
|
|
app.get('/', (req, res) => {
|
|
res.render('index', {
|
|
title: 'Wan2.1 - Video Generation',
|
|
message: req.flash('message'),
|
|
error: req.flash('error')
|
|
});
|
|
});
|
|
|
|
// Text to Video route
|
|
app.get('/text-to-video', (req, res) => {
|
|
res.render('text-to-video', {
|
|
title: 'Text to Video - Wan2.1',
|
|
message: req.flash('message'),
|
|
error: req.flash('error')
|
|
});
|
|
});
|
|
|
|
app.post('/text-to-video', (req, res) => {
|
|
const { prompt, resolution, steps, guideScale, shiftScale, seed, negativePrompt } = req.body;
|
|
|
|
// Generate a unique ID for this generation
|
|
const generationId = uuidv4();
|
|
const outputPath = path.join(__dirname, 'public/generated', `${generationId}.mp4`);
|
|
|
|
// Prepare the command to run the Python script
|
|
const pythonScript = path.join(__dirname, '../gradio/t2v_14B_singleGPU.py');
|
|
const command = `python ${pythonScript} --prompt "${prompt}" --resolution "${resolution}" --steps ${steps} --guide_scale ${guideScale} --shift_scale ${shiftScale} --seed ${seed || -1} --n_prompt "${negativePrompt || ''}" --output "${outputPath}"`;
|
|
|
|
// Execute the command
|
|
exec(command, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`Execution error: ${error}`);
|
|
req.flash('error', 'An error occurred during video generation.');
|
|
return res.redirect('/text-to-video');
|
|
}
|
|
|
|
console.log(`Generation output: ${stdout}`);
|
|
|
|
if (fs.existsSync(outputPath)) {
|
|
req.flash('message', 'Video generated successfully!');
|
|
return res.render('result', {
|
|
title: 'Generation Result - Wan2.1',
|
|
videoPath: `/generated/${generationId}.mp4`,
|
|
prompt: prompt
|
|
});
|
|
} else {
|
|
req.flash('error', 'Failed to generate video.');
|
|
return res.redirect('/text-to-video');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Image to Video route
|
|
app.get('/image-to-video', (req, res) => {
|
|
res.render('image-to-video', {
|
|
title: 'Image to Video - Wan2.1',
|
|
message: req.flash('message'),
|
|
error: req.flash('error')
|
|
});
|
|
});
|
|
|
|
app.post('/image-to-video', upload.single('image'), (req, res) => {
|
|
if (!req.file) {
|
|
req.flash('error', 'Please upload an image.');
|
|
return res.redirect('/image-to-video');
|
|
}
|
|
|
|
const { prompt, resolution, steps, guideScale, shiftScale, seed, negativePrompt } = req.body;
|
|
const imagePath = path.join('/uploads', req.file.filename);
|
|
const absoluteImagePath = path.join(__dirname, 'public', imagePath);
|
|
|
|
// Generate a unique ID for this generation
|
|
const generationId = uuidv4();
|
|
const outputPath = path.join(__dirname, 'public/generated', `${generationId}.mp4`);
|
|
|
|
// Prepare the command to run the Python script
|
|
const pythonScript = path.join(__dirname, '../gradio/i2v_14B_singleGPU.py');
|
|
const command = `python ${pythonScript} --image "${absoluteImagePath}" --prompt "${prompt}" --resolution "${resolution}" --steps ${steps} --guide_scale ${guideScale} --shift_scale ${shiftScale} --seed ${seed || -1} --n_prompt "${negativePrompt || ''}" --output "${outputPath}"`;
|
|
|
|
// Execute the command
|
|
exec(command, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`Execution error: ${error}`);
|
|
req.flash('error', 'An error occurred during video generation.');
|
|
return res.redirect('/image-to-video');
|
|
}
|
|
|
|
console.log(`Generation output: ${stdout}`);
|
|
|
|
if (fs.existsSync(outputPath)) {
|
|
req.flash('message', 'Video generated successfully!');
|
|
return res.render('result', {
|
|
title: 'Generation Result - Wan2.1',
|
|
videoPath: `/generated/${generationId}.mp4`,
|
|
prompt: prompt,
|
|
imagePath: imagePath
|
|
});
|
|
} else {
|
|
req.flash('error', 'Failed to generate video.');
|
|
return res.redirect('/image-to-video');
|
|
}
|
|
});
|
|
});
|
|
|
|
// First-Last Frame to Video route
|
|
app.get('/fl-to-video', (req, res) => {
|
|
res.render('fl-to-video', {
|
|
title: 'First-Last Frame to Video - Wan2.1',
|
|
message: req.flash('message'),
|
|
error: req.flash('error')
|
|
});
|
|
});
|
|
|
|
app.post('/fl-to-video', upload.fields([
|
|
{ name: 'firstFrame', maxCount: 1 },
|
|
{ name: 'lastFrame', maxCount: 1 }
|
|
]), (req, res) => {
|
|
if (!req.files || !req.files['firstFrame'] || !req.files['lastFrame']) {
|
|
req.flash('error', 'Please upload both first and last frame images.');
|
|
return res.redirect('/fl-to-video');
|
|
}
|
|
|
|
const firstFramePath = path.join('/uploads', req.files['firstFrame'][0].filename);
|
|
const lastFramePath = path.join('/uploads', req.files['lastFrame'][0].filename);
|
|
const absoluteFirstFramePath = path.join(__dirname, 'public', firstFramePath);
|
|
const absoluteLastFramePath = path.join(__dirname, 'public', lastFramePath);
|
|
|
|
const { resolution, steps, guideScale, seed } = req.body;
|
|
|
|
// Generate a unique ID for this generation
|
|
const generationId = uuidv4();
|
|
const outputPath = path.join(__dirname, 'public/generated', `${generationId}.mp4`);
|
|
|
|
// Prepare the command to run the Python script
|
|
const pythonScript = path.join(__dirname, '../gradio/fl2v_14B_singleGPU.py');
|
|
const command = `python ${pythonScript} --first "${absoluteFirstFramePath}" --last "${absoluteLastFramePath}" --resolution "${resolution}" --steps ${steps} --guide_scale ${guideScale} --seed ${seed || -1} --output "${outputPath}"`;
|
|
|
|
// Execute the command
|
|
exec(command, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`Execution error: ${error}`);
|
|
req.flash('error', 'An error occurred during video generation.');
|
|
return res.redirect('/fl-to-video');
|
|
}
|
|
|
|
console.log(`Generation output: ${stdout}`);
|
|
|
|
if (fs.existsSync(outputPath)) {
|
|
req.flash('message', 'Video generated successfully!');
|
|
return res.render('result', {
|
|
title: 'Generation Result - Wan2.1',
|
|
videoPath: `/generated/${generationId}.mp4`,
|
|
firstFramePath: firstFramePath,
|
|
lastFramePath: lastFramePath
|
|
});
|
|
} else {
|
|
req.flash('error', 'Failed to generate video.');
|
|
return res.redirect('/fl-to-video');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Create directories if they don't exist
|
|
const dirs = [
|
|
path.join(__dirname, 'public/uploads'),
|
|
path.join(__dirname, 'public/generated')
|
|
];
|
|
|
|
dirs.forEach(dir => {
|
|
if (!fs.existsSync(dir)){
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
}
|
|
});
|
|
|
|
// Start server
|
|
app.listen(port, () => {
|
|
console.log(`Server running at http://localhost:${port}`);
|
|
});
|