Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
·
caa2240
1
Parent(s):
c64e57c
added an upscaler for images
Browse files- src/production/generateAudio.mts +1 -1
- src/production/generateVoice.mts +1 -1
- src/production/interpolateVideo.mts +1 -1
- src/production/renderImageSegmentation.mts +1 -2
- src/production/renderImageUpscaling.mts +26 -0
- src/production/renderPipeline.mts +14 -1
- src/production/upscaleVideo.mts +1 -1
- src/utils/segmentImage.mts +1 -1
- src/utils/upscaleImage.mts +42 -0
src/production/generateAudio.mts
CHANGED
|
@@ -37,7 +37,7 @@ export async function generateAudio(prompt: string, audioFileName: string) {
|
|
| 37 |
waitUntil: "networkidle2",
|
| 38 |
})
|
| 39 |
|
| 40 |
-
await new Promise(r => setTimeout(r,
|
| 41 |
|
| 42 |
const firstTextboxInput = await page.$('input[data-testid="textbox"]')
|
| 43 |
|
|
|
|
| 37 |
waitUntil: "networkidle2",
|
| 38 |
})
|
| 39 |
|
| 40 |
+
// await new Promise(r => setTimeout(r, 1000))
|
| 41 |
|
| 42 |
const firstTextboxInput = await page.$('input[data-testid="textbox"]')
|
| 43 |
|
src/production/generateVoice.mts
CHANGED
|
@@ -36,7 +36,7 @@ export async function generateVoice(prompt: string, voiceFileName: string) {
|
|
| 36 |
waitUntil: "networkidle2",
|
| 37 |
})
|
| 38 |
|
| 39 |
-
await new Promise(r => setTimeout(r,
|
| 40 |
|
| 41 |
const firstTextarea = await page.$('textarea[data-testid="textbox"]')
|
| 42 |
|
|
|
|
| 36 |
waitUntil: "networkidle2",
|
| 37 |
})
|
| 38 |
|
| 39 |
+
// await new Promise(r => setTimeout(r, 1000))
|
| 40 |
|
| 41 |
const firstTextarea = await page.$('textarea[data-testid="textbox"]')
|
| 42 |
|
src/production/interpolateVideo.mts
CHANGED
|
@@ -42,7 +42,7 @@ export async function interpolateVideo(fileName: string, steps: number, fps: num
|
|
| 42 |
const page = await browser.newPage()
|
| 43 |
await page.goto(instance, { waitUntil: 'networkidle2' })
|
| 44 |
|
| 45 |
-
await new Promise(r => setTimeout(r,
|
| 46 |
|
| 47 |
const fileField = await page.$('input[type=file]')
|
| 48 |
|
|
|
|
| 42 |
const page = await browser.newPage()
|
| 43 |
await page.goto(instance, { waitUntil: 'networkidle2' })
|
| 44 |
|
| 45 |
+
// await new Promise(r => setTimeout(r, 1000))
|
| 46 |
|
| 47 |
const fileField = await page.$('input[type=file]')
|
| 48 |
|
src/production/renderImageSegmentation.mts
CHANGED
|
@@ -17,7 +17,6 @@ export async function renderImageSegmentation(
|
|
| 17 |
|
| 18 |
if (actionnables.length > 0) {
|
| 19 |
console.log("we have some actionnables:", actionnables)
|
| 20 |
-
console.log("going to grab the first frame")
|
| 21 |
|
| 22 |
const tmpImageFilePath = path.join(tmpDir, `${uuidv4()}.png`)
|
| 23 |
|
|
@@ -26,7 +25,7 @@ export async function renderImageSegmentation(
|
|
| 26 |
console.log("wrote the image to ", tmpImageFilePath)
|
| 27 |
|
| 28 |
if (!tmpImageFilePath) {
|
| 29 |
-
console.error("failed to
|
| 30 |
response.error = "failed to segment the image"
|
| 31 |
response.status = "error"
|
| 32 |
} else {
|
|
|
|
| 17 |
|
| 18 |
if (actionnables.length > 0) {
|
| 19 |
console.log("we have some actionnables:", actionnables)
|
|
|
|
| 20 |
|
| 21 |
const tmpImageFilePath = path.join(tmpDir, `${uuidv4()}.png`)
|
| 22 |
|
|
|
|
| 25 |
console.log("wrote the image to ", tmpImageFilePath)
|
| 26 |
|
| 27 |
if (!tmpImageFilePath) {
|
| 28 |
+
console.error("failed to segment the image")
|
| 29 |
response.error = "failed to segment the image"
|
| 30 |
response.status = "error"
|
| 31 |
} else {
|
src/production/renderImageUpscaling.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { RenderedScene, RenderRequest } from "../types.mts"
|
| 2 |
+
import { upscaleImage } from "../utils/upscaleImage.mts"
|
| 3 |
+
|
| 4 |
+
export async function renderImageUpscaling(
|
| 5 |
+
request: RenderRequest,
|
| 6 |
+
response: RenderedScene,
|
| 7 |
+
): Promise<RenderedScene> {
|
| 8 |
+
|
| 9 |
+
try {
|
| 10 |
+
// note: this converts a base64 PNG to a base64 JPG (which is good, actually!)
|
| 11 |
+
response.assetUrl = await upscaleImage(response.assetUrl)
|
| 12 |
+
console.log(`upscaling worked on the first try!`)
|
| 13 |
+
} catch (err) {
|
| 14 |
+
console.error(`upscaling failed the first time.. let's try again..`)
|
| 15 |
+
try {
|
| 16 |
+
response.assetUrl = await upscaleImage(response.assetUrl)
|
| 17 |
+
console.log(`upscaling worked on the second try!`)
|
| 18 |
+
} catch (err) {
|
| 19 |
+
console.error(`upscaling failed on the second attempt.. let's keep the low-res image then :|`)
|
| 20 |
+
// no need to log a catastrophic failure here, since we still have the original (low-res image)
|
| 21 |
+
// to work with
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
return response
|
| 26 |
+
}
|
src/production/renderPipeline.mts
CHANGED
|
@@ -5,6 +5,8 @@ import { renderImage } from "./renderImage.mts"
|
|
| 5 |
import { renderVideo } from "./renderVideo.mts"
|
| 6 |
import { renderImageSegmentation } from "./renderImageSegmentation.mts"
|
| 7 |
import { renderVideoSegmentation } from "./renderVideoSegmentation.mts"
|
|
|
|
|
|
|
| 8 |
|
| 9 |
export async function renderPipeline(request: RenderRequest, response: RenderedScene) {
|
| 10 |
const isVideo = request?.nbFrames > 1
|
|
@@ -18,7 +20,18 @@ export async function renderPipeline(request: RenderRequest, response: RenderedS
|
|
| 18 |
console.log(`rendering an image..`)
|
| 19 |
}
|
| 20 |
await renderContent(request, response)
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
/*
|
| 24 |
this is the optimized pipeline
|
|
|
|
| 5 |
import { renderVideo } from "./renderVideo.mts"
|
| 6 |
import { renderImageSegmentation } from "./renderImageSegmentation.mts"
|
| 7 |
import { renderVideoSegmentation } from "./renderVideoSegmentation.mts"
|
| 8 |
+
import { upscaleImage } from "../utils/upscaleImage.mts"
|
| 9 |
+
import { renderImageUpscaling } from "./renderImageUpscaling.mts"
|
| 10 |
|
| 11 |
export async function renderPipeline(request: RenderRequest, response: RenderedScene) {
|
| 12 |
const isVideo = request?.nbFrames > 1
|
|
|
|
| 20 |
console.log(`rendering an image..`)
|
| 21 |
}
|
| 22 |
await renderContent(request, response)
|
| 23 |
+
|
| 24 |
+
// we upscale images with esrgan
|
| 25 |
+
// and for videos, well.. let's just skip this part,
|
| 26 |
+
// but later we could use Zeroscope V2 XL maybe?
|
| 27 |
+
const optionalUpscalingStep = isVideo
|
| 28 |
+
? Promise.resolve()
|
| 29 |
+
: renderImageUpscaling(request, response)
|
| 30 |
+
|
| 31 |
+
await Promise.all([
|
| 32 |
+
renderSegmentation(request, response),
|
| 33 |
+
optionalUpscalingStep
|
| 34 |
+
])
|
| 35 |
|
| 36 |
/*
|
| 37 |
this is the optimized pipeline
|
src/production/upscaleVideo.mts
CHANGED
|
@@ -35,7 +35,7 @@ export async function upscaleVideo(fileName: string, prompt: string) {
|
|
| 35 |
const inputFilePath = path.join(pendingFilesDirFilePath, fileName)
|
| 36 |
// console.log(`local file to upscale: ${inputFilePath}`)
|
| 37 |
|
| 38 |
-
await new Promise(r => setTimeout(r,
|
| 39 |
|
| 40 |
const fileField = await page.$('input[type=file]')
|
| 41 |
|
|
|
|
| 35 |
const inputFilePath = path.join(pendingFilesDirFilePath, fileName)
|
| 36 |
// console.log(`local file to upscale: ${inputFilePath}`)
|
| 37 |
|
| 38 |
+
// await new Promise(r => setTimeout(r, 1000))
|
| 39 |
|
| 40 |
const fileField = await page.$('input[type=file]')
|
| 41 |
|
src/utils/segmentImage.mts
CHANGED
|
@@ -40,7 +40,7 @@ export async function segmentImage(
|
|
| 40 |
const page = await browser.newPage()
|
| 41 |
await page.goto(instance, { waitUntil: 'networkidle2' })
|
| 42 |
|
| 43 |
-
await new Promise(r => setTimeout(r,
|
| 44 |
|
| 45 |
const fileField = await page.$('input[type="file"]')
|
| 46 |
|
|
|
|
| 40 |
const page = await browser.newPage()
|
| 41 |
await page.goto(instance, { waitUntil: 'networkidle2' })
|
| 42 |
|
| 43 |
+
// await new Promise(r => setTimeout(r, 1000))
|
| 44 |
|
| 45 |
const fileField = await page.$('input[type="file"]')
|
| 46 |
|
src/utils/upscaleImage.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import { client } from "@gradio/client"
|
| 3 |
+
|
| 4 |
+
import { getValidNumber } from "./getValidNumber.mts"
|
| 5 |
+
|
| 6 |
+
// we don't use replicas yet, because it ain't easy to get their hostname
|
| 7 |
+
const instances: string[] = [
|
| 8 |
+
`${process.env.VC_UPSCALING_SPACE_API_URL_1 || ""}`,
|
| 9 |
+
// `${process.env.VC_UPSCALING_SPACE_API_URL_2 || ""}`,
|
| 10 |
+
].filter(instance => instance?.length > 0)
|
| 11 |
+
|
| 12 |
+
// this doesn't work because of this error.. I think the version of Gradio is too old/young?
|
| 13 |
+
// ReferenceError: addEventListener is not defined
|
| 14 |
+
// at file:///Users/jbilcke/Projects/VideoChain-API/node_modules/@gradio/client/dist/index.js:551:15
|
| 15 |
+
// at processTicksAndRejections (node:internal/process/task_queues:95:5)
|
| 16 |
+
export async function upscaleImage(src: string, factor?: number) {
|
| 17 |
+
|
| 18 |
+
// bu default we do a 4X scale
|
| 19 |
+
const scaleFactor = getValidNumber(factor, 2, 10, 4)
|
| 20 |
+
|
| 21 |
+
const instance = instances.shift()
|
| 22 |
+
instances.push(instance)
|
| 23 |
+
|
| 24 |
+
const api = await client(instance, {
|
| 25 |
+
hf_token: `${process.env.VC_HF_API_TOKEN}` as any
|
| 26 |
+
})
|
| 27 |
+
|
| 28 |
+
const result = await api.predict("/upscale", [
|
| 29 |
+
src, // blob in 'Source Image' Image component
|
| 30 |
+
"realesr-general-x4v3", // string (Option from: ['RealESRGAN_x4plus', 'RealESRNet_x4plus', 'RealESRGAN_x4plus_anime_6B', 'RealESRGAN_x2plus', 'realesr-general-x4v3']) in 'Real-ESRGAN inference model to be used' Dropdown component
|
| 31 |
+
0.5, // number (numeric value between 0 and 1) in 'Denoise Strength (Used only with the realesr-general-x4v3 model)' Slider component
|
| 32 |
+
false, // boolean in 'Face Enhancement using GFPGAN (Doesn't work for anime images)' Checkbox component
|
| 33 |
+
scaleFactor, // number (numeric value between 1 and 10) in 'Image Upscaling Factor' Slider component
|
| 34 |
+
]);
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
const rawResponse = result as any
|
| 38 |
+
|
| 39 |
+
// console.log("rawResponse:", rawResponse)
|
| 40 |
+
|
| 41 |
+
return rawResponse?.data?.[0] as string
|
| 42 |
+
}
|