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 || ""}`
  }
}