ferrariedhgs commited on
Commit
84c5aa2
Β·
verified Β·
1 Parent(s): 926d5a4

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -139
app.py CHANGED
@@ -99,141 +99,153 @@ def warmup_models():
99
 
100
  # ── Frame 1: text ─────────────────────────────────────────────────────────────
101
 
102
- @spaces.GPU(duration=80)
103
- def run_text_gen(narrator: str):
104
- """GPU frame 1: GGUF text model β†’ room JSON + narrations.
105
- Returns a dict stored in gen_state; no PIL images yet.
106
  """
107
- # Normalise: strip whitespace and fall back to the first listed voice
 
 
 
 
 
108
  narrator = (narrator or "").strip()
109
  if narrator not in misc_f.VOICES:
110
  narrator = next(iter(misc_f.VOICES))
111
- log.warning("run_text_gen: invalid narrator, using %r", narrator)
112
- log.info("run_text_gen: narrator = %r", narrator)
113
- log.info("run_text_gen: loading GGUF text model…")
 
 
 
114
  llm = misc_f.load_text_model()
115
 
116
- room = misc_f.generate_game(llm)
117
  chain = generate_fixed_chain()
118
  narrations = misc_f.pregenerate_text(llm, room, chain)
119
 
120
  misc_f.unload_text_model(llm)
121
- log.info("run_text_gen: done.")
122
- return {"room": room, "chain": chain, "narrator": narrator,
123
- "narrations": narrations}
124
 
 
 
 
125
 
126
- def on_text_done(gen_state: dict):
127
- """CPU step: text is ready β€” do NOT show main screen yet.
128
- Keep the generating overlay up; images and audio still need to finish.
129
- We stash the story in the narrative box (hidden) so on_all_done can
130
- populate it in one shot when everything is ready.
131
- """
132
- story = gen_state["room"].get("room_story", "")
133
- log.info("on_text_done: text ready, waiting for images + audio before showing screen.")
134
- # Return story so it's available to on_all_done via narrative state,
135
- # but leave both screens unchanged.
136
- return story # β†’ narrative (hidden on main_screen, harmless update)
137
 
 
 
 
 
 
138
 
139
- # ── Frame 2: images + TTS (merged to avoid ZeroGPU rate-limit on 3rd lease) ───
140
- #
141
- # Running FLUX then VoxCPM sequentially in one @spaces.GPU frame means we only
142
- # consume 2 GPU leases total (text + this one) instead of 3, which keeps us
143
- # under the ZeroGPU 429 rate-limit. Each model is fully unloaded before the
144
- # next one is loaded so peak VRAM stays the same as before.
145
-
146
- @spaces.GPU(duration=360)
147
- def run_images_and_tts(gen_state: dict):
148
- """GPU frame 2: FLUX β†’ 9 images, then VoxCPM β†’ audio clips.
149
- Returns a combined dict with both 'img' and 'audio' keys.
150
- """
151
- room = gen_state["room"]
152
- chain = gen_state["chain"]
153
- narrations = gen_state["narrations"]
154
- narrator = gen_state["narrator"]
155
 
156
- # ── FLUX ──────────────────────────────────────────────────────────────────
157
- log.info("run_images_and_tts: loading FLUX image model…")
158
- image_model = misc_f.load_image_model()
 
 
159
 
160
- room_img = misc_f.generate_image(image_model, room["room_prompt"], "room")
161
- loc0 = misc_f.generate_image(image_model, room["containers"][0]["container_prompt"], "location")
162
- loc1 = misc_f.generate_image(image_model, room["containers"][1]["container_prompt"], "location")
163
- loc2 = misc_f.generate_image(image_model, room["containers"][2]["container_prompt"], "location")
164
- loc3 = misc_f.generate_image(image_model, room["containers"][3]["container_prompt"], "location")
165
- door_img = misc_f.generate_image(image_model, room["door_prompt"], "location")
166
- key0 = misc_f.generate_image(image_model, room["keys"][0]["key_prompt"], "item")
167
- key1 = misc_f.generate_image(image_model, room["keys"][1]["key_prompt"], "item")
168
- door_key = misc_f.generate_image(image_model, room["door_key_prompt"], "item")
 
 
 
 
 
 
 
 
169
 
170
  misc_f.unload_image_model(image_model)
171
- log.info("run_images_and_tts: FLUX done, unloaded.")
172
 
173
- img_result = {
174
- "room_img": room_img,
175
- "loc_imgs": [loc0, loc1, loc2, loc3],
176
- "door_img": door_img,
177
- "key_imgs": [key0, key1, door_key],
178
- }
 
 
 
 
 
 
 
 
179
 
180
- # ── VoxCPM ────────────────────────────────────────────────────────────────
181
- log.info("run_images_and_tts: loading VoxCPM TTS model…")
182
- tts_model = misc_f.load_tts_model()
183
- audio_paths = misc_f.pregenerate_audio(tts_model, room, chain, narrations, narrator)
184
  misc_f.unload_tts_model(tts_model)
