deeme commited on
Commit
83b4c2e
·
verified ·
1 Parent(s): eeff536

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +2 -2
  2. app.py +36 -19
Dockerfile CHANGED
@@ -2,9 +2,9 @@ FROM python:3.9-slim
2
 
3
  WORKDIR /app
4
 
5
- # 安装FFmpeg和Noto Sans CJK SC字体
6
  RUN apt-get update && \
7
- apt-get install -y ffmpeg fonts-roboto && \
8
  apt-get clean && \
9
  rm -rf /var/lib/apt/lists/*
10
 
 
2
 
3
  WORKDIR /app
4
 
5
+ # 安装FFmpeg
6
  RUN apt-get update && \
7
+ apt-get install -y ffmpeg fonts-noto-cjk && \
8
  apt-get clean && \
9
  rm -rf /var/lib/apt/lists/*
10
 
app.py CHANGED
@@ -156,13 +156,13 @@ def create_speech_subtitle_file(project_dir, speeches, panel_start_times, panel_
156
  logger.error(f"Error creating speech subtitle file: {e}")
157
  return None
158
 
159
- # 格式化时间为SRT格式
160
  def format_time(seconds):
161
  hours = int(seconds / 3600)
162
  minutes = int((seconds % 3600) / 60)
163
  secs = int(seconds % 60)
164
- millisecs = int((seconds - int(seconds)) * 1000)
165
- return f"{hours:02}:{minutes:02}:{secs:02},{millisecs:03}"
166
 
167
  # 创建音频文件
168
  async def create_audio_file(project_dir, captions, speeches):
@@ -181,7 +181,7 @@ async def create_audio_file(project_dir, captions, speeches):
181
  # 每个面板的旁白
182
  if caption:
183
  caption_audio = os.path.join(project_dir, f"caption_{i}.mp3")
184
- result = await generate_speech(caption, "alloy", caption_audio)
185
  if result:
186
  duration = get_audio_duration(caption_audio)
187
  audio_durations[f"caption_{i}"] = duration
@@ -191,7 +191,7 @@ async def create_audio_file(project_dir, captions, speeches):
191
  # 每个面板的对话
192
  if speech:
193
  speech_audio = os.path.join(project_dir, f"speech_{i}.mp3")
194
- result = await generate_speech(speech, "nova", speech_audio)
195
  if result:
196
  duration = get_audio_duration(speech_audio)
197
  audio_durations[f"speech_{i}"] = duration
@@ -268,14 +268,19 @@ def get_video_dimensions(video_path):
268
  return (1920, 1080)
269
 
270
  def process_sub_path(path):
271
- # 统一处理所有特殊字符
272
- return shlex.quote(
273
- str(Path(path).resolve())
274
- .replace(':', '\\:')
275
- .replace(' ', '\\ ')
276
- .replace('(', '\\(')
277
- .replace(')', '\\)')
278
- )
 
 
 
 
 
279
 
280
  # 创建视频
281
  def create_video(project_dir, image_paths, caption_subtitle_file, speech_subtitle_file,
@@ -311,14 +316,26 @@ def create_video(project_dir, image_paths, caption_subtitle_file, speech_subtitl
311
  # 构建滤镜链
312
  combined_filter = (
313
  f"subtitles={process_sub_path(caption_subtitle_file)}:"
314
- "force_style='Fontsize={},Alignment=2,MarginV={},Outline=1'".format(
315
- int(base_fontsize*0.9),
316
- video_height//10
 
 
 
 
 
 
317
  ),
318
  f"subtitles={process_sub_path(speech_subtitle_file)}:"
319
- "force_style='Fontsize={},Alignment=8,MarginV={},Outline=1'".format(
320
- base_fontsize,
321
- video_height//12
 
 
 
 
 
 
322
  )
323
  )
324
  filter_chain = ",".join(combined_filter)
 
156
  logger.error(f"Error creating speech subtitle file: {e}")
157
  return None
158
 
159
+ # 格式化时间
160
  def format_time(seconds):
161
  hours = int(seconds / 3600)
162
  minutes = int((seconds % 3600) / 60)
163
  secs = int(seconds % 60)
164
+ centisecs = int((seconds - int(seconds)) * 100)
165
+ return f"{hours}:{minutes:02}:{secs:02}.{centisecs:02}"
166
 
167
  # 创建音频文件
168
  async def create_audio_file(project_dir, captions, speeches):
 
181
  # 每个面板的旁白
182
  if caption:
183
  caption_audio = os.path.join(project_dir, f"caption_{i}.mp3")
184
+ result = await generate_speech(caption, "zh-CN-YunjianNeural", caption_audio)
185
  if result:
186
  duration = get_audio_duration(caption_audio)
187
  audio_durations[f"caption_{i}"] = duration
 
191
  # 每个面板的对话
192
  if speech:
193
  speech_audio = os.path.join(project_dir, f"speech_{i}.mp3")
194
+ result = await generate_speech(speech, "zh-CN-XiaoxiaoNeural", speech_audio)
195
  if result:
196
  duration = get_audio_duration(speech_audio)
197
  audio_durations[f"speech_{i}"] = duration
 
268
  return (1920, 1080)
269
 
270
  def process_sub_path(path):
271
+ """深度处理FFmpeg路径转义"""
272
+ # 统一转换为POSIX路径
273
+ processed = Path(path).as_posix()
274
+ # 转义特殊字符 [ ] : , ' \
275
+ processed = processed.translate(str.maketrans({
276
+ ':': r'\:',
277
+ "'": r"\\\'",
278
+ ',': r'\\,',
279
+ '[': r'\\[',
280
+ ']': r'\\]',
281
+ ' ': r'\ '
282
+ }))
283
+ return f"'{processed}'" # 用单引号包裹整个路径
284
 
285
  # 创建视频
286
  def create_video(project_dir, image_paths, caption_subtitle_file, speech_subtitle_file,
 
316
  # 构建滤镜链
317
  combined_filter = (
318
  f"subtitles={process_sub_path(caption_subtitle_file)}:"
319
+ "force_style='"
320
+ "Fontsize={},"
321
+ "Alignment=2,"
322
+ "MarginV={},"
323
+ "WrapStyle=1,"
324
+ "BlurEdges=1"
325
+ "'".format(
326
+ int(base_fontsize*0.6),
327
+ video_height//100
328
  ),
329
  f"subtitles={process_sub_path(speech_subtitle_file)}:"
330
+ "force_style='"
331
+ "Fontsize={},"
332
+ "Alignment=8,"
333
+ "MarginV={},"
334
+ "WrapStyle=1,"
335
+ "BlurEdges=1"
336
+ "'".format(
337
+ int(base_fontsize*0.5),
338
+ video_height//10
339
  )
340
  )
341
  filter_chain = ",".join(combined_filter)