Spaces:
Sleeping
Sleeping
| 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() |