Spaces:
Running
Running
File size: 10,291 Bytes
dd74184 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
import argparse
import datetime
import os
import shutil
import gradio as gr
from threading import Thread
# 导入你的模块
from doc_split import doc_split_with_qwen_plus
from json2md import convert_json_file_to_md, process_markdown
from markdown_gather import merge_style_with_md_files, remove_trailing_dashes, insert_logo, remove_empty_lines, title_to_md
from marp2image import convert_md_files_to_png
from audio_generate_each_sentence import process_json_file, synthesize_md_to_speech
from srt_generate_for_each_sentence import generate_srt_from_audio
from calculate_durations_for_each_image import calculate_audio_durations
from movie_editor import images_to_video_with_durations
from audio2video import merge_audio_and_add_to_video
from srt2video import merge_video_and_subtitle
from theme_generate import theme_generate_with_qwen_plus
def main(args, progress_callback, log_callback):
try:
# 记录开始时间
start_time = datetime.datetime.now()
progress_callback(f"开始时间: {start_time.strftime('%Y年%m月%d日 %H时%M分%S秒')}")
log_callback(f"开始时间: {start_time.strftime('%Y年%m月%d日 %H时%M分%S秒')}")
# 生成带有时间戳的文件夹名
timestamp = start_time.strftime("%Y%m%d_%H%M%S")
material_folder = f"material_{timestamp}"
# 创建输出保存路径,将渲染素材复制到指定路径下
input_base_name = os.path.splitext(os.path.basename(args.input_txt_path))[0]
# 更新各个路径,使用新的文件夹名
args.json_path = os.path.join(material_folder, "json")
args.image_path = os.path.join(material_folder, "image")
args.audio_path = os.path.join(material_folder, "audio")
args.markdown_path = os.path.join(material_folder, "markdown")
args.srt_and_video_path = os.path.join(material_folder, "video")
# 创建必要的文件夹
folders_to_create = [
material_folder, args.markdown_path, args.json_path,
args.image_path, args.audio_path, args.srt_and_video_path
]
for folder in folders_to_create:
if not os.path.exists(folder):
os.makedirs(folder)
log_callback(f"创建文件夹: {folder}")
# 复制样式文件
if os.path.exists(args.input_style_path):
for filename in os.listdir(args.input_style_path):
full_path = os.path.join(args.input_style_path, filename)
if os.path.isfile(full_path):
shutil.copy2(full_path, args.markdown_path)
log_callback(f"样式文件已复制到: {args.markdown_path}")
else:
log_callback(f"警告: 输入样式文件夹路径 {args.input_style_path} 不存在,跳过复制操作。", is_warning=True)
# 通过API调用通义千问-Plus为输入文档生成文档标题
theme = theme_generate_with_qwen_plus(args.input_txt_path, args.title)
progress_callback(f"生成的文档标题: {theme}")
log_callback(f"生成的文档标题: {theme}")
# 通过API调用通义千问-Plus为输入文档划分段落,并为每一个段落生成一个段落标题
doc_split_with_qwen_plus(args.input_txt_path, args.json_path)
progress_callback(f"文档已分割并保存到: {args.json_path}")
log_callback(f"文档已分割并保存到: {args.json_path}")
# 总结各段落内容,保存为Markdown格式,并设置背景图片,可自行将style文件夹下的theme.png替换为自定义背景
for filename in os.listdir(args.json_path):
if filename.endswith('.json'):
json_file_path = os.path.join(args.json_path, filename)
convert_json_file_to_md(json_file_path, args.markdown_path, args.theme_path)
log_callback(f"转换 {json_file_path} 到 Markdown 格式并保存到: {args.markdown_path}")
# 将文档标题添加到Markdown文件开头作为标题页,并设置标题页背景,可自行将style文件夹下的title.png替换为自定义标题页背景
title_to_md(os.path.join(args.markdown_path, f'{input_base_name}.md'), theme, args.title_path)
log_callback(f"文档标题已添加到 Markdown 文件: {os.path.join(args.markdown_path, f'{input_base_name}.md')}")
# 删除空行,符合Marp格式
remove_empty_lines(os.path.join(args.markdown_path, f'{input_base_name}.md'))
log_callback(f"删除空行: {os.path.join(args.markdown_path, f'{input_base_name}.md')}")
# 添加阿里云logo。可自行替换为其他logo:将logo图片命名为logo.png,放到style文件夹下
insert_logo(os.path.join(args.markdown_path, f'{input_base_name}.md'), os.path.join(args.logo_path))
log_callback(f"插入logo到 Markdown 文件: {os.path.join(args.markdown_path, f'{input_base_name}.md')}")
process_markdown(os.path.join(args.markdown_path, f'{input_base_name}.md'))
log_callback(f"处理 Markdown 文件: {os.path.join(args.markdown_path, f'{input_base_name}.md')}")
# 定义并添加Marp样式文件。可查阅Marp官方文档自定义样式:将样式文件命名为style.md,放到style文件夹下
merge_style_with_md_files(args.markdown_path, args.markdown_style_path)
log_callback(f"合并样式文件到 Markdown 文件: {args.markdown_path}")
# 删除Markdown文件末尾的“---”,避免生成空白图片
remove_trailing_dashes(args.markdown_path)
log_callback(f"删除 Markdown 文件末尾的 '---': {args.markdown_path}")
# 使用Marp生成演示文稿图片
convert_md_files_to_png(os.path.join(args.markdown_path, f'{input_base_name}.md'), args.image_path)
log_callback(f"生成图片: {args.image_path}")
# 将各段落文档划分为若干句子,并通过API调用CosyVoice合成语音
process_json_file(os.path.join(args.json_path, f'{input_base_name}.json'), args.audio_path)
synthesize_md_to_speech(os.path.join(args.audio_path, input_base_name))
log_callback(f"合成语音: {args.audio_path}")
# 生成srt字幕文件
generate_srt_from_audio(os.path.join(args.audio_path, input_base_name), args.srt_and_video_path,
os.path.join(args.srt_and_video_path, input_base_name))
log_callback(f"生成SRT字幕文件: {args.srt_and_video_path}")
# 计算各段落的所有音频时长
durations = calculate_audio_durations(os.path.join(args.audio_path, input_base_name))
log_callback(f"计算音频时长: {durations}")
# 将所有图片剪辑为视频
images_to_video_with_durations(os.path.join(args.image_path, f'{input_base_name}'), args.srt_and_video_path,
durations, args.fps, input_base_name)
log_callback(f"生成视频: {args.srt_and_video_path}")
# 将音频文件嵌入视频
merge_audio_and_add_to_video(os.path.join(args.srt_and_video_path, f'{input_base_name}.mp4'),
os.path.join(args.audio_path, f'{input_base_name}'),
os.path.join(args.srt_and_video_path, f'{input_base_name}_with_audio.mp4'))
log_callback(f"合并音频到视频: {args.srt_and_video_path}")
# 将字幕文件嵌入视频
merge_video_and_subtitle(args.srt_and_video_path, input_base_name)
log_callback(f"合并字幕到视频: {args.srt_and_video_path}")
# 记录结束时间
end_time = datetime.datetime.now()
progress_callback(f"结束时间: {end_time.strftime('%Y年%m月%d日 %H时%M分%S秒')}")
log_callback(f"结束时间: {end_time.strftime('%Y年%m月%d日 %H时%M分%S秒')}")
# 计算总时间
elapsed_time = end_time - start_time
elapsed_hours, remainder = divmod(elapsed_time.total_seconds(), 3600)
elapsed_minutes, elapsed_seconds = divmod(remainder, 60)
elapsed_time_str = f"{int(elapsed_hours)}时{int(elapsed_minutes)}分{int(elapsed_seconds)}秒"
progress_callback(f"总时间: {elapsed_time_str}")
log_callback(f"总时间: {elapsed_time_str}")
except Exception as e:
log_callback(f"发生错误: {str(e)}", is_error=True)
progress_callback(f"发生错误: {str(e)}", is_error=True)
raise e
def run_conversion(input_txt_path, fps, title):
args = argparse.Namespace(
input_txt_path=input_txt_path,
input_style_path='./style',
markdown_style_path='./style/style.md',
logo_path='./style/logo.png',
theme_path='./style/theme.png',
title_path='./style/title.png',
json_path='./material/json',
image_path='./material/image',
audio_path='./material/audio',
markdown_path='./material/markdown',
srt_and_video_path='./material/video',
fps=int(fps),
title=title
)
log_text = []
def progress_callback(message, is_error=False):
log_text.append(message)
if is_error:
log_text.append(f"错误: {message}")
def log_callback(message, is_warning=False, is_error=False):
log_text.append(message)
if is_warning:
log_text.append(f"警告: {message}")
elif is_error:
log_text.append(f"错误: {message}")
def video_generation_done():
log_text.append("视频生成成功!")
main(args, progress_callback, log_callback)
video_generation_done()
return "\n".join(log_text)
def gradio_interface():
iface = gr.Interface(
fn=run_conversion,
inputs=[
gr.Textbox(lines=1, placeholder="输入文本路径", label="输入文本路径"),
gr.Number(value=30, label="帧率"),
gr.Textbox(lines=1, placeholder="视频标题", label="视频标题")
],
outputs=gr.Textbox(label="日志输出"),
title="文档生成视频",
description="将文档转换为带有音频和字幕的视频。",
live=False
)
iface.launch(share=True) # 添加 share=True
if __name__ == "__main__":
gradio_interface() |