185
- log.info("run_images_and_tts: VoxCPM done, unloaded.")
186
 
187
- return {"img": img_result, "audio": audio_paths}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
 
190
- def on_all_done(gen_state: dict, combined: dict):
191
- """CPU step: everything is ready β€” flip to main screen and populate all widgets.
192
- 'combined' is the merged dict returned by run_images_and_tts.
193
- """
194
- room = gen_state["room"]
195
- chain = gen_state["chain"]
196
- narrator = gen_state["narrator"]
197
- narrations = gen_state["narrations"]
198
- img_result = combined["img"]
199
- audio_paths = combined["audio"]
200
- loc_imgs = img_result["loc_imgs"]
201
- key_imgs = img_result["key_imgs"]
202
 
203
  state = {
204
- "room": room,
205
- "chain": chain,
206
- "loc_imgs": loc_imgs,
207
- "key_imgs": key_imgs,
208
- "found_keys": set(),
209
  "tried_combos": set(),
210
- "door_opened": False,
211
- "narrator": narrator,
212
- "narrations": narrations,
213
- "audio_paths": audio_paths,
214
  }
215
 
216
- story = room.get("room_story", "")
217
- room_story_path = audio_paths.get("room_story")
218
- log.info("on_all_done: everything ready β€” switching to main screen.")
219
  return (
220
- gr.update(visible=False), # gen_screen
221
- gr.update(visible=True), # main_screen
222
- story, # narrative
223
- img_result["room_img"], # main_img
224
- loc_imgs, # gallery_top
225
- img_result["door_img"], # mid_img
226
- [], # stack_gallery (empty inventory at start)
227
- None, # small_img
228
- state, # room_state
229
- -1, # sel_container
230
- "", # sel_key
231
- gr.update(visible=True), # door_btn
232
- "Container: \u2014\nKey: \u2014", # selection_display
233
- gr.update(value=room_story_path, visible=bool(room_story_path)), # narration_audio
 
 
 
234
  )
235
-
236
-
237
  # ─── Gallery selection handlers ───────────────────────────────────────────���───
238
 
239
  def on_container_select_full(evt: gr.SelectData, state, key_id):
@@ -592,41 +604,39 @@ with gr.Blocks(title="1000 Rooms") as demo:
592
  # on_all_done hides the overlay via JS once everything is ready.
593
 
594
  gen_btn.click(
595
- fn=run_text_gen,
596
- inputs=[narrator_state],
597
- outputs=[gen_state],
598
- js="""() => {
599
- const ov = document.getElementById('nn-overlay');
600
- if (ov) ov.classList.remove('hidden');
601
- startNN();
602
- }""",
603
- ).then(
604
- fn=on_text_done,
605
- inputs=[gen_state],
606
- outputs=[narrative], # stash story; overlay stays up
607
- ).then(
608
- fn=run_images_and_tts,
609
- inputs=[gen_state],
610
- outputs=[combined_state],
611
- ).then(
612
- fn=on_all_done,
613
- inputs=[gen_state, combined_state],
614
- outputs=[
615
- gen_screen, main_screen,
616
- narrative,
617
- main_img, gallery_top, mid_img,
618
- stack_gallery, small_img,
619
- room_state,
620
- sel_container, sel_key,
621
- door_btn, selection_display,
622
- narration_audio,
623
- ],
624
- js="""() => {
625
- const ov = document.getElementById('nn-overlay');
626
- if (ov) ov.classList.add('hidden');
627
- stopNN();
628
- }""",
629
- )
630
 
631
 
632
  # ── Gallery selection wiring ──────────────────────────────────────────────
 
99
 
100
  # ── Frame 1: text ─────────────────────────────────────────────────────────────
101
 
102
+ @spaces.GPU(duration=360) # text + images + TTS combined
103
+ def run_generation_pipeline(narrator: str):
 
 
104
  """
105
+ Single GPU frame:
106
+ GGUF -> room generation
107
+ FLUX -> images
108
+ VoxCPM -> audio
109
+ """
110
+
111
  narrator = (narrator or "").strip()
112
  if narrator not in misc_f.VOICES:
113
  narrator = next(iter(misc_f.VOICES))
114
+
115
+ # ------------------------------------------------------------------
116
+ # TEXT
117
+ # ------------------------------------------------------------------
118
+
119
+ log.info("Loading text model...")
120
  llm = misc_f.load_text_model()
121
 
122
+ room = misc_f.generate_game(llm)
123
  chain = generate_fixed_chain()
124
  narrations = misc_f.pregenerate_text(llm, room, chain)
125
 
126
  misc_f.unload_text_model(llm)
 
 
 
127
 
128
+ # ------------------------------------------------------------------
129
+ # IMAGES
130
+ # ------------------------------------------------------------------
131
 
132
+ log.info("Loading image model...")
133
+ image_model = misc_f.load_image_model()
 
 
 
 
 
 
 
 
 
