Tim13ekd commited on
Commit
ad4cab5
·
verified ·
1 Parent(s): fd9d93c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -22
app.py CHANGED
@@ -35,7 +35,7 @@ def save_temp_audio(audio_file):
35
  else:
36
  raise ValueError("Das übergebene Audio ist kein gültiges Dateiformat oder NamedString.")
37
 
38
- def generate_slideshow_with_audio(images, input_text, duration_per_image=3, y_pos=0.5, fade_duration=0.7, font_size=60, speed=1.0):
39
  if not images:
40
  return None, "❌ Keine Bilder ausgewählt"
41
 
@@ -43,22 +43,19 @@ def generate_slideshow_with_audio(images, input_text, duration_per_image=3, y_po
43
  temp_dir = tempfile.mkdtemp()
44
  clips = []
45
 
46
- # Text in Segmente aufteilen
47
  words = input_text.split()
48
  total_words = len(words)
49
- segments_per_image = max(1, total_words // len(images)) # Sicherstellen, dass mindestens 1 Segment pro Bild
50
- texts = []
51
- for i in range(len(images)):
52
- start = i * segments_per_image
53
- end = min((i + 1) * segments_per_image, total_words)
54
- texts.append(" ".join(words[start:end]))
55
 
56
- temp_audio_file = None # Wir gehen davon aus, dass das Audio optional ist.
 
 
 
57
 
58
- for i, img_path in enumerate(images):
59
- img_path = Path(img_path.name) # Gradio liefert temporäre Dateipfade
60
  clip_path = Path(temp_dir) / f"clip_{i}.mp4"
61
- text = texts[i] if i < len(texts) else ""
62
 
63
  vf_filters = (
64
  "scale=w=1280:h=720:force_original_aspect_ratio=decrease,"
@@ -71,23 +68,23 @@ def generate_slideshow_with_audio(images, input_text, duration_per_image=3, y_po
71
  drawtext_filter = (
72
  f",drawtext=text={safe_text}:fontcolor=white:fontsize={font_size}:borderw=2:"
73
  f"x=(w-text_w)/2:y=(h-text_h)*{y_pos}:"
74
- f"alpha='if(lt(t,{fade_duration}), t/{fade_duration}, if(lt(t,{duration_per_image}-{fade_duration}), 1, ({duration_per_image}-t)/{fade_duration}))'"
75
  )
76
  vf_filters += drawtext_filter
77
 
78
  cmd = [
79
  "ffmpeg",
80
  "-y",
81
- "-loop", "1",
82
- "-i", str(img_path),
83
- "-t", str(duration_per_image),
84
  "-vf", vf_filters,
85
  str(clip_path)
86
  ]
87
  try:
88
  subprocess.run(cmd, check=True, capture_output=True, text=True)
89
  except subprocess.CalledProcessError as e:
90
- return None, f"❌ FFmpeg Fehler bei Bild {i+1}:\n{e.stderr}"
91
 
92
  clips.append(clip_path)
93
 
@@ -113,31 +110,55 @@ def generate_slideshow_with_audio(images, input_text, duration_per_image=3, y_po
113
  except subprocess.CalledProcessError as e:
114
  return None, f"❌ FFmpeg Concat Fehler:\n{e.stderr}"
115
 
116
- return str(output_file), "✅ Slideshow mit Text erstellt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
  # Gradio UI
119
  with gr.Blocks() as demo:
120
- gr.Markdown("# Slideshow mit Manuellem Text")
121
 
122
  img_input = gr.Files(label="Bilder auswählen (mehrere)", file_types=allowed_medias)
123
  text_input = gr.Textbox(
124
  label="Text eingeben",
125
- placeholder="Gib hier den Text ein, der in den Bildern angezeigt werden soll",
126
  lines=5
127
  )
128
- duration_input = gr.Number(value=3, label="Dauer pro Bild in Sekunden", precision=1)
129
  fade_input = gr.Number(value=0.7, label="Fade Dauer in Sekunden", precision=1)
130
  ypos_input = gr.Slider(minimum=0.0, maximum=0.9, step=0.01, value=0.5, label="Y-Position für alle Texte (0=oben, 0.5=mitte, 0.9=unten)")
131
  font_size_input = gr.Number(value=60, label="Textgröße (px)")
132
  speed_input = gr.Slider(minimum=0.1, maximum=3.0, value=1.0, label="Geschwindigkeit der Texteinblendung")
133
 
 
 
 
 
 
134
  out_video = gr.Video(interactive=False, label="Generiertes Video")
135
  status = gr.Textbox(interactive=False, label="Status")
136
 
137
  btn = gr.Button("Video erstellen")
138
  btn.click(
139
  fn=generate_slideshow_with_audio,
140
- inputs=[img_input, text_input, duration_input, ypos_input, fade_input, font_size_input, speed_input],
141
  outputs=[out_video, status]
142
  )
143
 
 
35
  else:
36
  raise ValueError("Das übergebene Audio ist kein gültiges Dateiformat oder NamedString.")
37
 
38
+ def generate_slideshow_with_audio(images, input_text, duration_per_word=0.5, y_pos=0.5, fade_duration=0.7, font_size=60, speed=1.0, audio_file=None):
39
  if not images:
40
  return None, "❌ Keine Bilder ausgewählt"
41
 
 
43
  temp_dir = tempfile.mkdtemp()
44
  clips = []
45
 
46
+ # Text in Wörter aufteilen
47
  words = input_text.split()
48
  total_words = len(words)
 
 
 
 
 
 
49
 
50
+ # Wenn Audio vorhanden ist, die Dauer an die Länge des Audios anpassen (optional)
51
+ temp_audio_file = None
52
+ if audio_file:
53
+ temp_audio_file = save_temp_audio(audio_file)
54
 
55
+ # Einzelne Clips für jedes Wort erstellen
56
+ for i, word in enumerate(words):
57
  clip_path = Path(temp_dir) / f"clip_{i}.mp4"
58
+ text = word
59
 
60
  vf_filters = (
61
  "scale=w=1280:h=720:force_original_aspect_ratio=decrease,"
 
68
  drawtext_filter = (
69
  f",drawtext=text={safe_text}:fontcolor=white:fontsize={font_size}:borderw=2:"
70
  f"x=(w-text_w)/2:y=(h-text_h)*{y_pos}:"
71
+ f"alpha='if(lt(t,{fade_duration}), t/{fade_duration}, if(lt(t,{duration_per_word}-{fade_duration}), 1, ({duration_per_word}-t)/{fade_duration}))'"
72
  )
73
  vf_filters += drawtext_filter
74
 
75
  cmd = [
76
  "ffmpeg",
77
  "-y",
78
+ "-f", "lavfi",
79
+ "-t", str(duration_per_word),
80
+ "-i", "color=c=black:s=1280x720",
81
  "-vf", vf_filters,
82
  str(clip_path)
83
  ]
84
  try:
85
  subprocess.run(cmd, check=True, capture_output=True, text=True)
86
  except subprocess.CalledProcessError as e:
87
+ return None, f"❌ FFmpeg Fehler bei Wort {i+1}:\n{e.stderr}"
88
 
89
  clips.append(clip_path)
90
 
 
110
  except subprocess.CalledProcessError as e:
111
  return None, f"❌ FFmpeg Concat Fehler:\n{e.stderr}"
112
 
113
+ # Audio hinzufügen, falls vorhanden
114
+ if temp_audio_file:
115
+ final_output = Path(temp_dir) / f"slideshow_audio_{uuid.uuid4().hex}.mp4"
116
+ cmd_audio = [
117
+ "ffmpeg",
118
+ "-y",
119
+ "-i", str(output_file),
120
+ "-i", str(temp_audio_file),
121
+ "-c:v", "copy",
122
+ "-c:a", "aac",
123
+ "-shortest",
124
+ str(final_output)
125
+ ]
126
+ try:
127
+ subprocess.run(cmd_audio, check=True, capture_output=True, text=True)
128
+ return str(final_output), "✅ Slideshow mit Audio und Text erstellt"
129
+ except subprocess.CalledProcessError as e:
130
+ return None, f"❌ FFmpeg Audio Merge Fehler:\n{e.stderr}"
131
+
132
+ return str(output_file), "✅ Slideshow erstellt (ohne Audio)"
133
 
134
  # Gradio UI
135
  with gr.Blocks() as demo:
136
+ gr.Markdown("# Slideshow mit Audio und Wort-Text")
137
 
138
  img_input = gr.Files(label="Bilder auswählen (mehrere)", file_types=allowed_medias)
139
  text_input = gr.Textbox(
140
  label="Text eingeben",
141
+ placeholder="Gib hier den Text ein, der Wort für Wort eingeblendet werden soll",
142
  lines=5
143
  )
144
+ duration_input = gr.Number(value=0.5, label="Dauer pro Wort in Sekunden", precision=1)
145
  fade_input = gr.Number(value=0.7, label="Fade Dauer in Sekunden", precision=1)
146
  ypos_input = gr.Slider(minimum=0.0, maximum=0.9, step=0.01, value=0.5, label="Y-Position für alle Texte (0=oben, 0.5=mitte, 0.9=unten)")
147
  font_size_input = gr.Number(value=60, label="Textgröße (px)")
148
  speed_input = gr.Slider(minimum=0.1, maximum=3.0, value=1.0, label="Geschwindigkeit der Texteinblendung")
149
 
150
+ audio_input = gr.File(
151
+ label="Audio hinzufügen (optional)",
152
+ file_types=allowed_audios
153
+ )
154
+
155
  out_video = gr.Video(interactive=False, label="Generiertes Video")
156
  status = gr.Textbox(interactive=False, label="Status")
157
 
158
  btn = gr.Button("Video erstellen")
159
  btn.click(
160
  fn=generate_slideshow_with_audio,
161
+ inputs=[img_input, text_input, duration_input, ypos_input, fade_input, font_size_input, speed_input, audio_input],
162
  outputs=[out_video, status]
163
  )
164