运行成功,但脚本问题还很大

This commit is contained in:
linyqh 2024-09-20 00:42:33 +08:00
parent 2bc94651a2
commit a675e35f1d
6 changed files with 149 additions and 68 deletions

View File

@ -451,7 +451,7 @@ def gemini_video2json(video_origin_name: str, video_origin_path: str, video_plot
""" % (language, video_plot) """ % (language, video_plot)
logger.debug(f"视频名称: {video_origin_name}") logger.debug(f"视频名称: {video_origin_name}")
try: # try:
gemini_video_file = gemini.upload_file(video_origin_path) gemini_video_file = gemini.upload_file(video_origin_path)
logger.debug(f"上传视频至 Google cloud 成功: {gemini_video_file.name}") logger.debug(f"上传视频至 Google cloud 成功: {gemini_video_file.name}")
while gemini_video_file.state.name == "PROCESSING": while gemini_video_file.state.name == "PROCESSING":
@ -461,9 +461,9 @@ def gemini_video2json(video_origin_name: str, video_origin_path: str, video_plot
logger.debug(f"视频当前状态(ACTIVE才可用): {gemini_video_file.state.name}") logger.debug(f"视频当前状态(ACTIVE才可用): {gemini_video_file.state.name}")
if gemini_video_file.state.name == "FAILED": if gemini_video_file.state.name == "FAILED":
raise ValueError(gemini_video_file.state.name) raise ValueError(gemini_video_file.state.name)
except Exception as err: # except Exception as err:
logger.error(f"上传视频至 Google cloud 失败, 请检查 VPN 配置和 APIKey 是否正确 \n{traceback.format_exc()}") # logger.error(f"上传视频至 Google cloud 失败, 请检查 VPN 配置和 APIKey 是否正确 \n{traceback.format_exc()}")
raise TimeoutError(f"上传视频至 Google cloud 失败, 请检查 VPN 配置和 APIKey 是否正确; {err}") # raise TimeoutError(f"上传视频至 Google cloud 失败, 请检查 VPN 配置和 APIKey 是否正确; {err}")
streams = model.generate_content([prompt, gemini_video_file], stream=True) streams = model.generate_content([prompt, gemini_video_file], stream=True)
response = [] response = []
@ -490,7 +490,7 @@ if __name__ == "__main__":
# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# #
video_subject = "卖菜大妈竟是皇嫂" video_subject = "卖菜大妈竟是皇嫂"
video_path = "/NarratoAI/resource/videos/demoyasuo.mp4" video_path = "../../resource/videos/demoyasuo.mp4"
video_plot = ''' ''' video_plot = ''' '''
language = "zh-CN" language = "zh-CN"

View File

@ -440,8 +440,9 @@ def start_subclip(task_id, params: VideoClipParams, subclip_path_videos):
logger.info(f"\n\n## 6. 最后一步: {index} => {final_video_path}") logger.info(f"\n\n## 6. 最后一步: {index} => {final_video_path}")
# 把所有东西合到在一起 # 把所有东西合到在一起
video.generate_video(video_path=combined_video_path, video.generate_video_v2(
audio_path=audio_file, video_path=combined_video_path,
audio_paths=audio_files,
subtitle_path=subtitle_path, subtitle_path=subtitle_path,
output_file=final_video_path, output_file=final_video_path,
params=params, params=params,

View File

@ -1,4 +1,5 @@
import re import re
import os
import glob import glob
import random import random
from typing import List from typing import List
@ -369,10 +370,17 @@ def generate_video_v2(
return _clip return _clip
video_clip = VideoFileClip(video_path) video_clip = VideoFileClip(video_path)
original_audio = video_clip.audio # 保存原始视频的音轨
video_duration = video_clip.duration
# 处理多个音频文件 # 处理多个音频文件
audio_clips = [] audio_clips = []
for audio_path in audio_paths: for audio_path in audio_paths:
# 确保每个音频文件路径是正确的
if not os.path.exists(audio_path):
logger.warning(f"音频文件不存在: {audio_path}")
continue
# 从文件名中提取时间信息 # 从文件名中提取时间信息
match = re.search(r'audio_(\d{2}-\d{2}-\d{2}-\d{2})\.mp3', os.path.basename(audio_path)) match = re.search(r'audio_(\d{2}-\d{2}-\d{2}-\d{2})\.mp3', os.path.basename(audio_path))
if match: if match:
@ -382,28 +390,53 @@ def generate_video_v2(
end_time = sum(int(x) * 60 ** i for i, x in enumerate(reversed(end))) end_time = sum(int(x) * 60 ** i for i, x in enumerate(reversed(end)))
audio_clip = AudioFileClip(audio_path).volumex(params.voice_volume) audio_clip = AudioFileClip(audio_path).volumex(params.voice_volume)
audio_clip = audio_clip.set_start(start_time).set_end(end_time)
# 确保结束时间不超过音频实际长度
actual_end_time = min(end_time - start_time, audio_clip.duration)
audio_clip = audio_clip.subclip(0, actual_end_time)
audio_clip = audio_clip.set_start(start_time).set_end(start_time + actual_end_time)
audio_clips.append(audio_clip) audio_clips.append(audio_clip)
else: else:
logger.warning(f"无法从文件名解析时间信息: {audio_path}") logger.warning(f"无法从文件名解析时间信息: {audio_path}")
# 合并所有音频剪辑 # 合并所有音频剪辑,包括原始音轨
if audio_clips: if audio_clips:
audio_clips.insert(0, original_audio) # 将原始音轨添加到音频剪辑列表的开头
audio_clip = CompositeAudioClip(audio_clips) audio_clip = CompositeAudioClip(audio_clips)
else: else:
logger.warning("没有有效的音频文件") logger.warning("没有有效的音频文件,使用原始音轨")
audio_clip = AudioClip(lambda t: 0, duration=video_clip.duration) audio_clip = original_audio
# 字幕处理部分保持不变 # 字幕处理部分
if subtitle_path and os.path.exists(subtitle_path): if subtitle_path and os.path.exists(subtitle_path):
sub = SubtitlesClip(subtitles=subtitle_path, encoding="utf-8") sub = SubtitlesClip(subtitles=subtitle_path, encoding="utf-8")
text_clips = [] text_clips = []
for item in sub.subtitles: for item in sub.subtitles:
clip = create_text_clip(subtitle_item=item) clip = create_text_clip(subtitle_item=item)
# 确保字幕的开始时间不早于视频开始
start_time = max(clip.start, 0)
# 如果字幕的开始时间晚于视频结束时间,则跳过此字幕
if start_time >= video_duration:
continue
# 调整字幕的结束时间,但不要超过视频长度
end_time = min(clip.end, video_duration)
# 调整字幕的时间范围
clip = clip.set_start(start_time).set_end(end_time)
text_clips.append(clip) text_clips.append(clip)
logger.info(f"处理了 {len(text_clips)} 段字幕")
# 创建一个新的视频剪辑,包含所有字幕
video_clip = CompositeVideoClip([video_clip, *text_clips]) video_clip = CompositeVideoClip([video_clip, *text_clips])
# 背景音乐处理部分保持不变 # 背景音乐处理部分
bgm_file = get_bgm_file(bgm_type=params.bgm_type, bgm_file=params.bgm_file) bgm_file = get_bgm_file(bgm_type=params.bgm_type, bgm_file=params.bgm_file)
if bgm_file: if bgm_file:
try: try:
@ -573,39 +606,43 @@ def combine_clip_videos(combined_video_path: str,
if __name__ == "__main__": if __name__ == "__main__":
combined_video_path = "../../storage/tasks/12312312/com123.mp4" # combined_video_path = "../../storage/tasks/12312312/com123.mp4"
#
video_paths = ['../../storage/cache_videos/vid-00_00-00_03.mp4', # video_paths = ['../../storage/cache_videos/vid-00_00-00_03.mp4',
'../../storage/cache_videos/vid-00_03-00_07.mp4', # '../../storage/cache_videos/vid-00_03-00_07.mp4',
'../../storage/cache_videos/vid-00_12-00_17.mp4', # '../../storage/cache_videos/vid-00_12-00_17.mp4',
'../../storage/cache_videos/vid-00_26-00_31.mp4'] # '../../storage/cache_videos/vid-00_26-00_31.mp4']
video_ost_list = [False, True, False, True] # video_ost_list = [False, True, False, True]
list_script = [ # list_script = [
{ # {
"picture": "夜晚,一个小孩在树林里奔跑,后面有人拿着火把在追赶", # "picture": "夜晚,一个小孩在树林里奔跑,后面有人拿着火把在追赶",
"timestamp": "00:00-00:03", # "timestamp": "00:00-00:03",
"narration": "夜黑风高的树林,一个小孩在拼命奔跑,后面的人穷追不舍!", # "narration": "夜黑风高的树林,一个小孩在拼命奔跑,后面的人穷追不舍!",
"OST": False # "OST": False,
}, # "new_timestamp": "00:00-00:03"
{ # },
"picture": "追赶的人命令抓住小孩", # {
"timestamp": "00:03-00:07", # "picture": "追赶的人命令抓住小孩",
"narration": "原声播放1", # "timestamp": "00:03-00:07",
"OST": True # "narration": "原声播放1",
}, # "OST": True,
{ # "new_timestamp": "00:03-00:07"
"picture": "小孩躲在草丛里,黑衣人用脚踢了踢他", # },
"timestamp": "00:12-00:17", # {
"narration": "小孩脱下外套,跑进树林, 一路奔跑,直到第二天清晨", # "picture": "小孩躲在草丛里,黑衣人用脚踢了踢他",
"OST": False # "timestamp": "00:12-00:17",
}, # "narration": "小孩脱下外套,跑进树林, 一路奔跑,直到第二天清晨",
{ # "OST": False,
"picture": "小孩跑到车前,慌慌张张地对女人说有人要杀他", # "new_timestamp": "00:07-00:12"
"timestamp": "00:26-00:31", # },
"narration": "原声播放2", # {
"OST": True # "picture": "小孩跑到车前,慌慌张张地对女人说有人要杀他",
} # "timestamp": "00:26-00:31",
] # "narration": "原声播放2",
# "OST": True,
# "new_timestamp": "00:12-00:17"
# }
# ]
# combine_clip_videos(combined_video_path=combined_video_path, video_paths=video_paths, video_ost_list=video_ost_list, list_script=list_script) # combine_clip_videos(combined_video_path=combined_video_path, video_paths=video_paths, video_ost_list=video_ost_list, list_script=list_script)
cfg = VideoClipParams() cfg = VideoClipParams()
@ -633,14 +670,18 @@ if __name__ == "__main__":
# params=cfg # params=cfg
# ) # )
video_path = "../../storage/tasks/12312312/com123.mp4" video_path = "../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/combined-1.mp4"
audio_paths = ['../../storage/tasks/12312312/audio_00-00-00-03.mp3', audio_paths = ['../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/audio_00-00-00-07.mp3',
'../../storage/tasks/12312312/audio_00-12-00-17.mp3'] '../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/audio_00-14-00-17.mp3',
'../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/audio_00-17-00-22.mp3',
'../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/audio_00-34-00-45.mp3',
'../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/audio_00-59-01-09.mp3',
]
subtitle_path = "../../storage/tasks/12312312/subtitle_multiple.srt" subtitle_path = "../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa\subtitle.srt"
output_file = "../../storage/tasks/12312312/out123.mp4" output_file = "../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/final-123.mp4"
generate_video_v2(video_path=video_path, generate_video_v2(video_path=video_path,
audio_paths=audio_paths, audio_paths=audio_paths,

View File

@ -1213,7 +1213,7 @@ def create_subtitle_from_multiple(text: str, sub_maker_list: List[SubMaker], lis
if script_item['OST']: if script_item['OST']:
continue continue
start_time, end_time = script_item['timestamp'].split('-') start_time, end_time = script_item['new_timestamp'].split('-')
if sub_maker_index >= len(sub_maker_list): if sub_maker_index >= len(sub_maker_list):
logger.error(f"Sub maker list index out of range: {sub_maker_index}") logger.error(f"Sub maker list index out of range: {sub_maker_index}")
break break
@ -1317,7 +1317,7 @@ def tts_multiple(task_id: str, list_script: list, voice_name: str, voice_rate: f
for item in list_script: for item in list_script:
if not item['OST']: if not item['OST']:
timestamp = item['timestamp'].replace(':', '-') timestamp = item['new_timestamp'].replace(':', '-')
audio_file = os.path.join(output_dir, f"audio_{timestamp}.mp3") audio_file = os.path.join(output_dir, f"audio_{timestamp}.mp3")
# 检查文件是否已存在,如存在且不强制重新生成,则跳过 # 检查文件是否已存在,如存在且不强制重新生成,则跳过

View File

@ -7,7 +7,7 @@ from loguru import logger
import json import json
from uuid import uuid4 from uuid import uuid4
import urllib3 import urllib3
from datetime import datetime from datetime import datetime, timedelta
from app.models import const from app.models import const
@ -326,3 +326,42 @@ def calculate_total_duration(scenes):
total_seconds += duration.total_seconds() total_seconds += duration.total_seconds()
return total_seconds return total_seconds
def add_new_timestamps(scenes):
"""
新增新视频的时间戳并为"原生播放"的narration添加唯一标识符
Args:
scenes: 场景列表
Returns:
更新后的场景列表
"""
current_time = timedelta()
updated_scenes = []
for scene in scenes:
new_scene = scene.copy() # 创建场景的副本,以保留原始数据
start, end = new_scene['timestamp'].split('-')
start_time = datetime.strptime(start, '%M:%S')
end_time = datetime.strptime(end, '%M:%S')
duration = end_time - start_time
new_start = current_time
current_time += duration
new_end = current_time
# 将 timedelta 转换为分钟和秒
new_start_str = f"{int(new_start.total_seconds() // 60):02d}:{int(new_start.total_seconds() % 60):02d}"
new_end_str = f"{int(new_end.total_seconds() // 60):02d}:{int(new_end.total_seconds() % 60):02d}"
new_scene['new_timestamp'] = f"{new_start_str}-{new_end_str}"
# 为"原生播放"的narration添加唯一标识符
if new_scene.get('narration') == "原声播放":
unique_id = str(uuid4())[:8] # 使用UUID的前8个字符作为唯一标识符
new_scene['narration'] = f"原声播放_{unique_id}"
updated_scenes.append(new_scene)
return updated_scenes

View File

@ -395,7 +395,7 @@ with left_panel:
# 去掉json的头尾标识 # 去掉json的头尾标识
input_json = input_json.strip('```json').strip('```') input_json = input_json.strip('```json').strip('```')
try: try:
data = json.loads(input_json) data = utils.add_new_timestamps(json.loads(input_json))
except Exception as err: except Exception as err:
raise ValueError( raise ValueError(
f"视频脚本格式错误,请检查脚本是否符合 JSON 格式;{err} \n\n{traceback.format_exc()}") f"视频脚本格式错误,请检查脚本是否符合 JSON 格式;{err} \n\n{traceback.format_exc()}")