multimodalart HF Staff commited on
Commit
c37f22a
·
verified ·
1 Parent(s): 0738932

Show the character in the output panel while the clips generate

Browse files
Files changed (1) hide show
  1. app.py +39 -4
app.py CHANGED
@@ -44,8 +44,10 @@ EXAMPLES = [
44
 
45
  PENDING = (
46
  "<div style='display:flex;align-items:center;justify-content:center;height:560px;opacity:.55;"
47
- "border:1px dashed var(--border-color-primary);border-radius:8px'>Building your character…</div>"
48
  )
 
 
49
  IDLE_PANEL = (
50
  "<div style='display:flex;align-items:center;justify-content:center;height:560px;opacity:.55;"
51
  "border:1px dashed var(--border-color-primary);border-radius:8px'>"
@@ -53,6 +55,32 @@ IDLE_PANEL = (
53
  )
54
 
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  def _out(name: str) -> str:
57
  return os.path.join(OUTPUT_DIR, f"{int(time.time() * 1000)}-{name}")
58
 
@@ -111,7 +139,8 @@ def forge(
111
  # ---- 1. the character design still ----
112
  if uploaded:
113
  character = uploaded
114
- yield PENDING, character, [], None, [], None, "Using your uploaded character."
 
115
  else:
116
  yield PENDING, None, [], None, [], None, "Designing the character…"
117
  backend = backends.BY_LABEL[backend_label]
@@ -126,7 +155,10 @@ def forge(
126
  except Exception as error:
127
  traceback.print_exc()
128
  raise gr.Error(f"{backend.space} failed: {type(error).__name__}: {error}") from error
129
- yield PENDING, character, [], None, [], None, f"Character designed. Animating {len(presets)} moves…"
 
 
 
130
 
131
  # ---- 2. one clip per move, concurrently ----
132
  # These requests are fully independent, so they are fired together: the wall clock becomes the slowest single
@@ -213,7 +245,10 @@ def forge(
213
  raise gr.Error("Every move failed. " + (failures[0] if failures else ""))
214
 
215
  gallery = [(clip["video"], clip["label"]) for clip in clips]
216
- yield PENDING, character, gallery, None, [], None, f"{len(clips)} clips generated. Cutting to pose extremes…"
 
 
 
217
 
218
  # ---- 3. key, cut to extremes, pack ----
219
  # One palette for the whole character, read before any keying. Shared across every move so the sheet cannot
 
44
 
45
  PENDING = (
46
  "<div style='display:flex;align-items:center;justify-content:center;height:560px;opacity:.55;"
47
+ "border:1px dashed var(--border-color-primary);border-radius:8px'>Designing your character…</div>"
48
  )
49
+
50
+
51
  IDLE_PANEL = (
52
  "<div style='display:flex;align-items:center;justify-content:center;height:560px;opacity:.55;"
53
  "border:1px dashed var(--border-color-primary);border-radius:8px'>"
 
55
  )
56
 
57
 
58
+ def building_panel(character_path: str | None, message: str) -> str:
59
+ """The output panel while the clips are still generating: the character, and what is happening to it.
60
+
61
+ The still is the first thing worth looking at and it exists a couple of minutes before the playable demo does,
62
+ so it goes straight into the main panel rather than staying folded away in the downloads accordion.
63
+
64
+ Embedded as a data URI, downscaled first. A file path here would have to go through `/gradio_api/file=`, which
65
+ is the route that already 403'd on this Space once, and the panel is re-yielded on every step — a 1024px PNG
66
+ would be a megabyte of base64 each time.
67
+ """
68
+ if not character_path:
69
+ return PENDING
70
+ try:
71
+ thumbnail = Image.open(character_path).convert("RGBA")
72
+ thumbnail.thumbnail((460, 460))
73
+ source = sk.data_uri(thumbnail)
74
+ except Exception: # noqa: BLE001 — the panel is cosmetic; never fail a run over it
75
+ return PENDING
76
+ return (
77
+ "<div style='display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;"
78
+ "height:560px;border:1px dashed var(--border-color-primary);border-radius:8px'>"
79
+ "<style>@keyframes sf-pulse{0%,100%{opacity:.55}50%{opacity:1}}</style>"
80
+ f"<img src='{source}' alt='character' style='max-height:400px;max-width:90%;border-radius:6px'>"
81
+ f"<div style='animation:sf-pulse 1.6s ease-in-out infinite;font-size:.95em'>{message}</div>"
82
+ "</div>"
83
+ )
84
  def _out(name: str) -> str:
85
  return os.path.join(OUTPUT_DIR, f"{int(time.time() * 1000)}-{name}")
86
 
 
139
  # ---- 1. the character design still ----
140
  if uploaded:
141
  character = uploaded
142
+ message = f"Animating {len(presets)} moves…"
143
+ yield building_panel(character, message), character, [], None, [], None, "Using your uploaded character."
144
  else:
145
  yield PENDING, None, [], None, [], None, "Designing the character…"
146
  backend = backends.BY_LABEL[backend_label]
 
155
  except Exception as error:
156
  traceback.print_exc()
157
  raise gr.Error(f"{backend.space} failed: {type(error).__name__}: {error}") from error
158
+ yield (
159
+ building_panel(character, f"Animating {len(presets)} moves…"),
160
+ character, [], None, [], None, f"Character designed. Animating {len(presets)} moves…",
161
+ )
162
 
163
  # ---- 2. one clip per move, concurrently ----
164
  # These requests are fully independent, so they are fired together: the wall clock becomes the slowest single
 
245
  raise gr.Error("Every move failed. " + (failures[0] if failures else ""))
246
 
247
  gallery = [(clip["video"], clip["label"]) for clip in clips]
248
+ yield (
249
+ building_panel(character, "Cutting to pose extremes…"),
250
+ character, gallery, None, [], None, f"{len(clips)} clips generated. Cutting to pose extremes…",
251
+ )
252
 
253
  # ---- 3. key, cut to extremes, pack ----
254
  # One palette for the whole character, read before any keying. Shared across every move so the sheet cannot