Spaces:
Paused
Paused
Julian Bilcke
commited on
Commit
·
5b3357c
1
Parent(s):
95bbb7f
working on adding turbo
Browse files
.env
CHANGED
|
@@ -31,6 +31,9 @@ VC_SDXL_SPACE_API_URL="https://jbilcke-hf-image-server.hf.space"
|
|
| 31 |
#--------------------- LCM INFERENCE SERVERS ---------------------
|
| 32 |
VC_LCM_SPACE_API_URL="https://jbilcke-hf-fast-image-server.hf.space"
|
| 33 |
|
|
|
|
|
|
|
|
|
|
| 34 |
#----------------- ZEROSCOPE INFERENCE SERVERS -------------------
|
| 35 |
VC_ZEROSCOPE_SPACE_API_URL_1="https://jbilcke-hf-zeroscope-server-1.hf.space"
|
| 36 |
VC_ZEROSCOPE_SPACE_API_URL_2="https://jbilcke-hf-zeroscope-server-2.hf.space"
|
|
|
|
| 31 |
#--------------------- LCM INFERENCE SERVERS ---------------------
|
| 32 |
VC_LCM_SPACE_API_URL="https://jbilcke-hf-fast-image-server.hf.space"
|
| 33 |
|
| 34 |
+
#--------------------- SDXL TURBO INFERENCE SERVERS ---------------------
|
| 35 |
+
VC_SDXL_TURBO_SPACE_API_URL="https://jbilcke-hf-faster-image-server.hf.space"
|
| 36 |
+
|
| 37 |
#----------------- ZEROSCOPE INFERENCE SERVERS -------------------
|
| 38 |
VC_ZEROSCOPE_SPACE_API_URL_1="https://jbilcke-hf-zeroscope-server-1.hf.space"
|
| 39 |
VC_ZEROSCOPE_SPACE_API_URL_2="https://jbilcke-hf-zeroscope-server-2.hf.space"
|
src/production/renderImage.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import { generateImageLCMAsBase64 } from "../providers/image-generation/generateImageLCMGradio.mts"
|
|
|
|
| 2 |
import { generateImageSDXLAsBase64 } from "../providers/image-generation/generateImageSDXLGradio.mts"
|
| 3 |
import { generateImageSDXL360AsBase64 } from "../providers/image-generation/generateImageSDXL360.mts"
|
| 4 |
import { RenderedScene, RenderRequest } from "../types.mts"
|
|
@@ -10,10 +11,19 @@ export async function renderImage(
|
|
| 10 |
|
| 11 |
const isSpherical = request.projection === 'spherical'
|
| 12 |
|
|
|
|
|
|
|
|
|
|
| 13 |
const generateImageAsBase64 = isSpherical
|
| 14 |
? generateImageSDXL360AsBase64
|
| 15 |
: request.turbo
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
: generateImageSDXLAsBase64
|
| 18 |
|
| 19 |
// console.log(`going to generate an image using ${request.projection || "default (cartesian)"} projection`)
|
|
|
|
| 1 |
import { generateImageLCMAsBase64 } from "../providers/image-generation/generateImageLCMGradio.mts"
|
| 2 |
+
import { generateImageSDXLTurboAsBase64 } from "../providers/image-generation/generateImageSDXLTurbo.mts"
|
| 3 |
import { generateImageSDXLAsBase64 } from "../providers/image-generation/generateImageSDXLGradio.mts"
|
| 4 |
import { generateImageSDXL360AsBase64 } from "../providers/image-generation/generateImageSDXL360.mts"
|
| 5 |
import { RenderedScene, RenderRequest } from "../types.mts"
|
|
|
|
| 11 |
|
| 12 |
const isSpherical = request.projection === 'spherical'
|
| 13 |
|
| 14 |
+
// we don't want to switch too much between model types in VideoChain,
|
| 15 |
+
// because for speed we need to pre-load the servers,
|
| 16 |
+
// but there is no point in pre-loading many servers for many models
|
| 17 |
const generateImageAsBase64 = isSpherical
|
| 18 |
? generateImageSDXL360AsBase64
|
| 19 |
: request.turbo
|
| 20 |
+
|
| 21 |
+
// turbo models are models that are slightly less beautiful
|
| 22 |
+
// but much, much faster to run
|
| 23 |
+
// for the moment we use SDXL + LCM, as it offers better scene coherence,
|
| 24 |
+
// but we might switch to SDXL Turbo in the future if its quality improves
|
| 25 |
+
? generateImageLCMAsBase64 // generateImageSDXLTurboAsBase64
|
| 26 |
+
|
| 27 |
: generateImageSDXLAsBase64
|
| 28 |
|
| 29 |
// console.log(`going to generate an image using ${request.projection || "default (cartesian)"} projection`)
|
src/production/renderVideo.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
import { RenderedScene, RenderRequest } from "../types.mts"
|
| 2 |
-
|
|
|
|
|
|
|
| 3 |
|
| 4 |
export async function renderVideo(
|
| 5 |
request: RenderRequest,
|
|
|
|
| 1 |
import { RenderedScene, RenderRequest } from "../types.mts"
|
| 2 |
+
|
| 3 |
+
// import { generateVideo } from "../providers/video-generation/generateVideoWithZeroscope.mts"
|
| 4 |
+
import { generateVideo } from "../providers/video-generation/generateVideoWithHotshotGradioAPI.mts"
|
| 5 |
|
| 6 |
export async function renderVideo(
|
| 7 |
request: RenderRequest,
|
src/providers/image-generation/generateImageSDXLTurbo.mts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import { client } from "@gradio/client"
|
| 3 |
+
|
| 4 |
+
import { generateSeed } from "../../utils/misc/generateSeed.mts"
|
| 5 |
+
import { getValidNumber } from "../../utils/validators/getValidNumber.mts"
|
| 6 |
+
import { convertToWebp } from "../../utils/image/convertToWebp.mts"
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
const instance = `${process.env.VC_SDXL_TURBO_SPACE_API_URL || ""}`
|
| 10 |
+
const secretToken = `${process.env.VC_MICROSERVICE_SECRET_TOKEN || ""}`
|
| 11 |
+
|
| 12 |
+
// console.log("DEBUG:", JSON.stringify({ instances, secretToken }, null, 2))
|
| 13 |
+
|
| 14 |
+
export async function generateImageSDXLTurboAsBase64(options: {
|
| 15 |
+
positivePrompt: string;
|
| 16 |
+
negativePrompt?: string;
|
| 17 |
+
seed?: number;
|
| 18 |
+
width?: number;
|
| 19 |
+
height?: number;
|
| 20 |
+
nbSteps?: number;
|
| 21 |
+
}): Promise<string> {
|
| 22 |
+
|
| 23 |
+
// console.log("querying " + instance)
|
| 24 |
+
const positivePrompt = options?.positivePrompt || ""
|
| 25 |
+
if (!positivePrompt) {
|
| 26 |
+
throw new Error("missing prompt")
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
// the negative prompt CAN be missing, since we use a trick
|
| 30 |
+
// where we make the interface mandatory in the TS doc,
|
| 31 |
+
// but browsers might send something partial
|
| 32 |
+
const negativePrompt = options?.negativePrompt || ""
|
| 33 |
+
|
| 34 |
+
// we treat 0 as meaning "random seed"
|
| 35 |
+
const seed = (options?.seed ? options.seed : 0) || generateSeed()
|
| 36 |
+
|
| 37 |
+
const maxRequestedResolution = 1024
|
| 38 |
+
const maxModelResolution = 512
|
| 39 |
+
|
| 40 |
+
const requestedWidth = getValidNumber(options?.width, 256, maxRequestedResolution, maxModelResolution)
|
| 41 |
+
const requestedHeight = getValidNumber(options?.height, 256, maxRequestedResolution, maxModelResolution)
|
| 42 |
+
|
| 43 |
+
// we try to preserve the original image ratio
|
| 44 |
+
const ratioH = requestedHeight / requestedWidth
|
| 45 |
+
const ratioW = requestedWidth / requestedHeight
|
| 46 |
+
|
| 47 |
+
// we always try to ccrank the resolution to the max
|
| 48 |
+
let width = ratioW < 1 ? Math.round(ratioW * maxModelResolution) : maxModelResolution
|
| 49 |
+
let height = ratioH < 1 ? Math.round(ratioH * maxModelResolution) : maxModelResolution
|
| 50 |
+
|
| 51 |
+
const positive = [
|
| 52 |
+
|
| 53 |
+
// oh well.. is it too late to move this to the bottom?
|
| 54 |
+
"beautiful",
|
| 55 |
+
|
| 56 |
+
// too opinionated, so let's remove it
|
| 57 |
+
// "intricate details",
|
| 58 |
+
|
| 59 |
+
positivePrompt,
|
| 60 |
+
|
| 61 |
+
"award winning",
|
| 62 |
+
"high resolution"
|
| 63 |
+
].filter(word => word)
|
| 64 |
+
.join(", ")
|
| 65 |
+
|
| 66 |
+
const negative = [
|
| 67 |
+
negativePrompt,
|
| 68 |
+
"watermark",
|
| 69 |
+
"copyright",
|
| 70 |
+
"blurry",
|
| 71 |
+
// "artificial",
|
| 72 |
+
// "cropped",
|
| 73 |
+
"low quality",
|
| 74 |
+
"ugly"
|
| 75 |
+
].filter(word => word)
|
| 76 |
+
.join(", ")
|
| 77 |
+
|
| 78 |
+
const api = await client(instance, {
|
| 79 |
+
hf_token: `${process.env.VC_HF_API_TOKEN}` as any
|
| 80 |
+
})
|
| 81 |
+
|
| 82 |
+
const rawResponse = (await api.predict("/run", [
|
| 83 |
+
positive, // string in 'Prompt' Textbox component
|
| 84 |
+
negative, // string in 'Negative prompt' Textbox component
|
| 85 |
+
seed, // number (numeric value between 0 and 2147483647) in 'Seed' Slider component
|
| 86 |
+
width, // number (numeric value between 256 and 1024) in 'Width' Slider component
|
| 87 |
+
height, // number (numeric value between 256 and 1024) in 'Height' Slider component
|
| 88 |
+
secretToken
|
| 89 |
+
])) as any
|
| 90 |
+
|
| 91 |
+
const result = rawResponse?.data?.[0] as string
|
| 92 |
+
if (!result?.length) {
|
| 93 |
+
throw new Error(`the returned image was empty`)
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
try {
|
| 97 |
+
const finalImage = await convertToWebp(result)
|
| 98 |
+
return finalImage
|
| 99 |
+
} catch (err) {
|
| 100 |
+
// console.log("err:", err)
|
| 101 |
+
throw new Error(err)
|
| 102 |
+
}
|
| 103 |
+
}
|