Merge pull request #541 from yyhhyyyyyy/update-requirements

⬆️ deps: Upgrade dependencies to latest versions and address minor issues
This commit is contained in:
Harry
2024-12-05 11:02:14 +08:00
committed by GitHub
11 changed files with 92 additions and 66 deletions

View File

@@ -1,5 +1,5 @@
# Use an official Python runtime as a parent image # Use an official Python runtime as a parent image
FROM python:3.10-slim-bullseye FROM python:3.11-slim-bullseye
# Set the working directory in the container # Set the working directory in the container
WORKDIR /MoneyPrinterTurbo WORKDIR /MoneyPrinterTurbo

View File

@@ -172,7 +172,7 @@ using [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index
```shell ```shell
git clone https://github.com/harry0703/MoneyPrinterTurbo.git git clone https://github.com/harry0703/MoneyPrinterTurbo.git
cd MoneyPrinterTurbo cd MoneyPrinterTurbo
conda create -n MoneyPrinterTurbo python=3.10 conda create -n MoneyPrinterTurbo python=3.11
conda activate MoneyPrinterTurbo conda activate MoneyPrinterTurbo
pip install -r requirements.txt pip install -r requirements.txt
``` ```

View File

@@ -193,7 +193,7 @@ docker-compose up
```shell ```shell
git clone https://github.com/harry0703/MoneyPrinterTurbo.git git clone https://github.com/harry0703/MoneyPrinterTurbo.git
cd MoneyPrinterTurbo cd MoneyPrinterTurbo
conda create -n MoneyPrinterTurbo python=3.10 conda create -n MoneyPrinterTurbo python=3.11
conda activate MoneyPrinterTurbo conda activate MoneyPrinterTurbo
pip install -r requirements.txt pip install -r requirements.txt
``` ```

View File

@@ -1,6 +1,6 @@
import warnings import warnings
from enum import Enum from enum import Enum
from typing import Any, List, Optional from typing import Any, List, Optional, Union
import pydantic import pydantic
from pydantic import BaseModel from pydantic import BaseModel
@@ -122,7 +122,7 @@ class VideoParams(BaseModel):
custom_position: float = 70.0 custom_position: float = 70.0
font_name: Optional[str] = "STHeitiMedium.ttc" font_name: Optional[str] = "STHeitiMedium.ttc"
text_fore_color: Optional[str] = "#FFFFFF" text_fore_color: Optional[str] = "#FFFFFF"
text_background_color: Optional[str] = "transparent" text_background_color: Union[bool, str] = True
font_size: int = 60 font_size: int = 60
stroke_color: Optional[str] = "#000000" stroke_color: Optional[str] = "#000000"
@@ -143,7 +143,7 @@ class SubtitleRequest(BaseModel):
subtitle_position: Optional[str] = "bottom" subtitle_position: Optional[str] = "bottom"
font_name: Optional[str] = "STHeitiMedium.ttc" font_name: Optional[str] = "STHeitiMedium.ttc"
text_fore_color: Optional[str] = "#FFFFFF" text_fore_color: Optional[str] = "#FFFFFF"
text_background_color: Optional[str] = "transparent" text_background_color: Union[bool, str] = True
font_size: int = 60 font_size: int = 60
stroke_color: Optional[str] = "#000000" stroke_color: Optional[str] = "#000000"
stroke_width: float = 1.5 stroke_width: float = 1.5

View File

@@ -1,9 +1,10 @@
import glob import glob
import os
import random import random
from typing import List from typing import List
from loguru import logger from loguru import logger
from moviepy.editor import * from moviepy import *
from moviepy.video.tools.subtitles import SubtitlesClip from moviepy.video.tools.subtitles import SubtitlesClip
from PIL import ImageFont from PIL import ImageFont
@@ -60,7 +61,7 @@ def combine_videos(
while start_time < clip_duration: while start_time < clip_duration:
end_time = min(start_time + max_clip_duration, clip_duration) end_time = min(start_time + max_clip_duration, clip_duration)
split_clip = clip.subclip(start_time, end_time) split_clip = clip.subclipped(start_time, end_time)
raw_clips.append(split_clip) raw_clips.append(split_clip)
# logger.info(f"splitting from {start_time:.2f} to {end_time:.2f}, clip duration {clip_duration:.2f}, split_clip duration {split_clip.duration:.2f}") # logger.info(f"splitting from {start_time:.2f} to {end_time:.2f}, clip duration {clip_duration:.2f}, split_clip duration {split_clip.duration:.2f}")
start_time = end_time start_time = end_time
@@ -76,11 +77,11 @@ def combine_videos(
for clip in raw_clips: for clip in raw_clips:
# Check if clip is longer than the remaining audio # Check if clip is longer than the remaining audio
if (audio_duration - video_duration) < clip.duration: if (audio_duration - video_duration) < clip.duration:
clip = clip.subclip(0, (audio_duration - video_duration)) clip = clip.subclipped(0, (audio_duration - video_duration))
# Only shorten clips if the calculated clip length (req_dur) is shorter than the actual clip to prevent still image # Only shorten clips if the calculated clip length (req_dur) is shorter than the actual clip to prevent still image
elif req_dur < clip.duration: elif req_dur < clip.duration:
clip = clip.subclip(0, req_dur) clip = clip.subclipped(0, req_dur)
clip = clip.set_fps(30) clip = clip.with_fps(30)
# Not all videos are same size, so we need to resize them # Not all videos are same size, so we need to resize them
clip_w, clip_h = clip.size clip_w, clip_h = clip.size
@@ -90,7 +91,7 @@ def combine_videos(
if clip_ratio == video_ratio: if clip_ratio == video_ratio:
# 等比例缩放 # 等比例缩放
clip = clip.resize((video_width, video_height)) clip = clip.resized((video_width, video_height))
else: else:
# 等比缩放视频 # 等比缩放视频
if clip_ratio > video_ratio: if clip_ratio > video_ratio:
@@ -102,15 +103,15 @@ def combine_videos(
new_width = int(clip_w * scale_factor) new_width = int(clip_w * scale_factor)
new_height = int(clip_h * scale_factor) new_height = int(clip_h * scale_factor)
clip_resized = clip.resize(newsize=(new_width, new_height)) clip_resized = clip.resized(new_size=(new_width, new_height))
background = ColorClip( background = ColorClip(
size=(video_width, video_height), color=(0, 0, 0) size=(video_width, video_height), color=(0, 0, 0)
) )
clip = CompositeVideoClip( clip = CompositeVideoClip(
[ [
background.set_duration(clip.duration), background.with_duration(clip.duration),
clip_resized.set_position("center"), clip_resized.with_position("center"),
] ]
) )
@@ -119,13 +120,13 @@ def combine_videos(
) )
if clip.duration > max_clip_duration: if clip.duration > max_clip_duration:
clip = clip.subclip(0, max_clip_duration) clip = clip.subclipped(0, max_clip_duration)
clips.append(clip) clips.append(clip)
video_duration += clip.duration video_duration += clip.duration
video_clip = concatenate_videoclips(clips) video_clip = concatenate_videoclips(clips)
video_clip = video_clip.set_fps(30) video_clip = video_clip.with_fps(30)
logger.info("writing") logger.info("writing")
# https://github.com/harry0703/MoneyPrinterTurbo/issues/111#issuecomment-2032354030 # https://github.com/harry0703/MoneyPrinterTurbo/issues/111#issuecomment-2032354030
video_clip.write_videofile( video_clip.write_videofile(
@@ -231,29 +232,30 @@ def generate_video(
logger.info(f"using font: {font_path}") logger.info(f"using font: {font_path}")
def create_text_clip(subtitle_item): def create_text_clip(subtitle_item):
params.font_size = int(params.font_size)
params.stroke_width = int(params.stroke_width)
phrase = subtitle_item[1] phrase = subtitle_item[1]
max_width = video_width * 0.9 max_width = video_width * 0.9
wrapped_txt, txt_height = wrap_text( wrapped_txt, txt_height = wrap_text(
phrase, max_width=max_width, font=font_path, fontsize=params.font_size phrase, max_width=max_width, font=font_path, fontsize=params.font_size
) )
_clip = TextClip( _clip = TextClip(
wrapped_txt, text=wrapped_txt,
font=font_path, font=font_path,
fontsize=params.font_size, font_size=params.font_size,
color=params.text_fore_color, color=params.text_fore_color,
bg_color=params.text_background_color, bg_color=params.text_background_color,
stroke_color=params.stroke_color, stroke_color=params.stroke_color,
stroke_width=params.stroke_width, stroke_width=params.stroke_width,
print_cmd=False,
) )
duration = subtitle_item[0][1] - subtitle_item[0][0] duration = subtitle_item[0][1] - subtitle_item[0][0]
_clip = _clip.set_start(subtitle_item[0][0]) _clip = _clip.with_start(subtitle_item[0][0])
_clip = _clip.set_end(subtitle_item[0][1]) _clip = _clip.with_end(subtitle_item[0][1])
_clip = _clip.set_duration(duration) _clip = _clip.with_duration(duration)
if params.subtitle_position == "bottom": if params.subtitle_position == "bottom":
_clip = _clip.set_position(("center", video_height * 0.95 - _clip.h)) _clip = _clip.with_position(("center", video_height * 0.95 - _clip.h))
elif params.subtitle_position == "top": elif params.subtitle_position == "top":
_clip = _clip.set_position(("center", video_height * 0.05)) _clip = _clip.with_position(("center", video_height * 0.05))
elif params.subtitle_position == "custom": elif params.subtitle_position == "custom":
# 确保字幕完全在屏幕内 # 确保字幕完全在屏幕内
margin = 10 # 额外的边距,单位为像素 margin = 10 # 额外的边距,单位为像素
@@ -261,16 +263,25 @@ def generate_video(
min_y = margin min_y = margin
custom_y = (video_height - _clip.h) * (params.custom_position / 100) custom_y = (video_height - _clip.h) * (params.custom_position / 100)
custom_y = max(min_y, min(custom_y, max_y)) # 限制 y 值在有效范围内 custom_y = max(min_y, min(custom_y, max_y)) # 限制 y 值在有效范围内
_clip = _clip.set_position(("center", custom_y)) _clip = _clip.with_position(("center", custom_y))
else: # center else: # center
_clip = _clip.set_position(("center", "center")) _clip = _clip.with_position(("center", "center"))
return _clip return _clip
video_clip = VideoFileClip(video_path) video_clip = VideoFileClip(video_path)
audio_clip = AudioFileClip(audio_path).volumex(params.voice_volume) audio_clip = AudioFileClip(audio_path).with_effects(
[afx.MultiplyVolume(params.voice_volume)]
)
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") generator = lambda text: TextClip(
text=text,
font=font_path,
font_size=params.font_size,
)
sub = SubtitlesClip(
subtitles=subtitle_path, encoding="utf-8", make_textclip=generator
)
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)
@@ -280,15 +291,18 @@ def generate_video(
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:
bgm_clip = ( bgm_clip = AudioFileClip(bgm_file).with_effects(
AudioFileClip(bgm_file).volumex(params.bgm_volume).audio_fadeout(3) [
afx.MultiplyVolume(params.voice_volume),
afx.AudioFadeOut(3),
afx.AudioLoop(duration=video_clip.duration),
]
) )
bgm_clip = afx.audio_loop(bgm_clip, duration=video_clip.duration)
audio_clip = CompositeAudioClip([audio_clip, bgm_clip]) audio_clip = CompositeAudioClip([audio_clip, bgm_clip])
except Exception as e: except Exception as e:
logger.error(f"failed to add bgm: {str(e)}") logger.error(f"failed to add bgm: {str(e)}")
video_clip = video_clip.set_audio(audio_clip) video_clip = video_clip.with_audio(audio_clip)
video_clip.write_videofile( video_clip.write_videofile(
output_file, output_file,
audio_codec="aac", audio_codec="aac",
@@ -324,14 +338,14 @@ def preprocess_video(materials: List[MaterialInfo], clip_duration=4):
# 创建一个图片剪辑并设置持续时间为3秒钟 # 创建一个图片剪辑并设置持续时间为3秒钟
clip = ( clip = (
ImageClip(material.url) ImageClip(material.url)
.set_duration(clip_duration) .with_duration(clip_duration)
.set_position("center") .with_position("center")
) )
# 使用resize方法来添加缩放效果。这里使用了lambda函数来使得缩放效果随时间变化。 # 使用resize方法来添加缩放效果。这里使用了lambda函数来使得缩放效果随时间变化。
# 假设我们想要从原始大小逐渐放大到120%的大小。 # 假设我们想要从原始大小逐渐放大到120%的大小。
# t代表当前时间clip.duration为视频总时长这里是3秒。 # t代表当前时间clip.duration为视频总时长这里是3秒。
# 注意1 表示100%的大小所以1.2表示120%的大小 # 注意1 表示100%的大小所以1.2表示120%的大小
zoom_clip = clip.resize( zoom_clip = clip.resized(
lambda t: 1 + (clip_duration * 0.03) * (t / clip.duration) lambda t: 1 + (clip_duration * 0.03) * (t / clip.duration)
) )

View File

@@ -302,21 +302,33 @@ Gender: Female
Name: en-US-AnaNeural Name: en-US-AnaNeural
Gender: Female Gender: Female
Name: en-US-AndrewMultilingualNeural
Gender: Male
Name: en-US-AndrewNeural Name: en-US-AndrewNeural
Gender: Male Gender: Male
Name: en-US-AriaNeural Name: en-US-AriaNeural
Gender: Female Gender: Female
Name: en-US-AvaMultilingualNeural
Gender: Female
Name: en-US-AvaNeural Name: en-US-AvaNeural
Gender: Female Gender: Female
Name: en-US-BrianMultilingualNeural
Gender: Male
Name: en-US-BrianNeural Name: en-US-BrianNeural
Gender: Male Gender: Male
Name: en-US-ChristopherNeural Name: en-US-ChristopherNeural
Gender: Male Gender: Male
Name: en-US-EmmaMultilingualNeural
Gender: Female
Name: en-US-EmmaNeural Name: en-US-EmmaNeural
Gender: Female Gender: Female
@@ -602,12 +614,24 @@ Gender: Male
Name: it-IT-ElsaNeural Name: it-IT-ElsaNeural
Gender: Female Gender: Female
Name: it-IT-GiuseppeNeural Name: it-IT-GiuseppeMultilingualNeural
Gender: Male Gender: Male
Name: it-IT-IsabellaNeural Name: it-IT-IsabellaNeural
Gender: Female Gender: Female
Name: iu-Cans-CA-SiqiniqNeural
Gender: Female
Name: iu-Cans-CA-TaqqiqNeural
Gender: Male
Name: iu-Latn-CA-SiqiniqNeural
Gender: Female
Name: iu-Latn-CA-TaqqiqNeural
Gender: Male
Name: ja-JP-KeitaNeural Name: ja-JP-KeitaNeural
Gender: Male Gender: Male
@@ -644,7 +668,7 @@ Gender: Male
Name: kn-IN-SapnaNeural Name: kn-IN-SapnaNeural
Gender: Female Gender: Female
Name: ko-KR-HyunsuNeural Name: ko-KR-HyunsuMultilingualNeural
Gender: Male Gender: Male
Name: ko-KR-InJoonNeural Name: ko-KR-InJoonNeural
@@ -758,7 +782,7 @@ Gender: Male
Name: pt-BR-FranciscaNeural Name: pt-BR-FranciscaNeural
Gender: Female Gender: Female
Name: pt-BR-ThalitaNeural Name: pt-BR-ThalitaMultilingualNeural
Gender: Female Gender: Female
Name: pt-PT-DuarteNeural Name: pt-PT-DuarteNeural

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 KiB

After

Width:  |  Height:  |  Size: 275 KiB

View File

@@ -1,26 +1,14 @@
requests~=2.31.0 moviepy==2.1.1
moviepy==2.0.0.dev2 streamlit==1.40.2
openai~=1.13.3 edge_tts==6.1.19
faster-whisper~=1.0.1 fastapi==0.115.6
edge_tts~=6.1.10 uvicorn==0.32.1
uvicorn~=0.27.1 openai==1.56.1
fastapi~=0.110.0 faster-whisper==1.1.0
tomli~=2.0.1 loguru==0.7.2
streamlit~=1.33.0 google.generativeai==0.8.3
loguru~=0.7.2 dashscope==1.20.14
aiohttp~=3.9.3 g4f==0.3.8.1
urllib3~=2.2.1 azure-cognitiveservices-speech==1.41.1
pillow~=10.3.0 redis==5.2.0
pydantic~=2.6.3 python-multipart==0.0.19
g4f~=0.3.0.4
dashscope~=1.15.0
google.generativeai~=0.4.1
python-multipart~=0.0.9
redis==5.0.3
# if you use pillow~=10.3.0, you will get "PIL.Image' has no attribute 'ANTIALIAS'" error when resize video
# please install opencv-python to fix "PIL.Image' has no attribute 'ANTIALIAS'" error
opencv-python~=4.9.0.80
# 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
git-changelog~=2.5.2

View File

@@ -479,7 +479,7 @@ with left_panel:
st.session_state["video_terms"] = ", ".join(terms) st.session_state["video_terms"] = ", ".join(terms)
params.video_terms = st.text_area( params.video_terms = st.text_area(
tr("Video Keywords"), value=st.session_state["video_terms"], height=50 tr("Video Keywords"), value=st.session_state["video_terms"]
) )
with middle_panel: with middle_panel: