Compare commits
98
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d4b94be7d | ||
|
|
1c66968873 | ||
|
|
492dbe58c0 | ||
|
|
871a100a8a | ||
|
|
3aacf3f27f | ||
|
|
fbd09a24b6 | ||
|
|
f6669c912c | ||
|
|
6a45c03b04 | ||
|
|
84a28ca95c | ||
|
|
6fda08cb53 | ||
|
|
754cfeed9e | ||
|
|
e61aaca243 | ||
|
|
8828ecb3af | ||
|
|
abd1e4f13f | ||
|
|
a6b3a77fd8 | ||
|
|
d304032279 | ||
|
|
f4bc0081f4 | ||
|
|
1ff02ce1a4 | ||
|
|
5e39b546ef | ||
|
|
a39a4ebb89 | ||
|
|
510bc2d1a3 | ||
|
|
4ca5ae68ea | ||
|
|
1a8a20f4ee | ||
|
|
80eb4e5302 | ||
|
|
9ff0bf10ab | ||
|
|
d020a0f9a2 | ||
|
|
012b987ab8 | ||
|
|
24a0a457a1 | ||
|
|
663e267d4c | ||
|
|
f174a61aee | ||
|
|
c9b5aef80b | ||
|
|
f107173b58 | ||
|
|
9b530eda75 | ||
|
|
7c7cb72c13 | ||
|
|
3a105ce922 | ||
|
|
690018c4ab | ||
|
|
6808439ca1 | ||
|
|
8cf56faad2 | ||
|
|
cb7d486288 | ||
|
|
086999fc1b | ||
|
|
a1b889108f | ||
|
|
9f18b24465 | ||
|
|
a3f157249c | ||
|
|
eb08d31509 | ||
|
|
1e1b7fdd8c | ||
|
|
5aad7bcc45 | ||
|
|
dd52597f49 | ||
|
|
5f836e08b8 | ||
|
|
b89b6cdc1d | ||
|
|
558aed1888 | ||
|
|
5eab3d28df | ||
|
|
fd76f496a0 | ||
|
|
4d9b44d9a0 | ||
|
|
951df5a239 | ||
|
|
0a35ee2310 | ||
|
|
efeb2e67e0 | ||
|
|
131f14de76 | ||
|
|
4e67931fe9 | ||
|
|
785525327d | ||
|
|
d4647573cd | ||
|
|
c3895b602c | ||
|
|
f18eb9a4a0 | ||
|
|
2834778e8f | ||
|
|
2f42c69d25 | ||
|
|
8c65f026e6 | ||
|
|
fff01107c8 | ||
|
|
0bdc66f6e5 | ||
|
|
1c3fc86085 | ||
|
|
d9eb0876a6 | ||
|
|
9b4130a8eb | ||
|
|
8fb5b4f695 | ||
|
|
65e306a198 | ||
|
|
3dabb63656 | ||
|
|
241fa91473 | ||
|
|
2a5c8dd58a | ||
|
|
2bfa10d7be | ||
|
|
3501e2e2f3 | ||
|
|
679e3a0982 | ||
|
|
35d05c7689 | ||
|
|
084cc2d2a2 | ||
|
|
a96c82ff01 | ||
|
|
aa7ff1940a | ||
|
|
58465ae14e | ||
|
|
2f49f61645 | ||
|
|
58a70caebc | ||
|
|
d0d470db0f | ||
|
|
068fc72346 | ||
|
|
fc5c8c748f | ||
|
|
24f86d08b7 | ||
|
|
99e402664c | ||
|
|
24cf9eae59 | ||
|
|
18b1582d2a | ||
|
|
96d9df9438 | ||
|
|
4ca156a032 | ||
|
|
5aecb5b7fd | ||
|
|
63c308ff05 | ||
|
|
e6e4b0b47f | ||
|
|
bedc8148ad |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Support request OR Bug report
|
||||
about: Create a report to help us improve
|
||||
name: Support Request/Issue
|
||||
about: Use this to create a support request or report a bug/issue
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -1,12 +1,15 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
about: Use this to create a Feature request
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Please confirm you have read the current Features request list**
|
||||
https://github.com/erew123/alltalk_tts/discussions/74
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
name: Support request OR Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
🔴 If you have installed AllTalk in a custom Python environment, I will only be able to provide limited assistance/support. AllTalk draws on a variety of scripts and libraries that are not written or managed by myself, and they may fail, error or give strange results in custom built python environments.
|
||||
|
||||
🔴 Please generate a diagnostics report and upload the "diagnostics.log" as this helps me understand your configuration.
|
||||
|
||||
https://github.com/erew123/alltalk_tts/tree/main?#-how-to-make-a-diagnostics-report-file
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behaviour:
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Text/logs**
|
||||
If applicable, copy/paste in your logs here from the console.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
AllTalk was updated: [approx. date]
|
||||
Custom Python environment: [yes/no give details if yes]
|
||||
Text-generation-webUI was updated: [approx. date]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,73 @@
|
||||
name: 'Setting up docker'
|
||||
|
||||
inputs:
|
||||
DOCKERHUB_USERNAME:
|
||||
description: "Docker hub username"
|
||||
required: true
|
||||
DOCKERHUB_REPO_NAME:
|
||||
description: "Docker hub repo name"
|
||||
required: true
|
||||
DOCKERHUB_TOKEN:
|
||||
description: "Docker hub token"
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@v1.3.1
|
||||
with:
|
||||
tool-cache: true
|
||||
swap-storage: false
|
||||
large-packages: false
|
||||
- name: Read variables
|
||||
shell: bash
|
||||
run: |
|
||||
source ./docker/variables.sh
|
||||
for key in "${!ALLTALK_VARS[@]}"
|
||||
do
|
||||
echo "${key}=${ALLTALK_VARS[${key}]}"
|
||||
echo "${key}=${ALLTALK_VARS[${key}]}" >> $GITHUB_ENV
|
||||
done
|
||||
|
||||
- name: Extract version from Git Tag
|
||||
shell: bash {0}
|
||||
run: |
|
||||
# Use the git tag if existing, otherwise 'latest':
|
||||
DOCKER_TAG=$( echo "${{ github.ref }}" | grep -q tags | cut -d'/' -f 3 )
|
||||
if [ -z "${DOCKER_TAG}" ]; then
|
||||
DOCKER_TAG="latest"
|
||||
fi
|
||||
echo "Using DOCKER_TAG=${DOCKER_TAG}"
|
||||
echo "DOCKER_TAG=${DOCKER_TAG}" >> $GITHUB_ENV
|
||||
|
||||
- name: Extract Docker Hub User and Repo Name
|
||||
shell: bash
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ inputs.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_REPO_NAME: ${{ inputs.DOCKERHUB_REPO_NAME }}
|
||||
run: |
|
||||
if [ -n "${DOCKERHUB_USERNAME}" ]; then
|
||||
echo "Using Github repository variable 'DOCKERHUB_USERNAME' as Docker hub username with value: '${DOCKERHUB_USERNAME}'"
|
||||
echo "DOCKERHUB_USERNAME=${DOCKERHUB_USERNAME}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Using Github repository name as Docker hub username"
|
||||
echo "DOCKERHUB_USERNAME=$(echo ${{ github.repository }} | cut -d'/' -f 1)" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
if [ -n "${DOCKERHUB_REPO_NAME}" ]; then
|
||||
echo "Using Github repository variable 'DOCKERHUB_REPO_NAME' as Docker hub repo name with value: '${DOCKERHUB_REPO_NAME}'"
|
||||
echo "DOCKERHUB_REPO_NAME=${DOCKERHUB_REPO_NAME}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Using Github repository name as Docker hub repo name"
|
||||
echo "DOCKERHUB_REPO_NAME=$(echo ${{ github.repository }} | cut -d'/' -f 2)" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ inputs.DOCKERHUB_USERNAME }}
|
||||
password: ${{ inputs.DOCKERHUB_TOKEN }}
|
||||
@@ -0,0 +1,124 @@
|
||||
name: Publish Docker v2
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [ published ]
|
||||
push:
|
||||
branches:
|
||||
- 'alltalkbeta'
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
# Limit the concurrency of entire workflow runs for a specific branch:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build_base_environment_docker_image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup docker
|
||||
uses: ./.github/actions/docker-setup
|
||||
with:
|
||||
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_REPO_NAME: ${{ vars.DOCKERHUB_REPO_NAME }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}_environment
|
||||
tags: |
|
||||
# Use sematic versioning on push tag event:
|
||||
type=semver,pattern={{version}}
|
||||
# set latest tag for main and alltalkbeta branch:
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') || github.ref == format('refs/heads/{0}', 'alltalkbeta') }}
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
base: 'alltalkbeta'
|
||||
filters: |
|
||||
docker-base:
|
||||
- 'docker/variables.sh'
|
||||
- 'docker/base/Dockerfile'
|
||||
docker-workflow:
|
||||
- '.github/workflows/publish-docker*.yml'
|
||||
|
||||
- name: Build and push base Docker image
|
||||
if: |
|
||||
steps.changes.outputs.docker-base == 'true' ||
|
||||
steps.changes.outputs.docker-workflow == 'true' ||
|
||||
github.event_name == 'release' ||
|
||||
(github.event_name == 'push' && contains(github.ref, 'refs/tags/'))
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./docker/base
|
||||
file: ./docker/base/Dockerfile
|
||||
platforms: "linux/amd64"
|
||||
push: true
|
||||
build-args: |
|
||||
CUDA_VERSION=${{ env.CUDA_VERSION }}
|
||||
PYTHON_VERSION=${{ env.PYTHON_VERSION }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}_environment:buildcache
|
||||
cache-to: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}_environment:buildcache,mode=max
|
||||
|
||||
build_main_docker_image:
|
||||
needs: build_base_environment_docker_image
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
tts: [ xtts, vits, piper ]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup docker
|
||||
uses: ./.github/actions/docker-setup
|
||||
with:
|
||||
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_REPO_NAME: ${{ vars.DOCKERHUB_REPO_NAME }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}
|
||||
flavor: |
|
||||
suffix=-${{ matrix.tts }},onlatest=true
|
||||
tags: |
|
||||
# Use sematic versioning on push tag event:
|
||||
type=semver,pattern={{version}}
|
||||
# set latest tag for main and alltalkbeta branch:
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') || github.ref == format('refs/heads/{0}', 'alltalkbeta') }}
|
||||
|
||||
- name: Build and push base Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: "linux/amd64"
|
||||
push: true
|
||||
build-args: |
|
||||
TTS_MODEL=${{ matrix.tts }}
|
||||
ALLTALK_DIR=${{ env.ALLTALK_DIR }}
|
||||
DEEPSPEED_VERSION=${{ env.DEEPSPEED_VERSION }}
|
||||
DOCKER_TAG=${{ env.DOCKER_TAG }}
|
||||
DOCKER_REPOSITORY=${{ env.DOCKERHUB_USERNAME }}/
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}:buildcache-${{ matrix.tts }}
|
||||
cache-to: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}:buildcache-${{ matrix.tts }},mode=max
|
||||
@@ -0,0 +1,67 @@
|
||||
name: Publish Docker image (main branch)
|
||||
|
||||
on:
|
||||
# push:
|
||||
# branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_and_push:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: "Dockerfile"
|
||||
platforms: "linux/amd64"
|
||||
tag_name: "cpu"
|
||||
- dockerfile: "nvidia.Dockerfile"
|
||||
platforms: "linux/amd64"
|
||||
tag_name: "cuda"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Lowercase Actor and Extract Repo Name
|
||||
run: |
|
||||
echo "ACTOR_LOWER=$(echo ${{ github.actor }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
echo "REPO_NAME=$(echo ${{ github.repository }} | cut -d'/' -f 2)" >> $GITHUB_ENV
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ env.ACTOR_LOWER }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./${{ matrix.dockerfile }}
|
||||
platforms: ${{ matrix.platforms }}
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/${{ env.ACTOR_LOWER }}/${{ env.REPO_NAME }}:${{ matrix.tag_name }}-${{ github.sha }}
|
||||
ghcr.io/${{ env.ACTOR_LOWER }}/${{ env.REPO_NAME }}:${{ matrix.tag_name }}
|
||||
ghcr.io/${{ env.ACTOR_LOWER }}/${{ env.REPO_NAME }}:latest
|
||||
${{ vars.DOCKERHUB_USERNAME }}/${{ env.REPO_NAME }}:${{ matrix.tag_name }}-${{ github.sha }}
|
||||
${{ vars.DOCKERHUB_USERNAME }}/${{ env.REPO_NAME }}:${{ matrix.tag_name }}
|
||||
${{ vars.DOCKERHUB_USERNAME }}/${{ env.REPO_NAME }}:latest
|
||||
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v3.4.2
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
repository: ${{ vars.DOCKERHUB_USERNAME }}/${{ env.REPO_NAME }}
|
||||
+6
-174
@@ -1,176 +1,8 @@
|
||||
voices/*
|
||||
models/*
|
||||
outputs/*
|
||||
finetune/*
|
||||
alltalk_environment/*
|
||||
system/config/at_github_sha.json
|
||||
system/tts_engines/tts_engines.json
|
||||
voices/*.*
|
||||
models/*.*
|
||||
outputs/*.*
|
||||
finetune/*.*
|
||||
config.json
|
||||
confignew.json
|
||||
models.json
|
||||
diagnostics.log
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
|
||||
.idea/*
|
||||
|
||||
# Docker build
|
||||
docker/deepspeed/build
|
||||
@@ -1,78 +0,0 @@
|
||||
# Docker
|
||||
The Docker image currently works on Windows and Linux, optionally supporting NVIDIA GPUs.
|
||||
|
||||
## General Remarks
|
||||
- The resulting Docker image is 21 GB in size. Building might require even more disk space temporarily.
|
||||
- Another 15 GB is required for building DeepSpeed
|
||||
- Build time depends on your hardware and internet connection. Expect at least 20-30min to be normal for a full build.
|
||||
- This includes building the conda environment as well as DeepSpeed, which is the basis for the alltalk Docker image.
|
||||
- The Docker build for alltalk:
|
||||
- Downloads XTTS as default TTS engine
|
||||
- Enables RVC by default
|
||||
- Downloads all supported RVC models
|
||||
- Enables deepspeed by default
|
||||
- Starting the Docker image should only a few seconds due to all the steps that were already executed during build.
|
||||
|
||||
## Docker for Linux
|
||||
|
||||
### Ubuntu Specific Setup for GPUs
|
||||
1. Make sure the latest nvidia drivers are installed: `sudo ubuntu-drivers install`
|
||||
1. Install Docker your preferred way. One way to do it is to follow the official documentation [here](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions).
|
||||
- Start by uninstalling the old versions
|
||||
- Follow the "apt" repository installation method
|
||||
- Check that everything is working with the "hello-world" container
|
||||
1. If, when launching the docker contain, you have an error message saying that the GPU cannot be used, you might have to install [Nvidia Docker Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html).
|
||||
- Install with the "apt" method
|
||||
- Run the docker configuration command
|
||||
```sudo nvidia-ctk runtime configure --runtime=docker```
|
||||
- Restart docker
|
||||
|
||||
## Docker for Windows (WSL2)
|
||||
### Windows Specific Setup for GPUs
|
||||
> Make sure your Nvidia drivers are up to date: https://www.nvidia.com/download/index.aspx
|
||||
1. Install WSL2 in PowerShell with `wsl --install` and restart
|
||||
2. Open PowerShell, type and enter ```ubuntu```. It should now load you into wsl2
|
||||
3. Remove the original nvidia cache key: `sudo apt-key del 7fa2af80`
|
||||
4. Download CUDA toolkit keyring: `wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb`
|
||||
5. Install keyring: `sudo dpkg -i cuda-keyring_1.1-1_all.deb`
|
||||
6. Update package list: `sudo apt-get update`
|
||||
7. Install CUDA toolkit: `sudo apt-get -y install cuda-toolkit-12-6`
|
||||
8. Install Docker Desktop using WSL2 as the backend
|
||||
9. Restart
|
||||
10. If you wish to monitor the terminal remotely via SSH, follow [this guide](https://www.hanselman.com/blog/how-to-ssh-into-wsl2-on-windows-10-from-an-external-machine).
|
||||
11. Open PowerShell, type ```ubuntu```, [then follow below](#building-and-running-in-docker)
|
||||
|
||||
## Building and Running in Docker
|
||||
|
||||
1. Open a terminal (or Ubuntu WSL) and go where you cloned the repo
|
||||
3. Build the image with `./docker-build.sh`
|
||||
4. Start the container with `./docker-start.sh`
|
||||
5. Visit `http://localhost:7851/` or remotely with `http://<ip>:7851`
|
||||
|
||||
## Arguments for building and starting docker
|
||||
There are various arguments to customize the build and start of the docker image.
|
||||
|
||||
### Arguments for `docker-build.sh`
|
||||
- `--tts_model` allows to choose the TTS model that is used by default. Valid values are `piper`, `vits`, `xtts`. Defaults to `xtts`.
|
||||
- Example: `docker-build.sh --tts_model piper`
|
||||
- `--tag` allows to choose the docker tag. Defaults to `latest`.
|
||||
- Example: `docker-build.sh --tag mytag`
|
||||
- `--clean` allows remove existing dependency build like conda environment or DeepSpeed.
|
||||
- Example: `docker-build.sh --clean`
|
||||
|
||||
### Arguments for `docker-start.sh`
|
||||
- `--config` lets you choose a config JSON file which can subset of `confignew.json`. This allows you to change only
|
||||
few values and leave the rest as defined in the default `confignew.json` file.
|
||||
- Example: `docker-start.sh --config /my/config/file.json` with content `{"branding": "My Brand "}` will just change
|
||||
the branding in `confignew.json`.
|
||||
- `--voices` lets you add voices for the TTS engine in WAV format. You have to specify the folder containing all
|
||||
voice files.
|
||||
- Example: `docker-start.sh --voices /my/voices/dir`
|
||||
- `--rvc_voices` similar to voices, this option lets you pick the folder containing the RVC models.
|
||||
- Example: `docker-start.sh --rvc_voices /my/rvc/voices/dir`
|
||||
- `--no_ui` allows you to not expose port 7852 for the gradio interface. Note that you still have to set `launch_gradio`
|
||||
to `false` via JSON file passed to `--config`.
|
||||
- `--tag` allows to choose the docker tag of the image to run. Defaults to `latest`.
|
||||
- Example: `docker-start.sh --tag mytag`
|
||||
- Since the above commands only address the most important options, you might pass additional arbitrary docker commands
|
||||
to the `docker-start.sh`.
|
||||
+17
-121
@@ -1,124 +1,20 @@
|
||||
ARG GITHUB_REPOSITORY
|
||||
FROM ${GITHUB_REPOSITORY}alltalk_environment:latest
|
||||
|
||||
# Argument to choose the model: piper, vits, xtts
|
||||
ARG TTS_MODEL="xtts"
|
||||
ENV TTS_MODEL=$TTS_MODEL
|
||||
|
||||
ARG DEEPSPEED_VERSION=0.16.2
|
||||
ENV DEEPSPEED_VERSION=$DEEPSPEED_VERSION
|
||||
|
||||
ARG ALLTALK_DIR=/opt/alltalk
|
||||
|
||||
ENV GRADIO_SERVER_NAME="0.0.0.0"
|
||||
|
||||
WORKDIR ${ALLTALK_DIR}
|
||||
|
||||
##############################################################################
|
||||
# Install python dependencies (cannot use --no-deps because requirements are not complete)
|
||||
##############################################################################
|
||||
COPY system/config system/config
|
||||
COPY system/requirements/requirements_standalone.txt system/requirements/requirements_standalone.txt
|
||||
COPY system/requirements/requirements_parler.txt system/requirements/requirements_parler.txt
|
||||
ENV PIP_CACHE_DIR=${ALLTALK_DIR}/pip_cache
|
||||
RUN <<EOR
|
||||
conda activate alltalk
|
||||
|
||||
mkdir ${ALLTALK_DIR}/pip_cache
|
||||
pip install --no-cache-dir --cache-dir=${ALLTALK_DIR}/pip_cache -r system/requirements/requirements_standalone.txt
|
||||
pip install --no-cache-dir --cache-dir=${ALLTALK_DIR}/pip_cache --upgrade gradio==4.32.2
|
||||
# Parler:
|
||||
pip install --no-cache-dir --cache-dir=${ALLTALK_DIR}/pip_cache -r system/requirements/requirements_parler.txt
|
||||
|
||||
conda clean --all --force-pkgs-dirs -y && pip cache purge
|
||||
EOR
|
||||
|
||||
##############################################################################
|
||||
# Install DeepSpeed
|
||||
##############################################################################
|
||||
RUN mkdir -p /tmp/deepseped
|
||||
COPY docker/deepspeed/build/*.whl /tmp/deepspeed/
|
||||
RUN <<EOR
|
||||
DEEPSPEED_WHEEL=$(realpath /tmp/deepspeed/*.whl)
|
||||
conda activate alltalk
|
||||
|
||||
echo "Using precompiled DeepSpeed wheel at ${DEEPSPEED_WHEEL}"
|
||||
CFLAGS="-I$CONDA_PREFIX/include/" LDFLAGS="-L$CONDA_PREFIX/lib/" \
|
||||
pip install --no-cache-dir ${DEEPSPEED_WHEEL}
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Failed to install pip dependencies: $RESULT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm ${DEEPSPEED_WHEEL}
|
||||
conda clean --all --force-pkgs-dirs -y && pip cache purge
|
||||
EOR
|
||||
|
||||
##############################################################################
|
||||
# Writing scripts to start alltalk:
|
||||
##############################################################################
|
||||
RUN <<EOR
|
||||
cat << EOF > start_alltalk.sh
|
||||
#!/usr/bin/env bash
|
||||
source ~/.bashrc
|
||||
|
||||
# Merging config from docker_confignew.json into confignew.json:
|
||||
jq -s '.[0] * .[1] * .[2]' confignew.json docker_default_config.json docker_confignew.json > confignew.json.tmp
|
||||
mv confignew.json.tmp confignew.json
|
||||
|
||||
conda activate alltalk
|
||||
python script.py
|
||||
EOF
|
||||
cat << EOF > start_finetune.sh
|
||||
#!/usr/bin/env bash
|
||||
source ~/.bashrc
|
||||
export TRAINER_TELEMETRY=0
|
||||
conda activate alltalk
|
||||
python finetune.py
|
||||
EOF
|
||||
cat << EOF > start_diagnostics.sh
|
||||
#!/usr/bin/env bash
|
||||
source ~/.bashrc
|
||||
conda activate alltalk
|
||||
python diagnostics.py
|
||||
EOF
|
||||
chmod +x start_alltalk.sh
|
||||
chmod +x start_finetune.sh
|
||||
chmod +x start_diagnostics.sh
|
||||
EOR
|
||||
FROM nvidia/cuda:12.1.1-devel-ubuntu22.04
|
||||
ENV HOST 0.0.0.0
|
||||
RUN apt-get update && apt-get upgrade -y \
|
||||
&& apt-get install -y git build-essential portaudio19-dev \
|
||||
python3 python3-pip gcc wget \
|
||||
ocl-icd-opencl-dev opencl-headers clinfo \
|
||||
libclblast-dev libopenblas-dev libaio-dev \
|
||||
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
|
||||
&& ln -s /usr/bin/python3 /usr/bin/python
|
||||
|
||||
WORKDIR /app
|
||||
ENV CUDA_DOCKER_ARCH=all
|
||||
COPY system/requirements/requirements_docker.txt system/requirements/requirements_docker.txt
|
||||
RUN pip install --no-cache-dir --no-deps -r system/requirements/requirements_docker.txt && \
|
||||
pip install --no-cache-dir deepspeed
|
||||
COPY . .
|
||||
|
||||
##############################################################################
|
||||
# Create script to execute firstrun.py and run it:
|
||||
##############################################################################
|
||||
RUN echo $'#!/usr/bin/env bash \n\
|
||||
source ~/.bashrc \n\
|
||||
conda activate alltalk \n\
|
||||
python ./system/config/firstrun.py $@' > ./start_firstrun.sh
|
||||
|
||||
RUN chmod +x start_firstrun.sh
|
||||
RUN ./start_firstrun.sh --tts_model $TTS_MODEL
|
||||
|
||||
RUN mkdir -p ${ALLTALK_DIR}/outputs
|
||||
RUN mkdir -p /root/.triton/autotune
|
||||
|
||||
##############################################################################
|
||||
# Enable deepspeed for all models:
|
||||
##############################################################################
|
||||
RUN find . -name model_settings.json -exec sed -i -e 's/"deepspeed_enabled": false/"deepspeed_enabled": true/g' {} \;
|
||||
|
||||
##############################################################################
|
||||
# Download all RVC models:
|
||||
##############################################################################
|
||||
RUN <<EOR
|
||||
jq -r '.[]' system/tts_engines/rvc_files.json > /tmp/rvc_files.txt
|
||||
xargs -n 1 curl --create-dirs --output-dir models/rvc_base -LO < /tmp/rvc_files.txt
|
||||
rm -f /tmp/rvc_files.txt
|
||||
EOR
|
||||
|
||||
##############################################################################
|
||||
# Start alltalk:
|
||||
##############################################################################
|
||||
ENTRYPOINT ["sh", "-c", "./start_alltalk.sh"]
|
||||
EXPOSE 7851 7852
|
||||
RUN chmod +x launch.sh
|
||||
ENTRYPOINT ["sh", "-c", "./launch.sh"]
|
||||
+35
-227
@@ -42,9 +42,6 @@ if "%ERRORLEVEL%" NEQ "0" (
|
||||
goto end
|
||||
)
|
||||
|
||||
:: Check for "-silent" install command-line argument
|
||||
if "%1"=="-silent" goto InstallCustomStandalone
|
||||
|
||||
:MainMenu
|
||||
cls
|
||||
echo.
|
||||
@@ -52,11 +49,10 @@ echo %L_BLUE%ALLTALK WINDOWS SETUP UTILITY%RESET%
|
||||
echo.
|
||||
echo INSTALLATION TYPE
|
||||
echo 1) I am using AllTalk as part of %L_GREEN%Text-generation-webui%RESET%
|
||||
echo 2) I am using AllTalk as a %L_BLUE%Standalone Application%RESET%
|
||||
echo 2) I am using AllTalk as a %L_GREEN%Standalone Application%RESET%
|
||||
echo.
|
||||
echo 9) %L_RED%Exit/Quit%RESET%
|
||||
echo.
|
||||
echo.
|
||||
set /p UserOption=" Enter your choice: "
|
||||
|
||||
if "%UserOption%"=="1" goto WebUIMenu
|
||||
@@ -138,13 +134,6 @@ goto StandaloneMenu
|
||||
|
||||
:InstallNvidiaTextGen
|
||||
pip install -r system\requirements\requirements_textgen.txt
|
||||
pip install -r system\requirements\requirements_textgen2.txt
|
||||
pip install -r system\requirements\requirements_parler.txt
|
||||
echo ** Faiss **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y pytorch::faiss-cpu
|
||||
echo ** FFmpeg **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y -c conda-forge "ffmpeg=*=*gpl*"
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y -c conda-forge "ffmpeg=*=h*_*" --no-deps
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo.
|
||||
echo There was an error installing the requirements.
|
||||
@@ -370,7 +359,7 @@ set TEMP=%cd%\alltalk_environment
|
||||
set INSTALL_DIR=%cd%\alltalk_environment
|
||||
set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda
|
||||
set INSTALL_ENV_DIR=%cd%\alltalk_environment\env
|
||||
set MINICONDA_DOWNLOAD_URL=https://repo.anaconda.com/miniconda/Miniconda3-py311_24.4.0-0-Windows-x86_64.exe
|
||||
set MINICONDA_DOWNLOAD_URL=https://repo.anaconda.com/miniconda/Miniconda3-py310_23.3.1-0-Windows-x86_64.exe
|
||||
set conda_exists=F
|
||||
|
||||
@rem figure out whether git and conda need to be installed
|
||||
@@ -392,207 +381,28 @@ call "%CONDA_ROOT_PREFIX%\_conda.exe" --version || ( echo. && echo Miniconda not
|
||||
|
||||
@rem create the installer env
|
||||
echo Packages to install: %PACKAGES_TO_INSTALL%
|
||||
call "%CONDA_ROOT_PREFIX%\_conda.exe" create --no-shortcuts -y -k --prefix "%INSTALL_ENV_DIR%" python=3.11.9 || ( echo. && echo Conda environment creation failed. && goto end )
|
||||
call "%CONDA_ROOT_PREFIX%\_conda.exe" create --no-shortcuts -y -k --prefix "%INSTALL_ENV_DIR%" python=3.11 || ( echo. && echo Conda environment creation failed. && goto end )
|
||||
|
||||
@rem check if conda environment was actually created
|
||||
if not exist "%INSTALL_ENV_DIR%\python.exe" ( echo. && echo Conda environment is empty. && goto end )
|
||||
|
||||
@rem activate installer env
|
||||
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" || ( echo. && echo Miniconda hook not found. && goto end )
|
||||
rem Install required packages
|
||||
|
||||
:install_pytorch
|
||||
echo ** Installing PyTorch 2.2.1 **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y pytorch==2.2.1 torchvision==0.17.1 torchaudio==2.2.1 pytorch-cuda=12.1 -c pytorch -c nvidia
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo PyTorch installation failed, errorlevel was %errorlevel%. There should be a Conda
|
||||
echo error message above with a code and/or text explanation of the issue. Please note
|
||||
echo the error code to help with diagnotics.
|
||||
echo.
|
||||
echo Generally speaking though, errors could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download PyTorch from Conda's website.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Conda environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to Conda's servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Known errors are in the AllTalk Github Wiki > Error Messages Help/Support
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the Pytorch installation?"
|
||||
if errorlevel 2 goto End
|
||||
if errorlevel 1 goto install_pytorch
|
||||
) else (
|
||||
echo PyTorch installation was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
:install_faiss
|
||||
echo ** Installing Faiss **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y pytorch::faiss-cpu
|
||||
echo Downloading and installing PyTorch. This step can take a long time
|
||||
echo depending on your internet connection and hard drive speed. Please
|
||||
echo be patient.
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo Faiss installation failed, errorlevel was %errorlevel%. There should be a Conda
|
||||
echo error message above with a code and/or text explanation of the issue. Please note
|
||||
echo the error code to help with diagnotics.
|
||||
echo.
|
||||
echo Generally speaking though, errors could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download Faiss from Conda's website.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Conda environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to Conda's servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Your Conda policy is set to Strict see the Github Wiki for help with this.
|
||||
echo 8. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Known errors are in the AllTalk Github Wiki > Error Messages Help/Support
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the Faiss installation?"
|
||||
if errorlevel 2 goto End
|
||||
if errorlevel 1 goto install_faiss
|
||||
) else (
|
||||
echo Faiss installation was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
:install_ffmpeg
|
||||
echo ** Installing FFmpeg **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y -c conda-forge "ffmpeg=*=*gpl*"
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y -c conda-forge "ffmpeg=*=h*_*" --no-deps
|
||||
pip install torch==2.2.2+cu121 torchaudio>=2.2.2+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo Installing other requirements.
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo FFmpeg installation failed, errorlevel was %errorlevel%. There should be a Conda
|
||||
echo error message above with a code and/or text explanation of the issue. Please note
|
||||
echo the error code to help with diagnotics.
|
||||
echo.
|
||||
echo Generally speaking though, errors could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download FFmpeg from Conda's website.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Conda environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to Conda's servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Your Conda policy is set to Strict see the Github Wiki for help with this.
|
||||
echo 8. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Known errors are in the AllTalk Github Wiki > Error Messages Help/Support
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the FFmpeg installation?"
|
||||
if errorlevel 2 goto End
|
||||
if errorlevel 1 goto install_ffmpeg
|
||||
) else (
|
||||
echo FFmpeg installation was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ** Requirements file **
|
||||
pip install -r system\requirements\requirements_standalone.txt
|
||||
echo.
|
||||
|
||||
:update_gradio
|
||||
echo ** Updating Gradio **
|
||||
pip install --upgrade gradio==4.44.1
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo Gradio update failed, errorlevel was %errorlevel%. There should be an error
|
||||
echo message above with a code and/or text explanation of the issue. Please note
|
||||
echo the error code to help with diagnotics.
|
||||
echo.
|
||||
echo Generally speaking though, errors could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download Gradio from PyPI.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Python environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to PyPI servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Known errors are in the AllTalk Github Wiki > Error Messages Help/Support
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the Gradio update?"
|
||||
if errorlevel 2 goto End
|
||||
if errorlevel 1 goto update_gradio
|
||||
) else (
|
||||
echo Gradio update was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
:install_deepspeed
|
||||
echo ** Downloading DeepSpeed **
|
||||
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo DeepSpeed download failed, errorlevel was %errorlevel%. There should be an error
|
||||
echo message above with a code and/or text explanation of the issue. Please note
|
||||
echo the error code to help with diagnotics.
|
||||
echo.
|
||||
echo Generally speaking though, errors could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to reach GitHub.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Permissions issues - Check you have enough rights on this system.
|
||||
echo 4. Firewall or proxy settings blocking access to GitHub.
|
||||
echo 5. Antivirus or security software interference.
|
||||
echo 6. The file may have been moved or deleted from the GitHub repository.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Known errors are in the AllTalk Github Wiki > Error Messages Help/Support
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the DeepSpeed download?"
|
||||
if errorlevel 2 goto End
|
||||
if errorlevel 1 goto install_deepspeed
|
||||
) else (
|
||||
echo DeepSpeed download was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ** Installing DeepSpeed **
|
||||
echo Installing DeepSpeed...
|
||||
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo DeepSpeed installation failed, errorlevel was %errorlevel%. There should be an error
|
||||
echo message above with a code and/or text explanation of the issue. Please note
|
||||
echo the error code to help with diagnotics. General issues may be:
|
||||
echo.
|
||||
echo Generally speaking though, errors could be caused by:
|
||||
echo.
|
||||
echo 1. The DeepSpeed wheel file was not downloaded successfully in the previous step.
|
||||
echo 2. Microsoft C++ development tools for Python are not installed correctly.
|
||||
echo 3. Disk space related issues - Check your disk space on this drive.
|
||||
echo 4. Incorrect or missing Python environment - Restart installation.
|
||||
echo 5. Permissions issues - Check you have enough rights on this system.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Known errors are in the AllTalk Github Wiki > Error Messages Help/Support
|
||||
echo.
|
||||
echo Please ensure you have followed the instructions to install the Microsoft C++ development
|
||||
echo tools for Python, which is detailed on the AllTalk GitHub page.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the DeepSpeed installation?"
|
||||
if errorlevel 2 goto End
|
||||
if errorlevel 1 goto install_deepspeed
|
||||
) else (
|
||||
echo DeepSpeed installation was successful.
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo.
|
||||
)
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
|
||||
echo ** Installing Parler **
|
||||
pip install -r system\requirements\requirements_parler.txt
|
||||
echo Clean Environment
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" clean --all --force-pkgs-dirs -y
|
||||
echo.
|
||||
|
||||
echo.
|
||||
echo Installation process completed.
|
||||
|
||||
@rem Create start_environment.bat to run AllTalk environment
|
||||
echo @echo off > start_environment.bat
|
||||
@@ -614,22 +424,11 @@ echo set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda >> start_finetune.bat
|
||||
echo set INSTALL_ENV_DIR=%cd%\alltalk_environment\env >> start_finetune.bat
|
||||
echo call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" >> start_finetune.bat
|
||||
echo call python finetune.py >> start_finetune.bat
|
||||
echo @echo off > start_diagnostics.bat
|
||||
echo cd /D "%~dp0" >> start_diagnostics.bat
|
||||
echo set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda >> start_diagnostics.bat
|
||||
echo set INSTALL_ENV_DIR=%cd%\alltalk_environment\env >> start_diagnostics.bat
|
||||
echo call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" >> start_diagnostics.bat
|
||||
echo call python diagnostics.py >> start_diagnostics.bat
|
||||
Echo.
|
||||
Echo Run %L_YELLOW%start_alltalk.bat%RESET% to start AllTalk.
|
||||
Echo Run %L_YELLOW%start_diagnostics.bat%RESET% to start the diagnostics.
|
||||
Echo Run %L_YELLOW%start_finetune.bat%RESET% to start Finetuning.
|
||||
Echo Run %L_YELLOW%start_environment.bat%RESET% to start the AllTalk Python environment.
|
||||
Echo.
|
||||
Echo Documentation is built into the Gradio interface. Please explore the documentation for
|
||||
Echo tips, troubleshooing and explanations as most common questions are answered there.
|
||||
Echo.
|
||||
if "%1"=="-silent" goto End
|
||||
pause
|
||||
goto StandaloneMenu
|
||||
|
||||
@@ -646,7 +445,7 @@ if not exist "%cd%\alltalk_environment\" (
|
||||
if not defined CONDA_PREFIX goto NoCondaEnvDeleteCustomStandalone
|
||||
@rem Deactivate Conda environment if it's active
|
||||
Echo Exiting the Conda Environment. Please run %L_GREEN%atsetup.bat%RESET% again and delete the environment.
|
||||
call conda deactivate
|
||||
conda deactivate
|
||||
:NoCondaEnvDeleteCustomStandalone
|
||||
echo Deleting "alltalk_environment". Please wait.
|
||||
rd /s /q "alltalk_environment"
|
||||
@@ -656,7 +455,6 @@ if %ERRORLEVEL% neq 0 (
|
||||
echo.
|
||||
echo Failed to delete alltalk_environment folder.
|
||||
echo Please make sure it is not in use and try again.
|
||||
echo Worst case, manually delete the folder called 'alltalk_environment'
|
||||
echo.
|
||||
pause
|
||||
goto StandaloneMenu
|
||||
@@ -733,14 +531,32 @@ if errorlevel 1 (
|
||||
)
|
||||
@rem Run Reapply requirements
|
||||
echo.
|
||||
echo Re-installing requirements. If you have problems after this, it may indicate
|
||||
echo that the custom Python environment is damaged in some way. As such it may be
|
||||
echo best to delete the custom Python environment and re-run the entire setup
|
||||
echo routine again to rebuild AllTalk's Python environment. Please press a key
|
||||
echo to continue re-applying the Requirements for a standalone installation.
|
||||
echo Downloading and installing PyTorch. This step can take a long time
|
||||
echo depending on your internet connection and hard drive speed. Please
|
||||
echo be patient.
|
||||
echo.
|
||||
pip install torch==2.2.2+cu121 torchaudio>=2.2.2+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo Installing other requirements.
|
||||
echo.
|
||||
pip install -r system\requirements\requirements_standalone.txt
|
||||
C:/Windows/system32/curl.exe -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo Installing DeepSpeed...
|
||||
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo.
|
||||
echo There was an error.
|
||||
echo Press any key to return to the menu.
|
||||
echo.
|
||||
pause
|
||||
goto StandaloneMenu
|
||||
)
|
||||
Echo.
|
||||
Echo.
|
||||
Echo Requirements have been re-applied/updated.
|
||||
Echo.
|
||||
pause
|
||||
goto install_faiss
|
||||
goto StandaloneMenu
|
||||
|
||||
:STPurgepipcache
|
||||
cd /D "%~dp0"
|
||||
@@ -832,20 +648,12 @@ goto StandaloneMenu
|
||||
echo Exiting AllTalk Setup Utility...
|
||||
echo.
|
||||
Echo Remember, after installation you can....
|
||||
Echo.
|
||||
Echo Run %L_YELLOW%start_alltalk.bat%RESET% to start AllTalk.
|
||||
Echo Run %L_YELLOW%start_finetune.bat%RESET% to start Finetuning.
|
||||
Echo Run %L_YELLOW%start_environment.bat%RESET% to start the AllTalk Python environment.
|
||||
Echo Run %L_YELLOW%start_diagnostics.bat%RESET% to start generate a diagnostics file.
|
||||
Echo.
|
||||
Echo Documentation is built into the Gradio interface. Please explore the documentation for
|
||||
Echo tips, troubleshooing and explanations as most common questions are answered there.
|
||||
exit /b
|
||||
|
||||
:End
|
||||
echo Exiting AllTalk Setup Utility...
|
||||
Echo.
|
||||
Echo Documentation is built into the Gradio interface and the AllTalk Wiki page on Github.
|
||||
Echo Please explore the documentation for tips, troubleshooing and explanations on the most
|
||||
Echo common questions.
|
||||
exit /b
|
||||
+28
-66
@@ -139,37 +139,6 @@ install_nvidia_textgen() {
|
||||
fi
|
||||
echo
|
||||
echo " Requirements installed successfully."
|
||||
|
||||
echo " Installing additional requirements..."
|
||||
if ! pip install -r system/requirements/requirements_textgen2.txt; then
|
||||
echo
|
||||
echo " There was an error installing additional requirements."
|
||||
echo " Please check the output for details."
|
||||
read -p " Press any key to return to the menu. " -n 1
|
||||
echo
|
||||
return
|
||||
fi
|
||||
|
||||
if ! conda install -y pytorch::faiss-cpu; then
|
||||
echo
|
||||
echo " There was an error installing faiss-cpu."
|
||||
echo " Please check the output for details."
|
||||
read -p " Press any key to return to the menu. " -n 1
|
||||
echo
|
||||
return
|
||||
fi
|
||||
|
||||
if ! conda install -y conda-forge::ffmpeg; then
|
||||
echo
|
||||
echo " There was an error installing ffmpeg."
|
||||
echo " Please check the output for details."
|
||||
read -p " Press any key to return to the menu. " -n 1
|
||||
echo
|
||||
return
|
||||
fi
|
||||
|
||||
echo
|
||||
echo " Additional requirements installed successfully."
|
||||
echo
|
||||
echo -e " To install ${L_YELLOW}DeepSpeed${NC} on Linux, there are additional"
|
||||
echo -e " steps required. Please see the Github or documentation on DeepSeed."
|
||||
@@ -178,7 +147,6 @@ install_nvidia_textgen() {
|
||||
echo
|
||||
}
|
||||
|
||||
|
||||
tg_gitpull() {
|
||||
echo
|
||||
if ! git pull; then
|
||||
@@ -204,9 +172,17 @@ install_deepspeed() {
|
||||
echo
|
||||
echo -e " ${L_BLUE}DEEPSPEED INSTALLATION REQUIREMENTS${NC}"
|
||||
echo
|
||||
echo -e " - Please go see this link as the instructions are there.${NC}"
|
||||
echo -e " The instructions there are making it as simple as posisble.${NC}"
|
||||
echo -e " ${L_GREEN}https://github.com/erew123/alltalk_tts/releases/tag/DeepSpeed-14.2-Linux${NC}"
|
||||
echo -e " - NVIDIA CUDA Toolkit must be installed from your ${L_GREEN}Linux package manager${NC}"
|
||||
echo -e " or ${L_GREEN}https://developer.nvidia.com/cuda-toolkit-archive${NC}"
|
||||
echo -e " - The environment variable ${L_GREEN}CUDA_HOME${NC} must be set in your Python env"
|
||||
echo -e " e.g. export CUDA_HOME=/usr/local/cuda."
|
||||
echo -e " - ${L_GREEN}libaio-dev${NC} must be installed."
|
||||
echo
|
||||
echo -e " See the following link for full instructions:"
|
||||
echo -e " ${L_GREEN}https://github.com/erew123/alltalk_tts?#-deepspeed-installation-options${NC}"
|
||||
echo
|
||||
echo -e " ${L_BLUE}Please ${L_RED}confirm${L_BLUE} that you have completed these steps before continuing"
|
||||
echo -e " with the DeepSpeed installation, or the install ${L_RED}will fail.${NC}"
|
||||
echo
|
||||
read -p " Have you completed all the above steps? (y/n): " confirm
|
||||
|
||||
@@ -216,7 +192,7 @@ install_deepspeed() {
|
||||
fi
|
||||
|
||||
echo -e "\n ${GREEN}Proceeding with DeepSpeed installation...${NC}"
|
||||
|
||||
pip install deepspeed
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e " ${RED}There was an error installing DeepSpeed.${NC}"
|
||||
return
|
||||
@@ -279,6 +255,9 @@ standalone_menu() {
|
||||
echo " 4) Delete AllTalk's custom Python environment"
|
||||
echo " 5) Purge the PIP cache"
|
||||
echo
|
||||
echo " DEEPSPEED"
|
||||
echo " 6) DeepSpeed Instructions/Install"
|
||||
echo
|
||||
echo " OTHER"
|
||||
echo " 8) Generate a diagnostics file"
|
||||
echo
|
||||
@@ -292,6 +271,7 @@ standalone_menu() {
|
||||
3) reapply_standalone ;;
|
||||
4) delete_custom_standalone ;;
|
||||
5) pippurge_standalone ;;
|
||||
6) install_deepspeed ;;
|
||||
8) generate_diagnostics_standalone ;;
|
||||
9) exit 0 ;;
|
||||
*) echo "Invalid option"; sleep 2 ;;
|
||||
@@ -322,7 +302,8 @@ install_custom_standalone() {
|
||||
INSTALL_DIR="$(pwd)/alltalk_environment"
|
||||
CONDA_ROOT_PREFIX="${INSTALL_DIR}/conda"
|
||||
INSTALL_ENV_DIR="${INSTALL_DIR}/env"
|
||||
MINICONDA_DOWNLOAD_URL="https://repo.anaconda.com/miniconda/Miniconda3-py311_24.4.0-0-Linux-${OS_ARCH}.sh"
|
||||
MINICONDA_DOWNLOAD_URL="https://repo.anaconda.com/miniconda/Miniconda3-py310_23.3.1-0-Linux-${OS_ARCH}.sh"
|
||||
|
||||
if [ ! -x "${CONDA_ROOT_PREFIX}/bin/conda" ]; then
|
||||
echo "Downloading Miniconda from $MINICONDA_DOWNLOAD_URL to ${INSTALL_DIR}/miniconda_installer.sh"
|
||||
mkdir -p "${INSTALL_DIR}"
|
||||
@@ -333,37 +314,22 @@ install_custom_standalone() {
|
||||
fi
|
||||
|
||||
if [ ! -d "${INSTALL_ENV_DIR}" ]; then
|
||||
"${CONDA_ROOT_PREFIX}/bin/conda" create -y --prefix "${INSTALL_ENV_DIR}" -c conda-forge python=3.11.9
|
||||
"${CONDA_ROOT_PREFIX}/bin/conda" create -y --prefix "${INSTALL_ENV_DIR}" python=3.11
|
||||
echo "Conda environment created at ${INSTALL_ENV_DIR}."
|
||||
fi
|
||||
|
||||
# Activate the environment and install requirements
|
||||
source "${CONDA_ROOT_PREFIX}/etc/profile.d/conda.sh"
|
||||
conda activate "${INSTALL_ENV_DIR}"
|
||||
# pip install torch==2.2.1+cu121 torchaudio==2.2.1+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121 --no-cache-dir
|
||||
conda install -y pytorch=2.2.1 torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia
|
||||
conda install -y nvidia/label/cuda-12.1.0::cuda-toolkit=12.1
|
||||
conda install -y pytorch::faiss-cpu
|
||||
conda install -y -c conda-forge "ffmpeg=*=*gpl*"
|
||||
conda install -y -c conda-forge "ffmpeg=*=h*_*" --no-deps
|
||||
echo
|
||||
echo " Downloading and installing PyTorch. This step can take a long time"
|
||||
echo " depending on your internet connection and hard drive speed. Please"
|
||||
echo " be patient."
|
||||
pip install torch==2.2.1+cu121 torchaudio==2.2.1+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo
|
||||
echo
|
||||
echo " Fix Nvidia's broken symlinks in the /env/lib folder"
|
||||
echo
|
||||
# Define the environment path
|
||||
env_path="${INSTALL_ENV_DIR}/lib"
|
||||
|
||||
echo " Installing additional requirements."
|
||||
echo
|
||||
pip install -r system/requirements/requirements_standalone.txt
|
||||
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
|
||||
pip install --upgrade gradio==4.44.1
|
||||
echo Installing DeepSpeed...
|
||||
pip install deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
|
||||
rm deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
|
||||
pip install -r system/requirements/requirements_parler.txt
|
||||
conda clean --all --force-pkgs-dirs -y
|
||||
# Create start_environment.sh to run AllTalk
|
||||
cat << EOF > start_environment.sh
|
||||
#!/bin/bash
|
||||
@@ -380,36 +346,33 @@ unset PYTHONPATH
|
||||
unset PYTHONHOME
|
||||
export CUDA_PATH="$INSTALL_ENV_DIR"
|
||||
export CUDA_HOME="$CUDA_PATH"
|
||||
export LD_LIBRARY_PATH=`python3 -c 'import os; import nvidia.cublas.lib; import nvidia.cudnn.lib; print(os.path.dirname(nvidia.cublas.lib.__file__) + ":" + os.path.dirname(nvidia.cudnn.lib.__file__))'`
|
||||
# activate env
|
||||
bash --init-file <(echo "source \"$CONDA_ROOT_PREFIX/etc/profile.d/conda.sh\" && conda activate \"$INSTALL_ENV_DIR\"")
|
||||
EOF
|
||||
# Create start_alltalk.sh to run AllTalk
|
||||
cat << EOF > start_alltalk.sh
|
||||
#!/bin/bash
|
||||
export LD_LIBRARY_PATH=`python3 -c 'import os; import nvidia.cublas.lib; import nvidia.cudnn.lib; print(os.path.dirname(nvidia.cublas.lib.__file__) + ":" + os.path.dirname(nvidia.cudnn.lib.__file__))'`
|
||||
source "${CONDA_ROOT_PREFIX}/etc/profile.d/conda.sh"
|
||||
conda activate "${INSTALL_ENV_DIR}"
|
||||
python script.py
|
||||
EOF
|
||||
# Create start_finetune.sh to run AllTalk
|
||||
cat << EOF > start_finetune.sh
|
||||
#!/bin/bash
|
||||
export TRAINER_TELEMETRY=0
|
||||
export LD_LIBRARY_PATH=`python3 -c 'import os; import nvidia.cublas.lib; import nvidia.cudnn.lib; print(os.path.dirname(nvidia.cublas.lib.__file__) + ":" + os.path.dirname(nvidia.cudnn.lib.__file__))'`
|
||||
source "${CONDA_ROOT_PREFIX}/etc/profile.d/conda.sh"
|
||||
conda activate "${INSTALL_ENV_DIR}"
|
||||
python finetune.py
|
||||
EOF
|
||||
cat << EOF > start_diagnostics.sh
|
||||
#!/bin/bash
|
||||
source "${CONDA_ROOT_PREFIX}/etc/profile.d/conda.sh"
|
||||
conda activate "${INSTALL_ENV_DIR}"
|
||||
python diagnostics.py
|
||||
EOF
|
||||
chmod +x start_alltalk.sh
|
||||
chmod +x start_environment.sh
|
||||
chmod +x start_finetune.sh
|
||||
chmod +x start_diagnostics.sh
|
||||
echo
|
||||
echo
|
||||
echo -e " Run ${L_YELLOW}./start_alltalk.sh${NC} to start AllTalk."
|
||||
echo -e " Run ${L_YELLOW}./start_diagnostics.sh${NC} to start Diagnostics."
|
||||
echo -e " Run ${L_YELLOW}./start_finetune.sh${NC} to start Finetuning."
|
||||
echo -e " Run ${L_YELLOW}./start_environment.sh${NC} to start the AllTalk Python environment."
|
||||
echo
|
||||
@@ -545,7 +508,6 @@ reapply_standalone() {
|
||||
echo " Installing additional requirements."
|
||||
echo
|
||||
pip install -r system/requirements/requirements_standalone.txt
|
||||
pip install -r system/requirements/requirements_parler.txt
|
||||
echo
|
||||
echo " Requirements have been re-applied/updated."
|
||||
echo
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from filelock import FileLock
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, MutableSequence
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, AliasGenerator, AliasChoices, Field
|
||||
|
||||
class AlltalkConfigTheme(BaseModel):
|
||||
# Map 'class' to 'clazz' and vice versa
|
||||
model_config = ConfigDict(
|
||||
alias_generator=AliasGenerator(
|
||||
validation_alias=lambda field_name:
|
||||
{
|
||||
"clazz": AliasChoices("clazz", "class"),
|
||||
}.get(field_name, None),
|
||||
serialization_alias=lambda field_name: "class" if field_name == "clazz" else field_name,
|
||||
)
|
||||
)
|
||||
file: str | None = None
|
||||
clazz: str = "gradio/base"
|
||||
|
||||
class AlltalkConfigRvcSettings(BaseModel):
|
||||
rvc_enabled: bool = False
|
||||
rvc_char_model_file: str = "Disabled"
|
||||
rvc_narr_model_file: str = "Disabled"
|
||||
split_audio: bool = True
|
||||
autotune: bool = False
|
||||
pitch: int = 0
|
||||
filter_radius: int = 3
|
||||
index_rate: float = 0.75
|
||||
rms_mix_rate: int = 1
|
||||
protect: float = 0.5
|
||||
hop_length: int = 130
|
||||
f0method: str = "fcpe"
|
||||
embedder_model: str = "hubert"
|
||||
training_data_size: int = 45000
|
||||
|
||||
class AlltalkConfigTgwUi(BaseModel):
|
||||
tgwui_activate_tts: bool = True
|
||||
tgwui_autoplay_tts: bool = True
|
||||
tgwui_narrator_enabled: str = "false"
|
||||
tgwui_non_quoted_text_is: str = "character"
|
||||
tgwui_deepspeed_enabled: bool = False
|
||||
tgwui_language: str = "English"
|
||||
tgwui_lowvram_enabled: bool = False
|
||||
tgwui_pitch_set: int = 0
|
||||
tgwui_temperature_set: float = 0.75
|
||||
tgwui_repetitionpenalty_set: int = 10
|
||||
tgwui_generationspeed_set: int = 1
|
||||
tgwui_narrator_voice: str = "female_01.wav"
|
||||
tgwui_show_text: bool = True
|
||||
tgwui_character_voice: str = "female_01.wav"
|
||||
tgwui_rvc_char_voice: str = "Disabled"
|
||||
tgwui_rvc_char_pitch: int = 0
|
||||
tgwui_rvc_narr_voice: str = "Disabled"
|
||||
tgwui_rvc_narr_pitch: int = 0
|
||||
|
||||
class AlltalkConfigApiDef(BaseModel):
|
||||
api_port_number: int = 7851
|
||||
api_allowed_filter: str = "[^a-zA-Z0-9\\s.,;:!?\\-\\'\"$\\u0400-\\u04FF\\u00C0-\\u017F\\u0150\\u0151\\u0170\\u0171\\u011E\\u011F\\u0130\\u0131\\u0900-\\u097F\\u2018\\u2019\\u201C\\u201D\\u3001\\u3002\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FFF\\u3400-\\u4DBF\\uF900-\\uFAFF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF\\uAC00-\\uD7A3\\u1100-\\u11FF\\u3130-\\u318F\\uFF01\\uFF0c\\uFF1A\\uFF1B\\uFF1F]"
|
||||
api_length_stripping: int = 3
|
||||
api_max_characters: int = 2000
|
||||
api_use_legacy_api: bool = False
|
||||
api_legacy_ip_address: str = "127.0.0.1"
|
||||
api_text_filtering: str = "standard"
|
||||
api_narrator_enabled: str = "false"
|
||||
api_text_not_inside: str = "character"
|
||||
api_language: str = "en"
|
||||
api_output_file_name: str = "myoutputfile"
|
||||
api_output_file_timestamp: bool = True
|
||||
api_autoplay: bool = False
|
||||
api_autoplay_volume: float = 0.5
|
||||
|
||||
class AlltalkConfigDebug(BaseModel):
|
||||
debug_transcode: bool = False
|
||||
debug_tts: bool = False
|
||||
debug_openai: bool = False
|
||||
debug_concat: bool = False
|
||||
debug_tts_variables: bool = False
|
||||
debug_rvc: bool = False
|
||||
debug_func: bool = False
|
||||
debug_api: bool = False
|
||||
debug_fullttstext: bool = False
|
||||
debug_narrator: bool = False
|
||||
debug_gradio_IP: bool = False
|
||||
debug_transcribe: bool = False
|
||||
debug_proxy: bool = False
|
||||
|
||||
class AlltalkConfigGradioPages(BaseModel):
|
||||
Generate_Help_page: bool = True
|
||||
Voice2RVC_page: bool = True
|
||||
TTS_Generator_page: bool = True
|
||||
TTS_Engines_Settings_page: bool = True
|
||||
alltalk_documentation_page: bool = True
|
||||
api_documentation_page: bool = True
|
||||
|
||||
class AlltalkAvailableEngine(BaseModel):
|
||||
name: str = ""
|
||||
selected_model: str = ""
|
||||
|
||||
class AlltalkConfigProxyEndpoint(BaseModel):
|
||||
enabled: bool = False
|
||||
external_port: int = 0
|
||||
external_ip: str = "0.0.0.0"
|
||||
cert_name: str = ""
|
||||
|
||||
class AlltalkConfigProxySettings(BaseModel):
|
||||
proxy_enabled: bool = False
|
||||
start_on_startup: bool = False
|
||||
gradio_endpoint: AlltalkConfigProxyEndpoint = AlltalkConfigProxyEndpoint(external_port=444)
|
||||
api_endpoint: AlltalkConfigProxyEndpoint = AlltalkConfigProxyEndpoint(external_port=443)
|
||||
cert_validation: bool = True
|
||||
logging_enabled: bool = True
|
||||
log_level: str = "INFO"
|
||||
|
||||
class AbstractJsonConfig(ABC):
|
||||
def __init__(self, config_path: Path | str, file_check_interval: int):
|
||||
super().__init__()
|
||||
self.__delegate = None
|
||||
self.__config_path = Path(config_path) if type(config_path) is str else config_path
|
||||
self.__last_read_time = 0 # Track when we last read the file
|
||||
self.__file_check_interval = file_check_interval
|
||||
|
||||
def get_config_path(self):
|
||||
return self.__config_path
|
||||
|
||||
def reload(self):
|
||||
self._load_config()
|
||||
return self
|
||||
|
||||
def _reload_on_change(self):
|
||||
# Check if config file has been modified and reload if needed
|
||||
if time.time() - self.__last_read_time >= self.__file_check_interval:
|
||||
try:
|
||||
most_recent_modification = self.get_config_path().stat().st_mtime
|
||||
if most_recent_modification > self.__last_read_time:
|
||||
self.reload()
|
||||
except Exception as e:
|
||||
print(f"Error checking config file: {e}")
|
||||
|
||||
def _load_config(self):
|
||||
self.__last_read_time = self.get_config_path().stat().st_mtime
|
||||
def __load():
|
||||
with open(self.get_config_path(), "r") as configfile:
|
||||
json_string = configfile.read()
|
||||
# The delegate is the actual config loaded:
|
||||
self.__delegate = self._handle_loaded_config(json_string)
|
||||
self.__with_lock_and_backup(self.get_config_path(), False, __load)
|
||||
|
||||
def _save_file(self, path: Path | None | str, default=None, indent=4):
|
||||
file_path = (Path(path) if type(path) is str else path) if path is not None else self.get_config_path()
|
||||
|
||||
def __save():
|
||||
with open(file_path, 'w') as file:
|
||||
file.write(self.__delegate.model_dump_json(indent=indent, by_alias=True))
|
||||
|
||||
self.__with_lock_and_backup(file_path, True, __save)
|
||||
|
||||
def __with_lock_and_backup(self, path: Path, backup: bool, callable: Callable[[], None]):
|
||||
lock_path = path.with_suffix('.lock')
|
||||
backup_path = None
|
||||
try:
|
||||
with FileLock(lock_path):
|
||||
# Create backup:
|
||||
if path.exists() and backup:
|
||||
backup_path = path.with_suffix('.backup')
|
||||
shutil.copy(path, backup_path)
|
||||
|
||||
try:
|
||||
callable()
|
||||
except Exception as e:
|
||||
if backup_path and backup_path.exists():
|
||||
shutil.copy(backup_path, path)
|
||||
raise Exception(f"Failed to save config: {e}")
|
||||
finally:
|
||||
# Cleanup lock and backup files:
|
||||
if lock_path.exists():
|
||||
lock_path.unlink()
|
||||
|
||||
if backup and backup_path and backup_path.exists():
|
||||
backup_path.unlink()
|
||||
|
||||
@abstractmethod
|
||||
def _handle_loaded_config(self, json_string: str):
|
||||
pass
|
||||
|
||||
def to_dict(self):
|
||||
return self.__delegate.model_dump(by_alias=True)
|
||||
|
||||
# Delegation to the loaded config data
|
||||
@property
|
||||
def _xtra(self): return [o for o in dir(self.__delegate) if not o.startswith('_')]
|
||||
|
||||
def __getattr__(self, key):
|
||||
if key in self._xtra: return getattr(self.__delegate, key)
|
||||
raise AttributeError(key)
|
||||
|
||||
def __getattribute__(self, key):
|
||||
if key.startswith("_"):
|
||||
# Private and protected attributes always are on self:
|
||||
return super().__getattribute__(key)
|
||||
if key in self._xtra:
|
||||
# Delegate attribute
|
||||
return getattr(self.__delegate, key)
|
||||
# Get own attribute:
|
||||
return super().__getattribute__(key)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key.startswith("_"):
|
||||
# Private and protected attributes always are on self:
|
||||
super().__setattr__(key, value)
|
||||
elif key in dir(self.__delegate):
|
||||
# Delegate attribute
|
||||
setattr(self.__delegate, key, value)
|
||||
else:
|
||||
# Set own attribute:
|
||||
super().__setattr__(key, value)
|
||||
|
||||
def __dir__(self):
|
||||
def custom_dir(c, add): return dir(type(c)) + list(c.__dict__.keys()) + add
|
||||
return custom_dir(self, self._xtra)
|
||||
|
||||
class AlltalkNewEnginesConfigFields:
|
||||
engines_available: MutableSequence[AlltalkAvailableEngine] = Field(default_factory=list)
|
||||
|
||||
class AlltalkNewEnginesConfigModel(BaseModel, AlltalkNewEnginesConfigFields):
|
||||
|
||||
def get_engine_names_available(self):
|
||||
return [engine.name for engine in self.engines_available]
|
||||
|
||||
def get_engines_matching(self, condition: Callable[[AlltalkAvailableEngine], bool]):
|
||||
return [x for x in self.engines_available if condition(x)]
|
||||
|
||||
class AlltalkNewEnginesConfig(AbstractJsonConfig, AlltalkNewEnginesConfigFields):
|
||||
__instance = None
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def __init__(self, config_path: Path | str = os.path.join(__this_dir, "system", "tts_engines", "new_engines.json")):
|
||||
super().__init__(config_path, 5)
|
||||
self._load_config()
|
||||
|
||||
@staticmethod
|
||||
def get_instance():
|
||||
if AlltalkNewEnginesConfig.__instance is None:
|
||||
AlltalkNewEnginesConfig.__instance = AlltalkNewEnginesConfig()
|
||||
AlltalkNewEnginesConfig.__instance._reload_on_change()
|
||||
return AlltalkNewEnginesConfig.__instance
|
||||
|
||||
def _handle_loaded_config(self, json_string: str):
|
||||
return AlltalkNewEnginesConfigModel.model_validate_json(json_string)
|
||||
|
||||
class AlltalkTTSEnginesConfigFields:
|
||||
engines_available: MutableSequence[AlltalkAvailableEngine] = Field(default_factory=list)
|
||||
engine_loaded: str = ""
|
||||
selected_model: str = ""
|
||||
|
||||
class AlltalkTTSEnginesConfigModel(BaseModel, AlltalkTTSEnginesConfigFields):
|
||||
|
||||
def get_engine_names_available(self):
|
||||
return [engine.name for engine in self.engines_available]
|
||||
|
||||
def is_valid_engine(self, engine_name):
|
||||
return engine_name in self.get_engine_names_available()
|
||||
|
||||
def change_engine(self, requested_engine):
|
||||
if requested_engine == self.engine_loaded:
|
||||
return self
|
||||
for engine in self.engines_available:
|
||||
if engine.name == requested_engine:
|
||||
self.engine_loaded = requested_engine
|
||||
self.selected_model = engine.selected_model
|
||||
return self
|
||||
return self
|
||||
|
||||
class AlltalkTTSEnginesConfig(AbstractJsonConfig, AlltalkTTSEnginesConfigFields):
|
||||
__instance = None
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def __init__(self, config_path: Path | str = os.path.join(__this_dir, "system", "tts_engines", "tts_engines.json")):
|
||||
super().__init__(config_path, 5)
|
||||
self._load_config()
|
||||
|
||||
@staticmethod
|
||||
def get_instance(force_reload = False):
|
||||
if AlltalkTTSEnginesConfig.__instance is None:
|
||||
force_reload = False
|
||||
AlltalkTTSEnginesConfig.__instance = AlltalkTTSEnginesConfig()
|
||||
|
||||
if force_reload:
|
||||
AlltalkTTSEnginesConfig.__instance.reload()
|
||||
else:
|
||||
AlltalkTTSEnginesConfig.__instance._reload_on_change()
|
||||
return AlltalkTTSEnginesConfig.__instance
|
||||
|
||||
def _handle_loaded_config(self, json_string: str):
|
||||
cfg = AlltalkTTSEnginesConfigModel.model_validate_json(json_string)
|
||||
cfg.engines_available = self.__handle_loaded_config_engines(cfg.engines_available)
|
||||
return cfg
|
||||
|
||||
def __handle_loaded_config_engines(self, available_engines):
|
||||
available_engine_names = [engine.name for engine in available_engines]
|
||||
|
||||
# Getting the engines that are not already part of the available engines:
|
||||
new_engines_config = AlltalkNewEnginesConfig.get_instance()
|
||||
new_engines = new_engines_config.get_engines_matching(lambda eng: eng.name not in available_engine_names)
|
||||
|
||||
# Merge engines:
|
||||
return available_engines + new_engines
|
||||
|
||||
def save(self, path: Path | str | None = None):
|
||||
self._save_file(path)
|
||||
|
||||
class AlltalkConfigFields:
|
||||
branding: str = "AllTalk "
|
||||
delete_output_wavs: str = "Disabled"
|
||||
gradio_interface: bool = True
|
||||
output_folder: str = "outputs"
|
||||
gradio_port_number: int = 7852
|
||||
firstrun_model: bool = True
|
||||
firstrun_splash: bool = True
|
||||
launch_gradio: bool = True
|
||||
transcode_audio_format: str = "Disabled"
|
||||
theme: AlltalkConfigTheme = AlltalkConfigTheme()
|
||||
rvc_settings: AlltalkConfigRvcSettings = AlltalkConfigRvcSettings()
|
||||
tgwui: AlltalkConfigTgwUi = AlltalkConfigTgwUi()
|
||||
api_def: AlltalkConfigApiDef = AlltalkConfigApiDef()
|
||||
debugging: AlltalkConfigDebug = AlltalkConfigDebug()
|
||||
gradio_pages: AlltalkConfigGradioPages = AlltalkConfigGradioPages()
|
||||
proxy_settings: AlltalkConfigProxySettings = AlltalkConfigProxySettings()
|
||||
|
||||
class AlltalkConfigModel(BaseModel, AlltalkConfigFields):
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def get_output_directory(self):
|
||||
return self.__this_dir / self.output_folder
|
||||
|
||||
class AlltalkConfig(AbstractJsonConfig, AlltalkConfigFields):
|
||||
__instance = None
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def __init__(self, config_path: Path | str = __this_dir / "confignew.json"):
|
||||
super().__init__(config_path, 5)
|
||||
self._load_config()
|
||||
|
||||
@staticmethod
|
||||
def default_config_path():
|
||||
return AlltalkConfig.__this_dir / "confignew.json"
|
||||
|
||||
@staticmethod
|
||||
def get_instance(force_reload = False):
|
||||
if AlltalkConfig.__instance is None:
|
||||
force_reload = False
|
||||
AlltalkConfig.__instance = AlltalkConfig()
|
||||
|
||||
if force_reload:
|
||||
AlltalkConfig.__instance.reload()
|
||||
else:
|
||||
AlltalkConfig.__instance._reload_on_change()
|
||||
return AlltalkConfig.__instance
|
||||
|
||||
def save(self, path: Path | str | None = None):
|
||||
self._save_file(path)
|
||||
|
||||
def _handle_loaded_config(self, json_string: str):
|
||||
model = AlltalkConfigModel.model_validate_json(json_string)
|
||||
model.get_output_directory().mkdir(parents=True, exist_ok=True)
|
||||
return model
|
||||
+21
-105
@@ -1,109 +1,25 @@
|
||||
{
|
||||
"activate": true,
|
||||
"autoplay": true,
|
||||
"branding": "AllTalk ",
|
||||
"narrator_enabled": false,
|
||||
"deepspeed_activate": false,
|
||||
"delete_output_wavs": "Disabled",
|
||||
"gradio_interface": true,
|
||||
"output_folder": "outputs",
|
||||
"gradio_port_number": 7852,
|
||||
"firstrun_model": true,
|
||||
"firstrun_splash": true,
|
||||
"launch_gradio": true,
|
||||
"transcode_audio_format": "Disabled",
|
||||
"theme": {
|
||||
"file": null,
|
||||
"class": "gradio/base"
|
||||
},
|
||||
"rvc_settings": {
|
||||
"rvc_enabled": false,
|
||||
"rvc_char_model_file": "Disabled",
|
||||
"rvc_narr_model_file": "Disabled",
|
||||
"split_audio": true,
|
||||
"autotune": false,
|
||||
"pitch": 0,
|
||||
"filter_radius": 3,
|
||||
"index_rate": 0.75,
|
||||
"rms_mix_rate": 1,
|
||||
"protect": 0.5,
|
||||
"hop_length": 130,
|
||||
"f0method": "fcpe",
|
||||
"embedder_model": "hubert",
|
||||
"training_data_size": 45000
|
||||
},
|
||||
"tgwui": {
|
||||
"tgwui_activate_tts": true,
|
||||
"tgwui_autoplay_tts": true,
|
||||
"tgwui_narrator_enabled": "false",
|
||||
"tgwui_non_quoted_text_is": "character",
|
||||
"tgwui_deepspeed_enabled": false,
|
||||
"tgwui_language": "English",
|
||||
"tgwui_lowvram_enabled": false,
|
||||
"tgwui_pitch_set": 0,
|
||||
"tgwui_temperature_set": 0.75,
|
||||
"tgwui_repetitionpenalty_set": 10,
|
||||
"tgwui_generationspeed_set": 1,
|
||||
"tgwui_narrator_voice": "female_01.wav",
|
||||
"tgwui_show_text": true,
|
||||
"tgwui_character_voice": "female_01.wav",
|
||||
"tgwui_rvc_char_voice": "Disabled",
|
||||
"tgwui_rvc_char_pitch": 0,
|
||||
"tgwui_rvc_narr_voice": "Disabled",
|
||||
"tgwui_rvc_narr_pitch": 0
|
||||
},
|
||||
"api_def": {
|
||||
"api_port_number": 7851,
|
||||
"api_allowed_filter": "[^a-zA-Z0-9\\s.,;:!?\\-\\'\"$\\u0400-\\u04FF\\u00C0-\\u017F\\u0150\\u0151\\u0170\\u0171\\u011E\\u011F\\u0130\\u0131\\u0900-\\u097F\\u2018\\u2019\\u201C\\u201D\\u3001\\u3002\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FFF\\u3400-\\u4DBF\\uF900-\\uFAFF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF\\uAC00-\\uD7A3\\u1100-\\u11FF\\u3130-\\u318F\\uFF01\\uFF0c\\uFF1A\\uFF1B\\uFF1F]",
|
||||
"api_length_stripping": 3,
|
||||
"api_max_characters": 2000,
|
||||
"api_use_legacy_api": false,
|
||||
"api_legacy_ip_address": "127.0.0.1",
|
||||
"api_text_filtering": "standard",
|
||||
"api_narrator_enabled": "false",
|
||||
"api_text_not_inside": "character",
|
||||
"api_language": "en",
|
||||
"api_output_file_name": "myoutputfile",
|
||||
"api_output_file_timestamp": true,
|
||||
"api_autoplay": false,
|
||||
"api_autoplay_volume": 0.5
|
||||
},
|
||||
"debugging": {
|
||||
"debug_transcode": false,
|
||||
"debug_tts": false,
|
||||
"debug_openai": false,
|
||||
"debug_concat": false,
|
||||
"debug_tts_variables": false,
|
||||
"debug_rvc": false,
|
||||
"debug_func": false,
|
||||
"debug_api": false,
|
||||
"debug_fullttstext": false,
|
||||
"debug_narrator": false,
|
||||
"debug_gradio_IP": false,
|
||||
"debug_transcribe": false,
|
||||
"debug_proxy": false
|
||||
},
|
||||
"gradio_pages": {
|
||||
"Generate_Help_page": true,
|
||||
"Voice2RVC_page": true,
|
||||
"TTS_Generator_page": true,
|
||||
"TTS_Engines_Settings_page": true,
|
||||
"alltalk_documentation_page": true,
|
||||
"api_documentation_page": true
|
||||
},
|
||||
"proxy_settings": {
|
||||
"proxy_enabled": false,
|
||||
"start_on_startup": false,
|
||||
"gradio_endpoint": {
|
||||
"enabled": false,
|
||||
"external_port": 444,
|
||||
"external_ip": "0.0.0.0",
|
||||
"cert_name": ""
|
||||
},
|
||||
"api_endpoint": {
|
||||
"enabled": false,
|
||||
"external_port": 443,
|
||||
"external_ip": "0.0.0.0",
|
||||
"cert_name": ""
|
||||
},
|
||||
"cert_validation": true,
|
||||
"logging_enabled": true,
|
||||
"log_level": "INFO"
|
||||
}
|
||||
"ip_address": "127.0.0.1",
|
||||
"language": "English",
|
||||
"low_vram": false,
|
||||
"local_temperature": "0.7",
|
||||
"local_repetition_penalty": "10.0",
|
||||
"tts_model_loaded": true,
|
||||
"tts_model_name": "tts_models/multilingual/multi-dataset/xtts_v2",
|
||||
"narrator_voice": "female_01.wav",
|
||||
"output_folder_wav": "extensions/alltalk_tts/outputs/",
|
||||
"output_folder_wav_standalone": "outputs/",
|
||||
"port_number": "7851",
|
||||
"remove_trailing_dots": false,
|
||||
"show_text": true,
|
||||
"tts_method_api_local": false,
|
||||
"tts_method_api_tts": false,
|
||||
"tts_method_xtts_local": true,
|
||||
"voice": "female_01.wav"
|
||||
}
|
||||
+112
-926
File diff suppressed because it is too large.
Load diff
@@ -1,98 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
. ${SCRIPT_DIR=}/docker/variables.sh
|
||||
|
||||
TTS_MODEL=xtts
|
||||
DOCKER_TAG=latest
|
||||
CLEAN=false
|
||||
|
||||
# Create required build directories if they don't exist
|
||||
mkdir -p ${SCRIPT_DIR=}/docker/deepspeed/build
|
||||
echo "Created build directories"
|
||||
|
||||
# Parse arguments
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--cuda-version)
|
||||
CUDA_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--python-version)
|
||||
PYTHON_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--tts_model)
|
||||
TTS_MODEL="$2"
|
||||
shift
|
||||
;;
|
||||
--deepspeed-version)
|
||||
DEEPSPEED_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--tag)
|
||||
DOCKER_TAG="$2"
|
||||
shift
|
||||
;;
|
||||
--github-repository)
|
||||
if [ -n "${GITHUB_REPOSITORY}" ] && ! [[ $GITHUB_REPOSITORY =~ ^--.* ]]; then
|
||||
GITHUB_REPOSITORY="$2"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
--clean)
|
||||
CLEAN=true
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "Invalid argument ($1)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$CLEAN" = true ]; then
|
||||
rm -rf ${SCRIPT_DIR=}/docker/deepspeed/build
|
||||
# Recreate directories after clean
|
||||
mkdir -p ${SCRIPT_DIR=}/docker/deepspeed/build
|
||||
echo "Cleaned and recreated build directories"
|
||||
fi
|
||||
|
||||
echo "Building base environment image"
|
||||
$SCRIPT_DIR/docker/base/build-base-env.sh \
|
||||
--cuda-version ${CUDA_VERSION} \
|
||||
--python-version ${PYTHON_VERSION} \
|
||||
--github-repository ${GITHUB_REPOSITORY} \
|
||||
--tag ${DOCKER_TAG}
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to build base environment image"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building DeepSpeed"
|
||||
$SCRIPT_DIR/docker/deepspeed/build-deepspeed.sh \
|
||||
--python-version ${PYTHON_VERSION} \
|
||||
--github-repository ${GITHUB_REPOSITORY} \
|
||||
--tag ${DOCKER_TAG}
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to build DeepSpeed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting docker build process using TTS model '${TTS_MODEL}' and docker tag '${DOCKER_TAG}'"
|
||||
echo "Building for CUDA $CUDA_VERSION using python ${PYTHON_VERSION}"
|
||||
|
||||
docker buildx \
|
||||
build \
|
||||
--progress=plain \
|
||||
--build-arg TTS_MODEL=$TTS_MODEL \
|
||||
--build-arg ALLTALK_DIR=$ALLTALK_DIR \
|
||||
--build-arg DEEPSPEED_VERSION=$DEEPSPEED_VERSION \
|
||||
-t ${GITHUB_REPOSITORY}alltalk_beta:${DOCKER_TAG} \
|
||||
.
|
||||
|
||||
echo "Docker build process finished. Use docker-start.sh to start the container."
|
||||
@@ -0,0 +1,20 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
alltalk-tts:
|
||||
image: erew123/alltalk_tts:cuda
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "7851:7851"
|
||||
volumes:
|
||||
- ./outputs:/app/outputs/
|
||||
- ./models:/app/models/
|
||||
- ./voices:/app/voices/
|
||||
- ./finetune/put-voice-samples-in-here:/app/finetune/put-voice-samples-in-here
|
||||
- ./dockerconfig.json:/app/confignew.json
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [ gpu ]
|
||||
@@ -0,0 +1,27 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
alltalk-tts:
|
||||
image: ${IMAGE:-alltalk:v1-9c}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "7851:7851"
|
||||
- "7852:7852"
|
||||
volumes:
|
||||
- ./outputs:/app/outputs/
|
||||
- ./models:/app/models/
|
||||
- ./voices:/app/voices/
|
||||
- ./finetune/put-voice-samples-in-here:/app/finetune/put-voice-samples-in-here
|
||||
- ./dockerconfig.json:/app/confignew.json
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:7851/api/ready"]
|
||||
interval: 1m30s
|
||||
timeout: 30s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [ gpu ]
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
. ${SCRIPT_DIR=}/docker/variables.sh
|
||||
|
||||
WITH_UI=true
|
||||
DOCKER_TAG=latest
|
||||
declare -a ADDITIONAL_ARGS=()
|
||||
|
||||
# Parse arguments
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--config)
|
||||
CONFIG="$2"
|
||||
shift
|
||||
;;
|
||||
--voices)
|
||||
VOICES="$2"
|
||||
shift
|
||||
;;
|
||||
--rvc_voices)
|
||||
RVC_VOICES="$2"
|
||||
shift
|
||||
;;
|
||||
--no_ui)
|
||||
WITH_UI=false
|
||||
;;
|
||||
--tag)
|
||||
DOCKER_TAG="$2"
|
||||
shift
|
||||
;;
|
||||
--github-repository)
|
||||
if [ -n "${GITHUB_REPOSITORY}" ] && ! [[ $GITHUB_REPOSITORY =~ ^--.* ]]; then
|
||||
GITHUB_REPOSITORY="$2"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Allow to pass arbitrary arguments to docker as well to be flexible:
|
||||
ADDITIONAL_ARGS+=( $1 )
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Compose docker arguments based on user input to the script:
|
||||
declare -a DOCKER_ARGS=()
|
||||
|
||||
if [[ -n $CONFIG ]]; then
|
||||
# Mount the config file to docker_confignew.json:
|
||||
DOCKER_ARGS+=( -v ${CONFIG}:${ALLTALK_DIR}/docker_confignew.json )
|
||||
fi
|
||||
|
||||
if [[ -n $VOICES ]]; then
|
||||
DOCKER_ARGS+=( -v ${VOICES}:${ALLTALK_DIR}/voices )
|
||||
fi
|
||||
|
||||
if [[ -n $RVC_VOICES ]]; then
|
||||
DOCKER_ARGS+=( -v ${RVC_VOICES}:${ALLTALK_DIR}/models/rvc_voices )
|
||||
fi
|
||||
|
||||
if [ "$WITH_UI" = true ] ; then
|
||||
DOCKER_ARGS+=( -p 7852:7852 )
|
||||
fi
|
||||
|
||||
docker run \
|
||||
--rm \
|
||||
-it \
|
||||
-p 7851:7851 \
|
||||
--gpus=all \
|
||||
--name alltalk \
|
||||
"${DOCKER_ARGS[@]}" \
|
||||
"${ADDITIONAL_ARGS[@]}" \
|
||||
${GITHUB_REPOSITORY}alltalk_beta:${DOCKER_TAG} &> /dev/stdout
|
||||
@@ -1,80 +0,0 @@
|
||||
FROM continuumio/miniconda3:24.7.1-0 AS build
|
||||
|
||||
ARG CUDA_VERSION=12.6.0
|
||||
ENV CUDA_VERSION=$CUDA_VERSION
|
||||
|
||||
ARG PYTHON_VERSION=3.11.11
|
||||
ENV PYTHON_VERSION=$PYTHON_VERSION
|
||||
|
||||
SHELL ["/bin/bash", "-l", "-c"]
|
||||
ENV SHELL=/bin/bash
|
||||
ENV HOST=0.0.0.0
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV CUDA_DOCKER_ARCH=all
|
||||
ENV NVIDIA_VISIBLE_DEVICES=all
|
||||
ENV CONDA_AUTO_UPDATE_CONDA="false"
|
||||
|
||||
ENV ALLTALK_DIR=/opt/alltalk
|
||||
|
||||
##############################################################################
|
||||
# Installation/Basic Utilities
|
||||
##############################################################################
|
||||
RUN <<EOR
|
||||
apt-get update
|
||||
apt-get upgrade -y
|
||||
apt-get install --no-install-recommends -y \
|
||||
espeak-ng \
|
||||
curl \
|
||||
wget \
|
||||
jq \
|
||||
vim
|
||||
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
EOR
|
||||
|
||||
##############################################################################
|
||||
# Create a conda environment and install dependencies:
|
||||
##############################################################################
|
||||
RUN <<EOR
|
||||
CUDA_SHORT_VERSION=${CUDA_VERSION%.*}
|
||||
conda create -y -n "alltalk" -c conda-forge python=${PYTHON_VERSION}
|
||||
conda activate alltalk
|
||||
conda install -y \
|
||||
gcc_linux-64 \
|
||||
gxx_linux-64 \
|
||||
libaio \
|
||||
faiss-gpu=1.9.0 \
|
||||
cuda=${CUDA_VERSION} cuda-tools=${CUDA_VERSION} cuda-toolkit=${CUDA_VERSION} cuda-version=${CUDA_SHORT_VERSION} \
|
||||
cuda-command-line-tools=${CUDA_VERSION} cuda-compiler=${CUDA_VERSION} cuda-runtime=${CUDA_VERSION} \
|
||||
cuda-libraries=${CUDA_VERSION} cuda-libraries-dev=${CUDA_VERSION} cuda-libraries-static=${CUDA_VERSION} \
|
||||
cuda-cudart=${CUDA_SHORT_VERSION} cuda-cudart_linux-64=${CUDA_SHORT_VERSION} \
|
||||
cudnn=9.3 \
|
||||
py-cpuinfo=9 \
|
||||
conda-forge::ffmpeg=7.1.0 \
|
||||
conda-forge::portaudio=19.7.0 \
|
||||
-c pytorch \
|
||||
-c nvidia \
|
||||
-c anaconda
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Failed to install conda dependencies: $RESULT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
conda clean -a && pip cache purge
|
||||
EOR
|
||||
|
||||
RUN <<EOR
|
||||
CUDA_SHORT_VERSION=${CUDA_VERSION%.*}
|
||||
CUDA_SHORT_VERSION_NO_DOT=${CUDA_SHORT_VERSION//./}
|
||||
|
||||
conda activate alltalk
|
||||
mkdir -p ${ALLTALK_DIR}/pip_cache
|
||||
pip install --no-cache-dir --cache-dir=${ALLTALK_DIR}/pip_cache \
|
||||
torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu${CUDA_SHORT_VERSION_NO_DOT}
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Failed to install pip dependencies: $RESULT"
|
||||
exit 1
|
||||
fi
|
||||
EOR
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
. ${SCRIPT_DIR=}/../variables.sh
|
||||
|
||||
DOCKER_TAG=latest
|
||||
|
||||
# Parse arguments
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--cuda-version)
|
||||
CUDA_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--python-version)
|
||||
PYTHON_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--tag)
|
||||
DOCKER_TAG="$2"
|
||||
shift
|
||||
;;
|
||||
--github-repository)
|
||||
if [ -n "${GITHUB_REPOSITORY}" ] && ! [[ $GITHUB_REPOSITORY =~ ^--.* ]]; then
|
||||
GITHUB_REPOSITORY="$2"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
echo "Building conda environment using python ${PYTHON_VERSION} with CUDA ${CUDA_VERSION}"
|
||||
|
||||
docker buildx \
|
||||
build \
|
||||
--progress=plain \
|
||||
--build-arg CUDA_VERSION=$CUDA_VERSION \
|
||||
--build-arg PYTHON_VERSION=$PYTHON_VERSION \
|
||||
-t ${GITHUB_REPOSITORY}alltalk_environment:${DOCKER_TAG} \
|
||||
.
|
||||
@@ -1,65 +0,0 @@
|
||||
ARG GITHUB_REPOSITORY
|
||||
FROM ${GITHUB_REPOSITORY}alltalk_environment:latest
|
||||
|
||||
ARG DEEPSPEED_VERSION=0.16.3
|
||||
ENV DEEPSPEED_VERSION=$DEEPSPEED_VERSION
|
||||
|
||||
##############################################################################
|
||||
# Directories:
|
||||
##############################################################################
|
||||
ENV STAGE_DIR=/tmp
|
||||
RUN mkdir -p ${STAGE_DIR}
|
||||
|
||||
##############################################################################
|
||||
# Install python dependencies
|
||||
##############################################################################
|
||||
ENV PIP_CACHE_DIR=/tmp/pip_cache
|
||||
RUN <<EOR
|
||||
conda activate alltalk
|
||||
|
||||
pip install \
|
||||
deepspeed-kernels
|
||||
EOR
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Clone DeepSpeed sources
|
||||
##############################################################################
|
||||
RUN <<EOR
|
||||
git clone https://github.com/microsoft/DeepSpeed.git ${STAGE_DIR}/DeepSpeed
|
||||
cd ${STAGE_DIR}/DeepSpeed
|
||||
git checkout .
|
||||
git checkout "tags/v${DEEPSPEED_VERSION}" -b "v${DEEPSPEED_VERSION}"
|
||||
|
||||
# Patching some files due to bug https://github.com/microsoft/DeepSpeed/issues/6709
|
||||
START_LINE=`awk '/#ifndef BF16_AVAILABLE/{ print NR; exit }' csrc/transformer/inference/csrc/gelu.cu`
|
||||
TO_LINE=$((START_LINE + 2))
|
||||
sed -i "${START_LINE},${TO_LINE}d" ./csrc/transformer/inference/csrc/gelu.cu
|
||||
|
||||
START_LINE=`awk '/#ifndef BF16_AVAILABLE/{ print NR; exit }' csrc/transformer/inference/csrc/transform.cu`
|
||||
TO_LINE=$((START_LINE + 2))
|
||||
sed -i "${START_LINE},${TO_LINE}d" ./csrc/transformer/inference/csrc/transform.cu
|
||||
EOR
|
||||
|
||||
##############################################################################
|
||||
# Create DeepSpeed build file
|
||||
##############################################################################
|
||||
RUN <<EOR
|
||||
cat << EOF > build_deepspeed.sh
|
||||
#!/usr/bin/env bash
|
||||
source ~/.bashrc
|
||||
mkdir -p /deepspeed
|
||||
|
||||
conda activate alltalk
|
||||
cd ${STAGE_DIR}/DeepSpeed
|
||||
DS_BUILD_OPS=1 python setup.py build_ext -j8 bdist_wheel
|
||||
mv ${STAGE_DIR}/DeepSpeed/dist/*.whl /deepspeed/
|
||||
EOF
|
||||
EOR
|
||||
|
||||
RUN chmod +x /build_deepspeed.sh
|
||||
|
||||
##############################################################################
|
||||
# Build DeepSpeed:
|
||||
##############################################################################
|
||||
ENTRYPOINT ["/build_deepspeed.sh"]
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
. ${SCRIPT_DIR=}/../variables.sh
|
||||
|
||||
DOCKER_TAG=latest
|
||||
|
||||
# Parse arguments
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--python-version)
|
||||
PYTHON_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--deepspeed-version)
|
||||
DEEPSPEED_VERSION="$2"
|
||||
shift
|
||||
;;
|
||||
--tag)
|
||||
DOCKER_TAG="$2"
|
||||
shift
|
||||
;;
|
||||
--github-repository)
|
||||
if [ -n "${GITHUB_REPOSITORY}" ] && ! [[ $GITHUB_REPOSITORY =~ ^--.* ]]; then
|
||||
GITHUB_REPOSITORY="$2"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
PYTHON_SHORT_VERSION=${PYTHON_VERSION%.*}
|
||||
PYTHON_VERSION_NO_DOT=${PYTHON_SHORT_VERSION//./}
|
||||
if [[ -n $(find build -name "deepspeed-${DEEPSPEED_VERSION}*-cp${PYTHON_VERSION_NO_DOT}-cp${PYTHON_VERSION_NO_DOT}-*.whl") ]]
|
||||
then
|
||||
echo "DeepSpeed was already built - skipping..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Building DeepSpeed $DEEPSPEED_VERSION using python ${PYTHON_VERSION}"
|
||||
|
||||
rm -rf build # make sure to properly clean up
|
||||
mkdir -p build
|
||||
|
||||
docker buildx \
|
||||
build \
|
||||
--build-arg GITHUB_REPOSITORY=$GITHUB_REPOSITORY \
|
||||
--build-arg DEEPSPEED_VERSION=$DEEPSPEED_VERSION \
|
||||
-t ${GITHUB_REPOSITORY}alltalk_deepspeed:${DOCKER_TAG} \
|
||||
.
|
||||
|
||||
docker run \
|
||||
--rm \
|
||||
-it \
|
||||
--gpus=all \
|
||||
--name deepspeed \
|
||||
-v $SCRIPT_DIR/build:/deepspeed \
|
||||
${GITHUB_REPOSITORY}alltalk_deepspeed:${DOCKER_TAG}
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export CUDA_VERSION=12.6.0
|
||||
export PYTHON_VERSION=3.11.11
|
||||
export DEEPSPEED_VERSION=0.16.2
|
||||
export ALLTALK_DIR=/opt/alltalk
|
||||
export GITHUB_REPOSITORY=
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"delete_output_wavs": "1",
|
||||
"rvc_settings": {
|
||||
"rvc_enabled": true,
|
||||
"f0method": "rmvpe"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"activate": true,
|
||||
"autoplay": true,
|
||||
"branding": "AllTalk ",
|
||||
"narrator_enabled": false,
|
||||
"deepspeed_activate": true,
|
||||
"delete_output_wavs": "Disabled",
|
||||
"ip_address": "127.0.0.1",
|
||||
"language": "English",
|
||||
"low_vram": false,
|
||||
"local_temperature": "0.7",
|
||||
"local_repetition_penalty": "10.0",
|
||||
"tts_model_loaded": true,
|
||||
"tts_model_name": "tts_models/multilingual/multi-dataset/xtts_v2",
|
||||
"narrator_voice": "female_01.wav",
|
||||
"output_folder_wav": "extensions/alltalk_tts/outputs/",
|
||||
"output_folder_wav_standalone": "outputs/",
|
||||
"port_number": "7851",
|
||||
"remove_trailing_dots": false,
|
||||
"show_text": true,
|
||||
"tts_method_api_local": false,
|
||||
"tts_method_api_tts": false,
|
||||
"tts_method_xtts_local": true,
|
||||
"voice": "female_01.wav"
|
||||
}
|
||||
+1365
-4286
File diff suppressed because it is too large.
Load diff
@@ -1,329 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "H-WKVp4Uukcl"
|
||||
},
|
||||
"source": [
|
||||
"#Install Server Requirements\n",
|
||||
"This should be run on a minimum of a T4 runtime, though it will run on a CPU only session, however long TTS generations may time out/error.\n",
|
||||
"\n",
|
||||
"This is a **work in progress**. Known issues:\n",
|
||||
"\n",
|
||||
"- The 1st TTS generation has a brief stutter.\n",
|
||||
"- RVC is not yet working.\n",
|
||||
"- Transcoding/ffmpeg isnt working.\n",
|
||||
"- Things yet to do on selecting your first model and other configuration setups.\n",
|
||||
"\n",
|
||||
"If you enable DeepSpeed for XTTS models, DeepSpeed has to compile on the 1st TTS generation which can take about 90 seconds. After that it should be fine."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "W6ls-RHTQeZv",
|
||||
"outputId": "25c62fb3-26ef-4493-8647-1d8e49bf5f01"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"************************************\n",
|
||||
"** Server requirements installed ***\n",
|
||||
"*** Please proceed to next step ****\n",
|
||||
"************************************\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#@markdown Click the `Play button` to the left of this message to install the requirements.<br><br>\n",
|
||||
"#@markdown **OPTIONAL** Mounting your Google Drive allows you to drag and drop samples/models via the `drive/Mydrive` path. This allows you<br>\n",
|
||||
"#@markdown to store or use specific audio samples or finetuned models.<br>\n",
|
||||
"#@markdown **Audio samples** need to be placed in `alltalk_tts/voices`<br>\n",
|
||||
"#@markdown **XTTS models** need to be placed in `alltalk_tts/models/xtts/{yourmodelfolderhere}`<br>\n",
|
||||
"mount_gdrive = False #@param{type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"if mount_gdrive:\n",
|
||||
" from google.colab import drive\n",
|
||||
" drive.mount('/content/drive')\n",
|
||||
"from IPython.display import clear_output\n",
|
||||
"print(\"*******************************************************************\")\n",
|
||||
"print(\"** Installing server requirements. This will take 5-10 minutes ****\")\n",
|
||||
"print(\"*******************************************************************\")\n",
|
||||
"!apt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 libaio-dev espeak-ng > '/dev/null' 2>&1\n",
|
||||
"clear_output()\n",
|
||||
"print(\"************************\")\n",
|
||||
"print(\"*** Cloning AllTalk ****\")\n",
|
||||
"print(\"************************\\n\")\n",
|
||||
"!git clone -b alltalkbeta https://github.com/erew123/alltalk_tts\n",
|
||||
"clear_output()\n",
|
||||
"print(\"\\n********************************\")\n",
|
||||
"print(\"*** Installing Requirements ****\")\n",
|
||||
"print(\"********************************\\n\")\n",
|
||||
"!python -m pip install --upgrade \"pip<24.1\"\n",
|
||||
"!pip install --quiet -r /content/alltalk_tts/system/requirements/requirements_colab.txt\n",
|
||||
"clear_output()\n",
|
||||
"print(\"\\n*****************************\")\n",
|
||||
"print(\"*** Installing DeepSpeed ****\")\n",
|
||||
"print(\"*****************************\\n\")\n",
|
||||
"!pip install deepspeed\n",
|
||||
"!pip install orjson\n",
|
||||
"!pip install faiss-cpu\n",
|
||||
"!pip install fairseq\n",
|
||||
"clear_output()\n",
|
||||
"print(\"\\n******************************\")\n",
|
||||
"print(\"*** Installing Cloudflare ****\")\n",
|
||||
"print(\"******************************\\n\")\n",
|
||||
"# Install cloudflare\n",
|
||||
"!wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb > '/dev/null' 2>&1\n",
|
||||
"!apt install ./cloudflared-linux-amd64.deb aria2 > '/dev/null' 2>&1\n",
|
||||
"!rm cloudflared-linux-amd64.deb > '/dev/null' 2>&1\n",
|
||||
"!python -m spacy download en_core_web_md\n",
|
||||
"clear_output()\n",
|
||||
"print(\"\\n***************************\")\n",
|
||||
"print(\"*** Installing Cutlass ****\")\n",
|
||||
"print(\"***************************\\n\")\n",
|
||||
"# Clone the CUTLASS repository\n",
|
||||
"!git clone https://github.com/NVIDIA/cutlass.git\n",
|
||||
"!export CUTLASSPATH=/content/cutlass\n",
|
||||
"!sudo curl -L https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz -o /usr/local/bin/ffmpeg.tar.xz\n",
|
||||
"clear_output()\n",
|
||||
"%cd /usr/local/bin/\n",
|
||||
"clear_output()\n",
|
||||
"!7z e /usr/local/bin/ffmpeg.tar.xz -y\n",
|
||||
"clear_output()\n",
|
||||
"!7z e /usr/local/bin/ffmpeg.tar -y\n",
|
||||
"clear_output()\n",
|
||||
"!sudo chmod a+rx /usr/local/bin/ffmpeg\n",
|
||||
"clear_output()\n",
|
||||
"!pip uninstall jax -y\n",
|
||||
"clear_output()\n",
|
||||
"print(\"************************************\")\n",
|
||||
"print(\"** Server requirements installed ***\")\n",
|
||||
"print(\"*** Please proceed to next step ****\")\n",
|
||||
"print(\"************************************\\n\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "2nk26r66RQ23"
|
||||
},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Start AllTalk TTS Server\n",
|
||||
"\n",
|
||||
"This will start the AllTalk API and Gradio Web interface. From here you can download models, generate TTS and use external applications via the API address.\n",
|
||||
"\n",
|
||||
"The AllTalk API address is what you would use in Kobold, SillyTavern, TGWUI's Remote extension etc if you want to generate TTS with those applications."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "9PCQhSoiWvhL"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#@markdown Click the `Play button` to the left of this message to start AllTalk API and Gradio Interface<br>\n",
|
||||
"import re\n",
|
||||
"import time\n",
|
||||
"import json\n",
|
||||
"import threading\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"def keep_alive():\n",
|
||||
" while True:\n",
|
||||
" time.sleep(60) # Run every 60 seconds (adjust as needed)\n",
|
||||
"\n",
|
||||
"keep_alive_thread = threading.Thread(target=keep_alive)\n",
|
||||
"keep_alive_thread.start()\n",
|
||||
"\n",
|
||||
"Tunnel = \"cloudflare\"\n",
|
||||
"host = \"127.0.0.1\"\n",
|
||||
"ports = [7851, 7852]\n",
|
||||
"tunnel_urls = []\n",
|
||||
"\n",
|
||||
"# Starting tunnels for each port.\n",
|
||||
"for port in ports:\n",
|
||||
" if Tunnel == \"cloudflare\":\n",
|
||||
" !nohup cloudflared tunnel --url http://{host}:{port} > lt_{port}.log 2>&1 &\n",
|
||||
" else:\n",
|
||||
" !nohup npx lt -p {port} > lt_{port}.log 2>&1 &\n",
|
||||
"\n",
|
||||
"# Wait a couple of seconds for the tunnels to initialize.\n",
|
||||
"time.sleep(10)\n",
|
||||
"\n",
|
||||
"# Extract URLs for each tunnel.\n",
|
||||
"for port in ports:\n",
|
||||
" log_file = f'lt_{port}.log'\n",
|
||||
" with open(log_file, 'r') as testwritefile:\n",
|
||||
" log_content = testwritefile.read()\n",
|
||||
"\n",
|
||||
" # Use regular expressions to find the URL.\n",
|
||||
" if Tunnel == \"cloudflare\":\n",
|
||||
" url_match = re.search(r'(https://[-a-z0-9]+\\.trycloudflare\\.com)', log_content)\n",
|
||||
" else:\n",
|
||||
" url_match = re.search(r'your url is: (https?://\\S+)', log_content)\n",
|
||||
"\n",
|
||||
" if url_match:\n",
|
||||
" tunnel_url = url_match.group(1)\n",
|
||||
" tunnel_urls.append(tunnel_url)\n",
|
||||
" else:\n",
|
||||
" print(f\"URL for port {port} not found.\")\n",
|
||||
"\n",
|
||||
"# Save the tunnel URLs to a JSON file.\n",
|
||||
"try:\n",
|
||||
" # Try to open the JSON file for reading.\n",
|
||||
" with open('/content/alltalk_tts/googlecolab.json', 'r') as f:\n",
|
||||
" data = json.load(f)\n",
|
||||
"except FileNotFoundError:\n",
|
||||
" # If the file doesn't exist, create an empty dictionary.\n",
|
||||
" data = {}\n",
|
||||
"\n",
|
||||
"data['google_ip_address'] = tunnel_urls\n",
|
||||
"\n",
|
||||
"# Write the modified data (or newly created data) back to the file.\n",
|
||||
"with open('/content/alltalk_tts/googlecolab.json', 'w') as f:\n",
|
||||
" json.dump(data, f)\n",
|
||||
"\n",
|
||||
"host = \"0.0.0.0\"\n",
|
||||
"\n",
|
||||
"if Tunnel == \"localtunnel\":\n",
|
||||
" print(\"Before you copy the link above click on it and copy that ip:\")\n",
|
||||
" !curl ipv4.icanhazip.com\n",
|
||||
"\n",
|
||||
"# Start API server.\n",
|
||||
"!python /content/alltalk_tts/script.py\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Start XTTS model Finetuning\n",
|
||||
"\n",
|
||||
"Starts the Finetuning application for XTTS models.\n",
|
||||
"\n",
|
||||
"You can either run the `Start AllTalk` to download the base XTTS model(s) for finetuning. Or you can use the folder icon on the left hand side of the screen and upload an XTTS model that you want to finetune. If you are manually uploading a model, you would place your model files in `models/xtts/{yourmodelfolderhere}` and you will need all the models files in that folder `config.json, dvae.pth, mel_stats.pth, model.pth, speakers_xtts.pth, vocab.json`. Without 1x model available, Finetuning will not start.\n",
|
||||
"\n",
|
||||
"Likewise you can download your finetuned model from there, OR copy it to your Google Drive after finetuning, for later use in AllTalk. To access the Finetuning Gradio interface, connect to the `Google Colab Finetuning url` when Finetuning has started."
|
||||
],
|
||||
"metadata": {
|
||||
"id": "gDzNPMwM7qvs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"#@markdown Click the `Play button` to the left of this message to start Finetuning<br>\n",
|
||||
"import re\n",
|
||||
"import time\n",
|
||||
"import json\n",
|
||||
"import threading\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"def keep_alive():\n",
|
||||
" while True:\n",
|
||||
" time.sleep(60) # Run every 60 seconds (adjust as needed)\n",
|
||||
"\n",
|
||||
"keep_alive_thread = threading.Thread(target=keep_alive)\n",
|
||||
"keep_alive_thread.start()\n",
|
||||
"\n",
|
||||
"Tunnel = \"cloudflare\"\n",
|
||||
"host = \"127.0.0.1\"\n",
|
||||
"ports = [7052]\n",
|
||||
"tunnel_urls = []\n",
|
||||
"\n",
|
||||
"# Starting tunnels for each port.\n",
|
||||
"for port in ports:\n",
|
||||
" if Tunnel == \"cloudflare\":\n",
|
||||
" !nohup cloudflared tunnel --url http://{host}:{port} > lt_{port}.log 2>&1 &\n",
|
||||
" else:\n",
|
||||
" !nohup npx lt -p {port} > lt_{port}.log 2>&1 &\n",
|
||||
"\n",
|
||||
"# Wait a couple of seconds for the tunnels to initialize.\n",
|
||||
"time.sleep(10)\n",
|
||||
"\n",
|
||||
"# Extract URLs for each tunnel.\n",
|
||||
"for port in ports:\n",
|
||||
" log_file = f'lt_{port}.log'\n",
|
||||
" with open(log_file, 'r') as testwritefile:\n",
|
||||
" log_content = testwritefile.read()\n",
|
||||
"\n",
|
||||
" # Use regular expressions to find the URL.\n",
|
||||
" if Tunnel == \"cloudflare\":\n",
|
||||
" url_match = re.search(r'(https://[-a-z0-9]+\\.trycloudflare\\.com)', log_content)\n",
|
||||
" else:\n",
|
||||
" url_match = re.search(r'your url is: (https?://\\S+)', log_content)\n",
|
||||
"\n",
|
||||
" if url_match:\n",
|
||||
" tunnel_url = url_match.group(1)\n",
|
||||
" tunnel_urls.append(tunnel_url)\n",
|
||||
" print(f\"Google Colab Finetuning url: {tunnel_url}\\n\")\n",
|
||||
" print(f\"********************************************************************\")\n",
|
||||
" print(f\"**** Use the above URL to connect to Finetuning on Google Colab ****\")\n",
|
||||
" print(f\"********************************************************************\")\n",
|
||||
" print(f\"************* Now starting the Finetuning Application **************\")\n",
|
||||
" print(f\"********************************************************************\\n\")\n",
|
||||
" else:\n",
|
||||
" print(f\"URL for port {port} not found.\")\n",
|
||||
"\n",
|
||||
"# Save the tunnel URLs to a JSON file.\n",
|
||||
"try:\n",
|
||||
" # Try to open the JSON file for reading.\n",
|
||||
" with open('/content/alltalk_tts/googlecolab.json', 'r') as f:\n",
|
||||
" data = json.load(f)\n",
|
||||
"except FileNotFoundError:\n",
|
||||
" # If the file doesn't exist, create an empty dictionary.\n",
|
||||
" data = {}\n",
|
||||
"\n",
|
||||
"data['google_ip_address'] = tunnel_urls\n",
|
||||
"\n",
|
||||
"# Write the modified data (or newly created data) back to the file.\n",
|
||||
"with open('/content/alltalk_tts/googlecolab.json', 'w') as f:\n",
|
||||
" json.dump(data, f)\n",
|
||||
"\n",
|
||||
"host = \"0.0.0.0\"\n",
|
||||
"\n",
|
||||
"if Tunnel == \"localtunnel\":\n",
|
||||
" print(\"Before you copy the link above click on it and copy that ip:\")\n",
|
||||
" !curl ipv4.icanhazip.com\n",
|
||||
"\n",
|
||||
"# Start API server.\n",
|
||||
"!python /content/alltalk_tts/finetune.py\n"
|
||||
],
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "Dewvq5s38Sfd"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"gpuType": "T4",
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
python modeldownload.py
|
||||
uvicorn tts_server:app --host 0.0.0.0 --port 7851 --workers 1 --proxy-headers &
|
||||
sleep 5
|
||||
python script.py
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"base_path": "models",
|
||||
"model_path": "xttsv2_2.0.2",
|
||||
"files_to_download": {
|
||||
"LICENSE.txt": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/LICENSE.txt?download=true",
|
||||
"README.md": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/README.md?download=true",
|
||||
"config.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/config.json?download=true",
|
||||
"model.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/model.pth?download=true",
|
||||
"dvae.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/dvae.pth?download=true",
|
||||
"mel_stats.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/mel_stats.pth?download=true",
|
||||
"speakers_xtts.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/speakers_xtts.pth?download=true",
|
||||
"vocab.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/vocab.json?download=true"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import requests
|
||||
from requests.exceptions import ConnectionError
|
||||
from tqdm import tqdm
|
||||
import importlib.metadata as metadata
|
||||
import json
|
||||
from packaging import version
|
||||
from datetime import datetime
|
||||
|
||||
#################################################################
|
||||
#### LOAD PARAMS FROM confignew.json - REQUIRED FOR BRANDING ####
|
||||
#################################################################
|
||||
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
# load standard config file in and get settings
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
config_file_path = this_dir / "confignew.json"
|
||||
params = load_config(config_file_path)
|
||||
|
||||
# Define the path to the modeldownload config file file
|
||||
modeldownload_config_file_path = this_dir / "modeldownload.json"
|
||||
|
||||
# Check if the JSON file exists
|
||||
if modeldownload_config_file_path.exists():
|
||||
with open(modeldownload_config_file_path, "r") as config_file:
|
||||
settings = json.load(config_file)
|
||||
|
||||
# Extract settings from the loaded JSON
|
||||
base_path = Path(settings.get("base_path", ""))
|
||||
model_path = Path(settings.get("model_path", ""))
|
||||
files_to_download = settings.get("files_to_download", {})
|
||||
else:
|
||||
# Default settings if the JSON file doesn't exist or is empty
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m modeldownload.json is missing so please re-download it and save it in the coquii_tts main folder.")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m API Local and XTTSv2 Local will error unless this is corrected.")
|
||||
|
||||
# Read the version specifier from requirements_nvidia.txt
|
||||
with open(this_dir / "system" / "requirements" / "requirements_standalone.txt", "r") as req_file:
|
||||
requirements = req_file.readlines()
|
||||
|
||||
tts_version_required = None
|
||||
for req in requirements:
|
||||
if req.startswith("TTS=="):
|
||||
tts_version_required = req.strip().split("==")[1]
|
||||
break
|
||||
|
||||
if tts_version_required is None:
|
||||
raise ValueError(f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements file")
|
||||
|
||||
def create_directory_if_not_exists(directory):
|
||||
if not directory.exists():
|
||||
directory.mkdir(parents=True)
|
||||
|
||||
def download_file(url, destination):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size_in_bytes = int(response.headers.get("content-length", 0))
|
||||
block_size = 1024 # 1 Kibibyte
|
||||
|
||||
progress_bar = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True)
|
||||
|
||||
with open(destination, "wb") as file:
|
||||
for data in response.iter_content(block_size):
|
||||
progress_bar.update(len(data))
|
||||
file.write(data)
|
||||
|
||||
progress_bar.close()
|
||||
|
||||
|
||||
def check_tts_version():
|
||||
try:
|
||||
tts_version = metadata.version("tts")
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent TTS Version : \033[93m"+tts_version+"\033[0m")
|
||||
|
||||
if version.parse(tts_version) < version.parse(tts_version_required):
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS version is too old. Please upgrade to version \033[93m"+tts_version_required+"\033[0m or later.\033[0m")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m At your terminal/command prompt \033[94mpip install --upgrade tts\033[0m")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent TTS Version is :\033[93m Up to date\033[0m")
|
||||
except metadata.PackageNotFoundError:
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS is not installed")
|
||||
|
||||
def check_torch_version():
|
||||
import torch
|
||||
pytorch_version = torch.__version__
|
||||
cuda_version = torch.version.cuda
|
||||
major, minor, micro = sys.version_info[:3]
|
||||
python_version = f"{major}.{minor}.{micro}"
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent Python Version :\033[93m {python_version}\033[0m")
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent PyTorch Version:\033[93m {pytorch_version}\033[0m")
|
||||
if cuda_version is None:
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent CUDA Version :\033[91m CUDA is not available\033[0m")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent CUDA Version :\033[93m {cuda_version}\033[0m")
|
||||
|
||||
def ordinal(n):
|
||||
return "%d%s" % (n, "th" if 4 <= n % 100 <= 20 else {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th"))
|
||||
|
||||
def format_datetime(iso_str):
|
||||
# Parse the ISO 8601 string to datetime
|
||||
dt = datetime.strptime(iso_str, "%Y-%m-%dT%H:%M:%SZ")
|
||||
# Format the datetime into a more readable string
|
||||
return dt.strftime(f"{ordinal(dt.day)} %B %Y at %H:%M")
|
||||
|
||||
def fetch_latest_commit_sha_and_date(owner, repo):
|
||||
url = f"https://api.github.com/repos/{owner}/{repo}/commits"
|
||||
try:
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
latest_commit = response.json()[0]
|
||||
latest_commit_sha = latest_commit['sha']
|
||||
latest_commit_date = latest_commit['commit']['committer']['date']
|
||||
return latest_commit_sha, latest_commit_date
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[91m Failed to fetch the latest commits due to an unexpected response from GitHub")
|
||||
return None, None
|
||||
except ConnectionError:
|
||||
# This block is executed when a connection error occurs
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[91m Could not reach GitHub to check for updates\033[0m")
|
||||
return None, None
|
||||
|
||||
def read_or_initialize_sha(file_path):
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
data = json.load(file)
|
||||
return data.get("last_known_commit_sha")
|
||||
else:
|
||||
# File doesn't exist, fetch the latest SHA and create the file
|
||||
latest_commit_sha = fetch_latest_commit_sha_and_date(github_site, github_repository)
|
||||
if latest_commit_sha:
|
||||
with open(file_path, 'w') as file:
|
||||
json.dump({"last_known_commit_sha": latest_commit_sha}, file)
|
||||
return latest_commit_sha
|
||||
else:
|
||||
# Handle the case where GitHub couldn't be reached
|
||||
return None
|
||||
|
||||
def update_sha_file(file_path, new_sha):
|
||||
with open(file_path, 'w') as file:
|
||||
json.dump({"last_known_commit_sha": new_sha}, file)
|
||||
|
||||
# Check and create directories
|
||||
if str(base_path) == "models":
|
||||
create_directory_if_not_exists(this_dir / base_path / model_path)
|
||||
else:
|
||||
create_directory_if_not_exists(base_path / model_path)
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Custom path set in \033[93mmodeldownload.json\033[0m. Using the following settings:")
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Base folder Path:\033[93m",base_path,"\033[0m",)
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Model folder Path:\033[93m",model_path,"\033[0m",)
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Full Path:\033[93m",base_path / model_path,"\033[0m",)
|
||||
|
||||
# Download files if they don't exist
|
||||
print(f"[{params['branding']}Startup] \033[92mModel is available :\033[93m Checking\033[0m")
|
||||
for filename, url in files_to_download.items():
|
||||
if str(base_path) == "models":
|
||||
destination = this_dir / base_path / model_path / filename
|
||||
else:
|
||||
destination = Path(base_path) / model_path / filename
|
||||
if not destination.exists():
|
||||
print(f"[{params['branding']}Startup] \033[92mModel Downloading file : \033[93m" + filename + "\033[0m")
|
||||
download_file(url, destination)
|
||||
print(f"[{params['branding']}Startup] \033[92mModel is available :\033[93m Checked\033[0m")
|
||||
|
||||
github_site = "erew123"
|
||||
github_repository = "alltalk_tts"
|
||||
|
||||
check_torch_version()
|
||||
check_tts_version()
|
||||
# Define the file path based on your directory structure
|
||||
sha_file_path = this_dir / "system" / "config" / "at_github_sha.json"
|
||||
|
||||
# Read or initialize the SHA (adjusted for handling both SHA and date)
|
||||
last_known_commit_sha = read_or_initialize_sha(sha_file_path) # Assuming adjustment for date
|
||||
|
||||
# Assuming you have fetched the latest commit SHA and date
|
||||
latest_commit_sha, latest_commit_date = fetch_latest_commit_sha_and_date(github_site, github_repository)
|
||||
|
||||
formatted_date = format_datetime(latest_commit_date) if latest_commit_date else "an unknown date"
|
||||
|
||||
if latest_commit_sha and latest_commit_sha != last_known_commit_sha:
|
||||
#print(f"There's an update available for alltalk_tts.")
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[93m {formatted_date}\033[0m")
|
||||
# Update the file with the new SHA
|
||||
update_sha_file(sha_file_path, latest_commit_sha)
|
||||
elif latest_commit_sha == last_known_commit_sha:
|
||||
#print(f"Your alltalk_tts software is up to date.")
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[93m {formatted_date}\033[0m")
|
||||
@@ -0,0 +1,22 @@
|
||||
FROM nvidia/cuda:12.1.1-devel-ubuntu22.04
|
||||
ENV HOST 0.0.0.0
|
||||
RUN apt-get update && apt-get upgrade -y \
|
||||
&& apt-get install -y git build-essential portaudio19-dev \
|
||||
python3 python3-pip gcc wget \
|
||||
ocl-icd-opencl-dev opencl-headers clinfo \
|
||||
libclblast-dev libopenblas-dev \
|
||||
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
|
||||
&& ln -s /usr/bin/python3 /usr/bin/python
|
||||
|
||||
RUN mkdir /app/pip_cache
|
||||
ENV PIP_CACHE_DIR=/app/pip_cache
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
ENV CUDA_DOCKER_ARCH=all
|
||||
RUN pip install --no-cache-dir --no-deps -r system/requirements/requirements_standalone.txt --cache-dir=/app/pip_cache && \
|
||||
pip install --no-cache-dir deepspeed --cache-dir=/app/pip_cache
|
||||
|
||||
EXPOSE 7851
|
||||
RUN chmod +x launch.sh
|
||||
ENTRYPOINT ["sh", "-c", "./launch.sh"]
|
||||
@@ -1,2 +0,0 @@
|
||||
[pytest]
|
||||
pythonpath = .
|
||||
@@ -1,20 +0,0 @@
|
||||
BASIC SETUP
|
||||
-----------
|
||||
Place the `alltalk.js` in your `\SillyTavern\public\scripts\extensions\tts\` folder, replacing the existing file.
|
||||
|
||||
CHANGING THE DEFAULT IP ADDRESS
|
||||
-------------------------------
|
||||
If you change the default IP/URL in the SillyTavern interface, you need to press Enter for it to save the setting. Just typing in an address/URL will not change the setting.
|
||||
|
||||
SIMPLE TROUBLESHOOTING
|
||||
----------------------
|
||||
The settings for AllTalk are stored, saved and managed by SillyTavern and not the AllTalk extension. You can manually edit OR delete these settings if necessary by editing the `settings.json` file that SillyTavern stores. I would suggest taking a copy of the file before making any changes.
|
||||
|
||||
Older versions of SillyTavern store `settings.json` file in `\SillyTavern\public\`
|
||||
|
||||
Newer version of SillyTavern store `settings.json` file in `\SillyTavern\data\default-user`
|
||||
|
||||
Within the `settings.json` file you will find a section called `"AllTalk": {` and it is closed out a few lines down with `},`
|
||||
|
||||
You can either manually edit any of the settings in there OR you can delete the entire section from the start of `"AllTalk":` to the end of `},` and when you refresh the SillyTavern web page OR restart SillyTavern, new settings for AllTalk will be created/saved.
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1 +0,0 @@
|
||||
Place the `alltalk.js` in your `\SillyTavern\public\scripts\extensions\tts\` folder, replacing the existing file.
|
||||
@@ -1,17 +0,0 @@
|
||||
Text-generation-webui remote extension for AllTalk!
|
||||
|
||||
This folder contains everything you need to set up a Text-generation-webui extension that can communicate with an AllTalk server remotely.
|
||||
|
||||
To get started, follow these simple steps:
|
||||
|
||||
1) In your Text-generation-webui's extensions folder, create a new folder and name it "alltalk_tts".
|
||||
2) Take all the files from this current folder and copy them into the newly created "alltalk_tts" folder.
|
||||
3) Start & Open Text-generation-webui and look for "alltalk_tts" in the list of extensions. Select alltalk_tts, save your settings and restart Text-generation-webui.
|
||||
4) Text-generation-webui will restart and load the AllTalk extension. You may see an error/warning as the extension will not yet have the IP address details of your remote AllTalk server.
|
||||
5) In the extension settings, enter the correct IP address and port of your AllTalk server. If your AllTalk server is running on a remote machine accessed through a secure tunnel, make sure to use "https" instead of "http".
|
||||
6) After entering the server details, click on the "Refresh settings & voices" button. If the settings are correct, the extension will download all the available settings from the AllTalk server.
|
||||
7) The first time you successfully generate speech using the extension, the settings will be automatically saved to a local configuration file.
|
||||
|
||||
Please note that if the AllTalk server you're connected to doesn't support certain settings/features, those options will be greyed out and unavailable in the extension.
|
||||
|
||||
Please use the "Refresh settings & voices" button to make sure the extension is in sync with your AllTalk server.
|
||||
@@ -1,720 +0,0 @@
|
||||
The birch canoe slid on the smooth planks.
|
||||
Glue the sheet to the dark blue background.
|
||||
It's easy to tell the depth of a well.
|
||||
These days a chicken leg is a rare dish.
|
||||
Rice is often served in round bowls.
|
||||
The juice of lemons makes fine punch.
|
||||
The box was thrown beside the parked truck.
|
||||
The hogs were fed chopped corn and garbage.
|
||||
Four hours of steady work faced us.
|
||||
A large size in stockings is hard to sell.
|
||||
The boy was there when the sun rose.
|
||||
A rod is used to catch pink salmon.
|
||||
The source of the huge river is the clear spring.
|
||||
Kick the ball straight and follow through.
|
||||
Help the woman get back to her feet.
|
||||
A pot of tea helps to pass the evening.
|
||||
Smoky fires lack flame and heat.
|
||||
The soft cushion broke the man's fall.
|
||||
The salt breeze came across from the sea.
|
||||
The girl at the booth sold fifty bonds.
|
||||
The small pup gnawed a hole in the sock.
|
||||
The fish twisted and turned on the bent hook.
|
||||
Press the pants and sew a button on the vest.
|
||||
The swan dive was far short of perfect.
|
||||
The beauty of the view stunned the young boy.
|
||||
Two blue fish swam in the tank.
|
||||
Her purse was full of useless trash.
|
||||
The colt reared and threw the tall rider.
|
||||
It snowed, rained, and hailed the same morning.
|
||||
Read verse out loud for pleasure.
|
||||
Hoist the load to your left shoulder.
|
||||
Take the winding path to reach the lake.
|
||||
Note closely the size of the gas tank.
|
||||
Wipe the grease off his dirty face.
|
||||
Mend the coat before you go out.
|
||||
The wrist was badly strained and hung limp.
|
||||
The stray cat gave birth to kittens.
|
||||
The young girl gave no clear response.
|
||||
The meal was cooked before the bell rang.
|
||||
What joy there is in living.
|
||||
A king ruled the state in the early days.
|
||||
The ship was torn apart on the sharp reef.
|
||||
Sickness kept him home the third week.
|
||||
The wide road shimmered in the hot sun.
|
||||
The lazy cow lay in the cool grass.
|
||||
Lift the square stone over the fence.
|
||||
The rope will bind the seven books at once.
|
||||
Hop over the fence and plunge in.
|
||||
The friendly gang left the drug store.
|
||||
Mesh wire keeps chicks inside.
|
||||
The frosty air passed through the coat.
|
||||
The crooked maze failed to fool the mouse.
|
||||
Adding fast leads to wrong sums.
|
||||
The show was a flop from the very start.
|
||||
A saw is a tool used for making boards.
|
||||
The wagon moved on well oiled wheels.
|
||||
March the soldiers past the next hill.
|
||||
A cup of sugar makes sweet fudge.
|
||||
Place a rosebush near the porch steps.
|
||||
Both lost their lives in the raging storm.
|
||||
We talked of the side show in the circus.
|
||||
Use a pencil to write the first draft.
|
||||
He ran half way to the hardware store.
|
||||
The clock struck to mark the third period.
|
||||
A small creek cut across the field.
|
||||
Cars and busses stalled in snow drifts.
|
||||
The set of china hit the floor with a crash.
|
||||
This is a grand season for hikes on the road.
|
||||
The dune rose from the edge of the water.
|
||||
Those words were the cue for the actor to leave.
|
||||
A yacht slid around the point into the bay.
|
||||
The two met while playing on the sand.
|
||||
The ink stain dried on the finished page.
|
||||
The walled town was seized without a fight.
|
||||
The lease ran out in sixteen weeks.
|
||||
A tame squirrel makes a nice pet.
|
||||
The horn of the car woke the sleeping cop.
|
||||
The heart beat strongly and with firm strokes.
|
||||
The pearl was worn in a thin silver ring.
|
||||
The fruit peel was cut in thick slices.
|
||||
The Navy attacked the big task force.
|
||||
See the cat glaring at the scared mouse.
|
||||
There are more than two factors here.
|
||||
The hat brim was wide and too droopy.
|
||||
The lawyer tried to lose his case.
|
||||
The grass curled around the fence post.
|
||||
Cut the pie into large parts.
|
||||
Men strive but seldom get rich.
|
||||
Always close the barn door tight.
|
||||
He lay prone and hardly moved a limb.
|
||||
The slush lay deep along the street.
|
||||
A wisp of cloud hung in the blue air.
|
||||
A pound of sugar costs more than eggs.
|
||||
The fin was sharp and cut the clear water.
|
||||
The play seems dull and quite stupid.
|
||||
Bail the boat to stop it from sinking.
|
||||
The term ended in late June that year.
|
||||
A tusk is used to make costly gifts.
|
||||
Ten pins were set in order.
|
||||
The bill was paid every third week.
|
||||
Oak is strong and also gives shade.
|
||||
Cats and dogs each hate the other.
|
||||
The pipe began to rust while new.
|
||||
Open the crate but don't break the glass.
|
||||
Add the sum to the product of these three.
|
||||
Thieves who rob friends deserve jail.
|
||||
The ripe taste of cheese improves with age.
|
||||
Act on these orders with great speed.
|
||||
The hog crawled under the high fence.
|
||||
Move the vat over the hot fire.
|
||||
The bark of the pine tree was shiny and dark.
|
||||
Leaves turn brown and yellow in the fall.
|
||||
The pennant waved when the wind blew.
|
||||
Split the log with a quick, sharp blow.
|
||||
Burn peat after the logs give out.
|
||||
He ordered peach pie with ice cream.
|
||||
Weave the carpet on the right hand side.
|
||||
Hemp is a weed found in parts of the tropics.
|
||||
A lame back kept his score low.
|
||||
We find joy in the simplest things.
|
||||
Type out three lists of orders.
|
||||
The harder he tried the less he got done.
|
||||
The boss ran the show with a watchful eye.
|
||||
The cup cracked and spilled its contents.
|
||||
Paste can cleanse the most dirty brass.
|
||||
The slang word for raw whiskey is booze.
|
||||
It caught its hind paw in a rusty trap.
|
||||
The wharf could be seen at the farther shore.
|
||||
Feel the heat of the weak dying flame.
|
||||
The tiny girl took off her hat.
|
||||
A cramp is no small danger on a swim.
|
||||
He said the same phrase thirty times.
|
||||
Pluck the bright rose without leaves.
|
||||
Two plus seven is less than ten.
|
||||
The glow deepened in the eyes of the sweet girl.
|
||||
Bring your problems to the wise chief.
|
||||
Write a fond note to the friend you cherish.
|
||||
Clothes and lodging are free to new men.
|
||||
We frown when events take a bad turn.
|
||||
Port is a strong wine with a smoky taste.
|
||||
The young kid jumped the rusty gate.
|
||||
Guess the results from the first scores.
|
||||
A salt pickle tastes fine with ham.
|
||||
The just claim got the right verdict.
|
||||
These thistles bend in a high wind.
|
||||
Pure bred poodles have curls.
|
||||
The tree top waved in a graceful way.
|
||||
The spot on the blotter was made by green ink.
|
||||
Mud was spattered on the front of his white shirt.
|
||||
The cigar burned a hole in the desk top.
|
||||
The empty flask stood on the tin tray.
|
||||
A speedy man can beat this track mark.
|
||||
He broke a new shoelace that day.
|
||||
The coffee stand is too high for the couch.
|
||||
The urge to write short stories is rare.
|
||||
The pencils have all been used.
|
||||
The pirates seized the crew of the lost ship.
|
||||
We tried to replace the coin but failed.
|
||||
She sewed the torn coat quite neatly.
|
||||
The sofa cushion is red and of light weight.
|
||||
The jacket hung on the back of the wide chair.
|
||||
At that high level the air is pure.
|
||||
Drop the two when you add the figures.
|
||||
A filing case is now hard to buy.
|
||||
An abrupt start does not win the prize.
|
||||
Wood is best for making toys and blocks.
|
||||
The office paint was a dull, sad tan.
|
||||
He knew the skill of the great young actress.
|
||||
A rag will soak up spilled water.
|
||||
A shower of dirt fell from the hot pipes.
|
||||
Steam hissed from the broken valve.
|
||||
The child almost hurt the small dog.
|
||||
There was a sound of dry leaves outside.
|
||||
The sky that morning was clear and bright blue.
|
||||
Torn scraps littered the stone floor.
|
||||
Sunday is the best part of the week.
|
||||
The doctor cured him with these pills.
|
||||
The new girl was fired today at noon.
|
||||
They felt gay when the ship arrived in port.
|
||||
Add the store's account to the last cent.
|
||||
Acid burns holes in wool cloth.
|
||||
Fairy tales should be fun to write.
|
||||
Eight miles of woodland burned to waste.
|
||||
The third act was dull and tired the players.
|
||||
A young child should not suffer fright.
|
||||
Add the column and put the sum here.
|
||||
We admire and love a good cook.
|
||||
There the flood mark is ten inches.
|
||||
He carved a head from the round block of marble.
|
||||
She has a smart way of wearing clothes.
|
||||
The fruit of a fig tree is apple-shaped.
|
||||
Corn cobs can be used to kindle a fire.
|
||||
Where were they when the noise started.
|
||||
The paper box is full of thumb tacks.
|
||||
Sell your gift to a buyer at a good gain.
|
||||
The tongs lay beside the ice pail.
|
||||
The petals fall with the next puff of wind.
|
||||
Bring your best compass to the third class.
|
||||
They could laugh although they were sad.
|
||||
Farmers came in to thresh the oat crop.
|
||||
The brown house was on fire to the attic.
|
||||
The lure is used to catch trout and flounder.
|
||||
Float the soap on top of the bath water.
|
||||
A blue crane is a tall wading bird.
|
||||
A fresh start will work such wonders.
|
||||
The club rented the rink for the fifth night.
|
||||
After the dance, they went straight home.
|
||||
The hostess taught the new maid to serve.
|
||||
He wrote his last novel there at the inn.
|
||||
Even the worst will beat his low score.
|
||||
The cement had dried when he moved it.
|
||||
The loss of the second ship was hard to take.
|
||||
The fly made its way along the wall.
|
||||
Do that with a wooden stick.
|
||||
Live wires should be kept covered.
|
||||
The large house had hot water taps.
|
||||
It is hard to erase blue or red ink.
|
||||
Write at once or you may forget it.
|
||||
The doorknob was made of bright clean brass.
|
||||
The wreck occurred by the bank on Main Street.
|
||||
A pencil with black lead writes best.
|
||||
Coax a young calf to drink from a bucket.
|
||||
Schools for ladies teach charm and grace.
|
||||
The lamp shone with a steady green flame.
|
||||
They took the axe and the saw to the forest.
|
||||
The ancient coin was quite dull and worn.
|
||||
The shaky barn fell with a loud crash.
|
||||
Jazz and swing fans like fast music.
|
||||
Rake the rubbish up and then burn it.
|
||||
Slash the gold cloth into fine ribbons.
|
||||
Try to have the court decide the case.
|
||||
They are pushed back each time they attack.
|
||||
He broke his ties with groups of former friends.
|
||||
They floated on the raft to sun their white backs.
|
||||
The map had an X that meant nothing.
|
||||
Whitings are small fish caught in nets.
|
||||
Some ads serve to cheat buyers.
|
||||
Jerk the rope and the bell rings weakly.
|
||||
A waxed floor makes us lose balance.
|
||||
Madam, this is the best brand of corn.
|
||||
On the islands the sea breeze is soft and mild.
|
||||
The play began as soon as we sat down.
|
||||
This will lead the world to more sound and fury.
|
||||
Add salt before you fry the egg.
|
||||
The rush for funds reached its peak Tuesday.
|
||||
The birch looked stark white and lonesome.
|
||||
The box is held by a bright red snapper.
|
||||
To make pure ice, you freeze water.
|
||||
The first worm gets snapped early.
|
||||
Jump the fence and hurry up the bank.
|
||||
Yell and clap as the curtain slides back.
|
||||
They are men who walk the middle of the road.
|
||||
Both brothers wear the same size.
|
||||
In some form or other we need fun.
|
||||
The prince ordered his head chopped off.
|
||||
The houses are built of red clay bricks.
|
||||
Ducks fly north but lack a compass.
|
||||
Fruit flavors are used in fizz drinks.
|
||||
These pills do less good than others.
|
||||
Canned pears lack full flavor.
|
||||
The dark pot hung in the front closet.
|
||||
Carry the pail to the wall and spill it there.
|
||||
The train brought our hero to the big town.
|
||||
We are sure that one war is enough.
|
||||
Gray paint stretched for miles around.
|
||||
The rude laugh filled the empty room.
|
||||
High seats are best for football fans.
|
||||
Tea served from the brown jug is tasty.
|
||||
A dash of pepper spoils beef stew.
|
||||
A zestful food is the hot-cross bun.
|
||||
The horse trotted around the field at a brisk pace.
|
||||
Find the twin who stole the pearl necklace.
|
||||
Cut the cord that binds the box tightly.
|
||||
The red tape bound the smuggled food.
|
||||
Look in the corner to find the tan shirt.
|
||||
The cold drizzle will halt the bond drive.
|
||||
Nine men were hired to dig the ruins.
|
||||
The junk yard had a mouldy smell.
|
||||
The flint sputtered and lit a pine torch.
|
||||
Soak the cloth and drown the sharp odor.
|
||||
The shelves were bare of both jam or crackers.
|
||||
A joy to every child is the swan boat.
|
||||
All sat frozen and watched the screen.
|
||||
A cloud of dust stung his tender eyes.
|
||||
To reach the end he needs much courage.
|
||||
Shape the clay gently into block form.
|
||||
A ridge on a smooth surface is a bump or flaw.
|
||||
Hedge apples may stain your hands green.
|
||||
Quench your thirst, then eat the crackers.
|
||||
Tight curls get limp on rainy days.
|
||||
The mute muffled the high tones of the horn.
|
||||
The gold ring fits only a pierced ear.
|
||||
The old pan was covered with hard fudge.
|
||||
Watch the log float in the wide river.
|
||||
The node on the stalk of wheat grew daily.
|
||||
The heap of fallen leaves was set on fire.
|
||||
Write fast if you want to finish early.
|
||||
His shirt was clean but one button was gone.
|
||||
The barrel of beer was a brew of malt and hops.
|
||||
Tin cans are absent from store shelves.
|
||||
Slide the box into that empty space.
|
||||
The plant grew large and green in the window.
|
||||
The beam dropped down on the workmen's head.
|
||||
Pink clouds floated with the breeze.
|
||||
She danced like a swan, tall and graceful.
|
||||
The tube was blown and the tire flat and useless.
|
||||
It is late morning on the old wall clock.
|
||||
Let's all join as we sing the last chorus.
|
||||
The last switch cannot be turned off.
|
||||
The fight will end in just six minutes.
|
||||
The store walls were lined with colored frocks.
|
||||
The peace league met to discuss their plans.
|
||||
The rise to fame of a person takes luck.
|
||||
Paper is scarce, so write with much care.
|
||||
The quick fox jumped on the sleeping cat.
|
||||
The nozzle of the fire hose was bright brass.
|
||||
Screw the round cap on as tight as needed.
|
||||
Time brings us many changes.
|
||||
The purple tie was ten years old.
|
||||
Men think and plan and sometimes act.
|
||||
Fill the ink jar with sticky glue.
|
||||
He smoke a big pipe with strong contents.
|
||||
We need grain to keep our mules healthy.
|
||||
Pack the records in a neat thin case.
|
||||
The crunch of feet in the snow was the only sound.
|
||||
The copper bowl shone in the sun's rays.
|
||||
Boards will warp unless kept dry.
|
||||
The plush chair leaned against the wall.
|
||||
Glass will clink when struck by metal.
|
||||
Bathe and relax in the cool green grass.
|
||||
Nine rows of soldiers stood in line.
|
||||
The beach is dry and shallow at low tide.
|
||||
The idea is to sew both edges straight.
|
||||
The kitten chased the dog down the street.
|
||||
Pages bound in cloth make a book.
|
||||
Try to trace the fine lines of the painting.
|
||||
Women form less than half of the group.
|
||||
The zones merge in the central part of town.
|
||||
A gem in the rough needs work to polish.
|
||||
Code is used when secrets are sent.
|
||||
Most of the news is easy for us to hear.
|
||||
He used the lathe to make brass objects.
|
||||
The vane on top of the pole revolved in the wind.
|
||||
Mince pie is a dish served to children.
|
||||
The clan gathered on each dull night.
|
||||
Let it burn, it gives us warmth and comfort.
|
||||
A castle built from sand fails to endure.
|
||||
A child's wit saved the day for us.
|
||||
Tack the strip of carpet to the worn floor.
|
||||
Next Tuesday we must vote.
|
||||
Pour the stew from the pot into the plate.
|
||||
Each penny shone like new.
|
||||
The man went to the woods to gather sticks.
|
||||
The dirt piles were lines along the road.
|
||||
The logs fell and tumbled into the clear stream.
|
||||
Just hoist it up and take it away.
|
||||
A ripe plum is fit for a king's palate.
|
||||
Our plans right now are hazy.
|
||||
Brass rings are sold by these natives.
|
||||
It takes a good trap to capture a bear.
|
||||
Feed the white mouse some flower seeds.
|
||||
The thaw came early and freed the stream.
|
||||
He took the lead and kept it the whole distance.
|
||||
The key you designed will fit the lock.
|
||||
Plead to the council to free the poor thief.
|
||||
Better hash is made of rare beef.
|
||||
This plank was made for walking on.
|
||||
The lake sparkled in the red hot sun.
|
||||
He crawled with care along the ledge.
|
||||
Tend the sheep while the dog wanders.
|
||||
It takes a lot of help to finish these.
|
||||
Mark the spot with a sign painted red.
|
||||
Take two shares as a fair profit.
|
||||
The fur of cats goes by many names.
|
||||
North winds bring colds and fevers.
|
||||
He asks no person to vouch for him.
|
||||
Go now and come here later.
|
||||
A sash of gold silk will trim her dress.
|
||||
Soap can wash most dirt away.
|
||||
That move means the game is over.
|
||||
He wrote down a long list of items.
|
||||
A siege will crack the strong defense.
|
||||
Grape juice and water mix well.
|
||||
Roads are paved with sticky tar.
|
||||
Fake stones shine but cost little.
|
||||
The drip of the rain made a pleasant sound.
|
||||
Smoke poured out of every crack.
|
||||
Serve the hot rum to the tired heroes.
|
||||
Much of the story makes good sense.
|
||||
The sun came up to light the eastern sky.
|
||||
Heave the line over the port side.
|
||||
A lathe cuts and trims any wood.
|
||||
It's a dense crowd in two distinct ways.
|
||||
His hip struck the knee of the next player.
|
||||
The stale smell of old beer lingers.
|
||||
The desk was firm on the shaky floor.
|
||||
It takes heat to bring out the odor.
|
||||
Beef is scarcer than some lamb.
|
||||
Raise the sail and steer the ship northward.
|
||||
A cone costs five cents on Mondays.
|
||||
A pod is what peas always grow in.
|
||||
Jerk the dart from the cork target.
|
||||
No cement will hold hard wood.
|
||||
We now have a new base for shipping.
|
||||
A list of names is carved around the base.
|
||||
The sheep were led home by a dog.
|
||||
Three for a dime, the young peddler cried.
|
||||
The sense of smell is better than that of touch.
|
||||
No hardship seemed to keep him sad.
|
||||
Grace makes up for lack of beauty.
|
||||
Nudge gently but wake her now.
|
||||
The news struck doubt into restless minds.
|
||||
Once we stood beside the shore.
|
||||
A chink in the wall allowed a draft to blow.
|
||||
Fasten two pins on each side.
|
||||
A cold dip restores health and zest.
|
||||
He takes the oath of office each March.
|
||||
The sand drifts over the sill of the old house.
|
||||
The point of the steel pen was bent and twisted.
|
||||
There is a lag between thought and act.
|
||||
Seed is needed to plant the spring corn.
|
||||
Draw the chart with heavy black lines.
|
||||
The boy owed his pal thirty cents.
|
||||
The chap slipped into the crowd and was lost.
|
||||
Hats are worn to tea and not to dinner.
|
||||
The ramp led up to the wide highway.
|
||||
Beat the dust from the rug onto the lawn.
|
||||
Say it slowly but make it ring clear.
|
||||
The straw nest housed five robins.
|
||||
Screen the porch with woven straw mats.
|
||||
This horse will nose his way to the finish.
|
||||
The dry wax protects the deep scratch.
|
||||
He picked up the dice for a second roll.
|
||||
These coins will be needed to pay his debt.
|
||||
The nag pulled the frail cart along.
|
||||
Twist the valve and release hot steam.
|
||||
The vamp of the shoe had a gold buckle.
|
||||
The smell of burned rags itches my nose.
|
||||
New pants lack cuffs and pockets.
|
||||
The marsh will freeze when cold enough.
|
||||
They slice the sausage thin with a knife.
|
||||
The bloom of the rose lasts a few days.
|
||||
A gray mare walked before the colt.
|
||||
Breakfast buns are fine with a hot drink.
|
||||
Bottles hold four kinds of rum.
|
||||
The man wore a feather in his felt hat.
|
||||
He wheeled the bike past the winding road.
|
||||
Drop the ashes on the worn old rug.
|
||||
The desk and both chairs were painted tan.
|
||||
Throw out the used paper cup and plate.
|
||||
A clean neck means a neat collar.
|
||||
The couch cover and hall drapes were blue.
|
||||
The stems of the tall glasses cracked and broke.
|
||||
The wall phone rang loud and often.
|
||||
The clothes dried on a thin wooden rack.
|
||||
Turn on the lantern which gives us light.
|
||||
The cleat sank deeply into the soft turf.
|
||||
The bills were mailed promptly on the tenth of the month.
|
||||
To have is better than to wait and hope.
|
||||
The price is fair for a good antique clock.
|
||||
The music played on while they talked.
|
||||
Dispense with a vest on a day like this.
|
||||
The bunch of grapes was pressed into wine.
|
||||
He sent the figs, but kept the ripe cherries.
|
||||
The hinge on the door creaked with old age.
|
||||
The screen before the fire kept in the sparks.
|
||||
Fly by night, and you waste little time.
|
||||
Thick glasses helped him read the print.
|
||||
Birth and death mark the limits of life.
|
||||
The chair looked strong but had no bottom.
|
||||
The kite flew wildly in the high wind.
|
||||
A fur muff is stylish once more.
|
||||
The tin box held priceless stones.
|
||||
We need an end of all such matter.
|
||||
The case was puzzling to the old and wise.
|
||||
The bright lanterns were gay on the dark lawn.
|
||||
We don't get much money but we have fun.
|
||||
The youth drove with zest, but little skill.
|
||||
Five years he lived with a shaggy dog.
|
||||
A fence cuts through the corner lot.
|
||||
The way to save money is not to spend much.
|
||||
Shut the hatch before the waves push it in.
|
||||
The odor of spring makes young hearts jump.
|
||||
Crack the walnut with your sharp side teeth.
|
||||
He offered proof in the form of a large chart.
|
||||
Send the stuff in a thick paper bag.
|
||||
A quart of milk is water for the most part.
|
||||
They told wild tales to frighten him.
|
||||
The three story house was built of stone.
|
||||
In the rear of the ground floor was a large passage.
|
||||
A man in a blue sweater sat at the desk.
|
||||
Oats are a food eaten by horse and man.
|
||||
Their eyelids droop for want of sleep.
|
||||
A sip of tea revives his tired friend.
|
||||
There are many ways to do these things.
|
||||
Tuck the sheet under the edge of the mat.
|
||||
A force equal to that would move the earth.
|
||||
We like to see clear weather.
|
||||
The work of the tailor is seen on each side.
|
||||
Take a chance and win a china doll.
|
||||
Shake the dust from your shoes, stranger.
|
||||
She was kind to sick old people.
|
||||
The square wooden crate was packed to be shipped.
|
||||
The dusty bench stood by the stone wall.
|
||||
We dress to suit the weather of most days.
|
||||
Smile when you say nasty words.
|
||||
A bowl of rice is free with chicken stew.
|
||||
The water in this well is a source of good health.
|
||||
Take shelter in this tent, but keep still.
|
||||
That guy is the writer of a few banned books.
|
||||
The little tales they tell are false.
|
||||
The door was barred, locked, and bolted as well.
|
||||
Ripe pears are fit for a queen's table.
|
||||
A big wet stain was on the round carpet.
|
||||
The kite dipped and swayed, but stayed aloft.
|
||||
The pleasant hours fly by much too soon.
|
||||
The room was crowded with a wild mob.
|
||||
This strong arm shall shield your honor.
|
||||
She blushed when he gave her a white orchid.
|
||||
The beetle droned in the hot June sun.
|
||||
Press the pedal with your left foot.
|
||||
Neat plans fail without luck.
|
||||
The black trunk fell from the landing.
|
||||
The bank pressed for payment of the debt.
|
||||
The theft of the pearl pin was kept secret.
|
||||
Shake hands with this friendly child.
|
||||
The vast space stretched into the far distance.
|
||||
A rich farm is rare in this sandy waste.
|
||||
His wide grin earned many friends.
|
||||
Flax makes a fine brand of paper.
|
||||
Hurdle the pit with the aid of a long pole.
|
||||
A strong bid may scare your partner stiff.
|
||||
Even a just cause needs power to win.
|
||||
Peep under the tent and see the clowns.
|
||||
The leaf drifts along with a slow spin.
|
||||
Cheap clothes are flashy but don't last.
|
||||
A thing of small note can cause despair.
|
||||
Flood the mails with requests for this book.
|
||||
A thick coat of black paint covered all.
|
||||
The pencil was cut to be sharp at both ends.
|
||||
Those last words were a strong statement.
|
||||
He wrote his name boldly at the top of the sheet.
|
||||
Dill pickles are sour but taste fine.
|
||||
Down that road is the way to the grain farmer.
|
||||
Either mud or dust are found at all times.
|
||||
The best method is to fix it in place with clips.
|
||||
If you mumble your speech will be lost.
|
||||
At night the alarm roused him from a deep sleep.
|
||||
Read just what the meter says.
|
||||
Fill your pack with bright trinkets for the poor.
|
||||
The small red neon lamp went out.
|
||||
Clams are small, round, soft, and tasty.
|
||||
The fan whirled its round blades softly.
|
||||
The line where the edges join was clean.
|
||||
Breathe deep and smell the piny air.
|
||||
It matters not if he reads these words or those.
|
||||
A brown leather bag hung from its strap.
|
||||
A toad and a frog are hard to tell apart.
|
||||
A white silk jacket goes with any shoes.
|
||||
A break in the dam almost caused a flood.
|
||||
Paint the sockets in the wall dull green.
|
||||
The child crawled into the dense grass.
|
||||
Bribes fail where honest men work.
|
||||
Trample the spark, else the flames will spread.
|
||||
The hilt of the sword was carved with fine designs.
|
||||
A round hole was drilled through the thin board.
|
||||
Footprints showed the path he took up the beach.
|
||||
She was waiting at my front lawn.
|
||||
A vent near the edge brought in fresh air.
|
||||
Prod the old mule with a crooked stick.
|
||||
It is a band of steel three inches wide.
|
||||
The pipe ran almost the length of the ditch.
|
||||
It was hidden from sight by a mass of leaves and shrubs.
|
||||
The weight of the package was seen on the high scale.
|
||||
Wake and rise, and step into the green outdoors.
|
||||
The green light in the brown box flickered.
|
||||
The brass tube circled the high wall.
|
||||
The lobes of her ears were pierced to hold rings.
|
||||
Hold the hammer near the end to drive the nail.
|
||||
Next Sunday is the twelfth of the month.
|
||||
Every word and phrase he speaks is true.
|
||||
He put his last cartridge into the gun and fired.
|
||||
They took their kids from the public school.
|
||||
Drive the screw straight into the wood.
|
||||
Keep the hatch tight and the watch constant.
|
||||
Sever the twine with a quick snip of the knife.
|
||||
Paper will dry out when wet.
|
||||
Slide the catch back and open the desk.
|
||||
Help the weak to preserve their strength.
|
||||
A sullen smile gets few friends.
|
||||
Stop whistling and watch the boys march.
|
||||
Jerk the cord, and out tumbles the gold.
|
||||
Slide the tray across the glass top.
|
||||
The cloud moved in a stately way and was gone.
|
||||
Light maple makes for a swell room.
|
||||
Set the piece here and say nothing.
|
||||
Dull stories make her laugh.
|
||||
A stiff cord will do to fasten your shoe.
|
||||
Get the trust fund to the bank early.
|
||||
Choose between the high road and the low.
|
||||
A plea for funds seems to come again.
|
||||
He lent his coat to the tall gaunt stranger.
|
||||
There is a strong chance it will happen once more.
|
||||
The duke left the park in a silver coach.
|
||||
Greet the new guests and leave quickly.
|
||||
When the frost has come it is time for turkey.
|
||||
Sweet words work better than fierce.
|
||||
A thin stripe runs down the middle.
|
||||
A six comes up more often than a ten.
|
||||
Lush fern grow on the lofty rocks.
|
||||
The ram scared the school children off.
|
||||
The team with the best timing looks good.
|
||||
The farmer swapped his horse for a brown ox.
|
||||
Sit on the perch and tell the others what to do.
|
||||
A steep trail is painful for our feet.
|
||||
The early phase of life moves fast.
|
||||
Green moss grows on the northern side.
|
||||
Tea in thin china has a sweet taste.
|
||||
Pitch the straw through the door of the stable.
|
||||
The latch on the back gate needed a nail.
|
||||
The goose was brought straight from the old market.
|
||||
The sink is the thing in which we pile dishes.
|
||||
A whiff of it will cure the most stubborn cold.
|
||||
The facts don't always show who is right.
|
||||
She flaps her cape as she parades the street.
|
||||
The loss of the cruiser was a blow to the fleet.
|
||||
Loop the braid to the left and then over.
|
||||
Plead with the lawyer to drop the lost cause.
|
||||
Calves thrive on tender spring grass.
|
||||
Post no bills on this office wall.
|
||||
Tear a thin sheet from the yellow pad.
|
||||
A cruise in warm waters in a sleek yacht is fun.
|
||||
A streak of color ran down the left edge.
|
||||
It was done before the boy could see it.
|
||||
Crouch before you jump or miss the mark.
|
||||
Pack the kits and don't forget the salt.
|
||||
The square peg will settle in the round hole.
|
||||
Fine soap saves tender skin.
|
||||
Poached eggs and tea must suffice.
|
||||
Bad nerves are jangled by a door slam.
|
||||
Ship maps are different from those for planes.
|
||||
Dimes showered down from all sides.
|
||||
They sang the same tunes at each party.
|
||||
The sky in the west is tinged with orange red.
|
||||
The pods of peas ferment in bare fields.
|
||||
The horse balked and threw the tall rider.
|
||||
The hitch between the horse and cart broke.
|
||||
Pile the coal high in the shed corner.
|
||||
A gold vase is both rare and costly.
|
||||
The knife was hung inside its bright sheath.
|
||||
The rarest spice comes from the far East.
|
||||
The roof should be tilted at a sharp slant.
|
||||
A smatter of French is worse than none.
|
||||
The mule trod the treadmill day and night.
|
||||
The aim of the contest is to raise a great fund.
|
||||
To send it now in large amounts is bad.
|
||||
There is a fine hard tang in salty air.
|
||||
Cod is the main business of the north shore.
|
||||
The slab was hewn from heavy blocks of slate.
|
||||
Dunk the stale biscuits into strong drink.
|
||||
Hang tinsel from both branches.
|
||||
Cap the jar with a tight brass cover.
|
||||
The poor boy missed the boat again.
|
||||
Be sure to set the lamp firmly in the hole.
|
||||
Pick a card and slip it under the pack.
|
||||
A round mat will cover the dull spot.
|
||||
The first part of the plan needs changing.
|
||||
A good book informs of what we ought to know.
|
||||
The mail comes in three batches per day.
|
||||
You cannot brew tea in a cold pot.
|
||||
Dots of light betrayed the black cat.
|
||||
Put the chart on the mantel and tack it down.
|
||||
The night shift men rate extra pay.
|
||||
The red paper brightened the dim stage.
|
||||
See the player scoot to third base.
|
||||
Slide the bill between the two leaves.
|
||||
Many hands help get the job done.
|
||||
We don't like to admit our small faults.
|
||||
No doubt about the way the wind blows.
|
||||
Dig deep in the earth for pirate's gold.
|
||||
The steady drip is worse than a drenching rain.
|
||||
A flat pack takes less luggage space.
|
||||
Green ice frosted the punch bowl.
|
||||
A stuffed chair slipped from the moving van.
|
||||
The stitch will serve but needs to be shortened.
|
||||
A thin book fits in the side pocket.
|
||||
The gloss on top made it unfit to read.
|
||||
The hail pattered on the burnt brown grass.
|
||||
Seven seals were stamped on great sheets.
|
||||
Our troops are set to strike heavy blows.
|
||||
The store was jammed before the sale could start.
|
||||
It was a bad error on the part of the new judge.
|
||||
One step more and the board will collapse.
|
||||
Take the match and strike it against your shoe.
|
||||
The pot boiled, but the contents failed to jell.
|
||||
The baby puts his right foot in his mouth.
|
||||
The bombs left most of the town in ruins.
|
||||
Stop and stare at the hard working man.
|
||||
The streets are narrow and full of sharp turns.
|
||||
The pup jerked the leash as he saw a feline shape.
|
||||
Open your book to the first page.
|
||||
Fish evade the net and swim off.
|
||||
Dip the pail once and let it settle.
|
||||
Will you please answer that phone.
|
||||
The big red apple fell to the ground.
|
||||
The curtain rose and the show was on.
|
||||
The young prince became heir to the throne.
|
||||
He sent the boy on a short errand.
|
||||
Leave now and you will arrive on time.
|
||||
The corner store was robbed last night.
|
||||
A gold ring will please most any girl.
|
||||
The long journey home took a year.
|
||||
She saw a cat in the neighbor's house.
|
||||
A pink shell was found on the sandy beach.
|
||||
Small children came to see him.
|
||||
The grass and bushes were wet with dew.
|
||||
The blind man counted his old coins.
|
||||
A severe storm tore down the barn.
|
||||
She called his name many times.
|
||||
When you hear the bell, come quickly.
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"Arabic": "ar",
|
||||
"Chinese": "zh-cn",
|
||||
"Czech": "cs",
|
||||
"Dutch": "nl",
|
||||
"English": "en",
|
||||
"French": "fr",
|
||||
"German": "de",
|
||||
"Hungarian": "hu",
|
||||
"Italian": "it",
|
||||
"Japanese": "ja",
|
||||
"Korean": "ko",
|
||||
"Polish": "pl",
|
||||
"Portuguese": "pt",
|
||||
"Russian": "ru",
|
||||
"Spanish": "es",
|
||||
"Turkish": "tr"
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"branding": "AllTalk ",
|
||||
"tgwui": {
|
||||
"tgwui_activate_tts": true,
|
||||
"tgwui_autoplay_tts": true,
|
||||
"tgwui_narrator_enabled": "false",
|
||||
"tgwui_non_quoted_text_is": "silent",
|
||||
"tgwui_deepspeed_enabled": false,
|
||||
"tgwui_language": "English",
|
||||
"tgwui_lowvram_enabled": false,
|
||||
"tgwui_pitch_set": 0,
|
||||
"tgwui_temperature_set": 0.75,
|
||||
"tgwui_repetitionpenalty_set": 10,
|
||||
"tgwui_generationspeed_set": 1,
|
||||
"tgwui_narrator_voice": "en_US-ljspeech-high.onnx",
|
||||
"tgwui_show_text": true,
|
||||
"tgwui_character_voice": "en_US-ljspeech-high.onnx",
|
||||
"tgwui_rvc_char_voice": "Disabled",
|
||||
"tgwui_rvc_char_pitch": 0,
|
||||
"tgwui_rvc_narr_voice": "Disabled",
|
||||
"tgwui_rvc_narr_pitch": 0
|
||||
},
|
||||
"remote_connection": {
|
||||
"server_protocol": "http://",
|
||||
"server_address": "127.0.0.1:7851",
|
||||
"connection_timeout": 5,
|
||||
"use_legacy_api": false
|
||||
}
|
||||
}
|
||||
+2359
-607
File diff suppressed because it is too large.
Load diff
@@ -124,6 +124,7 @@
|
||||
<option value="English" {% if data.language=='English' %}selected{% endif %}>English</option>
|
||||
<option value="French" {% if data.language=='French' %}selected{% endif %}>French</option>
|
||||
<option value="German" {% if data.language=='German' %}selected{% endif %}>German</option>
|
||||
<option value="Hindi" {% if data.language=='Hindi' %}selected{% endif %}>Hindi</option>
|
||||
<option value="Hungarian" {% if data.language=='Hungarian' %}selected{% endif %}>Hungarian</option>
|
||||
<option value="Italian" {% if data.language=='Italian' %}selected{% endif %}>Italian</option>
|
||||
<option value="Japanese" {% if data.language=='Japanese' %}selected{% endif %}>Japanese</option>
|
||||
@@ -215,8 +216,20 @@
|
||||
modeldownload_model_path }}</span>
|
||||
|
||||
|
||||
<label for="port_number" style="color: red;"> Port Number:</label>
|
||||
<input id="port_number" name="port_number" required="" type="text" value="{{ data.port_number }}" /><br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label for="ip_address" style="color: red;"> IP Address:</label>
|
||||
<input id="ip_address" name="ip_address" required="" type="text" value="{{ data.ip_address }}" />
|
||||
|
||||
<label for="port_number" style="color: red;"> Port Number:</label>
|
||||
<input id="port_number" name="port_number" required="" type="text" value="{{ data.port_number }}" />
|
||||
|
||||
<div class="radio-group">
|
||||
<label for="tts_method_api_local" style="color: #33cc33;">Model: <span
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
Binary file not shown.
@@ -1,296 +0,0 @@
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import json
|
||||
import warnings
|
||||
import pyperclip
|
||||
import requests
|
||||
from PyQt5.QtWidgets import (QApplication, QSystemTrayIcon, QMenu, QWidget, QVBoxLayout, QLabel,
|
||||
QLineEdit, QPushButton, QMessageBox, QComboBox, QSlider)
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
|
||||
from PyQt5.QtGui import QIcon
|
||||
|
||||
# Suppress the specific warning
|
||||
warnings.filterwarnings("ignore", category=UserWarning, module="charset_normalizer")
|
||||
|
||||
SETTINGS_FILE = "tts_settings.json"
|
||||
TTS_SERVER_URL = "http://127.0.0.1:7851"
|
||||
|
||||
LANGUAGES = {
|
||||
"ar": "Arabic", "zh-cn": "Chinese (Simplified)", "cs": "Czech", "nl": "Dutch",
|
||||
"en": "English", "fr": "French", "de": "German", "hi": "Hindi (limited support)",
|
||||
"hu": "Hungarian", "it": "Italian", "ja": "Japanese", "ko": "Korean",
|
||||
"pl": "Polish", "pt": "Portuguese", "ru": "Russian", "es": "Spanish", "tr": "Turkish"
|
||||
}
|
||||
|
||||
class ClipboardMonitor(QThread):
|
||||
text_changed = pyqtSignal(str)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.last_text = pyperclip.paste()
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
while self.running:
|
||||
current_text = pyperclip.paste()
|
||||
if current_text != self.last_text:
|
||||
self.text_changed.emit(current_text)
|
||||
self.last_text = current_text
|
||||
time.sleep(0.5)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
class TTSWorker(QThread):
|
||||
error_occurred = pyqtSignal(str)
|
||||
|
||||
def __init__(self, api_url, params):
|
||||
super().__init__()
|
||||
self.api_url = api_url
|
||||
self.params = params
|
||||
self.text_queue = []
|
||||
|
||||
def add_text(self, text):
|
||||
self.text_queue.append(text)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if self.text_queue:
|
||||
text = self.text_queue.pop(0)
|
||||
self.send_to_tts(text)
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
|
||||
def send_to_tts(self, text):
|
||||
params = self.params.copy()
|
||||
params["text_input"] = text
|
||||
params["language"] = params["language"][:2] # Ensure we only send the 2-letter code
|
||||
try:
|
||||
response = requests.post(f"{self.api_url}/api/tts-generate", data=params)
|
||||
if response.status_code != 200:
|
||||
error_message = f"TTS generation failed with status code: {response.status_code}. Response: {response.text}"
|
||||
print(error_message)
|
||||
self.error_occurred.emit(error_message)
|
||||
except requests.RequestException as e:
|
||||
error_message = f"Error sending request to TTS API: {e}"
|
||||
print(error_message)
|
||||
self.error_occurred.emit(error_message)
|
||||
|
||||
class SettingsWindow(QWidget):
|
||||
settings_updated = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, tts_worker):
|
||||
super().__init__()
|
||||
self.tts_worker = tts_worker
|
||||
self.voices = []
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
layout.addWidget(QLabel("AllTalk API URL:"))
|
||||
self.api_url_input = QLineEdit(self.tts_worker.api_url)
|
||||
layout.addWidget(self.api_url_input)
|
||||
|
||||
layout.addWidget(QLabel("Voice:"))
|
||||
self.voice_combo = QComboBox()
|
||||
layout.addWidget(self.voice_combo)
|
||||
|
||||
layout.addWidget(QLabel("Language:"))
|
||||
self.language_combo = QComboBox()
|
||||
for code, name in LANGUAGES.items():
|
||||
self.language_combo.addItem(f"{name} ({code})", code)
|
||||
current_lang = self.tts_worker.params.get("language", "en")
|
||||
index = self.language_combo.findData(current_lang)
|
||||
if index >= 0:
|
||||
self.language_combo.setCurrentIndex(index)
|
||||
layout.addWidget(self.language_combo)
|
||||
|
||||
layout.addWidget(QLabel("Text Filtering:"))
|
||||
self.text_filtering_input = QLineEdit(self.tts_worker.params["text_filtering"])
|
||||
layout.addWidget(self.text_filtering_input)
|
||||
|
||||
layout.addWidget(QLabel("Playback Volume:"))
|
||||
self.volume_slider = QSlider(Qt.Horizontal)
|
||||
self.volume_slider.setRange(1, 10)
|
||||
self.volume_slider.setValue(int(float(self.tts_worker.params["autoplay_volume"]) * 10))
|
||||
layout.addWidget(self.volume_slider)
|
||||
|
||||
save_button = QPushButton("Save")
|
||||
save_button.clicked.connect(self.save_settings)
|
||||
layout.addWidget(save_button)
|
||||
|
||||
refresh_button = QPushButton("Refresh Voices")
|
||||
refresh_button.clicked.connect(self.refresh_voices)
|
||||
layout.addWidget(refresh_button)
|
||||
|
||||
self.setWindowTitle("AllTalk Clipboard TTS")
|
||||
self.setGeometry(300, 300, 300, 400)
|
||||
|
||||
self.refresh_voices()
|
||||
|
||||
def refresh_voices(self):
|
||||
try:
|
||||
response = requests.get(f"{self.tts_worker.api_url}/api/voices")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data["status"] == "success" and "voices" in data:
|
||||
self.voices = data["voices"]
|
||||
self.voice_combo.clear()
|
||||
for voice in self.voices:
|
||||
self.voice_combo.addItem(voice)
|
||||
if self.voices:
|
||||
current_voice = self.tts_worker.params["character_voice_gen"]
|
||||
if current_voice in self.voices:
|
||||
self.voice_combo.setCurrentText(current_voice)
|
||||
else:
|
||||
self.voice_combo.setCurrentIndex(0)
|
||||
else:
|
||||
QMessageBox.warning(self, "Error", "Failed to fetch voices: Unexpected response format")
|
||||
else:
|
||||
QMessageBox.warning(self, "Error", f"Failed to fetch voices. Status code: {response.status_code}")
|
||||
except requests.RequestException as e:
|
||||
QMessageBox.warning(self, "Error", f"Failed to fetch voices: {str(e)}")
|
||||
|
||||
def save_settings(self):
|
||||
new_settings = {
|
||||
"api_url": self.api_url_input.text(),
|
||||
"params": {
|
||||
"character_voice_gen": self.voice_combo.currentText(),
|
||||
"language": self.language_combo.currentData(),
|
||||
"text_filtering": self.text_filtering_input.text(),
|
||||
"output_file_name": "clipboard_tts",
|
||||
"output_file_timestamp": "true",
|
||||
"autoplay": "true",
|
||||
"autoplay_volume": str(self.volume_slider.value() / 10.0)
|
||||
}
|
||||
}
|
||||
self.settings_updated.emit(new_settings)
|
||||
self.hide()
|
||||
|
||||
class TTSApp(QSystemTrayIcon):
|
||||
def __init__(self, app):
|
||||
super().__init__(parent=app)
|
||||
self.app = app
|
||||
self.load_settings()
|
||||
self.init_ui()
|
||||
|
||||
def load_settings(self):
|
||||
try:
|
||||
with open(SETTINGS_FILE, 'r') as f:
|
||||
self.settings = json.load(f)
|
||||
except FileNotFoundError:
|
||||
self.settings = {
|
||||
"api_url": TTS_SERVER_URL,
|
||||
"params": {
|
||||
"text_filtering": "standard",
|
||||
"character_voice_gen": "",
|
||||
"language": "en",
|
||||
"output_file_name": "clipboard_tts",
|
||||
"output_file_timestamp": "true",
|
||||
"autoplay": "true",
|
||||
"autoplay_volume": "0.8"
|
||||
}
|
||||
}
|
||||
|
||||
def save_settings(self):
|
||||
with open(SETTINGS_FILE, 'w') as f:
|
||||
json.dump(self.settings, f)
|
||||
|
||||
def init_ui(self):
|
||||
self.tts_worker = TTSWorker(self.settings["api_url"], self.settings["params"])
|
||||
self.tts_worker.error_occurred.connect(self.show_error_message)
|
||||
self.tts_worker.start()
|
||||
|
||||
self.clipboard_monitor = ClipboardMonitor()
|
||||
self.clipboard_monitor.text_changed.connect(self.on_text_changed)
|
||||
|
||||
self.setIcon(QIcon("icon.png"))
|
||||
self.setVisible(True)
|
||||
|
||||
menu = QMenu()
|
||||
start_action = menu.addAction("Start Monitoring")
|
||||
start_action.triggered.connect(self.start_monitoring)
|
||||
stop_action = menu.addAction("Stop Monitoring")
|
||||
stop_action.triggered.connect(self.stop_monitoring)
|
||||
settings_action = menu.addAction("Settings")
|
||||
settings_action.triggered.connect(self.show_settings)
|
||||
exit_action = menu.addAction("Exit")
|
||||
exit_action.triggered.connect(self.exit_app)
|
||||
self.setContextMenu(menu)
|
||||
|
||||
self.settings_window = SettingsWindow(self.tts_worker)
|
||||
self.settings_window.settings_updated.connect(self.update_settings)
|
||||
|
||||
def on_text_changed(self, text):
|
||||
self.tts_worker.add_text(text)
|
||||
|
||||
def start_monitoring(self):
|
||||
self.clipboard_monitor.start()
|
||||
self.showMessage("TTS App", "Clipboard monitoring started")
|
||||
|
||||
def stop_monitoring(self):
|
||||
self.clipboard_monitor.stop()
|
||||
self.showMessage("TTS App", "Clipboard monitoring stopped")
|
||||
|
||||
def show_settings(self):
|
||||
self.settings_window.show()
|
||||
|
||||
def update_settings(self, new_settings):
|
||||
self.settings = new_settings
|
||||
self.tts_worker.api_url = new_settings["api_url"]
|
||||
self.tts_worker.params = new_settings["params"]
|
||||
self.save_settings()
|
||||
self.showMessage("TTS App", "Settings updated successfully")
|
||||
|
||||
def show_error_message(self, message):
|
||||
QMessageBox.critical(None, "Error", message)
|
||||
|
||||
def exit_app(self):
|
||||
self.clipboard_monitor.stop()
|
||||
self.tts_worker.quit()
|
||||
QApplication.instance().quit()
|
||||
|
||||
def check_server_ready(url, timeout=10):
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
response = requests.get(f"{url}/api/ready")
|
||||
if response.status_code == 200 and response.text == "Ready":
|
||||
return True
|
||||
except requests.RequestException:
|
||||
pass
|
||||
time.sleep(1)
|
||||
return False
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
print("[Clipboard to TTS] Exiting...")
|
||||
QApplication.instance().quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("[Clipboard to TTS] AllTalk Clipboard to TTS is starting...")
|
||||
|
||||
if not check_server_ready(TTS_SERVER_URL):
|
||||
print("[Clipboard to TTS] Error: AllTalk TTS server is not ready. Please start the AllTalk server and try again.")
|
||||
sys.exit(1)
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
if not QSystemTrayIcon.isSystemTrayAvailable():
|
||||
print("[Clipboard to TTS] System tray is not available on this system.")
|
||||
sys.exit(1)
|
||||
|
||||
tts_app = TTSApp(app)
|
||||
|
||||
# This allows for Ctrl+C to work
|
||||
timer = QTimer()
|
||||
timer.start(500)
|
||||
timer.timeout.connect(lambda: None)
|
||||
|
||||
print("[Clipboard to TTS] AllTalk Clipboard to TTS is running... Check your system tray for the icon.")
|
||||
print("[Clipboard to TTS] Press Ctrl+C to exit")
|
||||
sys.exit(app.exec_())
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,13 +0,0 @@
|
||||
This is a Windows only clipboard to TTS extension. Its a very rough bit of code with no logic or error handling built in.
|
||||
|
||||
When run it will create a system tray icon that you can Start/Stop clipboard monitoring for the text stored in the clipboard changing. When the text changes, it will be sent to AllTalk for TTS generation. You can specify the voice to use in the System Tray icon Settings area.
|
||||
|
||||
In the main folder, run "start_environment.bat" to start the AllTalk Python environment.
|
||||
|
||||
You will need to "pip install pyqt5 pyperclip requests" for to install the requirements into the AllTalk Python environment (you will only need to do this the once, but always start the Python environment).
|
||||
|
||||
Go to the "cliptotts" folder and "python clipboard-to-tts.py" which should start the application.
|
||||
|
||||
Start monitoring of the clipboard on the icon in the system tray.
|
||||
|
||||
When you Ctrl+C text to the clipboard, it will be sent over for TTS generation and it will play back at the AllTalk console.
|
||||
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -1,564 +0,0 @@
|
||||
======================================
|
||||
AllTalk Base Diagnostic log file for Standalone Installations
|
||||
======================================
|
||||
Diagnostic log created at 2024-11-06 01:25:33.123679
|
||||
======================================
|
||||
|
||||
OPERATING SYSTEM:
|
||||
OS Version: Windows 10.0.22631
|
||||
Note: Windows 11 will list as build is 10.x.22xxx
|
||||
|
||||
HARDWARE ENVIRONMENT:
|
||||
CPU: Physical Cores: 8, Total Cores: 16, Max Frequency: 3800.0 MHz
|
||||
System RAM: 19.46 GB available out of 31.34 GB total
|
||||
|
||||
GPU INFORMATION:
|
||||
Fri Sep 27 20:50:15 2024
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| NVIDIA-SMI 560.94 Driver Version: 560.94 CUDA Version: 12.6 |
|
||||
|-----------------------------------------+------------------------+----------------------+
|
||||
| GPU Name Driver-Model | Bus-Id Disp.A | Volatile Uncorr. ECC |
|
||||
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
|
||||
| | | MIG M. |
|
||||
|=========================================+========================+======================|
|
||||
| 0 NVIDIA GeForce RTX 4070 WDDM | 00000000:01:00.0 On | N/A |
|
||||
| 0% 39C P8 13W / 200W | 1071MiB / 12282MiB | 1% Default |
|
||||
| | | N/A |
|
||||
+-----------------------------------------+------------------------+----------------------+
|
||||
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| Processes: |
|
||||
| GPU GI CI PID Type Process name GPU Memory |
|
||||
| ID ID Usage |
|
||||
|=========================================================================================|
|
||||
| 0 N/A N/A 1508 C+G ...nt.CBS_cw5n1h2txyewy\SearchHost.exe N/A |
|
||||
| 0 N/A N/A 2756 C+G ...\cef\cef.win7x64\steamwebhelper.exe N/A |
|
||||
| 0 N/A N/A 5488 C+G ...2txyewy\StartMenuExperienceHost.exe N/A |
|
||||
| 0 N/A N/A 6504 C+G ...ekyb3d8bbwe\PhoneExperienceHost.exe N/A |
|
||||
| 0 N/A N/A 7212 C+G ...t.LockApp_cw5n1h2txyewy\LockApp.exe N/A |
|
||||
| 0 N/A N/A 8604 C+G C:\Windows\explorer.exe N/A |
|
||||
| 0 N/A N/A 8852 C+G ...ft Office\root\Office16\OUTLOOK.EXE N/A |
|
||||
| 0 N/A N/A 11964 C+G ...5.0_x64__cv1g1gvanyjgm\WhatsApp.exe N/A |
|
||||
| 0 N/A N/A 12516 C+G ...CBS_cw5n1h2txyewy\TextInputHost.exe N/A |
|
||||
| 0 N/A N/A 13376 C+G ...\cef\cef.win7x64\steamwebhelper.exe N/A |
|
||||
| 0 N/A N/A 17632 C+G ...nr4m\radeonsoftware\AMDRSSrcExt.exe N/A |
|
||||
| 0 N/A N/A 18316 C+G ...m\radeonsoftware\RadeonSoftware.exe N/A |
|
||||
| 0 N/A N/A 18908 C+G ...siveControlPanel\SystemSettings.exe N/A |
|
||||
| 0 N/A N/A 19032 C+G ...am Files\Microsoft VS Code\Code.exe N/A |
|
||||
| 0 N/A N/A 21216 C+G ...bytes\Anti-Malware\Malwarebytes.exe N/A |
|
||||
| 0 N/A N/A 21476 C+G ...crosoft\Edge\Application\msedge.exe N/A |
|
||||
| 0 N/A N/A 21604 C+G ...ta\Local\WeMod\app-9.10.3\WeMod.exe N/A |
|
||||
| 0 N/A N/A 22344 C+G ...__8wekyb3d8bbwe\WindowsTerminal.exe N/A |
|
||||
| 0 N/A N/A 25292 C+G ...5n1h2txyewy\ShellExperienceHost.exe N/A |
|
||||
| 0 N/A N/A 26220 C ...\alltalk_environment\env\python.exe N/A |
|
||||
| 0 N/A N/A 27960 C+G ...Brave-Browser\Application\brave.exe N/A |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
|
||||
CUDA:
|
||||
CUDA Working: Success - CUDA is available and working.
|
||||
CUDA_HOME : N/A
|
||||
CUDA Device : NVIDIA GeForce RTX 4070
|
||||
CUDA Memory : 11.99 GB
|
||||
CUDA Version: 12.1
|
||||
|
||||
DISK INFORMATION:
|
||||
Drive: C:\ | Total: 1000.95 GB | Used: 852.08 GB | Free: 148.87 GB | Type: NTFS
|
||||
|
||||
NETWORK PORT:
|
||||
Port Status : Port 7851 is available.
|
||||
Cublas64_11 Path: C:\myfiles\alltalk_tts\alltalk_environment\env\Lib\site-packages\nvidia/cublas\bin\cublas64_11.dll
|
||||
|
||||
Windows C++ Build tools & Windows SDK:
|
||||
Windows Version: Windows 11
|
||||
Visual C++ Build Tools and/or Visual Studio found:
|
||||
Visual Studio 2019 Build Tools (Path: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools)
|
||||
|
||||
Windows SDK(s) found:
|
||||
SDK Version: 10.0.22000.0
|
||||
Path: C:\Program Files (x86)\Windows Kits\10
|
||||
Python setuptools version: 75.1.0
|
||||
|
||||
Windows Espeak-ng:
|
||||
Espeak-ng version: eSpeak NG text-to-speech: 1.52-dev Data at: C:\Program Files\eSpeak NG\/espeak-ng-data
|
||||
|
||||
PYTHON & PYTORCH:
|
||||
Torch Version: 2.2.1
|
||||
Python Version: 3.11.10
|
||||
Python Version Info: sys.version_info(major=3, minor=11, micro=10, releaselevel='final', serial=0)
|
||||
Python Executable: C:\myfiles\alltalk_tts\alltalk_environment\env\python.exe
|
||||
Python Virtual Environment: N/A (Should be N/A when in Text-generation-webui Conda Python environment)
|
||||
Conda Environment: C:\myfiles\alltalk_tts\alltalk_environment\env
|
||||
|
||||
Python Search Path:
|
||||
C:\myfiles\alltalk_tts
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\python311.zip
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\DLLs
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Lib
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Lib\site-packages
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Lib\site-packages\win32
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Lib\site-packages\win32\lib
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Lib\site-packages\Pythonwin
|
||||
|
||||
OS SEARCHPATH ENVIRONMENT:
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Lib\site-packages\PyQt6\Qt6\bin
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Library\mingw-w64\bin
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Library\usr\bin
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Library\bin
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\Scripts
|
||||
C:\myfiles\alltalk_tts\alltalk_environment\env\bin
|
||||
C:\Program Files (x86)\Common Files\Oracle\Java\javapath
|
||||
C:\Windows\system32
|
||||
C:\Windows
|
||||
C:\Windows\System32\Wbem
|
||||
C:\Windows\System32\WindowsPowerShell\v1.0
|
||||
C:\Program Files\dotnet
|
||||
C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR
|
||||
C:\Program Files\Git\cmd
|
||||
C:\ProgramData\chocolatey\bin
|
||||
C:
|
||||
C:\Program Files\nodejs
|
||||
C:\Program Files (x86)\Windows Kits\10\App Certification Kit
|
||||
C:\Program Files\Microsoft VS Code\bin
|
||||
C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common
|
||||
C:\Program Files\NVIDIA Corporation\Nsight Compute 2023.1.0
|
||||
C:\Program Files\eSpeak NG
|
||||
C:\Program Files (x86)\eSpeak NG
|
||||
|
||||
CONDA INFORMATION:
|
||||
Conda Executable: C:\myfiles\alltalk_tts\alltalk_environment\conda\condabin\..\Scripts\conda.exe
|
||||
Conda Version: 24.4.0
|
||||
Current Environment: C:\myfiles\alltalk_tts\alltalk_environment\env
|
||||
Conda Environments:
|
||||
- C:\myfiles\alltalk_tts\alltalk_environment\conda
|
||||
- C:\myfiles\alltalk_tts\alltalk_environment\env
|
||||
|
||||
CONDA PACKAGES IN CURRENT ENVIRONMENT:
|
||||
|
||||
CONDA-FORGE PACKAGES:
|
||||
aom Version: 3.9.1 Channel: conda-forge
|
||||
cairo Version: 1.18.0 Channel: conda-forge
|
||||
ffmpeg Version: 4.3.1 Channel: conda-forge
|
||||
fontconfig Version: 2.15.0 Channel: conda-forge
|
||||
freetype Version: 2.12.1 Channel: conda-forge
|
||||
harfbuzz Version: 9.0.0 Channel: conda-forge
|
||||
icu Version: 75.1 Channel: conda-forge
|
||||
lcms2 Version: 2.15 Channel: conda-forge
|
||||
libexpat Version: 2.6.4 Channel: conda-forge
|
||||
libglib Version: 2.82.2 Channel: conda-forge
|
||||
libiconv Version: 1.17 Channel: conda-forge
|
||||
libintl Version: 0.22.5 Channel: conda-forge
|
||||
libopus Version: 1.3.1 Channel: conda-forge
|
||||
libpng Version: 1.6.44 Channel: conda-forge
|
||||
libsqlite Version: 3.47.0 Channel: conda-forge
|
||||
libxcb Version: 1.13 Channel: conda-forge
|
||||
libxml2 Version: 2.13.5 Channel: conda-forge
|
||||
libzlib Version: 1.3.1 Channel: conda-forge
|
||||
openh264 Version: 2.4.1 Channel: conda-forge
|
||||
openssl Version: 3.4.0 Channel: conda-forge
|
||||
pcre2 Version: 10.44 Channel: conda-forge
|
||||
pixman Version: 0.43.4 Channel: conda-forge
|
||||
python Version: 3.11.10 Channel: conda-forge
|
||||
python_abi Version: 3.11 Channel: conda-forge
|
||||
svt-av1 Version: 2.2.1 Channel: conda-forge
|
||||
tk Version: 8.6.13 Channel: conda-forge
|
||||
vc14_runtime Version: 14.42.34433 Channel: conda-forge
|
||||
vs2015_runtime Version: 14.42.34433 Channel: conda-forge
|
||||
x264 Version: 1!164.3095 Channel: conda-forge
|
||||
x265 Version: 3.5 Channel: conda-forge
|
||||
xorg-libxau Version: 1.0.11 Channel: conda-forge
|
||||
xorg-libxdmcp Version: 1.1.3 Channel: conda-forge
|
||||
zlib Version: 1.3.1 Channel: conda-forge
|
||||
zstd Version: 1.5.6 Channel: conda-forge
|
||||
|
||||
PKGS/MAIN PACKAGES:
|
||||
blas Version: 1.0 Channel: pkgs/main
|
||||
brotli-python Version: 1.0.9 Channel: pkgs/main
|
||||
bzip2 Version: 1.0.8 Channel: pkgs/main
|
||||
ca-certificates Version: 2024.9.24 Channel: pkgs/main
|
||||
certifi Version: 2024.8.30 Channel: pkgs/main
|
||||
charset-normalizer Version: 3.3.2 Channel: pkgs/main
|
||||
dav1d Version: 1.2.1 Channel: pkgs/main
|
||||
font-ttf-dejavu-sans-mono Version: 2.37 Channel: pkgs/main
|
||||
font-ttf-inconsolata Version: 2.001 Channel: pkgs/main
|
||||
font-ttf-source-code-pro Version: 2.030 Channel: pkgs/main
|
||||
font-ttf-ubuntu Version: 0.83 Channel: pkgs/main
|
||||
fonts-anaconda Version: 1 Channel: pkgs/main
|
||||
fonts-conda-ecosystem Version: 1 Channel: pkgs/main
|
||||
gmpy2 Version: 2.1.2 Channel: pkgs/main
|
||||
graphite2 Version: 1.3.14 Channel: pkgs/main
|
||||
idna Version: 3.7 Channel: pkgs/main
|
||||
intel-openmp Version: 2023.1.0 Channel: pkgs/main
|
||||
jinja2 Version: 3.1.4 Channel: pkgs/main
|
||||
jpeg Version: 9e Channel: pkgs/main
|
||||
lerc Version: 3.0 Channel: pkgs/main
|
||||
libdeflate Version: 1.17 Channel: pkgs/main
|
||||
libffi Version: 3.4.4 Channel: pkgs/main
|
||||
libjpeg-turbo Version: 2.0.0 Channel: pkgs/main
|
||||
libtiff Version: 4.5.0 Channel: pkgs/main
|
||||
libuv Version: 1.48.0 Channel: pkgs/main
|
||||
libwebp-base Version: 1.3.2 Channel: pkgs/main
|
||||
lz4-c Version: 1.9.4 Channel: pkgs/main
|
||||
markupsafe Version: 2.1.3 Channel: pkgs/main
|
||||
mkl Version: 2023.1.0 Channel: pkgs/main
|
||||
mkl-service Version: 2.4.0 Channel: pkgs/main
|
||||
mkl_fft Version: 1.3.11 Channel: pkgs/main
|
||||
mkl_random Version: 1.2.8 Channel: pkgs/main
|
||||
mpc Version: 1.1.0 Channel: pkgs/main
|
||||
mpfr Version: 4.0.2 Channel: pkgs/main
|
||||
mpir Version: 3.0.0 Channel: pkgs/main
|
||||
mpmath Version: 1.3.0 Channel: pkgs/main
|
||||
networkx Version: 3.2.1 Channel: pkgs/main
|
||||
numpy Version: 1.26.4 Channel: pkgs/main
|
||||
numpy-base Version: 1.26.4 Channel: pkgs/main
|
||||
openjpeg Version: 2.5.2 Channel: pkgs/main
|
||||
packaging Version: 24.1 Channel: pkgs/main
|
||||
pip Version: 24.2 Channel: pkgs/main
|
||||
pthread-stubs Version: 0.3 Channel: pkgs/main
|
||||
pysocks Version: 1.7.1 Channel: pkgs/main
|
||||
pyyaml Version: 6.0.2 Channel: pkgs/main
|
||||
requests Version: 2.32.3 Channel: pkgs/main
|
||||
setuptools Version: 75.1.0 Channel: pkgs/main
|
||||
sqlite Version: 3.45.3 Channel: pkgs/main
|
||||
sympy Version: 1.13.2 Channel: pkgs/main
|
||||
tbb Version: 2021.8.0 Channel: pkgs/main
|
||||
ucrt Version: 10.0.20348.0 Channel: pkgs/main
|
||||
urllib3 Version: 2.2.3 Channel: pkgs/main
|
||||
vc Version: 14.40 Channel: pkgs/main
|
||||
wheel Version: 0.44.0 Channel: pkgs/main
|
||||
win_inet_pton Version: 1.1.0 Channel: pkgs/main
|
||||
xz Version: 5.4.6 Channel: pkgs/main
|
||||
yaml Version: 0.2.5 Channel: pkgs/main
|
||||
|
||||
PKGS/MSYS2 PACKAGES:
|
||||
m2w64-gcc-libgfortran Version: 5.3.0 Channel: pkgs/msys2
|
||||
m2w64-gcc-libs Version: 5.3.0 Channel: pkgs/msys2
|
||||
m2w64-gcc-libs-core Version: 5.3.0 Channel: pkgs/msys2
|
||||
m2w64-gmp Version: 6.1.0 Channel: pkgs/msys2
|
||||
m2w64-libwinpthread-git Version: 5.0.0.4634.697f757 Channel: pkgs/msys2
|
||||
msys2-conda-epoch Version: 20160418 Channel: pkgs/msys2
|
||||
|
||||
OTHER PACKAGES:
|
||||
faiss-cpu Version: 1.9.0 Channel: pytorch
|
||||
libfaiss Version: 1.9.0 Channel: pytorch
|
||||
pytorch Version: 2.2.1 Channel: pytorch
|
||||
pytorch-cuda Version: 12.1 Channel: pytorch
|
||||
pytorch-mutex Version: 1.0 Channel: pytorch
|
||||
|
||||
PACKAGE VERSIONS vs REQUIREMENTS FILE:
|
||||
coqui-tts Required: >= 0.24.3 Installed: 0.24.3
|
||||
filelock Required: >= 3.16.1 Installed: 3.13.4
|
||||
fuzzywuzzy Required: >= 0.18.0 Installed: 0.18.0
|
||||
ffmpeg-python Required: >= 0.2.0 Installed: 0.2.0
|
||||
gradio Required: == 4.44.1 Installed: 4.44.1
|
||||
importlib_metadata Required: >= 7.2.1 Installed: 8.5.0
|
||||
inputimeout Required: >= 1.0.4 Installed: 1.0.4
|
||||
Jinja2 Required: >= 3.1.4 Installed: 3.1.4
|
||||
librosa Required: >= 0.10.2.post1 Installed: 0.10.2.post1
|
||||
onnxruntime-gpu Required: >= 1.18.1 Installed: 1.20.1
|
||||
pydantic Required: >= 2.8.2 Installed: 2.10.1
|
||||
python-Levenshtein Required: >= 0.25.1 Installed: 0.26.1
|
||||
praat-parselmouth Required: >= 0.4.4 Installed: 0.4.5
|
||||
pyworld Required: >= 0.3.4 Installed: 0.3.4
|
||||
sounddevice Required: >= 0.4.7 Installed: 0.5.1
|
||||
soundfile Required: >= 0.12.1 Installed: 0.12.1
|
||||
spacy Required: >= 3.7.1 Installed: 3.7.5
|
||||
torchcrepe Required: >= 0.0.2 Installed: 0.0.23
|
||||
tqdm Required: >= 4.66.5 Installed: 4.67.1
|
||||
unidic-lite Required: >= 1.0.8 Installed: 1.0.8
|
||||
uvicorn Required: >= 0.29.0 Installed: 0.32.1
|
||||
pillow Required: == 10.3.0 Installed: 10.3.0
|
||||
pypinyin Required: >= 0.52.0 Installed: 0.53.0
|
||||
word2number Required: >= 1.1 Installed: 1.1
|
||||
cutlet Required: == 0.4.0 Installed: 0.4.0
|
||||
fugashi Required: == 1.3.1 Installed: 1.3.1
|
||||
fastapi Required: == 0.112.2 Installed: 0.112.2
|
||||
plotly Required: == 5.24.1 Installed: 5.24.1
|
||||
scipy Required: == 1.14.1 Installed: 1.14.1
|
||||
|
||||
PYTHON PACKAGES:
|
||||
absl-py = 2.1.0
|
||||
accelerate = 1.1.1
|
||||
aiofiles = 23.2.1
|
||||
aiohappyeyeballs = 2.4.3
|
||||
aiohttp = 3.11.7
|
||||
aiosignal = 1.3.1
|
||||
annotated-types = 0.7.0
|
||||
antlr4-python3-runtime = 4.9.3
|
||||
anyascii = 0.3.2
|
||||
anyio = 4.6.2.post1
|
||||
argbind = 0.3.9
|
||||
asttokens = 2.4.1
|
||||
attrs = 24.2.0
|
||||
audioread = 3.0.1
|
||||
babel = 2.16.0
|
||||
bitarray = 3.0.0
|
||||
bitsandbytes = 0.44.1
|
||||
blis = 0.7.11
|
||||
boto3 = 1.35.69
|
||||
botocore = 1.35.69
|
||||
Brotli = 1.0.9
|
||||
cached_path = 1.6.4
|
||||
cachetools = 5.5.0
|
||||
catalogue = 2.0.10
|
||||
certifi = 2024.8.30
|
||||
cffi = 1.17.1
|
||||
charset-normalizer = 3.3.2
|
||||
click = 8.1.7
|
||||
cloudpathlib = 0.20.0
|
||||
colorama = 0.4.6
|
||||
coloredlogs = 15.0.1
|
||||
confection = 0.1.5
|
||||
contourpy = 1.3.1
|
||||
coqpit = 0.0.17
|
||||
coqui-tts = 0.24.3
|
||||
coqui-tts-trainer = 0.1.7
|
||||
cutlet = 0.4.0
|
||||
cycler = 0.12.1
|
||||
cymem = 2.0.10
|
||||
Cython = 3.0.11
|
||||
datasets = 3.1.0
|
||||
dateparser = 1.1.8
|
||||
decorator = 5.1.1
|
||||
deepspeed = 0.14.0+ce78a63
|
||||
descript-audiotools = 0.7.4
|
||||
descript-audio-codec = 1.0.0
|
||||
dill = 0.3.8
|
||||
docker-pycreds = 0.4.0
|
||||
docopt = 0.6.2
|
||||
docstring_parser = 0.16
|
||||
einops = 0.8.0
|
||||
einx = 0.3.0
|
||||
ema-pytorch = 0.7.6
|
||||
encodec = 0.1.1
|
||||
executing = 2.1.0
|
||||
fairseq = 0.12.4
|
||||
faiss = 1.9.0
|
||||
fastapi = 0.112.2
|
||||
ffmpeg-python = 0.2.0
|
||||
ffmpy = 0.4.0
|
||||
filelock = 3.13.4
|
||||
fire = 0.7.0
|
||||
flatbuffers = 24.3.25
|
||||
flatten-dict = 0.4.2
|
||||
fonttools = 4.55.0
|
||||
frozendict = 2.4.6
|
||||
frozenlist = 1.5.0
|
||||
fsspec = 2024.9.0
|
||||
fugashi = 1.3.1
|
||||
future = 1.0.0
|
||||
fuzzywuzzy = 0.18.0
|
||||
gitdb = 4.0.11
|
||||
GitPython = 3.1.43
|
||||
gmpy2 = 2.1.2
|
||||
googleapis-common-protos = 1.66.0
|
||||
google-api-core = 2.23.0
|
||||
google-auth = 2.36.0
|
||||
google-cloud-core = 2.4.1
|
||||
google-cloud-storage = 2.18.2
|
||||
google-crc32c = 1.6.0
|
||||
google-resumable-media = 2.7.2
|
||||
gradio = 4.44.1
|
||||
gradio_client = 1.3.0
|
||||
grpcio = 1.68.0
|
||||
gruut = 2.4.0
|
||||
gruut-ipa = 0.13.0
|
||||
gruut_lang_de = 2.0.1
|
||||
gruut_lang_en = 2.0.1
|
||||
gruut_lang_es = 2.0.1
|
||||
gruut_lang_fr = 2.0.2
|
||||
h11 = 0.14.0
|
||||
hangul-romanize = 0.1.0
|
||||
hjson = 3.1.0
|
||||
httpcore = 1.0.7
|
||||
httpx = 0.27.2
|
||||
huggingface-hub = 0.26.2
|
||||
humanfriendly = 10.0
|
||||
hydra-core = 1.3.2
|
||||
idna = 3.7
|
||||
importlib_metadata = 8.5.0
|
||||
importlib_resources = 6.4.5
|
||||
inflect = 7.4.0
|
||||
inputimeout = 1.0.4
|
||||
ipython = 8.29.0
|
||||
jaconv = 0.4.0
|
||||
jedi = 0.19.2
|
||||
jieba = 0.42.1
|
||||
Jinja2 = 3.1.4
|
||||
jmespath = 1.0.1
|
||||
joblib = 1.4.2
|
||||
jsonlines = 1.2.0
|
||||
julius = 0.2.7
|
||||
kiwisolver = 1.4.7
|
||||
langcodes = 3.5.0
|
||||
language_data = 1.3.0
|
||||
lazy_loader = 0.4
|
||||
Levenshtein = 0.26.1
|
||||
librosa = 0.10.2.post1
|
||||
llvmlite = 0.43.0
|
||||
local-attention = 1.9.15
|
||||
lxml = 5.3.0
|
||||
marisa-trie = 1.2.1
|
||||
Markdown = 3.7
|
||||
markdown2 = 2.5.1
|
||||
markdown-it-py = 3.0.0
|
||||
MarkupSafe = 2.1.3
|
||||
matplotlib = 3.9.2
|
||||
matplotlib-inline = 0.1.7
|
||||
mdurl = 0.1.2
|
||||
mkl_fft = 1.3.11
|
||||
mkl_random = 1.2.8
|
||||
mkl-service = 2.4.0
|
||||
mojimoji = 0.0.13
|
||||
more-itertools = 10.5.0
|
||||
mpmath = 1.3.0
|
||||
msgpack = 1.1.0
|
||||
multidict = 6.1.0
|
||||
multiprocess = 0.70.16
|
||||
murmurhash = 1.0.11
|
||||
networkx = 3.2.1
|
||||
ninja = 1.11.1.2
|
||||
num2words = 0.5.13
|
||||
numba = 0.60.0
|
||||
numpy = 1.26.4
|
||||
omegaconf = 2.3.0
|
||||
onnxruntime-gpu = 1.20.1
|
||||
openai-whisper = 20240930
|
||||
orjson = 3.10.12
|
||||
packaging = 24.1
|
||||
pandas = 2.2.3
|
||||
parler_tts = 0.2.1
|
||||
parso = 0.8.4
|
||||
pillow = 10.3.0
|
||||
pip = 24.2
|
||||
platformdirs = 4.3.6
|
||||
plotly = 5.24.1
|
||||
pooch = 1.8.2
|
||||
portalocker = 3.0.0
|
||||
praat-parselmouth = 0.4.5
|
||||
preshed = 3.0.9
|
||||
prompt_toolkit = 3.0.48
|
||||
propcache = 0.2.0
|
||||
protobuf = 4.25.5
|
||||
proto-plus = 1.25.0
|
||||
psutil = 6.1.0
|
||||
pure_eval = 0.2.3
|
||||
pyarrow = 18.1.0
|
||||
pyasn1 = 0.6.1
|
||||
pyasn1_modules = 0.4.1
|
||||
pycparser = 2.22
|
||||
pydantic = 2.10.1
|
||||
pydantic_core = 2.27.1
|
||||
pydub = 0.25.1
|
||||
Pygments = 2.18.0
|
||||
pyloudnorm = 0.1.1
|
||||
pynvml = 11.5.3
|
||||
pyparsing = 3.2.0
|
||||
pypinyin = 0.53.0
|
||||
PyQt6 = 6.7.1
|
||||
PyQt6-Qt6 = 6.7.3
|
||||
PyQt6_sip = 13.8.0
|
||||
pyreadline3 = 3.5.4
|
||||
pysbd = 0.3.4
|
||||
PySocks = 1.7.1
|
||||
pystoi = 0.4.1
|
||||
python-crfsuite = 0.9.11
|
||||
python-dateutil = 2.9.0.post0
|
||||
python-Levenshtein = 0.26.1
|
||||
python-multipart = 0.0.17
|
||||
pytz = 2024.2
|
||||
pywin32 = 308
|
||||
pyworld = 0.3.4
|
||||
PyYAML = 6.0.2
|
||||
py-cpuinfo = 9.0.0
|
||||
randomname = 0.2.1
|
||||
RapidFuzz = 3.10.1
|
||||
regex = 2024.11.6
|
||||
requests = 2.32.3
|
||||
resampy = 0.4.3
|
||||
rich = 13.9.4
|
||||
rotary-embedding-torch = 0.8.5
|
||||
rsa = 4.9
|
||||
ruff = 0.8.0
|
||||
s3transfer = 0.10.4
|
||||
sacrebleu = 2.4.3
|
||||
safetensors = 0.4.5
|
||||
scikit-learn = 1.5.2
|
||||
scipy = 1.14.1
|
||||
semantic-version = 2.10.0
|
||||
sentencepiece = 0.2.0
|
||||
sentry-sdk = 2.19.0
|
||||
setproctitle = 1.3.4
|
||||
setuptools = 75.1.0
|
||||
shellingham = 1.5.4
|
||||
six = 1.16.0
|
||||
smart-open = 7.0.5
|
||||
smmap = 5.0.1
|
||||
sniffio = 1.3.1
|
||||
sounddevice = 0.5.1
|
||||
soundfile = 0.12.1
|
||||
soxr = 0.5.0.post1
|
||||
spacy = 3.7.5
|
||||
spacy-legacy = 3.0.12
|
||||
spacy-loggers = 1.0.5
|
||||
srsly = 2.4.8
|
||||
stack-data = 0.6.3
|
||||
starlette = 0.38.6
|
||||
SudachiDict-core = 20241021
|
||||
SudachiPy = 0.6.9
|
||||
sympy = 1.13.2
|
||||
tabulate = 0.9.0
|
||||
tenacity = 9.0.0
|
||||
tensorboard = 2.18.0
|
||||
tensorboard-data-server = 0.7.2
|
||||
termcolor = 2.5.0
|
||||
thinc = 8.2.5
|
||||
threadpoolctl = 3.5.0
|
||||
tiktoken = 0.8.0
|
||||
tokenizers = 0.20.3
|
||||
tomli = 2.1.0
|
||||
tomlkit = 0.12.0
|
||||
torch = 2.2.1
|
||||
torchaudio = 2.2.1
|
||||
torchcrepe = 0.0.23
|
||||
torchdiffeq = 0.2.5
|
||||
torchvision = 0.17.1
|
||||
torch-stoi = 0.2.3
|
||||
tqdm = 4.67.1
|
||||
traitlets = 5.14.3
|
||||
transformers = 4.46.1
|
||||
transformers-stream-generator = 0.0.5
|
||||
typeguard = 4.4.1
|
||||
typer = 0.13.1
|
||||
typing_extensions = 4.12.2
|
||||
tzdata = 2024.2
|
||||
tzlocal = 5.2
|
||||
unidic-lite = 1.0.8
|
||||
urllib3 = 2.2.3
|
||||
uvicorn = 0.32.1
|
||||
vocos = 0.1.0
|
||||
wandb = 0.18.7
|
||||
wasabi = 1.1.3
|
||||
wcwidth = 0.2.13
|
||||
weasel = 0.4.1
|
||||
websockets = 12.0
|
||||
Werkzeug = 3.1.3
|
||||
wheel = 0.44.0
|
||||
win-inet-pton = 1.1.0
|
||||
word2number = 1.1
|
||||
wrapt = 1.17.0
|
||||
xxhash = 3.5.0
|
||||
x-transformers = 1.42.17
|
||||
yarl = 1.18.0
|
||||
zipp = 3.21.0
|
||||
|
||||
DeepSpeed Installation Requirements:
|
||||
OS : Windows
|
||||
Python : 3.11.10
|
||||
PyTorch: 2.2.1
|
||||
CUDA : 12.1
|
||||
|
||||
To install DeepSpeed, run the following command based on your environment:
|
||||
pip install deepspeed==<version> --no-cache-dir
|
||||
Ensure to choose the correct DeepSpeed version matching your environment.
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,382 +0,0 @@
|
||||
"""
|
||||
firstrun.py
|
||||
|
||||
This script handles the first-time setup for the Alltalk TTS system. It allows the user to download and configure
|
||||
the initial Text-to-Speech (TTS) engine and associated models. It provides automatic detection for Docker or Google
|
||||
Colab environments to simplify the setup process, as well as an interactive menu or command-line arguments for manual configuration.
|
||||
|
||||
Features:
|
||||
---------
|
||||
1. **Automatic Environment Detection**:
|
||||
- Detects if the script is running in a Docker container or Google Colab environment.
|
||||
- Automatically sets up the Piper TTS engine in these cases.
|
||||
|
||||
2. **Command-Line Arguments**:
|
||||
- Accepts a `--tts_model` argument to bypass the interactive menu and directly set up a specific TTS engine:
|
||||
- `piper`: Sets up the Piper TTS engine.
|
||||
- `vits`: Sets up the VITS TTS engine.
|
||||
- `xtts`: Sets up the XTTS TTS engine.
|
||||
- `none`: Skips model setup entirely.
|
||||
|
||||
3. **Interactive Menu**:
|
||||
- If no command-line argument is provided and the environment is not Docker/Colab, it presents an interactive
|
||||
menu for the user to select a TTS model.
|
||||
|
||||
4. **Configuration Management**:
|
||||
- Updates the Alltalk TTS configuration files to reflect the selected TTS engine and marks the initial setup as complete.
|
||||
|
||||
Usage:
|
||||
------
|
||||
Command-Line:
|
||||
python firstrun.py --tts_model [piper|vits|xtts|none]
|
||||
|
||||
Interactive Mode:
|
||||
python firstrun.py
|
||||
|
||||
In Docker/Colab:
|
||||
The script automatically selects and sets up the Piper TTS engine without user interaction.
|
||||
|
||||
Functions:
|
||||
----------
|
||||
- **is_running_in_colab**: Detects if the script is running in Google Colab.
|
||||
- **is_running_in_docker**: Detects if the script is running in a Docker container.
|
||||
- **download_file**: Downloads a file with a progress bar and retry logic.
|
||||
- **setup_piper**: Sets up the Piper TTS engine and downloads associated files.
|
||||
- **setup_vits**: Sets up the VITS TTS engine and downloads associated files.
|
||||
- **setup_xtts**: Sets up the XTTS TTS engine and downloads associated files.
|
||||
- **update_tts_engines**: Updates the configuration to reflect the selected TTS engine.
|
||||
- **set_firstrun_model_false**: Marks the initial setup as complete in the configuration.
|
||||
- **warning_message**: Displays post-setup warnings or tips for the user.
|
||||
|
||||
Notes:
|
||||
------
|
||||
- Ensure network access is available for downloading models during setup.
|
||||
- Configuration files are automatically updated and backed up if needed.
|
||||
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
import sys
|
||||
import zipfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from inputimeout import inputimeout, TimeoutOccurred
|
||||
|
||||
# Setting the module search path:
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.resolve()))
|
||||
from config import AlltalkTTSEnginesConfig, AlltalkConfig #pylint: disable=wrong-import-position
|
||||
|
||||
this_dir = Path(__file__).parent.resolve().parent.resolve().parent.resolve()
|
||||
|
||||
def is_running_in_colab():
|
||||
"""Test for google colab"""
|
||||
try:
|
||||
import google.colab
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
def is_running_in_docker():
|
||||
"""Test for google colab"""
|
||||
path = '/proc/self/cgroup'
|
||||
return os.path.exists('/.dockerenv') or (
|
||||
os.path.exists(path) and any('docker' in line for line in open(path, encoding='utf-8'))
|
||||
)
|
||||
|
||||
def download_file(url: str, dest_path: str, timeout: int = 30, retries: int = 3) -> bool:
|
||||
"""
|
||||
Download a file from a URL to a specified destination path with progress bar.
|
||||
|
||||
Args:
|
||||
url (str): URL of the file to download.
|
||||
dest_path (str): Destination path where the file will be saved.
|
||||
timeout (int, optional): Connection and read timeout in seconds. Defaults to 30.
|
||||
retries (int, optional): Number of retry attempts for failed downloads. Defaults to 3.
|
||||
|
||||
Returns:
|
||||
bool: True if the file was successfully downloaded, False otherwise.
|
||||
|
||||
Raises:
|
||||
ValueError: If the downloaded file size does not match the expected size.
|
||||
"""
|
||||
progress_bar = None
|
||||
for attempt in range(1, retries + 1):
|
||||
try:
|
||||
print(f"Attempting to download: {url} (Attempt {attempt}/{retries})")
|
||||
response = requests.get(url, stream=True, timeout=(timeout, timeout))
|
||||
response.raise_for_status()
|
||||
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
block_size = 1024 # 1 Kibibyte
|
||||
|
||||
# Initialize progress bar
|
||||
progress_bar = tqdm(total=total_size, unit='iB', unit_scale=True,
|
||||
desc=f"Downloading {Path(dest_path).name} (Attempt {attempt}/{retries})")
|
||||
Path(dest_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(dest_path, 'wb') as dwn_file:
|
||||
for data in response.iter_content(block_size):
|
||||
if data:
|
||||
dwn_file.write(data)
|
||||
progress_bar.update(len(data))
|
||||
|
||||
if progress_bar:
|
||||
progress_bar.close()
|
||||
|
||||
# Verify file size
|
||||
if progress_bar.n != total_size and total_size > 0:
|
||||
raise ValueError(
|
||||
f"Downloaded size ({progress_bar.n} bytes) does not match expected size ({total_size} bytes)."
|
||||
)
|
||||
|
||||
print(f"Download completed: {dest_path}")
|
||||
return True
|
||||
|
||||
except requests.Timeout:
|
||||
print(f"Timeout error during download: {url}")
|
||||
except requests.ConnectionError:
|
||||
print(f"Connection error during download: {url}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"HTTP error during download: {url}. Details: {str(e)}")
|
||||
except ValueError as e:
|
||||
print(f"File validation error: {str(e)}")
|
||||
if Path(dest_path).exists():
|
||||
Path(dest_path).unlink() # Remove incomplete file
|
||||
break # Stop retrying on file validation errors
|
||||
except Exception as e:
|
||||
print(f"Unexpected error during download: {str(e)}")
|
||||
break # Stop retrying on unexpected errors
|
||||
finally:
|
||||
if progress_bar:
|
||||
progress_bar.close()
|
||||
|
||||
if Path(dest_path).exists():
|
||||
Path(dest_path).unlink() # Remove incomplete file
|
||||
|
||||
if attempt < retries:
|
||||
print(f"Retrying in 5 seconds... (Attempt {attempt + 1}/{retries})")
|
||||
time.sleep(5)
|
||||
else:
|
||||
print(f"Exhausted all retries for {url}.")
|
||||
|
||||
# Return False if all attempts fail
|
||||
return False
|
||||
|
||||
def setup_piper():
|
||||
"""Download base piper files"""
|
||||
os.makedirs(this_dir / 'models/piper', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
download_file("https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx?download=true",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx")
|
||||
download_file("https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx.json?download=true.json",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx.json")
|
||||
|
||||
def setup_vits():
|
||||
"""Download base vits files"""
|
||||
os.makedirs(this_dir / 'models/vits', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
zip_path = this_dir / 'models/vits/vits.zip'
|
||||
download_file("https://coqui.gateway.scarf.sh/v0.6.1_models/tts_models--en--vctk--vits.zip", zip_path)
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(this_dir / 'models/vits')
|
||||
os.remove(zip_path)
|
||||
|
||||
def setup_xtts():
|
||||
"""Download base xtts files"""
|
||||
os.makedirs(this_dir / 'models/xtts/xttsv2_2.0.3', exist_ok=True)
|
||||
base_url = "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/"
|
||||
files = [
|
||||
"LICENSE.txt",
|
||||
"README.md",
|
||||
"config.json",
|
||||
"model.pth",
|
||||
"dvae.pth",
|
||||
"mel_stats.pth",
|
||||
"speakers_xtts.pth",
|
||||
"vocab.json"
|
||||
]
|
||||
for each_file in files:
|
||||
download_file(base_url + each_file + "?download=true", this_dir / f"models/xtts/xttsv2_2.0.3/{each_file}")
|
||||
|
||||
def update_tts_engines(engine):
|
||||
"""Set engine to users choice that matches the download"""
|
||||
try:
|
||||
config_instance = AlltalkTTSEnginesConfig.get_instance()
|
||||
config_instance.change_engine(engine)
|
||||
config_instance.save()
|
||||
except Exception as e:
|
||||
print(f"[{branding}TTS] Error updating TTS engine configuration: {str(e)}")
|
||||
|
||||
def set_firstrun_model_false():
|
||||
"""
|
||||
Marks the first-run setup as complete in the Alltalk configuration.
|
||||
|
||||
This function updates the `firstrun_model` flag in the configuration file to `False`,
|
||||
indicating that the initial setup has been completed. It attempts to save the updated
|
||||
configuration and verifies the changes, retrying with a direct file write if necessary.
|
||||
"""
|
||||
try:
|
||||
# Get a fresh instance of the config
|
||||
config_fr = AlltalkConfig.get_instance()
|
||||
config_fr.firstrun_model = False
|
||||
|
||||
# Force a flush to disk immediately
|
||||
config_fr.save()
|
||||
|
||||
# Verify the save worked
|
||||
config_path = AlltalkConfig.default_config_path()
|
||||
with open(config_path, 'r', encoding="utf-8") as f:
|
||||
saved_config = json.load(f)
|
||||
if saved_config.get('firstrun_model', True):
|
||||
print(f"[{branding}TTS] Warning: Failed to save firstrun_model=False")
|
||||
# Try one more time with direct file write
|
||||
saved_config['firstrun_model'] = False
|
||||
with open(config_path, 'w', encoding="utf-8") as f:
|
||||
json.dump(saved_config, f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"[{branding}TTS] Error saving firstrun configuration: {str(e)}")
|
||||
|
||||
def warning_message():
|
||||
"""AllTalk V1 Warning message re updating"""
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[93mIf you have you have UPGRADED from v1 ensure you have re-installed\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mthe requirements. Otherwise you will get failures and errors!\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mOn Linux ignore the \033[0m'sparse_attn requires a torch version' \033[93mand\033[0m")
|
||||
print(f"[{branding}TTS] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Load confignew.json (might be version 1 or 2):
|
||||
with open(AlltalkConfig.default_config_path(), 'r', encoding="utf-8") as file:
|
||||
config_json = json.load(file)
|
||||
|
||||
branding = config_json['branding']
|
||||
|
||||
# Check if the config file is version 1
|
||||
if "ip_address" in config_json:
|
||||
print(f"[{branding}TTS] Detected version 1 configuration file.")
|
||||
print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
|
||||
|
||||
# Backup the old configuration file
|
||||
backup_path = AlltalkConfig.default_config_path() + ".backup"
|
||||
shutil.copyfile(AlltalkConfig.default_config_path(), backup_path)
|
||||
|
||||
# Copy the new configuration template to replace the old config file
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
shutil.copyfile(new_config_template_path, AlltalkConfig.default_config_path())
|
||||
|
||||
print(f"[{branding}TTS] Configuration file upgraded successfully.")
|
||||
|
||||
config = AlltalkConfig.get_instance()
|
||||
branding = config.branding
|
||||
# Argument parser setup
|
||||
parser = argparse.ArgumentParser(description="TTS Setup Script")
|
||||
parser.add_argument('--tts_model', type=str, choices=['piper', 'vits', 'xtts', 'none'],
|
||||
help="Specify TTS model to set up (piper, vits, xtts, or none)")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Check if firstrun_model is true
|
||||
if config.firstrun_model:
|
||||
# Handle command-line argument for tts_model
|
||||
if args.tts_model:
|
||||
if args.tts_model == 'piper':
|
||||
setup_piper()
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
elif args.tts_model == 'vits':
|
||||
setup_vits()
|
||||
update_tts_engines('vits')
|
||||
set_firstrun_model_false()
|
||||
elif args.tts_model == 'xtts':
|
||||
setup_xtts()
|
||||
update_tts_engines('xtts')
|
||||
set_firstrun_model_false()
|
||||
elif args.tts_model == 'none':
|
||||
print(f"[{branding}TTS] No TTS model setup requested.")
|
||||
print(f"[{branding}TTS] Setup completed for {args.tts_model}. Exiting.")
|
||||
sys.exit()
|
||||
|
||||
# Check for Colab or Docker environment first
|
||||
if is_running_in_colab() or is_running_in_docker():
|
||||
print(f"[{branding}TTS] Detected Colab/Docker environment - automatically selecting Piper")
|
||||
setup_piper()
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
warning_message()
|
||||
sys.exit()
|
||||
|
||||
# Present the menu if no argument is passed and not in Colab/Docker
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first-time startup.. Please download a start TTS model. Other TTS engines\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mand TTS models can be downloaded/managed in the Gradio Interface `TTS Engines Settings`\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mtab after initial setup.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# List of available models
|
||||
models = [
|
||||
{"name": "piper", "model": "piper"},
|
||||
{"name": "vits", "model": "tts_models--en--vctk--vits"},
|
||||
{"name": "xtts", "model": "xttsv2_2.0.3"},
|
||||
]
|
||||
|
||||
# Display models to the user
|
||||
print(f"[{branding}TTS] \033[94mAvailable First Time Start-up models:\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
for idx, model in enumerate(models):
|
||||
print(f"[{branding}TTS] \033[93m{idx + 1}. \033[94m{model['name']} - {model['model']}\033[0m")
|
||||
print(f"[{branding}TTS] \033[93m{len(models) + 1}.\033[94m I have my own models already\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[94mIn \033[91m60 seconds\033[0m \033[94ma Piper model will be \033[91mdownloaded automatically.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Auto-select model after 60 seconds
|
||||
selected_model = models[0] # Default to the first model (piper)
|
||||
try:
|
||||
user_choice = inputimeout(prompt=f"[{branding}TTS] \033[92mEnter your choice 1-4: \033[0m ", timeout=60)
|
||||
except TimeoutOccurred:
|
||||
user_choice = None
|
||||
|
||||
if user_choice is None:
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] No input received. Proceeding with the default model (piper).")
|
||||
elif user_choice.lower() == 'own' or (user_choice.isdigit() and int(user_choice) == len(models) + 1):
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] Please use the Gradio interface TTS Engine Settings > [Engine Name] > Model Download")
|
||||
print(f"[{branding}TTS] To download models for your selected TTS Engine. Or use the [Engine Name] help sections")
|
||||
print(f"[{branding}TTS] for instructions on using your own TTS models.")
|
||||
print(f"[{branding}TTS]")
|
||||
os.makedirs('models/piper', exist_ok=True)
|
||||
os.makedirs('models/vits', exist_ok=True)
|
||||
os.makedirs('models/xtts/', exist_ok=True)
|
||||
os.makedirs('models/f5-tts/', exist_ok=True)
|
||||
os.makedirs('models/rvc_voices/', exist_ok=True)
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
warning_message()
|
||||
exit()
|
||||
|
||||
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
|
||||
selected_model = models[int(user_choice) - 1]
|
||||
warning_message()
|
||||
|
||||
if user_choice is None or user_choice.lower() != 'own':
|
||||
if selected_model['name'] == 'piper':
|
||||
setup_piper()
|
||||
update_tts_engines('piper')
|
||||
elif selected_model['name'] == 'vits':
|
||||
setup_vits()
|
||||
update_tts_engines('vits')
|
||||
elif selected_model['name'] == 'xtts':
|
||||
setup_xtts()
|
||||
update_tts_engines('xtts')
|
||||
|
||||
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
|
||||
# Set firstrun_model to false
|
||||
set_firstrun_model_false()
|
||||
warning_message()
|
||||
sys.exit()
|
||||
else:
|
||||
sys.exit()
|
||||
@@ -1,287 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import zipfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from inputimeout import inputimeout, TimeoutOccurred
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, List, Any
|
||||
|
||||
# Setting the module search path:
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.resolve()))
|
||||
|
||||
from config import AlltalkTTSEnginesConfig, AlltalkConfig
|
||||
|
||||
this_dir = Path(__file__).parent.resolve().parent.resolve().parent.resolve()
|
||||
|
||||
def is_running_in_colab() -> bool:
|
||||
"""Check if the script is running in Google Colab."""
|
||||
try:
|
||||
import google.colab
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
def is_running_in_docker() -> bool:
|
||||
"""Check if the script is running in a Docker container."""
|
||||
return os.path.exists('/.dockerenv') or (
|
||||
os.path.exists('/proc/self/cgroup') and
|
||||
any('docker' in line for line in open('/proc/self/cgroup'))
|
||||
)
|
||||
|
||||
def download_file(url: str, dest_path: str, timeout: int = 30) -> bool:
|
||||
"""
|
||||
Download a file from a URL with progress bar and error handling.
|
||||
|
||||
Args:
|
||||
url: URL to download from
|
||||
dest_path: Where to save the file
|
||||
timeout: Connection timeout in seconds
|
||||
|
||||
Returns:
|
||||
bool: True if download was successful
|
||||
"""
|
||||
progress_bar = None
|
||||
try:
|
||||
response = requests.get(url, stream=True, timeout=timeout)
|
||||
response.raise_for_status()
|
||||
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
block_size = 1024
|
||||
|
||||
progress_bar = tqdm(total=total_size, unit='iB', unit_scale=True,
|
||||
desc=f"Downloading {Path(dest_path).name}")
|
||||
|
||||
Path(dest_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(dest_path, 'wb') as file:
|
||||
for data in response.iter_content(block_size):
|
||||
if data:
|
||||
file.write(data)
|
||||
progress_bar.update(len(data))
|
||||
|
||||
if progress_bar.n != total_size and total_size > 0:
|
||||
raise requests.exceptions.RequestException(
|
||||
f"Incomplete download: {progress_bar.n}/{total_size} bytes"
|
||||
)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error downloading {url}: {str(e)}")
|
||||
if Path(dest_path).exists():
|
||||
Path(dest_path).unlink()
|
||||
return False
|
||||
|
||||
finally:
|
||||
if progress_bar:
|
||||
progress_bar.close()
|
||||
|
||||
def setup_model(model_name: str) -> bool:
|
||||
"""
|
||||
Set up a specific TTS model.
|
||||
|
||||
Args:
|
||||
model_name: Name of the model to setup ('piper', 'vits', or 'xtts')
|
||||
|
||||
Returns:
|
||||
bool: True if setup was successful
|
||||
"""
|
||||
try:
|
||||
if model_name == "piper":
|
||||
os.makedirs(this_dir / 'models/piper', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
return all([
|
||||
download_file(
|
||||
"https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx?download=true",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx"
|
||||
),
|
||||
download_file(
|
||||
"https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx.json?download=true.json",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx.json"
|
||||
)
|
||||
])
|
||||
|
||||
elif model_name == "vits":
|
||||
os.makedirs(this_dir / 'models/vits', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
zip_path = this_dir / 'models/vits/vits.zip'
|
||||
|
||||
if not download_file(
|
||||
"https://coqui.gateway.scarf.sh/v0.6.1_models/tts_models--en--vctk--vits.zip",
|
||||
zip_path
|
||||
):
|
||||
return False
|
||||
|
||||
try:
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(this_dir / 'models/vits')
|
||||
os.remove(zip_path)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error extracting VITS model: {str(e)}")
|
||||
return False
|
||||
|
||||
elif model_name == "xtts":
|
||||
os.makedirs(this_dir / 'models/xtts/xttsv2_2.0.3', exist_ok=True)
|
||||
base_url = "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/"
|
||||
files = [
|
||||
"LICENSE.txt", "README.md", "config.json", "model.pth",
|
||||
"dvae.pth", "mel_stats.pth", "speakers_xtts.pth", "vocab.json"
|
||||
]
|
||||
return all(
|
||||
download_file(
|
||||
base_url + file + "?download=true",
|
||||
this_dir / f"models/xtts/xttsv2_2.0.3/{file}"
|
||||
) for file in files
|
||||
)
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error setting up {model_name}: {str(e)}")
|
||||
return False
|
||||
|
||||
def update_tts_engines(engine: str) -> bool:
|
||||
"""Update TTS engine configuration with error handling."""
|
||||
try:
|
||||
AlltalkTTSEnginesConfig.get_instance().change_engine(engine).save()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error updating TTS engine configuration: {str(e)}")
|
||||
return False
|
||||
|
||||
def set_firstrun_model_false() -> bool:
|
||||
"""Set firstrun_model to false with verification."""
|
||||
try:
|
||||
# Get fresh config instance and update
|
||||
config = AlltalkConfig.get_instance()
|
||||
config.firstrun_model = False
|
||||
config.save()
|
||||
|
||||
# Verify the save worked
|
||||
config_path = AlltalkConfig.default_config_path()
|
||||
with open(config_path, 'r') as f:
|
||||
saved_config = json.load(f)
|
||||
if saved_config.get('firstrun_model', True):
|
||||
print(f"Warning: Failed to save firstrun_model=False")
|
||||
# Try direct file write as fallback
|
||||
saved_config['firstrun_model'] = False
|
||||
with open(config_path, 'w') as f:
|
||||
json.dump(saved_config, f, indent=2)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error saving firstrun configuration: {str(e)}")
|
||||
return False
|
||||
|
||||
def warning_message(branding: str):
|
||||
"""Display warning messages about installation and compatibility."""
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[93mIf you have UPGRADED from v1 ensure you have re-installed\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mthe requirements. Otherwise you will get failures and errors!\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mOn Linux ignore the \033[0m'sparse_attn requires a torch version' \033[93mand\033[0m")
|
||||
print(f"[{branding}TTS] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
def main():
|
||||
"""Main execution function."""
|
||||
try:
|
||||
# Load configuration
|
||||
with open(AlltalkConfig.default_config_path(), 'r') as file:
|
||||
config_json = json.load(file)
|
||||
|
||||
branding = config_json['branding']
|
||||
|
||||
# Handle version 1 config upgrade
|
||||
if "ip_address" in config_json:
|
||||
print(f"[{branding}TTS] Detected version 1 configuration file.")
|
||||
print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
|
||||
|
||||
backup_path = AlltalkConfig.default_config_path() + ".backup"
|
||||
shutil.copyfile(AlltalkConfig.default_config_path(), backup_path)
|
||||
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
shutil.copyfile(new_config_template_path, AlltalkConfig.default_config_path())
|
||||
|
||||
print(f"[{branding}TTS] Configuration file upgraded successfully.")
|
||||
|
||||
config = AlltalkConfig.get_instance()
|
||||
branding = config.branding
|
||||
|
||||
if not config.firstrun_model:
|
||||
return
|
||||
|
||||
# Auto-select Piper for Colab/Docker
|
||||
if is_running_in_colab() or is_running_in_docker():
|
||||
print(f"[{branding}TTS] Detected Colab/Docker environment - automatically selecting Piper")
|
||||
if setup_model('piper'):
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
warning_message(branding)
|
||||
return
|
||||
|
||||
# Normal interactive setup
|
||||
models = [
|
||||
{"name": "piper", "model": "piper"},
|
||||
{"name": "vits", "model": "tts_models--en--vctk--vits"},
|
||||
{"name": "xtts", "model": "xttsv2_2.0.3"},
|
||||
]
|
||||
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first time startup. Please download a start TTS model.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[94mAvailable First Time Start-up models:\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
for idx, model in enumerate(models):
|
||||
print(f"[{branding}TTS] \033[93m{idx + 1}. \033[94m{model['name']} - {model['model']}\033[0m")
|
||||
print(f"[{branding}TTS] \033[93m{len(models) + 1}.\033[94m I have my own models already\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[94mIn \033[91m60 seconds\033[0m \033[94ma Piper model will be \033[91mdownloaded automatically.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
try:
|
||||
user_choice = inputimeout(
|
||||
prompt=f"[{branding}TTS] \033[92mEnter your choice 1-4: \033[0m ",
|
||||
timeout=60
|
||||
)
|
||||
except TimeoutOccurred:
|
||||
user_choice = None
|
||||
|
||||
if user_choice is None:
|
||||
print(f"[{branding}TTS] No input received. Proceeding with the default model (piper).")
|
||||
selected_model = models[0]
|
||||
elif user_choice.lower() == 'own' or (user_choice.isdigit() and int(user_choice) == len(models) + 1):
|
||||
print(f"[{branding}TTS] If you have your own XTTS models, please move them into the")
|
||||
print(f"[{branding}TTS] \033[93m/models/xtts/\033[0m folder")
|
||||
|
||||
os.makedirs('models/piper', exist_ok=True)
|
||||
os.makedirs('models/vits', exist_ok=True)
|
||||
os.makedirs('models/xtts/', exist_ok=True)
|
||||
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
warning_message(branding)
|
||||
return
|
||||
elif user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
|
||||
selected_model = models[int(user_choice) - 1]
|
||||
warning_message(branding)
|
||||
else:
|
||||
print(f"[{branding}TTS] Invalid choice. Proceeding with the default model (piper).")
|
||||
selected_model = models[0]
|
||||
|
||||
if setup_model(selected_model['name']):
|
||||
update_tts_engines(selected_model['name'])
|
||||
set_firstrun_model_false()
|
||||
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
|
||||
warning_message(branding)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,92 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get the conda environment path
|
||||
env_path="${CONDA_DEFAULT_ENV}/lib"
|
||||
|
||||
# List of broken symlinks
|
||||
declare -A symlinks=(
|
||||
["libcufile.so"]="libcufile.so"
|
||||
["libcufile_rdma.so"]="libcufile_rdma.so"
|
||||
["libcudart.so"]="libcudart.so"
|
||||
["libnvjpeg.so"]="libnvjpeg.so"
|
||||
["libcurand.so"]="libcurand.so"
|
||||
["libnvJitLink.so"]="libnvJitLink.so"
|
||||
["libnvrtc-builtins.so"]="libnvrtc-builtins.so"
|
||||
["libnvrtc.so"]="libnvrtc.so"
|
||||
)
|
||||
|
||||
# Function to test for broken symlinks
|
||||
test_broken_symlinks() {
|
||||
echo "Testing for broken symlinks..."
|
||||
broken_found=false
|
||||
for link in "${!symlinks[@]}"; do
|
||||
if [ -L "$env_path/$link" ] && [ ! -e "$env_path/$link" ]; then
|
||||
echo "Broken symlink found: $env_path/$link"
|
||||
broken_found=true
|
||||
fi
|
||||
done
|
||||
if [ "$broken_found" = false ]; then
|
||||
echo "No broken symlinks found."
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to fix broken symlinks
|
||||
fix_broken_symlinks() {
|
||||
echo "Fixing broken symlinks..."
|
||||
for link in "${!symlinks[@]}"; do
|
||||
if [ -L "$env_path/$link" ] && [ ! -e "$env_path/$link" ]; then
|
||||
echo "Removing broken link: $env_path/$link"
|
||||
rm "$env_path/$link"
|
||||
|
||||
# Find all possible target files
|
||||
target_files=($(find "$env_path" -name "${symlinks[$link]}*"))
|
||||
|
||||
if [ ${#target_files[@]} -gt 0 ]; then
|
||||
echo "Select a target file for $link:"
|
||||
for i in "${!target_files[@]}"; do
|
||||
echo "$((i+1)). ${target_files[$i]}"
|
||||
done
|
||||
|
||||
read -p "Enter the number of the target file to use: " choice
|
||||
choice=$((choice-1))
|
||||
|
||||
if [[ $choice -ge 0 && $choice -lt ${#target_files[@]} ]]; then
|
||||
target="${target_files[$choice]}"
|
||||
echo "Creating new symlink: $env_path/$link -> $target"
|
||||
ln -s "$target" "$env_path/$link"
|
||||
else
|
||||
echo "Invalid choice, skipping $link."
|
||||
fi
|
||||
else
|
||||
echo "No target files found for $link."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "Verification of symbolic links:"
|
||||
ls -l $env_path | grep -E "libcufile.so|libcudart.so|libcufile_rdma.so|libnvjpeg.so|libcurand.so|libnvJitLink.so|libnvrtc-builtins.so|libnvrtc.so"
|
||||
}
|
||||
|
||||
# Menu
|
||||
while true; do
|
||||
echo "Select an option:"
|
||||
echo "1. Test for broken symlinks"
|
||||
echo "2. Fix broken symlinks"
|
||||
echo "3. Exit"
|
||||
read -p "Enter your choice [1-3]: " choice
|
||||
case $choice in
|
||||
1)
|
||||
test_broken_symlinks
|
||||
;;
|
||||
2)
|
||||
fix_broken_symlinks
|
||||
;;
|
||||
3)
|
||||
echo "Exiting."
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Invalid choice. Please select 1, 2, or 3."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"English": "en",
|
||||
"French": "fr",
|
||||
"German": "de",
|
||||
"Hindi": "hi",
|
||||
"Hungarian": "hu",
|
||||
"Italian": "it",
|
||||
"Japanese": "ja",
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
find {addpathheretoscan}/alltalk_environment/env/lib -xtype l
|
||||
|
||||
here are the list on Cuda-Toolkit 12.1, others vary
|
||||
|
||||
.../alltalk_environment/env/lib/libcufile.so
|
||||
.../alltalk_environment/env/lib/libcudart.so
|
||||
.../alltalk_environment/env/lib/libcufile_rdma.so
|
||||
.../alltalk_environment/env/lib/libnvjpeg.so
|
||||
.../alltalk_environment/env/lib/libcurand.so
|
||||
.../alltalk_environment/env/lib/libnvJitLink.so
|
||||
.../alltalk_environment/env/lib/libnvrtc-builtins.so
|
||||
.../alltalk_environment/env/lib/libnvrtc.so
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,54 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
def merge_vocabularies(base_vocab_path, new_vocab_path, output_path):
|
||||
# Load the base model's vocab.json
|
||||
with open(base_vocab_path, 'r') as f:
|
||||
base_data = json.load(f)
|
||||
|
||||
# Load the new bpe_tokenizer.json
|
||||
with open(new_vocab_path, 'r') as f:
|
||||
new_data = json.load(f)
|
||||
|
||||
# Extract the vocabularies
|
||||
base_vocab = base_data['model']['vocab']
|
||||
new_vocab = new_data['model']['vocab']
|
||||
|
||||
# Find the maximum value in the base vocabulary
|
||||
max_value = max(base_vocab.values())
|
||||
|
||||
# Merge the vocabularies
|
||||
for key, value in new_vocab.items():
|
||||
if key not in base_vocab:
|
||||
max_value += 1
|
||||
base_vocab[key] = max_value
|
||||
|
||||
# Update the base data with the merged vocabulary
|
||||
base_data['model']['vocab'] = base_vocab
|
||||
|
||||
# Extract the merges
|
||||
base_merges = base_data['model']['merges']
|
||||
new_merges = new_data['model']['merges']
|
||||
|
||||
# Merge the merges
|
||||
merged_merges = base_merges.copy()
|
||||
for merge in new_merges:
|
||||
if merge not in merged_merges:
|
||||
merged_merges.append(merge)
|
||||
|
||||
# Update the base data with the merged merges
|
||||
base_data['model']['merges'] = merged_merges
|
||||
|
||||
# Write the merged vocabulary and merges to the output file
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump(base_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"Merged vocabulary and merges saved to {output_path}")
|
||||
|
||||
# Define file paths
|
||||
base_vocab_path = "/alltalk_tts/models/xtts/xttsv2_2.0.2/originalvocab.json" # base model vocab.json path (2.0.2)
|
||||
new_vocab_path = "/alltalk_tts/expanded_models/tortoise_tokenizer2xttsv2.json" # path to the custom dataset vocab.json
|
||||
output_path = "/alltalk_tts/expanded_models/combined_vocab.json" # location for combined vocab.json
|
||||
|
||||
# Merge the vocabularies
|
||||
merge_vocabularies(base_vocab_path, new_vocab_path, output_path)
|
||||
@@ -1,60 +0,0 @@
|
||||
# Credit Jarod Mica https://github.com/JarodMica/tortoise_dataset_tools/blob/master/bpe_tokenizer_tools/train_bpe_tokenizer.py
|
||||
# provide a cleaned txt file with only the transcription. Youll get back out the datasets vocab.json
|
||||
|
||||
from tokenizers import Tokenizer
|
||||
from tokenizers.models import BPE
|
||||
from tokenizers.trainers import BpeTrainer
|
||||
from tokenizers.pre_tokenizers import Whitespace
|
||||
from tkinter import Tk, filedialog
|
||||
import json
|
||||
import re
|
||||
|
||||
def clean_text(input_file_path, output_file_path):
|
||||
# Define the pattern to match numbers, specific symbols, and new lines
|
||||
# add \d to match any digit, and | is used to specify alternatives
|
||||
pattern = r'|�|«|\$|\n'
|
||||
|
||||
with open(input_file_path, 'r', encoding='utf-8') as input_file:
|
||||
text = input_file.read()
|
||||
cleaned_text = re.sub(pattern, '', text)
|
||||
|
||||
with open(output_file_path, 'w', encoding='utf-8') as output_file:
|
||||
output_file.write(cleaned_text)
|
||||
|
||||
def train_tokenizer(input_path, tokenizer_path, language, special_tokens=["[STOP]", "[UNK]", "[SPACE]" ], vocab_size=256):
|
||||
# Initialize a tokenizer with the BPE model
|
||||
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
|
||||
# Use a basic whitespace pre-tokenizer
|
||||
tokenizer.pre_tokenizer = Whitespace()
|
||||
|
||||
# trainer = BpeTrainer(special_tokens=["[STOP]", "[UNK]", "[SPACE]", "0","1","2","3","4","5","6","7","8","9",], vocab_size=256)
|
||||
trainer = BpeTrainer(special_tokens=special_tokens, vocab_size=vocab_size)
|
||||
|
||||
|
||||
clean_text(input_path, input_path)
|
||||
tokenizer.train([input_path], trainer)
|
||||
|
||||
tokenizer.save(tokenizer_path)
|
||||
|
||||
with open(tokenizer_path, 'r', encoding='utf-8') as f:
|
||||
tokenizer_json = json.load(f)
|
||||
|
||||
# Add language to tokenizer
|
||||
tokenizer_json['model']['language'] = language
|
||||
|
||||
with open(tokenizer_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(tokenizer_json, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def choose_file():
|
||||
root = Tk()
|
||||
root.withdraw()
|
||||
file = filedialog.askopenfilename()
|
||||
root.destroy()
|
||||
return file
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_path = choose_file()
|
||||
tokenizer_path = "/alltalk_tts/expanded_models/tortoise_tokenizer2xttsv2.json" # define path to put the newly create vocab.json
|
||||
special_tokens = ["[STOP]", "[UNK]", "[SPACE]"]
|
||||
vocab_size = 256 # model is stuck at this size
|
||||
train_tokenizer(input_path, tokenizer_path, language='multi', special_tokens=special_tokens, vocab_size=vocab_size)
|
||||
@@ -1,121 +0,0 @@
|
||||
"""
|
||||
This script does not have any specific alltalk integration yet. So we are manually entering paths and it works as a standalone.
|
||||
|
||||
The script does the following:
|
||||
- Expands the embedding layer of the base XTTSv2 model according to the user created/trained bpe_tokenizer-vocab.json and the base model vocab.json.
|
||||
Set variable paths with the base config and base model.pth.
|
||||
Set the new tokenizer/vocab bpe_tokenizer-vocab.json location.
|
||||
The new model will be saved at \expanded_models\expanded_model.pth
|
||||
|
||||
Once this is done the new expanded model must be swapped in for the base model.pth then combined with the dvae.pth, vocab.json(bpe_tokenizer-vocab.json), base model config.json,
|
||||
base model speaker_xtts.pth and base model vocoder.json.
|
||||
|
||||
|
||||
I left some print debug statements in the script, they may be nice for the user to see during the process.
|
||||
|
||||
"""
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import json
|
||||
from TTS.tts.models.xtts import Xtts
|
||||
from TTS.tts.layers.xtts.trainer.gpt_trainer import GPTTrainerConfig
|
||||
from TTS.tts.layers.xtts.tokenizer import VoiceBpeTokenizer
|
||||
|
||||
config_path = "/alltalk_tts/models/xtts/xttsv2_2.0.3/config.json" # Path to the base model config.json
|
||||
pretrained_model_path = "/alltalk_tts/models/xtts/xttsv2_2.0.3/model.pth" # Path to the base model.pth
|
||||
new_tokenizer_path = "/expanded_model/expanded_vocab.json" # Path to the new combined expanded_vocab.json
|
||||
expanded_model_path = "/expanded_model/expanded_model.pth" # Path to where you want the new expanded_model.pth
|
||||
|
||||
|
||||
# Open and load the configuration file
|
||||
with open(config_path, "r") as f:
|
||||
config_dict = json.load(f)
|
||||
|
||||
# Create a GPTTrainerConfig object and populate it with the loaded configuration
|
||||
config = GPTTrainerConfig()
|
||||
config.from_dict(data=config_dict)
|
||||
|
||||
# Function to get the vocabulary size from a tokenizer file
|
||||
def get_vocab_size(tokenizer_path):
|
||||
tokenizer = VoiceBpeTokenizer(vocab_file=tokenizer_path)
|
||||
return len(tokenizer.tokenizer.get_vocab())
|
||||
|
||||
# Function to adjust the pretrained model with a new tokenizer
|
||||
def adjust_pretrained_model(
|
||||
pretrained_model_path, adjusted_model_path, new_tokenizer_path):
|
||||
state_dict = torch.load(pretrained_model_path)
|
||||
pretrained_state_dict = state_dict["model"]
|
||||
model = Xtts(config)
|
||||
|
||||
# Load the pretrained state dictionary into the new model
|
||||
missing_keys, unexpected_keys = model.load_state_dict(pretrained_state_dict, strict=False)
|
||||
if missing_keys:
|
||||
print(f"Missing keys: {missing_keys}")
|
||||
if unexpected_keys:
|
||||
print(f"Unexpected keys: {unexpected_keys}")
|
||||
print("Pretrained model loaded successfully.")
|
||||
|
||||
# Create a new tokenizer with the new vocabulary
|
||||
new_tokenizer = VoiceBpeTokenizer(vocab_file=new_tokenizer_path)
|
||||
|
||||
# Get the old and new vocabulary sizes, and the embedding dimension
|
||||
old_vocab_size = model.gpt.text_embedding.num_embeddings
|
||||
new_vocab_size = len(new_tokenizer.tokenizer.get_vocab())
|
||||
embedding_dim = model.gpt.text_embedding.embedding_dim
|
||||
|
||||
print(f"Old vocab size: {old_vocab_size}")
|
||||
print(f"New vocab size: {new_vocab_size}")
|
||||
print(f"Embedding dimension: {embedding_dim}")
|
||||
|
||||
# Adjust the embedding layer with the new vocabulary size
|
||||
adjust_embedding_layer(model, new_vocab_size, adjusted_model_path)
|
||||
|
||||
# Freeze all parameters except the position embeddings
|
||||
freeze_except_position_embeddings(model)
|
||||
|
||||
# Function to adjust the embedding layer for the new vocabulary size
|
||||
def adjust_embedding_layer(model, new_vocab_size, adjusted_model_path):
|
||||
old_vocab_size = model.gpt.text_embedding.num_embeddings
|
||||
embedding_dim = model.gpt.text_embedding.embedding_dim
|
||||
|
||||
# Create new embedding and linear layers with the new vocabulary size
|
||||
new_text_embedding = nn.Embedding(new_vocab_size, embedding_dim)
|
||||
new_text_head = nn.Linear(embedding_dim, new_vocab_size)
|
||||
|
||||
# Copy weights from the old embedding layer to the new one
|
||||
if new_vocab_size > old_vocab_size:
|
||||
new_text_embedding.weight.data[:old_vocab_size] = model.gpt.text_embedding.weight.data
|
||||
new_text_head.weight.data[:old_vocab_size] = model.gpt.text_head.weight.data
|
||||
new_text_head.bias.data[:old_vocab_size] = model.gpt.text_head.bias.data
|
||||
|
||||
new_text_embedding.weight.data[old_vocab_size:].normal_(mean=0.0, std=0.02)
|
||||
new_text_head.weight.data[old_vocab_size:].normal_(mean=0.0, std=0.02)
|
||||
new_text_head.bias.data[old_vocab_size:].normal_(mean=0.0, std=0.02)
|
||||
else:
|
||||
new_text_embedding.weight.data = model.gpt.text_embedding.weight.data[:new_vocab_size]
|
||||
new_text_head.weight.data = model.gpt.text_head.weight.data[:new_vocab_size]
|
||||
new_text_head.bias.data = model.gpt.text_head.bias.data[:new_vocab_size]
|
||||
|
||||
model.gpt.text_embedding = new_text_embedding
|
||||
model.gpt.text_head = new_text_head
|
||||
|
||||
checkpoint = {"model": model.state_dict()}
|
||||
torch.save(checkpoint, adjusted_model_path)
|
||||
print(f"Adjusted model saved to {adjusted_model_path}")
|
||||
|
||||
# Function to freeze all parameters except the position embeddings
|
||||
def freeze_except_position_embeddings(model):
|
||||
for param in model.parameters():
|
||||
param.requires_grad = False
|
||||
|
||||
for name, param in model.named_parameters():
|
||||
if 'pos_embedding' in name:
|
||||
param.requires_grad = True
|
||||
|
||||
# Verify which parameters are frozen and which are not, comment this out if you dont want to debug. You should see only two true values
|
||||
for name, param in model.named_parameters():
|
||||
print(f"{name}: requires_grad={param.requires_grad}")
|
||||
|
||||
# Expand the pretrained model with the new tokenizer
|
||||
adjust_pretrained_model(pretrained_model_path, expanded_model_path, new_tokenizer_path)
|
||||
@@ -1,26 +0,0 @@
|
||||
# Simple script to remove LJ Speech formatting for the tokenizer
|
||||
# Combine metadata_train and metadata_eval.csv into a single file then run
|
||||
import csv
|
||||
|
||||
# Input and output file names
|
||||
input_file = '/alltalkbeta/metadata_eval.csv' # combine metadata_train and metadata_eval.csv
|
||||
output_file = '/alltalkbeta/dataset.txt' # this goes to the tokenizer
|
||||
|
||||
# Read the input CSV and write to the output file
|
||||
with open(input_file, 'r', newline='', encoding='utf-8') as infile, \
|
||||
open(output_file, 'w', newline='', encoding='utf-8') as outfile:
|
||||
|
||||
# Create CSV reader and writer objects
|
||||
reader = csv.reader(infile, delimiter='|')
|
||||
writer = csv.writer(outfile, delimiter='|')
|
||||
|
||||
# Skip the header
|
||||
next(reader, None)
|
||||
|
||||
# Process each row
|
||||
for row in reader:
|
||||
if len(row) >= 2:
|
||||
# Write only the second column (index 1) to the output file
|
||||
writer.writerow([row[1]])
|
||||
|
||||
print(f"Processing complete. Output written to {output_file}")
|
||||
@@ -1,76 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import gradio as gr
|
||||
|
||||
# Define directories
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
main_dir = this_dir.parent.parent.resolve()
|
||||
|
||||
# Folder paths
|
||||
folders = {
|
||||
"models": main_dir / "models",
|
||||
"finetune": main_dir / "finetune",
|
||||
"voices": main_dir / "voices",
|
||||
"outputs": main_dir / "outputs",
|
||||
"alltalk_environment": main_dir / "alltalk_environment"
|
||||
}
|
||||
|
||||
def get_folder_size_scandir(folder_path):
|
||||
total_size = 0
|
||||
for entry in os.scandir(folder_path):
|
||||
if entry.is_file(follow_symlinks=False):
|
||||
try:
|
||||
total_size += entry.stat(follow_symlinks=False).st_size
|
||||
except OSError as e:
|
||||
print(f"Error getting size for file {entry.path}: {e}")
|
||||
elif entry.is_dir(follow_symlinks=False):
|
||||
try:
|
||||
total_size += get_folder_size_scandir(entry.path)
|
||||
except OSError as e:
|
||||
print(f"Error accessing directory {entry.path}: {e}")
|
||||
return total_size
|
||||
|
||||
def format_size(size):
|
||||
# Convert size to a readable format
|
||||
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
|
||||
if size < 1024:
|
||||
return f"{size:.2f} {unit}"
|
||||
size /= 1024
|
||||
|
||||
def calculate_disk_space():
|
||||
sizes = {}
|
||||
for name, path in folders.items():
|
||||
if path.exists():
|
||||
folder_size = get_folder_size_scandir(path)
|
||||
# print(f"Folder: {name}, Total Size: {folder_size} bytes")
|
||||
sizes[name] = format_size(folder_size)
|
||||
else:
|
||||
sizes[name] = "Not present"
|
||||
|
||||
return sizes['models'], sizes['finetune'], sizes['voices'], sizes['outputs'], sizes['alltalk_environment']
|
||||
|
||||
def disk_space_page():
|
||||
# Define the layout
|
||||
with gr.Tab("Disk Space Usage"):
|
||||
with gr.Row():
|
||||
models_space = gr.Textbox(label="Models Folder", interactive=False)
|
||||
finetune_space = gr.Textbox(label="Finetune Folder", interactive=False)
|
||||
voices_space = gr.Textbox(label="Voices Folder", interactive=False)
|
||||
outputs_space = gr.Textbox(label="Outputs Folder", interactive=False)
|
||||
alltalk_env_space = gr.Textbox(label="Alltalk Python Environment", interactive=False)
|
||||
|
||||
calculate_button = gr.Button("Calculate Disk Space Usage")
|
||||
|
||||
# Define actions for buttons
|
||||
calculate_button.click(calculate_disk_space, outputs=[models_space, finetune_space, voices_space, outputs_space, alltalk_env_space])
|
||||
|
||||
def get_disk_interface():
|
||||
return disk_space_page
|
||||
|
||||
# Example usage in the main script
|
||||
if __name__ == "__main__":
|
||||
app = gr.Blocks()
|
||||
with app:
|
||||
disk_space_page()
|
||||
|
||||
app.launch()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,114 +0,0 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import importlib
|
||||
|
||||
# Hard-coded paths
|
||||
this_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
||||
config_file = os.path.join(this_folder, "confignew.json")
|
||||
gradio_pages_folder = os.path.join(this_folder, "system", "gradio_pages", "themes")
|
||||
theme_list_file = os.path.join(gradio_pages_folder, "theme_list.json")
|
||||
themes_file_path = os.path.join(gradio_pages_folder, "themes.py")
|
||||
|
||||
# Add gradio_pages folder to the system path
|
||||
sys.path.append(gradio_pages_folder)
|
||||
|
||||
def get_class(filename):
|
||||
with open(filename, "r", encoding="utf8") as file:
|
||||
for line in file:
|
||||
if "class " in line:
|
||||
return line.split("class ")[1].split(":")[0].split("(")[0].strip()
|
||||
return None
|
||||
|
||||
|
||||
def get_list():
|
||||
themes_from_files = [
|
||||
os.path.splitext(name)[0]
|
||||
for name in os.listdir(gradio_pages_folder)
|
||||
if name.endswith(".py")
|
||||
]
|
||||
try:
|
||||
with open(theme_list_file, "r", encoding="utf8") as json_file:
|
||||
themes_from_url = [item["id"] for item in json.load(json_file)]
|
||||
except FileNotFoundError:
|
||||
themes_from_url = []
|
||||
|
||||
combined_themes = sorted(set(themes_from_files + themes_from_url))
|
||||
return list(combined_themes)
|
||||
|
||||
|
||||
def select_theme(name):
|
||||
selected_file = name + ".py"
|
||||
full_path = os.path.join(gradio_pages_folder, selected_file)
|
||||
|
||||
try:
|
||||
with open(config_file, "r", encoding="utf8") as json_file:
|
||||
config_data = json.load(json_file)
|
||||
|
||||
if not os.path.exists(full_path):
|
||||
# If the theme is from theme_list.json, update only the class field
|
||||
config_data["theme"]["file"] = None
|
||||
config_data["theme"]["class"] = name
|
||||
message = f"Theme {name} successfully selected, restart AllTalk."
|
||||
else:
|
||||
# If the theme file exists locally, update both file and class fields
|
||||
class_found = get_class(full_path)
|
||||
if class_found:
|
||||
config_data["theme"]["file"] = selected_file
|
||||
config_data["theme"]["class"] = class_found
|
||||
message = f"Theme {name} successfully selected, restart AllTalk."
|
||||
else:
|
||||
message = f"Theme {name} was not found."
|
||||
|
||||
with open(config_file, "w", encoding="utf8") as json_file:
|
||||
json.dump(config_data, json_file, indent=2)
|
||||
|
||||
print(message)
|
||||
return message
|
||||
|
||||
except Exception as e:
|
||||
print(f"[AllTalk TTS] Error selecting theme {name}: {str(e)}")
|
||||
return message
|
||||
|
||||
def read_json():
|
||||
try:
|
||||
with open(config_file, "r", encoding="utf8") as json_file:
|
||||
data = json.load(json_file)
|
||||
selected_file = data["theme"]["file"]
|
||||
class_name = data["theme"]["class"]
|
||||
|
||||
if selected_file and class_name:
|
||||
return class_name
|
||||
elif not selected_file and class_name:
|
||||
return class_name
|
||||
else:
|
||||
return "gradio/base"
|
||||
except Exception as e:
|
||||
print(f"[AllTalk TTS] Error reading config.json: {e}")
|
||||
return "gradio/base"
|
||||
|
||||
|
||||
def load_json():
|
||||
try:
|
||||
with open(config_file, "r", encoding="utf8") as json_file:
|
||||
data = json.load(json_file)
|
||||
selected_file = data["theme"]["file"]
|
||||
class_name = data["theme"]["class"]
|
||||
|
||||
if selected_file and class_name:
|
||||
module_name = os.path.splitext(selected_file)[0]
|
||||
module_spec = importlib.util.spec_from_file_location(module_name, themes_file_path)
|
||||
module = importlib.util.module_from_spec(module_spec)
|
||||
module_spec.loader.exec_module(module)
|
||||
obtained_class = getattr(module, class_name)
|
||||
instance = obtained_class()
|
||||
print(f"Theme Loaded: {class_name}")
|
||||
return instance
|
||||
elif not selected_file and class_name:
|
||||
return class_name
|
||||
else:
|
||||
print("The theme is incorrect.")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error Loading: {str(e)}")
|
||||
return None
|
||||
@@ -1,81 +0,0 @@
|
||||
[
|
||||
{"id": "freddyaboulton/dracula_revamped"},
|
||||
{"id": "freddyaboulton/bad-theme-space"},
|
||||
{"id": "gradio/dracula_revamped"},
|
||||
{"id": "abidlabs/dracula_revamped"},
|
||||
{"id": "gradio/dracula_test"},
|
||||
{"id": "abidlabs/dracula_test"},
|
||||
{"id": "gradio/seafoam"},
|
||||
{"id": "gradio/glass"},
|
||||
{"id": "gradio/monochrome"},
|
||||
{"id": "gradio/soft"},
|
||||
{"id": "gradio/default"},
|
||||
{"id": "gradio/base"},
|
||||
{"id": "abidlabs/pakistan"},
|
||||
{"id": "dawood/microsoft_windows"},
|
||||
{"id": "ysharma/steampunk"},
|
||||
{"id": "ysharma/huggingface"},
|
||||
{"id": "gstaff/xkcd"},
|
||||
{"id": "JohnSmith9982/small_and_pretty"},
|
||||
{"id": "abidlabs/Lime"},
|
||||
{"id": "freddyaboulton/this-theme-does-not-exist-2"},
|
||||
{"id": "aliabid94/new-theme"},
|
||||
{"id": "aliabid94/test2"},
|
||||
{"id": "aliabid94/test3"},
|
||||
{"id": "aliabid94/test4"},
|
||||
{"id": "abidlabs/banana"},
|
||||
{"id": "freddyaboulton/test-blue"},
|
||||
{"id": "gstaff/sketch"},
|
||||
{"id": "gstaff/whiteboard"},
|
||||
{"id": "ysharma/llamas"},
|
||||
{"id": "abidlabs/font-test"},
|
||||
{"id": "YenLai/Superhuman"},
|
||||
{"id": "bethecloud/storj_theme"},
|
||||
{"id": "sudeepshouche/minimalist"},
|
||||
{"id": "knotdgaf/gradiotest"},
|
||||
{"id": "ParityError/Interstellar"},
|
||||
{"id": "ParityError/Anime"},
|
||||
{"id": "Ajaxon6255/Emerald_Isle"},
|
||||
{"id": "ParityError/LimeFace"},
|
||||
{"id": "finlaymacklon/smooth_slate"},
|
||||
{"id": "finlaymacklon/boxy_violet"},
|
||||
{"id": "derekzen/stardust"},
|
||||
{"id": "EveryPizza/Cartoony-Gradio-Theme"},
|
||||
{"id": "Ifeanyi/Cyanister"},
|
||||
{"id": "Tshackelton/IBMPlex-DenseReadable"},
|
||||
{"id": "snehilsanyal/scikit-learn"},
|
||||
{"id": "Himhimhim/xkcd"},
|
||||
{"id": "shivi/calm_seafoam"},
|
||||
{"id": "nota-ai/theme"},
|
||||
{"id": "rawrsor1/Everforest"},
|
||||
{"id": "SebastianBravo/simci_css"},
|
||||
{"id": "rottenlittlecreature/Moon_Goblin"},
|
||||
{"id": "abidlabs/test-yellow"},
|
||||
{"id": "abidlabs/test-yellow3"},
|
||||
{"id": "idspicQstitho/dracula_revamped"},
|
||||
{"id": "kfahn/AnimalPose"},
|
||||
{"id": "HaleyCH/HaleyCH_Theme"},
|
||||
{"id": "simulKitke/dracula_test"},
|
||||
{"id": "braintacles/CrimsonNight"},
|
||||
{"id": "wentaohe/whiteboardv2"},
|
||||
{"id": "reilnuud/polite"},
|
||||
{"id": "remilia/Ghostly"},
|
||||
{"id": "Franklisi/darkmode"},
|
||||
{"id": "coding-alt/soft"},
|
||||
{"id": "xiaobaiyuan/theme_land"},
|
||||
{"id": "step-3-profit/Midnight-Deep"},
|
||||
{"id": "xiaobaiyuan/theme_demo"},
|
||||
{"id": "Taithrah/Minimal"},
|
||||
{"id": "Insuz/SimpleIndigo"},
|
||||
{"id": "zkunn/Alipay_Gradio_theme"},
|
||||
{"id": "Insuz/Mocha"},
|
||||
{"id": "xiaobaiyuan/theme_brief"},
|
||||
{"id": "Ama434/434-base-Barlow"},
|
||||
{"id": "Ama434/def_barlow"},
|
||||
{"id": "Ama434/neutral-barlow"},
|
||||
{"id": "dawood/dracula_test"},
|
||||
{"id": "nuttea/Softblue"},
|
||||
{"id": "BlueDancer/Alien_Diffusion"},
|
||||
{"id": "naughtondale/monochrome"},
|
||||
{"id": "Dagfinn1962/standard"}
|
||||
]
|
||||
@@ -1,284 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable
|
||||
import gradio as gr
|
||||
|
||||
# gr.themes.builder()
|
||||
from gradio.themes.base import Base
|
||||
from gradio.themes.utils import colors, fonts, sizes
|
||||
import time
|
||||
|
||||
|
||||
class alltalk(Base):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
primary_hue: colors.Color | str = colors.neutral,
|
||||
secondary_hue: colors.Color | str = colors.neutral,
|
||||
neutral_hue: colors.Color | str = colors.neutral,
|
||||
spacing_size: sizes.Size | str = sizes.spacing_md,
|
||||
radius_size: sizes.Size | str = sizes.radius_md,
|
||||
text_size: sizes.Size | str = sizes.text_lg,
|
||||
font: fonts.Font | str | Iterable[fonts.Font | str] = (
|
||||
"Syne V",
|
||||
fonts.GoogleFont("Syne"),
|
||||
"ui-sans-serif",
|
||||
"system-ui",
|
||||
),
|
||||
font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
|
||||
"ui-monospace",
|
||||
fonts.GoogleFont("Nunito Sans"),
|
||||
),
|
||||
):
|
||||
super().__init__(
|
||||
primary_hue=primary_hue,
|
||||
secondary_hue=secondary_hue,
|
||||
neutral_hue=neutral_hue,
|
||||
spacing_size=spacing_size,
|
||||
radius_size=radius_size,
|
||||
text_size=text_size,
|
||||
font=font,
|
||||
font_mono=font_mono,
|
||||
)
|
||||
self.name = ("alltalk",)
|
||||
self.secondary_100 = ("#dbeafe",)
|
||||
self.secondary_200 = ("#bfdbfe",)
|
||||
self.secondary_300 = ("#93c5fd",)
|
||||
self.secondary_400 = ("#60a5fa",)
|
||||
self.secondary_50 = ("#eff6ff",)
|
||||
self.secondary_500 = ("#3b82f6",)
|
||||
self.secondary_600 = ("#2563eb",)
|
||||
self.secondary_700 = ("#1d4ed8",)
|
||||
self.secondary_800 = ("#1e40af",)
|
||||
self.secondary_900 = ("#1e3a8a",)
|
||||
self.secondary_950 = ("#1d3660",)
|
||||
|
||||
super().set(
|
||||
# Blaise
|
||||
background_fill_primary="#110F0F",
|
||||
background_fill_primary_dark="#110F0F",
|
||||
background_fill_secondary="#110F0F",
|
||||
background_fill_secondary_dark="#110F0F",
|
||||
block_background_fill="*neutral_800",
|
||||
block_background_fill_dark="*neutral_800",
|
||||
block_border_color="*border_color_primary",
|
||||
block_border_color_dark="*border_color_primary",
|
||||
block_border_width="1px",
|
||||
block_border_width_dark="1px",
|
||||
block_info_text_color="*body_text_color_subdued",
|
||||
block_info_text_color_dark="*body_text_color_subdued",
|
||||
block_info_text_size="*text_sm",
|
||||
block_info_text_weight="400",
|
||||
block_label_background_fill="*background_fill_primary",
|
||||
block_label_background_fill_dark="*background_fill_secondary",
|
||||
block_label_border_color="*border_color_primary",
|
||||
block_label_border_color_dark="*border_color_primary",
|
||||
block_label_border_width="1px",
|
||||
block_label_border_width_dark="1px",
|
||||
block_label_margin="0",
|
||||
block_label_padding="*spacing_sm *spacing_lg",
|
||||
block_label_radius="calc(*radius_lg - 1px) 0 calc(*radius_lg - 1px) 0",
|
||||
block_label_right_radius="0 calc(*radius_lg - 1px) 0 calc(*radius_lg - 1px)",
|
||||
block_label_shadow="*block_shadow",
|
||||
block_label_text_color="*#110F0F",
|
||||
block_label_text_color_dark="*#110F0F",
|
||||
block_label_text_weight="400",
|
||||
block_padding="*spacing_xl",
|
||||
block_radius="*radius_md",
|
||||
block_shadow="none",
|
||||
block_shadow_dark="none",
|
||||
block_title_background_fill="rgb(255,255,255)",
|
||||
block_title_background_fill_dark="rgb(255,255,255)",
|
||||
block_title_border_color="none",
|
||||
block_title_border_color_dark="none",
|
||||
block_title_border_width="0px",
|
||||
block_title_padding="*block_label_padding",
|
||||
block_title_radius="*block_label_radius",
|
||||
block_title_text_color="#110F0F",
|
||||
block_title_text_color_dark="#110F0F",
|
||||
block_title_text_size="*text_md",
|
||||
block_title_text_weight="600",
|
||||
body_background_fill="#110F0F",
|
||||
body_background_fill_dark="#110F0F",
|
||||
body_text_color="white",
|
||||
body_text_color_dark="white",
|
||||
body_text_color_subdued="*neutral_400",
|
||||
body_text_color_subdued_dark="*neutral_400",
|
||||
body_text_size="*text_md",
|
||||
body_text_weight="400",
|
||||
border_color_accent="*neutral_600",
|
||||
border_color_accent_dark="*neutral_600",
|
||||
border_color_primary="*neutral_800",
|
||||
border_color_primary_dark="*neutral_800",
|
||||
button_border_width="*input_border_width",
|
||||
button_border_width_dark="*input_border_width",
|
||||
button_cancel_background_fill="*button_secondary_background_fill",
|
||||
button_cancel_background_fill_dark="*button_secondary_background_fill",
|
||||
button_cancel_background_fill_hover="*button_cancel_background_fill",
|
||||
button_cancel_background_fill_hover_dark="*button_cancel_background_fill",
|
||||
button_cancel_border_color="*button_secondary_border_color",
|
||||
button_cancel_border_color_dark="*button_secondary_border_color",
|
||||
button_cancel_border_color_hover="*button_cancel_border_color",
|
||||
button_cancel_border_color_hover_dark="*button_cancel_border_color",
|
||||
button_cancel_text_color="#110F0F",
|
||||
button_cancel_text_color_dark="#110F0F",
|
||||
button_cancel_text_color_hover="#110F0F",
|
||||
button_cancel_text_color_hover_dark="#110F0F",
|
||||
button_large_padding="*spacing_lg calc(2 * *spacing_lg)",
|
||||
button_large_radius="*radius_lg",
|
||||
button_large_text_size="*text_lg",
|
||||
button_large_text_weight="600",
|
||||
button_primary_background_fill="*primary_600",
|
||||
button_primary_background_fill_dark="*primary_600",
|
||||
button_primary_background_fill_hover="*primary_500",
|
||||
button_primary_background_fill_hover_dark="*primary_500",
|
||||
button_primary_border_color="*primary_500",
|
||||
button_primary_border_color_dark="*primary_500",
|
||||
button_primary_border_color_hover="*primary_400",
|
||||
button_primary_border_color_hover_dark="*primary_400",
|
||||
button_primary_text_color="white",
|
||||
button_primary_text_color_dark="white",
|
||||
button_primary_text_color_hover="#110F0F",
|
||||
button_primary_text_color_hover_dark="#110F0F",
|
||||
button_secondary_background_fill="transparent",
|
||||
button_secondary_background_fill_dark="transparent",
|
||||
button_secondary_background_fill_hover="*neutral_800",
|
||||
button_secondary_background_fill_hover_dark="*neutral_800",
|
||||
button_secondary_border_color="*neutral_700",
|
||||
button_secondary_border_color_dark="*neutral_700",
|
||||
button_secondary_border_color_hover="*neutral_600",
|
||||
button_secondary_border_color_hover_dark="*neutral_600",
|
||||
button_secondary_text_color="white",
|
||||
button_secondary_text_color_dark="white",
|
||||
button_secondary_text_color_hover="*button_secondary_text_color",
|
||||
button_secondary_text_color_hover_dark="*button_secondary_text_color",
|
||||
button_shadow="none",
|
||||
button_shadow_active="*shadow_inset",
|
||||
button_shadow_hover="none",
|
||||
button_small_padding="*spacing_sm calc(2 * *spacing_sm)",
|
||||
button_small_radius="*radius_lg",
|
||||
button_small_text_size="*text_md",
|
||||
button_small_text_weight="400",
|
||||
button_transition="0.3s ease all",
|
||||
checkbox_background_color="*neutral_700",
|
||||
checkbox_background_color_dark="*neutral_700",
|
||||
checkbox_background_color_focus="*checkbox_background_color",
|
||||
checkbox_background_color_focus_dark="*checkbox_background_color",
|
||||
checkbox_background_color_hover="*checkbox_background_color",
|
||||
checkbox_background_color_hover_dark="*checkbox_background_color",
|
||||
checkbox_background_color_selected="*secondary_600",
|
||||
checkbox_background_color_selected_dark="*secondary_600",
|
||||
checkbox_border_color="*neutral_700",
|
||||
checkbox_border_color_dark="*neutral_700",
|
||||
checkbox_border_color_focus="*secondary_500",
|
||||
checkbox_border_color_focus_dark="*secondary_500",
|
||||
checkbox_border_color_hover="*neutral_600",
|
||||
checkbox_border_color_hover_dark="*neutral_600",
|
||||
checkbox_border_color_selected="*secondary_600",
|
||||
checkbox_border_color_selected_dark="*secondary_600",
|
||||
checkbox_border_radius="*radius_sm",
|
||||
checkbox_border_width="*input_border_width",
|
||||
checkbox_border_width_dark="*input_border_width",
|
||||
checkbox_check="url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e\")",
|
||||
checkbox_label_background_fill="transparent",
|
||||
checkbox_label_background_fill_dark="transparent",
|
||||
checkbox_label_background_fill_hover="transparent",
|
||||
checkbox_label_background_fill_hover_dark="transparent",
|
||||
checkbox_label_background_fill_selected="transparent",
|
||||
checkbox_label_background_fill_selected_dark="transparent",
|
||||
checkbox_label_border_color="transparent",
|
||||
checkbox_label_border_color_dark="transparent",
|
||||
checkbox_label_border_color_hover="transparent",
|
||||
checkbox_label_border_color_hover_dark="transparent",
|
||||
checkbox_label_border_width="transparent",
|
||||
checkbox_label_border_width_dark="transparent",
|
||||
checkbox_label_gap="*spacing_lg",
|
||||
checkbox_label_padding="*spacing_md calc(2 * *spacing_md)",
|
||||
checkbox_label_shadow="none",
|
||||
checkbox_label_text_color="*body_text_color",
|
||||
checkbox_label_text_color_dark="*body_text_color",
|
||||
checkbox_label_text_color_selected="*checkbox_label_text_color",
|
||||
checkbox_label_text_color_selected_dark="*checkbox_label_text_color",
|
||||
checkbox_label_text_size="*text_md",
|
||||
checkbox_label_text_weight="400",
|
||||
checkbox_shadow="*input_shadow",
|
||||
color_accent="*primary_500",
|
||||
color_accent_soft="*primary_50",
|
||||
color_accent_soft_dark="*neutral_700",
|
||||
container_radius="*radius_xl",
|
||||
embed_radius="*radius_lg",
|
||||
error_background_fill="*background_fill_primary",
|
||||
error_background_fill_dark="*background_fill_primary",
|
||||
error_border_color="*border_color_primary",
|
||||
error_border_color_dark="*border_color_primary",
|
||||
error_border_width="1px",
|
||||
error_border_width_dark="1px",
|
||||
error_text_color="#ef4444",
|
||||
error_text_color_dark="#ef4444",
|
||||
form_gap_width="0px",
|
||||
input_background_fill="*neutral_900",
|
||||
input_background_fill_dark="*neutral_900",
|
||||
input_background_fill_focus="*secondary_600",
|
||||
input_background_fill_focus_dark="*secondary_600",
|
||||
input_background_fill_hover="*input_background_fill",
|
||||
input_background_fill_hover_dark="*input_background_fill",
|
||||
input_border_color="*neutral_700",
|
||||
input_border_color_dark="*neutral_700",
|
||||
input_border_color_focus="*secondary_600",
|
||||
input_border_color_focus_dark="*primary_600",
|
||||
input_border_color_hover="*input_border_color",
|
||||
input_border_color_hover_dark="*input_border_color",
|
||||
input_border_width="1px",
|
||||
input_border_width_dark="1px",
|
||||
input_padding="*spacing_xl",
|
||||
input_placeholder_color="*neutral_500",
|
||||
input_placeholder_color_dark="*neutral_500",
|
||||
input_radius="*radius_lg",
|
||||
input_shadow="none",
|
||||
input_shadow_dark="none",
|
||||
input_shadow_focus="*input_shadow",
|
||||
input_shadow_focus_dark="*input_shadow",
|
||||
input_text_size="*text_md",
|
||||
input_text_weight="400",
|
||||
layout_gap="*spacing_xxl",
|
||||
link_text_color="*secondary_500",
|
||||
link_text_color_active="*secondary_500",
|
||||
link_text_color_active_dark="*secondary_500",
|
||||
link_text_color_dark="*secondary_500",
|
||||
link_text_color_hover="*secondary_400",
|
||||
link_text_color_hover_dark="*secondary_400",
|
||||
link_text_color_visited="*secondary_600",
|
||||
link_text_color_visited_dark="*secondary_600",
|
||||
loader_color="*color_accent",
|
||||
loader_color_dark="*color_accent",
|
||||
panel_background_fill="*background_fill_secondary",
|
||||
panel_background_fill_dark="*background_fill_secondary",
|
||||
panel_border_color="*border_color_primary",
|
||||
panel_border_color_dark="*border_color_primary",
|
||||
panel_border_width="1px",
|
||||
panel_border_width_dark="1px",
|
||||
prose_header_text_weight="600",
|
||||
prose_text_size="*text_md",
|
||||
prose_text_weight="400",
|
||||
radio_circle="url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e\")",
|
||||
section_header_text_size="*text_md",
|
||||
section_header_text_weight="400",
|
||||
shadow_drop="rgba(0,0,0,0.05) 0px 1px 2px 0px",
|
||||
shadow_drop_lg="0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
|
||||
shadow_inset="rgba(0,0,0,0.05) 0px 2px 4px 0px inset",
|
||||
shadow_spread="3px",
|
||||
shadow_spread_dark="1px",
|
||||
slider_color="#9E9E9E",
|
||||
slider_color_dark="#9E9E9E",
|
||||
stat_background_fill="*primary_500",
|
||||
stat_background_fill_dark="*primary_500",
|
||||
table_border_color="*neutral_700",
|
||||
table_border_color_dark="*neutral_700",
|
||||
table_even_background_fill="*neutral_950",
|
||||
table_even_background_fill_dark="*neutral_950",
|
||||
table_odd_background_fill="*neutral_900",
|
||||
table_odd_background_fill_dark="*neutral_900",
|
||||
table_radius="*radius_lg",
|
||||
table_row_focus="*color_accent_soft",
|
||||
table_row_focus_dark="*color_accent_soft",
|
||||
)
|
||||
@@ -1,196 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>OpenAI API/AllTalk TTS API Test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #1e1e1e;
|
||||
color: #c7c7c7;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.container {
|
||||
background-color: #2b2b2b;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
}
|
||||
label {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin: 10px 0 5px;
|
||||
color: #ffffff;
|
||||
}
|
||||
input[type="text"], input[type="number"], textarea, select {
|
||||
width: calc(100% - 20px);
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #555;
|
||||
border-radius: 4px;
|
||||
background-color: #3b3b3b;
|
||||
color: #ffffff;
|
||||
}
|
||||
input[type="submit"] {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.config, .response {
|
||||
background-color: #3b3b3b;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.form-group > div {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.form-group > div:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>OpenAI API/AllTalk TTS API Test</h1>
|
||||
<div class="config form-group">
|
||||
<div>
|
||||
<label for="ip">IP Address:</label>
|
||||
<input type="text" id="ip" name="ip" value="localhost" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="port">Port Number:</label>
|
||||
<input type="number" id="port" name="port" value="7851" required>
|
||||
</div>
|
||||
</div>
|
||||
<form id="ttsForm">
|
||||
<label for="model">Model:</label>
|
||||
<input type="text" id="model" name="model" value="some-model" required><br>
|
||||
|
||||
<label for="input">Input Text:</label>
|
||||
<textarea id="input" name="input" rows="8" required>Hello, this is a test.</textarea><br>
|
||||
<p id="charCount">Character count: 21</p>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<label for="voice">Voice:</label>
|
||||
<select id="voice" name="voice" required>
|
||||
<option value="alloy">Alloy</option>
|
||||
<option value="echo">Echo</option>
|
||||
<option value="fable">Fable</option>
|
||||
<option value="nova">Nova</option>
|
||||
<option value="onyx">Onyx</option>
|
||||
<option value="shimmer">Shimmer</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="response_format">Response Format:</label>
|
||||
<select id="response_format" name="response_format" required>
|
||||
<option value="wav">WAV</option>
|
||||
<option value="mp3">MP3</option>
|
||||
<option value="ogg">OGG</option>
|
||||
<option value="flac">FLAC</option>
|
||||
<option value="aac">AAC</option>
|
||||
<option value="m4a">M4A</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="speed">Speed:</label>
|
||||
<input type="number" id="speed" name="speed" value="1.0" step="0.1" required><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="autoplay">Auto-play:</label>
|
||||
<input type="checkbox" id="autoplay" name="autoplay"><br><br>
|
||||
|
||||
<input type="submit" value="Submit"><br><br>
|
||||
</form>
|
||||
<div id="response" class="response"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Real-time character count
|
||||
const inputField = document.getElementById('input');
|
||||
const charCountDisplay = document.getElementById('charCount');
|
||||
|
||||
inputField.addEventListener('input', () => {
|
||||
const trimmedInput = inputField.value.trim();
|
||||
charCountDisplay.textContent = `Character count: ${trimmedInput.length}`;
|
||||
});
|
||||
|
||||
document.getElementById('ttsForm').addEventListener('submit', async function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
const formData = new FormData(event.target);
|
||||
const jsonData = {};
|
||||
|
||||
// Sanitize input: trim spaces
|
||||
formData.forEach((value, key) => {
|
||||
if (key === 'input') {
|
||||
value = value.trim().replace(/\s+/g, ' '); // Trim and normalize spaces
|
||||
}
|
||||
jsonData[key] = key === 'speed' ? parseFloat(value) : value;
|
||||
});
|
||||
|
||||
const ip = document.getElementById('ip').value;
|
||||
const port = document.getElementById('port').value;
|
||||
const url = `http://${ip}:${port}/v1/audio/speech`;
|
||||
|
||||
const responseDiv = document.getElementById('response');
|
||||
responseDiv.innerHTML = 'Sending request...';
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(jsonData),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const audio = new Audio(url);
|
||||
audio.controls = true;
|
||||
if (document.getElementById('autoplay').checked) {
|
||||
audio.autoplay = true;
|
||||
}
|
||||
responseDiv.innerHTML = '';
|
||||
responseDiv.appendChild(audio);
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
responseDiv.innerHTML = 'Error: ' + errorText;
|
||||
}
|
||||
} catch (error) {
|
||||
responseDiv.innerHTML = 'Error: ' + error.message;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,51 +0,0 @@
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
from OpenSSL import crypto
|
||||
import sys
|
||||
|
||||
def generate_certificate(cert_name: str, output_dir: Path, cn: str = "localhost", days: int = 365):
|
||||
k = crypto.PKey()
|
||||
k.generate_key(crypto.TYPE_RSA, 2048)
|
||||
|
||||
cert = crypto.X509()
|
||||
cert.get_subject().CN = cn
|
||||
cert.set_serial_number(1000)
|
||||
cert.gmtime_adj_notBefore(0)
|
||||
cert.gmtime_adj_notAfter(days*24*60*60)
|
||||
cert.set_issuer(cert.get_subject())
|
||||
cert.set_pubkey(k)
|
||||
cert.sign(k, 'sha256')
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(output_dir / f"{cert_name}_cert.pem", "wb") as f:
|
||||
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
||||
with open(output_dir / f"{cert_name}_key.pem", "wb") as f:
|
||||
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))
|
||||
|
||||
def main():
|
||||
print("Certificate Generator")
|
||||
print("-" * 20)
|
||||
|
||||
# Get default paths
|
||||
default_path = Path(__file__).parent / "certificates"
|
||||
|
||||
# Get user input with defaults
|
||||
cert_name = input(f"Certificate name (default: test_cert): ") or "test_cert"
|
||||
cn = input(f"Common Name (default: localhost): ") or "localhost"
|
||||
days = input(f"Valid days (default: 365): ") or "365"
|
||||
output_dir = input(f"Output directory (default: {default_path}): ") or str(default_path)
|
||||
|
||||
try:
|
||||
days = int(days)
|
||||
output_path = Path(output_dir)
|
||||
generate_certificate(cert_name, output_path, cn, days)
|
||||
print(f"\nSuccess! Certificate files created:")
|
||||
print(f"- {output_path / f'{cert_name}_cert.pem'}")
|
||||
print(f"- {output_path / f'{cert_name}_key.pem'}")
|
||||
except Exception as e:
|
||||
print(f"\nError: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,120 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, Optional
|
||||
from datetime import datetime
|
||||
import ssl
|
||||
import OpenSSL
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class CertificateInfo:
|
||||
subject: str
|
||||
issuer: str
|
||||
valid_from: datetime
|
||||
valid_until: datetime
|
||||
serial_number: str
|
||||
is_valid: bool
|
||||
|
||||
class CertificateManager:
|
||||
def __init__(self, proxy_manager):
|
||||
self.proxy_manager = proxy_manager
|
||||
self.logger = logging.getLogger("ProxyCertManager")
|
||||
self.certs_path = proxy_manager.certs_path
|
||||
|
||||
def validate_certificate(self, cert_path: Path) -> Optional[CertificateInfo]:
|
||||
"""Validate and get information about a certificate"""
|
||||
try:
|
||||
with open(cert_path, 'rb') as cert_file:
|
||||
cert_data = cert_file.read()
|
||||
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_data)
|
||||
|
||||
valid_from = datetime.strptime(x509.get_notBefore().decode(), '%Y%m%d%H%M%SZ')
|
||||
valid_until = datetime.strptime(x509.get_notAfter().decode(), '%Y%m%d%H%M%SZ')
|
||||
now = datetime.now()
|
||||
|
||||
return CertificateInfo(
|
||||
subject=x509.get_subject().CN,
|
||||
issuer=x509.get_issuer().CN,
|
||||
valid_from=valid_from,
|
||||
valid_until=valid_until,
|
||||
serial_number=str(x509.get_serial_number()),
|
||||
is_valid=valid_from <= now <= valid_until
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.error(f"Certificate validation error: {e}")
|
||||
return None
|
||||
|
||||
def install_certificate(self, cert_path: Path, key_path: Path, name: str) -> bool:
|
||||
try:
|
||||
import shutil
|
||||
# Validate certificate first
|
||||
cert_info = self.validate_certificate(cert_path)
|
||||
if not cert_info or not cert_info.is_valid:
|
||||
self.logger.error("Invalid or corrupt certificate")
|
||||
return False
|
||||
|
||||
cert_dest = self.certs_path / f"{name}_cert.pem"
|
||||
key_dest = self.certs_path / f"{name}_key.pem"
|
||||
|
||||
shutil.copy2(cert_path, cert_dest)
|
||||
shutil.copy2(key_path, key_dest)
|
||||
|
||||
# Update config
|
||||
config = self.proxy_manager.config_manager.get_instance()
|
||||
config.proxy_settings.gradio_endpoint.cert_name = name
|
||||
config.proxy_settings.api_endpoint.cert_name = name
|
||||
config.save()
|
||||
|
||||
self.logger.info(f"Certificate '{name}' installed successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Certificate installation error: {e}")
|
||||
return False
|
||||
|
||||
def remove_certificate(self, name: str) -> bool:
|
||||
"""Remove a certificate"""
|
||||
try:
|
||||
cert_path = self.certs_path / f"{name}_cert.pem"
|
||||
key_path = self.certs_path / f"{name}_key.pem"
|
||||
|
||||
if cert_path.exists():
|
||||
cert_path.unlink()
|
||||
if key_path.exists():
|
||||
key_path.unlink()
|
||||
|
||||
self.logger.info(f"Certificate '{name}' removed successfully")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Certificate removal error: {e}")
|
||||
return False
|
||||
|
||||
def get_certificates_status(self) -> Dict[str, Any]:
|
||||
"""Get status of all installed certificates"""
|
||||
certificates = {}
|
||||
for cert_file in self.certs_path.glob("*_cert.pem"):
|
||||
name = cert_file.name.replace("_cert.pem", "")
|
||||
cert_info = self.validate_certificate(cert_file)
|
||||
if cert_info:
|
||||
certificates[name] = {
|
||||
"subject": cert_info.subject,
|
||||
"issuer": cert_info.issuer,
|
||||
"valid_from": cert_info.valid_from.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"valid_until": cert_info.valid_until.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"is_valid": cert_info.is_valid,
|
||||
"days_until_expiry": (cert_info.valid_until - datetime.now()).days
|
||||
}
|
||||
return certificates
|
||||
|
||||
def check_expiring_certificates(self, days_warning: int = 30) -> Dict[str, int]:
|
||||
"""Check for certificates nearing expiration"""
|
||||
expiring = {}
|
||||
for cert_file in self.certs_path.glob("*_cert.pem"):
|
||||
name = cert_file.name.replace("_cert.pem", "")
|
||||
cert_info = self.validate_certificate(cert_file)
|
||||
if cert_info:
|
||||
days_left = (cert_info.valid_until - datetime.now()).days
|
||||
if days_left < days_warning:
|
||||
expiring[name] = days_left
|
||||
return expiring
|
||||
@@ -1,127 +0,0 @@
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
from typing import Dict, Any
|
||||
import requests
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
|
||||
@dataclass
|
||||
class HealthMetrics:
|
||||
last_check: float = 0
|
||||
uptime_start: float = 0
|
||||
gradio_endpoint_up: bool = False
|
||||
api_endpoint_up: bool = False
|
||||
consecutive_failures: int = 0
|
||||
total_restarts: int = 0
|
||||
response_times: Dict[str, float] = field(default_factory=dict)
|
||||
|
||||
class HealthMonitor:
|
||||
def __init__(self, proxy_manager):
|
||||
self.proxy_manager = proxy_manager
|
||||
self.logger = logging.getLogger("ProxyHealthMonitor")
|
||||
self.metrics = HealthMetrics()
|
||||
self.monitoring = False
|
||||
self.monitor_thread = None
|
||||
self.check_interval = 30 # seconds
|
||||
|
||||
def start_monitoring(self):
|
||||
"""Start health monitoring thread"""
|
||||
if self.monitoring:
|
||||
return
|
||||
|
||||
self.monitoring = True
|
||||
self.metrics.uptime_start = time.time()
|
||||
self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True) # Make thread daemon
|
||||
self.monitor_thread.start()
|
||||
self.logger.info("Health monitoring started")
|
||||
|
||||
def stop_monitoring(self):
|
||||
"""Stop health monitoring thread"""
|
||||
if not self.monitoring:
|
||||
return
|
||||
|
||||
self.monitoring = False
|
||||
if self.monitor_thread and self.monitor_thread.is_alive():
|
||||
try:
|
||||
# Give the thread a chance to finish naturally
|
||||
self.monitor_thread.join(timeout=5)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Could not gracefully stop monitoring thread: {e}")
|
||||
finally:
|
||||
self.monitor_thread = None
|
||||
|
||||
self.logger.info("Health monitoring stopped")
|
||||
|
||||
def _monitor_loop(self):
|
||||
"""Main monitoring loop"""
|
||||
while self.monitoring:
|
||||
self._check_health()
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
def _check_health(self):
|
||||
"""Check health of proxy endpoints"""
|
||||
config = self.proxy_manager.config_manager.get_instance()
|
||||
proxy_settings = config.proxy_settings
|
||||
self.metrics.last_check = time.time()
|
||||
|
||||
try:
|
||||
# Only check endpoints that are enabled and running
|
||||
if proxy_settings.gradio_endpoint.enabled == "Enabled":
|
||||
try:
|
||||
start_time = time.time()
|
||||
response = requests.get(
|
||||
f"http://127.0.0.1:{config.gradio_port_number}/", # Use internal port
|
||||
timeout=5
|
||||
)
|
||||
self.metrics.response_times['gradio'] = time.time() - start_time
|
||||
self.metrics.gradio_endpoint_up = response.status_code == 200
|
||||
except Exception as e:
|
||||
self.logger.debug(f"Gradio endpoint check failed: {e}")
|
||||
self.metrics.gradio_endpoint_up = False
|
||||
|
||||
if proxy_settings.api_endpoint.enabled == "Enabled":
|
||||
try:
|
||||
start_time = time.time()
|
||||
response = requests.get(
|
||||
f"http://127.0.0.1:{config.api_def.api_port_number}/", # Use internal port
|
||||
timeout=5
|
||||
)
|
||||
self.metrics.response_times['api'] = time.time() - start_time
|
||||
self.metrics.api_endpoint_up = response.status_code == 200
|
||||
except Exception as e:
|
||||
self.logger.debug(f"API endpoint check failed: {e}")
|
||||
self.metrics.api_endpoint_up = False
|
||||
|
||||
if not self.metrics.gradio_endpoint_up and not self.metrics.api_endpoint_up:
|
||||
self.metrics.consecutive_failures += 1
|
||||
else:
|
||||
self.metrics.consecutive_failures = 0
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Health check failed: {str(e)}")
|
||||
self.metrics.consecutive_failures += 1
|
||||
|
||||
# Only attempt restart if we have multiple complete failures
|
||||
if self.metrics.consecutive_failures >= 3:
|
||||
self.logger.warning("Too many consecutive failures, attempting restart")
|
||||
try:
|
||||
if self.proxy_manager.stop_proxy() and self.proxy_manager.start_proxy():
|
||||
self.metrics.total_restarts += 1
|
||||
self.metrics.consecutive_failures = 0
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to restart proxy: {e}")
|
||||
|
||||
def get_health_status(self) -> Dict[str, Any]:
|
||||
"""Get current health metrics"""
|
||||
uptime = time.time() - self.metrics.uptime_start if self.metrics.uptime_start else 0
|
||||
return {
|
||||
"status": "healthy" if not self.metrics.consecutive_failures else "degraded",
|
||||
"uptime": f"{int(uptime/3600)}h {int((uptime%3600)/60)}m",
|
||||
"last_check": datetime.fromtimestamp(self.metrics.last_check).strftime('%Y-%m-%d %H:%M:%S')
|
||||
if self.metrics.last_check else "Never",
|
||||
"gradio_endpoint": "up" if self.metrics.gradio_endpoint_up else "down",
|
||||
"api_endpoint": "up" if self.metrics.api_endpoint_up else "down",
|
||||
"response_times": self.metrics.response_times,
|
||||
"total_restarts": self.metrics.total_restarts
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
import gradio as gr
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .proxy_manager import ProxyManager
|
||||
|
||||
def create_proxy_interface(proxy_manager: 'ProxyManager'):
|
||||
"""Create the proxy management interface"""
|
||||
config = proxy_manager.config_manager.get_instance()
|
||||
|
||||
def validate_ports(gradio_port, api_port):
|
||||
"""Validate port configurations"""
|
||||
if gradio_port == api_port and gradio_port != 0 and api_port != 0:
|
||||
return False, "Gradio and API ports cannot be the same!"
|
||||
if not (0 <= gradio_port <= 65535) or not (0 <= api_port <= 65535):
|
||||
return False, "Ports must be between 0 and 65535"
|
||||
return True, "Valid port configuration"
|
||||
|
||||
def handle_save_config(proxy_enabled, gradio_enabled, api_enabled,
|
||||
gradio_port, api_port, startup, external_ip):
|
||||
# Validate ports first
|
||||
valid, message = validate_ports(gradio_port, api_port)
|
||||
if not valid:
|
||||
return message
|
||||
|
||||
config.proxy_settings.proxy_enabled = proxy_enabled
|
||||
config.proxy_settings.start_on_startup = startup
|
||||
|
||||
# Update Gradio endpoint
|
||||
config.proxy_settings.gradio_endpoint.enabled = gradio_enabled
|
||||
config.proxy_settings.gradio_endpoint.external_port = int(gradio_port) if gradio_enabled else 0
|
||||
config.proxy_settings.gradio_endpoint.external_ip = external_ip
|
||||
|
||||
# Update API endpoint
|
||||
config.proxy_settings.api_endpoint.enabled = api_enabled
|
||||
config.proxy_settings.api_endpoint.external_port = int(api_port) if api_enabled else 0
|
||||
config.proxy_settings.api_endpoint.external_ip = external_ip
|
||||
|
||||
config.save()
|
||||
return "Configuration saved successfully"
|
||||
|
||||
def update_control_states(proxy_enabled):
|
||||
"""Update enabled/disabled state of controls based on master switch"""
|
||||
return {
|
||||
start_button: gr.update(interactive=proxy_enabled),
|
||||
stop_button: gr.update(interactive=proxy_enabled),
|
||||
gradio_enabled: gr.update(interactive=proxy_enabled),
|
||||
api_enabled: gr.update(interactive=proxy_enabled),
|
||||
start_on_startup: gr.update(interactive=proxy_enabled)
|
||||
}
|
||||
|
||||
def delete_all_certificates():
|
||||
"""Delete all certificates and reset config"""
|
||||
try:
|
||||
# Delete certificate files
|
||||
for cert_file in proxy_manager.certs_path.glob("*.pem"):
|
||||
cert_file.unlink()
|
||||
|
||||
# Reset config
|
||||
config = proxy_manager.config_manager.get_instance()
|
||||
config.proxy_settings.gradio_endpoint.cert_name = ""
|
||||
config.proxy_settings.api_endpoint.cert_name = ""
|
||||
config.save()
|
||||
|
||||
return "All certificates deleted and config reset"
|
||||
except Exception as e:
|
||||
return f"Error deleting certificates: {str(e)}"
|
||||
|
||||
with gr.Tab("Proxy Settings"):
|
||||
with gr.Column():
|
||||
with gr.Row():
|
||||
with gr.Group():
|
||||
proxy_enabled = gr.Checkbox(
|
||||
label="Enable Proxy System",
|
||||
value=config.proxy_settings.proxy_enabled,
|
||||
info="Master switch/safety lockout for proxy functionality"
|
||||
)
|
||||
start_on_startup = gr.Checkbox(
|
||||
label="Start Proxy Automatically on Startup",
|
||||
value=config.proxy_settings.start_on_startup,
|
||||
info="Automatically start proxy when app launches"
|
||||
)
|
||||
external_ip = gr.Textbox(
|
||||
label="External IP",
|
||||
value=config.proxy_settings.gradio_endpoint.external_ip,
|
||||
info="Use 0.0.0.0 to bind to all interfaces"
|
||||
)
|
||||
with gr.Group():
|
||||
gr.Markdown("API interface Proxy Management")
|
||||
api_enabled = gr.Dropdown(
|
||||
choices=["Enabled", "Disabled"],
|
||||
value="Enabled" if config.proxy_settings.api_endpoint.enabled == "Enabled" else "Disabled",
|
||||
label="API (TTS Generation) Proxy",
|
||||
info="Enable or Disable Proxying the API (TTS Generation)"
|
||||
)
|
||||
api_port = gr.Number(
|
||||
value=config.proxy_settings.api_endpoint.external_port,
|
||||
label="API Port",
|
||||
info="External port you want to use for the API (TTS Generation)"
|
||||
)
|
||||
with gr.Group():
|
||||
gr.Markdown("Gradio interface Proxy Management")
|
||||
gradio_enabled = gr.Dropdown(
|
||||
choices=["Enabled", "Disabled"],
|
||||
value="Enabled" if config.proxy_settings.gradio_endpoint.enabled == "Enabled" else "Disabled",
|
||||
label="Gradio Interface Proxy",
|
||||
info="Enable or Disable Proxying the Gradio interface"
|
||||
)
|
||||
gradio_port = gr.Number(
|
||||
value=config.proxy_settings.gradio_endpoint.external_port,
|
||||
label="Gradio Interface Port",
|
||||
info="External port you want to use for the Gradio interface"
|
||||
)
|
||||
|
||||
# Status and control section
|
||||
with gr.Row():
|
||||
with gr.Column(scale=2):
|
||||
status_output = gr.Textbox(
|
||||
label="Status",
|
||||
interactive=False,
|
||||
lines=4
|
||||
)
|
||||
with gr.Column(scale=1):
|
||||
save_button = gr.Button("Save Configuration", variant="primary")
|
||||
with gr.Row():
|
||||
start_button = gr.Button("Start Service")
|
||||
stop_button = gr.Button("Stop Service")
|
||||
status_button = gr.Button("Check Status")
|
||||
|
||||
# Certificate section
|
||||
with gr.Row():
|
||||
gr.Markdown("### Certificate Management")
|
||||
with gr.Row():
|
||||
with gr.Column(scale=1):
|
||||
cert_file = gr.File(label="Certificate (.crt/.pem)")
|
||||
with gr.Column(scale=1):
|
||||
key_file = gr.File(label="Key (.key)")
|
||||
with gr.Column(scale=1):
|
||||
cert_name = gr.Textbox(label="Certificate Name", placeholder="e.g., gradio_cert")
|
||||
upload_button = gr.Button("Upload Certificate", variant="primary")
|
||||
delete_button = gr.Button("Delete Certificates", variant="secondary")
|
||||
|
||||
# Connect everything
|
||||
save_button.click(
|
||||
fn=handle_save_config,
|
||||
inputs=[
|
||||
proxy_enabled,
|
||||
gradio_enabled,
|
||||
api_enabled,
|
||||
gradio_port,
|
||||
api_port,
|
||||
start_on_startup,
|
||||
external_ip
|
||||
],
|
||||
outputs=status_output
|
||||
)
|
||||
proxy_enabled.change(
|
||||
fn=update_control_states,
|
||||
inputs=[proxy_enabled],
|
||||
outputs=[start_button, stop_button, gradio_enabled, api_enabled, start_on_startup]
|
||||
)
|
||||
start_button.click(fn=proxy_manager.start_proxy, outputs=status_output)
|
||||
stop_button.click(fn=proxy_manager.stop_proxy, outputs=status_output)
|
||||
status_button.click(fn=proxy_manager.get_status, outputs=status_output)
|
||||
upload_button.click(
|
||||
fn=proxy_manager.handle_cert_upload,
|
||||
inputs=[cert_file, key_file, cert_name],
|
||||
outputs=status_output
|
||||
)
|
||||
delete_button.click(fn=delete_all_certificates, outputs=status_output)
|
||||
|
||||
return proxy_enabled, start_on_startup, gradio_port, api_port
|
||||
@@ -1,94 +0,0 @@
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
from typing import Dict, Any
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
@dataclass
|
||||
class ProxyMetrics:
|
||||
start_time: float = field(default_factory=time.time)
|
||||
total_requests: int = 0
|
||||
active_connections: int = 0
|
||||
bytes_transferred: int = 0
|
||||
request_times: Dict[str, float] = field(default_factory=lambda: defaultdict(float))
|
||||
requests_per_minute: Dict[str, int] = field(default_factory=lambda: defaultdict(int))
|
||||
status_codes: Dict[str, int] = field(default_factory=lambda: defaultdict(int))
|
||||
|
||||
class MetricsCollector:
|
||||
def __init__(self, proxy_manager):
|
||||
self.proxy_manager = proxy_manager
|
||||
self.logger = logging.getLogger("ProxyMetrics")
|
||||
self.metrics = ProxyMetrics()
|
||||
self.collecting = False
|
||||
self.collector_thread = None
|
||||
self.collect_interval = 60 # seconds
|
||||
self._lock = threading.Lock()
|
||||
|
||||
def start_collecting(self):
|
||||
"""Start metrics collection"""
|
||||
if self.collecting:
|
||||
return
|
||||
|
||||
self.collecting = True
|
||||
self.metrics = ProxyMetrics() # Reset metrics
|
||||
self.collector_thread = threading.Thread(target=self._collect_loop)
|
||||
self.collector_thread.daemon = True
|
||||
self.collector_thread.start()
|
||||
self.logger.info("Metrics collection started")
|
||||
|
||||
def stop_collecting(self):
|
||||
"""Stop metrics collection"""
|
||||
self.collecting = False
|
||||
if self.collector_thread:
|
||||
self.collector_thread.join()
|
||||
self.logger.info("Metrics collection stopped")
|
||||
|
||||
def _collect_loop(self):
|
||||
"""Main collection loop"""
|
||||
while self.collecting:
|
||||
self._update_metrics()
|
||||
time.sleep(self.collect_interval)
|
||||
|
||||
def _update_metrics(self):
|
||||
"""Update periodic metrics"""
|
||||
with self._lock:
|
||||
# Reset per-minute counters
|
||||
self.metrics.requests_per_minute.clear()
|
||||
|
||||
def record_request(self, endpoint: str, status_code: int, response_time: float, bytes_sent: int):
|
||||
"""Record metrics for a single request"""
|
||||
with self._lock:
|
||||
self.metrics.total_requests += 1
|
||||
self.metrics.bytes_transferred += bytes_sent
|
||||
self.metrics.request_times[endpoint] = response_time
|
||||
self.metrics.status_codes[str(status_code)] += 1
|
||||
self.metrics.requests_per_minute[endpoint] += 1
|
||||
|
||||
def get_current_metrics(self) -> Dict[str, Any]:
|
||||
"""Get current metrics"""
|
||||
with self._lock:
|
||||
uptime = time.time() - self.metrics.start_time
|
||||
return {
|
||||
"uptime": str(timedelta(seconds=int(uptime))),
|
||||
"total_requests": self.metrics.total_requests,
|
||||
"active_connections": self.metrics.active_connections,
|
||||
"bytes_transferred": f"{self.metrics.bytes_transferred / 1024 / 1024:.2f} MB",
|
||||
"average_response_times": {
|
||||
endpoint: f"{time:.2f}ms"
|
||||
for endpoint, time in self.metrics.request_times.items()
|
||||
},
|
||||
"requests_per_minute": dict(self.metrics.requests_per_minute),
|
||||
"status_codes": dict(self.metrics.status_codes)
|
||||
}
|
||||
|
||||
def increment_connections(self):
|
||||
"""Increment active connection count"""
|
||||
with self._lock:
|
||||
self.metrics.active_connections += 1
|
||||
|
||||
def decrement_connections(self):
|
||||
"""Decrement active connection count"""
|
||||
with self._lock:
|
||||
self.metrics.active_connections = max(0, self.metrics.active_connections - 1)
|
||||
@@ -1,235 +0,0 @@
|
||||
import os
|
||||
import logging
|
||||
import subprocess
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any
|
||||
from dataclasses import asdict
|
||||
import psutil
|
||||
from logging.handlers import RotatingFileHandler
|
||||
import logging
|
||||
import os
|
||||
from .security import SecurityManager
|
||||
from .health_monitor import HealthMonitor
|
||||
from .cert_manager import CertificateManager
|
||||
from .metrics import MetricsCollector
|
||||
|
||||
class ProxyManager:
|
||||
def __init__(self, config_manager, base_path: str = None):
|
||||
self.config_manager = config_manager
|
||||
# Set up base paths first
|
||||
self.base_path = Path(base_path) if base_path else Path(__file__).parent
|
||||
|
||||
# Create required directories
|
||||
self.certs_path = self.base_path / "certificates"
|
||||
self.logs_path = self.base_path / "logs"
|
||||
self.config_path = self.base_path / "config"
|
||||
|
||||
for path in [self.certs_path, self.logs_path, self.config_path]:
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Setup logging before managers
|
||||
self.setup_logging()
|
||||
|
||||
# Initialize managers after paths are created
|
||||
self.security = SecurityManager(self)
|
||||
self.health_monitor = HealthMonitor(self)
|
||||
self.cert_manager = CertificateManager(self)
|
||||
self.metrics = MetricsCollector(self)
|
||||
|
||||
self.proxy_process = None
|
||||
self.logger.info("Proxy manager initialized successfully")
|
||||
|
||||
def setup_logging(self):
|
||||
"""Setup logging configuration with customized format"""
|
||||
config = self.config_manager.get_instance()
|
||||
log_level = getattr(logging, config.proxy_settings.log_level, logging.INFO)
|
||||
|
||||
# Configure rotating file handler
|
||||
log_file = self.logs_path / "proxy.log"
|
||||
file_handler = RotatingFileHandler(
|
||||
log_file,
|
||||
maxBytes=5*1024*1024,
|
||||
backupCount=5,
|
||||
encoding='utf-8'
|
||||
)
|
||||
|
||||
# Configure logging formats
|
||||
file_format = logging.Formatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
console_format = logging.Formatter(
|
||||
'[AllTalk PRX] %(message)s'
|
||||
)
|
||||
|
||||
file_handler.setFormatter(file_format)
|
||||
|
||||
# Setup logger
|
||||
self.logger = logging.getLogger("ProxyManager")
|
||||
self.logger.setLevel(log_level)
|
||||
self.logger.addHandler(file_handler)
|
||||
|
||||
# Only add console handler if proxy debugging is enabled
|
||||
if config.debugging.debug_proxy:
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(console_format)
|
||||
self.logger.addHandler(console_handler)
|
||||
self.logger.info("Proxy debug logging enabled")
|
||||
|
||||
def _monitor_output(self, pipe, name):
|
||||
"""Monitor subprocess output and redirect to logger"""
|
||||
try:
|
||||
for line in iter(pipe.readline, ''):
|
||||
line = line.strip()
|
||||
if line:
|
||||
if name == "stderr":
|
||||
self.logger.error(line)
|
||||
else:
|
||||
# Pass through with our logging format
|
||||
print(line) # Direct print for formatted output
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error monitoring {name}: {e}")
|
||||
finally:
|
||||
pipe.close()
|
||||
|
||||
def start_proxy(self) -> bool:
|
||||
"""Start the proxy server with current configuration"""
|
||||
if self.proxy_process and self.proxy_process.poll() is None:
|
||||
self.logger.warning("Proxy already running")
|
||||
return False
|
||||
|
||||
config = self.config_manager.get_instance()
|
||||
proxy_settings = config.proxy_settings
|
||||
|
||||
try:
|
||||
|
||||
cmd = [
|
||||
"python", "-m", "twisted_server",
|
||||
"--external_ip_a", proxy_settings.api_endpoint.external_ip if proxy_settings.api_endpoint.enabled == "Enabled" else "0",
|
||||
"--internal_ip_a", "127.0.0.1",
|
||||
"--external_ip_b", proxy_settings.gradio_endpoint.external_ip if proxy_settings.gradio_endpoint.enabled == "Enabled" else "0",
|
||||
"--internal_ip_b", "127.0.0.1",
|
||||
"--cert_file_a", proxy_settings.api_endpoint.cert_name or "0",
|
||||
"--cert_file_b", proxy_settings.gradio_endpoint.cert_name or "0"
|
||||
]
|
||||
|
||||
# Start process with pipe for output
|
||||
self.proxy_process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
cwd=str(self.base_path),
|
||||
text=True,
|
||||
bufsize=1,
|
||||
env={**os.environ, 'PYTHONUNBUFFERED': '1'}, # Force unbuffered output
|
||||
universal_newlines=True
|
||||
)
|
||||
|
||||
# Start output monitoring threads
|
||||
threading.Thread(target=self._monitor_output,
|
||||
args=(self.proxy_process.stdout, "stdout"),
|
||||
daemon=True).start()
|
||||
threading.Thread(target=self._monitor_output,
|
||||
args=(self.proxy_process.stderr, "stderr"),
|
||||
daemon=True).start()
|
||||
|
||||
if proxy_settings.proxy_enabled:
|
||||
self.health_monitor.start_monitoring()
|
||||
self.metrics.start_collecting()
|
||||
|
||||
self.logger.info("Proxy server started successfully")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to start proxy: {e}")
|
||||
return False
|
||||
|
||||
def stop_proxy(self) -> bool:
|
||||
"""Stop the proxy server and all monitoring"""
|
||||
if not self.proxy_process:
|
||||
self.logger.warning("No proxy process running")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Stop all monitoring first
|
||||
self.health_monitor.stop_monitoring()
|
||||
self.metrics.stop_collecting()
|
||||
|
||||
# Stop the main process
|
||||
process = psutil.Process(self.proxy_process.pid)
|
||||
for proc in process.children(recursive=True):
|
||||
proc.terminate()
|
||||
process.terminate()
|
||||
|
||||
try:
|
||||
process.wait(timeout=5)
|
||||
except psutil.TimeoutExpired:
|
||||
process.kill()
|
||||
|
||||
self.proxy_process = None
|
||||
self.logger.info("Proxy server stopped successfully")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to stop proxy: {e}")
|
||||
return False
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
"""Get comprehensive status of the proxy system"""
|
||||
config = self.config_manager.get_instance()
|
||||
proxy_config = config.proxy_settings
|
||||
|
||||
status = {
|
||||
"running": self.proxy_process is not None and self.proxy_process.poll() is None,
|
||||
"config": {
|
||||
"gradio_endpoint": asdict(proxy_config.gradio_endpoint),
|
||||
"api_endpoint": asdict(proxy_config.api_endpoint),
|
||||
"start_on_startup": proxy_config.start_on_startup
|
||||
},
|
||||
"certificates": self.cert_manager.get_certificates_status(),
|
||||
"health": self.health_monitor.get_health_status(),
|
||||
"metrics": self.metrics.get_current_metrics(),
|
||||
"security": self.security.get_security_status()
|
||||
}
|
||||
|
||||
return status
|
||||
|
||||
def handle_cert_upload(self, cert_file, key_file, name):
|
||||
"""Handle certificate upload from the interface"""
|
||||
if not cert_file or not key_file or not name:
|
||||
return "Please provide both certificate and key files, and a name"
|
||||
|
||||
cert_path = Path(cert_file.name)
|
||||
key_path = Path(key_file.name)
|
||||
|
||||
success = self.cert_manager.install_certificate(cert_path, key_path, name)
|
||||
return "Certificate uploaded successfully" if success else "Failed to upload certificate"
|
||||
|
||||
def handle_start(self):
|
||||
"""Handle proxy start from the interface"""
|
||||
success = self.start_proxy()
|
||||
return "Proxy Server: Starting..." if success else "Failed to start proxy server"
|
||||
|
||||
def handle_stop(self):
|
||||
"""Handle proxy stop from the interface"""
|
||||
success = self.stop_proxy()
|
||||
return "Proxy Server: Stopped" if success else "Failed to stop proxy server"
|
||||
|
||||
def handle_status(self):
|
||||
"""Handle status request from the interface"""
|
||||
status = self.get_status()
|
||||
if status['running']:
|
||||
return "Proxy Server: Running\n" + \
|
||||
f"API Endpoint: {'Active' if status['config']['api_endpoint']['enabled'] == 'Enabled' else 'Disabled'}\n" + \
|
||||
f"Gradio Endpoint: {'Active' if status['config']['gradio_endpoint']['enabled'] == 'Enabled' else 'Disabled'}\n" + \
|
||||
f"Certificates: {len(status['certificates'])} configured"
|
||||
else:
|
||||
return "Proxy Server: Stopped"
|
||||
|
||||
def handle_security_event(self, event_type: str, details: Dict[str, Any]):
|
||||
"""Handle security events from the SecurityManager"""
|
||||
self.logger.warning(f"Security event: {event_type} - {details}")
|
||||
# Implement security response logic here
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup resources before shutdown"""
|
||||
self.stop_proxy()
|
||||
self.logger.info("Proxy manager cleanup completed")
|
||||
@@ -1,61 +0,0 @@
|
||||
import logging
|
||||
from typing import Dict, Any, Set
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from threading import Lock
|
||||
|
||||
@dataclass
|
||||
class SecurityMetrics:
|
||||
total_requests: int = 0
|
||||
blocked_requests: int = 0
|
||||
last_incident: float = 0
|
||||
blacklisted_ips: Set[str] = None
|
||||
|
||||
def __post_init__(self):
|
||||
if self.blacklisted_ips is None:
|
||||
self.blacklisted_ips = set()
|
||||
|
||||
class SecurityManager:
|
||||
def __init__(self, proxy_manager):
|
||||
self.proxy_manager = proxy_manager
|
||||
self.logger = logging.getLogger("ProxySecurityManager")
|
||||
self.metrics = SecurityMetrics()
|
||||
self.rate_limits = defaultdict(lambda: {"count": 0, "reset_time": 0})
|
||||
self.rate_limit_lock = Lock()
|
||||
|
||||
def check_rate_limit(self, ip: str, limit: int = 100, window: int = 60) -> bool:
|
||||
"""Check if IP has exceeded rate limit"""
|
||||
with self.rate_limit_lock:
|
||||
current_time = time.time()
|
||||
if self.rate_limits[ip]["reset_time"] < current_time:
|
||||
self.rate_limits[ip] = {"count": 0, "reset_time": current_time + window}
|
||||
|
||||
self.rate_limits[ip]["count"] += 1
|
||||
return self.rate_limits[ip]["count"] <= limit
|
||||
|
||||
def is_blacklisted(self, ip: str) -> bool:
|
||||
"""Check if IP is blacklisted"""
|
||||
return ip in self.metrics.blacklisted_ips
|
||||
|
||||
def add_to_blacklist(self, ip: str, reason: str):
|
||||
"""Add IP to blacklist"""
|
||||
self.metrics.blacklisted_ips.add(ip)
|
||||
self.logger.warning(f"IP {ip} blacklisted: {reason}")
|
||||
self.metrics.last_incident = time.time()
|
||||
|
||||
def remove_from_blacklist(self, ip: str):
|
||||
"""Remove IP from blacklist"""
|
||||
self.metrics.blacklisted_ips.discard(ip)
|
||||
self.logger.info(f"IP {ip} removed from blacklist")
|
||||
|
||||
def get_security_status(self) -> Dict[str, Any]:
|
||||
"""Get current security metrics"""
|
||||
return {
|
||||
"total_requests": self.metrics.total_requests,
|
||||
"blocked_requests": self.metrics.blocked_requests,
|
||||
"blacklisted_ips": len(self.metrics.blacklisted_ips),
|
||||
"last_incident": time.strftime('%Y-%m-%d %H:%M:%S',
|
||||
time.localtime(self.metrics.last_incident))
|
||||
if self.metrics.last_incident else "None"
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import logging
|
||||
|
||||
# Auto-install requirements if missing
|
||||
def install_requirements():
|
||||
"""Install missing requirements only if they're not already in sys.modules"""
|
||||
required_packages = [
|
||||
"twisted",
|
||||
"cryptography",
|
||||
"service_identity",
|
||||
"requests",
|
||||
"psutil"
|
||||
]
|
||||
|
||||
for package in required_packages:
|
||||
if package not in sys.modules:
|
||||
try:
|
||||
__import__(package)
|
||||
except ImportError:
|
||||
print(f"Package '{package}' is not installed. Installing now...")
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
||||
|
||||
install_requirements()
|
||||
|
||||
from twisted.internet import reactor, ssl
|
||||
from twisted.web import proxy, server
|
||||
import argparse
|
||||
import inspect
|
||||
|
||||
# Handle config import for both package and standalone usage
|
||||
try:
|
||||
from ...config import AlltalkConfig # Package import
|
||||
except ImportError:
|
||||
# Get the path to the root directory (3 levels up from this file)
|
||||
root_dir = Path(__file__).parent.parent.parent
|
||||
sys.path.append(str(root_dir))
|
||||
from config import AlltalkConfig # Standalone import
|
||||
|
||||
def initialize_configs():
|
||||
"""Initialize all configuration instances"""
|
||||
config_initalize = AlltalkConfig.get_instance()
|
||||
return config_initalize
|
||||
|
||||
# Load in configs
|
||||
central_config = initialize_configs()
|
||||
|
||||
##########################
|
||||
# Central print function #
|
||||
##########################
|
||||
# ANSI color codes
|
||||
BLUE = "\033[94m"
|
||||
# MAGENTA = "\033[95m"
|
||||
YELLOW = "\033[93m"
|
||||
RED = "\033[91m"
|
||||
GREEN = "\033[92m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
def print_message(message, message_type="standard", component="PRX"):
|
||||
"""Centralized print function for AllTalk messages
|
||||
Args:
|
||||
message (str): The message to print
|
||||
message_type (str): Type of message (standard/warning/error/debug_*/debug)
|
||||
component (str): Component identifier (TTS/ENG/GEN/API/etc.)
|
||||
"""
|
||||
prefix = f"[{central_config.branding}{component}] "
|
||||
|
||||
if message_type.startswith("debug_"):
|
||||
debug_flag = getattr(central_config.debugging, message_type, False)
|
||||
if not debug_flag:
|
||||
return
|
||||
|
||||
if message_type == "debug_func" and "Function entry:" in message:
|
||||
message_parts = message.split("Function entry:", 1)
|
||||
print(
|
||||
f"{prefix}{BLUE}Debug{RESET} {YELLOW}{message_type}{RESET} Function entry:{GREEN}{message_parts[1]}{RESET} twisted_server.py"
|
||||
)
|
||||
else:
|
||||
print(f"{prefix}{BLUE}Debug{RESET} {YELLOW}{message_type}{RESET} {message}")
|
||||
|
||||
elif message_type == "debug":
|
||||
print(f"{prefix}{BLUE}Debug{RESET} {message}")
|
||||
|
||||
elif message_type == "warning":
|
||||
print(f"{prefix}{YELLOW}Warning{RESET} {message}")
|
||||
|
||||
elif message_type == "error":
|
||||
print(f"{prefix}{RED}Error{RESET} {message}")
|
||||
|
||||
else:
|
||||
print(f"{prefix}{message}")
|
||||
|
||||
def debug_func_entry():
|
||||
"""Print debug message for function entry if debug_func is enabled"""
|
||||
if central_config.debugging.debug_func:
|
||||
current_func = inspect.currentframe().f_back.f_code.co_name
|
||||
print_message(f"Function entry: {current_func}", "debug_func")
|
||||
|
||||
class ProxyToInternalPort(proxy.ReverseProxyResource):
|
||||
def __init__(self, target_host, target_port):
|
||||
super().__init__(target_host, target_port, b"")
|
||||
self.logger = logging.getLogger("ProxyManager")
|
||||
|
||||
def proxyClientConnectionFailed(self, connector, reason):
|
||||
print_message(f"Connection failed: {reason}", message_type="debug_proxy")
|
||||
return proxy.ReverseProxyResource.proxyClientConnectionFailed(self, connector, reason)
|
||||
|
||||
def proxyClientConnectionMade(self, connector):
|
||||
print_message(f"Connection established to {self.host}:{self.port}", message_type="debug_proxy")
|
||||
return proxy.ReverseProxyResource.proxyClientConnectionMade(self, connector)
|
||||
|
||||
def getChild(self, path, request):
|
||||
try:
|
||||
decoded_path = path.decode('utf-8', 'ignore')
|
||||
client_addr = request.getClientAddress()
|
||||
ip = client_addr.host if hasattr(client_addr, 'host') else 'unknown'
|
||||
method = request.method.decode('utf-8', 'ignore')
|
||||
|
||||
print_message(f"{GREEN}Request: {RED}{method} {decoded_path}{GREEN} from {RESET}{ip} {GREEN}Forwarding to:{RESET} {self.host}:{self.port} {RED}{decoded_path}{RESET}", message_type="debug_proxy")
|
||||
#print_message(f"Forwarding to: {self.host}:{self.port}{decoded_path}", message_type="debug_proxy")
|
||||
except Exception as e:
|
||||
print_message(f"Error in getChild: {str(e)}", message_type="error")
|
||||
|
||||
child = proxy.ReverseProxyResource(self.host, self.port, self.path + b'/' + path)
|
||||
return child
|
||||
|
||||
def check_certificates(cert_file_base):
|
||||
"""Check if both key and cert files exist for the given certificate base name."""
|
||||
debug_func_entry()
|
||||
if cert_file_base != "0":
|
||||
cert_path = Path("certificates") # Add base path
|
||||
key_file = cert_path / f"{cert_file_base}_key.pem"
|
||||
cert_file = cert_path / f"{cert_file_base}_cert.pem"
|
||||
|
||||
if not key_file.exists() or not cert_file.exists():
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
def run_proxy(external_ip_a, internal_ip_a, external_ip_b, internal_ip_b, cert_file_a, cert_file_b):
|
||||
debug_func_entry()
|
||||
proxies_started = False
|
||||
api_port = central_config.api_def.api_port_number
|
||||
gradio_port = central_config.gradio_port_number
|
||||
api_port_external = central_config.proxy_settings.api_endpoint.external_port
|
||||
gradio_port_external = central_config.proxy_settings.gradio_endpoint.external_port
|
||||
|
||||
print_message("Starting proxy setup with the following parameters:", message_type="debug_proxy")
|
||||
print_message(f" |- External IP API : {'[DISABLED]' if external_ip_a == '0' else f'{external_ip_a}:{api_port_external}'} -> {internal_ip_a}:{api_port}", message_type="debug_proxy")
|
||||
print_message(f" |- External IP Gradio : {'[DISABLED]' if external_ip_b == '0' else f'{external_ip_b}:{gradio_port_external}'} -> {internal_ip_b}:{gradio_port}", message_type="debug_proxy")
|
||||
print_message(f" |- Certificate File A : {cert_file_a} {'[No Certificate So Disabled]' if cert_file_a == '0' else ''}", message_type="debug_proxy")
|
||||
print_message(f" |- Certificate File B : {cert_file_b} {'[No Certificate So Disabled]' if cert_file_b == '0' else ''}", message_type="debug_proxy")
|
||||
|
||||
# Gradio Proxy
|
||||
if external_ip_b != "0" and central_config.proxy_settings.gradio_endpoint.enabled == "Enabled":
|
||||
if cert_file_b != "0" and check_certificates(cert_file_b):
|
||||
sslContextB = ssl.DefaultOpenSSLContextFactory(
|
||||
f"certificates/{cert_file_b}_key.pem",
|
||||
f"certificates/{cert_file_b}_cert.pem"
|
||||
)
|
||||
proxy_gradio = ProxyToInternalPort(internal_ip_b, gradio_port)
|
||||
proxy_site_gradio = server.Site(proxy_gradio)
|
||||
reactor.listenSSL(gradio_port_external, proxy_site_gradio, sslContextB, interface=external_ip_b)
|
||||
print_message(f"Gradio SSL Proxy : {GREEN}From{RESET} {external_ip_b}:{gradio_port_external} {GREEN}->{RESET} {internal_ip_b}:{gradio_port} {GREEN}is now active.{RESET}")
|
||||
else:
|
||||
proxy_gradio = ProxyToInternalPort(internal_ip_b, gradio_port)
|
||||
proxy_site_gradio = server.Site(proxy_gradio)
|
||||
reactor.listenTCP(gradio_port_external, proxy_site_gradio, interface=external_ip_b)
|
||||
print_message(f"Gradio HTTP Proxy : {GREEN}From{RESET} {external_ip_b}:{gradio_port_external} {GREEN}->{RESET} {internal_ip_b}:{gradio_port} {GREEN}is now active.{RESET}")
|
||||
proxies_started = True
|
||||
else:
|
||||
print_message(f"Gradio Proxy is {RED}DISABLED{RESET}")
|
||||
|
||||
# API Proxy
|
||||
if external_ip_a != "0" and central_config.proxy_settings.api_endpoint.enabled == "Enabled":
|
||||
if cert_file_a != "0" and check_certificates(cert_file_a):
|
||||
sslContextA = ssl.DefaultOpenSSLContextFactory(
|
||||
f"certificates/{cert_file_a}_key.pem",
|
||||
f"certificates/{cert_file_a}_cert.pem"
|
||||
)
|
||||
proxy_api = ProxyToInternalPort(internal_ip_a, api_port)
|
||||
proxy_site_api = server.Site(proxy_api)
|
||||
reactor.listenSSL(api_port_external, proxy_site_api, sslContextA, interface=external_ip_a)
|
||||
print_message(f"API SSL Proxy : {GREEN}From{RESET} {external_ip_a}:{api_port_external} {GREEN}->{RESET} {internal_ip_a}:{api_port} {GREEN}is now active.{RESET}")
|
||||
else:
|
||||
proxy_api = ProxyToInternalPort(internal_ip_a, api_port)
|
||||
proxy_site_api = server.Site(proxy_api)
|
||||
reactor.listenTCP(api_port_external, proxy_site_api, interface=external_ip_a)
|
||||
print_message(f"API HTTP Proxy : {GREEN}From{RESET} {external_ip_a}:{api_port_external} {GREEN}->{RESET} {internal_ip_a}:{api_port} {GREEN}is now active.{RESET}")
|
||||
proxies_started = True
|
||||
else:
|
||||
print_message(f"API Proxy is {RED}DISABLED{RESET}")
|
||||
|
||||
if not proxies_started:
|
||||
print_message(f"No proxies were started. {RED}Both{RESET} API and Gradio proxies are {RED}DISABLED{RESET}.", message_type="warning")
|
||||
return
|
||||
|
||||
reactor.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--external_ip_a", required=True, help="External IP Address A ('0' to disable)")
|
||||
parser.add_argument("--internal_ip_a", required=True, help="Internal IP Address A")
|
||||
parser.add_argument("--external_ip_b", required=True, help="External IP Address B ('0' to disable)")
|
||||
parser.add_argument("--internal_ip_b", required=True, help="Internal IP Address B")
|
||||
parser.add_argument("--cert_file_a", required=True, help="Certificate file base name for External IP A (without '_key' or '_cert', or '0' for HTTP only)")
|
||||
parser.add_argument("--cert_file_b", required=True, help="Certificate file base name for External IP B (without '_key' or '_cert', or '0' for HTTP only)")
|
||||
args = parser.parse_args()
|
||||
|
||||
run_proxy(
|
||||
external_ip_a=args.external_ip_a,
|
||||
internal_ip_a=args.internal_ip_a,
|
||||
external_ip_b=args.external_ip_b,
|
||||
internal_ip_b=args.internal_ip_b,
|
||||
cert_file_a=args.cert_file_a,
|
||||
cert_file_b=args.cert_file_b
|
||||
)
|
||||
@@ -1,49 +0,0 @@
|
||||
coqui-tts==0.24.3
|
||||
openai-whisper
|
||||
ffmpeg-python>=0.2.0
|
||||
filelock>=3.16.1
|
||||
fuzzywuzzy
|
||||
gradio==4.44.1
|
||||
importlib_metadata>=7.1.0
|
||||
inputimeout>=1.0.4
|
||||
Jinja2>=3.1.0
|
||||
librosa>=0.10.2.post1
|
||||
local_attention==1.9.10
|
||||
onnxruntime-gpu>=1.18.0
|
||||
pydantic>=2.7.0
|
||||
python-Levenshtein>=0.25.1
|
||||
praat-parselmouth>=0.4.0
|
||||
pyworld>=0.3.0
|
||||
sounddevice>=0.4.7
|
||||
soundfile>=0.12.0
|
||||
spacy>=3.7.1
|
||||
torchcrepe>=0.0.2
|
||||
tqdm>=4.66.0
|
||||
unidic-lite>=1.0.8
|
||||
uvicorn>=0.29.0
|
||||
pillow==10.3.0
|
||||
fastapi==0.112.2
|
||||
starlette
|
||||
pypinyin
|
||||
pyee
|
||||
aiofiles
|
||||
h11
|
||||
gradio
|
||||
gradio_client
|
||||
httpx
|
||||
httpcore
|
||||
websockets
|
||||
pydub
|
||||
semantic_version
|
||||
ffmpy
|
||||
tomlkit
|
||||
python-multipart
|
||||
hangul_romanize
|
||||
word2number
|
||||
cutlet==0.4.0
|
||||
fugashi==1.3.1
|
||||
piper-tts; sys_platform == "linux"
|
||||
plotly==5.24.1
|
||||
scipy==1.14.1
|
||||
pyOpenSSL>=24.2.1
|
||||
langdetect>=1.0.9
|
||||
@@ -0,0 +1,173 @@
|
||||
absl-py==2.1.0
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.9.3
|
||||
aiosignal==1.3.1
|
||||
altair==5.2.0
|
||||
annotated-types==0.6.0
|
||||
anyascii==0.3.2
|
||||
anyio==4.3.0
|
||||
attrs==23.2.0
|
||||
audioread==3.0.1
|
||||
av==11.0.0
|
||||
Babel==2.14.0
|
||||
bangla==0.0.2
|
||||
blinker==1.7.0
|
||||
blis==0.7.11
|
||||
bnnumerizer==0.0.2
|
||||
bnunicodenormalizer==0.1.6
|
||||
catalogue==2.0.10
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
cloudpathlib==0.16.0
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
confection==0.1.4
|
||||
contourpy==1.2.0
|
||||
coqpit==0.0.17
|
||||
ctranslate2==4.1.0
|
||||
cutlet==0.4.0
|
||||
cycler==0.12.1
|
||||
cymem==2.0.8
|
||||
Cython==3.0.9
|
||||
dateparser==1.1.8
|
||||
decorator==5.1.1
|
||||
docopt==0.6.2
|
||||
einops==0.7.0
|
||||
encodec==0.1.1
|
||||
exceptiongroup
|
||||
fastapi==0.110.0
|
||||
faster-whisper==1.0.1
|
||||
ffmpy==0.3.2
|
||||
filelock==3.13.3
|
||||
Flask==3.0.2
|
||||
flatbuffers==24.3.25
|
||||
fonttools==4.50.0
|
||||
frozenlist==1.4.1
|
||||
fsspec==2024.3.1
|
||||
fugashi==1.3.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
g2pkk==0.1.2
|
||||
gradio==3.50.2
|
||||
gradio_client==0.6.1
|
||||
grpcio==1.62.1
|
||||
gruut==2.2.3
|
||||
gruut-ipa==0.13.0
|
||||
gruut-lang-de==2.0.0
|
||||
gruut-lang-en==2.0.0
|
||||
gruut-lang-es==2.0.0
|
||||
gruut-lang-fr==2.0.2
|
||||
h11==0.14.0
|
||||
hangul-romanize==0.1.0
|
||||
httpcore==1.0.4
|
||||
httpx==0.27.0
|
||||
huggingface-hub==0.22.1
|
||||
humanfriendly==10.0
|
||||
idna==3.6
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
inflect==7.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaconv==0.3.4
|
||||
jamo==0.4.1
|
||||
jieba==0.42.1
|
||||
Jinja2==3.1.3
|
||||
joblib==1.3.2
|
||||
jsonlines==1.2.0
|
||||
jsonschema==4.21.1
|
||||
jsonschema-specifications==2023.12.1
|
||||
kiwisolver==1.4.5
|
||||
langcodes==3.3.0
|
||||
lazy_loader==0.3
|
||||
librosa==0.10.1
|
||||
llvmlite==0.42.0
|
||||
Markdown==3.6
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.8.3
|
||||
mojimoji==0.0.13
|
||||
mpmath==1.3.0
|
||||
msgpack==1.0.8
|
||||
multidict==6.0.5
|
||||
murmurhash==1.0.10
|
||||
networkx==2.8.8
|
||||
nltk==3.8.1
|
||||
num2words==0.5.13
|
||||
numba==0.59.1
|
||||
numpy==1.26.4
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
onnxruntime==1.17.1
|
||||
orjson==3.9.15
|
||||
packaging==24.0
|
||||
pandas==1.5.3
|
||||
pillow==10.2.0
|
||||
platformdirs==4.2.0
|
||||
pooch==1.8.1
|
||||
preshed==3.0.9
|
||||
protobuf==5.26.0
|
||||
psutil==5.9.8
|
||||
pycparser==2.21
|
||||
pydantic==2.6.4
|
||||
pydantic_core==2.16.3
|
||||
pydub==0.25.1
|
||||
pynndescent==0.5.11
|
||||
pyparsing==3.1.2
|
||||
pypinyin==0.51.0
|
||||
pyreadline3==3.4.1
|
||||
pysbd==0.3.4
|
||||
python-crfsuite==0.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
python-Levenshtein>=0.25.0
|
||||
python-multipart==0.0.9
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
referencing==0.34.0
|
||||
regex==2023.12.25
|
||||
requests==2.31.0
|
||||
rpds-py==0.18.0
|
||||
safetensors==0.4.2
|
||||
scikit-learn==1.4.1.post1
|
||||
scipy==1.12.0
|
||||
semantic-version==2.10.0
|
||||
six==1.16.0
|
||||
smart-open==6.4.0
|
||||
sniffio==1.3.1
|
||||
sounddevice==0.4.6
|
||||
soundfile==0.12.1
|
||||
soxr==0.3.7
|
||||
spacy==3.7.4
|
||||
spacy-legacy==3.0.12
|
||||
spacy-loggers==1.0.5
|
||||
srsly==2.4.8
|
||||
starlette==0.36.3
|
||||
SudachiDict-core==20240109
|
||||
SudachiPy==0.6.8
|
||||
sympy==1.12
|
||||
tensorboard==2.16.2
|
||||
tensorboard-data-server==0.7.2
|
||||
thinc==8.2.3
|
||||
threadpoolctl==3.4.0
|
||||
tokenizers==0.15.2
|
||||
toolz==0.12.1
|
||||
torch>=2.2.0
|
||||
torchaudio>=2.2.0
|
||||
tqdm==4.66.2
|
||||
trainer==0.0.36
|
||||
transformers==4.39.1
|
||||
TTS==0.22.0
|
||||
typer==0.9.4
|
||||
typing_extensions==4.10.0
|
||||
tzdata==2024.1
|
||||
tzlocal==5.2
|
||||
umap-learn==0.5.5
|
||||
Unidecode==1.3.8
|
||||
unidic-lite==1.0.8
|
||||
urllib3==2.2.1
|
||||
uvicorn==0.29.0
|
||||
wasabi==1.1.2
|
||||
weasel==0.3.4
|
||||
websockets==11.0.3
|
||||
Werkzeug==3.0.1
|
||||
yarl==1.9.4
|
||||
zipp==3.18.1
|
||||
@@ -1 +0,0 @@
|
||||
git+https://github.com/SWivid/F5-TTS.git
|
||||
@@ -0,0 +1,171 @@
|
||||
absl-py==2.1.0
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.9.3
|
||||
aiosignal==1.3.1
|
||||
altair==5.2.0
|
||||
annotated-types==0.6.0
|
||||
anyascii==0.3.2
|
||||
anyio==4.3.0
|
||||
attrs==23.2.0
|
||||
audioread==3.0.1
|
||||
av==11.0.0
|
||||
Babel==2.14.0
|
||||
bangla==0.0.2
|
||||
blinker==1.7.0
|
||||
blis==0.7.11
|
||||
bnnumerizer==0.0.2
|
||||
bnunicodenormalizer==0.1.6
|
||||
catalogue==2.0.10
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
cloudpathlib==0.16.0
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
confection==0.1.4
|
||||
contourpy==1.2.0
|
||||
coqpit==0.0.17
|
||||
ctranslate2==4.1.0
|
||||
cutlet==0.4.0
|
||||
cycler==0.12.1
|
||||
cymem==2.0.8
|
||||
Cython==3.0.9
|
||||
dateparser==1.1.8
|
||||
decorator==5.1.1
|
||||
docopt==0.6.2
|
||||
einops==0.7.0
|
||||
encodec==0.1.1
|
||||
fastapi==0.110.0
|
||||
faster-whisper==1.0.1
|
||||
ffmpy==0.3.2
|
||||
filelock==3.13.3
|
||||
Flask==3.0.2
|
||||
flatbuffers==24.3.25
|
||||
fonttools==4.50.0
|
||||
frozenlist==1.4.1
|
||||
fsspec==2024.3.1
|
||||
fugashi==1.3.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
g2pkk==0.1.2
|
||||
gradio==3.50.2
|
||||
gradio_client==0.6.1
|
||||
grpcio==1.62.1
|
||||
gruut==2.2.3
|
||||
gruut-ipa==0.13.0
|
||||
gruut-lang-de==2.0.0
|
||||
gruut-lang-en==2.0.0
|
||||
gruut-lang-es==2.0.0
|
||||
gruut-lang-fr==2.0.2
|
||||
h11==0.14.0
|
||||
hangul-romanize==0.1.0
|
||||
httpcore==1.0.4
|
||||
httpx==0.27.0
|
||||
huggingface-hub==0.22.1
|
||||
humanfriendly==10.0
|
||||
idna==3.6
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
inflect==7.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaconv==0.3.4
|
||||
jamo==0.4.1
|
||||
jieba==0.42.1
|
||||
Jinja2==3.1.3
|
||||
joblib==1.3.2
|
||||
jsonlines==1.2.0
|
||||
jsonschema==4.21.1
|
||||
jsonschema-specifications==2023.12.1
|
||||
kiwisolver==1.4.5
|
||||
langcodes==3.3.0
|
||||
lazy_loader==0.3
|
||||
librosa==0.10.1
|
||||
llvmlite==0.42.0
|
||||
Markdown==3.6
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.8.3
|
||||
mojimoji==0.0.13
|
||||
mpmath==1.3.0
|
||||
msgpack==1.0.8
|
||||
multidict==6.0.5
|
||||
murmurhash==1.0.10
|
||||
networkx==2.8.8
|
||||
nltk==3.8.1
|
||||
num2words==0.5.13
|
||||
numba==0.59.1
|
||||
numpy>=1.17.0,<1.29.0
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
onnxruntime==1.17.1
|
||||
orjson==3.9.15
|
||||
packaging==24.0
|
||||
pandas==1.5.3
|
||||
pillow==10.2.0
|
||||
platformdirs==4.2.0
|
||||
pooch==1.8.1
|
||||
preshed==3.0.9
|
||||
protobuf==5.26.0
|
||||
psutil==5.9.8
|
||||
pycparser==2.21
|
||||
pydantic==2.6.4
|
||||
pydantic_core==2.16.3
|
||||
pydub==0.25.1
|
||||
pynndescent==0.5.11
|
||||
pyparsing==3.1.2
|
||||
pypinyin==0.51.0
|
||||
pyreadline3==3.4.1
|
||||
pysbd==0.3.4
|
||||
python-crfsuite==0.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
python-Levenshtein>=0.25.0
|
||||
python-multipart==0.0.9
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
referencing==0.34.0
|
||||
regex==2023.12.25
|
||||
requests==2.31.0
|
||||
rpds-py==0.18.0
|
||||
safetensors==0.4.2
|
||||
scikit-learn==1.4.1.post1
|
||||
scipy==1.12.0
|
||||
semantic-version==2.10.0
|
||||
six==1.16.0
|
||||
smart-open==6.4.0
|
||||
sniffio==1.3.1
|
||||
sounddevice==0.4.6
|
||||
soundfile==0.12.1
|
||||
soxr==0.3.7
|
||||
spacy==3.7.4
|
||||
spacy-legacy==3.0.12
|
||||
spacy-loggers==1.0.5
|
||||
srsly==2.4.8
|
||||
starlette==0.36.3
|
||||
SudachiDict-core==20240109
|
||||
SudachiPy==0.6.8
|
||||
sympy==1.12
|
||||
tensorboard==2.16.2
|
||||
tensorboard-data-server==0.7.2
|
||||
thinc==8.2.3
|
||||
threadpoolctl==3.4.0
|
||||
tokenizers==0.15.2
|
||||
toolz==0.12.1
|
||||
torch>=2.2.0
|
||||
torchaudio>=2.2.0
|
||||
tqdm==4.66.2
|
||||
trainer==0.0.36
|
||||
transformers==4.39.1
|
||||
typer==0.9.4
|
||||
typing_extensions==4.10.0
|
||||
tzdata==2024.1
|
||||
tzlocal==5.2
|
||||
umap-learn==0.5.5
|
||||
Unidecode==1.3.8
|
||||
unidic-lite==1.0.8
|
||||
urllib3==2.2.1
|
||||
uvicorn==0.29.0
|
||||
wasabi==1.1.2
|
||||
weasel==0.3.4
|
||||
websockets==11.0.3
|
||||
Werkzeug==3.0.1
|
||||
yarl==1.9.4
|
||||
zipp==3.18.1
|
||||
@@ -1 +0,0 @@
|
||||
git+https://github.com/huggingface/parler-tts.git
|
||||
@@ -1,39 +1,172 @@
|
||||
coqui-tts==0.24.3
|
||||
filelock>=3.13.4
|
||||
fuzzywuzzy>=0.18.0
|
||||
ffmpeg-python>=0.2.0
|
||||
gradio==4.44.1
|
||||
importlib_metadata>=7.2.1
|
||||
inputimeout>=1.0.4
|
||||
Jinja2>=3.1.4
|
||||
librosa>=0.10.2.post1
|
||||
local_attention==1.9.10
|
||||
openai-whisper
|
||||
onnxruntime-gpu>=1.18.1
|
||||
pydantic>=2.8.2
|
||||
python-Levenshtein>=0.25.1
|
||||
praat-parselmouth>=0.4.4
|
||||
pyworld>=0.3.4
|
||||
sounddevice>=0.4.7
|
||||
soundfile>=0.12.1
|
||||
spacy>=3.7.1
|
||||
torchcrepe>=0.0.2
|
||||
tqdm>=4.66.5
|
||||
unidic-lite>=1.0.8
|
||||
uvicorn>=0.29.0
|
||||
pillow==10.3.0
|
||||
pypinyin>=0.52.0
|
||||
hangul_romanize>=0.1.0
|
||||
word2number>=1.1
|
||||
absl-py==2.1.0
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.9.3
|
||||
aiosignal==1.3.1
|
||||
altair==5.2.0
|
||||
annotated-types==0.6.0
|
||||
anyascii==0.3.2
|
||||
anyio==4.3.0
|
||||
attrs==23.2.0
|
||||
audioread==3.0.1
|
||||
av==11.0.0
|
||||
Babel==2.14.0
|
||||
bangla==0.0.2
|
||||
blinker==1.7.0
|
||||
blis==0.7.11
|
||||
bnnumerizer==0.0.2
|
||||
bnunicodenormalizer==0.1.6
|
||||
catalogue==2.0.10
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
cloudpathlib==0.16.0
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
confection==0.1.4
|
||||
contourpy==1.2.0
|
||||
coqpit==0.0.17
|
||||
ctranslate2==4.1.0
|
||||
cutlet==0.4.0
|
||||
cycler==0.12.1
|
||||
cymem==2.0.8
|
||||
Cython==3.0.9
|
||||
dateparser==1.1.8
|
||||
decorator==5.1.1
|
||||
docopt==0.6.2
|
||||
einops==0.7.0
|
||||
encodec==0.1.1
|
||||
fastapi==0.110.0
|
||||
faster-whisper==1.0.1
|
||||
ffmpy==0.3.2
|
||||
filelock==3.13.3
|
||||
Flask==3.0.2
|
||||
flatbuffers==24.3.25
|
||||
fonttools==4.50.0
|
||||
frozenlist==1.4.1
|
||||
fsspec==2024.3.1
|
||||
fugashi==1.3.1
|
||||
./system/config/fairseq-0.12.4-cp311-cp311-win_amd64.whl; sys_platform == "win32"
|
||||
./system/config/fairseq-0.12.3.1-cp311-cp311-linux_x86_64.whl; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "darwin"
|
||||
piper-phonemize==1.1.0; sys_platform == "darwin"
|
||||
fastapi==0.112.2
|
||||
plotly==5.24.1
|
||||
scipy==1.14.1
|
||||
pyOpenSSL>=24.2.1
|
||||
langdetect>=1.0.9
|
||||
fuzzywuzzy>=0.18.0
|
||||
g2pkk==0.1.2
|
||||
gradio==3.50.2
|
||||
gradio_client==0.6.1
|
||||
grpcio==1.62.1
|
||||
gruut==2.2.3
|
||||
gruut-ipa==0.13.0
|
||||
gruut-lang-de==2.0.0
|
||||
gruut-lang-en==2.0.0
|
||||
gruut-lang-es==2.0.0
|
||||
gruut-lang-fr==2.0.2
|
||||
h11==0.14.0
|
||||
hangul-romanize==0.1.0
|
||||
httpcore==1.0.4
|
||||
httpx==0.27.0
|
||||
huggingface-hub==0.22.1
|
||||
humanfriendly==10.0
|
||||
idna==3.6
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
inflect==7.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaconv==0.3.4
|
||||
jamo==0.4.1
|
||||
jieba==0.42.1
|
||||
Jinja2==3.1.3
|
||||
joblib==1.3.2
|
||||
jsonlines==1.2.0
|
||||
jsonschema==4.21.1
|
||||
jsonschema-specifications==2023.12.1
|
||||
kiwisolver==1.4.5
|
||||
langcodes==3.3.0
|
||||
lazy_loader==0.3
|
||||
librosa==0.10.1
|
||||
llvmlite==0.42.0
|
||||
Markdown==3.6
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.8.3
|
||||
mojimoji==0.0.13
|
||||
mpmath==1.3.0
|
||||
msgpack==1.0.8
|
||||
multidict==6.0.5
|
||||
murmurhash==1.0.10
|
||||
networkx==2.8.8
|
||||
nltk==3.8.1
|
||||
num2words==0.5.13
|
||||
numba==0.59.1
|
||||
numpy==1.26.4
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
onnxruntime==1.17.1
|
||||
orjson==3.9.15
|
||||
packaging==24.0
|
||||
pandas==1.5.3
|
||||
pillow==10.2.0
|
||||
platformdirs==4.2.0
|
||||
pooch==1.8.1
|
||||
preshed==3.0.9
|
||||
protobuf==5.26.0
|
||||
psutil==5.9.8
|
||||
pycparser==2.21
|
||||
pydantic==2.6.4
|
||||
pydantic_core==2.16.3
|
||||
pydub==0.25.1
|
||||
pynndescent==0.5.11
|
||||
pyparsing==3.1.2
|
||||
pypinyin==0.51.0
|
||||
pyreadline3==3.4.1
|
||||
pysbd==0.3.4
|
||||
python-crfsuite==0.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
python-Levenshtein>=0.25.0
|
||||
python-multipart==0.0.9
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
referencing==0.34.0
|
||||
regex==2023.12.25
|
||||
requests==2.31.0
|
||||
rpds-py==0.18.0
|
||||
safetensors==0.4.2
|
||||
scikit-learn==1.4.1.post1
|
||||
scipy==1.12.0
|
||||
semantic-version==2.10.0
|
||||
six==1.16.0
|
||||
smart-open==6.4.0
|
||||
sniffio==1.3.1
|
||||
sounddevice==0.4.6
|
||||
soundfile==0.12.1
|
||||
soxr==0.3.7
|
||||
spacy==3.7.4
|
||||
spacy-legacy==3.0.12
|
||||
spacy-loggers==1.0.5
|
||||
srsly==2.4.8
|
||||
starlette==0.36.3
|
||||
SudachiDict-core==20240109
|
||||
SudachiPy==0.6.8
|
||||
sympy==1.12
|
||||
tensorboard==2.16.2
|
||||
tensorboard-data-server==0.7.2
|
||||
thinc==8.2.3
|
||||
threadpoolctl==3.4.0
|
||||
tokenizers==0.15.2
|
||||
toolz==0.12.1
|
||||
torch>=2.2.0
|
||||
torchaudio>=2.2.0
|
||||
tqdm==4.66.2
|
||||
trainer==0.0.36
|
||||
transformers==4.39.1
|
||||
TTS==0.22.0
|
||||
typer==0.9.4
|
||||
typing_extensions==4.10.0
|
||||
tzdata==2024.1
|
||||
tzlocal==5.2
|
||||
umap-learn==0.5.5
|
||||
Unidecode==1.3.8
|
||||
unidic-lite==1.0.8
|
||||
urllib3==2.2.1
|
||||
uvicorn==0.29.0
|
||||
wasabi==1.1.2
|
||||
weasel==0.3.4
|
||||
websockets==11.0.3
|
||||
Werkzeug==3.0.1
|
||||
yarl==1.9.4
|
||||
zipp==3.18.1
|
||||
@@ -1,36 +1,25 @@
|
||||
coqui-tts==0.24.3
|
||||
ffmpeg-python>=0.2.0
|
||||
filelock>=3.16.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
importlib_metadata>=7.1.0
|
||||
inputimeout>=1.0.4
|
||||
Jinja2>=3.1.0
|
||||
librosa>=0.10.2.post1
|
||||
local_attention>=1.9.0
|
||||
onnxruntime-gpu>=1.18.0
|
||||
openai-whisper
|
||||
pydantic>=2.7.0
|
||||
python-Levenshtein>=0.25.1
|
||||
praat-parselmouth>=0.4.0
|
||||
pyworld>=0.3.0
|
||||
sounddevice>=0.4.7
|
||||
soundfile>=0.12.0
|
||||
spacy>=3.7.1
|
||||
torchcrepe>=0.0.2
|
||||
tqdm>=4.66.0
|
||||
numpy>=1.22.0
|
||||
soundfile>=0.12.1
|
||||
uvicorn>=0.24.0.post1
|
||||
transformers>=4.37.1
|
||||
TTS>=0.22.0
|
||||
torch>=2.1.0
|
||||
torchaudio>=2.1.0
|
||||
fastapi>=0.104.1
|
||||
Jinja2>=3.1.2
|
||||
requests>=2.31.0
|
||||
tqdm>=4.66.1
|
||||
importlib-metadata>=4.8.1
|
||||
packaging>=23.2
|
||||
pydantic>=1.10.13
|
||||
sounddevice>=0.4.6
|
||||
python-multipart>=0.0.6
|
||||
cutlet>=0.3.0
|
||||
unidic-lite>=1.0.8
|
||||
uvicorn>=0.29.0
|
||||
pypinyin>=0.52.0
|
||||
hangul_romanize>=0.1.0
|
||||
word2number>=1.1
|
||||
cutlet==0.4.0
|
||||
fugashi==1.3.1
|
||||
./system/config/fairseq-0.12.4-cp311-cp311-win_amd64.whl; sys_platform == "win32"
|
||||
./system/config/fairseq-0.12.3.1-cp311-cp311-linux_x86_64.whl; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "darwin"
|
||||
piper-phonemize==1.1.0; sys_platform == "darwin"
|
||||
plotly==5.24.1
|
||||
scipy==1.14.1
|
||||
pyOpenSSL>=24.2.1
|
||||
langdetect>=1.0.9
|
||||
faster-whisper>=0.10.0
|
||||
pandas>=1.5.0
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
fuzzywuzzy>=0.18.0
|
||||
python-Levenshtein>=0.25.0
|
||||
spacy>=3.7.2
|
||||
@@ -1,5 +0,0 @@
|
||||
jsonlines>=4.0.0
|
||||
networkx>=3.0.0
|
||||
protobuf==4.25.3
|
||||
typing_extensions>=4.9.0
|
||||
pillow==10.3.0
|
||||
@@ -1,4 +0,0 @@
|
||||
filelock>=3.16.1
|
||||
pydantic>=2.7.0
|
||||
pytest>=8.3.3
|
||||
pytest-cov>=6.0.0
|
||||
@@ -281,7 +281,7 @@ class AllTalkTtsProvider {
|
||||
if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
|
||||
}
|
||||
const modelSelect = document.getElementById('switch_model');
|
||||
if (this.settings.finetuned_model === 'true') {
|
||||
if (this.settings.finetuned_model === true) {
|
||||
const ftOption = document.createElement('option');
|
||||
ftOption.value = 'XTTSv2 FT';
|
||||
ftOption.textContent = 'XTTSv2 FT';
|
||||
@@ -695,7 +695,7 @@ class AllTalkTtsProvider {
|
||||
const data = await response.json();
|
||||
if (data.output_file_url) {
|
||||
// Use an audio element to play the .wav file
|
||||
const audioElement = new Audio(`${this.settings.provider_endpoint}${data.output_file_url}`);
|
||||
const audioElement = new Audio(data.output_file_url);
|
||||
audioElement.play().catch(e => console.error("Error playing audio:", e));
|
||||
} else {
|
||||
console.warn("[previewTtsVoice] No output file URL received in the response");
|
||||
@@ -798,8 +798,7 @@ class AllTalkTtsProvider {
|
||||
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
//const outputUrl = data.output_file_url;
|
||||
const outputUrl = `${this.settings.provider_endpoint}${data.output_file_url}`;
|
||||
const outputUrl = data.output_file_url;
|
||||
return outputUrl; // Return only the output_file_url
|
||||
} catch (error) {
|
||||
console.error("[fetchTtsGeneration] Exception caught:", error);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,159 @@
|
||||
#tts_media_control {
|
||||
/* order: 100; */
|
||||
/* width: 40px;
|
||||
height: 40px;
|
||||
margin: 0;
|
||||
padding: 1px; */
|
||||
outline: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
/* transition: 0.3s;
|
||||
opacity: 0.7; */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* justify-content: center; */
|
||||
|
||||
}
|
||||
|
||||
#ttsExtensionMenuItem {
|
||||
transition: 0.3s;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
#ttsExtensionMenuItem:hover {
|
||||
opacity: 1;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
|
||||
#tts_media_control:hover {
|
||||
opacity: 1;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
|
||||
.voice_preview {
|
||||
margin: 0.25rem 0.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.voice_preview .voice_name {
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.voice_preview .voice_lang {
|
||||
width: 4rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.voice_preview .fa-play {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tts-button {
|
||||
margin: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
opacity: 0.7;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.tts-button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tts_block {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
column-gap: 5px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tts_custom_voices {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.novel_tts_hints {
|
||||
font-size: calc(0.9 * var(--mainFontSize));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.at-settings-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.at-settings-option {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.at-endpoint-option {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
margin-right: 25px;
|
||||
width: 38%;
|
||||
}
|
||||
|
||||
.at-website-row {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.at-website-option {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.at-settings-separator {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 18x;
|
||||
font-weight: bold;
|
||||
border-top: 1px solid #e1e1e1; /* Grey line */
|
||||
border-bottom: 1px solid #e1e1e1; /* Grey line */
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.at-status-message {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.at-model-endpoint-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.at-model-option, .endpoint-option {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.at-endpoint-option {
|
||||
width: 38%;
|
||||
}
|
||||
|
||||
#at-status_info {
|
||||
color: lightgreen;
|
||||
}
|
||||
Loaded 100 of 586 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user