jbilcke-hf's picture
jbilcke-hf HF staff
work in progress, starting to take shape
f62b8d3
raw
history blame
3.32 kB
"use server"
// TODO add a system to mark failed instances as "unavailable" for a couple of minutes
// console.log("process.env:", process.env)
import { generateSeed } from "@/lib/generateSeed";
import { getValidNumber } from "@/lib/getValidNumber";
// note: to reduce costs I use the small A10s (not the large)
// anyway, we will soon not need to use this cloud anymore
// since we will be able to leverage the Inference API
const instance = `${process.env.FAST_IMAGE_SERVER_API_GRADIO_URL || ""}`
const secretToken = `${process.env.FAST_IMAGE_SERVER_API_SECRET_TOKEN || ""}`
// console.log("DEBUG:", JSON.stringify({ instances, secretToken }, null, 2))
export async function generateImage(options: {
positivePrompt: string;
negativePrompt?: string;
seed?: number;
width?: number;
height?: number;
nbSteps?: number;
}): Promise<string> {
// console.log("querying " + instance)
const positivePrompt = options?.positivePrompt || ""
if (!positivePrompt) {
throw new Error("missing prompt")
}
// the negative prompt CAN be missing, since we use a trick
// where we make the interface mandatory in the TS doc,
// but browsers might send something partial
const negativePrompt = options?.negativePrompt || ""
// we treat 0 as meaning "random seed"
const seed = (options?.seed ? options.seed : 0) || generateSeed()
const width = getValidNumber(options?.width, 256, 1024, 512)
const height = getValidNumber(options?.height, 256, 1024, 512)
const nbSteps = getValidNumber(options?.nbSteps, 1, 8, 4)
// console.log("SEED:", seed)
const positive = [
// oh well.. is it too late to move this to the bottom?
"beautiful",
// too opinionated, so let's remove it
// "intricate details",
positivePrompt,
"award winning",
"high resolution"
].filter(word => word)
.join(", ")
const negative = [
negativePrompt,
"watermark",
"copyright",
"blurry",
// "artificial",
// "cropped",
"low quality",
"ugly"
].filter(word => word)
.join(", ")
const res = await fetch(instance + (instance.endsWith("/") ? "" : "/") + "api/predict", {
method: "POST",
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
fn_index: 0, // <- important!
data: [
positive, // string in 'Prompt' Textbox component
negative, // string in 'Negative prompt' Textbox component
seed, // number (numeric value between 0 and 2147483647) in 'Seed' Slider component
width, // number (numeric value between 256 and 1024) in 'Width' Slider component
height, // number (numeric value between 256 and 1024) in 'Height' Slider component
0.0, // can be disabled for LCM SDXL
nbSteps, // number (numeric value between 2 and 8) in 'Number of inference steps for base' Slider component
secretToken
]
}),
cache: "no-store",
})
const { data } = await res.json()
if (res.status !== 200 || !Array.isArray(data)) {
// This will activate the closest `error.js` Error Boundary
throw new Error(`Failed to fetch data (status: ${res.status})`)
}
if (!data[0]) {
throw new Error(`the returned image was empty`)
}
return data[0] as string
}