mirror of
https://github.com/linyqh/NarratoAI.git
synced 2025-12-12 19:52:48 +00:00
运行成功,但脚本问题还很大
This commit is contained in:
parent
2bc94651a2
commit
a675e35f1d
@ -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"
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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")
|
||||||
|
|
||||||
# 检查文件是否已存在,如存在且不强制重新生成,则跳过
|
# 检查文件是否已存在,如存在且不强制重新生成,则跳过
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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()}")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user