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

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

View File

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

View File

@ -1,4 +1,5 @@
import re
import os
import glob
import random
from typing import List
@ -369,10 +370,17 @@ def generate_video_v2(
return _clip
video_clip = VideoFileClip(video_path)
original_audio = video_clip.audio # 保存原始视频的音轨
video_duration = video_clip.duration
# 处理多个音频文件
audio_clips = []
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))
if match:
@ -382,28 +390,53 @@ def generate_video_v2(
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 = 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)
else:
logger.warning(f"无法从文件名解析时间信息: {audio_path}")
# 合并所有音频剪辑
# 合并所有音频剪辑,包括原始音轨
if audio_clips:
audio_clips.insert(0, original_audio) # 将原始音轨添加到音频剪辑列表的开头
audio_clip = CompositeAudioClip(audio_clips)
else:
logger.warning("没有有效的音频文件")
audio_clip = AudioClip(lambda t: 0, duration=video_clip.duration)
logger.warning("没有有效的音频文件,使用原始音轨")
audio_clip = original_audio
# 字幕处理部分保持不变
# 字幕处理部分
if subtitle_path and os.path.exists(subtitle_path):
sub = SubtitlesClip(subtitles=subtitle_path, encoding="utf-8")
text_clips = []
for item in sub.subtitles:
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)
logger.info(f"处理了 {len(text_clips)} 段字幕")
# 创建一个新的视频剪辑,包含所有字幕
video_clip = CompositeVideoClip([video_clip, *text_clips])
# 背景音乐处理部分保持不变
# 背景音乐处理部分
bgm_file = get_bgm_file(bgm_type=params.bgm_type, bgm_file=params.bgm_file)
if bgm_file:
try:
@ -573,39 +606,43 @@ def combine_clip_videos(combined_video_path: str,
if __name__ == "__main__":
combined_video_path = "../../storage/tasks/12312312/com123.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_12-00_17.mp4',
'../../storage/cache_videos/vid-00_26-00_31.mp4']
video_ost_list = [False, True, False, True]
list_script = [
{
"picture": "夜晚,一个小孩在树林里奔跑,后面有人拿着火把在追赶",
"timestamp": "00:00-00:03",
"narration": "夜黑风高的树林,一个小孩在拼命奔跑,后面的人穷追不舍!",
"OST": False
},
{
"picture": "追赶的人命令抓住小孩",
"timestamp": "00:03-00:07",
"narration": "原声播放1",
"OST": True
},
{
"picture": "小孩躲在草丛里,黑衣人用脚踢了踢他",
"timestamp": "00:12-00:17",
"narration": "小孩脱下外套,跑进树林, 一路奔跑,直到第二天清晨",
"OST": False
},
{
"picture": "小孩跑到车前,慌慌张张地对女人说有人要杀他",
"timestamp": "00:26-00:31",
"narration": "原声播放2",
"OST": True
}
]
# combined_video_path = "../../storage/tasks/12312312/com123.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_12-00_17.mp4',
# '../../storage/cache_videos/vid-00_26-00_31.mp4']
# video_ost_list = [False, True, False, True]
# list_script = [
# {
# "picture": "夜晚,一个小孩在树林里奔跑,后面有人拿着火把在追赶",
# "timestamp": "00:00-00:03",
# "narration": "夜黑风高的树林,一个小孩在拼命奔跑,后面的人穷追不舍!",
# "OST": False,
# "new_timestamp": "00:00-00:03"
# },
# {
# "picture": "追赶的人命令抓住小孩",
# "timestamp": "00:03-00:07",
# "narration": "原声播放1",
# "OST": True,
# "new_timestamp": "00:03-00:07"
# },
# {
# "picture": "小孩躲在草丛里,黑衣人用脚踢了踢他",
# "timestamp": "00:12-00:17",
# "narration": "小孩脱下外套,跑进树林, 一路奔跑,直到第二天清晨",
# "OST": False,
# "new_timestamp": "00:07-00:12"
# },
# {
# "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)
cfg = VideoClipParams()
@ -633,14 +670,18 @@ if __name__ == "__main__":
# 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',
'../../storage/tasks/12312312/audio_00-12-00-17.mp3']
audio_paths = ['../../storage/tasks/7f5ae494-abce-43cf-8f4f-4be43320eafa/audio_00-00-00-07.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,
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']:
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):
logger.error(f"Sub maker list index out of range: {sub_maker_index}")
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:
if not item['OST']:
timestamp = item['timestamp'].replace(':', '-')
timestamp = item['new_timestamp'].replace(':', '-')
audio_file = os.path.join(output_dir, f"audio_{timestamp}.mp3")
# 检查文件是否已存在,如存在且不强制重新生成,则跳过

View File

@ -7,7 +7,7 @@ from loguru import logger
import json
from uuid import uuid4
import urllib3
from datetime import datetime
from datetime import datetime, timedelta
from app.models import const
@ -326,3 +326,42 @@ def calculate_total_duration(scenes):
total_seconds += duration.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的头尾标识
input_json = input_json.strip('```json').strip('```')
try:
data = json.loads(input_json)
data = utils.add_new_timestamps(json.loads(input_json))
except Exception as err:
raise ValueError(
f"视频脚本格式错误,请检查脚本是否符合 JSON 格式;{err} \n\n{traceback.format_exc()}")