134
 
135
+ room_img = misc_f.generate_image(
136
+ image_model,
137
+ room["room_prompt"],
138
+ "room"
139
+ )
140
 
141
+ loc_imgs = [
142
+ misc_f.generate_image(
143
+ image_model,
144
+ room["containers"][i]["container_prompt"],
145
+ "location"
146
+ )
147
+ for i in range(4)
148
+ ]
 
 
 
 
 
 
 
 
149
 
150
+ door_img = misc_f.generate_image(
151
+ image_model,
152
+ room["door_prompt"],
153
+ "location"
154
+ )
155
 
156
+ key0 = misc_f.generate_image(
157
+ image_model,
158
+ room["keys"][0]["key_prompt"],
159
+ "item"
160
+ )
161
+
162
+ key1 = misc_f.generate_image(
163
+ image_model,
164
+ room["keys"][1]["key_prompt"],
165
+ "item"
166
+ )
167
+
168
+ door_key = misc_f.generate_image(
169
+ image_model,
170
+ room["door_key_prompt"],
171
+ "item"
172
+ )
173
 
174
  misc_f.unload_image_model(image_model)
 
175
 
176
+ # ------------------------------------------------------------------
177
+ # TTS
178
+ # ------------------------------------------------------------------
179
+
180
+ log.info("Loading TTS model...")
181
+ tts_model = misc_f.load_tts_model()
182
+
183
+ audio_paths = misc_f.pregenerate_audio(
184
+ tts_model,
185
+ room,
186
+ chain,
187
+ narrations,
188
+ narrator,
189
+ )
190
 
 
 
 
 
191
  misc_f.unload_tts_model(tts_model)
 
192
 
193
+ # ------------------------------------------------------------------
194
+ # RETURN EVERYTHING
195
+ # ------------------------------------------------------------------
196
+
197
+ return {
198
+ "room": room,
199
+ "chain": chain,
200
+ "narrator": narrator,
201
+ "narrations": narrations,
202
+ "images": {
203
+ "room_img": room_img,
204
+ "loc_imgs": loc_imgs,
205
+ "door_img": door_img,
206
+ "key_imgs": [key0, key1, door_key],
207
+ },
208
+ "audio_paths": audio_paths,
209
+ }
210
 
211
 
212
+ def on_generation_done(result):
213
+ room = result["room"]
 
 
 
 
 
 
 
 
 
 
214
 
215
  state = {
216
+ "room": room,
217
+ "chain": result["chain"],
218
+ "loc_imgs": result["images"]["loc_imgs"],
219
+ "key_imgs": result["images"]["key_imgs"],
220
+ "found_keys": set(),
221
  "tried_combos": set(),
222
+ "door_opened": False,
223
+ "narrator": result["narrator"],
224
+ "narrations": result["narrations"],
225
+ "audio_paths": result["audio_paths"],
226
  }
227
 
228
+ story = room.get("room_story", "")
229
+
 
230
  return (
231
+ gr.update(visible=False),
232
+ gr.update(visible=True),
233
+ story,
234
+ result["images"]["room_img"],
235
+ result["images"]["loc_imgs"],
236
+ result["images"]["door_img"],
237
+ [],
238
+ None,
239
+ state,
240
+ -1,
241
+ "",
242
+ gr.update(visible=True),
243
+ "Container: β€”\nKey: β€”",
244
+ gr.update(
245
+ value=result["audio_paths"].get("room_story"),
246
+ visible=bool(result["audio_paths"].get("room_story"))
247
+ ),
248
  )
 
 
249
  # ─── Gallery selection handlers ───────────────────────────────────────────���───
250
 
251
  def on_container_select_full(evt: gr.SelectData, state, key_id):
 
604
  # on_all_done hides the overlay via JS once everything is ready.
605
 
606
  gen_btn.click(
607
+ fn=run_generation_pipeline,
608
+ inputs=[narrator_state],
609
+ outputs=[combined_state],
610
+ js="""() => {
611
+ const ov = document.getElementById('nn-overlay');
612
+ if (ov) ov.classList.remove('hidden');
613
+ startNN();
614
+ }"""
615
+ ).then(
616
+ fn=on_generation_done,
617
+ inputs=[combined_state],
618
+ outputs=[
619
+ gen_screen,
620
+ main_screen,
621
+ narrative,
622
+ main_img,
623
+ gallery_top,
624
+ mid_img,
625
+ stack_gallery,
626
+ small_img,
627
+ room_state,
628
+ sel_container,
629
+ sel_key,
630
+ door_btn,
631
+ selection_display,
632
+ narration_audio,
633
+ ],
634
+ js="""() => {
635
+ const ov = document.getElementById('nn-overlay');
636
+ if (ov) ov.classList.add('hidden');
637
+ stopNN();
638
+ }"""
639
+ )
 
 
640
 
641
 
642
  # ── Gallery selection wiring ──────────────────────────────────────────────