pixnova.js

Face swap supports images and videos, and baby generator.

#image#video#tools#ai
42
6 Des 2025, 06:26
RawEdit
javascript0 lines
/***
  @ Base: https://pixnova.ai/
  @ Author: Shannz
  @ Note: face swap supports image to image and image to video, and ai baby generator
***/

import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid';

const CONFIG = {
    URLS: {
        API: 'https://api.pixnova.ai/api',
        TOOLS: 'https://api.pixnova.ai/aitools'
    },
    HEADERS: {
        'User-Agent': 'ScRaPe/9.9 (KaliLinux; Nusantara Os; My/Shannz)',
        'Accept': 'application/json, text/plain, */*',
        'origin': 'https://pixnova.ai',
        'theme-version': '83EmcUoQTUv50LhNx0VrdcK8rcGexcP35FcZDcpgWsAXEyO4xqL5shCY6sFIWB2Q'
    },
    PUBLIC_KEY: `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwlO+boC6cwRo3UfXVBadaYwcX
0zKS2fuVNY2qZ0dgwb1NJ+/Q9FeAosL4ONiosD71on3PVYqRUlL5045mvH2K9i8b
AFVMEip7E6RMK6tKAAif7xzZrXnP1GZ5Rijtqdgwh+YmzTo39cuBCsZqK9oEoeQ3
r/myG9S+9cR5huTuFQIDAQAB
-----END PUBLIC KEY-----`
};

const getOriginFrom = () => crypto.createHash('md5').update('pixnova.ai').digest('hex').substring(8, 24);
const generateRandomString = (len) => Array.from({length: len}, () => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.charAt(Math.floor(Math.random() * 62))).join('');
const sleep = (ms) => new Promise(r => setTimeout(r, ms));

const rsaEncrypt = (data) => crypto.publicEncrypt({ key: CONFIG.PUBLIC_KEY, padding: crypto.constants.RSA_PKCS1_PADDING }, Buffer.from(data)).toString('base64');

const aesCbcEncrypt = (text, keyStr) => {
    const key = Buffer.from(keyStr, 'utf-8');
    const cipher = crypto.createCipheriv('aes-128-cbc', key, key);
    let encrypted = cipher.update(`pixnova:${text}`, 'utf8', 'base64');
    return encrypted + cipher.final('base64');
};

const aesGcmEncrypt = (jsonData, fp1Key) => {
    const keyHash = crypto.createHash('sha256').update(fp1Key).digest();
    const iv = crypto.randomBytes(12);
    const cipher = crypto.createCipheriv('aes-256-gcm', keyHash, iv);
    let encrypted = cipher.update(JSON.stringify(jsonData), 'utf8');
    const final = cipher.final();
    return Buffer.concat([iv, encrypted, final, cipher.getAuthTag()]).toString('base64');
};

