mirror of
https://github.com/linyqh/NarratoAI.git
synced 2025-12-12 11:22:51 +00:00
feat(clip_video): 支持亚秒级视频裁剪
- 增加对带毫秒时间戳的支持 - 优化时间戳解析和格式化逻辑 - 调整FFmpeg命令以支持毫秒级精度 - 更新文件命名规则以适应新时间戳格式 - 修复相关服务和接口以确保兼容性
This commit is contained in:
parent
bc732c10fd
commit
bacc1adfad
@ -368,7 +368,7 @@ class VideoClipParams(BaseModel):
|
|||||||
|
|
||||||
tts_volume: Optional[float] = Field(default=1.0, description="解说语音音量(后处理)")
|
tts_volume: Optional[float] = Field(default=1.0, description="解说语音音量(后处理)")
|
||||||
original_volume: Optional[float] = Field(default=1.0, description="视频原声音量")
|
original_volume: Optional[float] = Field(default=1.0, description="视频原声音量")
|
||||||
bgm_volume: Optional[float] = Field(default=0.6, description="背景音乐音量")
|
bgm_volume: Optional[float] = Field(default=0.3, description="背景音乐音量")
|
||||||
|
|
||||||
|
|
||||||
class VideoTranscriptionRequest(BaseModel):
|
class VideoTranscriptionRequest(BaseModel):
|
||||||
|
|||||||
@ -22,10 +22,10 @@ def parse_timestamp(timestamp: str) -> tuple:
|
|||||||
解析时间戳字符串,返回开始和结束时间
|
解析时间戳字符串,返回开始和结束时间
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
timestamp: 格式为'HH:MM:SS-HH:MM:SS'的时间戳字符串
|
timestamp: 格式为'HH:MM:SS-HH:MM:SS'或'HH:MM:SS,sss-HH:MM:SS,sss'的时间戳字符串
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (开始时间, 结束时间) 格式为'HH:MM:SS'
|
tuple: (开始时间, 结束时间) 格式为'HH:MM:SS'或'HH:MM:SS,sss'
|
||||||
"""
|
"""
|
||||||
start_time, end_time = timestamp.split('-')
|
start_time, end_time = timestamp.split('-')
|
||||||
return start_time, end_time
|
return start_time, end_time
|
||||||
@ -36,20 +36,39 @@ def calculate_end_time(start_time: str, duration: float, extra_seconds: float =
|
|||||||
根据开始时间和持续时间计算结束时间
|
根据开始时间和持续时间计算结束时间
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start_time: 开始时间,格式为'HH:MM:SS'
|
start_time: 开始时间,格式为'HH:MM:SS'或'HH:MM:SS,sss'(带毫秒)
|
||||||
duration: 持续时间,单位为秒
|
duration: 持续时间,单位为秒
|
||||||
extra_seconds: 额外添加的秒数,默认为1秒
|
extra_seconds: 额外添加的秒数,默认为1秒
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: 计算后的结束时间,格式为'HH:MM:SS'
|
str: 计算后的结束时间,格式与输入格式相同
|
||||||
"""
|
"""
|
||||||
h, m, s = map(int, start_time.split(':'))
|
# 检查是否包含毫秒
|
||||||
total_seconds = h * 3600 + m * 60 + s + duration + extra_seconds
|
has_milliseconds = ',' in start_time
|
||||||
|
milliseconds = 0
|
||||||
|
|
||||||
|
if has_milliseconds:
|
||||||
|
time_part, ms_part = start_time.split(',')
|
||||||
|
h, m, s = map(int, time_part.split(':'))
|
||||||
|
milliseconds = int(ms_part)
|
||||||
|
else:
|
||||||
|
h, m, s = map(int, start_time.split(':'))
|
||||||
|
|
||||||
|
# 转换为总毫秒数
|
||||||
|
total_milliseconds = ((h * 3600 + m * 60 + s) * 1000 + milliseconds +
|
||||||
|
int((duration + extra_seconds) * 1000))
|
||||||
|
|
||||||
|
# 计算新的时、分、秒、毫秒
|
||||||
|
ms_new = total_milliseconds % 1000
|
||||||
|
total_seconds = total_milliseconds // 1000
|
||||||
h_new = int(total_seconds // 3600)
|
h_new = int(total_seconds // 3600)
|
||||||
m_new = int((total_seconds % 3600) // 60)
|
m_new = int((total_seconds % 3600) // 60)
|
||||||
s_new = int(total_seconds % 60)
|
s_new = int(total_seconds % 60)
|
||||||
|
|
||||||
|
# 返回与输入格式一致的时间字符串
|
||||||
|
if has_milliseconds:
|
||||||
|
return f"{h_new:02d}:{m_new:02d}:{s_new:02d},{ms_new:03d}"
|
||||||
|
else:
|
||||||
return f"{h_new:02d}:{m_new:02d}:{s_new:02d}"
|
return f"{h_new:02d}:{m_new:02d}:{s_new:02d}"
|
||||||
|
|
||||||
|
|
||||||
@ -144,7 +163,7 @@ def clip_video(
|
|||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
for item in tts_result:
|
for item in tts_result:
|
||||||
_id = item["_id"]
|
_id = item.get("_id", item.get("timestamp", "unknown"))
|
||||||
timestamp = item["timestamp"]
|
timestamp = item["timestamp"]
|
||||||
start_time, _ = parse_timestamp(timestamp)
|
start_time, _ = parse_timestamp(timestamp)
|
||||||
|
|
||||||
@ -152,16 +171,22 @@ def clip_video(
|
|||||||
duration = item["duration"]
|
duration = item["duration"]
|
||||||
calculated_end_time = calculate_end_time(start_time, duration)
|
calculated_end_time = calculate_end_time(start_time, duration)
|
||||||
|
|
||||||
# 格式化输出文件名
|
# 转换为FFmpeg兼容的时间格式(逗号替换为点)
|
||||||
output_filename = f"vid-{start_time.replace(':', '-')}-{calculated_end_time.replace(':', '-')}.mp4"
|
ffmpeg_start_time = start_time.replace(',', '.')
|
||||||
|
ffmpeg_end_time = calculated_end_time.replace(',', '.')
|
||||||
|
|
||||||
|
# 格式化输出文件名(使用连字符替代冒号和逗号)
|
||||||
|
safe_start_time = start_time.replace(':', '-').replace(',', '-')
|
||||||
|
safe_end_time = calculated_end_time.replace(':', '-').replace(',', '-')
|
||||||
|
output_filename = f"vid_{safe_start_time}@{safe_end_time}.mp4"
|
||||||
output_path = os.path.join(output_dir, output_filename)
|
output_path = os.path.join(output_dir, output_filename)
|
||||||
|
|
||||||
# 构建FFmpeg命令
|
# 构建FFmpeg命令
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg", "-y", *hwaccel_args,
|
"ffmpeg", "-y", *hwaccel_args,
|
||||||
"-i", video_origin_path,
|
"-i", video_origin_path,
|
||||||
"-ss", start_time,
|
"-ss", ffmpeg_start_time,
|
||||||
"-to", calculated_end_time,
|
"-to", ffmpeg_end_time,
|
||||||
"-c:v", "h264_videotoolbox" if hwaccel == "videotoolbox" else "libx264",
|
"-c:v", "h264_videotoolbox" if hwaccel == "videotoolbox" else "libx264",
|
||||||
"-c:a", "aac",
|
"-c:a", "aac",
|
||||||
"-strict", "experimental",
|
"-strict", "experimental",
|
||||||
@ -170,7 +195,7 @@ def clip_video(
|
|||||||
|
|
||||||
# 执行FFmpeg命令
|
# 执行FFmpeg命令
|
||||||
try:
|
try:
|
||||||
logger.info(f"裁剪视频片段: {timestamp} -> {start_time}到{calculated_end_time}")
|
logger.info(f"裁剪视频片段: {timestamp} -> {ffmpeg_start_time}到{ffmpeg_end_time}")
|
||||||
# logger.debug(f"执行命令: {' '.join(ffmpeg_cmd)}")
|
# logger.debug(f"执行命令: {' '.join(ffmpeg_cmd)}")
|
||||||
|
|
||||||
process = subprocess.run(
|
process = subprocess.run(
|
||||||
|
|||||||
@ -377,20 +377,18 @@ def validate_params(video_path, audio_path, output_file, params):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
task_id = "qyn2-2-demo"
|
task_id = "demo"
|
||||||
|
|
||||||
# 提前裁剪是为了方便检查视频
|
# 提前裁剪是为了方便检查视频
|
||||||
subclip_path_videos = {
|
subclip_path_videos = {
|
||||||
1: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/6e7e343c7592c7d6f9a9636b55000f23/vid-00-00-00-00-01-15.mp4',
|
1: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/588c37cba4e2e62714c24c4c9054fc51/vid-00-00-00_000-00-00-27_000.mp4',
|
||||||
2: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/6e7e343c7592c7d6f9a9636b55000f23/vid-00-01-15-00-04-40.mp4',
|
2: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/588c37cba4e2e62714c24c4c9054fc51/vid-00-00-30_000-00-00-57_000.mp4',
|
||||||
3: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/6e7e343c7592c7d6f9a9636b55000f23/vid-00-04-41-00-04-58.mp4',
|
3: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/588c37cba4e2e62714c24c4c9054fc51/vid-00-01-00_000-00-01-27_000.mp4',
|
||||||
4: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/6e7e343c7592c7d6f9a9636b55000f23/vid-00-04-58-00-05-45.mp4',
|
4: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/588c37cba4e2e62714c24c4c9054fc51/vid-00-01-30_000-00-01-57_000.mp4',
|
||||||
5: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/6e7e343c7592c7d6f9a9636b55000f23/vid-00-05-45-00-06-00.mp4',
|
|
||||||
6: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/6e7e343c7592c7d6f9a9636b55000f23/vid-00-06-00-00-06-03.mp4',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
params = VideoClipParams(
|
params = VideoClipParams(
|
||||||
video_clip_json_path="/Users/apple/Desktop/home/NarratoAI/resource/scripts/demo.json",
|
video_clip_json_path="/Users/apple/Desktop/home/NarratoAI/resource/scripts/2025-0507-185159.json",
|
||||||
video_origin_path="/Users/apple/Desktop/home/NarratoAI/resource/videos/qyn2-2无片头片尾.mp4",
|
video_origin_path="/Users/apple/Desktop/home/NarratoAI/resource/videos/test.mp4",
|
||||||
)
|
)
|
||||||
start_subclip(task_id, params, subclip_path_videos)
|
start_subclip(task_id, params, subclip_path_videos)
|
||||||
|
|||||||
@ -21,16 +21,25 @@ def extract_timestamp_from_video_path(video_path: str) -> str:
|
|||||||
video_path: 视频文件路径
|
video_path: 视频文件路径
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
提取出的时间戳,格式为 'HH:MM:SS-HH:MM:SS'
|
提取出的时间戳,格式为 'HH:MM:SS-HH:MM:SS' 或 'HH:MM:SS,sss-HH:MM:SS,sss'
|
||||||
"""
|
"""
|
||||||
# 使用正则表达式从文件名中提取时间戳
|
# 使用正则表达式从文件名中提取时间戳
|
||||||
filename = os.path.basename(video_path)
|
filename = os.path.basename(video_path)
|
||||||
match = re.search(r'vid-(\d{2}-\d{2}-\d{2})-(\d{2}-\d{2}-\d{2})\.mp4', filename)
|
|
||||||
|
|
||||||
if match:
|
# 匹配新格式: vid_00-00-00-000@00-00-20-250.mp4
|
||||||
|
match_new = re.search(r'vid_(\d{2})-(\d{2})-(\d{2})-(\d{3})@(\d{2})-(\d{2})-(\d{2})-(\d{3})\.mp4', filename)
|
||||||
|
if match_new:
|
||||||
|
# 提取并格式化时间戳(包含毫秒)
|
||||||
|
start_h, start_m, start_s, start_ms = match_new.group(1), match_new.group(2), match_new.group(3), match_new.group(4)
|
||||||
|
end_h, end_m, end_s, end_ms = match_new.group(5), match_new.group(6), match_new.group(7), match_new.group(8)
|
||||||
|
return f"{start_h}:{start_m}:{start_s},{start_ms}-{end_h}:{end_m}:{end_s},{end_ms}"
|
||||||
|
|
||||||
|
# 匹配旧格式: vid-00-00-00-00-00-00.mp4
|
||||||
|
match_old = re.search(r'vid-(\d{2}-\d{2}-\d{2})-(\d{2}-\d{2}-\d{2})\.mp4', filename)
|
||||||
|
if match_old:
|
||||||
# 提取并格式化时间戳
|
# 提取并格式化时间戳
|
||||||
start_time = match.group(1).replace('-', ':')
|
start_time = match_old.group(1).replace('-', ':')
|
||||||
end_time = match.group(2).replace('-', ':')
|
end_time = match_old.group(2).replace('-', ':')
|
||||||
return f"{start_time}-{end_time}"
|
return f"{start_time}-{end_time}"
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
@ -41,7 +50,7 @@ def calculate_duration(timestamp: str) -> float:
|
|||||||
计算时间戳范围的持续时间(秒)
|
计算时间戳范围的持续时间(秒)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
timestamp: 格式为 'HH:MM:SS-HH:MM:SS' 的时间戳
|
timestamp: 格式为 'HH:MM:SS-HH:MM:SS' 或 'HH:MM:SS,sss-HH:MM:SS,sss' 的时间戳
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
持续时间(秒)
|
持续时间(秒)
|
||||||
@ -49,13 +58,28 @@ def calculate_duration(timestamp: str) -> float:
|
|||||||
try:
|
try:
|
||||||
start_time, end_time = timestamp.split('-')
|
start_time, end_time = timestamp.split('-')
|
||||||
|
|
||||||
# 解析时间
|
# 处理毫秒部分
|
||||||
|
if ',' in start_time:
|
||||||
|
start_parts = start_time.split(',')
|
||||||
|
start_time_parts = start_parts[0].split(':')
|
||||||
|
start_ms = float('0.' + start_parts[1]) if len(start_parts) > 1 else 0
|
||||||
|
start_h, start_m, start_s = map(int, start_time_parts)
|
||||||
|
else:
|
||||||
start_h, start_m, start_s = map(int, start_time.split(':'))
|
start_h, start_m, start_s = map(int, start_time.split(':'))
|
||||||
|
start_ms = 0
|
||||||
|
|
||||||
|
if ',' in end_time:
|
||||||
|
end_parts = end_time.split(',')
|
||||||
|
end_time_parts = end_parts[0].split(':')
|
||||||
|
end_ms = float('0.' + end_parts[1]) if len(end_parts) > 1 else 0
|
||||||
|
end_h, end_m, end_s = map(int, end_time_parts)
|
||||||
|
else:
|
||||||
end_h, end_m, end_s = map(int, end_time.split(':'))
|
end_h, end_m, end_s = map(int, end_time.split(':'))
|
||||||
|
end_ms = 0
|
||||||
|
|
||||||
# 转换为秒
|
# 转换为秒
|
||||||
start_seconds = start_h * 3600 + start_m * 60 + start_s
|
start_seconds = start_h * 3600 + start_m * 60 + start_s + start_ms
|
||||||
end_seconds = end_h * 3600 + end_m * 60 + end_s
|
end_seconds = end_h * 3600 + end_m * 60 + end_s + end_ms
|
||||||
|
|
||||||
# 计算时间差(秒)
|
# 计算时间差(秒)
|
||||||
return round(end_seconds - start_seconds, 2)
|
return round(end_seconds - start_seconds, 2)
|
||||||
@ -177,51 +201,51 @@ if __name__ == '__main__':
|
|||||||
list_script = [
|
list_script = [
|
||||||
{
|
{
|
||||||
'picture': '【解说】好的,各位,欢迎回到我的频道!《庆余年 2》刚开播就给了我们一个王炸!范闲在北齐"死"了?这怎么可能!',
|
'picture': '【解说】好的,各位,欢迎回到我的频道!《庆余年 2》刚开播就给了我们一个王炸!范闲在北齐"死"了?这怎么可能!',
|
||||||
'timestamp': '00:00:00-00:01:15',
|
'timestamp': '00:00:00,001-00:01:15,001',
|
||||||
'narration': '好的各位,欢迎回到我的频道!《庆余年 2》刚开播就给了我们一个王炸!范闲在北齐"死"了?这怎么可能!上集片尾那个巨大的悬念,这一集就立刻揭晓了!范闲假死归来,他面临的第一个,也是最大的难关,就是如何面对他最敬爱的,同时也是最可怕的那个人——庆帝!',
|
'narration': '好的各位,欢迎回到我的频道!《庆余年 2》刚开播就给了我们一个王炸!范闲在北齐"死"了?这怎么可能!上集片尾那个巨大的悬念,这一集就立刻揭晓了!范闲假死归来,他面临的第一个,也是最大的难关,就是如何面对他最敬爱的,同时也是最可怕的那个人——庆帝!',
|
||||||
'OST': 0,
|
'OST': 0,
|
||||||
'_id': 1
|
'_id': 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'picture': '【解说】上一集我们看到,范闲在北齐遭遇了惊天变故,生死不明!',
|
'picture': '【解说】上一集我们看到,范闲在北齐遭遇了惊天变故,生死不明!',
|
||||||
'timestamp': '00:01:15-00:04:40',
|
'timestamp': '00:01:15,001-00:04:40,001',
|
||||||
'narration': '但我们都知道,他绝不可能就这么轻易退场!第二集一开场,范闲就已经秘密回到了京都。他的生死传闻,可不像我们想象中那样只是小范围流传,而是…',
|
'narration': '但我们都知道,他绝不可能就这么轻易退场!第二集一开场,范闲就已经秘密回到了京都。他的生死传闻,可不像我们想象中那样只是小范围流传,而是…',
|
||||||
'OST': 0,
|
'OST': 0,
|
||||||
'_id': 2
|
'_id': 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'picture': '画面切到王启年小心翼翼地向范闲汇报。',
|
'picture': '画面切到王启年小心翼翼地向范闲汇报。',
|
||||||
'timestamp': '00:04:41-00:04:58',
|
'timestamp': '00:04:41,001-00:04:58,001',
|
||||||
'narration': '我发现大人的死讯不光是在民间,在官场上也它传开了,所以呢,所以啊,可不是什么好事,将来您跟陛下怎么交代,这可是欺君之罪',
|
'narration': '我发现大人的死讯不光是在民间,在官场上也它传开了,所以呢,所以啊,可不是什么好事,将来您跟陛下怎么交代,这可是欺君之罪',
|
||||||
'OST': 1,
|
'OST': 1,
|
||||||
'_id': 3
|
'_id': 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'picture': '【解说】"欺君之罪"!在封建王朝,这可是抄家灭族的大罪!搁一般人,肯定脚底抹油溜之大吉了。',
|
'picture': '【解说】"欺君之罪"!在封建王朝,这可是抄家灭族的大罪!搁一般人,肯定脚底抹油溜之大吉了。',
|
||||||
'timestamp': '00:04:58-00:05:45',
|
'timestamp': '00:04:58,001-00:05:45,001',
|
||||||
'narration': '"欺君之罪"!在封建王朝,这可是抄家灭族的大罪!搁一般人,肯定脚底抹油溜之大吉了。但范闲是谁啊?他偏要反其道而行之!他竟然决定,直接去见庆帝!冒着天大的风险,用"假死"这个事实去赌庆帝的态度!',
|
'narration': '"欺君之罪"!在封建王朝,这可是抄家灭族的大罪!搁一般人,肯定脚底抹油溜之大吉了。但范闲是谁啊?他偏要反其道而行之!他竟然决定,直接去见庆帝!冒着天大的风险,用"假死"这个事实去赌庆帝的态度!',
|
||||||
'OST': 0,
|
'OST': 0,
|
||||||
'_id': 4
|
'_id': 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'picture': '【解说】但想见庆帝,哪有那么容易?范闲艺高人胆大,竟然选择了最激进的方式——闯宫!',
|
'picture': '【解说】但想见庆帝,哪有那么容易?范闲艺高人胆大,竟然选择了最激进的方式——闯宫!',
|
||||||
'timestamp': '00:05:45-00:06:00',
|
'timestamp': '00:05:45,001-00:06:00,001',
|
||||||
'narration': '但想见庆帝,哪有那么容易?范闲艺高人胆大,竟然选择了最激进的方式——闯宫!',
|
'narration': '但想见庆帝,哪有那么容易?范闲艺高人胆大,竟然选择了最激进的方式——闯宫!',
|
||||||
'OST': 0,
|
'OST': 0,
|
||||||
'_id': 5
|
'_id': 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'picture': '画面切换到范闲蒙面闯入皇宫,被侍卫包围的场景。',
|
'picture': '画面切换到范闲蒙面闯入皇宫,被侍卫包围的场景。',
|
||||||
'timestamp': '00:06:00-00:06:03',
|
'timestamp': '00:06:00,001-00:06:03,001',
|
||||||
'narration': '抓刺客',
|
'narration': '抓刺客',
|
||||||
'OST': 1,
|
'OST': 1,
|
||||||
'_id': 6
|
'_id': 6
|
||||||
}]
|
}]
|
||||||
video_res = {
|
video_res = {
|
||||||
1: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/2c0c2ae91b4f58596634a0b2f64d3eb0/vid-00-00-00-00-00-26.mp4',
|
1: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/fc3db5844d1ba7d7d838be52c0dac1bd/vid_00-00-00-000@00-00-20-250.mp4',
|
||||||
2: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/2c0c2ae91b4f58596634a0b2f64d3eb0/vid-00-01-15-00-01-29.mp4',
|
2: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/fc3db5844d1ba7d7d838be52c0dac1bd/vid_00-00-30-000@00-00-48-950.mp4',
|
||||||
4: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/2c0c2ae91b4f58596634a0b2f64d3eb0/vid-00-04-58-00-05-20.mp4',
|
4: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/fc3db5844d1ba7d7d838be52c0dac1bd/vid_00-01-00-000@00-01-15-688.mp4',
|
||||||
5: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/2c0c2ae91b4f58596634a0b2f64d3eb0/vid-00-05-45-00-05-53.mp4'}
|
5: '/Users/apple/Desktop/home/NarratoAI/storage/temp/clip_video/fc3db5844d1ba7d7d838be52c0dac1bd/vid_00-01-30-000@00-01-49-512.mp4'}
|
||||||
audio_res = {
|
audio_res = {
|
||||||
1: '/Users/apple/Desktop/home/NarratoAI/storage/tasks/qyn2-2-demo/audio_00_00_00-00_01_15.mp3',
|
1: '/Users/apple/Desktop/home/NarratoAI/storage/tasks/qyn2-2-demo/audio_00_00_00-00_01_15.mp3',
|
||||||
2: '/Users/apple/Desktop/home/NarratoAI/storage/tasks/qyn2-2-demo/audio_00_01_15-00_04_40.mp3',
|
2: '/Users/apple/Desktop/home/NarratoAI/storage/tasks/qyn2-2-demo/audio_00_01_15-00_04_40.mp3',
|
||||||
|
|||||||
@ -6,6 +6,7 @@ streamlit~=1.45.0
|
|||||||
watchdog==6.0.0
|
watchdog==6.0.0
|
||||||
loguru~=0.7.3
|
loguru~=0.7.3
|
||||||
tomli~=2.2.1
|
tomli~=2.2.1
|
||||||
|
pydub==0.25.1
|
||||||
|
|
||||||
openai~=1.77.0
|
openai~=1.77.0
|
||||||
google-generativeai>=0.8.5
|
google-generativeai>=0.8.5
|
||||||
|
|||||||
6
webui.py
6
webui.py
@ -120,9 +120,7 @@ def tr(key):
|
|||||||
def render_generate_button():
|
def render_generate_button():
|
||||||
"""渲染生成按钮和处理逻辑"""
|
"""渲染生成按钮和处理逻辑"""
|
||||||
if st.button(tr("Generate Video"), use_container_width=True, type="primary"):
|
if st.button(tr("Generate Video"), use_container_width=True, type="primary"):
|
||||||
try:
|
|
||||||
from app.services import task as tm
|
from app.services import task as tm
|
||||||
import torch
|
|
||||||
|
|
||||||
# 重置日志容器和记录
|
# 重置日志容器和记录
|
||||||
log_container = st.empty()
|
log_container = st.empty()
|
||||||
@ -189,8 +187,8 @@ def render_generate_button():
|
|||||||
file_utils.open_task_folder(config.root_dir, task_id)
|
file_utils.open_task_folder(config.root_dir, task_id)
|
||||||
logger.info(tr("视频生成完成"))
|
logger.info(tr("视频生成完成"))
|
||||||
|
|
||||||
finally:
|
# finally:
|
||||||
PerformanceMonitor.cleanup_resources()
|
# PerformanceMonitor.cleanup_resources()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user