94 lines
2.6 KiB
Python
94 lines
2.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Flask Web 入口
|
|
|
|
提供简单的 Web 界面,输入主题后自动生成短视频。
|
|
"""
|
|
|
|
import os
|
|
import uuid
|
|
import traceback
|
|
from flask import Flask, render_template, request, jsonify, send_from_directory
|
|
|
|
from core.script_gen import generate_script
|
|
from core.tts import text_to_speech
|
|
from core.subtitle import build_srt
|
|
from core.video import compose_video
|
|
|
|
app = Flask(__name__)
|
|
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "output")
|
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
|
|
|
|
|
def _probe_duration(path: str) -> float:
|
|
"""获取音频时长(秒)"""
|
|
from moviepy.editor import AudioFileClip
|
|
clip = AudioFileClip(path)
|
|
dur = clip.duration
|
|
clip.close()
|
|
return float(dur)
|
|
|
|
|
|
def run_pipeline(topic: str, scenes: int = 5, rate: int = 160) -> dict:
|
|
"""完整生成流水线"""
|
|
job_id = uuid.uuid4().hex[:8]
|
|
job_dir = os.path.join(OUTPUT_DIR, job_id)
|
|
audio_dir = os.path.join(job_dir, "audio")
|
|
os.makedirs(audio_dir, exist_ok=True)
|
|
|
|
script = generate_script(topic, scenes)
|
|
|
|
audio_paths = []
|
|
durations = []
|
|
for s in script:
|
|
ap = os.path.join(audio_dir, f"{s['index']}.mp3")
|
|
text_to_speech(s["text"], ap, rate=rate)
|
|
audio_paths.append(ap)
|
|
durations.append(_probe_duration(ap))
|
|
|
|
srt_path = os.path.join(job_dir, "subtitle.srt")
|
|
build_srt(script, durations, srt_path)
|
|
|
|
video_path = os.path.join(job_dir, "video.mp4")
|
|
compose_video(script, audio_paths, durations, video_path)
|
|
|
|
return {
|
|
"job_id": job_id,
|
|
"video": f"output/{job_id}/video.mp4",
|
|
"subtitle": f"output/{job_id}/subtitle.srt",
|
|
"script": script,
|
|
}
|
|
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return render_template("index.html")
|
|
|
|
|
|
@app.route("/api/generate", methods=["POST"])
|
|
def api_generate():
|
|
data = request.get_json(force=True, silent=True) or {}
|
|
topic = (data.get("topic") or "").strip()
|
|
scenes = int(data.get("scenes") or 5)
|
|
rate = int(data.get("rate") or 160)
|
|
|
|
if not topic:
|
|
return jsonify({"ok": False, "error": "请填写主题"}), 400
|
|
if scenes < 1 or scenes > 8:
|
|
return jsonify({"ok": False, "error": "场景数需在 1-8 之间"}), 400
|
|
|
|
try:
|
|
result = run_pipeline(topic, scenes, rate)
|
|
return jsonify({"ok": True, **result})
|
|
except Exception as e:
|
|
traceback.print_exc()
|
|
return jsonify({"ok": False, "error": str(e)}), 500
|
|
|
|
|
|
@app.route("/output/<path:filename>")
|
|
def serve_output(filename):
|
|
return send_from_directory(OUTPUT_DIR, filename)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app.run(host="0.0.0.0", port=5000, debug=True)
|