ulduldp commited on
Commit
0d51b0d
·
verified ·
1 Parent(s): 73fac7b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -11
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, render_template_string, request, jsonify
2
  import os
3
  import uuid
4
  import subprocess
@@ -8,9 +8,11 @@ from faster_whisper import WhisperModel
8
 
9
  app = Flask(__name__)
10
 
11
- UPLOAD_FOLDER = "uploads"
12
- OUTPUT_FOLDER = "static/videos"
13
- SUBTITLE_FOLDER = "subtitles"
 
 
14
 
15
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
16
  os.makedirs(OUTPUT_FOLDER, exist_ok=True)
@@ -169,7 +171,7 @@ video{
169
 
170
  <div id="loading">Generating Video...</div>
171
 
172
- <video id="video" controls></video>
173
 
174
  <div class="download-btn" id="downloadDiv">
175
  <a id="downloadBtn" download>Download Video</a>
@@ -249,6 +251,7 @@ def ass_escape(text: str) -> str:
249
  return text
250
 
251
  def escape_ffmpeg_path(path: str) -> str:
 
252
  return (
253
  path
254
  .replace("\\", "\\\\")
@@ -309,7 +312,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
309
  wrapped = ass_escape(wrapped)
310
  wrapped = wrapped.replace("\n", r"\N")
311
 
312
- # Solid black background, white text, no glow/blur
313
  dialogue = (
314
  f"Dialogue: 0,{start},{end},Default,,0,0,0,,"
315
  r"{\bord0\shad0\blur0\1c&HFFFFFF&\3c&H000000&\4c&H000000&\4a&H00}"
@@ -325,6 +328,21 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
325
  def home():
326
  return render_template_string(HTML)
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  @app.route("/generate", methods=["POST"])
329
  def generate():
330
  if "image" not in request.files or "audio" not in request.files:
@@ -376,39 +394,50 @@ def generate():
376
  make_ass_subtitles(transcript, ass_path)
377
  safe_ass_path = escape_ffmpeg_path(os.path.abspath(ass_path))
378
 
379
- # Simple scale/crop + subtitles
380
  vf = (
381
  "scale=1080:1920:force_original_aspect_ratio=increase,"
382
  "crop=1080:1920,"
383
- f"subtitles='{safe_ass_path}'"
384
  )
385
 
386
  cmd = [
387
  "ffmpeg",
388
  "-y",
389
  "-loop", "1",
 
390
  "-i", image_path,
391
  "-i", audio_path,
392
  "-vf", vf,
 
 
393
  "-c:v", "libx264",
394
  "-preset", "ultrafast",
 
395
  "-pix_fmt", "yuv420p",
396
  "-r", "24",
397
  "-c:a", "aac",
398
  "-b:a", "128k",
 
399
  "-shortest",
400
  output_path
401
  ]
402
 
403
- subprocess.run(
404
  cmd,
405
  stdout=subprocess.PIPE,
406
  stderr=subprocess.PIPE,
407
  check=True
408
  )
409
 
 
 
 
 
 
 
410
  return jsonify({
411
- "video_url": f"/static/videos/{output_filename}",
412
  "transcript": transcript,
413
  "full_text": " ".join(full_text_parts).strip(),
414
  "language": getattr(info, "language", None)
@@ -427,4 +456,4 @@ def generate():
427
  })
428
 
429
  if __name__ == "__main__":
430
- app.run(host="0.0.0.0", port=7860)
 
1
+ from flask import Flask, render_template_string, request, jsonify, send_from_directory, abort
2
  import os
3
  import uuid
4
  import subprocess
 
8
 
9
  app = Flask(__name__)
10
 
11
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
12
+
13
+ UPLOAD_FOLDER = os.path.join(BASE_DIR, "uploads")
14
+ OUTPUT_FOLDER = os.path.join(BASE_DIR, "static", "videos")
15
+ SUBTITLE_FOLDER = os.path.join(BASE_DIR, "subtitles")
16
 
17
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
18
  os.makedirs(OUTPUT_FOLDER, exist_ok=True)
 
171
 
172
  <div id="loading">Generating Video...</div>
173
 
174
+ <video id="video" controls playsinline></video>
175
 
176
  <div class="download-btn" id="downloadDiv">
177
  <a id="downloadBtn" download>Download Video</a>
 
251
  return text
252
 
253
  def escape_ffmpeg_path(path: str) -> str:
254
+ # For ffmpeg filter strings
255
  return (
256
  path
257
  .replace("\\", "\\\\")
 
312
  wrapped = ass_escape(wrapped)
313
  wrapped = wrapped.replace("\n", r"\N")
314
 
315
+ # Solid black background, white text
316
  dialogue = (
317
  f"Dialogue: 0,{start},{end},Default,,0,0,0,,"
318
  r"{\bord0\shad0\blur0\1c&HFFFFFF&\3c&H000000&\4c&H000000&\4a&H00}"
 
328
  def home():
329
  return render_template_string(HTML)
330
 
331
+ @app.route("/video/<path:filename>")
332
+ def serve_video(filename):
333
+ file_path = os.path.join(OUTPUT_FOLDER, filename)
334
+ if not os.path.exists(file_path):
335
+ abort(404)
336
+
337
+ response = send_from_directory(
338
+ OUTPUT_FOLDER,
339
+ filename,
340
+ as_attachment=False,
341
+ conditional=True
342
+ )
343
+ response.headers["Cache-Control"] = "no-store"
344
+ return response
345
+
346
  @app.route("/generate", methods=["POST"])
347
  def generate():
348
  if "image" not in request.files or "audio" not in request.files:
 
394
  make_ass_subtitles(transcript, ass_path)
395
  safe_ass_path = escape_ffmpeg_path(os.path.abspath(ass_path))
396
 
397
+ # Scale/crop image to 9:16 + burn subtitles
398
  vf = (
399
  "scale=1080:1920:force_original_aspect_ratio=increase,"
400
  "crop=1080:1920,"
401
+ f"ass='{safe_ass_path}'"
402
  )
403
 
404
  cmd = [
405
  "ffmpeg",
406
  "-y",
407
  "-loop", "1",
408
+ "-framerate", "1",
409
  "-i", image_path,
410
  "-i", audio_path,
411
  "-vf", vf,
412
+ "-map", "0:v:0",
413
+ "-map", "1:a:0",
414
  "-c:v", "libx264",
415
  "-preset", "ultrafast",
416
+ "-crf", "20",
417
  "-pix_fmt", "yuv420p",
418
  "-r", "24",
419
  "-c:a", "aac",
420
  "-b:a", "128k",
421
+ "-movflags", "+faststart",
422
  "-shortest",
423
  output_path
424
  ]
425
 
426
+ result = subprocess.run(
427
  cmd,
428
  stdout=subprocess.PIPE,
429
  stderr=subprocess.PIPE,
430
  check=True
431
  )
432
 
433
+ if not os.path.exists(output_path) or os.path.getsize(output_path) == 0:
434
+ return jsonify({
435
+ "error": "Video file not created",
436
+ "details": "FFmpeg ran but output file is missing or empty."
437
+ })
438
+
439
  return jsonify({
440
+ "video_url": f"/video/{output_filename}",
441
  "transcript": transcript,
442
  "full_text": " ".join(full_text_parts).strip(),
443
  "language": getattr(info, "language", None)
 
456
  })
457
 
458
  if __name__ == "__main__":
459
+ app.run(host="0.0.0.0", port=7860, debug=True)