Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
951460b9f1 | ||
|
|
6523509539 | ||
|
|
68cb074a92 | ||
|
|
aa2f16eb3e | ||
|
|
6e3d54c811 | ||
|
|
238f6e4b55 | ||
|
|
7fdfbbcd3e | ||
|
|
f8f10669cb | ||
|
|
f42b5f3710 | ||
|
|
aa945361ad | ||
|
|
3473ebf7f5 | ||
|
|
66fc858d05 | ||
|
|
de106e77a6 | ||
|
|
b8c57f0088 | ||
|
|
d2706a5fe4 | ||
|
|
d65e126486 | ||
|
|
f6c40deec6 | ||
|
|
579d3c0948 | ||
|
|
017a95d051 | ||
|
|
9314291748 | ||
|
|
18be15f446 | ||
|
|
b36caf63cf | ||
|
|
10f177adac | ||
|
|
c8d11ac4c3 | ||
|
|
6cb5f23487 | ||
|
|
83f0a54234 | ||
|
|
235362b044 | ||
|
|
a789fe7e9a | ||
|
|
9a20328d7a | ||
|
|
fda81b2e9a | ||
|
|
7ed4a1762d | ||
|
|
2bbbe5480e | ||
|
|
91e4d3ef72 | ||
|
|
4a33655ad7 | ||
|
|
95922908ce | ||
|
|
8449303a90 | ||
|
|
7bee963a18 | ||
|
|
e8f0db25ee | ||
|
|
33245996c5 | ||
|
|
4d5ca7f6f4 |
132
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,6 +1,6 @@
|
|||||||
name: 🐛 Bug
|
name: 🐛 Bug | Bug Report
|
||||||
description: 出现错误或未按预期工作
|
description: 报告错误或异常问题 | Report an error or unexpected behavior
|
||||||
title: "请在此处填写标题"
|
title: "[Bug]: "
|
||||||
labels:
|
labels:
|
||||||
- bug
|
- bug
|
||||||
|
|
||||||
@ -8,74 +8,80 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
**在提交此问题之前,请确保您已阅读以下文档:[Getting Started (英文)](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README-en.md#system-requirements-) 或 [快速开始 (中文)](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README.md#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B-)。**
|
**提交问题前,请确保您已阅读以下文档:[Getting Started (English)](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README-en.md#system-requirements-) 或 [快速开始 (中文)](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README.md#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B-)。**
|
||||||
|
|
||||||
**请填写以下信息:**
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: 是否已存在类似问题?
|
|
||||||
description: |
|
|
||||||
请务必检查此问题是否已有用户反馈。
|
|
||||||
|
|
||||||
在提交新问题前,使用 GitHub 的问题搜索框(包括已关闭的问题)或通过 Google、StackOverflow 等工具搜索,确认该问题是否重复。
|
**Before submitting an issue, please make sure you've read the following documentation: [Getting Started (English)](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README-en.md#system-requirements-) or [快速开始 (Chinese)](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README.md#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B-).**
|
||||||
|
|
||||||
您可能已经可以找到解决问题的方法!
|
|
||||||
options:
|
|
||||||
- label: 我已搜索现有问题
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 当前行为
|
label: 问题描述 | Current Behavior
|
||||||
description: 描述您当前遇到的情况。
|
|
||||||
placeholder: |
|
|
||||||
MoneyPrinterTurbo 未按预期工作。当我执行某个操作时,视频未成功生成/程序报错了...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 预期行为
|
|
||||||
description: 描述您期望发生的情况。
|
|
||||||
placeholder: |
|
|
||||||
当我执行某个操作时,程序应当...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 重现步骤
|
|
||||||
description: 描述重现问题的步骤。描述的越详细,越有助于定位和修复问题。
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 堆栈追踪/日志
|
|
||||||
description: |
|
description: |
|
||||||
如果您有任何堆栈追踪或日志,请将它们粘贴在此处。(注意不要包含敏感信息)
|
描述您遇到的问题
|
||||||
validations:
|
Describe the issue you're experiencing
|
||||||
required: true
|
placeholder: |
|
||||||
- type: input
|
当我执行...操作时,程序出现了...问题
|
||||||
attributes:
|
When I perform..., the program shows...
|
||||||
label: Python 版本
|
|
||||||
description: 您遇到此问题时使用的 Python 版本。
|
|
||||||
placeholder: v3.13.0, v3.10.0 等
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: 操作系统
|
|
||||||
description: 您使用 MoneyPrinterTurbo 遇到问题时的操作系统信息。
|
|
||||||
placeholder: macOS 14.1, Windows 11 等
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: MoneyPrinterTurbo 版本
|
|
||||||
description: 您在哪个版本的 MoneyPrinterTurbo 中遇到了此问题?
|
|
||||||
placeholder: v1.2.2 等
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 其他信息
|
label: 重现步骤 | Steps to Reproduce
|
||||||
description: 您还有什么其他信息想补充吗?例如问题的截图或视频记录。
|
description: |
|
||||||
|
详细描述如何重现此问题
|
||||||
|
Describe in detail how to reproduce this issue
|
||||||
|
placeholder: |
|
||||||
|
1. 打开...
|
||||||
|
2. 点击...
|
||||||
|
3. 出现错误...
|
||||||
|
|
||||||
|
1. Open...
|
||||||
|
2. Click on...
|
||||||
|
3. Error occurs...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 错误日志 | Error Logs
|
||||||
|
description: |
|
||||||
|
请提供相关错误信息或日志(注意不要包含敏感信息)
|
||||||
|
Please provide any error messages or logs (be careful not to include sensitive information)
|
||||||
|
placeholder: |
|
||||||
|
错误信息、日志或截图...
|
||||||
|
Error messages, logs, or screenshots...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Python 版本 | Python Version
|
||||||
|
description: |
|
||||||
|
您使用的 Python 版本
|
||||||
|
The Python version you're using
|
||||||
|
placeholder: v3.13.0, v3.10.0, etc.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: 操作系统 | Operating System
|
||||||
|
description: |
|
||||||
|
您的操作系统信息
|
||||||
|
Your operating system information
|
||||||
|
placeholder: macOS 14.1, Windows 11, Ubuntu 22.04, etc.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: MoneyPrinterTurbo 版本 | Version
|
||||||
|
description: |
|
||||||
|
您使用的 MoneyPrinterTurbo 版本
|
||||||
|
The version of MoneyPrinterTurbo you're using
|
||||||
|
placeholder: v1.2.2, etc.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 补充信息 | Additional Information
|
||||||
|
description: |
|
||||||
|
其他对解决问题有帮助的信息(如截图、视频等)
|
||||||
|
Any other information that might help solve the issue (screenshots, videos, etc.)
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
45
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,38 +1,29 @@
|
|||||||
name: ✨ 增加功能
|
name: ✨ 增加功能 | Feature Request
|
||||||
description: 为此项目提出一个新想法
|
description: 为此项目提出一个新想法或建议 | Suggest a new idea for this project
|
||||||
title: "请在此处填写标题"
|
title: "[Feature]: "
|
||||||
labels:
|
labels:
|
||||||
- enhancement
|
- enhancement
|
||||||
|
|
||||||
body:
|
body:
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: 是否已存在类似的功能请求?
|
|
||||||
description: 请确保此功能请求是否重复。
|
|
||||||
options:
|
|
||||||
- label: 我已搜索现有的功能请求
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 痛点
|
label: 需求描述 | Problem Statement
|
||||||
description: 请解释您的功能请求。
|
description: |
|
||||||
placeholder: 我希望可以实现这一点
|
请描述您希望解决的问题或需求
|
||||||
|
Please describe the problem you want to solve
|
||||||
|
placeholder: |
|
||||||
|
我在使用过程中遇到了...
|
||||||
|
I encountered... when using this project
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 建议的解决方案
|
label: 建议的解决方案 | Proposed Solution
|
||||||
description: 请描述您能想到的解决方案。
|
description: |
|
||||||
placeholder: 您可以添加这个功能 / 更改这个流程 / 使用某种方法
|
请描述您认为可行的解决方案或实现方式
|
||||||
|
Please describe your suggested solution or implementation
|
||||||
|
placeholder: |
|
||||||
|
可以考虑添加...功能来解决这个问题
|
||||||
|
Consider adding... feature to address this issue
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 有用的资源
|
|
||||||
description: 请提供一些有助于实现您建议的资源。
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 其他信息
|
|
||||||
description: 您还有什么其他想补充的信息吗?例如问题的截图或视频记录。
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
33
.github/workflows/gh-pages.yml
vendored
@ -1,33 +0,0 @@
|
|||||||
name: gp-pages
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- 'sites/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Set-up Node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: "18.15.0"
|
|
||||||
- name: Install pnpm
|
|
||||||
run: npm install -g pnpm
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm i
|
|
||||||
working-directory: ./sites
|
|
||||||
- name: Build gh-pages
|
|
||||||
run: pnpm docs:build
|
|
||||||
working-directory: ./sites
|
|
||||||
- name: Deploy to gh-pages
|
|
||||||
uses: crazy-max/ghaction-github-pages@v1
|
|
||||||
with:
|
|
||||||
target_branch: gh-pages
|
|
||||||
build_dir: sites/docs/.vuepress/dist
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.MY_TOKEN }}
|
|
||||||
9
.gitignore
vendored
@ -25,4 +25,11 @@ node_modules
|
|||||||
./models/*
|
./models/*
|
||||||
|
|
||||||
venv/
|
venv/
|
||||||
.venv
|
.venv
|
||||||
|
|
||||||
|
# Debug and test files
|
||||||
|
CLAUDE.md
|
||||||
|
debug/
|
||||||
|
debug_*.py
|
||||||
|
test_*.py
|
||||||
|
streamlit.log
|
||||||
@ -1 +0,0 @@
|
|||||||
./MoneyPrinterTurbo/.venv/bin/python
|
|
||||||
22
CHANGELOG.md
@ -1,22 +0,0 @@
|
|||||||
<!-- insertion marker -->
|
|
||||||
## [1.1.2](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/releases/tag/1.1.2) - 2024-04-18
|
|
||||||
|
|
||||||
<small>[Compare with first commit](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/compare/d4f7b53b841e65da658e3d77822f9923286ddab6...1.1.2)</small>
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
- add support for maximum concurrency of /api/v1/videos ([abe12ab](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/abe12abd7b78997651468ad5dd656985066f8bd9) by kevin.zhang).
|
|
||||||
- add task deletion endpoint ([d57434e](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/d57434e0d31c8195dbcd3c86ff2763af96736cdf) by kevin.zhang).
|
|
||||||
- add redis support for task state management ([3d45348](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/3d453486627234937c7bfe6f176890360074696b) by kevin.zhang).
|
|
||||||
- enable cors to allow play video through mounted videos url ([3b1871d](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/3b1871d591873594bb4aa8dc17a1253b3a7563a3) by kevin.zhang).
|
|
||||||
- add /api/v1/get_bgm_list and /api/v1/upload_bgm_file ([6d8911f](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/6d8911f5bf496e7c5dd718309a302df88d11817b) by cathy).
|
|
||||||
- return combined videos in /api/v1/tasks response ([28199c9](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/28199c93b78f67e9a6bf50f290f1591078f63da8) by cathy).
|
|
||||||
- add Dockerfile ([f3b3c7f](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/f3b3c7fb47b01ed4ecba44eaebf29f5d6d2cb7b5) by kevin.zhang).
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
- response parsing bug for gemini ([ee7306d](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/ee7306d216ea41e40855bbca396cacb094d572db) by elf-mouse).
|
|
||||||
|
|
||||||
### Code Refactoring
|
|
||||||
|
|
||||||
- Streaming MP4 files in the browser using video html element instead of waiting for the entire file to download before playing ([d13a3cf](https://github.com/KevinZhang19870314/MoneyPrinterTurbo/commit/d13a3cf6e911d1573c62b1f6459c3c0b7a1bc18d) by kevin.zhang).
|
|
||||||
46
Dockerfile
@ -9,12 +9,40 @@ RUN chmod 777 /MoneyPrinterTurbo
|
|||||||
|
|
||||||
ENV PYTHONPATH="/MoneyPrinterTurbo"
|
ENV PYTHONPATH="/MoneyPrinterTurbo"
|
||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies with domestic mirrors first for stability
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN echo "deb http://mirrors.aliyun.com/debian bullseye main" > /etc/apt/sources.list && \
|
||||||
git \
|
echo "deb http://mirrors.aliyun.com/debian-security bullseye-security main" >> /etc/apt/sources.list && \
|
||||||
imagemagick \
|
( \
|
||||||
ffmpeg \
|
for i in 1 2 3; do \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
echo "Attempt $i: Using Aliyun mirror"; \
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
imagemagick \
|
||||||
|
ffmpeg && break || \
|
||||||
|
echo "Attempt $i failed, retrying..."; \
|
||||||
|
if [ $i -eq 3 ]; then \
|
||||||
|
echo "Aliyun mirror failed, switching to Tsinghua mirror"; \
|
||||||
|
sed -i 's/mirrors.aliyun.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
|
||||||
|
sed -i 's/mirrors.aliyun.com\/debian-security/mirrors.tuna.tsinghua.edu.cn\/debian-security/g' /etc/apt/sources.list && \
|
||||||
|
( \
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
imagemagick \
|
||||||
|
ffmpeg || \
|
||||||
|
( \
|
||||||
|
echo "Tsinghua mirror failed, switching to default Debian mirror"; \
|
||||||
|
sed -i 's/mirrors.tuna.tsinghua.edu.cn/deb.debian.org/g' /etc/apt/sources.list && \
|
||||||
|
sed -i 's/mirrors.tuna.tsinghua.edu.cn\/debian-security/security.debian.org/g' /etc/apt/sources.list; \
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
imagemagick \
|
||||||
|
ffmpeg; \
|
||||||
|
); \
|
||||||
|
); \
|
||||||
|
fi; \
|
||||||
|
sleep 5; \
|
||||||
|
done \
|
||||||
|
) && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Fix security policy for ImageMagick
|
# Fix security policy for ImageMagick
|
||||||
RUN sed -i '/<policy domain="path" rights="none" pattern="@\*"/d' /etc/ImageMagick-6/policy.xml
|
RUN sed -i '/<policy domain="path" rights="none" pattern="@\*"/d' /etc/ImageMagick-6/policy.xml
|
||||||
@ -22,8 +50,10 @@ RUN sed -i '/<policy domain="path" rights="none" pattern="@\*"/d' /etc/ImageMagi
|
|||||||
# Copy only the requirements.txt first to leverage Docker cache
|
# Copy only the requirements.txt first to leverage Docker cache
|
||||||
COPY requirements.txt ./
|
COPY requirements.txt ./
|
||||||
|
|
||||||
# Install Python dependencies
|
# Install Python dependencies with domestic mirrors first and retry logic
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com --retries 3 --timeout 60 -r requirements.txt || \
|
||||||
|
pip install --no-cache-dir -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/ --trusted-host mirrors.tuna.tsinghua.edu.cn --retries 3 --timeout 60 -r requirements.txt || \
|
||||||
|
pip install --no-cache-dir --retries 3 --timeout 60 -r requirements.txt
|
||||||
|
|
||||||
# Now copy the rest of the codebase into the image
|
# Now copy the rest of the codebase into the image
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
90
README-en.md
@ -38,15 +38,15 @@ project. It allows for online use without deployment, which is very convenient.
|
|||||||
- Chinese version: https://reccloud.cn
|
- Chinese version: https://reccloud.cn
|
||||||
- English version: https://reccloud.com
|
- English version: https://reccloud.com
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Thanks for Sponsorship 🙏
|
## Thanks for Sponsorship 🙏
|
||||||
|
|
||||||
Thanks to Picwish https://picwish.cn for supporting and sponsoring this project, enabling continuous updates and maintenance.
|
Thanks to Picwish https://picwish.com for supporting and sponsoring this project, enabling continuous updates and maintenance.
|
||||||
|
|
||||||
Picwish focuses on the **image processing field**, providing a rich set of **image processing tools** that extremely simplify complex operations, truly making image processing easier.
|
Picwish focuses on the **image processing field**, providing a rich set of **image processing tools** that extremely simplify complex operations, truly making image processing easier.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Features 🎯
|
## Features 🎯
|
||||||
|
|
||||||
@ -65,11 +65,7 @@ Picwish focuses on the **image processing field**, providing a rich set of **ima
|
|||||||
supports `subtitle outlining`
|
supports `subtitle outlining`
|
||||||
- [x] Supports **background music**, either random or specified music files, with adjustable `background music volume`
|
- [x] Supports **background music**, either random or specified music files, with adjustable `background music volume`
|
||||||
- [x] Video material sources are **high-definition** and **royalty-free**, and you can also use your own **local materials**
|
- [x] Video material sources are **high-definition** and **royalty-free**, and you can also use your own **local materials**
|
||||||
- [x] Supports integration with various models such as **OpenAI**, **Moonshot**, **Azure**, **gpt4free**, **one-api**,
|
- [x] Supports integration with various models such as **OpenAI**, **Moonshot**, **Azure**, **gpt4free**, **one-api**, **Qwen**, **Google Gemini**, **Ollama**, **DeepSeek**, **ERNIE**, **Pollinations**, **ModelScope** and more
|
||||||
**Qwen**, **Google Gemini**, **Ollama**, **DeepSeek**, **ERNIE** and more
|
|
||||||
- For users in China, it is recommended to use **DeepSeek** or **Moonshot** as the large model provider (directly accessible in China, no VPN needed. Free credits upon registration, generally sufficient for use)
|
|
||||||
|
|
||||||
❓[How to Use the Free OpenAI GPT-3.5 Model?](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README-en.md#common-questions-)
|
|
||||||
|
|
||||||
### Future Plans 📅
|
### Future Plans 📅
|
||||||
|
|
||||||
@ -119,15 +115,20 @@ Picwish focuses on the **image processing field**, providing a rich set of **ima
|
|||||||
|
|
||||||
## System Requirements 📦
|
## System Requirements 📦
|
||||||
|
|
||||||
- Recommended minimum 4 CPU cores or more, 8G of memory or more, GPU is not required
|
- Recommended minimum 4 CPU cores or more, 4G of memory or more, GPU is not required
|
||||||
- Windows 10 or MacOS 11.0, and their later versions
|
- Windows 10 or MacOS 11.0, and their later versions
|
||||||
|
|
||||||
## Quick Start 🚀
|
## Quick Start 🚀
|
||||||
|
|
||||||
Download the one-click startup package, extract and use directly (the path should not contain **Chinese characters**, **special characters**, or **spaces**)
|
### Run in Google Colab
|
||||||
|
Want to try MoneyPrinterTurbo without setting up a local environment? Run it directly in Google Colab!
|
||||||
|
|
||||||
|
[](https://colab.research.google.com/github/harry0703/MoneyPrinterTurbo/blob/main/docs/MoneyPrinterTurbo.ipynb)
|
||||||
|
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
- Baidu Netdisk (1.2.1 latest version): https://pan.baidu.com/s/1pSNjxTYiVENulTLm6zieMQ?pwd=g36q Extraction code: g36q
|
|
||||||
|
Google Drive (v1.2.6): https://drive.google.com/file/d/1HsbzfT7XunkrCrHw5ncUjFX8XX4zAuUh/view?usp=sharing
|
||||||
|
|
||||||
After downloading, it is recommended to **double-click** `update.bat` first to update to the **latest code**, then double-click `start.bat` to launch
|
After downloading, it is recommended to **double-click** `update.bat` first to update to the **latest code**, then double-click `start.bat` to launch
|
||||||
|
|
||||||
@ -141,9 +142,6 @@ One-click startup packages have not been created yet. See the **Installation & D
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Try to avoid using **Chinese paths** to prevent unpredictable issues
|
|
||||||
- Ensure your **network** is stable, VPN needs to be in `global traffic` mode
|
|
||||||
|
|
||||||
#### ① Clone the Project
|
#### ① Clone the Project
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@ -183,19 +181,16 @@ Open your browser and visit http://0.0.0.0:8080/docs Or http://0.0.0.0:8080/redo
|
|||||||
|
|
||||||
### Manual Deployment 📦
|
### Manual Deployment 📦
|
||||||
|
|
||||||
> Video tutorials
|
#### ① Create a Python Virtual Environment
|
||||||
>
|
|
||||||
> - Complete usage demonstration: https://v.douyin.com/iFhnwsKY/
|
|
||||||
> - How to deploy on Windows: https://v.douyin.com/iFyjoW3M
|
|
||||||
|
|
||||||
#### ① Install Dependencies
|
It is recommended to create a Python virtual environment using [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index.html)
|
||||||
|
|
||||||
It is recommended to use [pdm](https://pdm-project.org/en/latest/#installation)
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
||||||
cd MoneyPrinterTurbo
|
cd MoneyPrinterTurbo
|
||||||
pdm sync
|
conda create -n MoneyPrinterTurbo python=3.11
|
||||||
|
conda activate MoneyPrinterTurbo
|
||||||
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
#### ② Install ImageMagick
|
#### ② Install ImageMagick
|
||||||
@ -310,34 +305,6 @@ own fonts.
|
|||||||
|
|
||||||
## Common Questions 🤔
|
## Common Questions 🤔
|
||||||
|
|
||||||
### ❓How to Use the Free OpenAI GPT-3.5 Model?
|
|
||||||
|
|
||||||
[OpenAI has announced that ChatGPT with 3.5 is now free](https://openai.com/blog/start-using-chatgpt-instantly), and
|
|
||||||
developers have wrapped it into an API for direct usage.
|
|
||||||
|
|
||||||
**Ensure you have Docker installed and running**. Execute the following command to start the Docker service:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -p 3040:3040 missuo/freegpt35
|
|
||||||
```
|
|
||||||
|
|
||||||
Once successfully started, modify the `config.toml` configuration as follows:
|
|
||||||
|
|
||||||
- Set `llm_provider` to `openai`
|
|
||||||
- Fill in `openai_api_key` with any value, for example, '123456'
|
|
||||||
- Change `openai_base_url` to `http://localhost:3040/v1/`
|
|
||||||
- Set `openai_model_name` to `gpt-3.5-turbo`
|
|
||||||
|
|
||||||
> Note: This method may be unstable
|
|
||||||
|
|
||||||
### ❓AttributeError: 'str' object has no attribute 'choices'
|
|
||||||
|
|
||||||
This issue is caused by the large language model not returning a correct response.
|
|
||||||
|
|
||||||
It's likely a network issue. Use a **VPN**, or set `openai_base_url` to your proxy, which should solve the problem.
|
|
||||||
|
|
||||||
At the same time, it is recommended to use **Moonshot** or **DeepSeek** as the large model provider, as these service providers have faster access and are more stable in China.
|
|
||||||
|
|
||||||
### ❓RuntimeError: No ffmpeg exe could be found
|
### ❓RuntimeError: No ffmpeg exe could be found
|
||||||
|
|
||||||
Normally, ffmpeg will be automatically downloaded and detected.
|
Normally, ffmpeg will be automatically downloaded and detected.
|
||||||
@ -357,24 +324,6 @@ actual installation path.
|
|||||||
ffmpeg_path = "C:\\Users\\harry\\Downloads\\ffmpeg.exe"
|
ffmpeg_path = "C:\\Users\\harry\\Downloads\\ffmpeg.exe"
|
||||||
```
|
```
|
||||||
|
|
||||||
### ❓Error generating audio or downloading videos
|
|
||||||
|
|
||||||
[issue 56](https://github.com/harry0703/MoneyPrinterTurbo/issues/56)
|
|
||||||
|
|
||||||
```
|
|
||||||
failed to generate audio, maybe the network is not available.
|
|
||||||
if you are in China, please use a VPN.
|
|
||||||
```
|
|
||||||
|
|
||||||
[issue 44](https://github.com/harry0703/MoneyPrinterTurbo/issues/44)
|
|
||||||
|
|
||||||
```
|
|
||||||
failed to download videos, maybe the network is not available.
|
|
||||||
if you are in China, please use a VPN.
|
|
||||||
```
|
|
||||||
|
|
||||||
This is likely due to network issues preventing access to foreign services. Please use a VPN to resolve this.
|
|
||||||
|
|
||||||
### ❓ImageMagick is not installed on your computer
|
### ❓ImageMagick is not installed on your computer
|
||||||
|
|
||||||
[issue 33](https://github.com/harry0703/MoneyPrinterTurbo/issues/33)
|
[issue 33](https://github.com/harry0703/MoneyPrinterTurbo/issues/33)
|
||||||
@ -431,11 +380,6 @@ Solution: [Click to see how to manually download the model from netdisk](#subtit
|
|||||||
- You can submit an [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues) or
|
- You can submit an [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues) or
|
||||||
a [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls).
|
a [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls).
|
||||||
|
|
||||||
## Reference Projects 📚
|
|
||||||
|
|
||||||
This project is based on https://github.com/FujiwaraChoki/MoneyPrinter and has been refactored with a lot of
|
|
||||||
optimizations and added functionalities. Thanks to the original author for their spirit of open source.
|
|
||||||
|
|
||||||
## License 📝
|
## License 📝
|
||||||
|
|
||||||
Click to view the [`LICENSE`](LICENSE) file
|
Click to view the [`LICENSE`](LICENSE) file
|
||||||
|
|||||||
32
README.md
@ -58,10 +58,10 @@
|
|||||||
- [x] 支持 **字幕生成**,可以调整 `字体`、`位置`、`颜色`、`大小`,同时支持`字幕描边`设置
|
- [x] 支持 **字幕生成**,可以调整 `字体`、`位置`、`颜色`、`大小`,同时支持`字幕描边`设置
|
||||||
- [x] 支持 **背景音乐**,随机或者指定音乐文件,可设置`背景音乐音量`
|
- [x] 支持 **背景音乐**,随机或者指定音乐文件,可设置`背景音乐音量`
|
||||||
- [x] 视频素材来源 **高清**,而且 **无版权**,也可以使用自己的 **本地素材**
|
- [x] 视频素材来源 **高清**,而且 **无版权**,也可以使用自己的 **本地素材**
|
||||||
- [x] 支持 **OpenAI**、**Moonshot**、**Azure**、**gpt4free**、**one-api**、**通义千问**、**Google Gemini**、**Ollama**、
|
- [x] 支持 **OpenAI**、**Moonshot**、**Azure**、**gpt4free**、**one-api**、**通义千问**、**Google Gemini**、**Ollama**、**DeepSeek**、 **文心一言**, **Pollinations**、**ModelScope** 等多种模型接入
|
||||||
**DeepSeek**、 **文心一言** 等多种模型接入
|
|
||||||
- 中国用户建议使用 **DeepSeek** 或 **Moonshot** 作为大模型提供商(国内可直接访问,不需要VPN。注册就送额度,基本够用)
|
- 中国用户建议使用 **DeepSeek** 或 **Moonshot** 作为大模型提供商(国内可直接访问,不需要VPN。注册就送额度,基本够用)
|
||||||
|
|
||||||
|
|
||||||
### 后期计划 📅
|
### 后期计划 📅
|
||||||
|
|
||||||
- [ ] GPT-SoVITS 配音支持
|
- [ ] GPT-SoVITS 配音支持
|
||||||
@ -112,15 +112,24 @@
|
|||||||
|
|
||||||
## 配置要求 📦
|
## 配置要求 📦
|
||||||
|
|
||||||
- 建议最低 CPU 4核或以上,内存 8G 或以上,显卡非必须
|
- 建议最低 CPU **4核** 或以上,内存 **4G** 或以上,显卡非必须
|
||||||
- Windows 10 或 MacOS 11.0 以上系统
|
- Windows 10 或 MacOS 11.0 以上系统
|
||||||
|
|
||||||
|
|
||||||
## 快速开始 🚀
|
## 快速开始 🚀
|
||||||
|
|
||||||
|
### 在 Google Colab 中运行
|
||||||
|
免去本地环境配置,点击直接在 Google Colab 中快速体验 MoneyPrinterTurbo
|
||||||
|
|
||||||
|
[](https://colab.research.google.com/github/harry0703/MoneyPrinterTurbo/blob/main/docs/MoneyPrinterTurbo.ipynb)
|
||||||
|
|
||||||
|
|
||||||
|
### Windows一键启动包
|
||||||
|
|
||||||
下载一键启动包,解压直接使用(路径不要有 **中文**、**特殊字符**、**空格**)
|
下载一键启动包,解压直接使用(路径不要有 **中文**、**特殊字符**、**空格**)
|
||||||
|
|
||||||
### Windows
|
- 百度网盘(v1.2.6): https://pan.baidu.com/s/1wg0UaIyXpO3SqIpaq790SQ?pwd=sbqx 提取码: sbqx
|
||||||
- 百度网盘(1.2.1 老版本): https://pan.baidu.com/s/1pSNjxTYiVENulTLm6zieMQ?pwd=g36q 提取码: g36q
|
- Google Drive (v1.2.6): https://drive.google.com/file/d/1HsbzfT7XunkrCrHw5ncUjFX8XX4zAuUh/view?usp=sharing
|
||||||
|
|
||||||
下载后,建议先**双击执行** `update.bat` 更新到**最新代码**,然后双击 `start.bat` 启动
|
下载后,建议先**双击执行** `update.bat` 更新到**最新代码**,然后双击 `start.bat` 启动
|
||||||
|
|
||||||
@ -178,14 +187,16 @@ docker-compose up
|
|||||||
- 完整的使用演示:https://v.douyin.com/iFhnwsKY/
|
- 完整的使用演示:https://v.douyin.com/iFhnwsKY/
|
||||||
- 如何在Windows上部署:https://v.douyin.com/iFyjoW3M
|
- 如何在Windows上部署:https://v.douyin.com/iFyjoW3M
|
||||||
|
|
||||||
#### ① 依赖安装
|
#### ① 创建虚拟环境
|
||||||
|
|
||||||
建议使用 [pdm](https://pdm-project.org/en/latest/#installation)
|
建议使用 [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index.html) 创建 python 虚拟环境
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
||||||
cd MoneyPrinterTurbo
|
cd MoneyPrinterTurbo
|
||||||
pdm sync
|
conda create -n MoneyPrinterTurbo python=3.11
|
||||||
|
conda activate MoneyPrinterTurbo
|
||||||
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
#### ② 安装好 ImageMagick
|
#### ② 安装好 ImageMagick
|
||||||
@ -349,11 +360,6 @@ Trying to load the model directly from the local cache, if it exists.
|
|||||||
- 可以提交 [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues)
|
- 可以提交 [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues)
|
||||||
或者 [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls)。
|
或者 [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls)。
|
||||||
|
|
||||||
## 参考项目 📚
|
|
||||||
|
|
||||||
该项目基于 https://github.com/FujiwaraChoki/MoneyPrinter 重构而来,做了大量的优化,增加了更多的功能。
|
|
||||||
感谢原作者的开源精神。
|
|
||||||
|
|
||||||
## 许可证 📝
|
## 许可证 📝
|
||||||
|
|
||||||
点击查看 [`LICENSE`](LICENSE) 文件
|
点击查看 [`LICENSE`](LICENSE) 文件
|
||||||
|
|||||||
@ -25,6 +25,8 @@ from app.models.schema import (
|
|||||||
TaskQueryResponse,
|
TaskQueryResponse,
|
||||||
TaskResponse,
|
TaskResponse,
|
||||||
TaskVideoRequest,
|
TaskVideoRequest,
|
||||||
|
VideoMaterialUploadResponse,
|
||||||
|
VideoMaterialRetrieveResponse
|
||||||
)
|
)
|
||||||
from app.services import state as sm
|
from app.services import state as sm
|
||||||
from app.services import task as tm
|
from app.services import task as tm
|
||||||
@ -222,6 +224,51 @@ def upload_bgm_file(request: Request, file: UploadFile = File(...)):
|
|||||||
"", status_code=400, message=f"{request_id}: Only *.mp3 files can be uploaded"
|
"", status_code=400, message=f"{request_id}: Only *.mp3 files can be uploaded"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/video_materials", response_model=VideoMaterialRetrieveResponse, summary="Retrieve local video materials"
|
||||||
|
)
|
||||||
|
def get_video_materials_list(request: Request):
|
||||||
|
allowed_suffixes = ("mp4", "mov", "avi", "flv", "mkv", "jpg", "jpeg", "png")
|
||||||
|
local_videos_dir = utils.storage_dir("local_videos", create=True)
|
||||||
|
files = []
|
||||||
|
for suffix in allowed_suffixes:
|
||||||
|
files.extend(glob.glob(os.path.join(local_videos_dir, f"*.{suffix}")))
|
||||||
|
video_materials_list = []
|
||||||
|
for file in files:
|
||||||
|
video_materials_list.append(
|
||||||
|
{
|
||||||
|
"name": os.path.basename(file),
|
||||||
|
"size": os.path.getsize(file),
|
||||||
|
"file": file,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
response = {"files": video_materials_list}
|
||||||
|
return utils.get_response(200, response)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/video_materials",
|
||||||
|
response_model=VideoMaterialUploadResponse,
|
||||||
|
summary="Upload the video material file to the local videos directory",
|
||||||
|
)
|
||||||
|
def upload_video_material_file(request: Request, file: UploadFile = File(...)):
|
||||||
|
request_id = base.get_task_id(request)
|
||||||
|
# check file ext
|
||||||
|
allowed_suffixes = ("mp4", "mov", "avi", "flv", "mkv", "jpg", "jpeg", "png")
|
||||||
|
if file.filename.endswith(allowed_suffixes):
|
||||||
|
local_videos_dir = utils.storage_dir("local_videos", create=True)
|
||||||
|
save_path = os.path.join(local_videos_dir, file.filename)
|
||||||
|
# save file
|
||||||
|
with open(save_path, "wb+") as buffer:
|
||||||
|
# If the file already exists, it will be overwritten
|
||||||
|
file.file.seek(0)
|
||||||
|
buffer.write(file.file.read())
|
||||||
|
response = {"file": save_path}
|
||||||
|
return utils.get_response(200, response)
|
||||||
|
|
||||||
|
raise HttpException(
|
||||||
|
"", status_code=400, message=f"{request_id}: Only files with extensions {', '.join(allowed_suffixes)} can be uploaded"
|
||||||
|
)
|
||||||
|
|
||||||
@router.get("/stream/{file_path:path}")
|
@router.get("/stream/{file_path:path}")
|
||||||
async def stream_video(request: Request, file_path: str):
|
async def stream_video(request: Request, file_path: str):
|
||||||
|
|||||||
@ -81,7 +81,8 @@ class VideoParams(BaseModel):
|
|||||||
video_materials: Optional[List[MaterialInfo]] = (
|
video_materials: Optional[List[MaterialInfo]] = (
|
||||||
None # Materials used to generate the video
|
None # Materials used to generate the video
|
||||||
)
|
)
|
||||||
|
|
||||||
|
custom_audio_file: Optional[str] = None # Custom audio file path, will ignore video_script and disable subtitle
|
||||||
video_language: Optional[str] = "" # auto detect
|
video_language: Optional[str] = "" # auto detect
|
||||||
|
|
||||||
voice_name: Optional[str] = ""
|
voice_name: Optional[str] = ""
|
||||||
@ -301,3 +302,33 @@ class BgmUploadResponse(BaseResponse):
|
|||||||
"data": {"file": "/MoneyPrinterTurbo/resource/songs/example.mp3"},
|
"data": {"file": "/MoneyPrinterTurbo/resource/songs/example.mp3"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class VideoMaterialRetrieveResponse(BaseResponse):
|
||||||
|
class Config:
|
||||||
|
json_schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"status": 200,
|
||||||
|
"message": "success",
|
||||||
|
"data": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"name": "example.mp4",
|
||||||
|
"size": 12345678,
|
||||||
|
"file": "/MoneyPrinterTurbo/resource/videos/example.mp4",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
class VideoMaterialUploadResponse(BaseResponse):
|
||||||
|
class Config:
|
||||||
|
json_schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"status": 200,
|
||||||
|
"message": "success",
|
||||||
|
"data": {
|
||||||
|
"file": "/MoneyPrinterTurbo/resource/videos/example.mp4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import requests
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import g4f
|
import g4f
|
||||||
@ -57,7 +58,7 @@ def _generate_response(prompt: str) -> str:
|
|||||||
elif llm_provider == "gemini":
|
elif llm_provider == "gemini":
|
||||||
api_key = config.app.get("gemini_api_key")
|
api_key = config.app.get("gemini_api_key")
|
||||||
model_name = config.app.get("gemini_model_name")
|
model_name = config.app.get("gemini_model_name")
|
||||||
base_url = "***"
|
base_url = config.app.get("gemini_base_url", "")
|
||||||
elif llm_provider == "qwen":
|
elif llm_provider == "qwen":
|
||||||
api_key = config.app.get("qwen_api_key")
|
api_key = config.app.get("qwen_api_key")
|
||||||
model_name = config.app.get("qwen_model_name")
|
model_name = config.app.get("qwen_model_name")
|
||||||
@ -73,6 +74,12 @@ def _generate_response(prompt: str) -> str:
|
|||||||
base_url = config.app.get("deepseek_base_url")
|
base_url = config.app.get("deepseek_base_url")
|
||||||
if not base_url:
|
if not base_url:
|
||||||
base_url = "https://api.deepseek.com"
|
base_url = "https://api.deepseek.com"
|
||||||
|
elif llm_provider == "modelscope":
|
||||||
|
api_key = config.app.get("modelscope_api_key")
|
||||||
|
model_name = config.app.get("modelscope_model_name")
|
||||||
|
base_url = config.app.get("modelscope_base_url")
|
||||||
|
if not base_url:
|
||||||
|
base_url = "https://api-inference.modelscope.cn/v1/"
|
||||||
elif llm_provider == "ernie":
|
elif llm_provider == "ernie":
|
||||||
api_key = config.app.get("ernie_api_key")
|
api_key = config.app.get("ernie_api_key")
|
||||||
secret_key = config.app.get("ernie_secret_key")
|
secret_key = config.app.get("ernie_secret_key")
|
||||||
@ -82,23 +89,61 @@ def _generate_response(prompt: str) -> str:
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"{llm_provider}: secret_key is not set, please set it in the config.toml file."
|
f"{llm_provider}: secret_key is not set, please set it in the config.toml file."
|
||||||
)
|
)
|
||||||
else:
|
elif llm_provider == "pollinations":
|
||||||
raise ValueError(
|
try:
|
||||||
"llm_provider is not set, please set it in the config.toml file."
|
base_url = config.app.get("pollinations_base_url", "")
|
||||||
)
|
if not base_url:
|
||||||
|
base_url = "https://text.pollinations.ai/openai"
|
||||||
|
model_name = config.app.get("pollinations_model_name", "openai-fast")
|
||||||
|
|
||||||
|
# Prepare the payload
|
||||||
|
payload = {
|
||||||
|
"model": model_name,
|
||||||
|
"messages": [
|
||||||
|
{"role": "user", "content": prompt}
|
||||||
|
],
|
||||||
|
"seed": 101 # Optional but helps with reproducibility
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional parameters if configured
|
||||||
|
if config.app.get("pollinations_private"):
|
||||||
|
payload["private"] = True
|
||||||
|
if config.app.get("pollinations_referrer"):
|
||||||
|
payload["referrer"] = config.app.get("pollinations_referrer")
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make the API request
|
||||||
|
response = requests.post(base_url, headers=headers, json=payload)
|
||||||
|
response.raise_for_status()
|
||||||
|
result = response.json()
|
||||||
|
|
||||||
|
if result and "choices" in result and len(result["choices"]) > 0:
|
||||||
|
content = result["choices"][0]["message"]["content"]
|
||||||
|
return content.replace("\n", "")
|
||||||
|
else:
|
||||||
|
raise Exception(f"[{llm_provider}] returned an invalid response format")
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
raise Exception(f"[{llm_provider}] request failed: {str(e)}")
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"[{llm_provider}] error: {str(e)}")
|
||||||
|
|
||||||
if not api_key:
|
if llm_provider not in ["pollinations", "ollama"]: # Skip validation for providers that don't require API key
|
||||||
raise ValueError(
|
if not api_key:
|
||||||
f"{llm_provider}: api_key is not set, please set it in the config.toml file."
|
raise ValueError(
|
||||||
)
|
f"{llm_provider}: api_key is not set, please set it in the config.toml file."
|
||||||
if not model_name:
|
)
|
||||||
raise ValueError(
|
if not model_name:
|
||||||
f"{llm_provider}: model_name is not set, please set it in the config.toml file."
|
raise ValueError(
|
||||||
)
|
f"{llm_provider}: model_name is not set, please set it in the config.toml file."
|
||||||
if not base_url:
|
)
|
||||||
raise ValueError(
|
if not base_url:
|
||||||
f"{llm_provider}: base_url is not set, please set it in the config.toml file."
|
raise ValueError(
|
||||||
)
|
f"{llm_provider}: base_url is not set, please set it in the config.toml file."
|
||||||
|
)
|
||||||
|
|
||||||
if llm_provider == "qwen":
|
if llm_provider == "qwen":
|
||||||
import dashscope
|
import dashscope
|
||||||
@ -128,7 +173,10 @@ def _generate_response(prompt: str) -> str:
|
|||||||
if llm_provider == "gemini":
|
if llm_provider == "gemini":
|
||||||
import google.generativeai as genai
|
import google.generativeai as genai
|
||||||
|
|
||||||
genai.configure(api_key=api_key, transport="rest")
|
if not base_url:
|
||||||
|
genai.configure(api_key=api_key, transport="rest")
|
||||||
|
else:
|
||||||
|
genai.configure(api_key=api_key, transport="rest", client_options={'api_endpoint': base_url})
|
||||||
|
|
||||||
generation_config = {
|
generation_config = {
|
||||||
"temperature": 0.5,
|
"temperature": 0.5,
|
||||||
@ -172,8 +220,6 @@ def _generate_response(prompt: str) -> str:
|
|||||||
return generated_text
|
return generated_text
|
||||||
|
|
||||||
if llm_provider == "cloudflare":
|
if llm_provider == "cloudflare":
|
||||||
import requests
|
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
f"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model_name}",
|
f"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model_name}",
|
||||||
headers={"Authorization": f"Bearer {api_key}"},
|
headers={"Authorization": f"Bearer {api_key}"},
|
||||||
@ -192,20 +238,15 @@ def _generate_response(prompt: str) -> str:
|
|||||||
return result["result"]["response"]
|
return result["result"]["response"]
|
||||||
|
|
||||||
if llm_provider == "ernie":
|
if llm_provider == "ernie":
|
||||||
import requests
|
response = requests.post(
|
||||||
|
"https://aip.baidubce.com/oauth/2.0/token",
|
||||||
params = {
|
params={
|
||||||
"grant_type": "client_credentials",
|
"grant_type": "client_credentials",
|
||||||
"client_id": api_key,
|
"client_id": api_key,
|
||||||
"client_secret": secret_key,
|
"client_secret": secret_key,
|
||||||
}
|
}
|
||||||
access_token = (
|
|
||||||
requests.post(
|
|
||||||
"https://aip.baidubce.com/oauth/2.0/token", params=params
|
|
||||||
)
|
|
||||||
.json()
|
|
||||||
.get("access_token")
|
|
||||||
)
|
)
|
||||||
|
access_token = response.json().get("access_token")
|
||||||
url = f"{base_url}?access_token={access_token}"
|
url = f"{base_url}?access_token={access_token}"
|
||||||
|
|
||||||
payload = json.dumps(
|
payload = json.dumps(
|
||||||
@ -232,6 +273,34 @@ def _generate_response(prompt: str) -> str:
|
|||||||
api_version=api_version,
|
api_version=api_version,
|
||||||
azure_endpoint=base_url,
|
azure_endpoint=base_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if llm_provider == "modelscope":
|
||||||
|
content = ''
|
||||||
|
client = OpenAI(
|
||||||
|
api_key=api_key,
|
||||||
|
base_url=base_url,
|
||||||
|
)
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model=model_name,
|
||||||
|
messages=[{"role": "user", "content": prompt}],
|
||||||
|
extra_body={"enable_thinking": False},
|
||||||
|
stream=True
|
||||||
|
)
|
||||||
|
if response:
|
||||||
|
for chunk in response:
|
||||||
|
if not chunk.choices:
|
||||||
|
continue
|
||||||
|
delta = chunk.choices[0].delta
|
||||||
|
if delta and delta.content:
|
||||||
|
content += delta.content
|
||||||
|
|
||||||
|
if not content.strip():
|
||||||
|
raise ValueError("Empty content in stream response")
|
||||||
|
|
||||||
|
return content.replace("\n", "")
|
||||||
|
else:
|
||||||
|
raise Exception(f"[{llm_provider}] returned an empty response")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
client = OpenAI(
|
client = OpenAI(
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
@ -409,3 +478,4 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
print("######################")
|
print("######################")
|
||||||
print(search_terms)
|
print(search_terms)
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,10 @@ import os.path
|
|||||||
import re
|
import re
|
||||||
from timeit import default_timer as timer
|
from timeit import default_timer as timer
|
||||||
|
|
||||||
from faster_whisper import WhisperModel
|
try:
|
||||||
|
from faster_whisper import WhisperModel
|
||||||
|
except ImportError:
|
||||||
|
WhisperModel = None
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from app.config import config
|
from app.config import config
|
||||||
@ -17,6 +20,9 @@ model = None
|
|||||||
|
|
||||||
def create(audio_file, subtitle_file: str = ""):
|
def create(audio_file, subtitle_file: str = ""):
|
||||||
global model
|
global model
|
||||||
|
if WhisperModel is None:
|
||||||
|
logger.warning("faster_whisper not available, skipping whisper subtitle generation")
|
||||||
|
return ""
|
||||||
if not model:
|
if not model:
|
||||||
model_path = f"{utils.root_dir()}/models/whisper-{model_size}"
|
model_path = f"{utils.root_dir()}/models/whisper-{model_size}"
|
||||||
model_bin_file = f"{model_path}/model.bin"
|
model_bin_file = f"{model_path}/model.bin"
|
||||||
|
|||||||
@ -71,30 +71,66 @@ def save_script_data(task_id, video_script, video_terms, params):
|
|||||||
|
|
||||||
|
|
||||||
def generate_audio(task_id, params, video_script):
|
def generate_audio(task_id, params, video_script):
|
||||||
|
'''
|
||||||
|
Generate audio for the video script.
|
||||||
|
If a custom audio file is provided, it will be used directly.
|
||||||
|
There will be no subtitle maker object returned in this case.
|
||||||
|
Otherwise, TTS will be used to generate the audio.
|
||||||
|
Returns:
|
||||||
|
- audio_file: path to the generated or provided audio file
|
||||||
|
- audio_duration: duration of the audio in seconds
|
||||||
|
- sub_maker: subtitle maker object if TTS is used, None otherwise
|
||||||
|
'''
|
||||||
logger.info("\n\n## generating audio")
|
logger.info("\n\n## generating audio")
|
||||||
audio_file = path.join(utils.task_dir(task_id), "audio.mp3")
|
custom_audio_file = params.custom_audio_file
|
||||||
sub_maker = voice.tts(
|
if not custom_audio_file or not os.path.exists(custom_audio_file):
|
||||||
text=video_script,
|
if custom_audio_file:
|
||||||
voice_name=voice.parse_voice_name(params.voice_name),
|
logger.warning(
|
||||||
voice_rate=params.voice_rate,
|
f"custom audio file not found: {custom_audio_file}, using TTS to generate audio."
|
||||||
voice_file=audio_file,
|
)
|
||||||
)
|
else:
|
||||||
if sub_maker is None:
|
logger.info("no custom audio file provided, using TTS to generate audio.")
|
||||||
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
audio_file = path.join(utils.task_dir(task_id), "audio.mp3")
|
||||||
logger.error(
|
sub_maker = voice.tts(
|
||||||
"""failed to generate audio:
|
text=video_script,
|
||||||
|
voice_name=voice.parse_voice_name(params.voice_name),
|
||||||
|
voice_rate=params.voice_rate,
|
||||||
|
voice_file=audio_file,
|
||||||
|
)
|
||||||
|
if sub_maker is None:
|
||||||
|
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
|
logger.error(
|
||||||
|
"""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))
|
if audio_duration == 0:
|
||||||
return audio_file, audio_duration, sub_maker
|
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
|
logger.error("failed to get audio duration.")
|
||||||
|
return None, None, None
|
||||||
|
return audio_file, audio_duration, sub_maker
|
||||||
|
else:
|
||||||
|
logger.info(f"using custom audio file: {custom_audio_file}")
|
||||||
|
audio_duration = voice.get_audio_duration(custom_audio_file)
|
||||||
|
if audio_duration == 0:
|
||||||
|
sm.state.update_task(task_id, state=const.TASK_STATE_FAILED)
|
||||||
|
logger.error("failed to get audio duration from custom audio file.")
|
||||||
|
return None, None, None
|
||||||
|
return custom_audio_file, audio_duration, None
|
||||||
|
|
||||||
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:
|
'''
|
||||||
|
Generate subtitle for the video script.
|
||||||
|
If subtitle generation is disabled or no subtitle maker is provided, it will return an empty string.
|
||||||
|
Otherwise, it will generate the subtitle using the specified provider.
|
||||||
|
Returns:
|
||||||
|
- subtitle_path: path to the generated subtitle file
|
||||||
|
'''
|
||||||
|
logger.info("\n\n## generating subtitle")
|
||||||
|
if not params.subtitle_enabled or sub_maker is None:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
subtitle_path = path.join(utils.task_dir(task_id), "subtitle.srt")
|
subtitle_path = path.join(utils.task_dir(task_id), "subtitle.srt")
|
||||||
|
|||||||
@ -193,9 +193,6 @@ def combine_videos(
|
|||||||
clip_resized = clip.resized(new_size=(new_width, new_height)).with_position("center")
|
clip_resized = clip.resized(new_size=(new_width, new_height)).with_position("center")
|
||||||
clip = CompositeVideoClip([background, clip_resized])
|
clip = CompositeVideoClip([background, clip_resized])
|
||||||
|
|
||||||
close_clip(clip_resized)
|
|
||||||
close_clip(background)
|
|
||||||
|
|
||||||
shuffle_side = random.choice(["left", "right", "top", "bottom"])
|
shuffle_side = random.choice(["left", "right", "top", "bottom"])
|
||||||
if video_transition_mode.value == VideoTransitionMode.none.value:
|
if video_transition_mode.value == VideoTransitionMode.none.value:
|
||||||
clip = clip
|
clip = clip
|
||||||
|
|||||||
@ -11,6 +11,7 @@ from edge_tts import SubMaker, submaker
|
|||||||
from edge_tts.submaker import mktimestamp
|
from edge_tts.submaker import mktimestamp
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from moviepy.video.tools import subtitles
|
from moviepy.video.tools import subtitles
|
||||||
|
from moviepy.audio.io.AudioFileClip import AudioFileClip
|
||||||
|
|
||||||
from app.config import config
|
from app.config import config
|
||||||
from app.utils import utils
|
from app.utils import utils
|
||||||
@ -42,6 +43,39 @@ def get_siliconflow_voices() -> list[str]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_gemini_voices() -> list[str]:
|
||||||
|
"""
|
||||||
|
获取Gemini TTS的声音列表
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
声音列表,格式为 ["gemini:Zephyr-Female", "gemini:Puck-Male", ...]
|
||||||
|
"""
|
||||||
|
# Gemini TTS支持的语音列表
|
||||||
|
voices_with_gender = [
|
||||||
|
("Zephyr", "Female"),
|
||||||
|
("Puck", "Male"),
|
||||||
|
("Charon", "Male"),
|
||||||
|
("Kore", "Female"),
|
||||||
|
("Fenrir", "Male"),
|
||||||
|
("Aoede", "Female"),
|
||||||
|
("Thalia", "Female"),
|
||||||
|
("Sage", "Male"),
|
||||||
|
("Echo", "Female"),
|
||||||
|
("Harmony", "Female"),
|
||||||
|
("Lux", "Female"),
|
||||||
|
("Nova", "Female"),
|
||||||
|
("Vale", "Male"),
|
||||||
|
("Orion", "Male"),
|
||||||
|
("Atlas", "Male"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# 添加gemini:前缀,并格式化为显示名称
|
||||||
|
return [
|
||||||
|
f"gemini:{voice}-{gender}"
|
||||||
|
for voice, gender in voices_with_gender
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_all_azure_voices(filter_locals=None) -> list[str]:
|
def get_all_azure_voices(filter_locals=None) -> list[str]:
|
||||||
azure_voices_str = """
|
azure_voices_str = """
|
||||||
Name: af-ZA-AdriNeural
|
Name: af-ZA-AdriNeural
|
||||||
@ -1077,6 +1111,11 @@ def is_siliconflow_voice(voice_name: str):
|
|||||||
return voice_name.startswith("siliconflow:")
|
return voice_name.startswith("siliconflow:")
|
||||||
|
|
||||||
|
|
||||||
|
def is_gemini_voice(voice_name: str):
|
||||||
|
"""检查是否是Gemini TTS的声音"""
|
||||||
|
return voice_name.startswith("gemini:")
|
||||||
|
|
||||||
|
|
||||||
def tts(
|
def tts(
|
||||||
text: str,
|
text: str,
|
||||||
voice_name: str,
|
voice_name: str,
|
||||||
@ -1103,6 +1142,18 @@ def tts(
|
|||||||
else:
|
else:
|
||||||
logger.error(f"Invalid siliconflow voice name format: {voice_name}")
|
logger.error(f"Invalid siliconflow voice name format: {voice_name}")
|
||||||
return None
|
return None
|
||||||
|
elif is_gemini_voice(voice_name):
|
||||||
|
# 从voice_name中提取声音名称
|
||||||
|
# 格式: gemini:voice-Gender
|
||||||
|
parts = voice_name.split(":")
|
||||||
|
if len(parts) >= 2:
|
||||||
|
# 移除性别后缀,例如 "Zephyr-Female" -> "Zephyr"
|
||||||
|
voice_with_gender = parts[1]
|
||||||
|
voice = voice_with_gender.split("-")[0]
|
||||||
|
return gemini_tts(text, voice, voice_rate, voice_file, voice_volume)
|
||||||
|
else:
|
||||||
|
logger.error(f"Invalid gemini voice name format: {voice_name}")
|
||||||
|
return None
|
||||||
return azure_tts_v1(text, voice_name, voice_rate, voice_file)
|
return azure_tts_v1(text, voice_name, voice_rate, voice_file)
|
||||||
|
|
||||||
|
|
||||||
@ -1337,6 +1388,10 @@ def azure_tts_v2(text: str, voice_name: str, voice_file: str) -> Union[SubMaker,
|
|||||||
# Creates an instance of a speech config with specified subscription key and service region.
|
# Creates an instance of a speech config with specified subscription key and service region.
|
||||||
speech_key = config.azure.get("speech_key", "")
|
speech_key = config.azure.get("speech_key", "")
|
||||||
service_region = config.azure.get("speech_region", "")
|
service_region = config.azure.get("speech_region", "")
|
||||||
|
if not speech_key or not service_region:
|
||||||
|
logger.error("Azure speech key or region is not set")
|
||||||
|
return None
|
||||||
|
|
||||||
audio_config = speechsdk.audio.AudioOutputConfig(
|
audio_config = speechsdk.audio.AudioOutputConfig(
|
||||||
filename=voice_file, use_default_speaker=True
|
filename=voice_file, use_default_speaker=True
|
||||||
)
|
)
|
||||||
@ -1380,6 +1435,130 @@ def azure_tts_v2(text: str, voice_name: str, voice_file: str) -> Union[SubMaker,
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def gemini_tts(
|
||||||
|
text: str,
|
||||||
|
voice_name: str,
|
||||||
|
voice_rate: float,
|
||||||
|
voice_file: str,
|
||||||
|
voice_volume: float = 1.0,
|
||||||
|
) -> Union[SubMaker, None]:
|
||||||
|
"""
|
||||||
|
使用Google Gemini TTS生成语音
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: 要转换的文本
|
||||||
|
voice_name: 语音名称,如 "Zephyr", "Puck" 等
|
||||||
|
voice_rate: 语音速率(当前未使用)
|
||||||
|
voice_file: 输出音频文件路径
|
||||||
|
voice_volume: 音频音量(当前未使用)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SubMaker对象或None
|
||||||
|
"""
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import io
|
||||||
|
from pydub import AudioSegment
|
||||||
|
import google.generativeai as genai
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 配置Gemini API
|
||||||
|
api_key = config.app.get("gemini_api_key", "")
|
||||||
|
if not api_key:
|
||||||
|
logger.error("Gemini API key is not set")
|
||||||
|
return None
|
||||||
|
|
||||||
|
genai.configure(api_key=api_key)
|
||||||
|
|
||||||
|
logger.info(f"start, voice name: {voice_name}, try: 1")
|
||||||
|
|
||||||
|
# 使用Gemini TTS API
|
||||||
|
model = genai.GenerativeModel("gemini-2.5-flash-preview-tts")
|
||||||
|
|
||||||
|
generation_config = {
|
||||||
|
"response_modalities": ["AUDIO"],
|
||||||
|
"speech_config": {
|
||||||
|
"voice_config": {
|
||||||
|
"prebuilt_voice_config": {
|
||||||
|
"voice_name": voice_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = model.generate_content(
|
||||||
|
contents=text,
|
||||||
|
generation_config=generation_config
|
||||||
|
)
|
||||||
|
|
||||||
|
# 检查响应
|
||||||
|
if not response.candidates or not response.candidates[0].content:
|
||||||
|
logger.error("No audio content received from Gemini TTS")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 获取音频数据
|
||||||
|
audio_data = None
|
||||||
|
for part in response.candidates[0].content.parts:
|
||||||
|
if hasattr(part, 'inline_data') and part.inline_data:
|
||||||
|
audio_data = part.inline_data.data
|
||||||
|
break
|
||||||
|
|
||||||
|
if not audio_data:
|
||||||
|
logger.error("No audio data found in response")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 音频数据已经是原始字节,不需要base64解码
|
||||||
|
if isinstance(audio_data, str):
|
||||||
|
# 如果是字符串,则需要base64解码
|
||||||
|
audio_bytes = base64.b64decode(audio_data)
|
||||||
|
else:
|
||||||
|
# 如果已经是字节,直接使用
|
||||||
|
audio_bytes = audio_data
|
||||||
|
|
||||||
|
# 尝试不同的音频格式 - Gemini可能返回不同的格式
|
||||||
|
audio_segment = None
|
||||||
|
|
||||||
|
# Gemini返回Linear PCM格式,按照文档参数解析
|
||||||
|
try:
|
||||||
|
audio_segment = AudioSegment.from_file(
|
||||||
|
io.BytesIO(audio_bytes),
|
||||||
|
format="raw",
|
||||||
|
frame_rate=24000, # Gemini TTS默认采样率
|
||||||
|
channels=1, # 单声道
|
||||||
|
sample_width=2 # 16-bit
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to load PCM audio: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 导出为MP3格式
|
||||||
|
audio_segment.export(voice_file, format="mp3")
|
||||||
|
|
||||||
|
logger.info(f"completed, output file: {voice_file}")
|
||||||
|
|
||||||
|
# 创建SubMaker对象用于字幕
|
||||||
|
sub_maker = SubMaker()
|
||||||
|
audio_duration = len(audio_segment) / 1000.0 # 转换为秒
|
||||||
|
|
||||||
|
# 将音频长度转换为100纳秒单位(与edge_tts兼容)
|
||||||
|
audio_duration_100ns = int(audio_duration * 10000000)
|
||||||
|
|
||||||
|
# 使用create_sub方法正确创建字幕项
|
||||||
|
sub_maker.create_sub(
|
||||||
|
(0, audio_duration_100ns),
|
||||||
|
text
|
||||||
|
)
|
||||||
|
|
||||||
|
return sub_maker
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
|
logger.error(f"Missing required package for Gemini TTS: {str(e)}. Please install: pip install pydub")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Gemini TTS failed, error: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _format_text(text: str) -> str:
|
def _format_text(text: str) -> str:
|
||||||
# text = text.replace("\n", " ")
|
# text = text.replace("\n", " ")
|
||||||
text = text.replace("[", " ")
|
text = text.replace("[", " ")
|
||||||
@ -1482,7 +1661,7 @@ def create_subtitle(sub_maker: submaker.SubMaker, text: str, subtitle_file: str)
|
|||||||
logger.error(f"failed, error: {str(e)}")
|
logger.error(f"failed, error: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
def get_audio_duration(sub_maker: submaker.SubMaker):
|
def _get_audio_duration_from_submaker(sub_maker: submaker.SubMaker):
|
||||||
"""
|
"""
|
||||||
获取音频时长
|
获取音频时长
|
||||||
"""
|
"""
|
||||||
@ -1490,6 +1669,35 @@ def get_audio_duration(sub_maker: submaker.SubMaker):
|
|||||||
return 0.0
|
return 0.0
|
||||||
return sub_maker.offset[-1][1] / 10000000
|
return sub_maker.offset[-1][1] / 10000000
|
||||||
|
|
||||||
|
def _get_audio_duration_from_mp3(mp3_file: str) -> float:
|
||||||
|
"""
|
||||||
|
获取MP3音频时长
|
||||||
|
"""
|
||||||
|
if not os.path.exists(mp3_file):
|
||||||
|
logger.error(f"MP3 file does not exist: {mp3_file}")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use moviepy to get the duration of the MP3 file
|
||||||
|
with AudioFileClip(mp3_file) as audio:
|
||||||
|
return audio.duration # Duration in seconds
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to get audio duration from MP3: {str(e)}")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
def get_audio_duration( target: Union[str, submaker.SubMaker]) -> float:
|
||||||
|
"""
|
||||||
|
获取音频时长
|
||||||
|
如果是SubMaker对象,则从SubMaker中获取时长
|
||||||
|
如果是MP3文件,则从MP3文件中获取时长
|
||||||
|
"""
|
||||||
|
if isinstance(target, submaker.SubMaker):
|
||||||
|
return _get_audio_duration_from_submaker(target)
|
||||||
|
elif isinstance(target, str) and target.endswith(".mp3"):
|
||||||
|
return _get_audio_duration_from_mp3(target)
|
||||||
|
else:
|
||||||
|
logger.error(f"Invalid target type: {type(target)}")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
voice_name = "zh-CN-XiaoxiaoMultilingualNeural-V2-Female"
|
voice_name = "zh-CN-XiaoxiaoMultilingualNeural-V2-Female"
|
||||||
|
|||||||
17
changelog.py
@ -1,17 +0,0 @@
|
|||||||
from git_changelog.cli import build_and_render
|
|
||||||
|
|
||||||
# 运行这段脚本自动生成CHANGELOG.md文件
|
|
||||||
|
|
||||||
build_and_render(
|
|
||||||
repository=".",
|
|
||||||
output="CHANGELOG.md",
|
|
||||||
convention="angular",
|
|
||||||
provider="github",
|
|
||||||
template="keepachangelog",
|
|
||||||
parse_trailers=True,
|
|
||||||
parse_refs=False,
|
|
||||||
sections=["build", "deps", "feat", "fix", "refactor"],
|
|
||||||
versioning="pep440",
|
|
||||||
bump="1.1.2", # 指定bump版本
|
|
||||||
in_place=True,
|
|
||||||
)
|
|
||||||
@ -30,8 +30,18 @@ pixabay_api_keys = []
|
|||||||
# oneapi
|
# oneapi
|
||||||
# cloudflare
|
# cloudflare
|
||||||
# ernie (文心一言)
|
# ernie (文心一言)
|
||||||
|
# modelscope (魔搭社区)
|
||||||
llm_provider = "openai"
|
llm_provider = "openai"
|
||||||
|
|
||||||
|
########## Pollinations AI Settings
|
||||||
|
# Visit https://pollinations.ai/ to learn more
|
||||||
|
# API Key is optional - leave empty for public access
|
||||||
|
pollinations_api_key = ""
|
||||||
|
# Default base URL for Pollinations API
|
||||||
|
pollinations_base_url = "https://pollinations.ai/api/v1"
|
||||||
|
# Default model for text generation
|
||||||
|
pollinations_model_name = "openai-fast"
|
||||||
|
|
||||||
########## Ollama Settings
|
########## Ollama Settings
|
||||||
# No need to set it unless you want to use your own proxy
|
# No need to set it unless you want to use your own proxy
|
||||||
ollama_base_url = ""
|
ollama_base_url = ""
|
||||||
@ -90,6 +100,14 @@ deepseek_api_key = ""
|
|||||||
deepseek_base_url = "https://api.deepseek.com"
|
deepseek_base_url = "https://api.deepseek.com"
|
||||||
deepseek_model_name = "deepseek-chat"
|
deepseek_model_name = "deepseek-chat"
|
||||||
|
|
||||||
|
|
||||||
|
########## ModelScope API Key
|
||||||
|
# Visit https://modelscope.cn/docs/model-service/API-Inference/intro to get your API key
|
||||||
|
# And note that you need to bind your Alibaba Cloud account before using the API.
|
||||||
|
modelscope_api_key = ""
|
||||||
|
modelscope_base_url = "https://api-inference.modelscope.cn/v1/"
|
||||||
|
modelscope_model_name = "Qwen/Qwen3-32B"
|
||||||
|
|
||||||
# Subtitle Provider, "edge" or "whisper"
|
# Subtitle Provider, "edge" or "whisper"
|
||||||
# If empty, the subtitle will not be generated
|
# If empty, the subtitle will not be generated
|
||||||
subtitle_provider = "edge"
|
subtitle_provider = "edge"
|
||||||
|
|||||||
118
docs/MoneyPrinterTurbo.ipynb
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# MoneyPrinterTurbo Setup Guide\n",
|
||||||
|
"\n",
|
||||||
|
"This notebook will guide you through the process of setting up [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## 1. Clone Repository and Install Dependencies\n",
|
||||||
|
"\n",
|
||||||
|
"First, we'll clone the repository from GitHub and install all required packages:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {
|
||||||
|
"id": "S8Eu-aQarY_B"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!git clone https://github.com/harry0703/MoneyPrinterTurbo.git\n",
|
||||||
|
"%cd MoneyPrinterTurbo\n",
|
||||||
|
"!pip install -q -r requirements.txt\n",
|
||||||
|
"!pip install pyngrok --quiet"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## 2. Configure ngrok for Remote Access\n",
|
||||||
|
"\n",
|
||||||
|
"We'll use ngrok to create a secure tunnel to expose our local Streamlit server to the internet.\n",
|
||||||
|
"\n",
|
||||||
|
"**Important**: You need to get your authentication token from the [ngrok dashboard](https://dashboard.ngrok.com/get-started/your-authtoken) to use this service."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from pyngrok import ngrok\n",
|
||||||
|
"\n",
|
||||||
|
"# Terminate any existing ngrok tunnels\n",
|
||||||
|
"ngrok.kill()\n",
|
||||||
|
"\n",
|
||||||
|
"# Set your authentication token\n",
|
||||||
|
"# Replace \"your_ngrok_auth_token\" with your actual token\n",
|
||||||
|
"ngrok.set_auth_token(\"your_ngrok_auth_token\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## 3. Launch Application and Generate Public URL\n",
|
||||||
|
"\n",
|
||||||
|
"Now we'll start the Streamlit server and create an ngrok tunnel to make it accessible online:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {
|
||||||
|
"base_uri": "https://localhost:8080/"
|
||||||
|
},
|
||||||
|
"collapsed": true,
|
||||||
|
"id": "oahsIOXmwjl9",
|
||||||
|
"outputId": "ee23a96c-af21-4207-deb7-9fab69e0c05e"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import subprocess\n",
|
||||||
|
"import time\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"🚀 Starting MoneyPrinterTurbo...\")\n",
|
||||||
|
"# Start Streamlit server on port 8501\n",
|
||||||
|
"streamlit_proc = subprocess.Popen([\n",
|
||||||
|
" \"streamlit\", \"run\", \"./webui/Main.py\", \"--server.port=8501\"\n",
|
||||||
|
"])\n",
|
||||||
|
"\n",
|
||||||
|
"# Wait for the server to initialize\n",
|
||||||
|
"time.sleep(5)\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"🌐 Creating ngrok tunnel to expose the MoneyPrinterTurbo...\")\n",
|
||||||
|
"public_url = ngrok.connect(8501, bind_tls=True)\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"✅ Deployment complete! Access your MoneyPrinterTurbo at:\")\n",
|
||||||
|
"print(public_url)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"colab": {
|
||||||
|
"provenance": []
|
||||||
|
},
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"name": "python"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 0
|
||||||
|
}
|
||||||
BIN
docs/picwish.com.jpg
Normal file
|
After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 667 KiB |
BIN
docs/webui.jpg
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 654 KiB |
|
Before Width: | Height: | Size: 137 KiB |
@ -1,32 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "MoneyPrinterTurbo"
|
|
||||||
version = "1.2.3"
|
|
||||||
description = "Default template for PDM package"
|
|
||||||
authors = [
|
|
||||||
{name = "yyhhyyyyyy", email = "yyhhyyyyyy8@gmail.com"},
|
|
||||||
]
|
|
||||||
dependencies = [
|
|
||||||
"moviepy==2.1.1",
|
|
||||||
"streamlit==1.40.2",
|
|
||||||
"edge-tts==6.1.19",
|
|
||||||
"fastapi==0.115.6",
|
|
||||||
"uvicorn==0.32.1",
|
|
||||||
"openai==1.56.1",
|
|
||||||
"faster-whisper==1.1.0",
|
|
||||||
"loguru==0.7.2",
|
|
||||||
"google-generativeai==0.8.3",
|
|
||||||
"dashscope==1.20.14",
|
|
||||||
"g4f==0.3.8.1",
|
|
||||||
"azure-cognitiveservices-speech==1.41.1",
|
|
||||||
"redis==5.2.0",
|
|
||||||
"python-multipart==0.0.19",
|
|
||||||
"streamlit-authenticator==0.4.1",
|
|
||||||
"pyyaml",
|
|
||||||
]
|
|
||||||
requires-python = "==3.11.*"
|
|
||||||
readme = "README.md"
|
|
||||||
license = {text = "MIT"}
|
|
||||||
|
|
||||||
|
|
||||||
[tool.pdm]
|
|
||||||
distribution = false
|
|
||||||
@ -12,4 +12,5 @@ g4f==0.5.2.2
|
|||||||
azure-cognitiveservices-speech==1.41.1
|
azure-cognitiveservices-speech==1.41.1
|
||||||
redis==5.2.0
|
redis==5.2.0
|
||||||
python-multipart==0.0.19
|
python-multipart==0.0.19
|
||||||
pyyaml
|
pyyaml
|
||||||
|
requests>=2.31.0
|
||||||
|
|||||||
BIN
resource/fonts/Charm-Bold.ttf
Normal file
BIN
resource/fonts/Charm-Regular.ttf
Normal file
@ -1,208 +0,0 @@
|
|||||||
import { viteBundler } from "@vuepress/bundler-vite";
|
|
||||||
import { defaultTheme } from "@vuepress/theme-default";
|
|
||||||
import { defineUserConfig } from "vuepress";
|
|
||||||
|
|
||||||
const base = "MoneyPrinterTurbo";
|
|
||||||
const isProd = process.env.NODE_ENV === "production";
|
|
||||||
|
|
||||||
export default defineUserConfig({
|
|
||||||
lang: "zh-CN",
|
|
||||||
base: `/${base}/`,
|
|
||||||
bundler: viteBundler(),
|
|
||||||
theme: defaultTheme({
|
|
||||||
repo: "harry0703/MoneyPrinterTurbo",
|
|
||||||
docsDir: "sites/docs",
|
|
||||||
colorModeSwitch: true,
|
|
||||||
locales: {
|
|
||||||
"/": {
|
|
||||||
// navbar
|
|
||||||
navbar: [
|
|
||||||
{ text: "Guide", link: "/guide/" },
|
|
||||||
// { text: "Components", link: "/components/" },
|
|
||||||
],
|
|
||||||
selectLanguageText: "Languages",
|
|
||||||
selectLanguageName: "English",
|
|
||||||
selectLanguageAriaLabel: "Select language",
|
|
||||||
// sidebar
|
|
||||||
sidebar: {
|
|
||||||
"/guide/": [
|
|
||||||
{
|
|
||||||
text: "Guide",
|
|
||||||
children: [
|
|
||||||
{ text: "Get Started", link: "/guide/README.md" },
|
|
||||||
{ text: "Video Demonstration", link: "/guide/video-demonstration.md" },
|
|
||||||
{ text: "Features", link: "/guide/features.md" },
|
|
||||||
{ text: "Speech Synthesis", link: "/guide/speech-synthesis.md" },
|
|
||||||
{ text: "Subtitle Generation", link: "/guide/subtitle-generation.md" },
|
|
||||||
{ text: "Background Music", link: "/guide/background-music.md" },
|
|
||||||
{ text: "Subtitle Font", link: "/guide/subtitle-font.md" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: "Others",
|
|
||||||
children: [
|
|
||||||
{ text: "FAQ", link: "/guide/faq.md" },
|
|
||||||
{ text: "Feedback", link: "/guide/feedback.md" },
|
|
||||||
{ text: "Reference Project", link: "/guide/reference-project.md" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// "/components/": getComponentsSidebar("Components", "Advanced"),
|
|
||||||
},
|
|
||||||
// page meta
|
|
||||||
editLinkText: "Edit this page on GitHub",
|
|
||||||
},
|
|
||||||
"/zh/": {
|
|
||||||
// navbar
|
|
||||||
navbar: [
|
|
||||||
{ text: "指南", link: "/zh/guide/" },
|
|
||||||
// { text: "组件", link: "/zh/components/" },
|
|
||||||
],
|
|
||||||
selectLanguageText: "选择语言",
|
|
||||||
selectLanguageName: "简体中文",
|
|
||||||
selectLanguageAriaLabel: "选择语言",
|
|
||||||
// sidebar
|
|
||||||
sidebar: {
|
|
||||||
"/zh/guide/": [
|
|
||||||
{
|
|
||||||
text: "指南",
|
|
||||||
children: [
|
|
||||||
{ text: "快速开始", link: "/zh/guide/README.md" },
|
|
||||||
{ text: "配置要求", link: "/zh/guide/configuration-requirements.md" },
|
|
||||||
{ text: "视频演示", link: "/zh/guide/video-demonstration.md" },
|
|
||||||
{ text: "功能", link: "/zh/guide/features.md" },
|
|
||||||
{ text: "语音合成", link: "/zh/guide/speech-synthesis.md" },
|
|
||||||
{ text: "字幕生成", link: "/zh/guide/subtitle-generation.md" },
|
|
||||||
{ text: "背景音乐", link: "/zh/guide/background-music.md" },
|
|
||||||
{ text: "字幕字体", link: "/zh/guide/subtitle-font.md" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: "其他",
|
|
||||||
children: [
|
|
||||||
{ text: "常见问题", link: "/zh/guide/faq.md" },
|
|
||||||
{ text: "反馈建议", link: "/zh/guide/feedback.md" },
|
|
||||||
{ text: "参考项目", link: "/zh/guide/reference-project.md" },
|
|
||||||
{ text: "特别感谢", link: "/zh/guide/special-thanks.md" },
|
|
||||||
{ text: "感谢赞助", link: "/zh/guide/thanks-for-sponsoring" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// "/zh/others/": getComponentsSidebar("组件", "高级"),
|
|
||||||
},
|
|
||||||
// page meta
|
|
||||||
editLinkText: "在 GitHub 上编辑此页",
|
|
||||||
lastUpdatedText: "上次更新",
|
|
||||||
contributorsText: "贡献者",
|
|
||||||
// custom containers
|
|
||||||
tip: "提示",
|
|
||||||
warning: "注意",
|
|
||||||
danger: "警告",
|
|
||||||
// 404 page
|
|
||||||
notFound: [
|
|
||||||
"这里什么都没有",
|
|
||||||
"我们怎么到这来了?",
|
|
||||||
"这是一个 404 页面",
|
|
||||||
"看起来我们进入了错误的链接",
|
|
||||||
],
|
|
||||||
backToHome: "返回首页",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
themePlugins: {
|
|
||||||
// only enable git plugin in production mode
|
|
||||||
git: isProd,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
locales: {
|
|
||||||
"/": {
|
|
||||||
lang: "en-US",
|
|
||||||
title: "MoneyPrinterTurbo",
|
|
||||||
description: "Generate short videos with one click using AI LLM.",
|
|
||||||
},
|
|
||||||
"/zh/": {
|
|
||||||
lang: "zh-CN",
|
|
||||||
title: "MoneyPrinterTurbo",
|
|
||||||
description: "利用AI大模型,一键生成高清短视频。",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
head: [
|
|
||||||
[
|
|
||||||
"link",
|
|
||||||
{
|
|
||||||
rel: "icon",
|
|
||||||
type: "image/png",
|
|
||||||
sizes: "16x16",
|
|
||||||
href: `/${base}/icons/favicon-16x16.png`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"link",
|
|
||||||
{
|
|
||||||
rel: "icon",
|
|
||||||
type: "image/png",
|
|
||||||
sizes: "32x32",
|
|
||||||
href: `/${base}/icons/favicon-32x32.png`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
["meta", { name: "application-name", content: "MoneyPrinterTurbo" }],
|
|
||||||
[
|
|
||||||
"meta",
|
|
||||||
{ name: "apple-mobile-web-app-title", content: "MoneyPrinterTurbo" },
|
|
||||||
],
|
|
||||||
["meta", { name: "apple-mobile-web-app-capable", content: "yes" }],
|
|
||||||
[
|
|
||||||
"meta",
|
|
||||||
{ name: "apple-mobile-web-app-status-bar-style", content: "black" },
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"link",
|
|
||||||
{
|
|
||||||
rel: "apple-touch-icon",
|
|
||||||
href: `/${base}/icons/apple-touch-icon-152x152.png`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"link",
|
|
||||||
{
|
|
||||||
rel: "mask-icon",
|
|
||||||
href: "/${base}/icons/safari-pinned-tab.svg",
|
|
||||||
color: "#3eaf7c",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"meta",
|
|
||||||
{
|
|
||||||
name: "msapplication-TileImage",
|
|
||||||
content: "/${base}/icons/msapplication-icon-144x144.png",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
["meta", { name: "msapplication-TileColor", content: "#000000" }],
|
|
||||||
["meta", { name: "theme-color", content: "#3eaf7c" }],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
function getGuideSidebar(groupA: string, groupB: string) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
text: groupA,
|
|
||||||
children: ["README.md", { text: "特别感谢", link: "/zh/guide/special-thanks.md" }, "2.md"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: groupB,
|
|
||||||
children: ["custom-validator.md", "1.md", "2.md", "3.md"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getComponentsSidebar(groupA: string, groupB: string) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
text: groupA,
|
|
||||||
children: ["README.md", "1.md", "2.md"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: groupB,
|
|
||||||
children: ["custom-components.md"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
@ -1,149 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000"
|
|
||||||
preserveAspectRatio="xMidYMid meet">
|
|
||||||
<metadata>
|
|
||||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
|
||||||
</metadata>
|
|
||||||
<g transform="translate(0.000000,16.000000) scale(0.000320,-0.000320)"
|
|
||||||
fill="#000000" stroke="none">
|
|
||||||
<path d="M18 46618 c45 -75 122 -207 122 -211 0 -2 25 -45 55 -95 30 -50 55
|
|
||||||
-96 55 -102 0 -5 5 -10 10 -10 6 0 10 -4 10 -9 0 -5 73 -135 161 -288 89 -153
|
|
||||||
173 -298 187 -323 14 -25 32 -57 41 -72 88 -149 187 -324 189 -335 2 -7 8 -13
|
|
||||||
13 -13 5 0 9 -4 9 -10 0 -5 46 -89 103 -187 175 -302 490 -846 507 -876 8 -16
|
|
||||||
20 -36 25 -45 28 -46 290 -498 339 -585 13 -23 74 -129 136 -236 61 -107 123
|
|
||||||
-215 137 -240 14 -25 29 -50 33 -56 5 -5 23 -37 40 -70 18 -33 38 -67 44 -75
|
|
||||||
11 -16 21 -33 63 -109 14 -25 29 -50 33 -56 4 -5 21 -35 38 -65 55 -100 261
|
|
||||||
-455 269 -465 4 -5 14 -21 20 -35 15 -29 41 -75 103 -180 24 -41 52 -88 60
|
|
||||||
-105 9 -16 57 -100 107 -185 112 -193 362 -626 380 -660 8 -14 23 -38 33 -55
|
|
||||||
11 -16 23 -37 27 -45 4 -8 26 -46 48 -85 23 -38 53 -90 67 -115 46 -81 64
|
|
||||||
-113 178 -310 62 -107 121 -210 132 -227 37 -67 56 -99 85 -148 16 -27 32 -57
|
|
||||||
36 -65 4 -8 15 -27 25 -42 9 -15 53 -89 96 -165 44 -76 177 -307 296 -513 120
|
|
||||||
-206 268 -463 330 -570 131 -227 117 -203 200 -348 36 -62 73 -125 82 -140 10
|
|
||||||
-15 21 -34 25 -42 4 -8 20 -37 36 -65 17 -27 38 -65 48 -82 49 -85 64 -111 87
|
|
||||||
-153 13 -25 28 -49 32 -55 4 -5 78 -134 165 -285 87 -151 166 -288 176 -305
|
|
||||||
10 -16 26 -43 35 -59 9 -17 125 -217 257 -445 132 -229 253 -441 270 -471 17
|
|
||||||
-30 45 -79 64 -108 18 -29 33 -54 33 -57 0 -2 20 -37 44 -77 24 -40 123 -212
|
|
||||||
221 -383 97 -170 190 -330 205 -355 16 -25 39 -65 53 -90 13 -25 81 -144 152
|
|
||||||
-265 70 -121 137 -238 150 -260 12 -22 37 -65 55 -95 18 -30 43 -73 55 -95 12
|
|
||||||
-22 48 -85 80 -140 77 -132 163 -280 190 -330 13 -22 71 -123 130 -225 59
|
|
||||||
-102 116 -199 126 -217 10 -17 29 -50 43 -72 15 -22 26 -43 26 -45 0 -2 27
|
|
||||||
-50 60 -106 33 -56 60 -103 60 -105 0 -2 55 -98 90 -155 8 -14 182 -316 239
|
|
||||||
-414 13 -22 45 -79 72 -124 27 -46 49 -86 49 -89 0 -2 14 -24 30 -48 16 -24
|
|
||||||
30 -46 30 -49 0 -5 74 -135 100 -176 5 -8 24 -42 43 -75 50 -88 58 -101 262
|
|
||||||
-455 104 -179 199 -345 213 -370 14 -25 28 -49 32 -55 4 -5 17 -26 28 -45 10
|
|
||||||
-19 62 -109 114 -200 114 -197 133 -230 170 -295 16 -27 33 -57 38 -65 17 -28
|
|
||||||
96 -165 103 -180 4 -8 16 -28 26 -45 10 -16 77 -131 148 -255 72 -124 181
|
|
||||||
-313 243 -420 62 -107 121 -209 131 -227 35 -62 323 -560 392 -678 38 -66 83
|
|
||||||
-145 100 -175 16 -30 33 -59 37 -65 4 -5 17 -27 29 -47 34 -61 56 -100 90
|
|
||||||
-156 17 -29 31 -55 31 -57 0 -2 17 -32 39 -67 21 -35 134 -229 251 -433 117
|
|
||||||
-203 235 -407 261 -451 27 -45 49 -85 49 -88 0 -4 8 -19 19 -34 15 -21 200
|
|
||||||
-341 309 -533 10 -19 33 -58 51 -87 17 -29 31 -54 31 -56 0 -2 25 -44 55 -94
|
|
||||||
30 -50 55 -95 55 -98 0 -4 6 -15 14 -23 7 -9 27 -41 43 -71 17 -30 170 -297
|
|
||||||
342 -594 171 -296 311 -542 311 -547 0 -5 5 -9 10 -9 6 0 10 -4 10 -10 0 -5
|
|
||||||
22 -47 49 -92 27 -46 58 -99 68 -118 24 -43 81 -140 93 -160 5 -8 66 -114 135
|
|
||||||
-235 69 -121 130 -227 135 -235 12 -21 259 -447 283 -490 10 -19 28 -47 38
|
|
||||||
-62 11 -14 19 -29 19 -32 0 -3 37 -69 83 -148 99 -170 305 -526 337 -583 13
|
|
||||||
-22 31 -53 41 -70 11 -16 22 -37 26 -45 7 -14 82 -146 103 -180 14 -24 181
|
|
||||||
-311 205 -355 13 -22 46 -80 75 -130 29 -49 64 -110 78 -135 14 -25 51 -88 82
|
|
||||||
-140 31 -52 59 -102 63 -110 4 -8 18 -33 31 -55 205 -353 284 -489 309 -535
|
|
||||||
17 -30 45 -78 62 -106 18 -28 36 -60 39 -72 4 -12 12 -22 17 -22 5 0 9 -4 9
|
|
||||||
-10 0 -5 109 -197 241 -427 133 -230 250 -431 259 -448 51 -90 222 -385 280
|
|
||||||
-485 37 -63 78 -135 92 -160 14 -25 67 -117 118 -205 51 -88 101 -175 111
|
|
||||||
-193 34 -58 55 -95 149 -257 51 -88 101 -173 110 -190 9 -16 76 -131 147 -255
|
|
||||||
72 -124 140 -241 151 -260 61 -108 281 -489 355 -615 38 -66 77 -133 87 -150
|
|
||||||
35 -63 91 -161 100 -175 14 -23 99 -169 128 -220 54 -97 135 -235 142 -245 4
|
|
||||||
-5 20 -32 35 -60 26 -48 238 -416 276 -480 10 -16 26 -46 37 -65 30 -53 382
|
|
||||||
-661 403 -695 10 -16 22 -37 26 -45 4 -8 26 -48 50 -88 24 -41 43 -75 43 -77
|
|
||||||
0 -2 22 -40 50 -85 27 -45 50 -84 50 -86 0 -3 38 -69 83 -147 84 -142 302
|
|
||||||
-520 340 -587 10 -19 34 -60 52 -90 18 -30 44 -75 57 -100 14 -25 45 -79 70
|
|
||||||
-120 25 -41 56 -96 70 -121 14 -25 77 -133 138 -240 62 -107 122 -210 132
|
|
||||||
-229 25 -43 310 -535 337 -581 11 -19 26 -45 34 -59 17 -32 238 -414 266 -460
|
|
||||||
11 -19 24 -41 28 -49 3 -7 75 -133 160 -278 84 -146 153 -269 153 -274 0 -5 5
|
|
||||||
-9 10 -9 6 0 10 -4 10 -10 0 -5 82 -150 181 -322 182 -314 201 -346 240 -415
|
|
||||||
12 -21 80 -139 152 -263 71 -124 141 -245 155 -270 14 -25 28 -49 32 -55 6 -8
|
|
||||||
145 -248 220 -380 37 -66 209 -362 229 -395 11 -19 24 -42 28 -49 4 -8 67
|
|
||||||
-118 140 -243 73 -125 133 -230 133 -233 0 -2 15 -28 33 -57 19 -29 47 -78 64
|
|
||||||
-108 17 -30 53 -93 79 -139 53 -90 82 -141 157 -272 82 -142 115 -199 381
|
|
||||||
-659 142 -245 268 -463 281 -485 12 -22 71 -125 132 -230 60 -104 172 -298
|
|
||||||
248 -430 76 -132 146 -253 156 -270 11 -16 22 -36 26 -44 3 -8 30 -54 60 -103
|
|
||||||
29 -49 53 -91 53 -93 0 -3 18 -34 40 -70 22 -36 40 -67 40 -69 0 -2 37 -66 81
|
|
||||||
-142 45 -77 98 -168 119 -204 20 -36 47 -81 58 -100 12 -19 27 -47 33 -62 6
|
|
||||||
-16 15 -28 20 -28 5 0 9 -4 9 -9 0 -6 63 -118 140 -251 77 -133 140 -243 140
|
|
||||||
-245 0 -2 18 -33 41 -70 22 -37 49 -83 60 -101 10 -19 29 -51 40 -71 25 -45
|
|
||||||
109 -189 126 -218 7 -11 17 -29 22 -40 6 -11 22 -38 35 -60 14 -22 37 -62 52
|
|
||||||
-90 14 -27 35 -62 45 -77 11 -14 19 -29 19 -32 0 -3 18 -35 40 -71 22 -36 40
|
|
||||||
-67 40 -69 0 -2 19 -35 42 -72 23 -38 55 -94 72 -124 26 -47 139 -244 171
|
|
||||||
-298 6 -9 21 -36 34 -60 28 -48 37 -51 51 -19 6 12 19 36 29 52 10 17 27 46
|
|
||||||
38 65 11 19 104 181 208 360 103 179 199 345 213 370 14 25 42 74 64 109 21
|
|
||||||
34 38 65 38 67 0 2 18 33 40 69 22 36 40 67 40 69 0 3 177 310 199 346 16 26
|
|
||||||
136 234 140 244 2 5 25 44 52 88 27 44 49 81 49 84 0 2 18 34 40 70 22 36 40
|
|
||||||
67 40 69 0 2 20 36 43 77 35 58 169 289 297 513 9 17 50 86 90 155 40 69 86
|
|
||||||
150 103 180 16 30 35 62 41 70 6 8 16 24 22 35 35 64 72 129 167 293 59 100
|
|
||||||
116 199 127 220 11 20 30 53 41 72 43 72 1070 1850 1121 1940 14 25 65 113
|
|
||||||
113 195 48 83 96 166 107 185 10 19 28 50 38 68 11 18 73 124 137 235 64 111
|
|
||||||
175 303 246 427 71 124 173 299 225 390 52 91 116 202 143 248 27 45 49 85 49
|
|
||||||
89 0 4 6 14 14 22 7 9 28 43 46 76 26 47 251 436 378 655 11 19 29 51 40 70
|
|
||||||
11 19 101 176 201 348 99 172 181 317 181 323 0 5 5 9 10 9 6 0 10 5 10 11 0
|
|
||||||
6 8 23 18 37 11 15 32 52 49 82 16 30 130 228 253 440 122 212 234 405 248
|
|
||||||
430 13 25 39 70 57 100 39 65 69 117 130 225 25 44 50 87 55 95 12 19 78 134
|
|
||||||
220 380 61 107 129 224 150 260 161 277 222 382 246 425 15 28 47 83 71 123
|
|
||||||
24 41 43 78 43 83 0 5 4 9 8 9 4 0 13 12 19 28 7 15 23 45 36 67 66 110 277
|
|
||||||
478 277 483 0 3 6 13 14 21 7 9 27 41 43 71 17 30 45 80 63 110 34 57 375 649
|
|
||||||
394 685 6 11 16 27 22 35 6 8 26 42 44 75 18 33 41 74 51 90 10 17 24 41 32
|
|
||||||
55 54 97 72 128 88 152 11 14 19 28 19 30 0 3 79 141 175 308 96 167 175 305
|
|
||||||
175 308 0 3 6 13 14 21 7 9 26 39 41 66 33 60 276 483 338 587 24 40 46 80 50
|
|
||||||
88 4 8 13 24 20 35 14 23 95 163 125 215 11 19 52 91 92 160 40 69 80 139 90
|
|
||||||
155 9 17 103 179 207 360 105 182 200 346 211 365 103 181 463 802 489 845 7
|
|
||||||
11 15 27 19 35 4 8 29 51 55 95 64 110 828 1433 848 1470 9 17 24 41 33 55 9
|
|
||||||
14 29 48 45 77 15 28 52 93 82 145 30 51 62 107 71 123 17 30 231 398 400 690
|
|
||||||
51 88 103 179 115 202 12 23 26 48 32 55 6 7 24 38 40 68 17 30 61 107 98 170
|
|
||||||
37 63 84 144 103 180 19 36 41 72 48 81 8 8 14 18 14 21 0 4 27 51 59 106 32
|
|
||||||
55 72 124 89 154 16 29 71 125 122 213 51 88 104 180 118 205 13 25 28 50 32
|
|
||||||
55 4 6 17 26 28 45 11 19 45 80 77 135 31 55 66 116 77 135 11 19 88 152 171
|
|
||||||
295 401 694 620 1072 650 1125 11 19 87 152 170 295 83 143 158 273 166 288 9
|
|
||||||
16 21 36 26 45 6 9 31 52 55 96 25 43 54 94 66 115 11 20 95 164 186 321 91
|
|
||||||
157 173 299 182 315 9 17 26 46 37 65 12 19 66 114 121 210 56 96 108 186 117
|
|
||||||
200 8 14 24 40 34 59 24 45 383 664 412 713 5 9 17 29 26 45 15 28 120 210
|
|
||||||
241 419 36 61 68 117 72 125 4 8 12 23 19 34 35 57 245 420 262 453 11 20 35
|
|
||||||
61 53 90 17 29 32 54 32 56 0 3 28 51 62 108 33 57 70 119 80 138 10 19 23 42
|
|
||||||
28 50 5 8 32 53 59 100 27 47 149 258 271 470 122 212 234 405 248 430 30 53
|
|
||||||
62 108 80 135 6 11 15 27 19 35 4 8 85 150 181 315 96 165 187 323 202 350 31
|
|
||||||
56 116 202 130 225 5 8 25 42 43 75 19 33 92 159 162 280 149 257 157 271 202
|
|
||||||
350 19 33 38 67 43 75 9 14 228 392 275 475 12 22 55 96 95 165 40 69 80 139
|
|
||||||
90 155 24 42 202 350 221 383 9 15 27 47 41 72 14 25 75 131 136 236 61 106
|
|
||||||
121 210 134 232 99 172 271 470 279 482 5 8 23 40 40 70 18 30 81 141 142 245
|
|
||||||
60 105 121 210 135 235 14 25 71 124 127 220 56 96 143 247 194 335 51 88 96
|
|
||||||
167 102 175 14 24 180 311 204 355 23 43 340 590 356 615 5 8 50 87 101 175
|
|
||||||
171 301 517 898 582 1008 25 43 46 81 46 83 0 2 12 23 27 47 14 23 40 67 56
|
|
||||||
97 16 30 35 62 42 70 7 8 15 22 18 30 4 8 20 38 37 65 16 28 33 57 37 65 6 12
|
|
||||||
111 196 143 250 5 8 55 95 112 193 57 98 113 195 126 215 12 20 27 46 32 57 6
|
|
||||||
11 14 27 20 35 5 8 76 130 156 270 80 140 165 287 187 325 23 39 52 90 66 115
|
|
||||||
13 25 30 52 37 61 8 8 14 18 14 21 0 4 41 77 92 165 50 87 175 302 276 478
|
|
||||||
101 176 208 360 236 408 28 49 67 117 86 152 19 35 41 70 48 77 6 6 12 15 12
|
|
||||||
19 0 7 124 224 167 291 12 21 23 40 23 42 0 2 21 40 46 83 26 43 55 92 64 109
|
|
||||||
54 95 327 568 354 614 19 30 45 75 59 100 71 128 82 145 89 148 4 2 8 8 8 13
|
|
||||||
0 5 42 82 94 172 311 538 496 858 518 897 14 25 40 70 58 100 18 30 42 71 53
|
|
||||||
90 10 19 79 139 152 265 73 127 142 246 153 265 10 19 43 76 72 125 29 50 63
|
|
||||||
108 75 130 65 116 80 140 87 143 4 2 8 8 8 12 0 8 114 212 140 250 6 8 14 24
|
|
||||||
20 35 5 11 54 97 108 190 l100 170 -9611 3 c-5286 1 -9614 -1 -9618 -5 -5 -6
|
|
||||||
-419 -719 -619 -1068 -89 -155 -267 -463 -323 -560 -38 -66 -81 -140 -95 -165
|
|
||||||
-31 -56 -263 -457 -526 -910 -110 -190 -224 -388 -254 -440 -29 -52 -61 -109
|
|
||||||
-71 -125 -23 -39 -243 -420 -268 -465 -11 -19 -204 -352 -428 -740 -224 -388
|
|
||||||
-477 -826 -563 -975 -85 -148 -185 -322 -222 -385 -37 -63 -120 -207 -185
|
|
||||||
-320 -65 -113 -177 -306 -248 -430 -72 -124 -172 -297 -222 -385 -51 -88 -142
|
|
||||||
-245 -202 -350 -131 -226 -247 -427 -408 -705 -65 -113 -249 -432 -410 -710
|
|
||||||
-160 -278 -388 -673 -506 -877 -118 -205 -216 -373 -219 -373 -3 0 -52 82
|
|
||||||
-109 183 -58 100 -144 250 -192 332 -95 164 -402 696 -647 1120 -85 149 -228
|
|
||||||
396 -317 550 -212 365 -982 1700 -1008 1745 -10 19 -43 76 -72 125 -29 50 -64
|
|
||||||
110 -77 135 -14 25 -63 110 -110 190 -47 80 -96 165 -110 190 -14 25 -99 171
|
|
||||||
-188 325 -89 154 -174 300 -188 325 -13 25 -64 113 -112 195 -48 83 -140 242
|
|
||||||
-205 355 -65 113 -183 317 -263 454 -79 137 -152 264 -163 282 -50 89 -335
|
|
||||||
583 -354 614 -12 19 -34 58 -50 85 -15 28 -129 226 -253 440 -124 215 -235
|
|
||||||
408 -247 430 -12 22 -69 121 -127 220 -58 99 -226 389 -373 645 -148 256 -324
|
|
||||||
561 -392 678 -67 117 -134 232 -147 255 -13 23 -33 59 -46 80 l-22 37 -9615 0
|
|
||||||
-9615 0 20 -32z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "VuePress",
|
|
||||||
"short_name": "VuePress",
|
|
||||||
"description": "Vue-powered Static Site Generator",
|
|
||||||
"start_url": "/index.html",
|
|
||||||
"display": "standalone",
|
|
||||||
"background_color": "#fff",
|
|
||||||
"theme_color": "#3eaf7c",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/icons/android-chrome-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/android-chrome-512x512.png",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 294 KiB |
|
Before Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 100 KiB |
@ -1,941 +0,0 @@
|
|||||||
Name: af-ZA-AdriNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: af-ZA-WillemNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: am-ET-AmehaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: am-ET-MekdesNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-AE-FatimaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-AE-HamdanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-BH-AliNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-BH-LailaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-DZ-AminaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-DZ-IsmaelNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-EG-SalmaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-EG-ShakirNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-IQ-BasselNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-IQ-RanaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-JO-SanaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-JO-TaimNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-KW-FahedNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-KW-NouraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-LB-LaylaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-LB-RamiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-LY-ImanNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-LY-OmarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-MA-JamalNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-MA-MounaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-OM-AbdullahNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-OM-AyshaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-QA-AmalNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-QA-MoazNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-SA-HamedNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-SA-ZariyahNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-SY-AmanyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-SY-LaithNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-TN-HediNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ar-TN-ReemNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-YE-MaryamNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ar-YE-SalehNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: az-AZ-BabekNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: az-AZ-BanuNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: bg-BG-BorislavNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: bg-BG-KalinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: bn-BD-NabanitaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: bn-BD-PradeepNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: bn-IN-BashkarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: bn-IN-TanishaaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: bs-BA-GoranNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: bs-BA-VesnaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ca-ES-EnricNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ca-ES-JoanaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: cs-CZ-AntoninNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: cs-CZ-VlastaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: cy-GB-AledNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: cy-GB-NiaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: da-DK-ChristelNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: da-DK-JeppeNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: de-AT-IngridNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: de-AT-JonasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: de-CH-JanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: de-CH-LeniNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: de-DE-AmalaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: de-DE-ConradNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: de-DE-FlorianMultilingualNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: de-DE-KatjaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: de-DE-KillianNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: de-DE-SeraphinaMultilingualNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: el-GR-AthinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: el-GR-NestorasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-AU-NatashaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-AU-WilliamNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-CA-ClaraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-CA-LiamNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-GB-LibbyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-GB-MaisieNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-GB-RyanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-GB-SoniaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-GB-ThomasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-HK-SamNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-HK-YanNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-IE-ConnorNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-IE-EmilyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-IN-NeerjaExpressiveNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-IN-NeerjaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-IN-PrabhatNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-KE-AsiliaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-KE-ChilembaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-NG-AbeoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-NG-EzinneNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-NZ-MitchellNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-NZ-MollyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-PH-JamesNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-PH-RosaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-SG-LunaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-SG-WayneNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-TZ-ElimuNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-TZ-ImaniNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-AnaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-AndrewNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-US-AriaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-AvaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-BrianNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-US-ChristopherNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-US-EmmaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-EricNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-US-GuyNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-US-JennyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-MichelleNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-US-RogerNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-US-SteffanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: en-ZA-LeahNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: en-ZA-LukeNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-AR-ElenaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-AR-TomasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-BO-MarceloNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-BO-SofiaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-CL-CatalinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-CL-LorenzoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-CO-GonzaloNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-CO-SalomeNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-CR-JuanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-CR-MariaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-CU-BelkysNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-CU-ManuelNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-DO-EmilioNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-DO-RamonaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-EC-AndreaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-EC-LuisNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-ES-AlvaroNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-ES-ElviraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-ES-XimenaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-GQ-JavierNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-GQ-TeresaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-GT-AndresNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-GT-MartaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-HN-CarlosNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-HN-KarlaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-MX-DaliaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-MX-JorgeNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-NI-FedericoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-NI-YolandaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-PA-MargaritaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-PA-RobertoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-PE-AlexNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-PE-CamilaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-PR-KarinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-PR-VictorNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-PY-MarioNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-PY-TaniaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-SV-LorenaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-SV-RodrigoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-US-AlonsoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-US-PalomaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-UY-MateoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: es-UY-ValentinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-VE-PaolaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: es-VE-SebastianNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: et-EE-AnuNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: et-EE-KertNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fa-IR-DilaraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fa-IR-FaridNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fi-FI-HarriNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fi-FI-NooraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fil-PH-AngeloNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fil-PH-BlessicaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fr-BE-CharlineNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fr-BE-GerardNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-CA-AntoineNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-CA-JeanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-CA-SylvieNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fr-CA-ThierryNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-CH-ArianeNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fr-CH-FabriceNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-FR-DeniseNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fr-FR-EloiseNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: fr-FR-HenriNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-FR-RemyMultilingualNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: fr-FR-VivienneMultilingualNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ga-IE-ColmNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ga-IE-OrlaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: gl-ES-RoiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: gl-ES-SabelaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: gu-IN-DhwaniNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: gu-IN-NiranjanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: he-IL-AvriNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: he-IL-HilaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: hi-IN-MadhurNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: hi-IN-SwaraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: hr-HR-GabrijelaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: hr-HR-SreckoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: hu-HU-NoemiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: hu-HU-TamasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: id-ID-ArdiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: id-ID-GadisNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: is-IS-GudrunNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: is-IS-GunnarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: it-IT-DiegoNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: it-IT-ElsaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: it-IT-GiuseppeNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: it-IT-IsabellaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ja-JP-KeitaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ja-JP-NanamiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: jv-ID-DimasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: jv-ID-SitiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ka-GE-EkaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ka-GE-GiorgiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: kk-KZ-AigulNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: kk-KZ-DauletNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: km-KH-PisethNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: km-KH-SreymomNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: kn-IN-GaganNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: kn-IN-SapnaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ko-KR-HyunsuNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ko-KR-InJoonNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ko-KR-SunHiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: lo-LA-ChanthavongNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: lo-LA-KeomanyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: lt-LT-LeonasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: lt-LT-OnaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: lv-LV-EveritaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: lv-LV-NilsNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: mk-MK-AleksandarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: mk-MK-MarijaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ml-IN-MidhunNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ml-IN-SobhanaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: mn-MN-BataaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: mn-MN-YesuiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: mr-IN-AarohiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: mr-IN-ManoharNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ms-MY-OsmanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ms-MY-YasminNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: mt-MT-GraceNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: mt-MT-JosephNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: my-MM-NilarNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: my-MM-ThihaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: nb-NO-FinnNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: nb-NO-PernilleNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ne-NP-HemkalaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ne-NP-SagarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: nl-BE-ArnaudNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: nl-BE-DenaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: nl-NL-ColetteNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: nl-NL-FennaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: nl-NL-MaartenNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: pl-PL-MarekNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: pl-PL-ZofiaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ps-AF-GulNawazNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ps-AF-LatifaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: pt-BR-AntonioNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: pt-BR-FranciscaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: pt-BR-ThalitaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: pt-PT-DuarteNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: pt-PT-RaquelNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ro-RO-AlinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ro-RO-EmilNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ru-RU-DmitryNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ru-RU-SvetlanaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: si-LK-SameeraNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: si-LK-ThiliniNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sk-SK-LukasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: sk-SK-ViktoriaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sl-SI-PetraNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sl-SI-RokNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: so-SO-MuuseNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: so-SO-UbaxNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sq-AL-AnilaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sq-AL-IlirNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: sr-RS-NicholasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: sr-RS-SophieNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: su-ID-JajangNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: su-ID-TutiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sv-SE-MattiasNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: sv-SE-SofieNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sw-KE-RafikiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: sw-KE-ZuriNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: sw-TZ-DaudiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: sw-TZ-RehemaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ta-IN-PallaviNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ta-IN-ValluvarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ta-LK-KumarNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ta-LK-SaranyaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ta-MY-KaniNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ta-MY-SuryaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ta-SG-AnbuNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ta-SG-VenbaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: te-IN-MohanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: te-IN-ShrutiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: th-TH-NiwatNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: th-TH-PremwadeeNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: tr-TR-AhmetNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: tr-TR-EmelNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: uk-UA-OstapNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: uk-UA-PolinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ur-IN-GulNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: ur-IN-SalmanNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ur-PK-AsadNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: ur-PK-UzmaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: uz-UZ-MadinaNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: uz-UZ-SardorNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: vi-VN-HoaiMyNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: vi-VN-NamMinhNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zh-CN-XiaoxiaoNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-CN-XiaoyiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-CN-YunjianNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zh-CN-YunxiNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zh-CN-YunxiaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zh-CN-YunyangNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zh-CN-liaoning-XiaobeiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-CN-shaanxi-XiaoniNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-HK-HiuGaaiNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-HK-HiuMaanNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-HK-WanLungNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zh-TW-HsiaoChenNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-TW-HsiaoYuNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zh-TW-YunJheNeural
|
|
||||||
Gender: Male
|
|
||||||
|
|
||||||
Name: zu-ZA-ThandoNeural
|
|
||||||
Gender: Female
|
|
||||||
|
|
||||||
Name: zu-ZA-ThembaNeural
|
|
||||||
Gender: Male
|
|
||||||
|
Before Width: | Height: | Size: 340 KiB |
|
Before Width: | Height: | Size: 384 KiB |
|
Before Width: | Height: | Size: 340 KiB |
|
Before Width: | Height: | Size: 166 KiB |
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
home: true
|
|
||||||
heroImage: /hero.png
|
|
||||||
actions:
|
|
||||||
- text: Get Started →
|
|
||||||
link: /guide/
|
|
||||||
type: primary
|
|
||||||
features:
|
|
||||||
- title: Multilingual
|
|
||||||
details: Supports video scripts in both Chinese and English; offers multiple voice synthesis options.
|
|
||||||
- title: Maintainability
|
|
||||||
details: Complete MVC architecture with clear code structure, easy to maintain, supports both API and Web interface.
|
|
||||||
- title: Multi-Model Support
|
|
||||||
details: Supports integration with multiple models including OpenAI, moonshot, Azure, gpt4free, one-api, Tongyi Qianwen, Google Gemini, Ollama, and others.
|
|
||||||
footer: MIT Licensed | Copyright © 2024-present MoneyPrinterTurbo
|
|
||||||
---
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
## Installation & Deployment 📥
|
|
||||||
|
|
||||||
Simply provide a <b>topic</b> or <b>keyword</b> for a video, and it will automatically generate the video copy, video
|
|
||||||
materials, video subtitles, and video background music before synthesizing a high-definition short video.
|
|
||||||
|
|
||||||
### WebUI
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### API Interface
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- Try to avoid using **Chinese paths** to prevent unpredictable issues
|
|
||||||
- Ensure your **network** is stable, meaning you can access foreign websites normally
|
|
||||||
|
|
||||||
#### ① Clone the Project
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ② Modify the Configuration File
|
|
||||||
|
|
||||||
- Copy the `config.example.toml` file and rename it to `config.toml`
|
|
||||||
- Follow the instructions in the `config.toml` file to configure `pexels_api_keys` and `llm_provider`, and according to
|
|
||||||
the llm_provider's service provider, set up the corresponding API Key
|
|
||||||
|
|
||||||
#### ③ Configure Large Language Models (LLM)
|
|
||||||
|
|
||||||
- To use `GPT-4.0` or `GPT-3.5`, you need an `API Key` from `OpenAI`. If you don't have one, you can set `llm_provider`
|
|
||||||
to `g4f` (a free-to-use GPT library https://github.com/xtekky/gpt4free)
|
|
||||||
|
|
||||||
### Docker Deployment 🐳
|
|
||||||
|
|
||||||
#### ① Launch the Docker Container
|
|
||||||
|
|
||||||
If you haven't installed Docker, please install it first https://www.docker.com/products/docker-desktop/
|
|
||||||
If you are using a Windows system, please refer to Microsoft's documentation:
|
|
||||||
|
|
||||||
1. https://learn.microsoft.com/en-us/windows/wsl/install
|
|
||||||
2. https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd MoneyPrinterTurbo
|
|
||||||
docker-compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ② Access the Web Interface
|
|
||||||
|
|
||||||
Open your browser and visit http://0.0.0.0:8501
|
|
||||||
|
|
||||||
#### ③ Access the API Interface
|
|
||||||
|
|
||||||
Open your browser and visit http://0.0.0.0:8080/docs Or http://0.0.0.0:8080/redoc
|
|
||||||
|
|
||||||
### Manual Deployment 📦
|
|
||||||
|
|
||||||
#### ① Create a Python Virtual Environment
|
|
||||||
|
|
||||||
It is recommended to create a Python virtual environment
|
|
||||||
using [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index.html)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
|
||||||
cd MoneyPrinterTurbo
|
|
||||||
conda create -n MoneyPrinterTurbo python=3.10
|
|
||||||
conda activate MoneyPrinterTurbo
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ② Install ImageMagick
|
|
||||||
|
|
||||||
###### Windows:
|
|
||||||
|
|
||||||
- Download https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-29-Q16-x64-static.exe
|
|
||||||
- Install the downloaded ImageMagick, **do not change the installation path**
|
|
||||||
- Modify the `config.toml` configuration file, set `imagemagick_path` to your actual installation path (if you didn't
|
|
||||||
change the path during installation, just uncomment it)
|
|
||||||
|
|
||||||
###### MacOS:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew install imagemagick
|
|
||||||
```
|
|
||||||
|
|
||||||
###### Ubuntu
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt-get install imagemagick
|
|
||||||
```
|
|
||||||
|
|
||||||
###### CentOS
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo yum install ImageMagick
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ③ Launch the Web Interface 🌐
|
|
||||||
|
|
||||||
Note that you need to execute the following commands in the `root directory` of the MoneyPrinterTurbo project
|
|
||||||
|
|
||||||
###### Windows
|
|
||||||
|
|
||||||
```bat
|
|
||||||
conda activate MoneyPrinterTurbo
|
|
||||||
webui.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
###### MacOS or Linux
|
|
||||||
|
|
||||||
```shell
|
|
||||||
conda activate MoneyPrinterTurbo
|
|
||||||
sh webui.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
After launching, the browser will open automatically
|
|
||||||
|
|
||||||
#### ④ Launch the API Service 🚀
|
|
||||||
|
|
||||||
```shell
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
After launching, you can view the `API documentation` at http://127.0.0.1:8080/docs and directly test the interface
|
|
||||||
online for a quick experience.
|
|
||||||
|
|
||||||
## License 📝
|
|
||||||
|
|
||||||
Click to view the [`LICENSE`](LICENSE) file
|
|
||||||
|
|
||||||
## Star History
|
|
||||||
|
|
||||||
[](https://star-history.com/#harry0703/MoneyPrinterTurbo&Date)
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
## Background Music 🎵
|
|
||||||
|
|
||||||
Background music for videos is located in the project's `resource/songs` directory.
|
|
||||||
> The current project includes some default music from YouTube videos. If there are copyright issues, please delete
|
|
||||||
> them.
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
## Common Questions 🤔
|
|
||||||
|
|
||||||
### ❓How to Use the Free OpenAI GPT-3.5 Model?
|
|
||||||
|
|
||||||
[OpenAI has announced that ChatGPT with 3.5 is now free](https://openai.com/blog/start-using-chatgpt-instantly), and
|
|
||||||
developers have wrapped it into an API for direct usage.
|
|
||||||
|
|
||||||
**Ensure you have Docker installed and running**. Execute the following command to start the Docker service:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -p 3040:3040 missuo/freegpt35
|
|
||||||
```
|
|
||||||
|
|
||||||
Once successfully started, modify the `config.toml` configuration as follows:
|
|
||||||
|
|
||||||
- Set `llm_provider` to `openai`
|
|
||||||
- Fill in `openai_api_key` with any value, for example, '123456'
|
|
||||||
- Change `openai_base_url` to `http://localhost:3040/v1/`
|
|
||||||
- Set `openai_model_name` to `gpt-3.5-turbo`
|
|
||||||
|
|
||||||
### ❓RuntimeError: No ffmpeg exe could be found
|
|
||||||
|
|
||||||
Normally, ffmpeg will be automatically downloaded and detected.
|
|
||||||
However, if your environment has issues preventing automatic downloads, you may encounter the following error:
|
|
||||||
|
|
||||||
```
|
|
||||||
RuntimeError: No ffmpeg exe could be found.
|
|
||||||
Install ffmpeg on your system, or set the IMAGEIO_FFMPEG_EXE environment variable.
|
|
||||||
```
|
|
||||||
|
|
||||||
In this case, you can download ffmpeg from https://www.gyan.dev/ffmpeg/builds/, unzip it, and set `ffmpeg_path` to your
|
|
||||||
actual installation path.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[app]
|
|
||||||
# Please set according to your actual path, note that Windows path separators are \\
|
|
||||||
ffmpeg_path = "C:\\Users\\harry\\Downloads\\ffmpeg.exe"
|
|
||||||
```
|
|
||||||
|
|
||||||
### ❓Error generating audio or downloading videos
|
|
||||||
|
|
||||||
[issue 56](https://github.com/harry0703/MoneyPrinterTurbo/issues/56)
|
|
||||||
|
|
||||||
```
|
|
||||||
failed to generate audio, maybe the network is not available.
|
|
||||||
if you are in China, please use a VPN.
|
|
||||||
```
|
|
||||||
|
|
||||||
[issue 44](https://github.com/harry0703/MoneyPrinterTurbo/issues/44)
|
|
||||||
|
|
||||||
```
|
|
||||||
failed to download videos, maybe the network is not available.
|
|
||||||
if you are in China, please use a VPN.
|
|
||||||
```
|
|
||||||
|
|
||||||
This is likely due to network issues preventing access to foreign services. Please use a VPN to resolve this.
|
|
||||||
|
|
||||||
### ❓ImageMagick is not installed on your computer
|
|
||||||
|
|
||||||
[issue 33](https://github.com/harry0703/MoneyPrinterTurbo/issues/33)
|
|
||||||
|
|
||||||
1. Follow the `example configuration` provided `download address` to
|
|
||||||
install https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-30-Q16-x64-static.exe, using the static library
|
|
||||||
2. Do not install in a path with Chinese characters to avoid unpredictable issues
|
|
||||||
|
|
||||||
[issue 54](https://github.com/harry0703/MoneyPrinterTurbo/issues/54#issuecomment-2017842022)
|
|
||||||
|
|
||||||
For Linux systems, you can manually install it, refer to https://cn.linux-console.net/?p=16978
|
|
||||||
|
|
||||||
Thanks to [@wangwenqiao666](https://github.com/wangwenqiao666) for their research and exploration
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
## Features 🎯
|
|
||||||
|
|
||||||
- [x] Complete **MVC architecture**, **clearly structured** code, easy to maintain, supports both `API`
|
|
||||||
and `Web interface`
|
|
||||||
- [x] Supports **AI-generated** video copy, as well as **customized copy**
|
|
||||||
- [x] Supports various **high-definition video** sizes
|
|
||||||
- [x] Portrait 9:16, `1080x1920`
|
|
||||||
- [x] Landscape 16:9, `1920x1080`
|
|
||||||
- [x] Supports **batch video generation**, allowing the creation of multiple videos at once, then selecting the most
|
|
||||||
satisfactory one
|
|
||||||
- [x] Supports setting the **duration of video clips**, facilitating adjustments to material switching frequency
|
|
||||||
- [x] Supports video copy in both **Chinese** and **English**
|
|
||||||
- [x] Supports **multiple voice** synthesis
|
|
||||||
- [x] Supports **subtitle generation**, with adjustable `font`, `position`, `color`, `size`, and also
|
|
||||||
supports `subtitle outlining`
|
|
||||||
- [x] Supports **background music**, either random or specified music files, with adjustable `background music volume`
|
|
||||||
- [x] Video material sources are **high-definition** and **royalty-free**
|
|
||||||
- [x] Supports integration with various models such as **OpenAI**, **moonshot**, **Azure**, **gpt4free**, **one-api**,
|
|
||||||
**qianwen**, **Google Gemini**, **Ollama** and more
|
|
||||||
|
|
||||||
❓[How to Use the Free OpenAI GPT-3.5 Model?](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/README-en.md#common-questions-)
|
|
||||||
|
|
||||||
### Future Plans 📅
|
|
||||||
|
|
||||||
- [ ] Introduce support for GPT-SoVITS dubbing
|
|
||||||
- [ ] Enhance voice synthesis with large models for a more natural and emotionally resonant voice output
|
|
||||||
- [ ] Incorporate video transition effects to ensure a smoother viewing experience
|
|
||||||
- [ ] Improve the relevance of video content
|
|
||||||
- [ ] Add options for video length: short, medium, long
|
|
||||||
- [ ] Package the application into a one-click launch bundle for Windows and macOS for ease of use
|
|
||||||
- [ ] Enable the use of custom materials
|
|
||||||
- [ ] Offer voiceover and background music options with real-time preview
|
|
||||||
- [ ] Support a wider range of voice synthesis providers, such as OpenAI TTS, Azure TTS
|
|
||||||
- [ ] Automate the upload process to the YouTube platform
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## Feedback & Suggestions 📢
|
|
||||||
|
|
||||||
- You can submit an [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues) or
|
|
||||||
a [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls).
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## Reference Projects 📚
|
|
||||||
|
|
||||||
This project is based on https://github.com/FujiwaraChoki/MoneyPrinter and has been refactored with a lot of
|
|
||||||
optimizations and added functionalities. Thanks to the original author for their spirit of open source.
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
## Voice Synthesis 🗣
|
|
||||||
|
|
||||||
A list of all supported voices can be viewed here: [Voice List](/voice-list.txt)
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## Subtitle Fonts 🅰
|
|
||||||
|
|
||||||
Fonts for rendering video subtitles are located in the project's `resource/fonts` directory, and you can also add your
|
|
||||||
own fonts.
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
## Subtitle Generation 📜
|
|
||||||
|
|
||||||
Currently, there are 2 ways to generate subtitles:
|
|
||||||
|
|
||||||
- edge: Faster generation speed, better performance, no specific requirements for computer configuration, but the
|
|
||||||
quality may be unstable
|
|
||||||
- whisper: Slower generation speed, poorer performance, specific requirements for computer configuration, but more
|
|
||||||
reliable quality
|
|
||||||
|
|
||||||
You can switch between them by modifying the `subtitle_provider` in the `config.toml` configuration file
|
|
||||||
|
|
||||||
It is recommended to use `edge` mode, and switch to `whisper` mode if the quality of the subtitles generated is not
|
|
||||||
satisfactory.
|
|
||||||
|
|
||||||
> If left blank, it means no subtitles will be generated.
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
## Video Demos 📺
|
|
||||||
|
|
||||||
### Portrait 9:16
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> How to Add Fun to Your Life </th>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> What is the Meaning of Life</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/a84d33d5-27a2-4aba-8fd0-9fb2bd91c6a6"></video></td>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/112c9564-d52b-4472-99ad-970b75f66476"></video></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
### Landscape 16:9
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> What is the Meaning of Life</th>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> Why Exercise</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/346ebb15-c55f-47a9-a653-114f08bb8073"></video></td>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/271f2fae-8283-44a0-8aa0-0ed8f9a6fa87"></video></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
home: true
|
|
||||||
heroImage: /hero.png
|
|
||||||
actions:
|
|
||||||
- text: 快速上手 →
|
|
||||||
link: /zh/guide/
|
|
||||||
type: primary
|
|
||||||
features:
|
|
||||||
- title: 多语言
|
|
||||||
details: 支持 中文 和 英文 视频文案;支持 多种语音 合成。
|
|
||||||
- title: 可维护性
|
|
||||||
details: 完整的 MVC架构,代码 结构清晰,易于维护,支持 API 和 Web界面。
|
|
||||||
- title: 多模型支持
|
|
||||||
details: 支持 OpenAI、moonshot、Azure、gpt4free、one-api、通义千问、Google Gemini、Ollama 等多种模型接入。
|
|
||||||
footer: MIT Licensed | Copyright © 2024-present MoneyPrinterTurbo
|
|
||||||
---
|
|
||||||
@ -1,157 +0,0 @@
|
|||||||
## 快速开始 🚀
|
|
||||||
|
|
||||||
<br>
|
|
||||||
只需提供一个视频 <b>主题</b> 或 <b>关键词</b> ,就可以全自动生成视频文案、视频素材、视频字幕、视频背景音乐,然后合成一个高清的短视频。
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h4>Web界面</h4>
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
<h4>API界面</h4>
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
下载一键启动包,解压直接使用
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
- 百度网盘: https://pan.baidu.com/s/1bpGjgQVE5sADZRn3A6F87w?pwd=xt16 提取码: xt16
|
|
||||||
|
|
||||||
下载后,建议先**双击执行** `update.bat` 更新到**最新代码**,然后双击 `start.bat` 启动 Web 界面
|
|
||||||
|
|
||||||
### 其他系统
|
|
||||||
|
|
||||||
还没有制作一键启动包,看下面的 **安装部署** 部分,建议使用 **docker** 部署,更加方便。
|
|
||||||
|
|
||||||
## 安装部署 📥
|
|
||||||
|
|
||||||
### 前提条件
|
|
||||||
|
|
||||||
- 尽量不要使用 **中文路径**,避免出现一些无法预料的问题
|
|
||||||
- 请确保你的 **网络** 是正常的,VPN 需要打开`全局流量`模式
|
|
||||||
|
|
||||||
#### ① 克隆代码
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ② 修改配置文件
|
|
||||||
|
|
||||||
- 将 `config.example.toml` 文件复制一份,命名为 `config.toml`
|
|
||||||
- 按照 `config.toml` 文件中的说明,配置好 `pexels_api_keys` 和 `llm_provider`,并根据 llm_provider 对应的服务商,配置相关的
|
|
||||||
API Key
|
|
||||||
|
|
||||||
#### ③ 配置大模型(LLM)
|
|
||||||
|
|
||||||
- 如果要使用 `GPT-4.0` 或 `GPT-3.5`,需要有 `OpenAI` 的 `API Key`,如果没有,可以将 `llm_provider` 设置为 `g4f` (
|
|
||||||
一个免费使用 GPT 的开源库 https://github.com/xtekky/gpt4free ,但是该免费的服务,稳定性较差,有时候可以用,有时候用不了)
|
|
||||||
- 或者可以使用到 [月之暗面](https://platform.moonshot.cn/console/api-keys) 申请。注册就送
|
|
||||||
15 元体验金,可以对话 1500 次左右。然后设置 `llm_provider="moonshot"` 和 `moonshot_api_key`
|
|
||||||
- 也可以使用 通义千问,具体请看配置文件里面的注释说明
|
|
||||||
|
|
||||||
### Docker 部署 🐳
|
|
||||||
|
|
||||||
#### ① 启动 Docker
|
|
||||||
|
|
||||||
如果未安装 Docker,请先安装 https://www.docker.com/products/docker-desktop/
|
|
||||||
|
|
||||||
如果是 Windows 系统,请参考微软的文档:
|
|
||||||
|
|
||||||
1. https://learn.microsoft.com/zh-cn/windows/wsl/install
|
|
||||||
2. https://learn.microsoft.com/zh-cn/windows/wsl/tutorials/wsl-containers
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd MoneyPrinterTurbo
|
|
||||||
docker-compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ② 访问 Web 界面
|
|
||||||
|
|
||||||
打开浏览器,访问 http://0.0.0.0:8501
|
|
||||||
|
|
||||||
#### ③ 访问 API 文档
|
|
||||||
|
|
||||||
打开浏览器,访问 http://0.0.0.0:8080/docs 或者 http://0.0.0.0:8080/redoc
|
|
||||||
|
|
||||||
### 手动部署 📦
|
|
||||||
|
|
||||||
> 视频教程
|
|
||||||
|
|
||||||
- 完整的使用演示:https://v.douyin.com/iFhnwsKY/
|
|
||||||
- 如何在 Windows 上部署:https://v.douyin.com/iFyjoW3M
|
|
||||||
|
|
||||||
#### ① 创建虚拟环境
|
|
||||||
|
|
||||||
建议使用 [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index.html) 创建 python 虚拟环境
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/harry0703/MoneyPrinterTurbo.git
|
|
||||||
cd MoneyPrinterTurbo
|
|
||||||
conda create -n MoneyPrinterTurbo python=3.10
|
|
||||||
conda activate MoneyPrinterTurbo
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ② 安装好 ImageMagick
|
|
||||||
|
|
||||||
###### Windows:
|
|
||||||
|
|
||||||
- 下载 https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-30-Q16-x64-static.exe
|
|
||||||
- 安装下载好的 ImageMagick,注意不要修改安装路径
|
|
||||||
- 修改 `配置文件 config.toml` 中的 `imagemagick_path` 为你的实际安装路径(如果安装的时候没有修改路径,直接取消注释即可)
|
|
||||||
|
|
||||||
###### MacOS:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew install imagemagick
|
|
||||||
```
|
|
||||||
|
|
||||||
###### Ubuntu
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt-get install imagemagick
|
|
||||||
```
|
|
||||||
|
|
||||||
###### CentOS
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo yum install ImageMagick
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ③ 启动 Web 界面 🌐
|
|
||||||
|
|
||||||
注意需要到 MoneyPrinterTurbo 项目 `根目录` 下执行以下命令
|
|
||||||
|
|
||||||
###### Windows
|
|
||||||
|
|
||||||
```bat
|
|
||||||
conda activate MoneyPrinterTurbo
|
|
||||||
webui.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
###### MacOS or Linux
|
|
||||||
|
|
||||||
```shell
|
|
||||||
conda activate MoneyPrinterTurbo
|
|
||||||
sh webui.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
启动后,会自动打开浏览器
|
|
||||||
|
|
||||||
#### ④ 启动 API 服务 🚀
|
|
||||||
|
|
||||||
```shell
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
启动后,可以查看 `API文档` http://127.0.0.1:8080/docs 或者 http://127.0.0.1:8080/redoc 直接在线调试接口,快速体验。
|
|
||||||
|
|
||||||
## 许可证 📝
|
|
||||||
|
|
||||||
点击查看 [`LICENSE`](LICENSE) 文件
|
|
||||||
|
|
||||||
## Star History
|
|
||||||
|
|
||||||
[](https://star-history.com/#harry0703/MoneyPrinterTurbo&Date)
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## 背景音乐 🎵
|
|
||||||
|
|
||||||
用于视频的背景音乐,位于项目的 `resource/songs` 目录下。
|
|
||||||
> 当前项目里面放了一些默认的音乐,来自于 YouTube 视频,如有侵权,请删除。
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## 配置要求 📦
|
|
||||||
|
|
||||||
- 建议最低 CPU 4核或以上,内存 8G 或以上,显卡非必须
|
|
||||||
- Windows 10 或 MacOS 11.0 以上系统
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
## 常见问题 🤔
|
|
||||||
|
|
||||||
### ❓如何使用免费的OpenAI GPT-3.5模型?
|
|
||||||
|
|
||||||
[OpenAI宣布ChatGPT里面3.5已经免费了](https://openai.com/blog/start-using-chatgpt-instantly),有开发者将其封装成了API,可以直接调用
|
|
||||||
|
|
||||||
**确保你安装和启动了docker服务**,执行以下命令启动docker服务
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -p 3040:3040 missuo/freegpt35
|
|
||||||
```
|
|
||||||
|
|
||||||
启动成功后,修改 `config.toml` 中的配置
|
|
||||||
|
|
||||||
- `llm_provider` 设置为 `openai`
|
|
||||||
- `openai_api_key` 随便填写一个即可,比如 '123456'
|
|
||||||
- `openai_base_url` 改为 `http://localhost:3040/v1/`
|
|
||||||
- `openai_model_name` 改为 `gpt-3.5-turbo`
|
|
||||||
|
|
||||||
### ❓AttributeError: 'str' object has no attribute 'choices'`
|
|
||||||
|
|
||||||
这个问题是由于 OpenAI 或者其他 LLM,没有返回正确的回复导致的。
|
|
||||||
|
|
||||||
大概率是网络原因, 使用 **VPN**,或者设置 `openai_base_url` 为你的代理 ,应该就可以解决了。
|
|
||||||
|
|
||||||
### ❓RuntimeError: No ffmpeg exe could be found
|
|
||||||
|
|
||||||
通常情况下,ffmpeg 会被自动下载,并且会被自动检测到。
|
|
||||||
但是如果你的环境有问题,无法自动下载,可能会遇到如下错误:
|
|
||||||
|
|
||||||
```
|
|
||||||
RuntimeError: No ffmpeg exe could be found.
|
|
||||||
Install ffmpeg on your system, or set the IMAGEIO_FFMPEG_EXE environment variable.
|
|
||||||
```
|
|
||||||
|
|
||||||
此时你可以从 https://www.gyan.dev/ffmpeg/builds/ 下载ffmpeg,解压后,设置 `ffmpeg_path` 为你的实际安装路径即可。
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[app]
|
|
||||||
# 请根据你的实际路径设置,注意 Windows 路径分隔符为 \\
|
|
||||||
ffmpeg_path = "C:\\Users\\harry\\Downloads\\ffmpeg.exe"
|
|
||||||
```
|
|
||||||
|
|
||||||
### ❓生成音频时报错或下载视频报错
|
|
||||||
|
|
||||||
[issue 56](https://github.com/harry0703/MoneyPrinterTurbo/issues/56)
|
|
||||||
|
|
||||||
```
|
|
||||||
failed to generate audio, maybe the network is not available.
|
|
||||||
if you are in China, please use a VPN.
|
|
||||||
```
|
|
||||||
|
|
||||||
[issue 44](https://github.com/harry0703/MoneyPrinterTurbo/issues/44)
|
|
||||||
|
|
||||||
```
|
|
||||||
failed to download videos, maybe the network is not available.
|
|
||||||
if you are in China, please use a VPN.
|
|
||||||
```
|
|
||||||
|
|
||||||
这个大概率是网络原因,无法访问境外的服务,请使用VPN解决。
|
|
||||||
|
|
||||||
### ❓ImageMagick is not installed on your computer
|
|
||||||
|
|
||||||
[issue 33](https://github.com/harry0703/MoneyPrinterTurbo/issues/33)
|
|
||||||
|
|
||||||
1. 按照 `示例配置` 里面提供的 `下载地址`
|
|
||||||
,安装 https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-29-Q16-x64-static.exe, 用静态库
|
|
||||||
2. 不要安装在中文路径里面,避免出现一些无法预料的问题
|
|
||||||
|
|
||||||
[issue 54](https://github.com/harry0703/MoneyPrinterTurbo/issues/54#issuecomment-2017842022)
|
|
||||||
|
|
||||||
如果是linux系统,可以手动安装,参考 https://cn.linux-console.net/?p=16978
|
|
||||||
|
|
||||||
感谢 [@wangwenqiao666](https://github.com/wangwenqiao666)的研究探索
|
|
||||||
|
|
||||||
### ❓ImageMagick的安全策略阻止了与临时文件@/tmp/tmpur5hyyto.txt相关的操作
|
|
||||||
|
|
||||||
[issue 92](https://github.com/harry0703/MoneyPrinterTurbo/issues/92)
|
|
||||||
|
|
||||||
可以在ImageMagick的配置文件policy.xml中找到这些策略。
|
|
||||||
这个文件通常位于 /etc/ImageMagick-`X`/ 或 ImageMagick 安装目录的类似位置。
|
|
||||||
修改包含`pattern="@"`的条目,将`rights="none"`更改为`rights="read|write"`以允许对文件的读写操作。
|
|
||||||
|
|
||||||
感谢 [@chenhengzh](https://github.com/chenhengzh)的研究探索
|
|
||||||
|
|
||||||
### ❓OSError: [Errno 24] Too many open files
|
|
||||||
|
|
||||||
[issue 100](https://github.com/harry0703/MoneyPrinterTurbo/issues/100)
|
|
||||||
|
|
||||||
这个问题是由于系统打开文件数限制导致的,可以通过修改系统的文件打开数限制来解决。
|
|
||||||
|
|
||||||
查看当前限制
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ulimit -n
|
|
||||||
```
|
|
||||||
|
|
||||||
如果过低,可以调高一些,比如
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ulimit -n 10240
|
|
||||||
```
|
|
||||||
|
|
||||||
### ❓AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'
|
|
||||||
|
|
||||||
[issue 101](https://github.com/harry0703/MoneyPrinterTurbo/issues/101),
|
|
||||||
[issue 83](https://github.com/harry0703/MoneyPrinterTurbo/issues/83),
|
|
||||||
[issue 70](https://github.com/harry0703/MoneyPrinterTurbo/issues/70)
|
|
||||||
|
|
||||||
先看下当前的 Pillow 版本是多少
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pip list |grep Pillow
|
|
||||||
```
|
|
||||||
|
|
||||||
如果是 10.x 的版本,可以尝试下降级看看,有用户反馈降级后正常
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pip uninstall Pillow
|
|
||||||
pip install Pillow==9.5.0
|
|
||||||
# 或者降级到 8.4.0
|
|
||||||
pip install Pillow==8.4.0
|
|
||||||
```
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
## 功能特性 🎯
|
|
||||||
|
|
||||||
- [x] 完整的 **MVC架构**,代码 **结构清晰**,易于维护,支持 `API` 和 `Web界面`
|
|
||||||
- [x] 支持视频文案 **AI自动生成**,也可以**自定义文案**
|
|
||||||
- [x] 支持多种 **高清视频** 尺寸
|
|
||||||
- [x] 竖屏 9:16,`1080x1920`
|
|
||||||
- [x] 横屏 16:9,`1920x1080`
|
|
||||||
- [x] 支持 **批量视频生成**,可以一次生成多个视频,然后选择一个最满意的
|
|
||||||
- [x] 支持 **视频片段时长**设置,方便调节素材切换频率
|
|
||||||
- [x] 支持 **中文** 和 **英文** 视频文案
|
|
||||||
- [x] 支持 **多种语音** 合成
|
|
||||||
- [x] 支持 **字幕生成**,可以调整 `字体`、`位置`、`颜色`、`大小`,同时支持`字幕描边`设置
|
|
||||||
- [x] 支持 **背景音乐**,随机或者指定音乐文件,可设置`背景音乐音量`
|
|
||||||
- [x] 视频素材来源 **高清**,而且 **无版权**
|
|
||||||
- [x] 支持 **OpenAI**、**moonshot**、**Azure**、**gpt4free**、**one-api**、**通义千问**、**Google Gemini**、**Ollama** 等多种模型接入
|
|
||||||
|
|
||||||
❓[如何使用免费的 **OpenAI GPT-3.5
|
|
||||||
** 模型?](https://github.com/harry0703/MoneyPrinterTurbo?tab=readme-ov-file#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98-)
|
|
||||||
|
|
||||||
### 后期计划 📅
|
|
||||||
|
|
||||||
- [ ] GPT-SoVITS 配音支持
|
|
||||||
- [ ] 优化语音合成,利用大模型,使其合成的声音,更加自然,情绪更加丰富
|
|
||||||
- [ ] 增加视频转场效果,使其看起来更加的流畅
|
|
||||||
- [ ] 增加更多视频素材来源,优化视频素材和文案的匹配度
|
|
||||||
- [ ] 增加视频长度选项:短、中、长
|
|
||||||
- [ ] 增加免费网络代理,让访问OpenAI和素材下载不再受限
|
|
||||||
- [ ] 可以使用自己的素材
|
|
||||||
- [ ] 朗读声音和背景音乐,提供实时试听
|
|
||||||
- [ ] 支持更多的语音合成服务商,比如 OpenAI TTS
|
|
||||||
- [ ] 自动上传到YouTube平台
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## 反馈建议 📢
|
|
||||||
|
|
||||||
- 可以提交 [issue](https://github.com/harry0703/MoneyPrinterTurbo/issues)
|
|
||||||
或者 [pull request](https://github.com/harry0703/MoneyPrinterTurbo/pulls)。
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
## 参考项目 📚
|
|
||||||
|
|
||||||
该项目基于 https://github.com/FujiwaraChoki/MoneyPrinter 重构而来,做了大量的优化,增加了更多的功能。
|
|
||||||
感谢原作者的开源精神。
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
## 特别感谢 🙏
|
|
||||||
|
|
||||||
由于该项目的 **部署** 和 **使用**,对于一些小白用户来说,还是 **有一定的门槛**,在此特别感谢
|
|
||||||
**录咖(AI智能 多媒体服务平台)** 网站基于该项目,提供的免费`AI视频生成器`服务,可以不用部署,直接在线使用,非常方便。
|
|
||||||
|
|
||||||
- 中文版:https://reccloud.cn
|
|
||||||
- 英文版:https://reccloud.com
|
|
||||||
|
|
||||||

|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
## 语音合成 🗣
|
|
||||||
|
|
||||||
所有支持的声音列表,可以查看:[声音列表](/voice-list.txt)
|
|
||||||
|
|
||||||
2024-04-16 v1.1.2 新增了9种Azure的语音合成声音,需要配置API KEY,该声音合成的更加真实。
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
## 字幕字体 🅰
|
|
||||||
|
|
||||||
用于视频字幕的渲染,位于项目的 `resource/fonts` 目录下,你也可以放进去自己的字体。
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
## 字幕生成 📜
|
|
||||||
|
|
||||||
当前支持2种字幕生成方式:
|
|
||||||
|
|
||||||
- **edge**: 生成`速度快`,性能更好,对电脑配置没有要求,但是质量可能不稳定
|
|
||||||
- **whisper**: 生成`速度慢`,性能较差,对电脑配置有一定要求,但是`质量更可靠`。
|
|
||||||
|
|
||||||
可以修改 `config.toml` 配置文件中的 `subtitle_provider` 进行切换
|
|
||||||
|
|
||||||
建议使用 `edge` 模式,如果生成的字幕质量不好,再切换到 `whisper` 模式
|
|
||||||
|
|
||||||
> 注意:
|
|
||||||
|
|
||||||
1. whisper 模式下需要到 HuggingFace 下载一个模型文件,大约 3GB 左右,请确保网络通畅
|
|
||||||
2. 如果留空,表示不生成字幕。
|
|
||||||
|
|
||||||
> 由于国内无法访问 HuggingFace,可以使用以下方法下载 `whisper-large-v3` 的模型文件
|
|
||||||
|
|
||||||
下载地址:
|
|
||||||
|
|
||||||
- 百度网盘: https://pan.baidu.com/s/11h3Q6tsDtjQKTjUu3sc5cA?pwd=xjs9
|
|
||||||
- 夸克网盘:https://pan.quark.cn/s/3ee3d991d64b
|
|
||||||
|
|
||||||
模型下载后解压,整个目录放到 `.\MoneyPrinterTurbo\models` 里面,
|
|
||||||
最终的文件路径应该是这样: `.\MoneyPrinterTurbo\models\whisper-large-v3`
|
|
||||||
|
|
||||||
```
|
|
||||||
MoneyPrinterTurbo
|
|
||||||
├─models
|
|
||||||
│ └─whisper-large-v3
|
|
||||||
│ config.json
|
|
||||||
│ model.bin
|
|
||||||
│ preprocessor_config.json
|
|
||||||
│ tokenizer.json
|
|
||||||
│ vocabulary.json
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
## 感谢赞助 🙏
|
|
||||||
|
|
||||||
感谢佐糖 https://picwish.cn 对该项目的支持和赞助,使得该项目能够持续的更新和维护。
|
|
||||||
|
|
||||||
佐糖专注于**图像处理领域**,提供丰富的**图像处理工具**,将复杂操作极致简化,真正实现让图像处理更简单。
|
|
||||||
|
|
||||||

|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
## 视频演示 📺
|
|
||||||
|
|
||||||
### 竖屏 9:16
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> 《如何增加生活的乐趣》</th>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> 《金钱的作用》<br>更真实的合成声音</th>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji> 《生命的意义是什么》</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/a84d33d5-27a2-4aba-8fd0-9fb2bd91c6a6"></video></td>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/af2f3b0b-002e-49fe-b161-18ba91c055e8"></video></td>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/112c9564-d52b-4472-99ad-970b75f66476"></video></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
### 横屏 16:9
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji>《生命的意义是什么》</th>
|
|
||||||
<th align="center"><g-emoji class="g-emoji" alias="arrow_forward">▶️</g-emoji>《为什么要运动》</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/346ebb15-c55f-47a9-a653-114f08bb8073"></video></td>
|
|
||||||
<td align="center"><video src="https://github.com/harry0703/MoneyPrinterTurbo/assets/4928832/271f2fae-8283-44a0-8aa0-0ed8f9a6fa87"></video></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "MoneyPrinterTurbo",
|
|
||||||
"version": "1.1.2",
|
|
||||||
"description": "利用AI大模型,一键生成高清短视频 Generate short videos with one click using AI LLM.",
|
|
||||||
"main": "index.js",
|
|
||||||
"repository": "https://github.com/harry0703/MoneyPrinterTurbo",
|
|
||||||
"author": "harry0703",
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"@vue/tsconfig": "^0.1.3",
|
|
||||||
"@vuepress/bundler-vite": "2.0.0-rc.9",
|
|
||||||
"@vuepress/theme-default": "2.0.0-rc.25",
|
|
||||||
"gh-pages": "^6.1.1",
|
|
||||||
"vue": "^3.4.23",
|
|
||||||
"vue-router": "^4.3.1",
|
|
||||||
"vuepress": "2.0.0-rc.9"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"docs:dev": "vuepress dev docs",
|
|
||||||
"docs:build": "vuepress build docs",
|
|
||||||
"predeploy": "pnpm docs:build",
|
|
||||||
"deploy": "gh-pages -d docs/.vuepress/dist"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2284
sites/pnpm-lock.yaml
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@vue/tsconfig/tsconfig.node.json",
|
|
||||||
"include": [
|
|
||||||
"vite.config.*",
|
|
||||||
"vitest.config.*",
|
|
||||||
"cypress.config.*"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"types": [
|
|
||||||
"node"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@vue/tsconfig/tsconfig.web.json",
|
|
||||||
"module": "esnext",
|
|
||||||
"include": [
|
|
||||||
"env.d.ts",
|
|
||||||
"src/**/*",
|
|
||||||
"src/**/*.vue",
|
|
||||||
"docs/.vuepress/*.ts"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": ".",
|
|
||||||
"isolatedModules": true,
|
|
||||||
"paths": {
|
|
||||||
"@/*": [
|
|
||||||
"./src/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.config.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -7,6 +7,7 @@ This directory contains unit tests for the **MoneyPrinterTurbo** project.
|
|||||||
- `services/`: Tests for components in the `app/services` directory
|
- `services/`: Tests for components in the `app/services` directory
|
||||||
- `test_video.py`: Tests for the video service
|
- `test_video.py`: Tests for the video service
|
||||||
- `test_task.py`: Tests for the task service
|
- `test_task.py`: Tests for the task service
|
||||||
|
- `test_voice.py`: Tests for the voice service
|
||||||
|
|
||||||
## Running Tests
|
## Running Tests
|
||||||
|
|
||||||
|
|||||||
107
test/services/test_voice.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import asyncio
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# add project root to python path
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||||
|
|
||||||
|
from app.utils import utils
|
||||||
|
from app.services import voice as vs
|
||||||
|
|
||||||
|
temp_dir = utils.storage_dir("temp")
|
||||||
|
|
||||||
|
text_en = """
|
||||||
|
What is the meaning of life?
|
||||||
|
This question has puzzled philosophers, scientists, and thinkers of all kinds for centuries.
|
||||||
|
Throughout history, various cultures and individuals have come up with their interpretations and beliefs around the purpose of life.
|
||||||
|
Some say it's to seek happiness and self-fulfillment, while others believe it's about contributing to the welfare of others and making a positive impact in the world.
|
||||||
|
Despite the myriad of perspectives, one thing remains clear: the meaning of life is a deeply personal concept that varies from one person to another.
|
||||||
|
It's an existential inquiry that encourages us to reflect on our values, desires, and the essence of our existence.
|
||||||
|
"""
|
||||||
|
|
||||||
|
text_zh = """
|
||||||
|
预计未来3天深圳冷空气活动频繁,未来两天持续阴天有小雨,出门带好雨具;
|
||||||
|
10-11日持续阴天有小雨,日温差小,气温在13-17℃之间,体感阴凉;
|
||||||
|
12日天气短暂好转,早晚清凉;
|
||||||
|
"""
|
||||||
|
|
||||||
|
voice_rate=1.0
|
||||||
|
voice_volume=1.0
|
||||||
|
|
||||||
|
class TestVoiceService(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(self.loop)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.loop.close()
|
||||||
|
|
||||||
|
def test_siliconflow(self):
|
||||||
|
voice_name = "siliconflow:FunAudioLLM/CosyVoice2-0.5B:alex-Male"
|
||||||
|
voice_name = vs.parse_voice_name(voice_name)
|
||||||
|
|
||||||
|
async def _do():
|
||||||
|
parts = voice_name.split(":")
|
||||||
|
if len(parts) >= 3:
|
||||||
|
model = parts[1]
|
||||||
|
# 移除性别后缀,例如 "alex-Male" -> "alex"
|
||||||
|
voice_with_gender = parts[2]
|
||||||
|
voice = voice_with_gender.split("-")[0]
|
||||||
|
# 构建完整的voice参数,格式为 "model:voice"
|
||||||
|
full_voice = f"{model}:{voice}"
|
||||||
|
voice_file = f"{temp_dir}/tts-siliconflow-{voice}.mp3"
|
||||||
|
subtitle_file = f"{temp_dir}/tts-siliconflow-{voice}.srt"
|
||||||
|
sub_maker = vs.siliconflow_tts(
|
||||||
|
text=text_zh, model=model, voice=full_voice, voice_file=voice_file, voice_rate=voice_rate, voice_volume=voice_volume
|
||||||
|
)
|
||||||
|
if not sub_maker:
|
||||||
|
self.fail("siliconflow tts failed")
|
||||||
|
vs.create_subtitle(sub_maker=sub_maker, text=text_zh, subtitle_file=subtitle_file)
|
||||||
|
audio_duration = vs.get_audio_duration(sub_maker)
|
||||||
|
print(f"voice: {voice_name}, audio duration: {audio_duration}s")
|
||||||
|
else:
|
||||||
|
self.fail("siliconflow invalid voice name")
|
||||||
|
|
||||||
|
self.loop.run_until_complete(_do())
|
||||||
|
|
||||||
|
def test_azure_tts_v1(self):
|
||||||
|
voice_name = "zh-CN-XiaoyiNeural-Female"
|
||||||
|
voice_name = vs.parse_voice_name(voice_name)
|
||||||
|
print(voice_name)
|
||||||
|
|
||||||
|
voice_file = f"{temp_dir}/tts-azure-v1-{voice_name}.mp3"
|
||||||
|
subtitle_file = f"{temp_dir}/tts-azure-v1-{voice_name}.srt"
|
||||||
|
sub_maker = vs.azure_tts_v1(
|
||||||
|
text=text_zh, voice_name=voice_name, voice_file=voice_file, voice_rate=voice_rate
|
||||||
|
)
|
||||||
|
if not sub_maker:
|
||||||
|
self.fail("azure tts v1 failed")
|
||||||
|
vs.create_subtitle(sub_maker=sub_maker, text=text_zh, subtitle_file=subtitle_file)
|
||||||
|
audio_duration = vs.get_audio_duration(sub_maker)
|
||||||
|
print(f"voice: {voice_name}, audio duration: {audio_duration}s")
|
||||||
|
|
||||||
|
def test_azure_tts_v2(self):
|
||||||
|
voice_name = "zh-CN-XiaoxiaoMultilingualNeural-V2-Female"
|
||||||
|
voice_name = vs.parse_voice_name(voice_name)
|
||||||
|
print(voice_name)
|
||||||
|
|
||||||
|
async def _do():
|
||||||
|
voice_file = f"{temp_dir}/tts-azure-v2-{voice_name}.mp3"
|
||||||
|
subtitle_file = f"{temp_dir}/tts-azure-v2-{voice_name}.srt"
|
||||||
|
sub_maker = vs.azure_tts_v2(
|
||||||
|
text=text_zh, voice_name=voice_name, voice_file=voice_file
|
||||||
|
)
|
||||||
|
if not sub_maker:
|
||||||
|
self.fail("azure tts v2 failed")
|
||||||
|
vs.create_subtitle(sub_maker=sub_maker, text=text_zh, subtitle_file=subtitle_file)
|
||||||
|
audio_duration = vs.get_audio_duration(sub_maker)
|
||||||
|
print(f"voice: {voice_name}, audio duration: {audio_duration}s")
|
||||||
|
|
||||||
|
self.loop.run_until_complete(_do())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# python -m unittest test.services.test_voice.TestVoiceService.test_azure_tts_v1
|
||||||
|
# python -m unittest test.services.test_voice.TestVoiceService.test_azure_tts_v2
|
||||||
|
unittest.main()
|
||||||
@ -105,6 +105,7 @@ support_locales = [
|
|||||||
"fr-FR",
|
"fr-FR",
|
||||||
"vi-VN",
|
"vi-VN",
|
||||||
"th-TH",
|
"th-TH",
|
||||||
|
"tr-TR",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -231,12 +232,14 @@ if not config.app.get("hide_config", False):
|
|||||||
"Azure",
|
"Azure",
|
||||||
"Qwen",
|
"Qwen",
|
||||||
"DeepSeek",
|
"DeepSeek",
|
||||||
|
"ModelScope",
|
||||||
"Gemini",
|
"Gemini",
|
||||||
"Ollama",
|
"Ollama",
|
||||||
"G4f",
|
"G4f",
|
||||||
"OneAPI",
|
"OneAPI",
|
||||||
"Cloudflare",
|
"Cloudflare",
|
||||||
"ERNIE",
|
"ERNIE",
|
||||||
|
"Pollinations",
|
||||||
]
|
]
|
||||||
saved_llm_provider = config.app.get("llm_provider", "OpenAI").lower()
|
saved_llm_provider = config.app.get("llm_provider", "OpenAI").lower()
|
||||||
saved_llm_provider_index = 0
|
saved_llm_provider_index = 0
|
||||||
@ -372,6 +375,19 @@ if not config.app.get("hide_config", False):
|
|||||||
- **Model Name**: 固定为 deepseek-chat
|
- **Model Name**: 固定为 deepseek-chat
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if llm_provider == "modelscope":
|
||||||
|
if not llm_model_name:
|
||||||
|
llm_model_name = "Qwen/Qwen3-32B"
|
||||||
|
if not llm_base_url:
|
||||||
|
llm_base_url = "https://api-inference.modelscope.cn/v1/"
|
||||||
|
with llm_helper:
|
||||||
|
tips = """
|
||||||
|
##### ModelScope 配置说明
|
||||||
|
- **API Key**: [点击到官网申请](https://modelscope.cn/docs/model-service/API-Inference/intro)
|
||||||
|
- **Base Url**: 固定为 https://api-inference.modelscope.cn/v1/
|
||||||
|
- **Model Name**: 比如 Qwen/Qwen3-32B,[点击查看模型列表](https://modelscope.cn/models?filter=inference_type&page=1)
|
||||||
|
"""
|
||||||
|
|
||||||
if llm_provider == "ernie":
|
if llm_provider == "ernie":
|
||||||
with llm_helper:
|
with llm_helper:
|
||||||
tips = """
|
tips = """
|
||||||
@ -381,6 +397,17 @@ if not config.app.get("hide_config", False):
|
|||||||
- **Base Url**: 填写 **请求地址** [点击查看文档](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11#%E8%AF%B7%E6%B1%82%E8%AF%B4%E6%98%8E)
|
- **Base Url**: 填写 **请求地址** [点击查看文档](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11#%E8%AF%B7%E6%B1%82%E8%AF%B4%E6%98%8E)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if llm_provider == "pollinations":
|
||||||
|
if not llm_model_name:
|
||||||
|
llm_model_name = "default"
|
||||||
|
with llm_helper:
|
||||||
|
tips = """
|
||||||
|
##### Pollinations AI Configuration
|
||||||
|
- **API Key**: Optional - Leave empty for public access
|
||||||
|
- **Base Url**: Default is https://text.pollinations.ai/openai
|
||||||
|
- **Model Name**: Use 'openai-fast' or specify a model name
|
||||||
|
"""
|
||||||
|
|
||||||
if tips and config.ui["language"] == "zh":
|
if tips and config.ui["language"] == "zh":
|
||||||
st.warning(
|
st.warning(
|
||||||
"中国用户建议使用 **DeepSeek** 或 **Moonshot** 作为大模型提供商\n- 国内可直接访问,不需要VPN \n- 注册就送额度,基本够用"
|
"中国用户建议使用 **DeepSeek** 或 **Moonshot** 作为大模型提供商\n- 国内可直接访问,不需要VPN \n- 注册就送额度,基本够用"
|
||||||
@ -622,6 +649,7 @@ with middle_panel:
|
|||||||
("azure-tts-v1", "Azure TTS V1"),
|
("azure-tts-v1", "Azure TTS V1"),
|
||||||
("azure-tts-v2", "Azure TTS V2"),
|
("azure-tts-v2", "Azure TTS V2"),
|
||||||
("siliconflow", "SiliconFlow TTS"),
|
("siliconflow", "SiliconFlow TTS"),
|
||||||
|
("gemini-tts", "Google Gemini TTS"),
|
||||||
]
|
]
|
||||||
|
|
||||||
# 获取保存的TTS服务器,默认为v1
|
# 获取保存的TTS服务器,默认为v1
|
||||||
@ -648,6 +676,9 @@ with middle_panel:
|
|||||||
if selected_tts_server == "siliconflow":
|
if selected_tts_server == "siliconflow":
|
||||||
# 获取硅基流动的声音列表
|
# 获取硅基流动的声音列表
|
||||||
filtered_voices = voice.get_siliconflow_voices()
|
filtered_voices = voice.get_siliconflow_voices()
|
||||||
|
elif selected_tts_server == "gemini-tts":
|
||||||
|
# 获取Gemini TTS的声音列表
|
||||||
|
filtered_voices = voice.get_gemini_voices()
|
||||||
else:
|
else:
|
||||||
# 获取Azure的声音列表
|
# 获取Azure的声音列表
|
||||||
all_voices = voice.get_all_azure_voices(filter_locals=None)
|
all_voices = voice.get_all_azure_voices(filter_locals=None)
|
||||||
@ -840,7 +871,7 @@ with right_panel:
|
|||||||
st.write(tr("Subtitle Settings"))
|
st.write(tr("Subtitle Settings"))
|
||||||
params.subtitle_enabled = st.checkbox(tr("Enable Subtitles"), value=True)
|
params.subtitle_enabled = st.checkbox(tr("Enable Subtitles"), value=True)
|
||||||
font_names = get_all_fonts()
|
font_names = get_all_fonts()
|
||||||
saved_font_name = config.ui.get("font_name", "")
|
saved_font_name = config.ui.get("font_name", "MicrosoftYaHeiBold.ttc")
|
||||||
saved_font_name_index = 0
|
saved_font_name_index = 0
|
||||||
if saved_font_name in font_names:
|
if saved_font_name in font_names:
|
||||||
saved_font_name_index = font_names.index(saved_font_name)
|
saved_font_name_index = font_names.index(saved_font_name)
|
||||||
@ -894,6 +925,69 @@ with right_panel:
|
|||||||
params.stroke_color = st.color_picker(tr("Stroke Color"), "#000000")
|
params.stroke_color = st.color_picker(tr("Stroke Color"), "#000000")
|
||||||
with stroke_cols[1]:
|
with stroke_cols[1]:
|
||||||
params.stroke_width = st.slider(tr("Stroke Width"), 0.0, 10.0, 1.5)
|
params.stroke_width = st.slider(tr("Stroke Width"), 0.0, 10.0, 1.5)
|
||||||
|
with st.expander(tr("Click to show API Key management"), expanded=False):
|
||||||
|
st.subheader(tr("Manage Pexels and Pixabay API Keys"))
|
||||||
|
|
||||||
|
col1, col2 = st.tabs(["Pexels API Keys", "Pixabay API Keys"])
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
st.subheader("Pexels API Keys")
|
||||||
|
if config.app["pexels_api_keys"]:
|
||||||
|
st.write(tr("Current Keys:"))
|
||||||
|
for key in config.app["pexels_api_keys"]:
|
||||||
|
st.code(key)
|
||||||
|
else:
|
||||||
|
st.info(tr("No Pexels API Keys currently"))
|
||||||
|
|
||||||
|
new_key = st.text_input(tr("Add Pexels API Key"), key="pexels_new_key")
|
||||||
|
if st.button(tr("Add Pexels API Key")):
|
||||||
|
if new_key and new_key not in config.app["pexels_api_keys"]:
|
||||||
|
config.app["pexels_api_keys"].append(new_key)
|
||||||
|
config.save_config()
|
||||||
|
st.success(tr("Pexels API Key added successfully"))
|
||||||
|
elif new_key in config.app["pexels_api_keys"]:
|
||||||
|
st.warning(tr("This API Key already exists"))
|
||||||
|
else:
|
||||||
|
st.error(tr("Please enter a valid API Key"))
|
||||||
|
|
||||||
|
if config.app["pexels_api_keys"]:
|
||||||
|
delete_key = st.selectbox(
|
||||||
|
tr("Select Pexels API Key to delete"), config.app["pexels_api_keys"], key="pexels_delete_key"
|
||||||
|
)
|
||||||
|
if st.button(tr("Delete Selected Pexels API Key")):
|
||||||
|
config.app["pexels_api_keys"].remove(delete_key)
|
||||||
|
config.save_config()
|
||||||
|
st.success(tr("Pexels API Key deleted successfully"))
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
st.subheader("Pixabay API Keys")
|
||||||
|
|
||||||
|
if config.app["pixabay_api_keys"]:
|
||||||
|
st.write(tr("Current Keys:"))
|
||||||
|
for key in config.app["pixabay_api_keys"]:
|
||||||
|
st.code(key)
|
||||||
|
else:
|
||||||
|
st.info(tr("No Pixabay API Keys currently"))
|
||||||
|
|
||||||
|
new_key = st.text_input(tr("Add Pixabay API Key"), key="pixabay_new_key")
|
||||||
|
if st.button(tr("Add Pixabay API Key")):
|
||||||
|
if new_key and new_key not in config.app["pixabay_api_keys"]:
|
||||||
|
config.app["pixabay_api_keys"].append(new_key)
|
||||||
|
config.save_config()
|
||||||
|
st.success(tr("Pixabay API Key added successfully"))
|
||||||
|
elif new_key in config.app["pixabay_api_keys"]:
|
||||||
|
st.warning(tr("This API Key already exists"))
|
||||||
|
else:
|
||||||
|
st.error(tr("Please enter a valid API Key"))
|
||||||
|
|
||||||
|
if config.app["pixabay_api_keys"]:
|
||||||
|
delete_key = st.selectbox(
|
||||||
|
tr("Select Pixabay API Key to delete"), config.app["pixabay_api_keys"], key="pixabay_delete_key"
|
||||||
|
)
|
||||||
|
if st.button(tr("Delete Selected Pixabay API Key")):
|
||||||
|
config.app["pixabay_api_keys"].remove(delete_key)
|
||||||
|
config.save_config()
|
||||||
|
st.success(tr("Pixabay API Key deleted successfully"))
|
||||||
|
|
||||||
start_button = st.button(tr("Generate Video"), use_container_width=True, type="primary")
|
start_button = st.button(tr("Generate Video"), use_container_width=True, type="primary")
|
||||||
if start_button:
|
if start_button:
|
||||||
|
|||||||
@ -100,6 +100,23 @@
|
|||||||
"Hide Log": "Protokoll ausblenden",
|
"Hide Log": "Protokoll ausblenden",
|
||||||
"Hide Basic Settings": "Basis-Einstellungen ausblenden\n\nWenn diese Option deaktiviert ist, wird die Basis-Einstellungen-Leiste nicht auf der Seite angezeigt.\n\nWenn Sie sie erneut anzeigen möchten, setzen Sie `hide_config = false` in `config.toml`",
|
"Hide Basic Settings": "Basis-Einstellungen ausblenden\n\nWenn diese Option deaktiviert ist, wird die Basis-Einstellungen-Leiste nicht auf der Seite angezeigt.\n\nWenn Sie sie erneut anzeigen möchten, setzen Sie `hide_config = false` in `config.toml`",
|
||||||
"LLM Settings": "**LLM-Einstellungen**",
|
"LLM Settings": "**LLM-Einstellungen**",
|
||||||
"Video Source Settings": "**Videoquellen-Einstellungen**"
|
"Video Source Settings": "**Videoquellen-Einstellungen**",
|
||||||
|
"Click to show API Key management": "Klicken Sie hier, um die API-Schlüsselverwaltung anzuzeigen",
|
||||||
|
"Manage Pexels and Pixabay API Keys": "Pexels- und Pixabay-API-Schlüssel verwalten",
|
||||||
|
"Current Keys:": "Aktuelle Schlüssel:",
|
||||||
|
"No Pexels API Keys currently": "Derzeit keine Pexels-API-Schlüssel",
|
||||||
|
"Add Pexels API Key": "Pexels-API-Schlüssel hinzufügen",
|
||||||
|
"Pexels API Key added successfully": "Pexels-API-Schlüssel erfolgreich hinzugefügt",
|
||||||
|
"This API Key already exists": "Dieser API-Schlüssel existiert bereits",
|
||||||
|
"Please enter a valid API Key": "Bitte geben Sie einen gültigen API-Schlüssel ein",
|
||||||
|
"Select Pexels API Key to delete": "Wählen Sie den zu löschenden Pexels-API-Schlüssel aus",
|
||||||
|
"Delete Selected Pexels API Key": "Ausgewählten Pexels-API-Schlüssel löschen",
|
||||||
|
"Pexels API Key deleted successfully": "Pexels-API-Schlüssel erfolgreich gelöscht",
|
||||||
|
"No Pixabay API Keys currently": "Derzeit keine Pixabay-API-Schlüssel",
|
||||||
|
"Add Pixabay API Key": "Pixabay-API-Schlüssel hinzufügen",
|
||||||
|
"Pixabay API Key added successfully": "Pixabay-API-Schlüssel erfolgreich hinzugefügt",
|
||||||
|
"Select Pixabay API Key to delete": "Wählen Sie den zu löschenden Pixabay-API-Schlüssel aus",
|
||||||
|
"Delete Selected Pixabay API Key": "Ausgewählten Pixabay-API-Schlüssel löschen",
|
||||||
|
"Pixabay API Key deleted successfully": "Pixabay-API-Schlüssel erfolgreich gelöscht"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,6 +100,23 @@
|
|||||||
"Hide Log": "Hide Log",
|
"Hide Log": "Hide Log",
|
||||||
"Hide Basic Settings": "Hide Basic Settings\n\nHidden, the basic settings panel will not be displayed on the page.\n\nIf you need to display it again, please set `hide_config = false` in `config.toml`",
|
"Hide Basic Settings": "Hide Basic Settings\n\nHidden, the basic settings panel will not be displayed on the page.\n\nIf you need to display it again, please set `hide_config = false` in `config.toml`",
|
||||||
"LLM Settings": "**LLM Settings**",
|
"LLM Settings": "**LLM Settings**",
|
||||||
"Video Source Settings": "**Video Source Settings**"
|
"Video Source Settings": "**Video Source Settings**",
|
||||||
|
"Click to show API Key management": "Click to show API Key management",
|
||||||
|
"Manage Pexels and Pixabay API Keys": "Manage Pexels and Pixabay API Keys",
|
||||||
|
"Current Keys:": "Current Keys:",
|
||||||
|
"No Pexels API Keys currently": "No Pexels API Keys currently",
|
||||||
|
"Add Pexels API Key": "Add Pexels API Key",
|
||||||
|
"Pexels API Key added successfully": "Pexels API Key added successfully",
|
||||||
|
"This API Key already exists": "This API Key already exists",
|
||||||
|
"Please enter a valid API Key": "Please enter a valid API Key",
|
||||||
|
"Select Pexels API Key to delete": "Select Pexels API Key to delete",
|
||||||
|
"Delete Selected Pexels API Key": "Delete Selected Pexels API Key",
|
||||||
|
"Pexels API Key deleted successfully": "Pexels API Key deleted successfully",
|
||||||
|
"No Pixabay API Keys currently": "No Pixabay API Keys currently",
|
||||||
|
"Add Pixabay API Key": "Add Pixabay API Key",
|
||||||
|
"Pixabay API Key added successfully": "Pixabay API Key added successfully",
|
||||||
|
"Select Pixabay API Key to delete": "Select Pixabay API Key to delete",
|
||||||
|
"Delete Selected Pixabay API Key": "Delete Selected Pixabay API Key",
|
||||||
|
"Pixabay API Key deleted successfully": "Pixabay API Key deleted successfully"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,6 +100,23 @@
|
|||||||
"Hide Log": "Ocultar Log",
|
"Hide Log": "Ocultar Log",
|
||||||
"Hide Basic Settings": "Ocultar Configurações Básicas\n\nOculto, o painel de configurações básicas não será exibido na página.\n\nSe precisar exibi-lo novamente, defina `hide_config = false` em `config.toml`",
|
"Hide Basic Settings": "Ocultar Configurações Básicas\n\nOculto, o painel de configurações básicas não será exibido na página.\n\nSe precisar exibi-lo novamente, defina `hide_config = false` em `config.toml`",
|
||||||
"LLM Settings": "**Configurações do LLM**",
|
"LLM Settings": "**Configurações do LLM**",
|
||||||
"Video Source Settings": "**Configurações da Fonte do Vídeo**"
|
"Video Source Settings": "**Configurações da Fonte do Vídeo**",
|
||||||
|
"Click to show API Key management": "Clique para mostrar o gerenciamento de chaves de API",
|
||||||
|
"Manage Pexels and Pixabay API Keys": "Gerenciar chaves de API do Pexels e Pixabay",
|
||||||
|
"Current Keys:": "Chaves atuais:",
|
||||||
|
"No Pexels API Keys currently": "Nenhuma chave de API do Pexels atualmente",
|
||||||
|
"Add Pexels API Key": "Adicionar chave de API do Pexels",
|
||||||
|
"Pexels API Key added successfully": "Chave de API do Pexels adicionada com sucesso",
|
||||||
|
"This API Key already exists": "Esta chave de API já existe",
|
||||||
|
"Please enter a valid API Key": "Por favor, insira uma chave de API válida",
|
||||||
|
"Select Pexels API Key to delete": "Selecione a chave de API do Pexels para excluir",
|
||||||
|
"Delete Selected Pexels API Key": "Excluir chave de API do Pexels selecionada",
|
||||||
|
"Pexels API Key deleted successfully": "Chave de API do Pexels excluída com sucesso",
|
||||||
|
"No Pixabay API Keys currently": "Nenhuma chave de API do Pixabay atualmente",
|
||||||
|
"Add Pixabay API Key": "Adicionar chave de API do Pixabay",
|
||||||
|
"Pixabay API Key added successfully": "Chave de API do Pixabay adicionada com sucesso",
|
||||||
|
"Select Pixabay API Key to delete": "Selecione a chave de API do Pixabay para excluir",
|
||||||
|
"Delete Selected Pixabay API Key": "Excluir chave de API do Pixabay selecionada",
|
||||||
|
"Pixabay API Key deleted successfully": "Chave de API do Pixabay excluída com sucesso"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
105
webui/i18n/ru.json
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"Language": "Русский",
|
||||||
|
"Translation": {
|
||||||
|
"Login Required": "Требуется авторизация",
|
||||||
|
"Please login to access settings": "Войдите для доступа к настройкам",
|
||||||
|
"Username": "Имя пользователя",
|
||||||
|
"Password": "Пароль",
|
||||||
|
"Login": "Войти",
|
||||||
|
"Login Error": "Ошибка входа",
|
||||||
|
"Incorrect username or password": "Неверное имя пользователя или пароль",
|
||||||
|
"Please enter your username and password": "Введите имя пользователя и пароль",
|
||||||
|
"Video Script Settings": "**Настройки сценария видео**",
|
||||||
|
"Video Subject": "Тема видео (Укажите ключевое слово, :red[ИИ автоматически создаст] сценарий видео)",
|
||||||
|
"Script Language": "Язык сценария видео (ИИ автоматически определит язык по теме)",
|
||||||
|
"Generate Video Script and Keywords": "Нажмите для создания [Сценария видео] и [Ключевых слов] на основе **темы** с помощью ИИ",
|
||||||
|
"Auto Detect": "Автоопределение",
|
||||||
|
"Video Script": "Сценарий видео (:blue[① Необязательно, создается ИИ ② Правильная пунктуация помогает генерации субтитров])",
|
||||||
|
"Generate Video Keywords": "Нажмите для создания [Ключевых слов] на основе **сценария** с помощью ИИ",
|
||||||
|
"Please Enter the Video Subject": "Сначала введите сценарий видео",
|
||||||
|
"Generating Video Script and Keywords": "ИИ создает сценарий и ключевые слова...",
|
||||||
|
"Generating Video Keywords": "ИИ создает ключевые слова...",
|
||||||
|
"Video Keywords": "Ключевые слова видео (:blue[① Необязательно, создается ИИ ② Используйте **запятые** для разделения, только на английском])",
|
||||||
|
"Video Settings": "**Настройки видео**",
|
||||||
|
"Video Concat Mode": "Режим объединения видео",
|
||||||
|
"Random": "Случайное объединение (Рекомендуется)",
|
||||||
|
"Sequential": "Последовательное объединение",
|
||||||
|
"Video Transition Mode": "Режим переходов видео",
|
||||||
|
"None": "Без переходов",
|
||||||
|
"Shuffle": "Перемешивание",
|
||||||
|
"FadeIn": "Появление",
|
||||||
|
"FadeOut": "Затухание",
|
||||||
|
"SlideIn": "Вход слайдом",
|
||||||
|
"SlideOut": "Выход слайдом",
|
||||||
|
"Video Ratio": "Соотношение сторон видео",
|
||||||
|
"Portrait": "Вертикальное 9:16",
|
||||||
|
"Landscape": "Горизонтальное 16:9",
|
||||||
|
"Clip Duration": "Максимальная длительность видеофрагмента (секунды)",
|
||||||
|
"Number of Videos Generated Simultaneously": "Количество одновременно создаваемых видео",
|
||||||
|
"Audio Settings": "**Настройки аудио**",
|
||||||
|
"Speech Synthesis": "Голос синтеза речи",
|
||||||
|
"Speech Region": "Регион (:red[Обязательно,[Получить регион](https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/SpeechServices)])",
|
||||||
|
"Speech Key": "API-ключ (:red[Обязательно,[Получить API-ключ](https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/SpeechServices)])",
|
||||||
|
"Speech Volume": "Громкость речи (1.0 соответствует 100%)",
|
||||||
|
"Speech Rate": "Скорость речи (1.0 означает обычную скорость)",
|
||||||
|
"Male": "Мужской",
|
||||||
|
"Female": "Женский",
|
||||||
|
"Background Music": "Фоновая музыка",
|
||||||
|
"No Background Music": "Без фоновой музыки",
|
||||||
|
"Random Background Music": "Случайная фоновая музыка",
|
||||||
|
"Custom Background Music": "Пользовательская фоновая музыка",
|
||||||
|
"Custom Background Music File": "Введите путь к файлу пользовательской фоновой музыки:",
|
||||||
|
"Background Music Volume": "Громкость фоновой музыки (0.2 соответствует 20%, фоновая музыка не должна быть слишком громкой)",
|
||||||
|
"Subtitle Settings": "**Настройки субтитров**",
|
||||||
|
"Enable Subtitles": "Включить субтитры (Если не отмечено, настройки ниже не будут применены)",
|
||||||
|
"Font": "Шрифт субтитров",
|
||||||
|
"Position": "Расположение субтитров",
|
||||||
|
"Top": "Сверху",
|
||||||
|
"Center": "По центру",
|
||||||
|
"Bottom": "Снизу (Рекомендуется)",
|
||||||
|
"Custom": "Пользовательское расположение (70, означает 70% от верха)",
|
||||||
|
"Font Size": "Размер шрифта субтитров",
|
||||||
|
"Font Color": "Цвет шрифта субтитров",
|
||||||
|
"Stroke Color": "Цвет обводки субтитров",
|
||||||
|
"Stroke Width": "Ширина обводки субтитров",
|
||||||
|
"Generate Video": "Создать видео",
|
||||||
|
"Video Script and Subject Cannot Both Be Empty": "Тема и сценарий видео не могут быть пустыми одновременно",
|
||||||
|
"Generating Video": "Создание видео, пожалуйста подождите...",
|
||||||
|
"Start Generating Video": "Начать создание видео",
|
||||||
|
"Video Generation Completed": "Создание видео завершено",
|
||||||
|
"Video Generation Failed": "Ошибка создания видео",
|
||||||
|
"You can download the generated video from the following links": "Вы можете скачать созданное видео по следующим ссылкам",
|
||||||
|
"Pexels API Key": "Pexels API-ключ ([Получить API-ключ](https://www.pexels.com/api/))",
|
||||||
|
"Pixabay API Key": "Pixabay API-ключ ([Получить API-ключ](https://pixabay.com/api/docs/#api_search_videos))",
|
||||||
|
"Basic Settings": "**Основные настройки** (:blue[Нажмите для раскрытия])",
|
||||||
|
"Language": "Язык",
|
||||||
|
"LLM Provider": "Провайдер LLM",
|
||||||
|
"API Key": "API-ключ (:red[Обязательно])",
|
||||||
|
"Base Url": "Базовый URL",
|
||||||
|
"Account ID": "ID аккаунта (Получите в панели управления Cloudflare)",
|
||||||
|
"Model Name": "Название модели",
|
||||||
|
"Please Enter the LLM API Key": "Введите **LLM API-ключ**",
|
||||||
|
"Please Enter the Pexels API Key": "Введите **Pexels API-ключ**",
|
||||||
|
"Please Enter the Pixabay API Key": "Введите **Pixabay API-ключ**",
|
||||||
|
"Get Help": "Если нужна помощь или есть вопросы, присоединяйтесь к Discord: https://harryai.cc",
|
||||||
|
"Video Source": "Источник видео",
|
||||||
|
"TikTok": "TikTok (Поддержка TikTok скоро появится)",
|
||||||
|
"Bilibili": "Bilibili (Поддержка Bilibili скоро появится)",
|
||||||
|
"Xiaohongshu": "Xiaohongshu (Поддержка Xiaohongshu скоро появится)",
|
||||||
|
"Local file": "Локальный файл",
|
||||||
|
"Play Voice": "Воспроизвести голос",
|
||||||
|
"Voice Example": "Это пример текста для тестирования синтеза речи",
|
||||||
|
"Synthesizing Voice": "Синтезирование голоса, пожалуйста подождите...",
|
||||||
|
"TTS Provider": "Выберите провайдера синтеза речи",
|
||||||
|
"TTS Servers": "TTS серверы",
|
||||||
|
"No voices available for the selected TTS server. Please select another server.": "Для выбранного TTS сервера нет доступных голосов. Выберите другой сервер.",
|
||||||
|
"SiliconFlow API Key": "SiliconFlow API-ключ [Нажмите для получения](https://cloud.siliconflow.cn/account/ak)",
|
||||||
|
"SiliconFlow TTS Settings": "Настройки SiliconFlow TTS",
|
||||||
|
"Speed: Range [0.25, 4.0], default is 1.0": "Скорость: Диапазон [0.25, 4.0], по умолчанию 1.0",
|
||||||
|
"Volume: Uses Speech Volume setting, default 1.0 maps to gain 0": "Громкость: Использует настройку громкости речи, по умолчанию 1.0 соответствует усилению 0",
|
||||||
|
"Hide Log": "Скрыть журнал",
|
||||||
|
"Hide Basic Settings": "Скрыть основные настройки\n\nПри скрытии панель основных настроек не будет отображаться на странице.\n\nДля повторного отображения установите `hide_config = false` в `config.toml`",
|
||||||
|
"LLM Settings": "**Настройки LLM**",
|
||||||
|
"Video Source Settings": "**Настройки источника видео**"
|
||||||
|
}
|
||||||
|
}
|
||||||
105
webui/i18n/tr.json
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"Language": "Türkçe",
|
||||||
|
"Translation": {
|
||||||
|
"Login Required": "Giriş Gerekli",
|
||||||
|
"Please login to access settings": "Ayarlara erişmek için lütfen giriş yapın",
|
||||||
|
"Username": "Kullanıcı Adı",
|
||||||
|
"Password": "Şifre",
|
||||||
|
"Login": "Giriş Yap",
|
||||||
|
"Login Error": "Giriş Hatası",
|
||||||
|
"Incorrect username or password": "Hatalı kullanıcı adı veya şifre",
|
||||||
|
"Please enter your username and password": "Lütfen kullanıcı adınızı ve şifrenizi girin",
|
||||||
|
"Video Script Settings": "**Video Senaryo Ayarları**",
|
||||||
|
"Video Subject": "Video Konusu (:red[Yapay zeka otomatik olarak] video senaryosu oluşturacak bir anahtar kelime girin)",
|
||||||
|
"Script Language": "Video Senaryosu Dili (Yapay zeka, konunuzun diline göre otomatik çıktı verecektir)",
|
||||||
|
"Generate Video Script and Keywords": "**Konuya** dayalı olarak yapay zeka ile [Video Senaryosu] ve [Video Anahtar Kelimeleri] oluşturmak için tıklayın",
|
||||||
|
"Auto Detect": "Otomatik Algılama",
|
||||||
|
"Video Script": "Video Senaryosu (:blue[① İsteğe bağlı, yapay zeka tarafından oluşturulur ② Doğru noktalama altyazı oluşturmaya yardımcı olur])",
|
||||||
|
"Generate Video Keywords": "**Senaryoya** dayalı olarak yapay zeka ile [Video Anahtar Kelimeleri] oluşturmak için tıklayın",
|
||||||
|
"Please Enter the Video Subject": "Lütfen Önce Video Senaryosunu Girin",
|
||||||
|
"Generating Video Script and Keywords": "Yapay zeka video senaryosu ve anahtar kelimeleri oluşturuyor...",
|
||||||
|
"Generating Video Keywords": "Yapay zeka video anahtar kelimelerini oluşturuyor...",
|
||||||
|
"Video Keywords": "Video Anahtar Kelimeleri (:blue[① İsteğe bağlı, yapay zeka tarafından oluşturulur ② Ayırmak için **İngilizce virgül** kullanın, yalnızca İngilizce])",
|
||||||
|
"Video Settings": "**Video Ayarları**",
|
||||||
|
"Video Concat Mode": "Video Birleştirme Modu",
|
||||||
|
"Random": "Rastgele Birleştirme (Önerilen)",
|
||||||
|
"Sequential": "Sıralı Birleştirme",
|
||||||
|
"Video Transition Mode": "Video Geçiş Modu",
|
||||||
|
"None": "Yok",
|
||||||
|
"Shuffle": "Karıştır",
|
||||||
|
"FadeIn": "Yavaşça Belirme",
|
||||||
|
"FadeOut": "Yavaşça Kaybolma",
|
||||||
|
"SlideIn": "Kayarak Giriş",
|
||||||
|
"SlideOut": "Kayarak Çıkış",
|
||||||
|
"Video Ratio": "Video En-Boy Oranı",
|
||||||
|
"Portrait": "Dikey 9:16",
|
||||||
|
"Landscape": "Yatay 16:9",
|
||||||
|
"Clip Duration": "Video Kliplerinin Maksimum Süresi (saniye)",
|
||||||
|
"Number of Videos Generated Simultaneously": "Aynı Anda Oluşturulan Video Sayısı",
|
||||||
|
"Audio Settings": "**Ses Ayarları**",
|
||||||
|
"Speech Synthesis": "Konuşma Sentezi Sesi",
|
||||||
|
"Speech Region": "Bölge (:red[Gerekli, [Bölge Al](https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/SpeechServices)])",
|
||||||
|
"Speech Key": "API Anahtarı (:red[Gerekli, [API Anahtarı Al](https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/SpeechServices)])",
|
||||||
|
"Speech Volume": "Konuşma Ses Seviyesi (1.0, %100 anlamına gelir)",
|
||||||
|
"Speech Rate": "Konuşma Hızı (1.0, 1x hız anlamına gelir)",
|
||||||
|
"Male": "Erkek",
|
||||||
|
"Female": "Kadın",
|
||||||
|
"Background Music": "Arka Plan Müziği",
|
||||||
|
"No Background Music": "Arka Plan Müziği Yok",
|
||||||
|
"Random Background Music": "Rastgele Arka Plan Müziği",
|
||||||
|
"Custom Background Music": "Özel Arka Plan Müziği",
|
||||||
|
"Custom Background Music File": "Lütfen özel arka plan müziği dosya yolunu girin:",
|
||||||
|
"Background Music Volume": "Arka Plan Müziği Ses Seviyesi (0.2, %20 anlamına gelir, arka plan müziği çok yüksek olmamalı)",
|
||||||
|
"Subtitle Settings": "**Altyazı Ayarları**",
|
||||||
|
"Enable Subtitles": "Altyazıları Etkinleştir (İşaretlenmezse aşağıdaki ayarlar geçerli olmaz)",
|
||||||
|
"Font": "Altyazı Fontu",
|
||||||
|
"Position": "Altyazı Konumu",
|
||||||
|
"Top": "Üst",
|
||||||
|
"Center": "Orta",
|
||||||
|
"Bottom": "Alt (Önerilen)",
|
||||||
|
"Custom": "Özel konum (70, üstten %70 aşağı anlamına gelir)",
|
||||||
|
"Font Size": "Altyazı Font Boyutu",
|
||||||
|
"Font Color": "Altyazı Font Rengi",
|
||||||
|
"Stroke Color": "Altyazı Çerçeve Rengi",
|
||||||
|
"Stroke Width": "Altyazı Çerçeve Kalınlığı",
|
||||||
|
"Generate Video": "Video Oluştur",
|
||||||
|
"Video Script and Subject Cannot Both Be Empty": "Video Konusu ve Video Senaryosu aynı anda boş olamaz",
|
||||||
|
"Generating Video": "Video oluşturuluyor, lütfen bekleyin...",
|
||||||
|
"Start Generating Video": "Video Oluşturmaya Başla",
|
||||||
|
"Video Generation Completed": "Video Oluşturma Tamamlandı",
|
||||||
|
"Video Generation Failed": "Video Oluşturma Başarısız",
|
||||||
|
"You can download the generated video from the following links": "Oluşturulan videoyu aşağıdaki bağlantılardan indirebilirsiniz",
|
||||||
|
"Pexels API Key": "Pexels API Anahtarı ([API Anahtarı Al](https://www.pexels.com/api/))",
|
||||||
|
"Pixabay API Key": "Pixabay API Anahtarı ([API Anahtarı Al](https://pixabay.com/api/docs/#api_search_videos))",
|
||||||
|
"Basic Settings": "**Temel Ayarlar** (:blue[Genişletmek için tıklayın])",
|
||||||
|
"Language": "Dil",
|
||||||
|
"LLM Provider": "LLM Sağlayıcı",
|
||||||
|
"API Key": "API Anahtarı (:red[Gerekli])",
|
||||||
|
"Base Url": "Temel URL",
|
||||||
|
"Account ID": "Hesap Kimlik Numarası (Cloudflare panodan alın)",
|
||||||
|
"Model Name": "Model Adı",
|
||||||
|
"Please Enter the LLM API Key": "Lütfen **LLM API Anahtarını** Girin",
|
||||||
|
"Please Enter the Pexels API Key": "Lütfen **Pexels API Anahtarını** Girin",
|
||||||
|
"Please Enter the Pixabay API Key": "Lütfen **Pixabay API Anahtarını** Girin",
|
||||||
|
"Get Help": "Yardıma ihtiyacınız varsa veya sorularınız varsa discord'a katılabilirsiniz: https://harryai.cc",
|
||||||
|
"Video Source": "Video Kaynağı",
|
||||||
|
"TikTok": "TikTok (TikTok desteği yakında geliyor)",
|
||||||
|
"Bilibili": "Bilibili (Bilibili desteği yakında geliyor)",
|
||||||
|
"Xiaohongshu": "Xiaohongshu (Xiaohongshu desteği yakında geliyor)",
|
||||||
|
"Local file": "Yerel dosya",
|
||||||
|
"Play Voice": "Sesi Oynat",
|
||||||
|
"Voice Example": "Bu, konuşma sentezini test etmek için örnek bir metindir",
|
||||||
|
"Synthesizing Voice": "Ses sentezleniyor, lütfen bekleyin...",
|
||||||
|
"TTS Provider": "Ses sentezi sağlayıcısını seçin",
|
||||||
|
"TTS Servers": "TTS Sunucuları",
|
||||||
|
"No voices available for the selected TTS server. Please select another server.": "Seçilen TTS sunucusu için uygun ses bulunamadı. Lütfen başka bir sunucu seçin.",
|
||||||
|
"SiliconFlow API Key": "SiliconFlow API Anahtarı [Almak için tıklayın](https://cloud.siliconflow.cn/account/ak)",
|
||||||
|
"SiliconFlow TTS Settings": "SiliconFlow TTS Ayarları",
|
||||||
|
"Speed: Range [0.25, 4.0], default is 1.0": "Hız: Aralık [0.25, 4.0], varsayılan 1.0",
|
||||||
|
"Volume: Uses Speech Volume setting, default 1.0 maps to gain 0": "Ses Seviyesi: Konuşma Ses Seviyesi ayarını kullanır, varsayılan 1.0 gain 0'a eşittir",
|
||||||
|
"Hide Log": "Günlüğü Gizle",
|
||||||
|
"Hide Basic Settings": "Temel Ayarları Gizle\n\nGizlendiği takdirde, temel ayarlar paneli sayfada görüntülenmeyecektir.\n\nTekrar görüntülemek için `config.toml` dosyasında `hide_config = false` olarak ayarlayın",
|
||||||
|
"LLM Settings": "**LLM Ayarları**",
|
||||||
|
"Video Source Settings": "**Video Kaynağı Ayarları**"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -100,6 +100,23 @@
|
|||||||
"Hide Log": "Ẩn Nhật Ký",
|
"Hide Log": "Ẩn Nhật Ký",
|
||||||
"Hide Basic Settings": "Ẩn Cài Đặt Cơ Bản\n\nẨn, thanh cài đặt cơ bản sẽ không hiển thị trên trang web.\n\nNếu bạn muốn hiển thị lại, vui lòng đặt `hide_config = false` trong `config.toml`",
|
"Hide Basic Settings": "Ẩn Cài Đặt Cơ Bản\n\nẨn, thanh cài đặt cơ bản sẽ không hiển thị trên trang web.\n\nNếu bạn muốn hiển thị lại, vui lòng đặt `hide_config = false` trong `config.toml`",
|
||||||
"LLM Settings": "**Cài Đặt LLM**",
|
"LLM Settings": "**Cài Đặt LLM**",
|
||||||
"Video Source Settings": "**Cài Đặt Nguồn Video**"
|
"Video Source Settings": "**Cài Đặt Nguồn Video**",
|
||||||
|
"Click to show API Key management": "Nhấn để hiển thị quản lý API Key",
|
||||||
|
"Manage Pexels and Pixabay API Keys": "Quản lý API Key của Pexels và Pixabay",
|
||||||
|
"Current Keys:": "Các Key hiện tại:",
|
||||||
|
"No Pexels API Keys currently": "Hiện không có API Key Pexels",
|
||||||
|
"Add Pexels API Key": "Thêm API Key Pexels",
|
||||||
|
"Pexels API Key added successfully": "Thêm API Key Pexels thành công",
|
||||||
|
"This API Key already exists": "API Key này đã tồn tại",
|
||||||
|
"Please enter a valid API Key": "Vui lòng nhập API Key hợp lệ",
|
||||||
|
"Select Pexels API Key to delete": "Chọn API Key Pexels để xóa",
|
||||||
|
"Delete Selected Pexels API Key": "Xóa API Key Pexels đã chọn",
|
||||||
|
"Pexels API Key deleted successfully": "Xóa API Key Pexels thành công",
|
||||||
|
"No Pixabay API Keys currently": "Hiện không có API Key Pixabay",
|
||||||
|
"Add Pixabay API Key": "Thêm API Key Pixabay",
|
||||||
|
"Pixabay API Key added successfully": "Thêm API Key Pixabay thành công",
|
||||||
|
"Select Pixabay API Key to delete": "Chọn API Key Pixabay để xóa",
|
||||||
|
"Delete Selected Pixabay API Key": "Xóa API Key Pixabay đã chọn",
|
||||||
|
"Pixabay API Key deleted successfully": "Xóa API Key Pixabay thành công"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,6 +100,23 @@
|
|||||||
"Hide Log": "隐藏日志",
|
"Hide Log": "隐藏日志",
|
||||||
"Hide Basic Settings": "隐藏基础设置\n\n隐藏后,基础设置面板将不会显示在页面中。\n\n如需要再次显示,请在 `config.toml` 中设置 `hide_config = false`",
|
"Hide Basic Settings": "隐藏基础设置\n\n隐藏后,基础设置面板将不会显示在页面中。\n\n如需要再次显示,请在 `config.toml` 中设置 `hide_config = false`",
|
||||||
"LLM Settings": "**大模型设置**",
|
"LLM Settings": "**大模型设置**",
|
||||||
"Video Source Settings": "**视频源设置**"
|
"Video Source Settings": "**视频源设置**",
|
||||||
|
"Click to show API Key management": "点击以显示 API Key 管理功能",
|
||||||
|
"Manage Pexels and Pixabay API Keys": "管理 Pexels 和 Pixabay API Keys",
|
||||||
|
"Current Keys:": "当前 Keys:",
|
||||||
|
"No Pexels API Keys currently": "暂无 Pexels API Keys",
|
||||||
|
"Add Pexels API Key": "新增 Pexels API Key",
|
||||||
|
"Pexels API Key added successfully": "Pexels API Key 添加成功",
|
||||||
|
"This API Key already exists": "这个 Key 已经存在",
|
||||||
|
"Please enter a valid API Key": "请输入一个有效的 Key",
|
||||||
|
"Select Pexels API Key to delete": "选择要删除的 Pexels API Key",
|
||||||
|
"Delete Selected Pexels API Key": "删除选定的 Pexels API Key",
|
||||||
|
"Pexels API Key deleted successfully": "Pexels API Key 删除成功",
|
||||||
|
"No Pixabay API Keys currently": "暂无 Pixabay API Keys",
|
||||||
|
"Add Pixabay API Key": "新增 Pixabay API Key",
|
||||||
|
"Pixabay API Key added successfully": "Pixabay API Key 添加成功",
|
||||||
|
"Select Pixabay API Key to delete": "选择要删除的 Pixabay API Key",
|
||||||
|
"Delete Selected Pixabay API Key": "删除选定的 Pixabay API Key",
|
||||||
|
"Pixabay API Key deleted successfully": "Pixabay API Key 删除成功"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||