File size: 3,601 Bytes
7448744 8bc9511 7448744 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
import Replicate from "replicate"
import { generateSeed } from "@/lib/generateSeed"
import { VideoOptions } from "@/types"
import { sleep } from "@/lib/sleep"
const replicateToken = `${process.env.AUTH_REPLICATE_API_TOKEN || ""}`
const replicateModel = `${process.env.VIDEO_HOTSHOT_XL_API_REPLICATE_MODEL || ""}`
const replicateModelVersion = `${process.env.VIDEO_HOTSHOT_XL_API_REPLICATE_MODEL_VERSION || ""}`
export async function generateVideoWithReplicateAPI({
positivePrompt = "",
negativePrompt = "",
size = "512x512",
huggingFaceLora,
replicateLora,
nbFrames = 8,
duration = 1000,
steps = 30,
}: VideoOptions): Promise<string> {
if (!replicateToken) {
throw new Error(`you need to configure your AUTH_REPLICATE_API_TOKEN in order to use the REPLICATE rendering engine`)
}
if (!replicateModel) {
throw new Error(`you need to configure your RENDERING_REPLICATE_API_MODEL in order to use the REPLICATE rendering engine`)
}
if (!replicateModelVersion) {
throw new Error(`you need to configure your REPLICATE_API_MODEL_VERSION in order to use the REPLICATE rendering engine`)
}
const replicate = new Replicate({ auth: replicateToken })
const [width, height] = size.split("x").map(x => Number(x))
// console.log("Calling replicate..")
const seed = generateSeed()
const prediction = await replicate.predictions.create({
version: replicateModelVersion,
input: {
prompt,
negative_prompt: negativePrompt,
// this is not a URL but a model name
hf_lora_url: replicateLora ? undefined : huggingFaceLora,
// this is a URL to the .tar (we can get it from the "trainings" page)
replicate_weights_url: huggingFaceLora ? undefined : replicateLora,
width,
height,
// those are used to create an upsampling or downsampling
// original_width: width,
// original_height: height,
// target_width: width,
// target_height: height,
video_length: 8, // nb frames
video_duration: 1000, // video duration in ms
seed
}
})
// console.log("prediction:", prediction)
// response times are random on Replicate, so this sleep doesn't really help us
// we should of course do it like on the AI Comic Factory (use the async loading/polling)
// but on the other hand if it takes 2 minutes to answer, it's not really useful either
await sleep(50000)
try {
const res = await fetch(`https://api.replicate.com/v1/predictions/${prediction.id}`, {
method: "GET",
headers: {
Authorization: `Token ${replicateToken}`,
},
cache: 'no-store',
})
if (res.status !== 200) {
throw new Error("failed")
}
const response = (await res.json()) as any
const error = `${response?.error || ""}`
if (error) {
throw new Error(error)
}
return `${response?.output || ""}`
} catch (err) {
// OK let's give replicate a second chance
await sleep(10000)
const res = await fetch(`https://api.replicate.com/v1/predictions/${prediction.id}`, {
method: "GET",
headers: {
Authorization: `Token ${replicateToken}`,
},
cache: 'no-store',
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
// next: { revalidate: 1 }
})
if (res.status !== 200) {
throw new Error('Failed to fetch data')
}
const response = (await res.json()) as any
const error = `${response?.error || ""}`
if (error) {
throw new Error(error)
}
return `${response?.output || ""}`
}
} |