File size: 4,726 Bytes
f64828c
a99b4ac
 
07ae658
 
a99b4ac
f64828c
 
f7f7c46
 
 
 
 
 
 
 
 
 
07ae658
 
f7f7c46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
07ae658
f64828c
 
07ae658
f7f7c46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f64828c
 
07ae658
f7f7c46
66f11df
 
 
 
f7f7c46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
07ae658
f7f7c46
f64828c
f7f7c46
f64828c
f7f7c46
 
f132701
f7f7c46
a99b4ac
f7f7c46
0cf8825
 
f7f7c46
0cf8825
 
f7f7c46
 
0cf8825
a99b4ac
f7f7c46
 
a99b4ac
f7f7c46
 
66f11df
f7f7c46
a99b4ac
 
07ae658
 
 
66f11df
f7f7c46
66f11df
 
 
 
 
 
 
f7f7c46
 
66f11df
f7f7c46
07ae658
f7f7c46
07ae658
 
f7f7c46
 
 
 
07ae658
 
f7f7c46
07ae658
 
 
 
 
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import { v4 as uuid } from 'uuid'
import { upscaleVideo } from './upscaleVideo.mts'
import { keepVideo } from './keepVideo.mts'

import { getStats } from './getStats.mts'
import { enhanceVideo } from './enhanceVideo.mts'
import { callZeroscope } from './callZeroscope.mts'
import { downloadVideo } from './downloadVideo.mts'
import { getDatabase } from './getDatabase.mts'
import { callMusicgen } from './callMusicgen.mts'

let hasReachedStartingPoint = false

type RunMode = 'running' | 'paused' | 'dry_run'

const status = `${process.env.WEBTV_STATUS || 'dry_run'}` as RunMode

console.log(`Web TV server status: ${status}`)

const main = async () => {
  if (status === 'paused') {
    setTimeout(() => {
      main()
    }, 30000)
    return
  }

  console.log('Reading persistent file structure..')
  const stats = await getStats()
  console.log(`New format: We have ${stats.nbVideoFiles} video files`)

  console.log(`Legacy: We have ${stats.nbLegacyVideoFiles} video files and ${stats.nbLegacyAudioFiles} audio files`)

  console.log('Reading prompt database..')
  const db = await getDatabase('./database.json')

  const nbTotalShots = db.sequences.reduce((a, s) => a + s.shots.length, 0)
  console.log(`Prompt database version: ${db.version}`)
  console.log(`We got ${db.sequences.length} sequences for ${nbTotalShots} shots in total`)

  console.log('Generating videos sequences..')
  const instanceId = process.env.WEBTV_WORKER_INSTANCE_ID || '0'

  const startingPointExists = db.sequences.some(seq => seq.shots.some(shot => shot.shotId === db.startAtShotId))
  
  if (!startingPointExists) {
    console.log(`Starting point ${db.startAtShotId} not found, we will start at the beginning`)
    hasReachedStartingPoint = true
  } else if (db.startAtShotId) {
    console.log(`We are going to start at shot ${db.startAtShotId}`)
  } else {
    console.log('We are going to start at the beginning')
  }

  for (const sequence of db.sequences) {
    const containsStartingPoint = sequence.shots.some(shot => shot.shotId === db.startAtShotId)

    // we skip sequences that were already processed
    if (!hasReachedStartingPoint && !containsStartingPoint) {
      continue
    }

    console.log(`
-----------------------------------------------------------
Going to generate ${sequence.shots.length} for prompt:
${sequence.videoPrompt}
`)

    const sequenceId = uuid()

    const generatedShots: string[] = []

    // this is hardcoded everywhere for now, since videos longer than 3 sec require the Nvidia A100
    const videoDurationInSecs = 3

    let shotIndex = 0

    for (const shot of sequence.shots) {

      if (shot.shotId === db.startAtShotId) {
        hasReachedStartingPoint = true
      }

      if (!hasReachedStartingPoint) {
        shotIndex++
        continue
      }

      console.log(`- generating shot: ${shot.shotId}`)

      if (status === 'dry_run') {
        // console.log('DRY RUN')
        shotIndex++
        continue
      }

      try {
        const generatedVideoUrl = await callZeroscope(shot.videoPrompt)

        const shotFileName = `inst_${instanceId}_seq_${sequenceId}_shot_${shotIndex++}_${Date.now()}.mp4`

        console.log(`- downloading shot ${shotFileName} from ${generatedVideoUrl}`)
        await downloadVideo(generatedVideoUrl, shotFileName)

        console.log(`- downloaded shot ${shotFileName}`)

        console.log('- upscaling shot..')
      
        try {
          await upscaleVideo(shotFileName, shot.videoPrompt)
        } catch (err) {
          // upscaling is finicky, if it fails we try again
          console.log('- trying again to upscale shot..')
          await upscaleVideo(shotFileName, shot.videoPrompt)
        }

        console.log('- enhancing shot..')
        await enhanceVideo(shotFileName)

        console.log('- saving final shot..')
        await keepVideo(shotFileName, process.env.WEBTV_VIDEO_STORAGE_PATH_NEXT)

        generatedShots.push(shotFileName)

        console.log('- done!')
      } catch (err) {
        console.log(`- error: ${err}`)
      }

      const totalRunTime = videoDurationInSecs * generatedShots.length

      if (totalRunTime <= 0) {
        continue
      }

      // TODO: generate music from MusicGen, with the correct length
      // (or we could generate a slightly larger track and let ffmpeg cut it)
      console.log(`TODO: generate ${totalRunTime} seconds of music`)
      await callMusicgen(sequence.audioPrompt) // this does nothing for now

    }

    console.log('Finished generating sequence')
  }

  console.log('Finished the cycle')

  hasReachedStartingPoint = true // set this to true in all cases

  setTimeout(() => {
    main()
  }, 2000)
}

setTimeout(() => {
  main()
}, 3000)