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