2023-06-14 13:06:11 -04:00
// Generates image using stable diffusion webui's api (automatic1111)
const fs = require ( 'fs' ) ;
const { StructuredTool } = require ( 'langchain/tools' ) ;
const { z } = require ( 'zod' ) ;
const path = require ( 'path' ) ;
const axios = require ( 'axios' ) ;
const sharp = require ( 'sharp' ) ;
class StableDiffusionAPI extends StructuredTool {
constructor ( fields ) {
super ( ) ;
this . name = 'stable-diffusion' ;
this . url = fields . SD _WEBUI _URL || this . getServerURL ( ) ;
this . description = ` You can generate images with 'stable-diffusion'. This tool is exclusively for visual content.
Guidelines :
- Visually describe the moods , details , structures , styles , and / or proportions of the image . Remember , the focus is on visual attributes .
- Craft your input by "showing" and not "telling" the imagery . Think in terms of what you ' d want to see in a photograph or a painting .
- Here ' s an example for generating a realistic portrait photo of a man :
"prompt" : "photo of a man in black clothes, half body, high detailed skin, coastline, overcast weather, wind, waves, 8k uhd, dslr, soft lighting, high quality, film grain, Fujifilm XT3"
"negative_prompt" : "semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, out of frame, low quality, ugly, mutation, deformed"
- Generate images only once per human query unless explicitly requested by the user ` ;
this . schema = z . object ( {
2023-07-14 09:36:49 -04:00
prompt : z
. string ( )
. describe (
'Detailed keywords to describe the subject, using at least 7 keywords to accurately describe the image, separated by comma' ,
) ,
negative _prompt : z
. string ( )
. describe (
'Keywords we want to exclude from the final image, using at least 7 keywords to accurately describe the image, separated by comma' ,
) ,
2023-06-14 13:06:11 -04:00
} ) ;
}
replaceNewLinesWithSpaces ( inputString ) {
return inputString . replace ( /\r\n|\r|\n/g , ' ' ) ;
}
getMarkdownImageUrl ( imageName ) {
2023-07-14 09:36:49 -04:00
const imageUrl = path
. join ( this . relativeImageUrl , imageName )
. replace ( /\\/g , '/' )
. replace ( 'public/' , '' ) ;
2023-06-14 13:06:11 -04:00
return `  ` ;
}
getServerURL ( ) {
const url = process . env . SD _WEBUI _URL || '' ;
if ( ! url ) {
throw new Error ( 'Missing SD_WEBUI_URL environment variable.' ) ;
}
return url ;
}
2023-06-14 13:38:03 -04:00
async _call ( data ) {
2023-06-14 13:06:11 -04:00
const url = this . url ;
2023-06-14 13:38:03 -04:00
const { prompt , negative _prompt } = data ;
2023-06-14 13:06:11 -04:00
const payload = {
prompt ,
negative _prompt ,
2023-07-14 09:36:49 -04:00
steps : 20 ,
2023-06-14 13:06:11 -04:00
} ;
const response = await axios . post ( ` ${ url } /sdapi/v1/txt2img ` , payload ) ;
const image = response . data . images [ 0 ] ;
const pngPayload = { image : ` data:image/png;base64, ${ image } ` } ;
const response2 = await axios . post ( ` ${ url } /sdapi/v1/png-info ` , pngPayload ) ;
const info = response2 . data . info ;
// Generate unique name
const imageName = ` ${ Date . now ( ) } .png ` ;
2023-07-14 09:36:49 -04:00
this . outputPath = path . resolve (
_ _dirname ,
'..' ,
'..' ,
'..' ,
'..' ,
'..' ,
'client' ,
'public' ,
'images' ,
) ;
2023-06-14 13:38:03 -04:00
const appRoot = path . resolve ( _ _dirname , '..' , '..' , '..' , '..' , '..' , 'client' ) ;
2023-06-14 13:06:11 -04:00
this . relativeImageUrl = path . relative ( appRoot , this . outputPath ) ;
// Check if directory exists, if not create it
if ( ! fs . existsSync ( this . outputPath ) ) {
fs . mkdirSync ( this . outputPath , { recursive : true } ) ;
}
try {
const buffer = Buffer . from ( image . split ( ',' , 1 ) [ 0 ] , 'base64' ) ;
await sharp ( buffer )
. withMetadata ( {
iptcpng : {
2023-07-14 09:36:49 -04:00
parameters : info ,
} ,
2023-06-14 13:06:11 -04:00
} )
. toFile ( this . outputPath + '/' + imageName ) ;
this . result = this . getMarkdownImageUrl ( imageName ) ;
} catch ( error ) {
console . error ( 'Error while saving the image:' , error ) ;
// this.result = theImageUrl;
}
return this . result ;
}
}
module . exports = StableDiffusionAPI ;