export const Pixnova = {
    request: async (endpoint, data = {}, apiType = 'API', isUpload = false) => {
        const baseUrl = apiType === 'TOOLS' ? CONFIG.URLS.TOOLS : CONFIG.URLS.API;
        const aesSecret = generateRandomString(16);
        const fp = uuidv4().replace(/-/g, '');
        const fp1 = aesCbcEncrypt(fp, aesSecret);
        
        const headers = {
            ...CONFIG.HEADERS,
            'x-code': Date.now().toString(),
            'fp': fp, 'fp1': fp1, 'x-guide': rsaEncrypt(aesSecret),
            'referer': apiType === 'TOOLS' ? 'https://pixnova.ai/id/ai-baby-generator/' : 'https://pixnova.ai/'
        };

        let payload = data;
        let method = 'POST';

        if (isUpload) {
            Object.assign(headers, data.getHeaders());
        } else {
            headers['Content-Type'] = 'application/json';
            if (!payload.origin_from) {
                payload.origin_from = getOriginFrom(); 
            }
            if (endpoint.includes('generate_video_face')) {
                payload = { request_type: 2, data: aesGcmEncrypt(payload, fp1) };
            }
        }

        try {
            const response = await axios({ method, url: `${baseUrl}${endpoint}`, headers, data: payload });
            if (response.data?.code === 200) return response.data;
            throw new Error(`API Error [${endpoint}]: ${response.data?.message || JSON.stringify(response.data)}`);
        } catch (error) {
            throw new Error(`Http Error: ${error.message}`);
        }
    },

    uploadImage: async (filePath, type = 'API') => {
        if (!fs.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
        const formData = new FormData();
        formData.append('file', fs.createReadStream(filePath));
        
        let endpoint = '/upload_img';
        
        if (type === 'TOOLS') {
            endpoint = '/upload-img';
            formData.append('fn_name', 'demo-ai-baby');
            formData.append('origin_from', getOriginFrom());
        } else {
            formData.append('request_from', '2');
            formData.append('origin_from', getOriginFrom());
        }

        const res = await Pixnova.request(endpoint, formData, type, true);
        return type === 'TOOLS' ? res.data.path : res.data; 
    },

    uploadVideo: async (filePath) => {
        if (!fs.existsSync(filePath)) throw new Error(`Video not found: ${filePath}`);
        const fileBuffer = fs.readFileSync(filePath);
        const ext = path.extname(filePath).replace('.', '').toLowerCase();
        const fileName = `${crypto.createHash('md5').update(fileBuffer).digest('hex')}_0_10.${ext}`;
        const presign = await Pixnova.request('/upload_file', {
            file_name: fileName, type: 'video', request_from: 2, origin_from: getOriginFrom()
        }, 'API');

        await axios.put(presign.data.url, fileBuffer, {
            headers: { 'Content-Type': `video/${ext}`, 'x-oss-storage-class': 'Standard' },
            maxBodyLength: Infinity, maxContentLength: Infinity
        });

        return presign.data.url.split('?')[0].replace(/^https?:\/\/[^\/]+\//, '');
    },

    poll: async (taskId, endpoint, apiType = 'API', extraPayload = {}) => {
        let attempt = 0;
        process.stdout.write(`   ā³ Processing... `);
        while (attempt < 200) { 
            const payload = { task_id: taskId, request_from: 2, ...extraPayload };
            const res = await Pixnova.request(endpoint, payload, apiType);
            const s = res.data;

            if (s.status === 2) {
                console.log('āœ… Done!');
                const imgPath = s.result_image || s.result_video;
                if (!imgPath) return null;
                
                if (imgPath.startsWith('http')) return imgPath;
                if (apiType === 'TOOLS') return `https://oss-global.pixnova.ai/${imgPath}`;
                return `https://media.visro.ai/${imgPath}`;
            }
            if (s.status === 3 || s.status === -1) throw new Error('Task Failed/Cancelled.');
            
            process.stdout.write('.');
            attempt++;
            await sleep(3000);
        }
        throw new Error('Timeout.');
    },

    swapImage: async (targetImgPath, faceImgPath) => {
        console.log(`\nšŸ–¼ļø  SWAP IMAGE: ${path.basename(targetImgPath)} + ${path.basename(faceImgPath)}`);
        try {
            const targetUrl = await Pixnova.uploadImage(targetImgPath, 'API');
            const faceUrl = await Pixnova.uploadImage(faceImgPath, 'API');
            
            const res = await Pixnova.request('/generate_face', {
                source_image: targetUrl, face_image: faceUrl, request_from: 2
            }, 'API');
            
            return await Pixnova.poll(res.data.task_id, '/check_status', 'API', { is_batch: true });
        } catch (e) {
            console.error(`   āŒ Error: ${e.message}`);
            return null;
        }
    },

    swapVideo: async (targetVideoPath, faceImgPath) => {
        console.log(`\nšŸŽ„ SWAP VIDEO: ${path.basename(targetVideoPath)} + ${path.basename(faceImgPath)}`);
        try {
            console.log('   Uploading Video...');
            const videoUrl = await Pixnova.uploadVideo(targetVideoPath);
            const faceUrl = await Pixnova.uploadImage(faceImgPath, 'API');
            
            console.log('   Queuing Task...');
            const res = await Pixnova.request('/pn/v1/generate_video_face', {
                source_video: videoUrl, face_image: faceUrl, start: 0, end: 10, type: 1, request_from: 2, enhance: 0
            }, 'API');
            
            return await Pixnova.poll(res.data.task_id, '/pn/v1/check_status', 'API', { is_batch: true });
        } catch (e) {
            console.error(`   āŒ Error: ${e.message}`);
            return null;
        }
    },

    generateBaby: async (fatherPath, motherPath, gender = 'boy') => {
        console.log(`\nšŸ‘¶ BABY GENERATOR (${gender.toUpperCase()})`);
        try {
            const fatherUrl = await Pixnova.uploadImage(fatherPath, 'TOOLS');
            const motherUrl = await Pixnova.uploadImage(motherPath, 'TOOLS');
            
            const payload = {
                fn_name: "demo-ai-baby", call_type: 3,
                input: { gender, father_image: fatherUrl, mother_image: motherUrl, request_from: 2 },
                request_from: 2, origin_from: "111977c0d5def647"
            };

            const res = await Pixnova.request('/of/create', payload, 'TOOLS');
            return await Pixnova.poll(res.data.task_id, '/of/check-status', 'TOOLS', { 
                fn_name: "demo-ai-baby", call_type: 3 
            });
        } catch (e) {
            console.error(`   āŒ Error: ${e.message}`);
            return null;
        }
    }
};

/**
(async () => {
  // 1. Swap Image
  const res1 = await Pixnova.swapImage('./target.jpg', './bahan.jpg');
  console.log('Result Swap:', res1);

  // 2. Baby Generator
  const res2 = await Pixnova.generateBaby('./ayah.jpg', './ibu.jpg', 'girl');
  console.log('Result Baby:', res2);

  // 3. Swap Video
  const res3 = await Pixnova.swapVideo('./target.mp4', './bahan.jpg');
  console.log('Result Video:', res3);
})();
**/