mirror of
https://github.com/linyqh/NarratoAI.git
synced 2025-12-12 19:34:19 +00:00
build: 更新依赖并重构部分代码
- 更新 moviepy 依赖版本 - 添加 edge-tts、streamlit 等新依赖 - 移除 g4f、dashscope 等未使用的依赖- 重构 merge_video.py 中的导入语句 - 注释掉 task.py 中的多个函数定义
This commit is contained in:
parent
3d9b4b6d93
commit
c3ea0bcc69
@ -15,147 +15,147 @@ from app.services import state as sm
|
|||||||
from app.utils import utils
|
from app.utils import utils
|
||||||
|
|
||||||
|
|
||||||
def generate_script(task_id, params):
|
# def generate_script(task_id, params):
|
||||||
logger.info("\n\n## generating video script")
|
# logger.info("\n\n## generating video script")
|
||||||
video_script = params.video_script.strip()
|
# video_script = params.video_script.strip()
|
||||||
if not video_script:
|
# if not video_script:
|
||||||
video_script = llm.generate_script(
|
# video_script = llm.generate_script(
|
||||||
video_subject=params.video_subject,
|
# video_subject=params.video_subject,
|
||||||
language=params.video_language,
|
# language=params.video_language,
|
||||||
paragraph_number=params.paragraph_number,
|
# paragraph_number=params.paragraph_number,
|
||||||
)
|
# )
|
||||||
else:
|
# else:
|
||||||
logger.debug(f"video script: \n{video_script}")
|
# logger.debug(f"video script: \n{video_script}")
|
||||||
|
|
||||||
if not video_script:
|
# if not video_script:
|
||||||
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
# sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
logger.error("failed to generate video script.")
|
# logger.error("failed to generate video script.")
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
return video_script
|
# return video_script
|
||||||
|
|
||||||
|
|
||||||
def generate_terms(task_id, params, video_script):
|
# def generate_terms(task_id, params, video_script):
|
||||||
logger.info("\n\n## generating video terms")
|
# logger.info("\n\n## generating video terms")
|
||||||
video_terms = params.video_terms
|
# video_terms = params.video_terms
|
||||||
if not video_terms:
|
# if not video_terms:
|
||||||
video_terms = llm.generate_terms(
|
# video_terms = llm.generate_terms(
|
||||||
video_subject=params.video_subject, video_script=video_script, amount=5
|
# video_subject=params.video_subject, video_script=video_script, amount=5
|
||||||
)
|
# )
|
||||||
else:
|
# else:
|
||||||
if isinstance(video_terms, str):
|
# if isinstance(video_terms, str):
|
||||||
video_terms = [term.strip() for term in re.split(r"[,,]", video_terms)]
|
# video_terms = [term.strip() for term in re.split(r"[,,]", video_terms)]
|
||||||
elif isinstance(video_terms, list):
|
# elif isinstance(video_terms, list):
|
||||||
video_terms = [term.strip() for term in video_terms]
|
# video_terms = [term.strip() for term in video_terms]
|
||||||
else:
|
# else:
|
||||||
raise ValueError("video_terms must be a string or a list of strings.")
|
# raise ValueError("video_terms must be a string or a list of strings.")
|
||||||
|
|
||||||
logger.debug(f"video terms: {utils.to_json(video_terms)}")
|
# logger.debug(f"video terms: {utils.to_json(video_terms)}")
|
||||||
|
|
||||||
if not video_terms:
|
# if not video_terms:
|
||||||
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
# sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
logger.error("failed to generate video terms.")
|
# logger.error("failed to generate video terms.")
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
return video_terms
|
# return video_terms
|
||||||
|
|
||||||
|
|
||||||
def save_script_data(task_id, video_script, video_terms, params):
|
# def save_script_data(task_id, video_script, video_terms, params):
|
||||||
script_file = path.join(utils.task_dir(task_id), "script.json")
|
# script_file = path.join(utils.task_dir(task_id), "script.json")
|
||||||
script_data = {
|
# script_data = {
|
||||||
"script": video_script,
|
# "script": video_script,
|
||||||
"search_terms": video_terms,
|
# "search_terms": video_terms,
|
||||||
"params": params,
|
# "params": params,
|
||||||
}
|
# }
|
||||||
|
|
||||||
with open(script_file, "w", encoding="utf-8") as f:
|
# with open(script_file, "w", encoding="utf-8") as f:
|
||||||
f.write(utils.to_json(script_data))
|
# f.write(utils.to_json(script_data))
|
||||||
|
|
||||||
|
|
||||||
def generate_audio(task_id, params, video_script):
|
# def generate_audio(task_id, params, video_script):
|
||||||
logger.info("\n\n## generating audio")
|
# logger.info("\n\n## generating audio")
|
||||||
audio_file = path.join(utils.task_dir(task_id), "audio.mp3")
|
# audio_file = path.join(utils.task_dir(task_id), "audio.mp3")
|
||||||
sub_maker = voice.tts(
|
# sub_maker = voice.tts(
|
||||||
text=video_script,
|
# text=video_script,
|
||||||
voice_name=voice.parse_voice_name(params.voice_name),
|
# voice_name=voice.parse_voice_name(params.voice_name),
|
||||||
voice_rate=params.voice_rate,
|
# voice_rate=params.voice_rate,
|
||||||
voice_file=audio_file,
|
# voice_file=audio_file,
|
||||||
)
|
# )
|
||||||
if sub_maker is None:
|
# if sub_maker is None:
|
||||||
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
# sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
logger.error(
|
# logger.error(
|
||||||
"""failed to generate audio:
|
# """failed to generate audio:
|
||||||
1. check if the language of the voice matches the language of the video script.
|
# 1. check if the language of the voice matches the language of the video script.
|
||||||
2. check if the network is available. If you are in China, it is recommended to use a VPN and enable the global traffic mode.
|
# 2. check if the network is available. If you are in China, it is recommended to use a VPN and enable the global traffic mode.
|
||||||
""".strip()
|
# """.strip()
|
||||||
)
|
# )
|
||||||
return None, None, None
|
# return None, None, None
|
||||||
|
|
||||||
audio_duration = math.ceil(voice.get_audio_duration(sub_maker))
|
# audio_duration = math.ceil(voice.get_audio_duration(sub_maker))
|
||||||
return audio_file, audio_duration, sub_maker
|
# return audio_file, audio_duration, sub_maker
|
||||||
|
|
||||||
|
|
||||||
def generate_subtitle(task_id, params, video_script, sub_maker, audio_file):
|
# def generate_subtitle(task_id, params, video_script, sub_maker, audio_file):
|
||||||
if not params.subtitle_enabled:
|
# if not params.subtitle_enabled:
|
||||||
return ""
|
# return ""
|
||||||
|
|
||||||
subtitle_path = path.join(utils.task_dir(task_id), "subtitle111.srt")
|
# subtitle_path = path.join(utils.task_dir(task_id), "subtitle111.srt")
|
||||||
subtitle_provider = config.app.get("subtitle_provider", "").strip().lower()
|
# subtitle_provider = config.app.get("subtitle_provider", "").strip().lower()
|
||||||
logger.info(f"\n\n## generating subtitle, provider: {subtitle_provider}")
|
# logger.info(f"\n\n## generating subtitle, provider: {subtitle_provider}")
|
||||||
|
|
||||||
subtitle_fallback = False
|
# subtitle_fallback = False
|
||||||
if subtitle_provider == "edge":
|
# if subtitle_provider == "edge":
|
||||||
voice.create_subtitle(
|
# voice.create_subtitle(
|
||||||
text=video_script, sub_maker=sub_maker, subtitle_file=subtitle_path
|
# text=video_script, sub_maker=sub_maker, subtitle_file=subtitle_path
|
||||||
)
|
# )
|
||||||
if not os.path.exists(subtitle_path):
|
# if not os.path.exists(subtitle_path):
|
||||||
subtitle_fallback = True
|
# subtitle_fallback = True
|
||||||
logger.warning("subtitle file not found, fallback to whisper")
|
# logger.warning("subtitle file not found, fallback to whisper")
|
||||||
|
|
||||||
if subtitle_provider == "whisper" or subtitle_fallback:
|
# if subtitle_provider == "whisper" or subtitle_fallback:
|
||||||
subtitle.create(audio_file=audio_file, subtitle_file=subtitle_path)
|
# subtitle.create(audio_file=audio_file, subtitle_file=subtitle_path)
|
||||||
logger.info("\n\n## correcting subtitle")
|
# logger.info("\n\n## correcting subtitle")
|
||||||
subtitle.correct(subtitle_file=subtitle_path, video_script=video_script)
|
# subtitle.correct(subtitle_file=subtitle_path, video_script=video_script)
|
||||||
|
|
||||||
subtitle_lines = subtitle.file_to_subtitles(subtitle_path)
|
# subtitle_lines = subtitle.file_to_subtitles(subtitle_path)
|
||||||
if not subtitle_lines:
|
# if not subtitle_lines:
|
||||||
logger.warning(f"subtitle file is invalid: {subtitle_path}")
|
# logger.warning(f"subtitle file is invalid: {subtitle_path}")
|
||||||
return ""
|
# return ""
|
||||||
|
|
||||||
return subtitle_path
|
# return subtitle_path
|
||||||
|
|
||||||
|
|
||||||
def get_video_materials(task_id, params, video_terms, audio_duration):
|
# def get_video_materials(task_id, params, video_terms, audio_duration):
|
||||||
if params.video_source == "local":
|
# if params.video_source == "local":
|
||||||
logger.info("\n\n## preprocess local materials")
|
# logger.info("\n\n## preprocess local materials")
|
||||||
materials = video.preprocess_video(
|
# materials = video.preprocess_video(
|
||||||
materials=params.video_materials, clip_duration=params.video_clip_duration
|
# materials=params.video_materials, clip_duration=params.video_clip_duration
|
||||||
)
|
# )
|
||||||
if not materials:
|
# if not materials:
|
||||||
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
# sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
logger.error(
|
# logger.error(
|
||||||
"no valid materials found, please check the materials and try again."
|
# "no valid materials found, please check the materials and try again."
|
||||||
)
|
# )
|
||||||
return None
|
# return None
|
||||||
return [material_info.url for material_info in materials]
|
# return [material_info.url for material_info in materials]
|
||||||
else:
|
# else:
|
||||||
logger.info(f"\n\n## downloading videos from {params.video_source}")
|
# logger.info(f"\n\n## downloading videos from {params.video_source}")
|
||||||
downloaded_videos = material.download_videos(
|
# downloaded_videos = material.download_videos(
|
||||||
task_id=task_id,
|
# task_id=task_id,
|
||||||
search_terms=video_terms,
|
# search_terms=video_terms,
|
||||||
source=params.video_source,
|
# source=params.video_source,
|
||||||
video_aspect=params.video_aspect,
|
# video_aspect=params.video_aspect,
|
||||||
video_contact_mode=params.video_concat_mode,
|
# video_contact_mode=params.video_concat_mode,
|
||||||
audio_duration=audio_duration * params.video_count,
|
# audio_duration=audio_duration * params.video_count,
|
||||||
max_clip_duration=params.video_clip_duration,
|
# max_clip_duration=params.video_clip_duration,
|
||||||
)
|
# )
|
||||||
if not downloaded_videos:
|
# if not downloaded_videos:
|
||||||
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
# sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
logger.error(
|
# logger.error(
|
||||||
"failed to download videos, maybe the network is not available. if you are in China, please use a VPN."
|
# "failed to download videos, maybe the network is not available. if you are in China, please use a VPN."
|
||||||
)
|
# )
|
||||||
return None
|
# return None
|
||||||
return downloaded_videos
|
# return downloaded_videos
|
||||||
|
|
||||||
|
|
||||||
def start_subclip(task_id: str, params: VideoClipParams, subclip_path_videos: dict):
|
def start_subclip(task_id: str, params: VideoClipParams, subclip_path_videos: dict):
|
||||||
|
|||||||
@ -1,38 +1,38 @@
|
|||||||
requests~=2.31.0
|
requests~=2.32.0
|
||||||
moviepy==2.1.1
|
moviepy==2.1.1
|
||||||
faster-whisper~=1.0.1
|
edge-tts==6.1.19
|
||||||
uvicorn~=0.27.1
|
streamlit~=1.45.0
|
||||||
fastapi~=0.115.4
|
|
||||||
tomli~=2.0.1
|
openai~=1.77.0
|
||||||
streamlit~=1.40.0
|
google-generativeai>=0.8.5
|
||||||
|
|
||||||
loguru~=0.7.2
|
loguru~=0.7.2
|
||||||
|
fastapi~=0.115.4
|
||||||
|
uvicorn~=0.27.1
|
||||||
|
pydantic~=2.11.4
|
||||||
|
|
||||||
|
faster-whisper~=1.0.1
|
||||||
|
tomli~=2.0.1
|
||||||
aiohttp~=3.10.10
|
aiohttp~=3.10.10
|
||||||
|
httpx==0.27.2
|
||||||
urllib3~=2.2.1
|
urllib3~=2.2.1
|
||||||
pydantic~=2.6.3
|
|
||||||
g4f~=0.3.0.4
|
|
||||||
dashscope~=1.15.0
|
|
||||||
google.generativeai>=0.8.3
|
|
||||||
python-multipart~=0.0.9
|
python-multipart~=0.0.9
|
||||||
redis==5.0.3
|
redis==5.0.3
|
||||||
opencv-python~=4.10.0.84
|
opencv-python~=4.10.0.84
|
||||||
# for azure speech
|
|
||||||
# https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/9-more-realistic-ai-voices-for-conversations-now-generally/ba-p/4099471
|
|
||||||
azure-cognitiveservices-speech~=1.37.0
|
azure-cognitiveservices-speech~=1.37.0
|
||||||
git-changelog~=2.5.2
|
git-changelog~=2.5.2
|
||||||
watchdog==5.0.2
|
watchdog==5.0.2
|
||||||
pydub==0.25.1
|
pydub==0.25.1
|
||||||
psutil>=5.9.0
|
psutil>=5.9.0
|
||||||
opencv-python~=4.10.0.84
|
|
||||||
scikit-learn~=1.5.2
|
scikit-learn~=1.5.2
|
||||||
google-generativeai~=0.8.3
|
|
||||||
pillow==10.3.0
|
pillow==10.3.0
|
||||||
python-dotenv~=1.0.1
|
python-dotenv~=1.0.1
|
||||||
openai~=1.53.0
|
|
||||||
tqdm>=4.66.6
|
tqdm>=4.66.6
|
||||||
tenacity>=9.0.0
|
tenacity>=9.0.0
|
||||||
tiktoken==0.8.0
|
tiktoken==0.8.0
|
||||||
yt-dlp==2024.11.18
|
|
||||||
pysrt==1.1.2
|
pysrt==1.1.2
|
||||||
httpx==0.27.2
|
transformers==4.50.0
|
||||||
transformers==4.47.0
|
|
||||||
edge-tts==6.1.19
|
# yt-dlp==2025.4.30
|
||||||
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
合并视频和字幕文件
|
合并视频和字幕文件
|
||||||
"""
|
"""
|
||||||
from moviepy.editor import VideoFileClip, concatenate_videoclips
|
from moviepy import VideoFileClip, concatenate_videoclips
|
||||||
import pysrt
|
import pysrt
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user