llama vision | inpaint mask | whisk images | Search

The code imports modules for interacting with the file system, working with file paths, and making HTTP requests. It defines a function doImage2Image that takes an image and a prompt, processes the image, makes a POST request to generate an image, and returns the seed and generated image.

Run example

npm run import -- "image 2 image"

image 2 image

const fs = require('fs')
const path = require('path')
const {request} = require('gaxios')

const OUTPUT_PATH = path.join(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE, 'stable-diffusion-webui/outputs')

async function doImage2Image(image, prompt) {
  let width = 1024
  if(prompt.includes('View360')) {
    width = 2048
  }

  let base64_image
  if(typeof image == 'string') {
    if(image.startsWith('data:image/'))
      image = image.replace(/^data:image\/.*?;base64,/gi, '')
  
    if(image.includes('://')) {
      let result = await request({
        url: image,
        method: 'GET',
      })
      base64_image = Buffer.from(await result.data.arrayBuffer()).toString('base64')
    } else if (!fs.existsSync(image)) {
      base64_image = Buffer.from(image, 'base64').toString('base64')
    } else {
      base64_image = fs.readFileSync(image).toString('base64')
    }  
  } else {
    base64_image = image.toString('base64')
  }

  try {
    let result = await request({
      url: 'http://127.0.0.1:7860/sdapi/v1/img2img',
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      data: JSON.stringify({
        prompt: prompt,
        negative_prompt: 'bad hands, bad feet, bad faces, bad eyes, bad anatomy, extra limbs, missing limbs, tattoo, statue, picture frame, anime, cartoon, signature, abstract',
        save_images: true,
        "width": width,
        "height": 1024,
        "steps": 30,
        tiling: false,
        init_images: [base64_image],
      })
    })
    
    let seed = JSON.parse(result.data.info).seed
    let buff = Buffer.from(result.data.images[0], 'base64');
    let now = new Date()
    let folderName = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0')
    let stablePath = path.join(OUTPUT_PATH, 'img2img-images', folderName)
    let imagePath
    if(fs.existsSync(stablePath)) {
      let images = fs.readdirSync(stablePath)
      for(let i = 0; i < images.length; i++) {
        if(images[i].match('-' + seed + '-')) {
          imagePath = path.join('img2img-images', folderName, images[i])
          break
        }
      }
    }
    return {seed, image: buff, imagePath, prompt}

  } catch (e) {
    console.error(e)
  }
}

module.exports = {
  doImage2Image,
  OUTPUT_PATH
}

What the code could have been:

const gaxios = require('gaxios');
const fs = require('fs');
const path = require('path');

const OUTPUT_PATH = process.env.HOME
 ? path.join(process.env.HOME,'stable-diffusion-webui/outputs')
  : process.env.HOMEPATH
 ? path.join(process.env.HOMEPATH,'stable-diffusion-webui/outputs')
  : process.env.USERPROFILE
 ? path.join(process.env.USERPROFILE,'stable-diffusion-webui/outputs')
  : './outputs';

async function doImage2Image(image, prompt) {
  try {
    const width = getPreferredWidth(prompt);
    const base64Image = await getImageData(image);
    const result = await sendImageData(base64Image, prompt);
    const { seed, imagePath } = await processResult(result, width);
    return { seed, image: result.data.images[0], imagePath, prompt };
  } catch (error) {
    console.error(error);
  }
}

/**
 * Returns the preferred width based on the prompt.
 * @param {string} prompt
 * @returns {number}
 */
function getPreferredWidth(prompt) {
  return prompt.includes('View360')? 2048 : 1024;
}

/**
 * Retrieves the image data from the provided image.
 * @param {string} image
 * @returns {Promise<string>}
 */
async function getImageData(image) {
  if (typeof image ==='string' && image.startsWith('data:image/')) {
    image = image.replace(/^data:image\/.*?;base64,/gi, '');
  }

  if (image.includes('://')) {
    const response = await gaxios.request({
      url: image,
      method: 'GET',
    });
    return Buffer.from(await response.data.arrayBuffer()).toString('base64');
  } else if (!fs.existsSync(image)) {
    return image;
  } else {
    return fs.readFileSync(image).toString('base64');
  }
}

/**
 * Sends the image data to the SD API.
 * @param {string} base64Image
 * @param {string} prompt
 * @returns {Promise<Object>}
 */
async function sendImageData(base64Image, prompt) {
  const response = await gaxios.request({
    url: 'http://127.0.0.1:7860/sdapi/v1/img2img',
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    data: JSON.stringify({
      prompt,
      negative_prompt: 'bad hands, bad feet, bad faces, bad eyes, bad anatomy, extra limbs, missing limbs, tattoo, statue, picture frame, anime, cartoon, signature, abstract',
      save_images: true,
      width: getPreferredWidth(prompt),
      height: 1024,
      steps: 30,
      tiling: false,
      init_images: [base64Image],
    }),
  });
  return response.data;
}

/**
 * Processes the result from the SD API.
 * @param {Object} result
 * @param {number} width
 * @returns {Promise<{ seed: string, imagePath: string }>}
 */
async function processResult(result, width) {
  const seed = JSON.parse(result.info).seed;
  const buff = Buffer.from(result.images[0], 'base64');
  const now = new Date();
  const folderName = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
  const stablePath = path.join(OUTPUT_PATH, 'img2img-images', folderName);
  let imagePath;
  if (fs.existsSync(stablePath)) {
    const images = fs.readdirSync(stablePath);
    for (let i = 0; i < images.length; i++) {
      if (images[i].match(`-${seed}-`)) {
        imagePath = path.join('img2img-images', folderName, images[i]);
        break;
      }
    }
  }
  return { seed, imagePath };
}

module.exports = {
  doImage2Image,
  OUTPUT_PATH,
};

Breakdown of the code

Importing Modules

The code starts by importing three modules:

Defining Constants

Defining the doImage2Image Function

This is an asynchronous function that takes two arguments:

Image Processing

The function processes the input image as follows:

Making the Image Generation Request

The function makes a POST request to http://127.0.0.1:7860/sdapi/v1/img2img with the following data:

The response from the server is parsed to extract the seed and the generated image.