diff --git a/README.md b/README.md index 7a829bf..17e6cbc 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,9 @@ - [ ] 支持更多的语音合成服务商,比如 OpenAI TTS, Azure TTS - [ ] 自动上传到YouTube平台 +## 交流讨论 💬 + + ## 视频演示 📺 ### 竖屏 9:16 @@ -102,8 +105,17 @@ +## 配置要求 📦 +- 建议最低 CPU 4核或以上,内存 8G 或以上,显卡非必须 +- Windows 10 或 MacOS 11.0 以上系统 + ## 安装部署 📥 +> 不想部署的可以直接下载安装包,解压直接使用 +- **Windows** 版本下载地址 + - 百度网盘: https://pan.baidu.com/s/1BB3SGtAFTytzFLS5t2d8Gg?pwd=5bry + +### 前提条件 - 尽量不要使用 **中文路径**,避免出现一些无法预料的问题 - 请确保你的 **网络** 是正常的,VPN需要打开`全局流量`模式 @@ -375,14 +387,6 @@ pip install Pillow==8.4.0 - 可以提交 [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues) 或者 [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls)。 -- 也可以关注我的 **抖音** 或 **视频号**:`网旭哈瑞.AI` - - 我会在上面发布一些 **使用教程** 和 **纯技术** 分享。 - - 如果有更新和优化,我也会在上面 **及时通知**。 - - 有问题也可以在上面 **留言**,我会 **尽快回复**。 - -| 抖音 | | 视频号 | -|:---------------------------------------:|:------------:|:-------------------------------------------:| -| | | | ## 参考项目 📚 diff --git a/app/config/config.py b/app/config/config.py index 2afcdd0..19d4a77 100644 --- a/app/config/config.py +++ b/app/config/config.py @@ -53,7 +53,7 @@ listen_port = _cfg.get("listen_port", 8080) project_name = _cfg.get("project_name", "MoneyPrinterTurbo") project_description = _cfg.get("project_description", "https://github.com/harry0703/MoneyPrinterTurbo") -project_version = _cfg.get("project_version", "1.0.1") +project_version = _cfg.get("project_version", "1.1.0") reload_debug = False imagemagick_path = app.get("imagemagick_path", "") diff --git a/app/services/llm.py b/app/services/llm.py index fda371f..e622818 100644 --- a/app/services/llm.py +++ b/app/services/llm.py @@ -5,6 +5,8 @@ from typing import List from loguru import logger from openai import OpenAI from openai import AzureOpenAI +from openai.types.chat import ChatCompletion + from app.config import config @@ -154,7 +156,15 @@ def _generate_response(prompt: str) -> str: messages=[{"role": "user", "content": prompt}] ) if response: - content = response.choices[0].message.content + if isinstance(response, ChatCompletion): + content = response.choices[0].message.content + else: + raise Exception( + f"[{llm_provider}] returned an invalid response: \"{response}\", please check your network " + f"connection and try again.") + else: + raise Exception( + f"[{llm_provider}] returned an empty response, please check your network connection and try again.") return content.replace("\n", "") diff --git a/app/services/subtitle.py b/app/services/subtitle.py index 5ea8028..d19ac59 100644 --- a/app/services/subtitle.py +++ b/app/services/subtitle.py @@ -1,4 +1,5 @@ import json +import os.path import re from faster_whisper import WhisperModel @@ -17,8 +18,13 @@ model = None def create(audio_file, subtitle_file: str = ""): global model if not model: - logger.info(f"loading model: {model_size}, device: {device}, compute_type: {compute_type}") - model = WhisperModel(model_size_or_path=model_size, + model_path = f"{utils.root_dir()}/models/whisper-{model_size}" + model_bin_file = f"{model_path}/model.bin" + if not os.path.isdir(model_path) or not os.path.isfile(model_bin_file): + model_path = model_size + + logger.info(f"loading model: {model_path}, device: {device}, compute_type: {compute_type}") + model = WhisperModel(model_size_or_path=model_path, device=device, compute_type=compute_type) diff --git a/app/services/video.py b/app/services/video.py index 6ada901..e05dc12 100644 --- a/app/services/video.py +++ b/app/services/video.py @@ -124,7 +124,7 @@ def wrap_text(text, max_width, font='Arial', fontsize=60): width, height = get_text_size(text) if width <= max_width: - return text + return text, height logger.warning(f"wrapping text, max_width: {max_width}, text_width: {width}, text: {text}") @@ -149,8 +149,9 @@ def wrap_text(text, max_width, font='Arial', fontsize=60): if processed: _wrapped_lines_ = [line.strip() for line in _wrapped_lines_] result = '\n'.join(_wrapped_lines_).strip() + height = len(_wrapped_lines_) * height logger.warning(f"wrapped text: {result}") - return result + return result, height _wrapped_lines_ = [] chars = list(text) @@ -165,8 +166,9 @@ def wrap_text(text, max_width, font='Arial', fontsize=60): _txt_ = '' _wrapped_lines_.append(_txt_) result = '\n'.join(_wrapped_lines_).strip() + height = len(_wrapped_lines_) * height logger.warning(f"wrapped text: {result}") - return result + return result, height def generate_video(video_path: str, @@ -199,23 +201,15 @@ def generate_video(video_path: str, logger.info(f"using font: {font_path}") - if params.subtitle_position == "top": - position_height = video_height * 0.1 - elif params.subtitle_position == "bottom": - position_height = video_height * 0.9 - else: - position_height = "center" - - def generator(txt, **kwargs): + def create_text_clip(subtitle_item): + phrase = subtitle_item[1] max_width = video_width * 0.9 - # logger.debug(f"rendering text: {txt}") - wrapped_txt = wrap_text(txt, - max_width=max_width, - font=font_path, - fontsize=params.font_size - ) # 调整max_width以适应你的视频 - - clip = TextClip( + wrapped_txt, txt_height = wrap_text(phrase, + max_width=max_width, + font=font_path, + fontsize=params.font_size + ) + _clip = TextClip( wrapped_txt, font=font_path, fontsize=params.font_size, @@ -225,15 +219,28 @@ def generate_video(video_path: str, stroke_width=params.stroke_width, print_cmd=False, ) - return clip + duration = subtitle_item[0][1] - subtitle_item[0][0] + _clip = _clip.set_start(subtitle_item[0][0]) + _clip = _clip.set_end(subtitle_item[0][1]) + _clip = _clip.set_duration(duration) + if params.subtitle_position == "bottom": + _clip = _clip.set_position(('center', video_height * 0.95 - _clip.h)) + elif params.subtitle_position == "top": + _clip = _clip.set_position(('center', video_height * 0.1)) + else: + _clip = _clip.set_position(('center', 'center')) + return _clip video_clip = VideoFileClip(video_path) audio_clip = AudioFileClip(audio_path).volumex(params.voice_volume) if subtitle_path and os.path.exists(subtitle_path): - sub = SubtitlesClip(subtitles=subtitle_path, make_textclip=generator, encoding='utf-8') - sub_clip = sub.set_position(lambda _t: ('center', position_height)) - video_clip = CompositeVideoClip([video_clip, sub_clip]) + sub = SubtitlesClip(subtitles=subtitle_path, encoding='utf-8') + text_clips = [] + for item in sub.subtitles: + clip = create_text_clip(subtitle_item=item) + text_clips.append(clip) + 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: @@ -258,7 +265,7 @@ if __name__ == "__main__": txt_zh = "测试长字段这是您的旅行技巧指南帮助您进行预算友好的冒险" font = utils.resource_dir() + "/fonts/STHeitiMedium.ttc" for txt in [txt_en, txt_zh]: - t = wrap_text(text=txt, max_width=1000, font=font, fontsize=60) + t, h = wrap_text(text=txt, max_width=1000, font=font, fontsize=60) print(t) task_id = "aa563149-a7ea-49c2-b39f-8c32cc225baf" diff --git a/docs/wechat-01.jpg b/docs/wechat-01.jpg new file mode 100644 index 0000000..96add13 Binary files /dev/null and b/docs/wechat-01.jpg differ diff --git a/webui/Main.py b/webui/Main.py index 9631d39..6ff61cf 100644 --- a/webui/Main.py +++ b/webui/Main.py @@ -38,7 +38,7 @@ hide_streamlit_style = """ """ st.markdown(hide_streamlit_style, unsafe_allow_html=True) -st.title("MoneyPrinterTurbo") +st.title(f"MoneyPrinterTurbo v{config.project_version}") font_dir = os.path.join(root_dir, "resource", "fonts") song_dir = os.path.join(root_dir, "resource", "songs") diff --git a/webui/i18n/de.json b/webui/i18n/de.json index 63bd397..d68899b 100644 --- a/webui/i18n/de.json +++ b/webui/i18n/de.json @@ -58,6 +58,6 @@ "Model Name": "Model Name", "Please Enter the LLM API Key": "Please Enter the **LLM API Key**", "Please Enter the Pexels API Key": "Please Enter the **Pexels API Key**", - "Get Help": "If you need help, or have any questions, you can join discord for help: https://harryai.cc/moneyprinterturbo" + "Get Help": "If you need help, or have any questions, you can join discord for help: https://harryai.cc" } } \ No newline at end of file diff --git a/webui/i18n/en.json b/webui/i18n/en.json index f9458a9..5fca842 100644 --- a/webui/i18n/en.json +++ b/webui/i18n/en.json @@ -59,6 +59,6 @@ "Model Name": "Model Name", "Please Enter the LLM API Key": "Please Enter the **LLM API Key**", "Please Enter the Pexels API Key": "Please Enter the **Pexels API Key**", - "Get Help": "If you need help, or have any questions, you can join discord for help: https://harryai.cc/moneyprinterturbo" + "Get Help": "If you need help, or have any questions, you can join discord for help: https://harryai.cc" } } \ No newline at end of file diff --git a/webui/i18n/zh.json b/webui/i18n/zh.json index 7019c27..28f719d 100644 --- a/webui/i18n/zh.json +++ b/webui/i18n/zh.json @@ -59,6 +59,6 @@ "Model Name": "模型名称 (:blue[需要到大模型提供商的后台确认被授权的模型名称])", "Please Enter the LLM API Key": "请先填写大模型 **API Key**", "Please Enter the Pexels API Key": "请先填写 **Pexels API Key**", - "Get Help": "有任何问题或建议,可以加入 **微信群** 求助或讨论:https://harryai.cc/moneyprinterturbo" + "Get Help": "有任何问题或建议,可以加入 **微信群** 求助或讨论:https://harryai.cc" } } \ No newline at end of file