yooi commited on
Commit
7f23bd8
·
verified ·
1 Parent(s): e86e788

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +16 -30
app.py CHANGED
@@ -6,7 +6,6 @@ see poetic/providers/ for the swappable provider seam (local ZeroGPU vs HF API).
6
 
7
  import logging
8
  import tempfile
9
- from concurrent.futures import ThreadPoolExecutor
10
 
11
  import gradio as gr
12
 
@@ -20,12 +19,10 @@ from poetic.recite import (
20
  music_tags,
21
  voice_or_default,
22
  )
23
- from poetic.storyboard import generate_scenes
24
  from poetic.styles import DEFAULT_IMAGE_STYLE, apply_image_style
25
  from poetic.textfree import ensure_text_free
26
  from poetic.video import (
27
  audio_duration,
28
- concat_clips,
29
  mix_recitation_over_music,
30
  mux_song_into_video,
31
  )
@@ -107,39 +104,28 @@ def _paint_scene(scene_brief: str, style_id: str):
107
  return providers.get_painter().paint(brief)
108
 
109
 
110
- def do_animate(brief_en: str, audio_path: str | None, poem: str,
111
- understanding: str = "", style_id: str = "",
112
  progress: gr.Progress = gr.Progress()):
113
- """Storyboard film: derive a few scenes from the poem's meaning, paint each,
114
- animate each (in parallel), crossfade them into one smooth clip, add the song."""
115
- if not (poem and poem.strip()):
116
- raise gr.Error("请先写下您的诗。")
117
- if not (brief_en and brief_en.strip()):
118
- raise gr.Error("请先点「读诗」,我才能编出画面。")
 
 
119
  try:
120
- progress(0.05, desc="构思分镜(把诗拆成几幕画面)…")
121
- scenes = generate_scenes(poem.strip(), understanding or "", brief_en, n=3)
122
- log.info("do_animate: %d keyframes\n%s", len(scenes), "\n---\n".join(scenes))
123
-
124
- progress(0.2, desc="绘制关键画面…")
125
- with ThreadPoolExecutor(max_workers=min(4, len(scenes))) as ex:
126
- keyframes = list(ex.map(lambda s: _paint_scene(s, style_id), scenes))
127
-
128
- # First-last-frame interpolation: each segment is a smooth generated
129
- # video from one keyframe to the next, joined seamlessly → one flowing
130
- # film (not crossfaded scenes).
131
- clips = providers.get_animator().interpolate_keyframes(
132
- keyframes, scenes,
133
  progress_cb=lambda f, d: progress(f, desc=d),
134
  )
135
- progress(0.9, desc="衔接成完整影片…")
136
- video = concat_clips(clips)
137
  except gr.Error:
138
  raise
139
  except Exception as exc: # noqa: BLE001 — cold-start/network → warm copy
140
- raise gr.Error("正在编排小影片(用大模型衔接画面,约三五分钟),请稍候再点一次「让画活起来」。") from exc
141
  if audio_path:
142
- progress(0.95, desc="把歌配到影片里…")
143
  video = mux_song_into_video(video, audio_path)
144
  return video
145
 
@@ -152,7 +138,7 @@ def do_everything(poem: str, style_id: str, voice: str, music_vibe: str,
152
  yield understanding, brief_en, card, painting, gr.update(), gr.update()
153
  audio = do_recite(poem, voice, music_vibe)
154
  yield understanding, brief_en, card, painting, audio, gr.update()
155
- video = do_animate(brief_en, audio, poem, understanding, style_id)
156
  yield understanding, brief_en, card, painting, audio, video
157
 
158
 
@@ -454,7 +440,7 @@ with gr.Blocks(title="诗情画意 · Poetry to Art") as demo:
454
 
455
  animate_btn.click(
456
  do_animate,
457
- inputs=[brief_state, song_audio, poem_box, understanding_md, style_radio],
458
  outputs=video_out,
459
  )
460
 
 
6
 
7
  import logging
8
  import tempfile
 
9
 
10
  import gradio as gr
11
 
 
19
  music_tags,
20
  voice_or_default,
21
  )
 
22
  from poetic.styles import DEFAULT_IMAGE_STYLE, apply_image_style
23
  from poetic.textfree import ensure_text_free
24
  from poetic.video import (
25
  audio_duration,
 
26
  mix_recitation_over_music,
27
  mux_song_into_video,
28
  )
 
104
  return providers.get_painter().paint(brief)
105
 
106
 
107
+ def do_animate(painting, brief_en: str, audio_path: str | None, style_id: str = "",
 
108
  progress: gr.Progress = gr.Progress()):
109
+ """Single coherent shot: animate the painting itself (slow camera move +
110
+ ambient motion) — one continuous living painting, no scene morphing/cuts.
111
+ Then lay the recitation + music underneath."""
112
+ if painting is None:
113
+ if not (brief_en and brief_en.strip()):
114
+ raise gr.Error("请先点「作画」,有了画才能让它动起来。")
115
+ progress(0.1, desc="先画一幅…")
116
+ painting = _paint_scene(brief_en, style_id)
117
  try:
118
+ video = providers.get_animator().animate(
119
+ painting, brief_en or "",
 
 
 
 
 
 
 
 
 
 
 
120
  progress_cb=lambda f, d: progress(f, desc=d),
121
  )
122
+ progress(0.93, desc="收尾…")
 
123
  except gr.Error:
124
  raise
125
  except Exception as exc: # noqa: BLE001 — cold-start/network → warm copy
126
+ raise gr.Error("正在让画动起来(首次最久,约一两分钟),请稍候再点一次「让画活起来」。") from exc
127
  if audio_path:
128
+ progress(0.96, desc="把朗诵与音乐配进来…")
129
  video = mux_song_into_video(video, audio_path)
130
  return video
131
 
 
138
  yield understanding, brief_en, card, painting, gr.update(), gr.update()
139
  audio = do_recite(poem, voice, music_vibe)
140
  yield understanding, brief_en, card, painting, audio, gr.update()
141
+ video = do_animate(painting, brief_en, audio, style_id)
142
  yield understanding, brief_en, card, painting, audio, video
143
 
144
 
 
440
 
441
  animate_btn.click(
442
  do_animate,
443
+ inputs=[painting_state, brief_state, song_audio, style_radio],
444
  outputs=video_out,
445
  )
446