VirtualOasis commited on
Commit
0422489
·
1 Parent(s): 0c81186
Files changed (1) hide show
  1. app.py +64 -8
app.py CHANGED
@@ -26,6 +26,23 @@ SCENE_COLUMNS = ["Scene", "Title", "Action", "Visuals", "Characters", "Duration
26
  CHARACTER_COLUMNS = ["ID", "Name", "Role", "Traits"]
27
 
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  def _ensure_storyboard(board: Storyboard | None) -> Storyboard:
30
  if not board:
31
  raise gr.Error("Create a storyboard first.")
@@ -43,7 +60,7 @@ def handle_storyboard(
43
  style: str,
44
  scene_count: int,
45
  google_api_key: str,
46
- ) -> Tuple[str, List[List[str]], List[List[str]], Storyboard]:
47
  _validate_inputs(idea, inspiration_image)
48
  generator = StoryGenerator(api_key=google_api_key or None)
49
  storyboard = generator.generate(
@@ -55,11 +72,13 @@ def handle_storyboard(
55
  summary_md = f"### {storyboard.title}\n{storyboard.synopsis}"
56
  scene_rows = storyboard.scenes_table()
57
  character_rows = storyboard.characters_table()
 
58
  return (
59
  summary_md,
60
  [[row[col] for col in SCENE_COLUMNS] for row in scene_rows],
61
  [[row[col] for col in CHARACTER_COLUMNS] for row in character_rows],
62
  storyboard,
 
63
  )
64
 
65
 
@@ -69,12 +88,32 @@ def handle_character_design(
69
  ):
70
  board = _ensure_storyboard(storyboard)
71
  designer = CharacterDesigner(api_key=google_api_key or None)
72
- gallery, updated_board = designer.design(board)
 
73
  if not gallery:
74
  raise gr.Error("Failed to design characters.")
75
  return gallery, updated_board
76
 
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  def handle_video_render(
79
  storyboard: Storyboard | None,
80
  hf_token: str,
@@ -155,26 +194,41 @@ with gr.Blocks(fill_height=True, elem_id="cinegen-app") as demo:
155
  scenes_df = gr.Dataframe(headers=SCENE_COLUMNS, wrap=True)
156
  characters_df = gr.Dataframe(headers=CHARACTER_COLUMNS, wrap=True)
157
 
158
- storyboard_btn.click(
159
- fn=handle_storyboard,
160
- inputs=[idea_box, inspiration, style_dropdown, scene_slider, google_key_input],
161
- outputs=[summary_md, scenes_df, characters_df, story_state],
162
- )
163
-
164
  with gr.Row():
165
  design_btn = gr.Button("Design Characters", variant="secondary")
166
  render_btn = gr.Button("Render Short Film", variant="primary")
167
 
 
 
 
 
 
 
 
 
 
168
  gallery = gr.Gallery(label="Character References", columns=4, height=320)
169
  render_logs = gr.Markdown(label="Render Log")
170
  final_video = gr.Video(label="CineGen Short Film", interactive=False)
171
 
 
 
 
 
 
 
172
  design_btn.click(
173
  fn=handle_character_design,
174
  inputs=[story_state, google_key_input],
175
  outputs=[gallery, story_state],
176
  )
177
 
 
 
 
 
 
 
178
  def _model_value(label: str) -> str:
179
  lookup = dict(VIDEO_MODEL_CHOICES)
180
  return lookup.get(label, VIDEO_MODEL_CHOICES[0][1])
@@ -186,6 +240,8 @@ with gr.Blocks(fill_height=True, elem_id="cinegen-app") as demo:
186
  fn=render_wrapper,
187
  inputs=[story_state, hf_token_input, video_model_dropdown],
188
  outputs=[final_video, render_logs],
 
 
189
  )
190
 
191
  if __name__ == "__main__":
 
26
  CHARACTER_COLUMNS = ["ID", "Name", "Role", "Traits"]
27
 
28
 
29
+ def _character_dropdown_update(board: Storyboard | None):
30
+ if not board or not board.characters:
31
+ return gr.Dropdown.update(choices=[], value=None, interactive=False)
32
+ choices = [character.identifier for character in board.characters]
33
+ return gr.Dropdown.update(choices=choices, value=choices[0], interactive=True)
34
+
35
+
36
+ def _gallery_from_board(board: Storyboard) -> List[Tuple[str, str]]:
37
+ gallery: List[Tuple[str, str]] = []
38
+ for character in board.characters:
39
+ if not character.reference_image:
40
+ continue
41
+ caption = f"{character.name} — {character.role}"
42
+ gallery.append((character.reference_image, caption))
43
+ return gallery
44
+
45
+
46
  def _ensure_storyboard(board: Storyboard | None) -> Storyboard:
47
  if not board:
48
  raise gr.Error("Create a storyboard first.")
 
60
  style: str,
61
  scene_count: int,
62
  google_api_key: str,
63
+ ) -> Tuple[str, List[List[str]], List[List[str]], Storyboard, gr.Dropdown]:
64
  _validate_inputs(idea, inspiration_image)
65
  generator = StoryGenerator(api_key=google_api_key or None)
66
  storyboard = generator.generate(
 
72
  summary_md = f"### {storyboard.title}\n{storyboard.synopsis}"
73
  scene_rows = storyboard.scenes_table()
74
  character_rows = storyboard.characters_table()
75
+ dropdown_update = _character_dropdown_update(storyboard)
76
  return (
77
  summary_md,
78
  [[row[col] for col in SCENE_COLUMNS] for row in scene_rows],
79
  [[row[col] for col in CHARACTER_COLUMNS] for row in character_rows],
80
  storyboard,
81
+ dropdown_update,
82
  )
83
 
84
 
 
88
  ):
89
  board = _ensure_storyboard(storyboard)
90
  designer = CharacterDesigner(api_key=google_api_key or None)
91
+ _, updated_board = designer.design(board)
92
+ gallery = _gallery_from_board(updated_board)
93
  if not gallery:
94
  raise gr.Error("Failed to design characters.")
95
  return gallery, updated_board
96
 
97
 
98
+ def handle_character_regen(
99
+ storyboard: Storyboard | None,
100
+ character_id: str | None,
101
+ google_api_key: str,
102
+ ):
103
+ board = _ensure_storyboard(storyboard)
104
+ if not character_id:
105
+ raise gr.Error("Select a character ID to regenerate.")
106
+ designer = CharacterDesigner(api_key=google_api_key or None)
107
+ try:
108
+ _, updated_board = designer.redesign_character(board, character_id)
109
+ except ValueError as exc:
110
+ raise gr.Error(str(exc)) from exc
111
+ gallery = _gallery_from_board(updated_board)
112
+ if not gallery:
113
+ raise gr.Error("Failed to refresh character art.")
114
+ return gallery, updated_board
115
+
116
+
117
  def handle_video_render(
118
  storyboard: Storyboard | None,
119
  hf_token: str,
 
194
  scenes_df = gr.Dataframe(headers=SCENE_COLUMNS, wrap=True)
195
  characters_df = gr.Dataframe(headers=CHARACTER_COLUMNS, wrap=True)
196
 
 
 
 
 
 
 
197
  with gr.Row():
198
  design_btn = gr.Button("Design Characters", variant="secondary")
199
  render_btn = gr.Button("Render Short Film", variant="primary")
200
 
201
+ with gr.Row():
202
+ character_select = gr.Dropdown(
203
+ label="Character Slot",
204
+ choices=[],
205
+ interactive=False,
206
+ info="Select an ID from the storyboard table to regenerate its portrait.",
207
+ )
208
+ regen_btn = gr.Button("Regenerate Selected Character", variant="secondary")
209
+
210
  gallery = gr.Gallery(label="Character References", columns=4, height=320)
211
  render_logs = gr.Markdown(label="Render Log")
212
  final_video = gr.Video(label="CineGen Short Film", interactive=False)
213
 
214
+ storyboard_btn.click(
215
+ fn=handle_storyboard,
216
+ inputs=[idea_box, inspiration, style_dropdown, scene_slider, google_key_input],
217
+ outputs=[summary_md, scenes_df, characters_df, story_state, character_select],
218
+ )
219
+
220
  design_btn.click(
221
  fn=handle_character_design,
222
  inputs=[story_state, google_key_input],
223
  outputs=[gallery, story_state],
224
  )
225
 
226
+ regen_btn.click(
227
+ fn=handle_character_regen,
228
+ inputs=[story_state, character_select, google_key_input],
229
+ outputs=[gallery, story_state],
230
+ )
231
+
232
  def _model_value(label: str) -> str:
233
  lookup = dict(VIDEO_MODEL_CHOICES)
234
  return lookup.get(label, VIDEO_MODEL_CHOICES[0][1])
 
240
  fn=render_wrapper,
241
  inputs=[story_state, hf_token_input, video_model_dropdown],
242
  outputs=[final_video, render_logs],
243
+ queue=True,
244
+ concurrency_limit=1,
245
  )
246
 
247
  if __name__ == "__main__":