Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c20f45154 | ||
|
|
97cda27c7e | ||
|
|
a075495a0a | ||
|
|
b205657be3 | ||
|
|
483d6c8e79 | ||
|
|
9bd4665e6b | ||
|
|
62e1ab7e89 | ||
|
|
740c54db1c | ||
|
|
e188467730 | ||
|
|
743f23240e | ||
|
|
66dadbca25 | ||
|
|
8125b46dbe | ||
|
|
d4bd46f203 | ||
|
|
f13d6d336b | ||
|
|
1fa2f2e110 | ||
|
|
9ad4005e52 | ||
|
|
6d6b92d4b2 | ||
|
|
bf5d913cae | ||
|
|
f52ccd3931 | ||
|
|
37e7c8002d | ||
|
|
ad7382ee68 | ||
|
|
2428bfe357 | ||
|
|
74f3acc51f | ||
|
|
90a98f140b | ||
|
|
885311ecd8 | ||
|
|
c2952e9758 | ||
|
|
7e6e18c6d9 | ||
|
|
47eafafeda | ||
|
|
5edaab1356 | ||
|
|
7bde34d2ce | ||
|
|
0aa4638f68 | ||
|
|
22dd9c741c | ||
|
|
e000b8bb87 | ||
|
|
2d26f309df | ||
|
|
22d3e53a28 | ||
|
|
0ea646dbf3 | ||
|
|
282e3ce84c | ||
|
|
772afd47a1 | ||
|
|
1612835c5d | ||
|
|
ea551d3a84 | ||
|
|
47001203cd | ||
|
|
27ff5a12b0 | ||
|
|
0a89407e4d | ||
|
|
a579c5e6d2 | ||
|
|
5a21d14672 | ||
|
|
f4f5f82bb0 | ||
|
|
7b03804f9e | ||
|
|
f46493e6d8 | ||
|
|
2a64f6ad2b | ||
|
|
3368f8b016 | ||
|
|
121585ae84 | ||
|
|
3e6c11740d | ||
|
|
6b111494b3 | ||
|
|
b376a27da2 | ||
|
|
eeec4de703 | ||
|
|
49f98033b3 | ||
|
|
c1470930f4 | ||
|
|
1dec4f027b | ||
|
|
a9ef8edcb4 | ||
|
|
299238be7d | ||
|
|
29c7ea1526 | ||
|
|
e974e14a10 | ||
|
|
59c654bacd | ||
|
|
969b4e3f46 | ||
|
|
86c64fc9ba | ||
|
|
b8c0db6f56 | ||
|
|
57982cb810 | ||
|
|
6387007f56 | ||
|
|
cdf8d695e2 | ||
|
|
833bf3da4f | ||
|
|
f68086db0b | ||
|
|
1f7842ef5a | ||
|
|
9bb0d1fa58 | ||
|
|
015b9033ec | ||
|
|
7f261bb5e9 | ||
|
|
00b93cfe1b | ||
|
|
c0d01ee931 | ||
|
|
d0ceb2bb65 | ||
|
|
3231e61d56 | ||
|
|
32f3b721c2 | ||
|
|
8c588939d2 | ||
|
|
ff1077f282 | ||
|
|
36d0e92ed9 | ||
|
|
8dfb84d7e2 | ||
|
|
4caecdc5eb | ||
|
|
40f2fbf54e | ||
|
|
ab37dd8849 | ||
|
|
03b02e0e4c | ||
|
|
351f46c7b5 | ||
|
|
71ba584e7c | ||
|
|
b3f53e93cc | ||
|
|
0ed3cb75b5 | ||
|
|
c29de18ad4 | ||
|
|
ec1d0e8c5d | ||
|
|
12bf008b3f | ||
|
|
ecdc10ece5 | ||
|
|
360f70cb0a | ||
|
|
51c91c3d70 | ||
|
|
81a9f4c847 | ||
|
|
cdce7511dc | ||
|
|
6d4b6d336b | ||
|
|
6c4a9b19c7 | ||
|
|
82ecf3eecc | ||
|
|
d750959f52 | ||
|
|
bd74de53da | ||
|
|
fcec9d8f5b | ||
|
|
85e5e6ab86 | ||
|
|
d15931bdda | ||
|
|
abc9cf1fb7 | ||
|
|
2b60f5b0da | ||
|
|
e524063ec2 | ||
|
|
d93906a75f | ||
|
|
ad57deed20 | ||
|
|
d0866e3c6c | ||
|
|
af907a299d | ||
|
|
7928af1bb7 | ||
|
|
4d837a0219 | ||
|
|
e50817a234 | ||
|
|
c3bb58d2af | ||
|
|
c17959f142 | ||
|
|
def2d51c5f | ||
|
|
6166d4f751 | ||
|
|
cd164ae258 | ||
|
|
f089e3e85b | ||
|
|
d008c7ab0a | ||
|
|
a199adfbd6 | ||
|
|
61998b4d39 | ||
|
|
55799b2de8 | ||
|
|
ece55ffe06 | ||
|
|
dbc2582fa6 | ||
|
|
535c9b652a | ||
|
|
6c28d58b4a | ||
|
|
c9a222932c | ||
|
|
7010369966 | ||
|
|
525a337835 | ||
|
|
2bd1ef843e | ||
|
|
a9d95fc563 | ||
|
|
1a37ae4ba5 | ||
|
|
8c6fc4853d | ||
|
|
f34ebbd675 | ||
|
|
64cffcdf80 | ||
|
|
2731a559f4 | ||
|
|
a91a83268f | ||
|
|
5d406fbbfb | ||
|
|
cefd1e045b | ||
|
|
bec4e905d3 | ||
|
|
f5e99a5e72 | ||
|
|
631ea6dd8a | ||
|
|
08a04ba506 | ||
|
|
c78927b80a | ||
|
|
04e08c58b8 | ||
|
|
893747c9a9 | ||
|
|
d52dcf86d5 | ||
|
|
ad0eab1224 | ||
|
|
62d1cc05d3 | ||
|
|
b8292da92f | ||
|
|
180adb45dd | ||
|
|
5c0f08d49e | ||
|
|
571872dbe2 | ||
|
|
467bfbea55 | ||
|
|
5a3cbb6366 | ||
|
|
2351e418fd | ||
|
|
b987ff38a7 | ||
|
|
43899028e3 | ||
|
|
2c1ca8b2a3 | ||
|
|
139162c4e6 | ||
|
|
7da78ec045 | ||
|
|
11c70c7432 | ||
|
|
c2822edb1b | ||
|
|
cba7ed7b88 | ||
|
|
471a26f2a4 | ||
|
|
34d1b81ae4 | ||
|
|
f1b4d4b8b6 | ||
|
|
c05237143b | ||
|
|
c5846b832a | ||
|
|
7a38730c56 | ||
|
|
0b1e6f8711 | ||
|
|
8c38e925dd | ||
|
|
df70481934 | ||
|
|
e43c58a56e | ||
|
|
8dc9304a4c | ||
|
|
102424669b | ||
|
|
5210d075c1 | ||
|
|
30db974439 | ||
|
|
c2a558110b | ||
|
|
83ac18b83f | ||
|
|
6e36415746 | ||
|
|
fe7ffb535c | ||
|
|
80b7fccb50 | ||
|
|
2790ee9860 | ||
|
|
74ce2584cc | ||
|
|
8dd11541b4 | ||
|
|
d1317b49f0 | ||
|
|
a50d5a5028 | ||
|
|
33264554cd | ||
|
|
4a116e359a | ||
|
|
36bfb17eda | ||
|
|
697fb098c3 | ||
|
|
51a8e93df7 | ||
|
|
257fa59e70 | ||
|
|
7dbad85fc3 | ||
|
|
510894c793 | ||
|
|
a85058a3ac | ||
|
|
e54c7e4362 | ||
|
|
1f2ad303a0 | ||
|
|
d4a04096c8 | ||
|
|
dd45008e88 | ||
|
|
e9d9f54de6 | ||
|
|
3230397a82 | ||
|
|
840889ac9a | ||
|
|
d3e061b127 | ||
|
|
a428f67a2e | ||
|
|
b223e7b247 | ||
|
|
9296843508 | ||
|
|
f0c9e3e6bb | ||
|
|
22de1bf0c6 | ||
|
|
621f5434a7 | ||
|
|
81c8354cf8 | ||
|
|
3bc55a91e5 | ||
|
|
fc857f464c | ||
|
|
50aa6de96c | ||
|
|
10299194f8 | ||
|
|
d80d1ace3c | ||
|
|
f19f4e9a29 | ||
|
|
7e4ceef0e8 | ||
|
|
c1bc1f26cd | ||
|
|
70d385133d | ||
|
|
13b2eb5fe3 | ||
|
|
ff4b9d9e99 | ||
|
|
a22830f700 | ||
|
|
374c794fa9 | ||
|
|
d2adbd9c1e | ||
|
|
1dc4b8bf50 | ||
|
|
0eba72fc47 | ||
|
|
f2c87dcdab | ||
|
|
4a727ce14a | ||
|
|
6e15d43e63 | ||
|
|
dedc13b3b6 | ||
|
|
7cb206e531 | ||
|
|
4f80b39cd0 | ||
|
|
d5fa6bb46d | ||
|
|
332582baea | ||
|
|
2bd7ebc514 | ||
|
|
e5acc8bdbd | ||
|
|
7718bfd3ea | ||
|
|
002c5ad9db | ||
|
|
2c14847708 | ||
|
|
3647d69007 | ||
|
|
56a7ea1d8f | ||
|
|
863a7cd841 | ||
|
|
2e1709ab58 | ||
|
|
9c4efdc135 | ||
|
|
28675c976c | ||
|
|
afe3b9fe0b | ||
|
|
2e4d52170d | ||
|
|
0e2cc25571 | ||
|
|
abaa56e8f4 | ||
|
|
d0dc9f3212 | ||
|
|
67dcc411ad | ||
|
|
b11a087dc8 | ||
|
|
e068115eef | ||
|
|
0ec580539a | ||
|
|
e9feae12ad | ||
|
|
e183e3a7bb | ||
|
|
8a2b669da9 | ||
|
|
67d2b1c5ea | ||
|
|
f3b44424ef | ||
|
|
3b5c4b9b68 | ||
|
|
e452a926f2 | ||
|
|
b65291d44d | ||
|
|
b28ecaf43e | ||
|
|
ba1328311c | ||
|
|
9e6b9396bc | ||
|
|
2e40db5fe5 | ||
|
|
720bf8697f | ||
|
|
1893d1a130 | ||
|
|
8472baf031 | ||
|
|
6cab618706 | ||
|
|
ebf3b362f7 | ||
|
|
2dd303f53c | ||
|
|
df69fb0b07 | ||
|
|
a0d9771fa6 | ||
|
|
a71c46bb98 | ||
|
|
995f317b4f | ||
|
|
6ef2de2923 | ||
|
|
37c4e86566 | ||
|
|
11071b279b | ||
|
|
5ab7463f35 | ||
|
|
74c9238e3a | ||
|
|
e874e46304 |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
ko_fi: erew123
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
---
|
---
|
||||||
name: Bug report/Support request
|
name: Support request OR Bug report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
title: ''
|
title: ''
|
||||||
labels: ''
|
labels: ''
|
||||||
assignees: ''
|
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".
|
🔴 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
|
https://github.com/erew123/alltalk_tts/tree/main?#-how-to-make-a-diagnostics-report-file
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
name: Publish Docker image
|
||||||
|
|
||||||
|
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 }}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"*.html": "jinja-html"
|
||||||
|
},
|
||||||
|
"emmet.includeLanguages": {
|
||||||
|
"jinja-html": "html",
|
||||||
|
"jinja2": "html"
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,285 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// DeepSpeed Team
|
|
||||||
|
|
||||||
#include <ATen/cuda/CUDAContext.h>
|
|
||||||
#include <torch/extension.h>
|
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
|
||||||
#include "quantization.h"
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_quantize(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if ((((size / groups) - 1) / 4096 + 1) <= 256) {
|
|
||||||
launch_fake_quantize_kernel(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_sr_quantize(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if (((size / groups) / 4 / 1024) <= 256) {
|
|
||||||
launch_sr_fake_quantize_kernel(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_quantize_asym(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if ((((size / groups) - 1) / 4096 + 1) <= 256) {
|
|
||||||
launch_fake_quantize_kernel_asym(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_sr_quantize_asym(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if (((size / groups) / 4 / 1024) <= 256) {
|
|
||||||
launch_sr_fake_quantize_kernel_asym(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<at::Tensor> quantize_kernel(at::Tensor& input_vals,
|
|
||||||
int groups,
|
|
||||||
int numBits,
|
|
||||||
quantize::Type quantType)
|
|
||||||
{
|
|
||||||
auto dtype = at::kFloat;
|
|
||||||
auto params_options = at::TensorOptions()
|
|
||||||
.dtype(dtype)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
const int param_elems = (quantize::requires_offset(quantType)) ? 2 : 1;
|
|
||||||
auto params = torch::empty({groups, param_elems}, params_options);
|
|
||||||
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(at::kChar)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
auto output_sizes = input_vals.sizes().vec();
|
|
||||||
output_sizes[output_sizes.size() - 1] /= numBits == 8 ? 1 : 2;
|
|
||||||
auto output = torch::empty(output_sizes, output_options);
|
|
||||||
|
|
||||||
const int elems_per_group = at::numel(input_vals) / groups;
|
|
||||||
|
|
||||||
launch_quant((int8_t*)output.data_ptr(),
|
|
||||||
(float*)params.data_ptr(),
|
|
||||||
(__half*)input_vals.data_ptr(),
|
|
||||||
groups,
|
|
||||||
elems_per_group,
|
|
||||||
numBits,
|
|
||||||
quantType,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return {output, params};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor dequantize(at::Tensor& quantized_data,
|
|
||||||
at::Tensor& params,
|
|
||||||
int groups,
|
|
||||||
int num_bits,
|
|
||||||
quantize::Type quant_type)
|
|
||||||
{
|
|
||||||
auto dtype = (std::is_same<T, float>::value) ? torch::kFloat32 : torch::kFloat16;
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(dtype)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
auto output_sizes = quantized_data.sizes().vec();
|
|
||||||
output_sizes[output_sizes.size() - 1] *= num_bits == 8 ? 1 : 2;
|
|
||||||
auto output = torch::empty(output_sizes, output_options);
|
|
||||||
|
|
||||||
const int total_elems = at::numel(output);
|
|
||||||
const int elems_per_group = total_elems / groups;
|
|
||||||
|
|
||||||
launch_dequantize_kernel((T*)output.data_ptr(),
|
|
||||||
(const int8_t*)quantized_data.data_ptr(),
|
|
||||||
(const float*)params.data_ptr(),
|
|
||||||
quant_type,
|
|
||||||
num_bits,
|
|
||||||
elems_per_group,
|
|
||||||
total_elems,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
at::Tensor dequantize_int4_to_half_experimental(at::Tensor& data_in,
|
|
||||||
at::Tensor& scale_buffer,
|
|
||||||
at::Tensor& min_val_buffer,
|
|
||||||
int num_group,
|
|
||||||
int group_size)
|
|
||||||
{
|
|
||||||
auto output_options = at::TensorOptions().dtype(at::kHalf).device(at::kCUDA);
|
|
||||||
auto output = torch::empty({num_group, group_size}, output_options);
|
|
||||||
|
|
||||||
launch_dequantize_int4_to_half_experimental((uint8_t*)data_in.data_ptr(),
|
|
||||||
(half*)output.data_ptr(),
|
|
||||||
(half*)scale_buffer.data_ptr(),
|
|
||||||
(half*)min_val_buffer.data_ptr(),
|
|
||||||
num_group,
|
|
||||||
group_size,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<at::Tensor> ds_swizzle_quant(at::Tensor& input_vals,
|
|
||||||
int groups,
|
|
||||||
int num_bits,
|
|
||||||
quantize::Type quant_type,
|
|
||||||
int pipeline_size,
|
|
||||||
int nodes,
|
|
||||||
int devices_per_node)
|
|
||||||
{
|
|
||||||
auto scales_options = at::TensorOptions()
|
|
||||||
.dtype(at::kFloat)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
const int scales_elems = (quantize::requires_offset(quant_type)) ? 2 : 1;
|
|
||||||
auto scales = torch::empty({groups, scales_elems}, scales_options);
|
|
||||||
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(at::kChar)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
const int quantization_scalar = 8 / num_bits;
|
|
||||||
const int compressed_vals = at::numel(input_vals) / quantization_scalar;
|
|
||||||
|
|
||||||
auto output = torch::empty({compressed_vals}, output_options);
|
|
||||||
const int elems_per_group = at::numel(input_vals) / groups;
|
|
||||||
|
|
||||||
launch_swizzled_quant((int8_t*)output.data_ptr(),
|
|
||||||
(float*)scales.data_ptr(),
|
|
||||||
(__half*)input_vals.data_ptr(),
|
|
||||||
num_bits,
|
|
||||||
quant_type,
|
|
||||||
groups,
|
|
||||||
elems_per_group,
|
|
||||||
pipeline_size,
|
|
||||||
nodes,
|
|
||||||
devices_per_node,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return {output, scales};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<at::Tensor> quantized_reduction(at::Tensor& input_vals,
|
|
||||||
at::Tensor& input_scales,
|
|
||||||
int in_groups,
|
|
||||||
int out_groups,
|
|
||||||
int num_bits,
|
|
||||||
quantize::Type quant_type,
|
|
||||||
int devices_per_node)
|
|
||||||
{
|
|
||||||
auto scales_options = at::TensorOptions()
|
|
||||||
.dtype(at::kFloat)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
const int scales_elems = (quantize::requires_offset(quant_type)) ? 2 : 1;
|
|
||||||
auto scales = torch::empty({out_groups, scales_elems}, scales_options);
|
|
||||||
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(at::kChar)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
std::vector<int64_t> sz_vector(input_vals.sizes().begin(), input_vals.sizes().end());
|
|
||||||
sz_vector[sz_vector.size() - 1] = sz_vector.back() / devices_per_node; // num of GPU per nodes
|
|
||||||
at::IntArrayRef sz(sz_vector);
|
|
||||||
auto output = torch::empty(sz, output_options);
|
|
||||||
|
|
||||||
const int elems_per_in_tensor = at::numel(input_vals) / devices_per_node;
|
|
||||||
const int elems_per_in_group = elems_per_in_tensor / (in_groups / devices_per_node);
|
|
||||||
const int elems_per_out_group = elems_per_in_tensor / out_groups;
|
|
||||||
|
|
||||||
// old code:
|
|
||||||
// std::vector<long int> sz(input_vals.sizes().begin(), input_vals.sizes().end());
|
|
||||||
// sz[sz.size() - 1] = sz.back() / devices_per_node; // num of GPU per nodes
|
|
||||||
// const int elems_per_in_tensor = at::numel(input_vals) / devices_per_node;
|
|
||||||
// auto output = torch::empty(sz, output_options);
|
|
||||||
|
|
||||||
// const int elems_per_in_group = elems_per_in_tensor / (in_groups / devices_per_node);
|
|
||||||
// const int elems_per_out_group = elems_per_in_tensor / out_groups;
|
|
||||||
|
|
||||||
launch_dequant_reduce((int8_t*)output.data_ptr(),
|
|
||||||
(float*)scales.data_ptr(),
|
|
||||||
(const int8_t*)input_vals.data_ptr(),
|
|
||||||
(const float*)input_scales.data_ptr(),
|
|
||||||
devices_per_node,
|
|
||||||
num_bits,
|
|
||||||
quant_type,
|
|
||||||
out_groups,
|
|
||||||
elems_per_out_group,
|
|
||||||
elems_per_in_tensor,
|
|
||||||
in_groups / devices_per_node,
|
|
||||||
elems_per_in_group,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
return {output, scales};
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m)
|
|
||||||
{
|
|
||||||
m.def("ds_quantize_fp32", &ds_quantize<float>, "DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def("ds_quantize_fp16", &ds_quantize<__half>, "DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_fp32", &ds_sr_quantize<float>, "DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_fp16", &ds_sr_quantize<__half>, "DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
m.def("ds_quantize_asym_fp32", &ds_quantize_asym<float>, "DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def(
|
|
||||||
"ds_quantize_asym_fp16", &ds_quantize_asym<__half>, "DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_asym_fp32",
|
|
||||||
&ds_sr_quantize_asym<float>,
|
|
||||||
"DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_asym_fp16",
|
|
||||||
&ds_sr_quantize_asym<__half>,
|
|
||||||
"DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
pybind11::enum_<quantize::Type>(m, "QuantizationType")
|
|
||||||
.value("Symmetric", quantize::Type::Symmetric)
|
|
||||||
.value("Asymmetric", quantize::Type::Asymmetric)
|
|
||||||
.export_values();
|
|
||||||
m.def("quantize", &quantize_kernel);
|
|
||||||
m.def("dequantize", &dequantize<__half>);
|
|
||||||
m.def("dequantize_fp32", &dequantize<float>);
|
|
||||||
m.def("dequantize_int4_to_half_experimental",
|
|
||||||
&dequantize_int4_to_half_experimental,
|
|
||||||
"Dequantize int4 to half (experimental)");
|
|
||||||
m.def("swizzle_quant", &ds_swizzle_quant);
|
|
||||||
m.def("quantized_reduction", &quantized_reduction);
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
# Copyright (c) Microsoft Corporation.
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
# DeepSpeed Team
|
|
||||||
|
|
||||||
import os
|
|
||||||
import torch
|
|
||||||
import deepspeed
|
|
||||||
import subprocess
|
|
||||||
import argparse
|
|
||||||
import psutil
|
|
||||||
from .ops.op_builder.all_ops import ALL_OPS
|
|
||||||
from .git_version_info import installed_ops, torch_info
|
|
||||||
from deepspeed.accelerator import get_accelerator
|
|
||||||
|
|
||||||
GREEN = '\033[92m'
|
|
||||||
RED = '\033[91m'
|
|
||||||
YELLOW = '\033[93m'
|
|
||||||
END = '\033[0m'
|
|
||||||
SUCCESS = f"{GREEN} [SUCCESS] {END}"
|
|
||||||
OKAY = f"{GREEN}[OKAY]{END}"
|
|
||||||
WARNING = f"{YELLOW}[WARNING]{END}"
|
|
||||||
FAIL = f'{RED}[FAIL]{END}'
|
|
||||||
INFO = '[INFO]'
|
|
||||||
|
|
||||||
color_len = len(GREEN) + len(END)
|
|
||||||
okay = f"{GREEN}[OKAY]{END}"
|
|
||||||
warning = f"{YELLOW}[WARNING]{END}"
|
|
||||||
|
|
||||||
|
|
||||||
def op_report(verbose=True):
|
|
||||||
max_dots = 23
|
|
||||||
max_dots2 = 11
|
|
||||||
h = ["op name", "installed", "compatible"]
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
print("DeepSpeed C++/CUDA extension op report")
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
|
|
||||||
print("NOTE: Ops not installed will be just-in-time (JIT) compiled at\n"
|
|
||||||
" runtime if needed. Op compatibility means that your system\n"
|
|
||||||
" meet the required dependencies to JIT install the op.")
|
|
||||||
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
print("JIT compiled ops requires ninja")
|
|
||||||
ninja_status = OKAY if ninja_installed() else FAIL
|
|
||||||
print('ninja', "." * (max_dots - 5), ninja_status)
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
print(h[0], "." * (max_dots - len(h[0])), h[1], "." * (max_dots2 - len(h[1])), h[2])
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
installed = f"{GREEN}[YES]{END}"
|
|
||||||
no = f"{YELLOW}[NO]{END}"
|
|
||||||
for op_name, builder in ALL_OPS.items():
|
|
||||||
dots = "." * (max_dots - len(op_name))
|
|
||||||
is_compatible = OKAY if builder.is_compatible(verbose) else no
|
|
||||||
is_installed = installed if installed_ops.get(op_name, False) else no
|
|
||||||
dots2 = '.' * ((len(h[1]) + (max_dots2 - len(h[1]))) - (len(is_installed) - color_len))
|
|
||||||
print(op_name, dots, is_installed, dots2, is_compatible)
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
|
|
||||||
|
|
||||||
def ninja_installed():
|
|
||||||
try:
|
|
||||||
import ninja # noqa: F401 # type: ignore
|
|
||||||
except ImportError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def nvcc_version():
|
|
||||||
import torch.utils.cpp_extension
|
|
||||||
cuda_home = torch.utils.cpp_extension.CUDA_HOME
|
|
||||||
if cuda_home is None:
|
|
||||||
return f"{RED} [FAIL] cannot find CUDA_HOME via torch.utils.cpp_extension.CUDA_HOME={torch.utils.cpp_extension.CUDA_HOME} {END}"
|
|
||||||
try:
|
|
||||||
output = subprocess.check_output([cuda_home + "/bin/nvcc", "-V"], universal_newlines=True)
|
|
||||||
except FileNotFoundError:
|
|
||||||
return f"{RED} [FAIL] nvcc missing {END}"
|
|
||||||
output_split = output.split()
|
|
||||||
release_idx = output_split.index("release")
|
|
||||||
release = output_split[release_idx + 1].replace(',', '').split(".")
|
|
||||||
return ".".join(release)
|
|
||||||
|
|
||||||
|
|
||||||
def get_shm_size():
|
|
||||||
try:
|
|
||||||
temp_dir = os.getenv('TEMP') or os.getenv('TMP') or os.path.join(os.path.expanduser('~'), 'tmp')
|
|
||||||
shm_stats = psutil.disk_usage(temp_dir)
|
|
||||||
shm_size = shm_stats.total
|
|
||||||
shm_hbytes = human_readable_size(shm_size)
|
|
||||||
warn = []
|
|
||||||
if shm_size < 512 * 1024**2:
|
|
||||||
warn.append(
|
|
||||||
f" {YELLOW} [WARNING] Shared memory size might be too small, consider increasing it. {END}"
|
|
||||||
)
|
|
||||||
# Add additional warnings specific to your use case if needed.
|
|
||||||
return shm_hbytes, warn
|
|
||||||
except Exception as e:
|
|
||||||
return "UNKNOWN", [f"Error getting shared memory size: {e}"]
|
|
||||||
|
|
||||||
def human_readable_size(size):
|
|
||||||
units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
||||||
i = 0
|
|
||||||
while size >= 1024 and i < len(units) - 1:
|
|
||||||
size /= 1024
|
|
||||||
i += 1
|
|
||||||
return f'{size:.2f} {units[i]}'
|
|
||||||
|
|
||||||
|
|
||||||
def debug_report():
|
|
||||||
max_dots = 33
|
|
||||||
|
|
||||||
report = [("torch install path", torch.__path__), ("torch version", torch.__version__),
|
|
||||||
("deepspeed install path", deepspeed.__path__),
|
|
||||||
("deepspeed info", f"{deepspeed.__version__}, {deepspeed.__git_hash__}, {deepspeed.__git_branch__}")]
|
|
||||||
if get_accelerator().device_name() == 'cuda':
|
|
||||||
hip_version = getattr(torch.version, "hip", None)
|
|
||||||
report.extend([("torch cuda version", torch.version.cuda), ("torch hip version", hip_version),
|
|
||||||
("nvcc version", (None if hip_version else nvcc_version())),
|
|
||||||
("deepspeed wheel compiled w.", f"torch {torch_info['version']}, " +
|
|
||||||
(f"hip {torch_info['hip_version']}" if hip_version else f"cuda {torch_info['cuda_version']}"))
|
|
||||||
])
|
|
||||||
else:
|
|
||||||
report.extend([("deepspeed wheel compiled w.", f"torch {torch_info['version']} ")])
|
|
||||||
|
|
||||||
report.append(("shared memory (/dev/shm) size", get_shm_size()))
|
|
||||||
|
|
||||||
print("DeepSpeed general environment info:")
|
|
||||||
for name, value in report:
|
|
||||||
warns = []
|
|
||||||
if isinstance(value, tuple):
|
|
||||||
value, warns = value
|
|
||||||
print(name, "." * (max_dots - len(name)), value)
|
|
||||||
if warns:
|
|
||||||
for warn in warns:
|
|
||||||
print(warn)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('--hide_operator_status',
|
|
||||||
action='store_true',
|
|
||||||
help='Suppress display of installation and compatibility statuses of DeepSpeed operators. ')
|
|
||||||
parser.add_argument('--hide_errors_and_warnings', action='store_true', help='Suppress warning and error messages.')
|
|
||||||
args = parser.parse_args()
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def main(hide_operator_status=False, hide_errors_and_warnings=False):
|
|
||||||
if not hide_operator_status:
|
|
||||||
op_report(verbose=not hide_errors_and_warnings)
|
|
||||||
debug_report()
|
|
||||||
|
|
||||||
|
|
||||||
def cli_main():
|
|
||||||
args = parse_arguments()
|
|
||||||
main(hide_operator_status=args.hide_operator_status, hide_errors_and_warnings=args.hide_errors_and_warnings)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// DeepSpeed Team
|
|
||||||
|
|
||||||
#include <ATen/cuda/CUDAContext.h>
|
|
||||||
#include <torch/extension.h>
|
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
|
||||||
#include "quantization.h"
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_quantize(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if ((((size / groups) - 1) / 4096 + 1) <= 256) {
|
|
||||||
launch_fake_quantize_kernel(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_sr_quantize(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if (((size / groups) / 4 / 1024) <= 256) {
|
|
||||||
launch_sr_fake_quantize_kernel(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_quantize_asym(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if ((((size / groups) - 1) / 4096 + 1) <= 256) {
|
|
||||||
launch_fake_quantize_kernel_asym(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor ds_sr_quantize_asym(at::Tensor& vals, int groups, int bits)
|
|
||||||
{
|
|
||||||
auto t_size = vals.sizes();
|
|
||||||
int size = 1;
|
|
||||||
for (auto dim : t_size) size *= dim;
|
|
||||||
|
|
||||||
if (((size / groups) / 4 / 1024) <= 256) {
|
|
||||||
launch_sr_fake_quantize_kernel_asym(
|
|
||||||
(T*)vals.data_ptr(), size, groups, bits, at::cuda::getCurrentCUDAStream());
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<at::Tensor> quantize_kernel(at::Tensor& input_vals,
|
|
||||||
int groups,
|
|
||||||
int numBits,
|
|
||||||
quantize::Type quantType)
|
|
||||||
{
|
|
||||||
auto dtype = at::kFloat;
|
|
||||||
auto params_options = at::TensorOptions()
|
|
||||||
.dtype(dtype)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
const int param_elems = (quantize::requires_offset(quantType)) ? 2 : 1;
|
|
||||||
auto params = torch::empty({groups, param_elems}, params_options);
|
|
||||||
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(at::kChar)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
auto output_sizes = input_vals.sizes().vec();
|
|
||||||
output_sizes[output_sizes.size() - 1] /= numBits == 8 ? 1 : 2;
|
|
||||||
auto output = torch::empty(output_sizes, output_options);
|
|
||||||
|
|
||||||
const int elems_per_group = at::numel(input_vals) / groups;
|
|
||||||
|
|
||||||
launch_quant((int8_t*)output.data_ptr(),
|
|
||||||
(float*)params.data_ptr(),
|
|
||||||
(__half*)input_vals.data_ptr(),
|
|
||||||
groups,
|
|
||||||
elems_per_group,
|
|
||||||
numBits,
|
|
||||||
quantType,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return {output, params};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
at::Tensor dequantize(at::Tensor& quantized_data,
|
|
||||||
at::Tensor& params,
|
|
||||||
int groups,
|
|
||||||
int num_bits,
|
|
||||||
quantize::Type quant_type)
|
|
||||||
{
|
|
||||||
auto dtype = (std::is_same<T, float>::value) ? torch::kFloat32 : torch::kFloat16;
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(dtype)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
auto output_sizes = quantized_data.sizes().vec();
|
|
||||||
output_sizes[output_sizes.size() - 1] *= num_bits == 8 ? 1 : 2;
|
|
||||||
auto output = torch::empty(output_sizes, output_options);
|
|
||||||
|
|
||||||
const int total_elems = at::numel(output);
|
|
||||||
const int elems_per_group = total_elems / groups;
|
|
||||||
|
|
||||||
launch_dequantize_kernel((T*)output.data_ptr(),
|
|
||||||
(const int8_t*)quantized_data.data_ptr(),
|
|
||||||
(const float*)params.data_ptr(),
|
|
||||||
quant_type,
|
|
||||||
num_bits,
|
|
||||||
elems_per_group,
|
|
||||||
total_elems,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
at::Tensor dequantize_int4_to_half_experimental(at::Tensor& data_in,
|
|
||||||
at::Tensor& scale_buffer,
|
|
||||||
at::Tensor& min_val_buffer,
|
|
||||||
int num_group,
|
|
||||||
int group_size)
|
|
||||||
{
|
|
||||||
auto output_options = at::TensorOptions().dtype(at::kHalf).device(at::kCUDA);
|
|
||||||
auto output = torch::empty({num_group, group_size}, output_options);
|
|
||||||
|
|
||||||
launch_dequantize_int4_to_half_experimental((uint8_t*)data_in.data_ptr(),
|
|
||||||
(half*)output.data_ptr(),
|
|
||||||
(half*)scale_buffer.data_ptr(),
|
|
||||||
(half*)min_val_buffer.data_ptr(),
|
|
||||||
num_group,
|
|
||||||
group_size,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
at::Tensor dequantize_int8_to_half_experimental(at::Tensor& data_in,
|
|
||||||
at::Tensor& scale_buffer,
|
|
||||||
at::Tensor& min_val_buffer,
|
|
||||||
int num_group,
|
|
||||||
int group_size)
|
|
||||||
{
|
|
||||||
auto output_options = at::TensorOptions().dtype(at::kHalf).device(at::kCUDA);
|
|
||||||
auto output = torch::empty({num_group, group_size}, output_options);
|
|
||||||
|
|
||||||
launch_dequantize_int8_to_half_experimental((uint8_t*)data_in.data_ptr(),
|
|
||||||
(half*)output.data_ptr(),
|
|
||||||
(half*)scale_buffer.data_ptr(),
|
|
||||||
(half*)min_val_buffer.data_ptr(),
|
|
||||||
num_group,
|
|
||||||
group_size,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<at::Tensor> ds_swizzle_quant(at::Tensor& input_vals,
|
|
||||||
int groups,
|
|
||||||
int num_bits,
|
|
||||||
quantize::Type quant_type,
|
|
||||||
int pipeline_size,
|
|
||||||
int nodes,
|
|
||||||
int devices_per_node)
|
|
||||||
{
|
|
||||||
auto scales_options = at::TensorOptions()
|
|
||||||
.dtype(at::kFloat)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
const int scales_elems = (quantize::requires_offset(quant_type)) ? 2 : 1;
|
|
||||||
auto scales = torch::empty({groups, scales_elems}, scales_options);
|
|
||||||
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(at::kChar)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
const int quantization_scalar = 8 / num_bits;
|
|
||||||
const int compressed_vals = at::numel(input_vals) / quantization_scalar;
|
|
||||||
|
|
||||||
auto output = torch::empty({compressed_vals}, output_options);
|
|
||||||
const int elems_per_group = at::numel(input_vals) / groups;
|
|
||||||
|
|
||||||
launch_swizzled_quant((int8_t*)output.data_ptr(),
|
|
||||||
(float*)scales.data_ptr(),
|
|
||||||
(__half*)input_vals.data_ptr(),
|
|
||||||
num_bits,
|
|
||||||
quant_type,
|
|
||||||
groups,
|
|
||||||
elems_per_group,
|
|
||||||
pipeline_size,
|
|
||||||
nodes,
|
|
||||||
devices_per_node,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
|
|
||||||
return {output, scales};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<at::Tensor> quantized_reduction(at::Tensor& input_vals,
|
|
||||||
at::Tensor& input_scales,
|
|
||||||
int in_groups,
|
|
||||||
int out_groups,
|
|
||||||
int num_bits,
|
|
||||||
quantize::Type quant_type,
|
|
||||||
int devices_per_node)
|
|
||||||
{
|
|
||||||
auto scales_options = at::TensorOptions()
|
|
||||||
.dtype(at::kFloat)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
const int scales_elems = (quantize::requires_offset(quant_type)) ? 2 : 1;
|
|
||||||
auto scales = torch::empty({out_groups, scales_elems}, scales_options);
|
|
||||||
|
|
||||||
auto output_options = at::TensorOptions()
|
|
||||||
.dtype(at::kChar)
|
|
||||||
.layout(at::kStrided)
|
|
||||||
.device(at::kCUDA)
|
|
||||||
.requires_grad(false);
|
|
||||||
|
|
||||||
std::vector<int64_t> sz_vector(input_vals.sizes().begin(), input_vals.sizes().end());
|
|
||||||
sz_vector[sz_vector.size() - 1] = sz_vector.back() / devices_per_node; // num of GPU per nodes
|
|
||||||
at::IntArrayRef sz(sz_vector);
|
|
||||||
auto output = torch::empty(sz, output_options);
|
|
||||||
|
|
||||||
const int elems_per_in_tensor = at::numel(input_vals) / devices_per_node;
|
|
||||||
const int elems_per_in_group = elems_per_in_tensor / (in_groups / devices_per_node);
|
|
||||||
const int elems_per_out_group = elems_per_in_tensor / out_groups;
|
|
||||||
|
|
||||||
launch_dequant_reduce((int8_t*)output.data_ptr(),
|
|
||||||
(float*)scales.data_ptr(),
|
|
||||||
(const int8_t*)input_vals.data_ptr(),
|
|
||||||
(const float*)input_scales.data_ptr(),
|
|
||||||
devices_per_node,
|
|
||||||
num_bits,
|
|
||||||
quant_type,
|
|
||||||
out_groups,
|
|
||||||
elems_per_out_group,
|
|
||||||
elems_per_in_tensor,
|
|
||||||
in_groups / devices_per_node,
|
|
||||||
elems_per_in_group,
|
|
||||||
at::cuda::getCurrentCUDAStream());
|
|
||||||
return {output, scales};
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m)
|
|
||||||
{
|
|
||||||
m.def("ds_quantize_fp32", &ds_quantize<float>, "DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def("ds_quantize_fp16", &ds_quantize<__half>, "DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_fp32", &ds_sr_quantize<float>, "DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_fp16", &ds_sr_quantize<__half>, "DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
m.def("ds_quantize_asym_fp32", &ds_quantize_asym<float>, "DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def(
|
|
||||||
"ds_quantize_asym_fp16", &ds_quantize_asym<__half>, "DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_asym_fp32",
|
|
||||||
&ds_sr_quantize_asym<float>,
|
|
||||||
"DeepSpeed Quantize with fp32 (CUDA)");
|
|
||||||
m.def("ds_sr_quantize_asym_fp16",
|
|
||||||
&ds_sr_quantize_asym<__half>,
|
|
||||||
"DeepSpeed Quantize with fp16 (CUDA)");
|
|
||||||
pybind11::enum_<quantize::Type>(m, "QuantizationType")
|
|
||||||
.value("Symmetric", quantize::Type::Symmetric)
|
|
||||||
.value("Asymmetric", quantize::Type::Asymmetric)
|
|
||||||
.export_values();
|
|
||||||
m.def("quantize", &quantize_kernel);
|
|
||||||
m.def("dequantize", &dequantize<__half>);
|
|
||||||
m.def("dequantize_fp32", &dequantize<float>);
|
|
||||||
m.def("dequantize_int4_to_half_experimental",
|
|
||||||
&dequantize_int4_to_half_experimental,
|
|
||||||
"Dequantize int4 to half (experimental)");
|
|
||||||
m.def("dequantize_int8_to_half_experimental",
|
|
||||||
&dequantize_int8_to_half_experimental,
|
|
||||||
"Dequantize int8 to half (experimental)");
|
|
||||||
m.def("swizzle_quant", &ds_swizzle_quant);
|
|
||||||
m.def("quantized_reduction", &quantized_reduction);
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
# Copyright (c) Microsoft Corporation.
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
# DeepSpeed Team
|
|
||||||
|
|
||||||
import os
|
|
||||||
import torch
|
|
||||||
import deepspeed
|
|
||||||
import subprocess
|
|
||||||
import argparse
|
|
||||||
import psutil
|
|
||||||
from .ops.op_builder.all_ops import ALL_OPS
|
|
||||||
from .git_version_info import installed_ops, torch_info
|
|
||||||
from deepspeed.accelerator import get_accelerator
|
|
||||||
|
|
||||||
GREEN = '\033[92m'
|
|
||||||
RED = '\033[91m'
|
|
||||||
YELLOW = '\033[93m'
|
|
||||||
END = '\033[0m'
|
|
||||||
SUCCESS = f"{GREEN} [SUCCESS] {END}"
|
|
||||||
OKAY = f"{GREEN}[OKAY]{END}"
|
|
||||||
WARNING = f"{YELLOW}[WARNING]{END}"
|
|
||||||
FAIL = f'{RED}[FAIL]{END}'
|
|
||||||
INFO = '[INFO]'
|
|
||||||
|
|
||||||
color_len = len(GREEN) + len(END)
|
|
||||||
okay = f"{GREEN}[OKAY]{END}"
|
|
||||||
warning = f"{YELLOW}[WARNING]{END}"
|
|
||||||
|
|
||||||
|
|
||||||
def op_report(verbose=True):
|
|
||||||
max_dots = 23
|
|
||||||
max_dots2 = 11
|
|
||||||
h = ["op name", "installed", "compatible"]
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
print("DeepSpeed C++/CUDA extension op report")
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
|
|
||||||
print("NOTE: Ops not installed will be just-in-time (JIT) compiled at\n"
|
|
||||||
" runtime if needed. Op compatibility means that your system\n"
|
|
||||||
" meet the required dependencies to JIT install the op.")
|
|
||||||
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
print("JIT compiled ops requires ninja")
|
|
||||||
ninja_status = OKAY if ninja_installed() else FAIL
|
|
||||||
print('ninja', "." * (max_dots - 5), ninja_status)
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
print(h[0], "." * (max_dots - len(h[0])), h[1], "." * (max_dots2 - len(h[1])), h[2])
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
installed = f"{GREEN}[YES]{END}"
|
|
||||||
no = f"{YELLOW}[NO]{END}"
|
|
||||||
for op_name, builder in ALL_OPS.items():
|
|
||||||
dots = "." * (max_dots - len(op_name))
|
|
||||||
is_compatible = OKAY if builder.is_compatible(verbose) else no
|
|
||||||
is_installed = installed if installed_ops.get(op_name, False) else no
|
|
||||||
dots2 = '.' * ((len(h[1]) + (max_dots2 - len(h[1]))) - (len(is_installed) - color_len))
|
|
||||||
print(op_name, dots, is_installed, dots2, is_compatible)
|
|
||||||
print("-" * (max_dots + max_dots2 + len(h[0]) + len(h[1])))
|
|
||||||
|
|
||||||
|
|
||||||
def ninja_installed():
|
|
||||||
try:
|
|
||||||
import ninja # noqa: F401 # type: ignore
|
|
||||||
except ImportError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def nvcc_version():
|
|
||||||
import torch.utils.cpp_extension
|
|
||||||
cuda_home = torch.utils.cpp_extension.CUDA_HOME
|
|
||||||
if cuda_home is None:
|
|
||||||
return f"{RED} [FAIL] cannot find CUDA_HOME via torch.utils.cpp_extension.CUDA_HOME={torch.utils.cpp_extension.CUDA_HOME} {END}"
|
|
||||||
try:
|
|
||||||
output = subprocess.check_output([cuda_home + "/bin/nvcc", "-V"], universal_newlines=True)
|
|
||||||
except FileNotFoundError:
|
|
||||||
return f"{RED} [FAIL] nvcc missing {END}"
|
|
||||||
output_split = output.split()
|
|
||||||
release_idx = output_split.index("release")
|
|
||||||
release = output_split[release_idx + 1].replace(',', '').split(".")
|
|
||||||
return ".".join(release)
|
|
||||||
|
|
||||||
|
|
||||||
def get_shm_size():
|
|
||||||
try:
|
|
||||||
temp_dir = os.getenv('TEMP') or os.getenv('TMP') or os.path.join(os.path.expanduser('~'), 'tmp')
|
|
||||||
shm_stats = psutil.disk_usage(temp_dir)
|
|
||||||
shm_size = shm_stats.total
|
|
||||||
shm_hbytes = human_readable_size(shm_size)
|
|
||||||
warn = []
|
|
||||||
if shm_size < 512 * 1024**2:
|
|
||||||
warn.append(
|
|
||||||
f" {YELLOW} [WARNING] Shared memory size might be too small, consider increasing it. {END}"
|
|
||||||
)
|
|
||||||
# Add additional warnings specific to your use case if needed.
|
|
||||||
return shm_hbytes, warn
|
|
||||||
except Exception as e:
|
|
||||||
return "UNKNOWN", [f"Error getting shared memory size: {e}"]
|
|
||||||
|
|
||||||
|
|
||||||
def human_readable_size(size):
|
|
||||||
units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
||||||
i = 0
|
|
||||||
while size >= 1024 and i < len(units) - 1:
|
|
||||||
size /= 1024
|
|
||||||
i += 1
|
|
||||||
return f'{size:.2f} {units[i]}'
|
|
||||||
|
|
||||||
|
|
||||||
def debug_report():
|
|
||||||
max_dots = 33
|
|
||||||
|
|
||||||
report = [("torch install path", torch.__path__), ("torch version", torch.__version__),
|
|
||||||
("deepspeed install path", deepspeed.__path__),
|
|
||||||
("deepspeed info", f"{deepspeed.__version__}, {deepspeed.__git_hash__}, {deepspeed.__git_branch__}")]
|
|
||||||
if get_accelerator().device_name() == 'cuda':
|
|
||||||
hip_version = getattr(torch.version, "hip", None)
|
|
||||||
report.extend([("torch cuda version", torch.version.cuda), ("torch hip version", hip_version),
|
|
||||||
("nvcc version", (None if hip_version else nvcc_version())),
|
|
||||||
("deepspeed wheel compiled w.", f"torch {torch_info['version']}, " +
|
|
||||||
(f"hip {torch_info['hip_version']}" if hip_version else f"cuda {torch_info['cuda_version']}"))
|
|
||||||
])
|
|
||||||
else:
|
|
||||||
report.extend([("deepspeed wheel compiled w.", f"torch {torch_info['version']} ")])
|
|
||||||
|
|
||||||
report.append(("shared memory (/dev/shm) size", get_shm_size()))
|
|
||||||
|
|
||||||
print("DeepSpeed general environment info:")
|
|
||||||
for name, value in report:
|
|
||||||
warns = []
|
|
||||||
if isinstance(value, tuple):
|
|
||||||
value, warns = value
|
|
||||||
print(name, "." * (max_dots - len(name)), value)
|
|
||||||
if warns:
|
|
||||||
for warn in warns:
|
|
||||||
print(warn)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('--hide_operator_status',
|
|
||||||
action='store_true',
|
|
||||||
help='Suppress display of installation and compatibility statuses of DeepSpeed operators. ')
|
|
||||||
parser.add_argument('--hide_errors_and_warnings', action='store_true', help='Suppress warning and error messages.')
|
|
||||||
args = parser.parse_args()
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def main(hide_operator_status=False, hide_errors_and_warnings=False):
|
|
||||||
if not hide_operator_status:
|
|
||||||
op_report(verbose=not hide_errors_and_warnings)
|
|
||||||
debug_report()
|
|
||||||
|
|
||||||
|
|
||||||
def cli_main():
|
|
||||||
args = parse_arguments()
|
|
||||||
main(hide_operator_status=args.hide_operator_status, hide_errors_and_warnings=args.hide_errors_and_warnings)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
These are the modified files you would need for a MANUAL build of DeepSpeed 11.1 or 11.2.
|
|
||||||
|
|
||||||
They were created by a mix of instructions from erew123 and S95Sedan.
|
|
||||||
|
|
||||||
|
|
||||||
- You still have to download the DeepSpeed v11.1 or v11.2 installation files from Microsoft to use these files.
|
|
||||||
|
|
||||||
https://github.com/microsoft/DeepSpeed/releases/tag/v0.11.2
|
|
||||||
|
|
||||||
|
|
||||||
- These files were provided by S95Sedan here:
|
|
||||||
|
|
||||||
https://github.com/S95Sedan/Deepspeed-Windows
|
|
||||||
|
|
||||||
|
|
||||||
- They are related to the manual build of DeepSpeed for AllTalk, which is linked here:
|
|
||||||
|
|
||||||
https://github.com/erew123/alltalk_tts/tree/main?tab=readme-ov-file#-option-2---a-bit-more-complicated
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FROM ubuntu:22.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 \
|
||||||
|
&& ln -s /usr/bin/python3 /usr/bin/python
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN pip install --no-cache-dir -r requirements_other.txt
|
||||||
|
EXPOSE 7851
|
||||||
|
RUN chmod +x launch.sh
|
||||||
|
ENTRYPOINT ["sh", "-c", "./launch.sh"]
|
||||||
@@ -0,0 +1,638 @@
|
|||||||
|
@echo off
|
||||||
|
cd /D "%~dp0"
|
||||||
|
|
||||||
|
set PATH=%PATH%;%SystemRoot%\system32
|
||||||
|
|
||||||
|
:: Generate the ESC character
|
||||||
|
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
|
||||||
|
|
||||||
|
:: Standard Colors
|
||||||
|
set "BLACK=%ESC%[30m"
|
||||||
|
set "RED=%ESC%[31m"
|
||||||
|
set "GREEN=%ESC%[32m"
|
||||||
|
set "YELLOW=%ESC%[33m"
|
||||||
|
set "BLUE=%ESC%[34m"
|
||||||
|
set "MAGENTA=%ESC%[35m"
|
||||||
|
set "CYAN=%ESC%[36m"
|
||||||
|
set "WHITE=%ESC%[37m"
|
||||||
|
set "L_BLACK=%ESC%[90m"
|
||||||
|
set "L_RED=%ESC%[91m"
|
||||||
|
set "L_GREEN=%ESC%[92m"
|
||||||
|
set "L_YELLOW=%ESC%[93m"
|
||||||
|
set "L_BLUE=%ESC%[94m"
|
||||||
|
set "L_MAGENTA=%ESC%[95m"
|
||||||
|
set "L_CYAN=%ESC%[96m"
|
||||||
|
set "L_WHITE=%ESC%[97m"
|
||||||
|
set "RESET=%ESC%[0m"
|
||||||
|
|
||||||
|
@rem Check if curl is available
|
||||||
|
curl --version >nul 2>&1
|
||||||
|
if "%ERRORLEVEL%" NEQ "0" (
|
||||||
|
echo curl is not available on this system. Please install curl then re-run the script https://curl.se/
|
||||||
|
echo or perform a manual installation of a Conda Python environment.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
:MainMenu
|
||||||
|
cls
|
||||||
|
echo.
|
||||||
|
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_GREEN%Standalone Application%RESET%
|
||||||
|
echo.
|
||||||
|
echo 9) %L_RED%Exit/Quit%RESET%
|
||||||
|
echo.
|
||||||
|
set /p UserOption=" Enter your choice: "
|
||||||
|
|
||||||
|
if "%UserOption%"=="1" goto WebUIMenu
|
||||||
|
if "%UserOption%"=="2" goto StandaloneMenu
|
||||||
|
if "%UserOption%"=="9" goto End
|
||||||
|
goto MainMenu
|
||||||
|
|
||||||
|
:WebUIMenu
|
||||||
|
cls
|
||||||
|
echo.
|
||||||
|
echo %L_BLUE%TEXT-GENERATION-WEBUI SETUP%RESET%
|
||||||
|
echo.
|
||||||
|
echo Please ensure you have started your Text-generation-webui Python
|
||||||
|
echo environment. If you have NOT done this, please run %L_GREEN%cmd_windows.bat%RESET%
|
||||||
|
echo in the %L_GREEN%text-generation-webui%RESET% folder and then re-run this script.
|
||||||
|
echo.
|
||||||
|
echo BASE REQUIREMENTS
|
||||||
|
echo 1) Apply/Re-Apply the requirements for %L_GREEN%Text-generation-webui%RESET%.
|
||||||
|
echo.
|
||||||
|
echo OPTIONAL
|
||||||
|
echo 2) Git Pull the latest AllTalk updates from Github
|
||||||
|
echo.
|
||||||
|
echo DEEPSPEED FOR %L_YELLOW=%PyTorch 2.1.x%RESET%
|
||||||
|
echo 4) Install DeepSpeed v11.2 for CUDA %L_GREEN%11.8%RESET% and Python-3.11.x and %L_YELLOW%PyTorch 2.1.x%RESET%.
|
||||||
|
echo 5) Install DeepSpeed v11.2 for CUDA %L_GREEN%12.1%RESET% and Python-3.11.x and %L_YELLOW%PyTorch 2.1.x%RESET%.
|
||||||
|
echo.
|
||||||
|
echo DEEPSPEED FOR %L_YELLOW=%PyTorch 2.2.x%RESET% (March 2024 builds of Text-gen-webui and later)
|
||||||
|
echo 6) Install DeepSpeed v14.0 for CUDA %L_GREEN%12.1%RESET% and Python-3.11.x and %L_YELLOW%PyTorch 2.2.x%RESET%.
|
||||||
|
echo 7) Install DeepSpeed v14.0 for CUDA %L_GREEN%11.8%RESET% and Python-3.11.x and %L_YELLOW%PyTorch 2.2.x%RESET%.
|
||||||
|
echo.
|
||||||
|
echo U) Uninstall DeepSpeed.
|
||||||
|
echo.
|
||||||
|
echo. OTHER
|
||||||
|
echo 8) Generate a diagnostics file.
|
||||||
|
echo.
|
||||||
|
echo 9) %L_RED%Exit/Quit%RESET%
|
||||||
|
echo.
|
||||||
|
set /p WebUIOption="Enter your choice: "
|
||||||
|
if "%WebUIOption%"=="1" goto InstallNvidiaTextGen
|
||||||
|
if "%WebUIOption%"=="2" goto TGGitpull
|
||||||
|
if "%WebUIOption%"=="4" goto InstallDeepSpeed118TextGen
|
||||||
|
if "%WebUIOption%"=="5" goto InstallDeepSpeed121TextGen
|
||||||
|
if "%WebUIOption%"=="6" goto InstallDeepSpeed121TextGenPytorch221
|
||||||
|
if "%WebUIOption%"=="7" goto InstallDeepSpeed118TextGenPytorch221
|
||||||
|
if "%WebUIOption%"=="U" goto UnInstallDeepSpeed
|
||||||
|
if "%WebUIOption%"=="u" goto UnInstallDeepSpeed
|
||||||
|
if "%WebUIOption%"=="8" goto GenerateDiagsTextGen
|
||||||
|
if "%WebUIOption%"=="9" goto End
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:StandaloneMenu
|
||||||
|
cls
|
||||||
|
echo.
|
||||||
|
echo %L_BLUE%ALLTALK STANDALONE APPLICATION SETUP%RESET%
|
||||||
|
echo.
|
||||||
|
echo BASE REQUIREMENTS
|
||||||
|
echo 1) Install AllTalk as a Standalone Application
|
||||||
|
echo.
|
||||||
|
echo OPTIONAL
|
||||||
|
echo 2) Git Pull the latest AllTalk updates from Github
|
||||||
|
echo 3) Re-Apply/Update the requirements file
|
||||||
|
echo 4) Delete AllTalk's custom Python environment
|
||||||
|
echo 5) Purge the PIP cache
|
||||||
|
echo.
|
||||||
|
echo. OTHER
|
||||||
|
echo 8) Generate a diagnostics file
|
||||||
|
echo.
|
||||||
|
echo 9) %L_RED%Exit/Quit%RESET%
|
||||||
|
echo.
|
||||||
|
set /p StandaloneOption="Enter your choice: "
|
||||||
|
if "%StandaloneOption%"=="1" goto InstallCustomStandalone
|
||||||
|
if "%StandaloneOption%"=="2" goto STGitpull
|
||||||
|
if "%StandaloneOption%"=="3" goto STReapplyrequirements
|
||||||
|
if "%StandaloneOption%"=="4" goto STDeleteCustomStandalone
|
||||||
|
if "%StandaloneOption%"=="5" goto STPurgepipcache
|
||||||
|
if "%StandaloneOption%"=="8" goto GenerateDiagsStandalone
|
||||||
|
if "%StandaloneOption%"=="9" goto End
|
||||||
|
goto StandaloneMenu
|
||||||
|
|
||||||
|
:InstallNvidiaTextGen
|
||||||
|
pip install -r system\requirements\requirements_textgen.txt
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo There was an error installing the requirements.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo.
|
||||||
|
Echo Requirements installed successfully.
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:TGGitpull
|
||||||
|
git pull
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo There was an error pulling from Github.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo AllTalk Updated from Github. Please re-apply
|
||||||
|
echo the latest requirements file. Option 1
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:InstallDeepSpeed118TextGen
|
||||||
|
echo Downloading DeepSpeed...
|
||||||
|
curl -LO https://github.com/erew123/alltalk_tts/releases/download/deepspeed/deepspeed-0.11.2+cuda118-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to download DeepSpeed wheel file.
|
||||||
|
echo Please check your internet connection or try again later.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
echo DeepSpeed wheel file downloaded successfully.
|
||||||
|
echo Installing DeepSpeed...
|
||||||
|
pip install deepspeed-0.11.2+cuda118-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to install DeepSpeed.
|
||||||
|
echo Please check if the wheel file is compatible with your system.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo.
|
||||||
|
Echo DeepSpeed installed successfully.
|
||||||
|
Echo.
|
||||||
|
del deepspeed-0.11.2+cuda118-cp311-cp311-win_amd64.whl
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:InstallDeepSpeed121TextGen
|
||||||
|
echo Downloading DeepSpeed...
|
||||||
|
curl -LO https://github.com/erew123/alltalk_tts/releases/download/deepspeed/deepspeed-0.11.2+cuda121-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to download DeepSpeed wheel file.
|
||||||
|
echo Please check your internet connection or try again later.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
echo DeepSpeed wheel file downloaded successfully.
|
||||||
|
echo Installing DeepSpeed...
|
||||||
|
pip install deepspeed-0.11.2+cuda121-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to install DeepSpeed.
|
||||||
|
echo Please check if the wheel file is compatible with your system.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo.
|
||||||
|
Echo DeepSpeed installed successfully.
|
||||||
|
Echo.
|
||||||
|
del deepspeed-0.11.2+cuda121-cp311-cp311-win_amd64.whl
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:InstallDeepSpeed121TextGenPytorch221
|
||||||
|
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
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to download DeepSpeed wheel file.
|
||||||
|
echo Please check your internet connection or try again later.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
echo DeepSpeed wheel file downloaded successfully.
|
||||||
|
echo Installing DeepSpeed...
|
||||||
|
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to install DeepSpeed.
|
||||||
|
echo Please check if the wheel file is compatible with your system.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo.
|
||||||
|
Echo DeepSpeed installed successfully.
|
||||||
|
Echo.
|
||||||
|
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:InstallDeepSpeed118TextGenPytorch221
|
||||||
|
echo Downloading DeepSpeed...
|
||||||
|
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+cu118-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to download DeepSpeed wheel file.
|
||||||
|
echo Please check your internet connection or try again later.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
echo DeepSpeed wheel file downloaded successfully.
|
||||||
|
echo Installing DeepSpeed...
|
||||||
|
pip install deepspeed-0.14.0+cu118-cp311-cp311-win_amd64.whl
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to install DeepSpeed.
|
||||||
|
echo Please check if the wheel file is compatible with your system.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo.
|
||||||
|
Echo DeepSpeed installed successfully.
|
||||||
|
Echo.
|
||||||
|
del deepspeed-0.14.0+cu118-cp311-cp311-win_amd64.whl
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:UnInstallDeepSpeed
|
||||||
|
pip uninstall deepspeed
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo There was an error uninstalling DeepSpeed.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
Echo DeepSpeed uninstalled successfully.
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:GenerateDiagsTextGen
|
||||||
|
Python diagnostics.py
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo There was an error running diagnostics. Have you correctly started your
|
||||||
|
echo Text-generation-webui Python environment with %L_GREEN%cmd_windows.bat%RESET%?
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo.
|
||||||
|
Echo Diagnostics.log generated. Please scroll up to look over the log.
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto WebUIMenu
|
||||||
|
|
||||||
|
:InstallCustomStandalone
|
||||||
|
set PATH=%PATH%;%SystemRoot%\system32
|
||||||
|
|
||||||
|
@rem Check if curl is available
|
||||||
|
curl --version >nul 2>&1
|
||||||
|
if "%ERRORLEVEL%" NEQ "0" (
|
||||||
|
echo curl is not available on this system. Please install curl then re-run the script https://curl.se/
|
||||||
|
echo or perform a manual installation of a Conda Python environment.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
echo "%CD%"| findstr /C:" " >nul && echo This script relies on Miniconda which can not be silently installed under a path with spaces. Please correct your folder names and re-try installation. && goto exit
|
||||||
|
|
||||||
|
@rem Check for special characters in installation path
|
||||||
|
set "SPCHARMESSAGE=WARNING: Special characters were detected in the installation path! This can cause the installation to fail!"
|
||||||
|
echo "%CD%"| findstr /R /C:"[!#\$%&()\*+,;<=>?@\[\]\^`{|}~]" >nul && (
|
||||||
|
call :PrintBigMessage %SPCHARMESSAGE%
|
||||||
|
)
|
||||||
|
set SPCHARMESSAGE=
|
||||||
|
|
||||||
|
@rem fix failed install when installing to a separate drive
|
||||||
|
set TMP=%cd%\alltalk_environment
|
||||||
|
set TEMP=%cd%\alltalk_environment
|
||||||
|
|
||||||
|
@rem deactivate existing conda envs as needed to avoid conflicts
|
||||||
|
(call conda deactivate && call conda deactivate && call conda deactivate) 2>nul
|
||||||
|
|
||||||
|
@rem config
|
||||||
|
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-py310_23.3.1-0-Windows-x86_64.exe
|
||||||
|
set conda_exists=F
|
||||||
|
|
||||||
|
@rem figure out whether git and conda need to be installed
|
||||||
|
call "%CONDA_ROOT_PREFIX%\_conda.exe" --version >nul 2>&1
|
||||||
|
if "%ERRORLEVEL%" EQU "0" (
|
||||||
|
set conda_exists=T
|
||||||
|
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%"
|
||||||
|
goto RunScript
|
||||||
|
)
|
||||||
|
|
||||||
|
@rem download and install conda if not installed
|
||||||
|
echo Downloading Miniconda from %MINICONDA_DOWNLOAD_URL% to %INSTALL_DIR%\miniconda_installer.exe
|
||||||
|
mkdir "%INSTALL_DIR%"
|
||||||
|
call curl -Lk "%MINICONDA_DOWNLOAD_URL%" > "%INSTALL_DIR%\miniconda_installer.exe" || ( echo. && echo Miniconda failed to download. && goto end )
|
||||||
|
echo Installing Miniconda to %CONDA_ROOT_PREFIX%
|
||||||
|
start /wait "" "%INSTALL_DIR%\miniconda_installer.exe" /InstallationType=JustMe /NoShortcuts=1 /AddToPath=0 /RegisterPython=0 /NoRegistry=1 /S /D=%CONDA_ROOT_PREFIX%
|
||||||
|
echo Miniconda version:
|
||||||
|
call "%CONDA_ROOT_PREFIX%\_conda.exe" --version || ( echo. && echo Miniconda not found. && goto end )
|
||||||
|
|
||||||
|
@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 || ( 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 )
|
||||||
|
|
||||||
|
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.
|
||||||
|
echo.
|
||||||
|
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||||
|
echo Installing other requirements.
|
||||||
|
echo.
|
||||||
|
pip install -r system\requirements\requirements_standalone.txt
|
||||||
|
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-12.7/deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||||
|
echo Installing DeepSpeed...
|
||||||
|
pip install deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||||
|
del deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||||
|
|
||||||
|
|
||||||
|
@rem Create start_environment.bat to run AllTalk environment
|
||||||
|
echo @echo off > start_environment.bat
|
||||||
|
echo cd /D "%~dp0" >> start_environment.bat
|
||||||
|
echo set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda >> start_environment.bat
|
||||||
|
echo set INSTALL_ENV_DIR=%cd%\alltalk_environment\env >> start_environment.bat
|
||||||
|
echo call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" >> start_environment.bat
|
||||||
|
@rem Create start_alltalk.bat to run AllTalk
|
||||||
|
echo @echo off > start_alltalk.bat
|
||||||
|
echo cd /D "%~dp0" >> start_alltalk.bat
|
||||||
|
echo set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda >> start_alltalk.bat
|
||||||
|
echo set INSTALL_ENV_DIR=%cd%\alltalk_environment\env >> start_alltalk.bat
|
||||||
|
echo call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" >> start_alltalk.bat
|
||||||
|
echo call python script.py >> start_alltalk.bat
|
||||||
|
@rem Create start_finetune.bat to run AllTalk
|
||||||
|
echo @echo off > start_finetune.bat
|
||||||
|
echo cd /D "%~dp0" >> start_finetune.bat
|
||||||
|
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 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.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
|
||||||
|
:STDeleteCustomStandalone
|
||||||
|
@rem Check if the alltalk_environment directory exists
|
||||||
|
if not exist "%cd%\alltalk_environment\" (
|
||||||
|
echo.
|
||||||
|
echo %L_GREEN%alltalk_environment%RESET% directory does not exist. No need to delete.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Check if a Conda environment is active
|
||||||
|
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.
|
||||||
|
conda deactivate
|
||||||
|
:NoCondaEnvDeleteCustomStandalone
|
||||||
|
echo Deleting "alltalk_environment". Please wait.
|
||||||
|
rd /s /q "alltalk_environment"
|
||||||
|
del start_alltalk.bat
|
||||||
|
del start_environment.bat
|
||||||
|
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.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
Echo.
|
||||||
|
echo Environment %L_GREEN%alltalk_environment%RESET% deleted. Please set up the environment again.
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
|
||||||
|
:GenerateDiagsStandalone
|
||||||
|
cd /D "%~dp0"
|
||||||
|
set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda
|
||||||
|
set INSTALL_ENV_DIR=%cd%\alltalk_environment\env
|
||||||
|
@rem Check if the Conda environment exists
|
||||||
|
if not exist "%INSTALL_ENV_DIR%\python.exe" (
|
||||||
|
echo.
|
||||||
|
echo The Conda environment at "%INSTALL_ENV_DIR%" does not exist.
|
||||||
|
echo Please install the environment before proceeding.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Attempt to activate the Conda environment
|
||||||
|
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo Failed to activate the Conda environment.
|
||||||
|
echo Please check your installation and try again.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Run diagnostics
|
||||||
|
Python diagnostics.py
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo There was an error running diagnostics.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
Echo.
|
||||||
|
Echo Diagnostics.log generated. Please scroll up to look over the log.
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
|
||||||
|
:STReapplyrequirements
|
||||||
|
cd /D "%~dp0"
|
||||||
|
set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda
|
||||||
|
set INSTALL_ENV_DIR=%cd%\alltalk_environment\env
|
||||||
|
@rem Check if the Conda environment exists
|
||||||
|
if not exist "%INSTALL_ENV_DIR%\python.exe" (
|
||||||
|
echo.
|
||||||
|
echo The Conda environment at "%INSTALL_ENV_DIR%" does not exist.
|
||||||
|
echo Please install the environment before proceeding.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Attempt to activate the Conda environment
|
||||||
|
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo Failed to activate the Conda environment.
|
||||||
|
echo Please check your installation and try again.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Run Reapply requirements
|
||||||
|
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.
|
||||||
|
echo.
|
||||||
|
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||||
|
echo Installing other requirements.
|
||||||
|
echo.
|
||||||
|
pip install -r system\requirements\requirements_standalone.txt
|
||||||
|
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-12.7/deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||||
|
echo Installing DeepSpeed...
|
||||||
|
pip install deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||||
|
del deepspeed-0.12.7+d058d4b-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 StandaloneMenu
|
||||||
|
|
||||||
|
:STPurgepipcache
|
||||||
|
cd /D "%~dp0"
|
||||||
|
set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda
|
||||||
|
set INSTALL_ENV_DIR=%cd%\alltalk_environment\env
|
||||||
|
@rem Check if the Conda environment exists
|
||||||
|
if not exist "%INSTALL_ENV_DIR%\python.exe" (
|
||||||
|
echo.
|
||||||
|
echo The Conda environment at "%INSTALL_ENV_DIR%" does not exist.
|
||||||
|
echo Please install the environment before proceeding.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Attempt to activate the Conda environment
|
||||||
|
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo Failed to activate the Conda environment.
|
||||||
|
echo Please check your installation and try again.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Clear the PIP cache
|
||||||
|
echo.
|
||||||
|
echo Purging the PIP cache of downloaded files.
|
||||||
|
echo.
|
||||||
|
pip cache purge
|
||||||
|
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 The PIP cache has been purged.
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
|
||||||
|
:STGitpull
|
||||||
|
cd /D "%~dp0"
|
||||||
|
set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda
|
||||||
|
set INSTALL_ENV_DIR=%cd%\alltalk_environment\env
|
||||||
|
@rem Check if the Conda environment exists
|
||||||
|
if not exist "%INSTALL_ENV_DIR%\python.exe" (
|
||||||
|
echo.
|
||||||
|
echo The Conda environment at "%INSTALL_ENV_DIR%" does not exist.
|
||||||
|
echo Please install the environment before proceeding.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Attempt to activate the Conda environment
|
||||||
|
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo Failed to activate the Conda environment.
|
||||||
|
echo Please check your installation and try again.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
@rem Pull from Github
|
||||||
|
echo.
|
||||||
|
echo Pulling the latest updates. Please re-apply
|
||||||
|
echo the latest requirements file. Option 3
|
||||||
|
echo.
|
||||||
|
git pull
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo There was an error pulling from Github.
|
||||||
|
echo Press any key to return to the menu.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
)
|
||||||
|
Echo.
|
||||||
|
echo AllTalk Updated from Github. Please re-apply
|
||||||
|
echo the latest requirements file. Option 3
|
||||||
|
Echo.
|
||||||
|
pause
|
||||||
|
goto StandaloneMenu
|
||||||
|
|
||||||
|
:End
|
||||||
|
echo Exiting AllTalk Setup Utility...
|
||||||
|
exit /b
|
||||||
@@ -0,0 +1,486 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ANSI color codes
|
||||||
|
RED='\033[1;31m'
|
||||||
|
GREEN='\033[1;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[1;34m'
|
||||||
|
CYAN='\033[1;36m'
|
||||||
|
MAGENTA='\033[1;35m'
|
||||||
|
WHITE='\033[1;37m'
|
||||||
|
L_RED='\033[1;91m'
|
||||||
|
L_GREEN='\033[1;92m'
|
||||||
|
L_YELLOW='\033[1;93m'
|
||||||
|
L_BLUE='\033[1;94m'
|
||||||
|
L_CYAN='\033[1;96m'
|
||||||
|
L_MAGENTA='\033[1;95m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Navigate to the script's directory
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
# Function to check if curl is installed
|
||||||
|
check_curl() {
|
||||||
|
if ! command -v curl &> /dev/null; then
|
||||||
|
echo "curl is not available on this system. Please install curl then re-run the script https://curl.se/"
|
||||||
|
echo "or perform a manual installation of a Conda Python environment."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main Menu
|
||||||
|
main_menu() {
|
||||||
|
while true; do
|
||||||
|
clear
|
||||||
|
echo
|
||||||
|
echo -e " ${L_BLUE}ALLTALK LINUX SETUP UTILITY${NC}"
|
||||||
|
echo
|
||||||
|
echo " INSTALLATION TYPE"
|
||||||
|
echo -e " 1) I am using AllTalk as part of ${L_GREEN}Text-generation-webui${NC}"
|
||||||
|
echo -e " 2) I am using AllTalk as a ${L_GREEN}Standalone Application${NC}"
|
||||||
|
echo
|
||||||
|
echo -e " 9)${L_RED} Exit/Quit${NC}"
|
||||||
|
echo
|
||||||
|
read -p " Enter your choice: " user_option
|
||||||
|
|
||||||
|
case $user_option in
|
||||||
|
1) webui_menu ;;
|
||||||
|
2) standalone_menu ;;
|
||||||
|
9) exit 0 ;;
|
||||||
|
*) echo "Invalid option"; sleep 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Text-generation-webui Menu
|
||||||
|
webui_menu() {
|
||||||
|
while true; do
|
||||||
|
clear
|
||||||
|
echo
|
||||||
|
echo -e " ${L_BLUE}TEXT-GENERATION-WEBUI SETUP${NC}"
|
||||||
|
echo
|
||||||
|
echo -e " Please ensure you have started your Text-generation-webui Python"
|
||||||
|
echo -e " environment. If you have NOT done this, please run ${L_GREEN}/cmd_linux.sh${NC}"
|
||||||
|
echo -e " in the ${L_GREEN}text-generation-webui${NC} folder and then re-run this script."
|
||||||
|
echo
|
||||||
|
echo " BASE REQUIREMENTS"
|
||||||
|
echo -e " 1) Apply/Re-Apply the requirements for an ${L_GREEN}Text-generation-webui${NC}"
|
||||||
|
echo
|
||||||
|
echo " OPTIONAL"
|
||||||
|
echo " 2) Git Pull the latest AllTalk updates from Github"
|
||||||
|
echo
|
||||||
|
echo " DEEPSPEED"
|
||||||
|
echo " 4) Install DeepSpeed."
|
||||||
|
echo " 5) Uninstall DeepSpeed."
|
||||||
|
echo
|
||||||
|
echo " OTHER"
|
||||||
|
echo " 6) Generate a diagnostics file."
|
||||||
|
echo
|
||||||
|
echo -e " 9)${L_RED} Exit/Quit${NC}"
|
||||||
|
echo
|
||||||
|
read -p " Enter your choice: " webui_option
|
||||||
|
|
||||||
|
case $webui_option in
|
||||||
|
1) install_nvidia_textgen ;;
|
||||||
|
2) tg_gitpull ;;
|
||||||
|
4) install_deepspeed ;;
|
||||||
|
5) uninstall_deepspeed ;;
|
||||||
|
6) generate_diagnostics_textgen ;;
|
||||||
|
9) exit 0 ;;
|
||||||
|
*) echo "Invalid option"; sleep 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
install_nvidia_textgen() {
|
||||||
|
local requirements_file="system/requirements/requirements_textgen.txt"
|
||||||
|
echo " Installing Requirements from $requirements_file..."
|
||||||
|
if ! pip install -r "$requirements_file"; then
|
||||||
|
echo
|
||||||
|
echo " There was an error pulling from Github."
|
||||||
|
echo " Please check the output for details."
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " 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."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
tg_gitpull() {
|
||||||
|
echo
|
||||||
|
if ! git pull; then
|
||||||
|
echo
|
||||||
|
echo " There was an error installing the requirements."
|
||||||
|
echo " Please check the output for details."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " AllTalk Updated from Github. Please re-apply"
|
||||||
|
echo " the latest requirements file. (Option 1)"
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install DeepSpeed
|
||||||
|
install_deepspeed() {
|
||||||
|
clear
|
||||||
|
echo
|
||||||
|
echo -e " ${L_BLUE}DEEPSPEED INSTALLATION REQUIREMENTS${NC}"
|
||||||
|
echo
|
||||||
|
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
|
||||||
|
|
||||||
|
if [ "$confirm" != "y" ]; then
|
||||||
|
echo -e " ${RED}DeepSpeed installation cannot proceed without completing the prerequisites.${NC}"
|
||||||
|
return
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e " ${GREEN}DeepSpeed installed successfully.${NC}"
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
uninstall_deepspeed() {
|
||||||
|
echo "Uninstalling DeepSpeed..."
|
||||||
|
pip uninstall -y deepspeed
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
echo " There was an error uninstalling DeepSpeed."
|
||||||
|
echo
|
||||||
|
echo " Press any key to return to the menu."
|
||||||
|
read -n 1
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " DeepSpeed uninstalled successfully."
|
||||||
|
echo
|
||||||
|
echo " Press any key to continue."
|
||||||
|
read -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_diagnostics_textgen() {
|
||||||
|
# Run diagnostics
|
||||||
|
if ! python diagnostics.py; then
|
||||||
|
echo
|
||||||
|
echo " There was an error running diagnostics."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " Diagnostics log file generated successfully."
|
||||||
|
echo " Please see diagnostics.log"
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Standalone Menu
|
||||||
|
standalone_menu() {
|
||||||
|
while true; do
|
||||||
|
clear
|
||||||
|
echo
|
||||||
|
echo -e " ${L_BLUE}ALLTALK STANDALONE APPLICATION SETUP${NC}"
|
||||||
|
echo
|
||||||
|
echo " BASE REQUIREMENTS"
|
||||||
|
echo " 1) Install AllTalk as a Standalone Application"
|
||||||
|
echo
|
||||||
|
echo " OPTIONAL"
|
||||||
|
echo " 2) Git Pull the latest AllTalk updates from Github"
|
||||||
|
echo " 3) Re-Apply/Update the requirements file"
|
||||||
|
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
|
||||||
|
echo -e " 9)${L_RED} Exit/Quit${NC}"
|
||||||
|
echo
|
||||||
|
read -p " Enter your choice: " standalone_option
|
||||||
|
|
||||||
|
case $standalone_option in
|
||||||
|
1) install_custom_standalone ;;
|
||||||
|
2) gitpull_standalone ;;
|
||||||
|
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 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
install_custom_standalone() {
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
|
||||||
|
if [[ "$(pwd)" =~ " " ]]; then
|
||||||
|
echo "This script relies on Miniconda which can not be silently installed under a path with spaces."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Deactivate existing conda envs as needed to avoid conflicts
|
||||||
|
{ conda deactivate && conda deactivate && conda deactivate; } 2> /dev/null
|
||||||
|
|
||||||
|
OS_ARCH=$(uname -m)
|
||||||
|
case "${OS_ARCH}" in
|
||||||
|
x86_64*) OS_ARCH="x86_64" ;;
|
||||||
|
arm64* | aarch64*) OS_ARCH="aarch64" ;;
|
||||||
|
*) echo "Unknown system architecture: $OS_ARCH! This script runs only on x86_64 or arm64" && exit ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Config
|
||||||
|
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-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}"
|
||||||
|
curl -L "${MINICONDA_DOWNLOAD_URL}" -o "${INSTALL_DIR}/miniconda_installer.sh"
|
||||||
|
chmod +x "${INSTALL_DIR}/miniconda_installer.sh"
|
||||||
|
bash "${INSTALL_DIR}/miniconda_installer.sh" -b -p "${CONDA_ROOT_PREFIX}"
|
||||||
|
echo "Miniconda installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "${INSTALL_ENV_DIR}" ]; then
|
||||||
|
"${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}"
|
||||||
|
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 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||||
|
echo
|
||||||
|
echo " Installing additional requirements."
|
||||||
|
echo
|
||||||
|
pip install -r system/requirements/requirements_standalone.txt
|
||||||
|
# Create start_environment.sh to run AllTalk
|
||||||
|
cat << EOF > start_environment.sh
|
||||||
|
#!/bin/bash
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
if [[ "$(pwd)" =~ " " ]]; then echo This script relies on Miniconda which can not be silently installed under a path with spaces. && exit; fi
|
||||||
|
# deactivate existing conda envs as needed to avoid conflicts
|
||||||
|
{ conda deactivate && conda deactivate && conda deactivate; } 2> /dev/null
|
||||||
|
# config
|
||||||
|
CONDA_ROOT_PREFIX="$(pwd)/alltalk_environment/conda"
|
||||||
|
INSTALL_ENV_DIR="$(pwd)/alltalk_environment/env"
|
||||||
|
# environment isolation
|
||||||
|
export PYTHONNOUSERSITE=1
|
||||||
|
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
|
||||||
|
chmod +x start_alltalk.sh
|
||||||
|
chmod +x start_environment.sh
|
||||||
|
chmod +x start_finetune.sh
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo -e " Run ${L_YELLOW}./start_alltalk.sh${NC} to start AllTalk."
|
||||||
|
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
|
||||||
|
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."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_custom_standalone() {
|
||||||
|
local env_dir="$PWD/alltalk_environment"
|
||||||
|
# Check if the alltalk_environment directory exists
|
||||||
|
if [ ! -d "$env_dir" ]; then
|
||||||
|
echo " \"$env_dir\" directory does not exist. No need to delete."
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Check if a Conda environment is active and deactivate it
|
||||||
|
if [ -n "$CONDA_PREFIX" ]; then
|
||||||
|
echo " Exiting the Conda environment. You may need to start ./atstart.sh again"
|
||||||
|
conda deactivate
|
||||||
|
fi
|
||||||
|
echo "Deleting \"$env_dir\". Please wait."
|
||||||
|
rm -rf "$env_dir"
|
||||||
|
if [ -d "$env_dir" ]; then
|
||||||
|
echo " Failed to delete \"$env_dir\" folder."
|
||||||
|
echo " Please make sure it is not in use and try again."
|
||||||
|
else
|
||||||
|
echo " Environment \"$env_dir\" deleted successfully."
|
||||||
|
fi
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_diagnostics_standalone() {
|
||||||
|
local env_dir="$PWD/alltalk_environment"
|
||||||
|
local conda_root_prefix="${env_dir}/conda"
|
||||||
|
local install_env_dir="${env_dir}/env"
|
||||||
|
if [ ! -d "${install_env_dir}" ]; then
|
||||||
|
echo
|
||||||
|
echo " The Conda environment at '${install_env_dir}' does not exist."
|
||||||
|
echo " Please install the environment before proceeding."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
source "${conda_root_prefix}/etc/profile.d/conda.sh"
|
||||||
|
conda activate "${install_env_dir}"
|
||||||
|
if ! python diagnostics.py; then
|
||||||
|
echo
|
||||||
|
echo " There was an error running diagnostics."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " Diagnostics completed successfully."
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
gitpull_standalone() {
|
||||||
|
local env_dir="$PWD/alltalk_environment"
|
||||||
|
local conda_root_prefix="${env_dir}/conda"
|
||||||
|
local install_env_dir="${env_dir}/env"
|
||||||
|
if [ ! -d "${install_env_dir}" ]; then
|
||||||
|
echo
|
||||||
|
echo " The Conda environment at '${install_env_dir}' does not exist."
|
||||||
|
echo " Please install the environment before proceeding."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
source "${conda_root_prefix}/etc/profile.d/conda.sh"
|
||||||
|
conda activate "${install_env_dir}"
|
||||||
|
if ! git pull; then
|
||||||
|
echo
|
||||||
|
echo " There was an error pulling from Github."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " AllTalk Updated from Github. Please re-apply."
|
||||||
|
echo " the latest requirements file. (Option 3)"
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
pippurge_standalone() {
|
||||||
|
if ! pip cache purge; then
|
||||||
|
echo
|
||||||
|
echo " There was an error."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo " The PIP cache has been purged."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
reapply_standalone() {
|
||||||
|
local env_dir="$PWD/alltalk_environment"
|
||||||
|
local conda_root_prefix="${env_dir}/conda"
|
||||||
|
local install_env_dir="${env_dir}/env"
|
||||||
|
if [ ! -d "${install_env_dir}" ]; then
|
||||||
|
echo
|
||||||
|
echo " The Conda environment at '${install_env_dir}' does not exist."
|
||||||
|
echo " Please install the environment before proceeding."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to return to the menu. " -n 1
|
||||||
|
echo
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
source "${conda_root_prefix}/etc/profile.d/conda.sh"
|
||||||
|
conda activate "${install_env_dir}"
|
||||||
|
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 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||||
|
echo
|
||||||
|
echo " Installing additional requirements."
|
||||||
|
echo
|
||||||
|
pip install -r system/requirements/requirements_standalone.txt
|
||||||
|
echo
|
||||||
|
echo " Requirements have been re-applied/updated."
|
||||||
|
echo
|
||||||
|
read -p " Press any key to continue. " -n 1
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Start the main menu
|
||||||
|
main_menu
|
||||||
@@ -1 +1,25 @@
|
|||||||
{"activate": true, "autoplay": true, "branding": "AllTalk ", "narrator_enabled": false, "deepspeed_activate": false, "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"}
|
{
|
||||||
|
"activate": true,
|
||||||
|
"autoplay": true,
|
||||||
|
"branding": "AllTalk ",
|
||||||
|
"narrator_enabled": false,
|
||||||
|
"deepspeed_activate": false,
|
||||||
|
"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"
|
||||||
|
}
|
||||||
@@ -8,12 +8,15 @@ try:
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import glob
|
import glob
|
||||||
|
import site
|
||||||
import textwrap
|
import textwrap
|
||||||
|
import torch
|
||||||
import packaging.version
|
import packaging.version
|
||||||
import packaging.specifiers
|
import packaging.specifiers
|
||||||
from packaging.specifiers import SpecifierSet
|
from packaging.specifiers import SpecifierSet
|
||||||
from packaging.specifiers import SpecifierSet
|
from packaging.specifiers import SpecifierSet
|
||||||
from packaging.version import parse as parse_version
|
from packaging.version import parse as parse_version
|
||||||
|
from pathlib import Path
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print(f"\033[91mError importing module: {e}\033[0m\n")
|
print(f"\033[91mError importing module: {e}\033[0m\n")
|
||||||
print("\033[94mPlease ensure you started the Text-generation-webUI Python environment with either\033[0m")
|
print("\033[94mPlease ensure you started the Text-generation-webUI Python environment with either\033[0m")
|
||||||
@@ -21,6 +24,8 @@ except ImportError as e:
|
|||||||
print("\033[94mfrom the text-generation-webui directory, and then try running the diagnostics again.\033[0m")
|
print("\033[94mfrom the text-generation-webui directory, and then try running the diagnostics again.\033[0m")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
this_dir = Path(__file__).parent
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import psutil
|
import psutil
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -29,24 +34,30 @@ except ImportError:
|
|||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
def get_requirements_file():
|
def get_requirements_file():
|
||||||
requirements_files = glob.glob("requirements*.txt")
|
this_dir = Path(__file__).parent # Assuming 'this_dir' is defined as the script's directory
|
||||||
|
requirements_dir = this_dir / 'system' / 'requirements'
|
||||||
|
requirements_files = list(requirements_dir.glob('requirements*.txt')) # Using pathlib for globbing
|
||||||
|
|
||||||
if not requirements_files:
|
if not requirements_files:
|
||||||
print("\033[91mNo requirements files found.\033[0m")
|
print("\033[91mNo requirements files found.\033[0m")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
print("\033[94m\nSelect a requirements file to check against (or press Enter for default 'requirements.txt'):\033[0m\n")
|
print("\033[94m\nSelect a requirements file to check against (or press Enter for default 'requirements.txt'):\033[0m\n")
|
||||||
for i, file in enumerate(requirements_files, start=1):
|
for i, file_path in enumerate(requirements_files, start=1):
|
||||||
print(f"{i}. {file}")
|
print(f" {i}. {file_path.name}") # Only print the filename
|
||||||
|
|
||||||
choice = input("\nEnter the number of your choice: ")
|
choice = input("\nEnter the number of your choice: ")
|
||||||
try:
|
try:
|
||||||
choice = int(choice) - 1
|
choice = int(choice) - 1
|
||||||
return requirements_files[choice]
|
return str(requirements_files[choice]) # Return the full path as a string
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
return "requirements.txt"
|
return str(requirements_dir / "requirements.txt") # Return the default path as a string
|
||||||
|
|
||||||
# Set up logging with filemode='w'
|
# Set up logging with filemode='w'
|
||||||
logging.basicConfig(filename='diagnostics.log', filemode='w', level=logging.INFO)
|
logging.basicConfig(filename='diagnostics.log',
|
||||||
|
filemode='w',
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(message)s') # Custom format
|
||||||
|
|
||||||
# Function to get GPU information using subprocess
|
# Function to get GPU information using subprocess
|
||||||
def get_gpu_info():
|
def get_gpu_info():
|
||||||
@@ -56,6 +67,22 @@ def get_gpu_info():
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return "NVIDIA GPU information not available"
|
return "NVIDIA GPU information not available"
|
||||||
|
|
||||||
|
def get_cpu_info():
|
||||||
|
cpu_info = {
|
||||||
|
'physical_cores': psutil.cpu_count(logical=False),
|
||||||
|
'total_cores': psutil.cpu_count(logical=True),
|
||||||
|
'max_frequency': psutil.cpu_freq().max
|
||||||
|
}
|
||||||
|
return cpu_info
|
||||||
|
|
||||||
|
def get_disk_info():
|
||||||
|
disk_info = []
|
||||||
|
partitions = psutil.disk_partitions()
|
||||||
|
for p in partitions:
|
||||||
|
usage = psutil.disk_usage(p.mountpoint)
|
||||||
|
disk_info.append(f" Drive: {p.device} | Total: {usage.total / (1024 ** 3):.2f} GB | Used: {usage.used / (1024 ** 3):.2f} GB | Free: {usage.free / (1024 ** 3):.2f} GB | Type: {p.fstype}")
|
||||||
|
return disk_info
|
||||||
|
|
||||||
# Function to check if a port is in use
|
# Function to check if a port is in use
|
||||||
def is_port_in_use(port):
|
def is_port_in_use(port):
|
||||||
for conn in psutil.net_connections():
|
for conn in psutil.net_connections():
|
||||||
@@ -73,6 +100,38 @@ def satisfies_wildcard(installed_version, required_version):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def test_cuda():
|
||||||
|
cuda_available = torch.cuda.is_available()
|
||||||
|
if cuda_available:
|
||||||
|
try:
|
||||||
|
# Attempt to create a tensor on GPU
|
||||||
|
torch.tensor([1.0, 2.0]).cuda()
|
||||||
|
return "Success - CUDA is available and working."
|
||||||
|
except Exception as e:
|
||||||
|
return f"Fail - CUDA is available but not working. Error: {e}"
|
||||||
|
else:
|
||||||
|
return "Fail - CUDA is not available."
|
||||||
|
|
||||||
|
def find_files_in_path_with_wildcard(pattern):
|
||||||
|
# Get the site-packages directory of the current Python environment
|
||||||
|
site_packages_path = site.getsitepackages()
|
||||||
|
found_paths = []
|
||||||
|
# Adjust the sub-directory based on the operating system
|
||||||
|
sub_directory = "nvidia/cublas"
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
sub_directory = os.path.join(sub_directory, "lib")
|
||||||
|
else:
|
||||||
|
sub_directory = os.path.join(sub_directory, "bin")
|
||||||
|
# Iterate over each site-packages directory (there can be more than one)
|
||||||
|
for directory in site_packages_path:
|
||||||
|
# Construct the search directory path
|
||||||
|
search_directory = os.path.join(directory, sub_directory)
|
||||||
|
# Use glob to find all files matching the pattern in this directory
|
||||||
|
for file_path in glob.glob(os.path.join(search_directory, pattern)):
|
||||||
|
if os.path.isfile(file_path): # Ensure it's a file
|
||||||
|
found_paths.append(file_path)
|
||||||
|
return found_paths
|
||||||
|
|
||||||
# Function to log and print system information
|
# Function to log and print system information
|
||||||
def log_system_info():
|
def log_system_info():
|
||||||
# System information
|
# System information
|
||||||
@@ -88,6 +147,9 @@ def log_system_info():
|
|||||||
|
|
||||||
# Torch version
|
# Torch version
|
||||||
torch_version = torch.__version__
|
torch_version = torch.__version__
|
||||||
|
cuda_test_result = test_cuda()
|
||||||
|
cpu_info = get_cpu_info()
|
||||||
|
disk_info = get_disk_info()
|
||||||
|
|
||||||
# System RAM using psutil
|
# System RAM using psutil
|
||||||
try:
|
try:
|
||||||
@@ -123,6 +185,10 @@ def log_system_info():
|
|||||||
search_path = sys.path
|
search_path = sys.path
|
||||||
path_env = os.environ.get('PATH', 'N/A')
|
path_env = os.environ.get('PATH', 'N/A')
|
||||||
|
|
||||||
|
# Check for cublas
|
||||||
|
file_name = 'cublas64_11.*' if platform.system() == "Windows" else 'libcublas.so.11*'
|
||||||
|
found_paths = find_files_in_path_with_wildcard(file_name)
|
||||||
|
|
||||||
# Compare with requirements file
|
# Compare with requirements file
|
||||||
requirements_file = get_requirements_file()
|
requirements_file = get_requirements_file()
|
||||||
if requirements_file:
|
if requirements_file:
|
||||||
@@ -146,12 +212,27 @@ def log_system_info():
|
|||||||
logging.info(f"NOTE {requirements_file} not found. Skipping version checks.")
|
logging.info(f"NOTE {requirements_file} not found. Skipping version checks.")
|
||||||
|
|
||||||
# Log and print information
|
# Log and print information
|
||||||
|
logging.info(f"OPERATING SYSTEM:")
|
||||||
logging.info(f" OS Version: {os_version}")
|
logging.info(f" OS Version: {os_version}")
|
||||||
logging.info(f" Note: Windows 11 will list as build is 10.x.22xxx")
|
logging.info(f" Note: Windows 11 will list as build is 10.x.22xxx")
|
||||||
logging.info(f"Torch Version: {torch_version}")
|
logging.info(f"\nHARDWARE ENVIRONMENT:")
|
||||||
|
logging.info(f" CPU: Physical Cores: {cpu_info['physical_cores']}, Total Cores: {cpu_info['total_cores']}, Max Frequency: {cpu_info['max_frequency']} MHz")
|
||||||
logging.info(f" System RAM: {system_ram}")
|
logging.info(f" System RAM: {system_ram}")
|
||||||
logging.info(f"CUDA_HOME: {cuda_home}")
|
logging.info(f"\nGPU INFORMATION:{gpu_info}")
|
||||||
|
logging.info("DISK INFORMATION:")
|
||||||
|
for disk in disk_info:
|
||||||
|
logging.info(disk)
|
||||||
|
logging.info("\nNETWORK PORT:")
|
||||||
logging.info(f" Port Status: {port_status}")
|
logging.info(f" Port Status: {port_status}")
|
||||||
|
logging.info("\nCUDA:")
|
||||||
|
logging.info(f" CUDA Working: {cuda_test_result}")
|
||||||
|
logging.info(f" CUDA_HOME: {cuda_home}")
|
||||||
|
if found_paths:
|
||||||
|
logging.info(f" Cublas64_11 Path: {', '.join(found_paths)}")
|
||||||
|
else:
|
||||||
|
logging.info(f" Cublas64_11 Path: Not found in any search path directories.")
|
||||||
|
logging.info("\nPYTHON & PYTORCH:")
|
||||||
|
logging.info(f" Torch Version: {torch_version}")
|
||||||
logging.info(f" Python Version: {platform.python_version()}")
|
logging.info(f" Python Version: {platform.python_version()}")
|
||||||
logging.info(f" Python Version Info: {python_version_info}")
|
logging.info(f" Python Version Info: {python_version_info}")
|
||||||
logging.info(f" Python Executable: {python_executable}")
|
logging.info(f" Python Executable: {python_executable}")
|
||||||
@@ -160,38 +241,43 @@ def log_system_info():
|
|||||||
logging.info("\nPython Search Path:")
|
logging.info("\nPython Search Path:")
|
||||||
for path in search_path:
|
for path in search_path:
|
||||||
logging.info(f" {path}")
|
logging.info(f" {path}")
|
||||||
logging.info("\nOS PATH Environment Variable:")
|
logging.info("\nOS SEARCHPATH ENVIRONMENT:")
|
||||||
for path in path_env.split(';'):
|
for path in path_env.split(';'):
|
||||||
logging.info(f" {path}")
|
logging.info(f" {path}")
|
||||||
if required_packages: # Check if the dictionary is not empty
|
if required_packages: # Check if the dictionary is not empty
|
||||||
logging.info("\nPackage Versions:")
|
logging.info("\nPACKAGE VERSIONS vs REQUIREMENTS FILE:")
|
||||||
max_package_length = max(len(package) for package in required_packages.keys())
|
max_package_length = max(len(package) for package in required_packages.keys())
|
||||||
for package_name, (operator, required_version) in required_packages.items():
|
for package_name, (operator, required_version) in required_packages.items():
|
||||||
installed_version = installed_packages.get(package_name, 'Not installed')
|
installed_version = installed_packages.get(package_name, 'Not installed')
|
||||||
logging.info(f" {package_name.ljust(max_package_length)} Required: {operator} {required_version.ljust(12)} Installed: {installed_version}")
|
logging.info(f" {package_name.ljust(max_package_length)} Required: {operator} {required_version.ljust(12)} Installed: {installed_version}")
|
||||||
logging.info(f"GPU Information:\n{gpu_info}")
|
logging.info("\nPYTHON PACKAGES:")
|
||||||
logging.info("Package Versions:")
|
|
||||||
for package, version in package_versions.items():
|
for package, version in package_versions.items():
|
||||||
logging.info(f" {package}>= {version}")
|
logging.info(f" {package}>= {version}")
|
||||||
|
|
||||||
# Print to screen
|
# Print to screen
|
||||||
print(f"\n\033[94mOS Version:\033[0m \033[92m{os_version}\033[0m")
|
print(f"\n\033[94mOS Version:\033[0m \033[92m{os_version}\033[0m")
|
||||||
print(f"\033[94mOS Ver note:\033[0m \033[92m(Windows 11 will say build is 10.x.22xxx)\033[0m")
|
print(f"\033[94mOS Ver note:\033[0m \033[92m(Windows 11 will say build is 10.x.22xxx)\033[0m")
|
||||||
print(f"\033[94mCUDA_HOME:\033[0m \033[92m{cuda_home}\033[0m")
|
|
||||||
print(f"\033[94mSystem RAM:\033[0m \033[92m{system_ram}\033[0m")
|
print(f"\033[94mSystem RAM:\033[0m \033[92m{system_ram}\033[0m")
|
||||||
print(f"\033[94mPort Status:\033[0m \033[92m{port_status}\033[0m")
|
for disk in disk_info:
|
||||||
print(f"\033[94mTorch Version:\033[0m \033[92m{torch_version}\033[0m")
|
print(f"\033[94mDisk:\033[0m \033[92m{disk}\033[0m")
|
||||||
|
print(f"\033[94m\nGPU Information:\033[0m {gpu_info}")
|
||||||
|
print(f"\033[94mPort Status:\033[0m \033[92m{port_status}\033[0m\n")
|
||||||
|
if "Fail" in cuda_test_result:
|
||||||
|
print(f"\033[91mCUDA Working:\033[0m \033[91m{cuda_test_result}\033[0m")
|
||||||
|
else:
|
||||||
|
print(f"\033[94mCUDA Working:\033[0m \033[92m{cuda_test_result}\033[0m")
|
||||||
|
print(f"\033[94mCUDA_HOME:\033[0m \033[92m{cuda_home}\033[0m")
|
||||||
|
if found_paths:
|
||||||
|
print(f"\033[94mCublas64_11 Path:\033[0m \033[92m{', '.join(found_paths)}\033[0m")
|
||||||
|
else:
|
||||||
|
print(f"\033[94mCublas64_11 Path:\033[0m \033[91mNot found in any search path directories.\033[0m")
|
||||||
|
print(f"\033[94m\nTorch Version:\033[0m \033[92m{torch_version}\033[0m")
|
||||||
print(f"\033[94mPython Version:\033[0m \033[92m{platform.python_version()}\033[0m")
|
print(f"\033[94mPython Version:\033[0m \033[92m{platform.python_version()}\033[0m")
|
||||||
print(f"\033[94mPython Version Info:\033[0m \033[92m{python_version_info}\033[0m")
|
|
||||||
print(f"\033[94mPython Executable:\033[0m \033[92m{python_executable}\033[0m")
|
print(f"\033[94mPython Executable:\033[0m \033[92m{python_executable}\033[0m")
|
||||||
print(f"\033[94mPython Virtual Environment:\033[0m \033[92m{python_virtual_env}\033[0m (Should be N/A when in Text-generation-webui Conda Python environment)")
|
|
||||||
print(f"\033[94mConda Environment:\033[0m \033[92m{conda_env}\033[0m")
|
print(f"\033[94mConda Environment:\033[0m \033[92m{conda_env}\033[0m")
|
||||||
print(f"\n\033[94mPython Search Path:\033[0m")
|
print(f"\n\033[94mPython Search Path:\033[0m")
|
||||||
for path in search_path:
|
for path in search_path:
|
||||||
print(f" {path}")
|
print(f" {path}")
|
||||||
print(f"\n\033[94mOS Search PATH Environment Variable:\033[0m")
|
|
||||||
for path in path_env.split(';'):
|
|
||||||
print(f" {path}")
|
|
||||||
if required_packages: # Check if the dictionary is not empty
|
if required_packages: # Check if the dictionary is not empty
|
||||||
print("\033[94m\nRequirements file package comparison:\033[0m")
|
print("\033[94m\nRequirements file package comparison:\033[0m")
|
||||||
max_package_length = max(len(package) for package in required_packages.keys())
|
max_package_length = max(len(package) for package in required_packages.keys())
|
||||||
@@ -215,6 +301,13 @@ def log_system_info():
|
|||||||
|
|
||||||
# Print colored output
|
# Print colored output
|
||||||
print(f" {package_name.ljust(max_package_length)} Required: {color_required}{operator} {required_version.ljust(12)}\033[0m Installed: {color_installed}{installed_version}\033[0m")
|
print(f" {package_name.ljust(max_package_length)} Required: {color_required}{operator} {required_version.ljust(12)}\033[0m Installed: {color_installed}{installed_version}\033[0m")
|
||||||
|
|
||||||
|
print("\nOn Nvidia Graphics cards machines, if your \033[92mInstalled\033[0m version of \033[92mTorch\033[0m and \033[92mTorchaudio\033[0m does")
|
||||||
|
print("not have \033[92m+cu118\033[0m (Cuda 11.8) or \033[92m+cu121\033[0m (Cuda 12.1) listed after them, you do not have CUDA")
|
||||||
|
print("installed for Torch or Torchaudio in this Python environment. This will cause you problems")
|
||||||
|
print("with \033[94mAllTalk\033[0m and \033[94mFinetuning.\033[0m You may have to 'pip install' a new version of torch and")
|
||||||
|
print("torchaudio, using '\033[94m--upgrade --force-reinstall\033[0m' with the correct version of PyTorch for\033[0m")
|
||||||
|
print("your Python environment.\033[0m")
|
||||||
print("\033[94m\nRequirements file specifier meanings:\033[0m")
|
print("\033[94m\nRequirements file specifier meanings:\033[0m")
|
||||||
explanation = textwrap.dedent("""
|
explanation = textwrap.dedent("""
|
||||||
== Exact version != Any version except < Less than
|
== Exact version != Any version except < Less than
|
||||||
@@ -224,9 +317,9 @@ def log_system_info():
|
|||||||
""")
|
""")
|
||||||
print(explanation.strip())
|
print(explanation.strip())
|
||||||
print("")
|
print("")
|
||||||
print(f"GPU Information:{gpu_info}")
|
print(f"\033[94mDiagnostic log created:\033[0m \033[92mdiagnostics.log. \033[94mA brief summary of results is displayed above on\033[0m")
|
||||||
print(f"\033[94mDiagnostic log created:\033[0m \033[92mdiagnostics.log\033[0m")
|
print(f"\033[94mscreen. Please see the log file for more detail.\033[0m")
|
||||||
print(f"\033[94mPlease upload the log file with any support ticket.\033[0m")
|
print(f"\033[94m\nPlease upload the log file with any support ticket.\033[0m")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
log_system_info()
|
log_system_info()
|
||||||
@@ -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,13 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
alltalk-tts:
|
||||||
|
image: erew123/alltalk_tts:cpu
|
||||||
|
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
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import platform
|
||||||
|
import site
|
||||||
import tempfile
|
import tempfile
|
||||||
import signal
|
import signal
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
@@ -13,14 +15,18 @@ import random
|
|||||||
import gc
|
import gc
|
||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
|
import psutil
|
||||||
import pandas
|
import pandas
|
||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from faster_whisper import WhisperModel
|
from faster_whisper import WhisperModel
|
||||||
from TTS.tts.layers.xtts.tokenizer import multilingual_cleaners
|
# Use a local Tokenizer to resolve Japanese support
|
||||||
|
# from TTS.tts.layers.xtts.tokenizer import multilingual_cleaners
|
||||||
|
from system.ft_tokenizer.tokenizer import multilingual_cleaners
|
||||||
|
import importlib.metadata as metadata
|
||||||
|
from packaging import version
|
||||||
|
|
||||||
# STARTUP VARIABLES
|
# STARTUP VARIABLES
|
||||||
this_dir = Path(__file__).parent.resolve()
|
this_dir = Path(__file__).parent.resolve()
|
||||||
@@ -30,6 +36,7 @@ progress = 0
|
|||||||
theme = gr.themes.Default()
|
theme = gr.themes.Default()
|
||||||
refresh_symbol = '🔄'
|
refresh_symbol = '🔄'
|
||||||
os.environ['TRAINER_TELEMETRY'] = '0'
|
os.environ['TRAINER_TELEMETRY'] = '0'
|
||||||
|
pfc_status = "pass"
|
||||||
|
|
||||||
# Define the path to the modeldownload config file file
|
# Define the path to the modeldownload config file file
|
||||||
modeldownload_config_file_path = this_dir / "modeldownload.json"
|
modeldownload_config_file_path = this_dir / "modeldownload.json"
|
||||||
@@ -62,6 +69,215 @@ if finetuned_model:
|
|||||||
finetuned_model = all((trained_model_directory / file).exists() for file in required_files)
|
finetuned_model = all((trained_model_directory / file).exists() for file in required_files)
|
||||||
basemodel_or_finetunedmodel = True
|
basemodel_or_finetunedmodel = True
|
||||||
|
|
||||||
|
#######################
|
||||||
|
#### DIAGS for PFC ####
|
||||||
|
#######################
|
||||||
|
|
||||||
|
def check_disk_space():
|
||||||
|
global pfc_status
|
||||||
|
# Get the current working directory
|
||||||
|
current_directory = os.getcwd()
|
||||||
|
# Get the disk usage statistics for the current directory's disk
|
||||||
|
disk_usage = shutil.disk_usage(current_directory)
|
||||||
|
# Convert the free space to GB (1GB = 1 << 30 bytes)
|
||||||
|
free_space_gb = disk_usage.free / (1 << 30)
|
||||||
|
# Check if the free space is more than 18GB
|
||||||
|
is_more_than_18gb = free_space_gb > 18
|
||||||
|
disk_space_icon = "✅"
|
||||||
|
if not is_more_than_18gb:
|
||||||
|
disk_space_icon ="❌"
|
||||||
|
pfc_status = "fail" # Update global status if disk space check fails
|
||||||
|
# Generating the markdown text for disk space check
|
||||||
|
disk_space_markdown = f"""
|
||||||
|
### 🟩 <u>Disk Space Check</u>
|
||||||
|
{disk_space_icon} **Disk Space (> 18 GB):** {'' if is_more_than_18gb else 'You have less than 18GB on this disk '} {free_space_gb:.2f} GB
|
||||||
|
"""
|
||||||
|
return disk_space_markdown
|
||||||
|
|
||||||
|
def test_cuda():
|
||||||
|
global pfc_status
|
||||||
|
cuda_home = os.environ.get('CUDA_HOME', 'N/A')
|
||||||
|
cuda_available = torch.cuda.is_available()
|
||||||
|
if cuda_available:
|
||||||
|
try:
|
||||||
|
# Attempt to create a tensor on GPU
|
||||||
|
torch.tensor([1.0, 2.0]).cuda()
|
||||||
|
cuda_status = "CUDA is available and working."
|
||||||
|
cuda_icon = "✅"
|
||||||
|
except Exception as e:
|
||||||
|
cuda_status = f"CUDA is available but not working. Error: {e}"
|
||||||
|
cuda_icon = "❌"
|
||||||
|
pfc_status = "fail" # Update global status
|
||||||
|
else:
|
||||||
|
cuda_status = "CUDA is not available."
|
||||||
|
pfc_status = "fail" # Update global status
|
||||||
|
return cuda_status, cuda_icon, cuda_home
|
||||||
|
|
||||||
|
def find_files_in_path_with_wildcard(pattern):
|
||||||
|
# Get the site-packages directory of the current Python environment
|
||||||
|
site_packages_path = site.getsitepackages()
|
||||||
|
found_paths = []
|
||||||
|
# Adjust the sub-directory based on the operating system
|
||||||
|
sub_directory = "nvidia/cublas"
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
sub_directory = os.path.join(sub_directory, "lib")
|
||||||
|
else:
|
||||||
|
sub_directory = os.path.join(sub_directory, "bin")
|
||||||
|
# Iterate over each site-packages directory (there can be more than one)
|
||||||
|
for directory in site_packages_path:
|
||||||
|
# Construct the search directory path
|
||||||
|
search_directory = os.path.join(directory, sub_directory)
|
||||||
|
# Use glob to find all files matching the pattern in this directory
|
||||||
|
for file_path in glob.glob(os.path.join(search_directory, pattern)):
|
||||||
|
if os.path.isfile(file_path): # Ensure it's a file
|
||||||
|
found_paths.append(file_path)
|
||||||
|
return found_paths
|
||||||
|
|
||||||
|
def generate_cuda_markdown():
|
||||||
|
global pfc_status
|
||||||
|
cuda_status, cuda_icon, cuda_home = test_cuda()
|
||||||
|
file_name = 'cublas64_11.*' if platform.system() == "Windows" else 'libcublas.so.11*'
|
||||||
|
found_paths = find_files_in_path_with_wildcard(file_name)
|
||||||
|
if found_paths:
|
||||||
|
found_paths_str = ' '.join(found_paths)
|
||||||
|
found_path_icon = '✅'
|
||||||
|
else:
|
||||||
|
found_paths_str = "cublas64_11 is not accessible."
|
||||||
|
found_path_icon = '❌'
|
||||||
|
pfc_status = "fail" # Update global status
|
||||||
|
# Check if 'cu118' or 'cu121' is in the PyTorch version string
|
||||||
|
pytorch_version = torch.__version__
|
||||||
|
if 'cu118' in pytorch_version or 'cu121' in pytorch_version:
|
||||||
|
pytorch_cuda_version_status = ''
|
||||||
|
pytorch_icon = '✅'
|
||||||
|
else:
|
||||||
|
pytorch_cuda_version_status = 'Pytorch CUDA version problem '
|
||||||
|
pytorch_icon = '❌'
|
||||||
|
pfc_status = "fail" # Update global status
|
||||||
|
cuda_markdown = f"""
|
||||||
|
### 🟨 <u>CUDA Information</u><br>
|
||||||
|
{found_path_icon} **Cublas64_11 found:** {found_paths_str}
|
||||||
|
{pytorch_icon} **CUDA_HOME path:** {cuda_home}
|
||||||
|
"""
|
||||||
|
pytorch_markdown = f"""
|
||||||
|
### 🟦 <u>Python & Pytorch Information</u>
|
||||||
|
{pytorch_icon} **PyTorch Version:** {pytorch_cuda_version_status} {torch.__version__}
|
||||||
|
{cuda_icon} **CUDA is working:** {cuda_status}
|
||||||
|
"""
|
||||||
|
return cuda_markdown, pytorch_markdown
|
||||||
|
|
||||||
|
def get_system_ram_markdown():
|
||||||
|
global pfc_status
|
||||||
|
virtual_memory = psutil.virtual_memory()
|
||||||
|
total_ram_gb = virtual_memory.total / (1024 ** 3)
|
||||||
|
available_ram_gb = virtual_memory.available / (1024 ** 3)
|
||||||
|
used_ram_percentage = virtual_memory.percent
|
||||||
|
|
||||||
|
# Check if the available RAM is less than 8GB
|
||||||
|
warning_if_low_ram = available_ram_gb < 8
|
||||||
|
|
||||||
|
# Decide the message based on the available RAM
|
||||||
|
ram_status_message = "Warning" if warning_if_low_ram else ""
|
||||||
|
ram_status_icon = "⚠️" if warning_if_low_ram else "✅"
|
||||||
|
|
||||||
|
if torch.cuda.is_available():
|
||||||
|
gpu_device_id = torch.cuda.current_device()
|
||||||
|
gpu_device_name = torch.cuda.get_device_name(gpu_device_id)
|
||||||
|
# Get the total and available memory in bytes, then convert to GB
|
||||||
|
gpu_total_mem_gb = torch.cuda.get_device_properties(gpu_device_id).total_memory / (1024 ** 3)
|
||||||
|
# gpu_available_mem_gb = (torch.cuda.get_device_properties(gpu_device_id).total_memory - torch.cuda.memory_allocated(gpu_device_id)) / (1024 ** 3)
|
||||||
|
# gpu_available_mem_gb = (torch.cuda.get_device_properties(gpu_device_id).total_memory - torch.cuda.memory_reserved(gpu_device_id)) / (1024 ** 3)
|
||||||
|
gpu_reserved_mem_gb = torch.cuda.memory_reserved(gpu_device_id) / (1024 ** 3)
|
||||||
|
gpu_available_mem_gb = gpu_total_mem_gb - gpu_reserved_mem_gb
|
||||||
|
# Check if total or available memory is less than 11 GB and set icons
|
||||||
|
gpu_total_status_icon = "⚠️" if gpu_total_mem_gb < 12 else "✅"
|
||||||
|
gpu_available_status_icon = "⚠️" if gpu_available_mem_gb < 12 else "✅"
|
||||||
|
gpu_status_icon = "✅"
|
||||||
|
else:
|
||||||
|
gpu_status_icon = "⚠️"
|
||||||
|
gpu_device_name = "Cannot detect a CUDA card"
|
||||||
|
gpu_total_mem_gb = "Cannot detect a CUDA card"
|
||||||
|
gpu_available_mem_gb = "Cannot detect a CUDA card"
|
||||||
|
gpu_total_status_icon = gpu_status_icon
|
||||||
|
gpu_available_status_icon = gpu_status_icon
|
||||||
|
|
||||||
|
system_ram_markdown = f"""
|
||||||
|
### 🟪 <u>System RAM and VRAM Information</u> <br>
|
||||||
|
{ram_status_icon} **Total RAM:** {total_ram_gb:.2f} GB<br>
|
||||||
|
{ram_status_icon} **Available RAM:** {ram_status_message + ' - Available RAM is less than 8 GB. You have ' if warning_if_low_ram else ''} {available_ram_gb:.2f} GB available ({used_ram_percentage:.2f}% used)<br><br>
|
||||||
|
{gpu_status_icon} **GPU Name:** {gpu_device_name}<br>
|
||||||
|
{gpu_total_status_icon} **GPU Total RAM:** {gpu_total_mem_gb:.2f} GB<br>
|
||||||
|
{gpu_available_status_icon} **GPU Available RAM:** {gpu_available_mem_gb:.2f} GB<br>
|
||||||
|
"""
|
||||||
|
return system_ram_markdown
|
||||||
|
|
||||||
|
|
||||||
|
def check_base_model(base_model_path, files_to_download):
|
||||||
|
global pfc_status
|
||||||
|
# Assuming files_to_download is a dict with keys as filenames
|
||||||
|
base_model_files = list(files_to_download.keys())
|
||||||
|
missing_files = []
|
||||||
|
# Check if all base model files exist
|
||||||
|
for file in base_model_files:
|
||||||
|
file_path = this_dir / base_path / model_path / file
|
||||||
|
if not file_path.exists():
|
||||||
|
missing_files.append(file)
|
||||||
|
pfc_status = "fail"
|
||||||
|
return len(missing_files) == 0
|
||||||
|
|
||||||
|
# Assuming base_model_path and files_to_download are set from the JSON config as shown above
|
||||||
|
base_model_detected = check_base_model(base_model_path, files_to_download)
|
||||||
|
|
||||||
|
def generate_base_model_markdown(base_model_detected):
|
||||||
|
global pfc_status
|
||||||
|
base_model_status = 'Base model detected' if base_model_detected else 'Base model not detected'
|
||||||
|
base_model_icon = '✅' if base_model_detected else '❌'
|
||||||
|
base_model_markdown = f"""
|
||||||
|
### ⬛ <u>XTTS Base Model Detection</u>
|
||||||
|
{base_model_icon} **Base XTTS Model Status:** {base_model_status}
|
||||||
|
"""
|
||||||
|
return base_model_markdown
|
||||||
|
|
||||||
|
def check_tts_version(required_version="0.22.0"):
|
||||||
|
global pfc_status
|
||||||
|
try:
|
||||||
|
# Get the installed version of TTS
|
||||||
|
installed_version = metadata.version("tts")
|
||||||
|
# Check if the installed version meets the required version
|
||||||
|
if version.parse(installed_version) >= version.parse(required_version):
|
||||||
|
tts_status = f"TTS version {installed_version} is installed and meets the requirement."
|
||||||
|
tts_status_icon = "✅"
|
||||||
|
else:
|
||||||
|
tts_status = f"❌ Fail - TTS version {installed_version} is installed but does not meet the required version {required_version}."
|
||||||
|
tts_status_icon = "❌"
|
||||||
|
pfc_status = "fail" # Update global status
|
||||||
|
except metadata.PackageNotFoundError:
|
||||||
|
# If TTS is not installed
|
||||||
|
tts_status = "TTS is not installed."
|
||||||
|
pfc_status = "fail" # Update global status
|
||||||
|
tts_markdown = f"""
|
||||||
|
### 🟥 <u>TTS Information</u><br>
|
||||||
|
{tts_status_icon} **TTS Version:** {tts_status}
|
||||||
|
"""
|
||||||
|
return tts_markdown
|
||||||
|
|
||||||
|
# Disk space check results to append to the Markdown
|
||||||
|
disk_space_results = check_disk_space()
|
||||||
|
cuda_results, pytorch_results = generate_cuda_markdown()
|
||||||
|
system_ram_results = get_system_ram_markdown()
|
||||||
|
base_model_results = generate_base_model_markdown(base_model_detected)
|
||||||
|
tts_version_status = check_tts_version()
|
||||||
|
|
||||||
|
def pfc_check_fail():
|
||||||
|
global pfc_status
|
||||||
|
if pfc_status == "fail":
|
||||||
|
print("[FINETUNE]")
|
||||||
|
print("[FINETUNE] \033[91m****** WARNING PRE-FLIGHT CHECKS FAILED ******* WARNING PRE-FLIGHT CHECKS FAILED *****\033[0m")
|
||||||
|
print("[FINETUNE] \033[91m* Please refer to the \033[93mPre-flight check tab \033[91mand resolve any issues before continuing. *\033[0m")
|
||||||
|
print("[FINETUNE] \033[91m*********** Expect errors and failures if you do not resolve these issues. ***********\033[0m")
|
||||||
|
print("[FINETUNE]")
|
||||||
|
return
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
#### STEP 1 BITS ####
|
#### STEP 1 BITS ####
|
||||||
#####################
|
#####################
|
||||||
@@ -75,10 +291,11 @@ def create_temporary_file(folder, suffix=".wav"):
|
|||||||
unique_filename = f"custom_tempfile_{int(time.time())}_{random.randint(1, 1000)}{suffix}"
|
unique_filename = f"custom_tempfile_{int(time.time())}_{random.randint(1, 1000)}{suffix}"
|
||||||
return os.path.join(folder, unique_filename)
|
return os.path.join(folder, unique_filename)
|
||||||
|
|
||||||
def format_audio_list(target_language, whisper_model, out_path, gradio_progress=progress):
|
def format_audio_list(target_language, whisper_model, out_path, eval_split_number, gradio_progress=progress):
|
||||||
|
pfc_check_fail()
|
||||||
audio_files = [os.path.join(audio_folder, file) for file in os.listdir(audio_folder) if file.endswith(('.mp3', '.flac', '.wav'))]
|
audio_files = [os.path.join(audio_folder, file) for file in os.listdir(audio_folder) if file.endswith(('.mp3', '.flac', '.wav'))]
|
||||||
buffer=0.2
|
buffer=0.2
|
||||||
eval_percentage=0.15
|
eval_percentage = eval_split_number / 100.0
|
||||||
speaker_name="coqui"
|
speaker_name="coqui"
|
||||||
audio_total_size = 0
|
audio_total_size = 0
|
||||||
os.makedirs(out_path, exist_ok=True)
|
os.makedirs(out_path, exist_ok=True)
|
||||||
@@ -87,6 +304,7 @@ def format_audio_list(target_language, whisper_model, out_path, gradio_progress=
|
|||||||
print("[FINETUNE] \033[94mPart of AllTalk\033[0m https://github.com/erew123/alltalk_tts/")
|
print("[FINETUNE] \033[94mPart of AllTalk\033[0m https://github.com/erew123/alltalk_tts/")
|
||||||
print("[FINETUNE] \033[94mCoqui Public Model License\033[0m")
|
print("[FINETUNE] \033[94mCoqui Public Model License\033[0m")
|
||||||
print("[FINETUNE] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
|
print("[FINETUNE] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mWhisper model: \033[92m{whisper_model} \033[94mLanguage: \033[92m{target_language} \033[94mEvaluation data percentage: \033[92m{eval_split_number}%\033[0m")
|
||||||
print("[FINETUNE] \033[94mStarting Step 1\033[0m - Preparing Audio/Generating the dataset")
|
print("[FINETUNE] \033[94mStarting Step 1\033[0m - Preparing Audio/Generating the dataset")
|
||||||
# Write the target language to lang.txt in the output directory
|
# Write the target language to lang.txt in the output directory
|
||||||
lang_file_path = os.path.join(out_path, "lang.txt")
|
lang_file_path = os.path.join(out_path, "lang.txt")
|
||||||
@@ -109,7 +327,8 @@ def format_audio_list(target_language, whisper_model, out_path, gradio_progress=
|
|||||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||||
|
|
||||||
print("[FINETUNE] Loading Whisper Model:", whisper_model)
|
print("[FINETUNE] Loading Whisper Model:", whisper_model)
|
||||||
asr_model = WhisperModel(whisper_model, device=device, compute_type="float16")
|
print("[FINETUNE] Model will be downloaded if its not available, which will take a few minutes.")
|
||||||
|
asr_model = WhisperModel(whisper_model, device=device, compute_type="float32")
|
||||||
|
|
||||||
metadata = {"audio_file": [], "text": [], "speaker_name": []}
|
metadata = {"audio_file": [], "text": [], "speaker_name": []}
|
||||||
|
|
||||||
@@ -286,6 +505,8 @@ def format_audio_list(target_language, whisper_model, out_path, gradio_progress=
|
|||||||
# deallocate VRAM and RAM
|
# deallocate VRAM and RAM
|
||||||
del asr_model, final_eval_set, final_training_set, new_data_df, existing_metadata
|
del asr_model, final_eval_set, final_training_set, new_data_df, existing_metadata
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
if torch.cuda.is_available():
|
||||||
|
torch.cuda.empty_cache()
|
||||||
existing_train_df = None
|
existing_train_df = None
|
||||||
existing_eval_df = None
|
existing_eval_df = None
|
||||||
print("[FINETUNE] Train CSV:", train_metadata_path)
|
print("[FINETUNE] Train CSV:", train_metadata_path)
|
||||||
@@ -313,6 +534,7 @@ def basemodel_or_finetunedmodel_choice(value):
|
|||||||
basemodel_or_finetunedmodel = False
|
basemodel_or_finetunedmodel = False
|
||||||
|
|
||||||
def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv, output_path, max_audio_length=255995):
|
def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv, output_path, max_audio_length=255995):
|
||||||
|
pfc_check_fail()
|
||||||
# Logging parameters
|
# Logging parameters
|
||||||
RUN_NAME = "XTTS_FT"
|
RUN_NAME = "XTTS_FT"
|
||||||
PROJECT_NAME = "XTTS_trainer"
|
PROJECT_NAME = "XTTS_trainer"
|
||||||
@@ -322,6 +544,27 @@ def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv,
|
|||||||
# Set here the path that the checkpoints will be saved. Default: ./training/
|
# Set here the path that the checkpoints will be saved. Default: ./training/
|
||||||
OUT_PATH = os.path.join(output_path, "training")
|
OUT_PATH = os.path.join(output_path, "training")
|
||||||
print("[FINETUNE] \033[94mStarting Step 2\033[0m - Fine-tuning the XTTS Encoder")
|
print("[FINETUNE] \033[94mStarting Step 2\033[0m - Fine-tuning the XTTS Encoder")
|
||||||
|
print(f"[FINETUNE] \033[94mLanguage: \033[92m{language} \033[94mEpochs: \033[92m{num_epochs} \033[94mBatch size: \033[92m{batch_size}\033[0m \033[94mGrad accumulation steps: \033[92m{grad_acumm}\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mTraining : \033[92m{train_csv}\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mEvaluation : \033[92m{eval_csv}\033[0m")
|
||||||
|
if torch.cuda.is_available():
|
||||||
|
torch.cuda.empty_cache()
|
||||||
|
# Get the current device ID
|
||||||
|
gpu_device_id = torch.cuda.current_device()
|
||||||
|
gpu_available_mem_gb = (torch.cuda.get_device_properties(gpu_device_id).total_memory - torch.cuda.memory_allocated(gpu_device_id)) / (1024 ** 3)
|
||||||
|
print(f"[FINETUNE] \033[94mAvailable VRAM: \033[92m{gpu_available_mem_gb:.2f} GB\033[0m")
|
||||||
|
if gpu_available_mem_gb < 12:
|
||||||
|
print(f"[FINETUNE]")
|
||||||
|
print(f"[FINETUNE] \033[91m****** WARNING PRE-FLIGHT CHECKS FAILED ******* WARNING PRE-FLIGHT CHECKS FAILED *****\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mAvailable VRAM: \033[92m{gpu_available_mem_gb:.2f} GB\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mIf you are running on a Linux system and you have 12GB's or less of VRAM, this step\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mmay fail, due to not enough GPU VRAM. Windows systems will use system RAM as extended\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mVRAM and so should work ok. However, Windows machines will need enough System RAM\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94mavailable. Please read the PFC help section available on the first tab of the web\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[94minterface for more information.\033[0m")
|
||||||
|
print(f"[FINETUNE] \033[91m****** WARNING PRE-FLIGHT CHECKS FAILED ******* WARNING PRE-FLIGHT CHECKS FAILED *****\033[0m")
|
||||||
|
print(f"[FINETUNE]")
|
||||||
|
|
||||||
# Create the directory
|
# Create the directory
|
||||||
os.makedirs(OUT_PATH, exist_ok=True)
|
os.makedirs(OUT_PATH, exist_ok=True)
|
||||||
|
|
||||||
@@ -346,7 +589,7 @@ def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv,
|
|||||||
|
|
||||||
if basemodel_or_finetunedmodel:
|
if basemodel_or_finetunedmodel:
|
||||||
# BASE XTTS model checkpoints for fine-tuning.
|
# BASE XTTS model checkpoints for fine-tuning.
|
||||||
print("[FINETUNE] Starting finetuning on Base Model")
|
print("[FINETUNE] Starting finetuning on \033[92mBase Model\033[0m")
|
||||||
TOKENIZER_FILE = str(this_dir / base_path / model_path / "vocab.json")
|
TOKENIZER_FILE = str(this_dir / base_path / model_path / "vocab.json")
|
||||||
XTTS_CHECKPOINT = str(this_dir / base_path / model_path / "model.pth")
|
XTTS_CHECKPOINT = str(this_dir / base_path / model_path / "model.pth")
|
||||||
XTTS_CONFIG_FILE = str(this_dir / base_path / model_path / "config.json")
|
XTTS_CONFIG_FILE = str(this_dir / base_path / model_path / "config.json")
|
||||||
@@ -354,7 +597,7 @@ def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv,
|
|||||||
MEL_NORM_FILE = str(this_dir / base_path / model_path / "mel_stats.pth")
|
MEL_NORM_FILE = str(this_dir / base_path / model_path / "mel_stats.pth")
|
||||||
else:
|
else:
|
||||||
# FINETUNED XTTS model checkpoints for fine-tuning.
|
# FINETUNED XTTS model checkpoints for fine-tuning.
|
||||||
print("[FINETUNE] Starting finetuning on Existing Finetuned Model")
|
print("[FINETUNE] Starting finetuning on \033[92mExisting Finetuned Model\033[0m")
|
||||||
TOKENIZER_FILE = str(this_dir / base_path / "trainedmodel" / "vocab.json")
|
TOKENIZER_FILE = str(this_dir / base_path / "trainedmodel" / "vocab.json")
|
||||||
XTTS_CHECKPOINT = str(this_dir / base_path / "trainedmodel" / "model.pth")
|
XTTS_CHECKPOINT = str(this_dir / base_path / "trainedmodel" / "model.pth")
|
||||||
XTTS_CONFIG_FILE = str(this_dir / base_path / "trainedmodel" / "config.json")
|
XTTS_CONFIG_FILE = str(this_dir / base_path / "trainedmodel" / "config.json")
|
||||||
@@ -381,6 +624,11 @@ def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv,
|
|||||||
# define audio config
|
# define audio config
|
||||||
audio_config = XttsAudioConfig(sample_rate=22050, dvae_sample_rate=22050, output_sample_rate=24000)
|
audio_config = XttsAudioConfig(sample_rate=22050, dvae_sample_rate=22050, output_sample_rate=24000)
|
||||||
|
|
||||||
|
# Resolve Japanese threading issue
|
||||||
|
number_of_workers = 8
|
||||||
|
if language == "ja":
|
||||||
|
number_of_workers = 0
|
||||||
|
|
||||||
# training parameters config
|
# training parameters config
|
||||||
config = GPTTrainerConfig(
|
config = GPTTrainerConfig(
|
||||||
epochs=num_epochs,
|
epochs=num_epochs,
|
||||||
@@ -395,7 +643,7 @@ def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv,
|
|||||||
batch_size=BATCH_SIZE,
|
batch_size=BATCH_SIZE,
|
||||||
batch_group_size=48,
|
batch_group_size=48,
|
||||||
eval_batch_size=BATCH_SIZE,
|
eval_batch_size=BATCH_SIZE,
|
||||||
num_loader_workers=8,
|
num_loader_workers=number_of_workers,
|
||||||
eval_split_max_size=256,
|
eval_split_max_size=256,
|
||||||
print_step=50,
|
print_step=50,
|
||||||
plot_step=100,
|
plot_step=100,
|
||||||
@@ -469,17 +717,25 @@ def clear_gpu_cache():
|
|||||||
if torch.cuda.is_available():
|
if torch.cuda.is_available():
|
||||||
torch.cuda.empty_cache()
|
torch.cuda.empty_cache()
|
||||||
|
|
||||||
|
def find_a_speaker_file(folder_path):
|
||||||
|
search_path = folder_path / "*" / "speakers_xtts.pth"
|
||||||
|
files = glob.glob(str(search_path), recursive=True)
|
||||||
|
latest_file = max(files, key=os.path.getctime, default=None)
|
||||||
|
return latest_file
|
||||||
|
|
||||||
XTTS_MODEL = None
|
XTTS_MODEL = None
|
||||||
def load_model(xtts_checkpoint, xtts_config, xtts_vocab):
|
def load_model(xtts_checkpoint, xtts_config, xtts_vocab):
|
||||||
|
pfc_check_fail()
|
||||||
global XTTS_MODEL
|
global XTTS_MODEL
|
||||||
clear_gpu_cache()
|
clear_gpu_cache()
|
||||||
if not xtts_checkpoint or not xtts_config or not xtts_vocab:
|
if not xtts_checkpoint or not xtts_config or not xtts_vocab:
|
||||||
return "You need to run the previous steps or manually set the `XTTS checkpoint path`, `XTTS config path`, and `XTTS vocab path` fields !!"
|
return "You need to run the previous steps or manually set the `XTTS checkpoint path`, `XTTS config path`, and `XTTS vocab path` fields !!"
|
||||||
|
xtts_speakers_pth = find_a_speaker_file(this_dir / "models")
|
||||||
config = XttsConfig()
|
config = XttsConfig()
|
||||||
config.load_json(xtts_config)
|
config.load_json(xtts_config)
|
||||||
XTTS_MODEL = Xtts.init_from_config(config)
|
XTTS_MODEL = Xtts.init_from_config(config)
|
||||||
print("[FINETUNE] \033[94mStarting Step 3\033[0m Loading XTTS model!")
|
print("[FINETUNE] \033[94mStarting Step 3\033[0m Loading XTTS model!")
|
||||||
XTTS_MODEL.load_checkpoint(config, checkpoint_path=xtts_checkpoint, vocab_path=xtts_vocab, use_deepspeed=False)
|
XTTS_MODEL.load_checkpoint(config, checkpoint_path=xtts_checkpoint, vocab_path=xtts_vocab, use_deepspeed=False, speaker_file_path=xtts_speakers_pth)
|
||||||
if torch.cuda.is_available():
|
if torch.cuda.is_available():
|
||||||
XTTS_MODEL.cuda()
|
XTTS_MODEL.cuda()
|
||||||
|
|
||||||
@@ -510,7 +766,6 @@ def run_tts(lang, tts_text, speaker_audio_file):
|
|||||||
|
|
||||||
return "Speech generated !", out_path, speaker_audio_file
|
return "Speech generated !", out_path, speaker_audio_file
|
||||||
|
|
||||||
|
|
||||||
def get_available_voices(minimum_size_kb=1200):
|
def get_available_voices(minimum_size_kb=1200):
|
||||||
voice_files = [
|
voice_files = [
|
||||||
voice for voice in Path(f"{this_dir}/finetune/tmp-trn/wavs").glob("*.wav")
|
voice for voice in Path(f"{this_dir}/finetune/tmp-trn/wavs").glob("*.wav")
|
||||||
@@ -581,7 +836,7 @@ def compact_model():
|
|||||||
torch.save(checkpoint, target_dir / "model.pth")
|
torch.save(checkpoint, target_dir / "model.pth")
|
||||||
|
|
||||||
# Specify the files you want to copy
|
# Specify the files you want to copy
|
||||||
files_to_copy = ["vocab.json", "config.json", "dvae.pth", "mel_stats.pth"]
|
files_to_copy = ["vocab.json", "config.json", "dvae.pth", "mel_stats.pth","speakers_xtts.pth", ]
|
||||||
|
|
||||||
for file_name in files_to_copy:
|
for file_name in files_to_copy:
|
||||||
src_path = this_dir / base_path / base_model_path / file_name
|
src_path = this_dir / base_path / base_model_path / file_name
|
||||||
@@ -639,7 +894,7 @@ def compact_lastfinetuned_model():
|
|||||||
torch.save(checkpoint, target_dir / "model.pth")
|
torch.save(checkpoint, target_dir / "model.pth")
|
||||||
|
|
||||||
# Specify the files you want to copy
|
# Specify the files you want to copy
|
||||||
files_to_copy = ["vocab.json", "config.json", "dvae.pth", "mel_stats.pth"]
|
files_to_copy = ["vocab.json", "config.json", "dvae.pth", "mel_stats.pth", "speakers_xtts.pth",]
|
||||||
|
|
||||||
for file_name in files_to_copy:
|
for file_name in files_to_copy:
|
||||||
src_path = this_dir / base_path / base_model_path / file_name
|
src_path = this_dir / base_path / base_model_path / file_name
|
||||||
@@ -699,7 +954,6 @@ def compact_legacy_model():
|
|||||||
print("[FINETUNE] model.pth created in '/finetune/'")
|
print("[FINETUNE] model.pth created in '/finetune/'")
|
||||||
return "model.pth created in '/finetune/'"
|
return "model.pth created in '/finetune/'"
|
||||||
|
|
||||||
|
|
||||||
def delete_training_data():
|
def delete_training_data():
|
||||||
# Define the folder to be deleted
|
# Define the folder to be deleted
|
||||||
folder_to_delete = Path(this_dir / "finetune" / "tmp-trn")
|
folder_to_delete = Path(this_dir / "finetune" / "tmp-trn")
|
||||||
@@ -724,7 +978,6 @@ def delete_training_data():
|
|||||||
print(f"[FINETUNE] Folder {folder_to_delete} does not exist.")
|
print(f"[FINETUNE] Folder {folder_to_delete} does not exist.")
|
||||||
return "Folder '/finetune/tmp-trn/' does not exist."
|
return "Folder '/finetune/tmp-trn/' does not exist."
|
||||||
|
|
||||||
|
|
||||||
def delete_voice_sample_contents():
|
def delete_voice_sample_contents():
|
||||||
# Define the folder to be cleared
|
# Define the folder to be cleared
|
||||||
folder_to_clear = Path(this_dir / "finetune" / "put-voice-samples-in-here")
|
folder_to_clear = Path(this_dir / "finetune" / "put-voice-samples-in-here")
|
||||||
@@ -747,7 +1000,6 @@ def delete_voice_sample_contents():
|
|||||||
print(f"[FINETUNE] Folder {folder_to_clear} does not exist.")
|
print(f"[FINETUNE] Folder {folder_to_clear} does not exist.")
|
||||||
return f"Folder 'put-voice-samples-in-here' does not exist."
|
return f"Folder 'put-voice-samples-in-here' does not exist."
|
||||||
|
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
#### OTHER Generic ####
|
#### OTHER Generic ####
|
||||||
#######################
|
#######################
|
||||||
@@ -773,7 +1025,6 @@ class Logger:
|
|||||||
sys.stdout = Logger()
|
sys.stdout = Logger()
|
||||||
sys.stderr = sys.stdout
|
sys.stderr = sys.stdout
|
||||||
|
|
||||||
|
|
||||||
# logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
# logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -784,47 +1035,67 @@ logging.basicConfig(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def read_logs():
|
def read_logs():
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
with open(sys.stdout.log_file, "r") as f:
|
with open(sys.stdout.log_file, "r") as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
def cleanup_before_exit(signum, frame):
|
def cleanup_before_exit(signum, frame):
|
||||||
print("[FINETUNE] Received interrupt signal. Cleaning up and exiting...")
|
print("[FINETUNE] Received interrupt signal. Cleaning up and exiting...")
|
||||||
# Perform cleanup operations here if necessary
|
# Perform cleanup operations here if necessary
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
def create_refresh_button(refresh_components, refresh_methods, elem_class, interactive=True):
|
||||||
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_class, interactive=True):
|
|
||||||
"""
|
|
||||||
Copied from https://github.com/AUTOMATIC1111/stable-diffusion-webui
|
|
||||||
"""
|
|
||||||
def refresh():
|
def refresh():
|
||||||
refresh_method()
|
updates = {}
|
||||||
args = refreshed_args() if callable(refreshed_args) else refreshed_args
|
for component, method in zip(refresh_components, refresh_methods):
|
||||||
|
args = method() if callable(method) else method
|
||||||
|
if args and 'choices' in args:
|
||||||
|
# Select the most recent file (last in the sorted list)
|
||||||
|
args['value'] = args['choices'][-1] if args['choices'] else ""
|
||||||
for k, v in args.items():
|
for k, v in args.items():
|
||||||
setattr(refresh_component, k, v)
|
setattr(component, k, v)
|
||||||
|
updates[component] = gr.update(**(args or {}))
|
||||||
|
return updates
|
||||||
|
|
||||||
return gr.update(**(args or {}))
|
refresh_button = gr.Button("Refresh Dropdowns", elem_classes=elem_class, interactive=interactive)
|
||||||
|
|
||||||
refresh_button = gr.Button(refresh_symbol, elem_classes=elem_class, interactive=interactive, scale=0)
|
|
||||||
refresh_button.click(
|
refresh_button.click(
|
||||||
fn=refresh,
|
fn=refresh,
|
||||||
inputs=[],
|
inputs=[],
|
||||||
outputs=[refresh_component]
|
outputs=refresh_components
|
||||||
)
|
)
|
||||||
|
|
||||||
return refresh_button
|
return refresh_button
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pfc_markdown = f"""
|
||||||
|
### 🚀 <u>Pre-flight Checklist for Fine-tuning</u><br>
|
||||||
|
◽ <strong>Ensure</strong> each criterion is marked with a green check mark ✅ and a Pass status. <strong>Finetuning will fail otherwise.</strong><br>
|
||||||
|
◽ The help tabs along the top will assist in resolving issues and you can also find additional help guides on the AllTalk [GitHub repository](https://github.com/erew123/alltalk_tts#-finetuning-a-model).<br>
|
||||||
|
◽ For an overview of fine-tuning procedures, please refer to the "General Finetuning info" tab or visit the AllTalk [GitHub repository](https://github.com/erew123/alltalk_tts#-finetuning-a-model).
|
||||||
|
"""
|
||||||
|
|
||||||
|
custom_css = """
|
||||||
|
body {
|
||||||
|
font-size: 16px; /* Adjust the base font size as needed */
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-size: 1.25em; /* Adjust heading sizes relative to the base size */
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 1.1em; /* Paragraph font size, relative to the base size */
|
||||||
|
margin-bottom: 10px; /* Adjust paragraph spacing */
|
||||||
|
}
|
||||||
|
.gradio_container {
|
||||||
|
zoom: 1.1; /* Adjust the zoom to scale the entire container */
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Register the signal handler
|
# Register the signal handler
|
||||||
signal.signal(signal.SIGINT, cleanup_before_exit)
|
signal.signal(signal.SIGINT, cleanup_before_exit)
|
||||||
|
|
||||||
|
|
||||||
################
|
################
|
||||||
#### GRADIO ####
|
#### GRADIO ####
|
||||||
################
|
################
|
||||||
@@ -868,61 +1139,150 @@ if __name__ == "__main__":
|
|||||||
#### GRADIO INFO ####
|
#### GRADIO INFO ####
|
||||||
#####################
|
#####################
|
||||||
|
|
||||||
with gr.Blocks(theme=theme) as demo:
|
with gr.Blocks(theme=theme, css=custom_css) as demo:
|
||||||
with gr.Tab("Information/Guide"):
|
with gr.Tab("🚀 PFC"):
|
||||||
|
with gr.Tab("🚀 Pre-Flight Checklist"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{pfc_markdown}
|
||||||
|
{disk_space_results}
|
||||||
|
{system_ram_results}
|
||||||
|
{cuda_results}
|
||||||
|
{pytorch_results}
|
||||||
|
{base_model_results}
|
||||||
|
{tts_version_status}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
with gr.Tab("🟩 Disks Help"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{disk_space_results}<br><br>
|
||||||
|
◽ During actual training (Step 2) Finetuning will require approximately 18GB's of free disk space while performing training and will fail or perform badly if there is any less disk space. The majority of this disk space is used temporarily and will be cleared when you reach Step 4 and move & compact the model then delete the training data.<br>
|
||||||
|
◽ Because lots of data is being copied around, <strong>mechanical hard disks</strong> will be slow.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
with gr.Tab("🟪 RAM & VRAM Help"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{system_ram_results}<br>
|
||||||
|
◽ During actual training (Step 2) Finetuning will use around **14GB's** of VRAM. If your GPU doesnt have 14GB's of VRAM:<br>
|
||||||
|
- **Windows** systems will attempt to extend VRAM into your System RAM, and so should work.<br>
|
||||||
|
- **Linux** systems can only use the available VRAM, so may fail on 12GB VRAM or smaller GPU's.<br>
|
||||||
|
◽ For **Windows** users with 12GB or less, if you also have very low or slow System RAM you can expect bad performance or the training to fail.<br>
|
||||||
|
- 12GB cards may need 2GB System RAM.<br>
|
||||||
|
- 8GB cards may need 6GB System RAM.<br>
|
||||||
|
- 6GB cards may need 8GB System RAM.<br>
|
||||||
|
◽ Its hard to estimate what performance impact this could will have, due to different memory speeds, PCI speeds, GPU speeds etc.<br>
|
||||||
|
◽ If you have a low VRAM scenario and also are attempting to run on a mechanical hard drive, Finetuning could take ??? amount of time.<br>
|
||||||
|
◽ On Windows machines, please ensure you have **not** disabled System Memory Fallback for Stable Diffusion <a href="https://nvidia.custhelp.com/app/answers/detail/a_id/5490/~/system-memory-fallback-for-stable-diffusion" target="_blank">link here</a><br>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
with gr.Tab("🟨 CUDA & Cublas Help"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{cuda_results}<br><br>
|
||||||
|
◽ It DOESNT matter what version of CUDA you have installed within Python either, CUDA 11.8, CUDA 12.1 etc. The NVIDIA CUDA Development Toolkit is a completly different and seperate thing from Python/PyTorch.<br>
|
||||||
|
◽ Finetuning simply wants to access a tool within the CUDA Development Toolkit 11.8 called Cublas64_11.<br>
|
||||||
|
◽ If you dont have the toolkit installed, the idea is just to install the smallest bit possible and this will not affect or impact other things on your system.<br><br>
|
||||||
|
◽ You will need to download the Nvidia Cuda Toolkit 11.8<span style="color: #3366ff;"> network install</span> from <a href="https://developer.nvidia.com/cuda-11-8-0-download-archive" target="_blank">link here</a><br>
|
||||||
|
◽ 1) Run the installer and select <span style="color: #3366ff;">Custom Advanced</span> Uncheck <span style="color: #3366ff;">everything</span> at the top then expand <span style="color: #3366ff;">CUDA</span>, <span style="color: #3366ff;">Development</span> > <span style="color: #3366ff;">Compiler</span> > and select <span style="color: #3366ff;;">nvcc</span> then expand <span style="color: #3366ff;;">Libraries</span> and select <span style="color: #3366ff;;">CUBLAS</span>.<br>
|
||||||
|
◽ 2) Back at the top of <span style="color: #3366ff;">CUDA</span>, expand <span style="color: #3366ff;">Runtime</span> > <span style="color: #3366ff;">Libraries</span> and select <span style="color: #3366ff;">CUBLAS</span>. Click <span style="color: #3366ff;;">Next</span>, accept the default path (taking a note of its location) and let the install run. <br>
|
||||||
|
◽ 3) You should be able to drop to your terminal or command prompt and type <span style="color: #3366ff;">nvcc --version</span> and have it report <span style="color: #00a000;">Cuda compilation tools, release 11.8</span>. If it does you are good to go. If it doesn't > Step 4.<br>
|
||||||
|
◽ 4) <strong>Linux users</strong>, you can temporarily add these paths on your current terminal window with (you may need to confirm these are correct for your flavour of Linux):<br><br>
|
||||||
|
<span style="color: #3366ff;">export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}</span> (Add it to your ~/.bashrc if you want this to be permanent)<br>
|
||||||
|
<span style="color: #3366ff;">export LD_LIBRARY_PATH=/usr/local/cuda-11.8/bin</span><br><br>
|
||||||
|
<strong>Windows users</strong> need the add the following to the PATH environment variable. Start menu and search for "Environment Variables" or "Edit the system environment variables.". <br>
|
||||||
|
Find and select the "Path" variable, then click on the "Edit...". Click on the "New" button and add:<br><br>
|
||||||
|
<span style="color: #3366ff;">C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin.</span><br><br>
|
||||||
|
◽ 5) Once you have these set correctly, you should be able to open a new command prompt/terminal and <span style="color: #3366ff;">nvcc --version</span> at the command prompt/terminal, resulting in <span style="color: #00a000;">Cuda compilation tools, release 11.8</span>.<br>
|
||||||
|
◽ 6) If the nvcc command doesn't work OR it reports a version different from 11.8, finetuning wont work, so you will to double check your environment variables and get them working correctly.<br>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
with gr.Tab("🟦 Python & PyTorch Help"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{pytorch_results}<br><br>
|
||||||
|
◽ On the PyTorch version the:<br>
|
||||||
|
- first few digits are the version of PyTorch e.g. 2.1.0 is PyTorch 2.1.0<br>
|
||||||
|
- last few digits refer to the CUDA version e.g. cu118 is Cuda 11.8. cu121 is Cuda 12.1.<br>
|
||||||
|
◽ Ensure you have started your Python envuronment before running finetuning otherwise you will have failures on the above checks.<br>
|
||||||
|
◽ If PyTorch does not show a CUDA version, then PyTorch will need reinstalling with CUDA. I would suggest running <span style="color: #3366ff;">pip cache purge</span> before installing PyTorch again.<br>
|
||||||
|
◽ It DOESNT matter what version of PyTorch and CUDA you have installed within Python, CUDA 11.8, CUDA 12.1 etc. The NVIDIA CUDA Development Toolkit is a completly different and seperate thing.<br>
|
||||||
|
◽ Finetuning simply wants to access a tool within the CUDA Development Toolkit called Cublas64_11.<br>
|
||||||
|
◽ If you dont have the toolkit installed, the idea is just to install the smallest bit possible and this will not affect or impact other things on your system.<br>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
with gr.Tab("⬛ XTTS Base Model Help"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{base_model_results}<br><br>
|
||||||
|
◽ If your basemodel is not being detected, please ensure that <span style="color: #3366ff;">finetune.py</span> is being run from the AllTalk main folder.<br>
|
||||||
|
◽ Ensure you have started AllTalk normally at least once. You can start it again and it will download any missing files.<br>
|
||||||
|
◽ Check that there is an XTTS model within the models folder e.g. <span style="color: #3366ff;">/models/xttsv2_2.0.2/</span><br>
|
||||||
|
◽ The files required are "model.pth", "vocab.json", "config.json", "dvae.pth", "mel_stats.pth", "speakers_xtts.pth".
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
with gr.Tab("🟥 TTS Version Help"):
|
||||||
|
gr.Markdown(
|
||||||
|
f"""
|
||||||
|
{tts_version_status}<br><br>
|
||||||
|
◽ If your TTS version is showing as the incorrect version, please reinstall the Finetuning requirements at the command prompt/terminal.<br>
|
||||||
|
◽ <span style="color: #3366ff;">pip install -r requirements_finetune.txt</span><br>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
with gr.Tab("ℹ️ General Finetuning info"):
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
## <u>Finetuning Information</u><br>
|
|
||||||
### 🟥 <u>Important Note</u>
|
### 🟥 <u>Important Note</u>
|
||||||
#### - <span style="color: #3366ff;">finetune.py</span> needs to be run from the <span style="color: #3366ff;">/alltalk_tts/</span> folder. Don't move the location of this script.
|
◽ <span style="color: #3366ff;">finetune.py</span> needs to be run from the <span style="color: #3366ff;">/alltalk_tts/</span> folder. Don't move the location of this script.
|
||||||
#### - Have you run AllTalk at least once? It needs to have downloaded+updated the voice model, before we can finetune it.
|
|
||||||
### 🟦 <u>What you need to run finetuning</u>
|
### 🟦 <u>What you need to run finetuning</u>
|
||||||
#### - An Nvidia GPU. Tested on Windows with extended shared VRAM and training used about 16GB's total (which worked on a 12GB card).
|
◽ An Nvidia GPU.<br>
|
||||||
#### - If you have multiple Nvidia GPU's in your system, please see this [important note](https://github.com/erew123/alltalk_tts#-i-have-multiple-gpus-and-i-have-problems-running-finetuning).
|
◽ If you have multiple Nvidia GPU's in your system, please see the Github Help section [Multiple GPU's](https://github.com/erew123/alltalk_tts#performance-and-compatibility-issues).<br>
|
||||||
#### - I have not been able to test this on a GPU with less than 12GB of VRAM, so cannot say if it will work or how that would affect performance.
|
◽ Some decent quality audio, multiple files if you like. Minimum of 2 minutes and Ive tested up to 20 minutes of audio.<br>
|
||||||
#### - <span style="color: red;">Version 11.8</span> of Nvidia cuBLAS and cuDNN (guide below). Only 11.8 of cuBLAS and cuDNN work for this process currently.
|
◽ There is no major need to chop down your audio files into small slices as Step 1 will do that for you automatically and prepare the training set. But this can be helpful in cases where:<br>
|
||||||
#### - Minimum <span style="color: red;">18GB</span> free disk space (most of it is used temporarily).
|
- Whisper doesnt correctly detect and split down audio files.<br>
|
||||||
#### - Some decent quality audio, multiple files if you like. Minimum of 2 minutes and Ive tested up to 20 minutes of audio.
|
- You do not get a lot of "Speaker Reference Audio" files at the end of training.<br>
|
||||||
#### - There is no major need to chop down your audio files into small slices as Step 1 will do that for you automatically and prepare the training set. Ive been testing with 5 minute long clips.
|
◽ This process will need access to all your GPU and VRAM, so close any other software that's using your GPU currently.<br>
|
||||||
#### - This process will need access to all your GPU and VRAM, so close any other software that's using your GPU currently.
|
### 🟨 <u>What do I do from here?</u><br>
|
||||||
### 🟨 <u>Setting up cuBLAS and cuDNN <span style="color: red;">Version 11.8</span></u>
|
◽ Proceed through Step 1, 2, 3 and onto "What to do next".<br>
|
||||||
#### - If you have the <span style="color: #3366ff;;">Nvidia CUDA Toolkit Version 11.8</span> installed and can type <span style="color: #3366ff;;">nvcc --version</span> at the command prompt/terminal and it reports <span style="color: #00a000;">Cuda compilation tools, release 11.8</span> you should be good to go.
|
### 🟩 <u>Additional Information</u><br>
|
||||||
#### - If you dont have the toolkit installed, the idea is just to install the smallest bit possible and this will not affect or impact other things on your system.
|
◽ Guidance is provided on each step of the process however, if you are after more detailed information please visit:<br>
|
||||||
#### - You will need to download the Nvidia Cuda Toolkit 11.8<span style="color: #3366ff;"> network</span> install from [here](https://developer.nvidia.com/cuda-11-8-0-download-archive)
|
◽ [AllTalk Github Finetuning](https://github.com/erew123/alltalk_tts#-finetuning-a-model)<br>
|
||||||
#### 1) Run the installer and select <span style="color: #3366ff;">Custom Advanced</span> Uncheck <span style="color: #3366ff;">everything</span> at the top then expand <span style="color: #3366ff;">CUDA</span>, <span style="color: #3366ff;">Development</span> > <span style="color: #3366ff;">Compiler</span> > and select <span style="color: #3366ff;;">nvcc</span> then expand <span style="color: #3366ff;;">Libraries</span> and select <span style="color: #3366ff;;">CUBLAS</span>.
|
◽ [Coqui XTTS Documentation](https://docs.coqui.ai/en/latest/index.html)<br>
|
||||||
#### 2) Back at the top of <span style="color: #3366ff;">CUDA</span>, expand <span style="color: #3366ff;">Runtime</span> > <span style="color: #3366ff;">Libraries</span> and select <span style="color: #3366ff;">CUBLAS</span>. Click <span style="color: #3366ff;;">Next</span>, accept the default path (taking a note of its location) and let the install run.
|
|
||||||
#### 3) You should be able to drop to your terminal or command prompt and type <span style="color: #3366ff;">nvcc --version</span> and have it report <span style="color: #00a000;">Cuda compilation tools, release 11.8</span>. If it does you are good to go. If it doesn't > Step 4.
|
|
||||||
#### 4) Linux users, you can temporarily add these paths on your current terminal window with (you may need to confirm these are correct for your flavour of Linux):
|
|
||||||
#### <span style="color: #3366ff;">export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}</span> (Add it to your ~/.bashrc if you want this to be permanent)
|
|
||||||
#### <span style="color: #3366ff;">export LD_LIBRARY_PATH=/usr/local/cuda-11.8/bin</span>
|
|
||||||
#### Windows users need the add the following to the PATH environment variable. Start menu and search for "Environment Variables" or "Edit the system environment variables.".
|
|
||||||
#### Find and select the "Path" variable, then click on the "Edit...". Click on the "New" button and add:
|
|
||||||
#### <span style="color: #3366ff;">C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin.</span>
|
|
||||||
#### 5) Once you have these set correctly, you should be able to open a new command prompt/terminal and <span style="color: #3366ff;">nvcc --version</span> at the command prompt/terminal, resulting in <span style="color: #00a000;">Cuda compilation tools, release 11.8</span>.
|
|
||||||
#### 6) If the nvcc command doesn't work OR it reports a version different from 11.8, finetuning wont work, so you will to double check your environment variables and get them working correctly.
|
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
#### GRADIO STEP 1 ####
|
#### GRADIO STEP 1 ####
|
||||||
#######################
|
#######################
|
||||||
with gr.Tab("Step 1 - Preparing Audio/Generating the dataset"):
|
with gr.Tab("📁 Step 1 - Generating the dataset"):
|
||||||
|
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
## <u>STEP 1 - Preparing Audio/Generating the dataset</u><br>
|
### 📁 <u>Generating the dataset</u><br>
|
||||||
|
### 🟥 <u>Important Note - Windows - "UserWarning: huggingface_hub cache-system uses symlinks."</u>
|
||||||
|
◽ This error is caused by Huggingfaces download software downloading the Whisper model. If you get this error, please restart your Windows command prompt with "Run as Administrator" and restart finetuning.<br>
|
||||||
|
◽ This should only occur the 1st time it downloads the Whisper model. [Huggingface Reference here](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache#limitations)
|
||||||
### 🟦 <u>What you need to do</u>
|
### 🟦 <u>What you need to do</u>
|
||||||
#### - Please read Coqui's guide on what makes a good dataset [here](https://docs.coqui.ai/en/latest/what_makes_a_good_dataset.html#what-makes-a-good-dataset)
|
◽ Please read Coqui's guide on what makes a good dataset [here](https://docs.coqui.ai/en/latest/what_makes_a_good_dataset.html#what-makes-a-good-dataset)<br>
|
||||||
#### - Place your audio files in <span style="color: #3366ff;">{str(audio_folder)}</span>
|
◽ Place your audio files in <span style="color: #3366ff;">{str(audio_folder)}</span>
|
||||||
#### - Your audio samples can be in the format <span style="color: #3366ff;">mp3, wav,</span> or <span style="color: #3366ff;">flac.</span>
|
◽ Your audio samples can be in the format <span style="color: #3366ff;">mp3, wav,</span> or <span style="color: #3366ff;">flac.</span><br>
|
||||||
#### - You will need a minimum of <span style="color: #3366ff;">2 minutes</span> of audio in either one or multiple audio files. Very small sample files cause errors, so I would suggest 30 seconds and longer samples.
|
◽ You will need a minimum of <span style="color: #3366ff;">2 minutes</span> of audio in either one or multiple audio files. 5 to 10 minutes of audio would probably be better, allowing for more varied sample data to be generated.<br>
|
||||||
#### - When you have completed Steps 1, 2, and 3, you are welcome to delete your samples from "put-voice-samples-in-here".<br>
|
◽ Very small sample files cause errors, so I would recommend that the samples are at least 30 seconds and longer.<br>
|
||||||
### 🟨 <u>What this step is doing</u>
|
◽ FYI Anecdotal evidence suggests that the Whisper 2 model may yield superior results in audio splitting and dataset creation.<br>
|
||||||
#### - With step one, we are going to be stripping your audio file(s) into smaller files, using Whisper to find spoken words/sentences, compile that into excel sheets of training data, ready for finetuning the model on Step 2.
|
### 🟨 <u>What this step is doing</u><br>
|
||||||
#### - Whilst you can choose multiple Whisper models, its best only to use the 1 model as each one is about 3GB in size and will download to your local huggingface cache on first-time use. If and when you have completed training, you wish to delete this 3GB model from your system, you are welcome to do so.
|
◽ With step one, we are going to be stripping your audio file(s) into smaller files, using Whisper to find spoken words/sentences, compile that into excel sheets of training data, ready for Step 2.<br>
|
||||||
### 🟩 <u>How long will this take?</u>
|
◽ Whisper is making a best effort to find spoken audio and break it down into smaller audio files. The content of these audio files is then transcribed into CSV fles (which you can edit in Excel or similar).<br>
|
||||||
#### - First time, it needs to download the Whisper model which is 3GB. After that a few minutes on an average 3-4 year old system.
|
◽ These files (audio and CSV) are used at the next step to train the model "this is what the audio sounds like and these are the words being spoken".<br>
|
||||||
|
◽ If you wish to manually look at the CSV files before running the next step, you are welcome to do so and edit them as necessary. The greater the accuracy of the text the better the training will be.<br>
|
||||||
|
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/metadata_train.csv</span> Contains the list of wavs to text that will be used. This is what the model is trained with.<br>
|
||||||
|
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/metadata_eval.csv</span> Lists the evaluation wav to text, used to generate TTS while training and evaluate the quality of generated TTS to the original sample.<br>
|
||||||
|
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/wavs/</span> These are the wavs split out from your original training samples and match the contents of the CSV files.<br>
|
||||||
|
◽ Whilst you can choose multiple Whisper models, its best only to use the 1 model as each one is about 3GB in size and will download to your local huggingface cache on first-time use. <br>
|
||||||
|
◽ If and when you have completed training, should you wish to delete this 3GB Whisper model from your system, you are welcome to do so.<br>
|
||||||
|
### 🟩 <u>How long will this take?</u><br>
|
||||||
|
◽ First time, it needs to download the Whisper model which is 3GB. After that a few minutes on an average 3-4 year old system.<br>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -934,7 +1294,7 @@ if __name__ == "__main__":
|
|||||||
with gr.Row():
|
with gr.Row():
|
||||||
whisper_model = gr.Dropdown(
|
whisper_model = gr.Dropdown(
|
||||||
label="Whisper Model",
|
label="Whisper Model",
|
||||||
value="large-v3",
|
value="large-v2",
|
||||||
choices=[
|
choices=[
|
||||||
"large-v3",
|
"large-v3",
|
||||||
"large-v2",
|
"large-v2",
|
||||||
@@ -966,6 +1326,14 @@ if __name__ == "__main__":
|
|||||||
"ja"
|
"ja"
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
eval_split_number = gr.Number(
|
||||||
|
label="Evaluation data Split (the % to use for Evaluation data)",
|
||||||
|
value=15, # Default value
|
||||||
|
minimum=5, # Minimum value
|
||||||
|
maximum=95, # Maximum value
|
||||||
|
step=1, # Increment step
|
||||||
|
)
|
||||||
progress_data = gr.Label(
|
progress_data = gr.Label(
|
||||||
label="Progress:"
|
label="Progress:"
|
||||||
)
|
)
|
||||||
@@ -977,14 +1345,14 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
prompt_compute_btn = gr.Button(value="Step 1 - Create dataset")
|
prompt_compute_btn = gr.Button(value="Step 1 - Create dataset")
|
||||||
|
|
||||||
def preprocess_dataset(language, whisper_model, out_path, progress=gr.Progress(track_tqdm=True)):
|
def preprocess_dataset(language, whisper_model, out_path, eval_split_number, progress=gr.Progress(track_tqdm=True)):
|
||||||
clear_gpu_cache()
|
clear_gpu_cache()
|
||||||
test_for_audio_files = [file for file in os.listdir(audio_folder) if any(file.lower().endswith(ext) for ext in ['.wav', '.mp3', '.flac'])]
|
test_for_audio_files = [file for file in os.listdir(audio_folder) if any(file.lower().endswith(ext) for ext in ['.wav', '.mp3', '.flac'])]
|
||||||
if not test_for_audio_files:
|
if not test_for_audio_files:
|
||||||
return "I cannot find any mp3, wav or flac files in the folder called 'put-voice-samples-in-here'", "", ""
|
return "I cannot find any mp3, wav or flac files in the folder called 'put-voice-samples-in-here'", "", ""
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
train_meta, eval_meta, audio_total_size = format_audio_list(target_language=language, whisper_model=whisper_model ,out_path=out_path, gradio_progress=progress)
|
train_meta, eval_meta, audio_total_size = format_audio_list(target_language=language, whisper_model=whisper_model, out_path=out_path, eval_split_number=eval_split_number, gradio_progress=progress)
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
error = traceback.format_exc()
|
error = traceback.format_exc()
|
||||||
@@ -1004,20 +1372,27 @@ if __name__ == "__main__":
|
|||||||
#######################
|
#######################
|
||||||
#### GRADIO STEP 2 ####
|
#### GRADIO STEP 2 ####
|
||||||
#######################
|
#######################
|
||||||
with gr.Tab("Step 2 - Fine-tuning the XTTS Encoder"):
|
with gr.Tab("💻 Step 2 - Training"):
|
||||||
|
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
## <u>STEP 2 - Fine-tuning the XTTS Encoder</u><br>
|
### 💻 <u>Training</u><br>
|
||||||
### 🟦 <u>What you need to do</u>
|
### 🟦 <u>What you need to do</u>
|
||||||
#### - The <span style="color: #3366ff;">Train CSV</span> and <span style="color: #3366ff;">Eval CSV</span> should already be populated. If not, just go back to Step 1 and click the button again.
|
◽ The <span style="color: #3366ff;">Train CSV</span> and <span style="color: #3366ff;">Eval CSV</span> should already be populated. If not, just go back to Step 1 and click "Create Dataset" again.<br>
|
||||||
#### - If for any reason it crashed, close the app and re-start the finetuning and kick it off again, clicking through setp 1 (it doesnt need to regenerate the data)
|
◽ The default settings below are the suggested settings for most purposes, however you may choose to alter them depending on your specific use case.<br>
|
||||||
#### - The settings below are factory and should be ok.<br>
|
◽ There are no absolute correct settings for training. It will vary based on:<br>
|
||||||
### 🟨 <u>What this step is doing</u>
|
- What you are training (A human voice, A cartoon voice, A new language entirely etc)<br>
|
||||||
#### - Very simply put, it's taking all our wav files generated in Step 1, along with our recorded speech in out excel documents and its training the model on that voice.
|
- How much audio you have (you may want less or more eval or epochs)<br>
|
||||||
### 🟩 <u>How long will this take?</u>
|
◽ The key indicator of sufficient model training is whether it sounds right to you. Coqui suggests beginning with the base settings for training. If the resulting audio doesn't meet your expectations, additional training sessions may be necessary.<br>
|
||||||
#### - On a RTX 4070 with factory settings (as below) and 20 minutes of audio, this took 20 minutes. Again, it will vary by system and how much audio you are throwing at it. You have time to go make a coffee.
|
◽ **Number of epochs:** Defines how many times the entire dataset is passed through the neural network; more epochs can improve learning but increase the risk of memorizing the training data.<br>
|
||||||
#### - Look at your command prompt/terminal window if you want to see what it is doing.
|
◽ **Batch size:** Sets how many training examples are used in one iteration. Larger sizes speed up training but require more computational memory.<br>
|
||||||
|
◽ **Grad(ient) accumulation steps:** Allows larger batches by spreading the computation across multiple steps, enabling training with limited hardware resources.<br>
|
||||||
|
◽ **Max permitted audio size in seconds:** Limits the length of audio that the model processes. Any audio exceeding this duration will be truncated to fit the model's input constraints.<br>
|
||||||
|
### 🟨 <u>What this step is doing</u><br>
|
||||||
|
◽ Very simply put, it's taking all our wav files generated in Step 1, along with our recorded speech in out excel documents and its training the model on that voice e.g. listen to this audio file and this is what is being said in it, so learn to reproduce it.<br>
|
||||||
|
### 🟩 <u>How long will this take?</u><br>
|
||||||
|
◽ On a RTX 4070 with factory settings (as below) and 20 minutes of audio, this took 20 minutes. Again, it will vary by system and how much audio you are throwing at it. You have time to go make a coffee.<br>
|
||||||
|
◽ Look at your command prompt/terminal window if you want to see what it is doing.<br>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
@@ -1067,7 +1442,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
##### If you have an existing finetuned model in <span style="color: #3366ff;">/models/trainedmodel/</span> you will have an option to select <span style="color: #3366ff;">Existing finetuned model</span>, allowing you to further train it. Otherwise, you will only have Base Model as an option.
|
If you have an existing finetuned model in <span style="color: #3366ff;">/models/trainedmodel/</span> you will have an option to select <span style="color: #3366ff;">Existing finetuned model</span>, allowing you to further train it. Otherwise, you will only have Base Model as an option.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1095,8 +1470,8 @@ if __name__ == "__main__":
|
|||||||
return f"The training was interrupted due an error !! Please check the console to check the full error message! \n Error summary: {error}", "", "", "", ""
|
return f"The training was interrupted due an error !! Please check the console to check the full error message! \n Error summary: {error}", "", "", "", ""
|
||||||
|
|
||||||
# copy original files to avoid parameters changes issues
|
# copy original files to avoid parameters changes issues
|
||||||
os.system(f"cp {config_path} {exp_path}")
|
shutil.copy(config_path, exp_path)
|
||||||
os.system(f"cp {vocab_file} {exp_path}")
|
shutil.copy(vocab_file, exp_path)
|
||||||
|
|
||||||
ft_xtts_checkpoint = os.path.join(exp_path, "best_model.pth")
|
ft_xtts_checkpoint = os.path.join(exp_path, "best_model.pth")
|
||||||
print("[FINETUNE] Model training done. Move to Step 3")
|
print("[FINETUNE] Model training done. Move to Step 3")
|
||||||
@@ -1107,21 +1482,25 @@ if __name__ == "__main__":
|
|||||||
#### GRADIO STEP 3 ####
|
#### GRADIO STEP 3 ####
|
||||||
#######################
|
#######################
|
||||||
|
|
||||||
with gr.Tab("Step 3 - Inference/Testing"):
|
with gr.Tab("✅ Step 3 - Testing"):
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
## <u>STEP 3 - Inference/Testing</u><br>
|
### ✅ <u>Testing</u><br>
|
||||||
### 🟥 <u>Important Note</u>
|
### 🟥 <u>Important Note</u>
|
||||||
#### - This step will error if you are using TTS version 0.22.0. Please re-run <span style="color: #3366ff;">pip install -r requirements_finetune.txt</span> if it errors loading the model.
|
◽ If you dont believe the dropdown lists are populated correctly, you can use the "Refresh Dropdowns" button to search the finetuning folder path and update the lists. You can also manually edit the path to the listed files.<br>
|
||||||
#### - If you dont see multiple speaker reference files and you used more than 3 minutes of speech, try refreshing the page as it may not have loaded them correctly.
|
◽ You can use any config.json or vocab.json, as long as they match the model version you trained on. Only the XTTS checkpoint matters.<br>
|
||||||
|
◽ Upon successful processing of your speech data, expect to find multiple speaker reference files if your input consisted of over 3 minutes of speech.<br>
|
||||||
|
◽ Audio clips shorter than 7 seconds are automatically excluded from the reference list, as they generally do not provide sufficient length for effective TTS generation.<br>
|
||||||
|
◽ Should you find a lower number of reference files than anticipated, it may be due to the initial segmentation performed by Whisper (Step 1), which can occasionally result in clips that are too brief for our criteria or indeed too long. In such cases, consider manually segmenting your audio to give Whisper a better chance at generating training data and repeating the process.<br>
|
||||||
### 🟦 <u>What you need to do</u>
|
### 🟦 <u>What you need to do</u>
|
||||||
#### - The model is now trained and you are at the testing stage. Hopefully all the dropdowns should be pre-populated now.
|
◽ **Click** the **Refresh Dropdowns** button to correctly populate the **Speaker Reference Audio** with all the available WAV samples.<br>
|
||||||
#### - You need to <span style="color: #3366ff;">Load Fine-tuned XTTS model</span> and then select your <span style="color: #3366ff;">Speaker Reference Audio</span>. You can choose various <span style="color: #3366ff;">Speaker Reference Audios</span> to see which works best.
|
◽ The model is now trained and you are at the testing stage. Hopefully all the dropdowns should be pre-populated now.<br>
|
||||||
#### - All the <span style="color: #3366ff;">Speaker Reference Audios</span> in the dropdown are ones that are <span style="color: #3366ff;">8 seconds</span> long or more. You can use one of these later for your voice sample in All Talk, so remember the one you like.
|
◽ You need to <span style="color: #3366ff;">Load Fine-tuned XTTS model</span> and then select your <span style="color: #3366ff;">Speaker Reference Audio</span>. You can choose various <span style="color: #3366ff;">Speaker Reference Audios</span> to see which works best.<br>
|
||||||
#### - Some <span style="color: #3366ff;">Speaker Reference Audios</span> are a bit long and may cause issues generating the TTS, so try different ones.
|
◽ All the <span style="color: #3366ff;">Speaker Reference Audios</span> in the dropdown are ones that are <span style="color: #3366ff;">8 seconds</span> long or more. You can use one of these later for your voice sample in All Talk, so remember the one you like.<br>
|
||||||
#### - Once you are happy, move to the next tab for instruction on cleaning out the training data and how to copy your newly trained model over your current model.
|
◽ Some <span style="color: #3366ff;">Speaker Reference Audios</span> are a bit long and may cause issues generating the TTS, so try different ones.<br>
|
||||||
|
◽ Once you are happy, move to the next tab for instruction on cleaning out the training data and how to copy your newly trained model over your current model.<br>
|
||||||
### 🟨 <u>What this step is doing</u>
|
### 🟨 <u>What this step is doing</u>
|
||||||
#### - Its loading the finetuned model into memory, loading a voice sample and generating TTS, so that you can test out how well fine tuning worked.
|
◽ Its loading the finetuned model into memory, loading a voice sample and generating TTS, so that you can test out how well fine tuning worked.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1129,21 +1508,21 @@ if __name__ == "__main__":
|
|||||||
with gr.Column() as col1:
|
with gr.Column() as col1:
|
||||||
xtts_checkpoint = gr.Dropdown(
|
xtts_checkpoint = gr.Dropdown(
|
||||||
[str(file) for file in xtts_checkpoint_files],
|
[str(file) for file in xtts_checkpoint_files],
|
||||||
label="XTTS checkpoint path:",
|
label="XTTS checkpoint path (best_model.pth):",
|
||||||
value="",
|
value="",
|
||||||
allow_custom_value=True,
|
allow_custom_value=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
xtts_config = gr.Dropdown(
|
xtts_config = gr.Dropdown(
|
||||||
[str(file) for file in xtts_config_files],
|
[str(file) for file in xtts_config_files],
|
||||||
label="XTTS config path:",
|
label="XTTS config path (config.json):",
|
||||||
value="",
|
value="",
|
||||||
allow_custom_value=True,
|
allow_custom_value=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
xtts_vocab = gr.Dropdown(
|
xtts_vocab = gr.Dropdown(
|
||||||
[str(file) for file in xtts_vocab_files],
|
[str(file) for file in xtts_vocab_files],
|
||||||
label="XTTS vocab path:",
|
label="XTTS vocab path (vocab.json):",
|
||||||
value="",
|
value="",
|
||||||
allow_custom_value=True,
|
allow_custom_value=True,
|
||||||
)
|
)
|
||||||
@@ -1165,14 +1544,8 @@ if __name__ == "__main__":
|
|||||||
allow_custom_value=True, # Allow custom values
|
allow_custom_value=True, # Allow custom values
|
||||||
scale=1,
|
scale=1,
|
||||||
)
|
)
|
||||||
# Create refresh button
|
|
||||||
refresh_button = create_refresh_button(
|
|
||||||
speaker_reference_audio,
|
|
||||||
lambda: None, # Specify your refresh logic if needed
|
|
||||||
lambda: {"choices": get_available_voices(), "value": ""}, # Update choices and value
|
|
||||||
"refresh-button",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
with gr.Row():
|
||||||
tts_language = gr.Dropdown(
|
tts_language = gr.Dropdown(
|
||||||
label="Language",
|
label="Language",
|
||||||
value="en",
|
value="en",
|
||||||
@@ -1195,6 +1568,17 @@ if __name__ == "__main__":
|
|||||||
"ja",
|
"ja",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
# Create refresh button
|
||||||
|
refresh_button = create_refresh_button(
|
||||||
|
[xtts_checkpoint, xtts_config, xtts_vocab, speaker_reference_audio],
|
||||||
|
[
|
||||||
|
lambda: {"choices": find_models(main_directory, "pth"), "value": ""},
|
||||||
|
lambda: {"choices": find_jsons(main_directory, "config.json"), "value": ""},
|
||||||
|
lambda: {"choices": find_jsons(main_directory, "vocab.json"), "value": ""},
|
||||||
|
lambda: {"choices": get_available_voices(), "value": ""},
|
||||||
|
],
|
||||||
|
elem_class="refresh-button-class"
|
||||||
|
)
|
||||||
tts_text = gr.Textbox(
|
tts_text = gr.Textbox(
|
||||||
label="Input Text:",
|
label="Input Text:",
|
||||||
value="I've just fine tuned a text to speech language model and this is how it sounds. If it doesn't sound right, I will try a different Speaker Reference Audio file.",
|
value="I've just fine tuned a text to speech language model and this is how it sounds. If it doesn't sound right, I will try a different Speaker Reference Audio file.",
|
||||||
@@ -1209,22 +1593,25 @@ if __name__ == "__main__":
|
|||||||
tts_output_audio = gr.Audio(label="TTS Generated Audio.")
|
tts_output_audio = gr.Audio(label="TTS Generated Audio.")
|
||||||
reference_audio = gr.Audio(label="Speaker Reference Audio Used.")
|
reference_audio = gr.Audio(label="Speaker Reference Audio Used.")
|
||||||
|
|
||||||
with gr.Tab("What to do next"):
|
with gr.Tab("🔜 What to do next"):
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
## <u>What to do next</u><br>
|
### 🔜 <u>What to do next</u><br>
|
||||||
### 🟦 <u>What you need to do</u>
|
### 🟦 <u>What you need to do</u>
|
||||||
#### - You have a few options below:
|
You have a few options below:<br>
|
||||||
#### 🔹 Compact & move model. This will compress the raw finetuned model and move it, along with any large enough wav files created to one of two locations (please read text next to the button).<br> You can use the wav files in that location as sample voices with your model. Models moved to <span style="color: #3366ff;">/models/trainedmodel/</span> will be loadable within Text-gen-webui on the <span style="color: #3366ff;">XTTSv2 FT</span> loader.
|
◽ **Compact & move model:** This will compress the raw finetuned model and move it, along with any large enough wav files created to one of two locations (please read text next to the button). You can use the wav files in that location as sample voices with your model. Models moved to <span style="color: #3366ff;">/models/trainedmodel/</span> will be loadable within Text-gen-webui on the <span style="color: #3366ff;">XTTSv2 FT</span> loader.<br>
|
||||||
#### 🔹 Delete Generated Training data. This will delete the finetuned model and any other training data generated during this process. You will more than likely want to do this after you have Compacted & moved the model.
|
◽ **Delete Generated Training data:** This will delete the finetuned model and any other training data generated during this process. You will more than likely want to do this after you have Compacted & moved the model.<br>
|
||||||
#### 🔹 Delete original voice samples. This will delete the voice samples you placed in put-voice-samples-in-here (if you no longer have a use for them).
|
◽ **Delete original voice samples:** This will delete the voice samples you placed in put-voice-samples-in-here (if you no longer have a use for them).<br>
|
||||||
#### 🔹 Compress a legacy finetuned model. For any models that were generated pre the current version of finetuning, you can still compact them down.
|
◽ **Note:** Sample wav files will be copied into the model folder. You will need to MANUALLY copy/move the WAV file(s) you want to use to the AllTalk voices folder, to make them available within the interface.<br>
|
||||||
#### - Instructions on using the finetuned model in Text-generation-webui and also further tuning this model you just created are on <span style="color: #3366ff;">OPTION A - Compact and move model to '/trainedmodel/'</span>.
|
◽ **Note:** Text-generation-webui users, <span style="color: #3366ff;">OPTION A - Compact and move model to '/trainedmodel/'</span>. will make the model available for use within Text-gen-webui.<br>
|
||||||
|
### 🟩 <u>Using your Finetuned model as you main model</u>
|
||||||
|
◽ If you wish to use the model you have just fintuned as your main model, you will need to MANUALLY copy it over the base model in <span style="color: #3366ff;">/models/trainedmodel/</span> after you have used Option A or B.<br>
|
||||||
|
◽ Should you ever wish to revert your model back to the base model, you can delete the files in <span style="color: #3366ff;">/models/xttsv2_2.0.2/</span> and new copies will be re-downloaded when AllTalk starts up.<br>
|
||||||
### 🟨 <u>Clearing up disk space</u>
|
### 🟨 <u>Clearing up disk space</u>
|
||||||
#### - If you are not going to train anything again, you can delete the whisper model from inside of your huggingface cache (3GB approx)
|
◽ If you are not going to train anything again, you can delete the whisper model from inside of your huggingface cache (3GB approx) <br>
|
||||||
#### Linux <span style="color: #3366ff;">~/.cache/huggingface/hub/(folder-here)</span>
|
◽ **Linux:** <span style="color: #3366ff;">~/.cache/huggingface/hub/(folder-here)</span><br>
|
||||||
#### Windows <span style="color: #3366ff;">C:\users(your-username)\.cache\huggingface\hub\(folder-here)</span>.
|
◽ **Windows:** <span style="color: #3366ff;">C:\users(your-username)\.cache\huggingface\hub\(folder-here)</span>.<br>
|
||||||
#### - You can also uninstall the Nvidia CUDA 11.8 Toolkit if you wish and remove your environment variable entries.
|
◽ You can also uninstall the Nvidia CUDA 11.8 Toolkit if you wish and remove your environment variable entries.<br>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
final_progress_data = gr.Label(
|
final_progress_data = gr.Label(
|
||||||
@@ -1234,35 +1621,28 @@ if __name__ == "__main__":
|
|||||||
compact_btn = gr.Button(value="OPTION A - Compact and move model to '/trainedmodel/'")
|
compact_btn = gr.Button(value="OPTION A - Compact and move model to '/trainedmodel/'")
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
##### This will compact the model and move it, along with the reference wav's to <span style="color: #3366ff;">/models/trainedmodel/</span> and will <span style="color: red;">OVERWRITE</span> any model in that location. This model will become available to load in Text-gen-webui with the <span style="color: #3366ff;">XTTSv2 FT</span> loader. It will also be detected by Finetune as a model that can be further trained (Reload finetune.py).
|
This will compact the model and move it, along with the reference wav's to <span style="color: #3366ff;">/models/trainedmodel/</span> and will <span style="color: red;">OVERWRITE</span> any model in that location. This model will become available to load in Text-gen-webui with the <span style="color: #3366ff;">XTTSv2 FT</span> loader. It will also be detected by Finetune as a model that can be further trained (Reload finetune.py).
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
compact_lastfinetuned_btn = gr.Button(value="OPTION B - Compact and move model to '/lastfinetuned/'")
|
compact_lastfinetuned_btn = gr.Button(value="OPTION B - Compact and move model to '/lastfinetuned/'")
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
##### This will compact the model and move it, along with the reference wav's to <span style="color: #3366ff;">/models/lastfinetuned/</span> and will <span style="color: red;">OVERWRITE</span> any model in that location. This will just leave you a finetuned model that you can do with as you please. It will <span style="color: red;">NOT</span> be available in Text-gen-webui unless you copy it over one of the other model loader locations.
|
This will compact the model and move it, along with the reference wav's to <span style="color: #3366ff;">/models/lastfinetuned/</span> and will <span style="color: red;">OVERWRITE</span> any model in that location. This will just leave you a finetuned model that you can do with as you please. It will <span style="color: red;">NOT</span> be available in Text-gen-webui unless you copy it over one of the other model loader locations.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
delete_training_btn = gr.Button(value="Delete generated training data")
|
delete_training_btn = gr.Button(value="Delete generated training data")
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
##### This will <span style="color: red;">DELETE</span> your training data and the raw finetuned model from <span style="color: #3366ff;">/finetune/tmp-trn/</span>.
|
This will <span style="color: red;">DELETE</span> your training data and the raw finetuned model from <span style="color: #3366ff;">/finetune/tmp-trn/</span>.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
delete_voicesamples_btn = gr.Button(value="Delete original voice samples")
|
delete_voicesamples_btn = gr.Button(value="Delete original voice samples")
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
f"""
|
f"""
|
||||||
##### This will <span style="color: red;">DELETE</span> your original voice samples from <span style="color: #3366ff;">/finetune/put-voice-samples-in-here/</span>.
|
This will <span style="color: red;">DELETE</span> your original voice samples from <span style="color: #3366ff;">/finetune/put-voice-samples-in-here/</span>.
|
||||||
"""
|
|
||||||
)
|
|
||||||
with gr.Row():
|
|
||||||
compact_legacy_btn = gr.Button(value="Compact a legacy finetuned model")
|
|
||||||
gr.Markdown(
|
|
||||||
f"""
|
|
||||||
##### This will compact your old finetuned models from 5GB to 1.9GB. Place your 5GB <span style="color: #3366ff;">base_model.pth</span> file in <span style="color: #3366ff;">/finetune/</span> (rename your file to <span style="color: #3366ff;">base_model.pth</span> if necessary). This will generate you a <span style="color: #3366ff;">model.pth</span> file.
|
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1272,6 +1652,7 @@ if __name__ == "__main__":
|
|||||||
lang,
|
lang,
|
||||||
whisper_model,
|
whisper_model,
|
||||||
out_path,
|
out_path,
|
||||||
|
eval_split_number,
|
||||||
],
|
],
|
||||||
outputs=[
|
outputs=[
|
||||||
progress_data,
|
progress_data,
|
||||||
@@ -1332,10 +1713,6 @@ if __name__ == "__main__":
|
|||||||
fn=delete_voice_sample_contents,
|
fn=delete_voice_sample_contents,
|
||||||
outputs=[final_progress_data],
|
outputs=[final_progress_data],
|
||||||
)
|
)
|
||||||
compact_legacy_btn.click(
|
|
||||||
fn=compact_legacy_model,
|
|
||||||
outputs=[final_progress_data],
|
|
||||||
)
|
|
||||||
model_to_train.change(basemodel_or_finetunedmodel_choice, model_to_train, None)
|
model_to_train.change(basemodel_or_finetunedmodel_choice, model_to_train, None)
|
||||||
|
|
||||||
demo.queue().launch(
|
demo.queue().launch(
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import torch
|
|
||||||
import os
|
|
||||||
MODEL_PATH = "best_model.pth"
|
|
||||||
# Check if best_model.pth exists
|
|
||||||
if not os.path.exists(MODEL_PATH):
|
|
||||||
print(f"\nCannot find \033[94m{MODEL_PATH}\033[0m in the current folder.")
|
|
||||||
|
|
||||||
# Check if model.pth exists as an alternative
|
|
||||||
ALTERNATIVE_PATH = "model.pth"
|
|
||||||
if os.path.exists(ALTERNATIVE_PATH):
|
|
||||||
print(f"\nIf your model is currently called \033[93m{ALTERNATIVE_PATH}\033[0m please rename it to \033[94mbest_model.pth\033[0m.")
|
|
||||||
else:
|
|
||||||
print(f"Please put \033[91mbest_model.pth\033[0m in the current folder or rename your model file to \033[94mbest_model.pth\033[0m.")
|
|
||||||
exit(1)
|
|
||||||
# Attempt to load the model
|
|
||||||
try:
|
|
||||||
checkpoint = torch.load(MODEL_PATH, map_location=torch.device("cpu"))
|
|
||||||
except Exception as e:
|
|
||||||
print("Error loading checkpoint:", e)
|
|
||||||
raise
|
|
||||||
del checkpoint["optimizer"]
|
|
||||||
for key in list(checkpoint["model"].keys()):
|
|
||||||
if "dvae" in key:
|
|
||||||
del checkpoint["model"][key]
|
|
||||||
torch.save(checkpoint, "model.pth")
|
|
||||||
print(f"\nYour compacted model is created \033[93mmodel.pth\033[0m.")
|
|
||||||
@@ -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
|
||||||
@@ -45,18 +45,18 @@ else:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Read the version specifier from requirements_nvidia.txt
|
# Read the version specifier from requirements_nvidia.txt
|
||||||
with open(this_dir / "requirements_nvidia.txt", "r") as req_file:
|
with open(this_dir / "system" / "requirements" / "requirements_standalone.txt", "r") as req_file:
|
||||||
requirements = req_file.readlines()
|
requirements = req_file.readlines()
|
||||||
|
|
||||||
tts_version_required = None
|
tts_version_required = None
|
||||||
for req in requirements:
|
for req in requirements:
|
||||||
if req.startswith("TTS>="):
|
if req.startswith("TTS=="):
|
||||||
tts_version_required = req.strip().split(">=")[1]
|
tts_version_required = req.strip().split("==")[1]
|
||||||
break
|
break
|
||||||
|
|
||||||
if tts_version_required is None:
|
if tts_version_required is None:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements_nvidia.txt"
|
f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements file"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
ENV CUDA_DOCKER_ARCH=all
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir -r requirements_nvidia.txt && \
|
||||||
|
pip install --no-cache-dir -r requirements_finetune.txt && \
|
||||||
|
pip install --no-cache-dir -r requirements_other.txt && \
|
||||||
|
pip install --no-cache-dir deepspeed
|
||||||
|
EXPOSE 7851
|
||||||
|
RUN chmod +x launch.sh
|
||||||
|
ENTRYPOINT ["sh", "-c", "./launch.sh"]
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
gradio>=3.50.2
|
|
||||||
torch>=2.1.0+cu118
|
|
||||||
torchaudio>=2.1.0+cu118
|
|
||||||
TTS==0.21.3
|
|
||||||
faster-whisper>=0.10.0
|
|
||||||
tqdm>=4.66.0
|
|
||||||
pandas>=1.5.0
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
numpy>=1.22.0
|
|
||||||
soundfile>=0.12.1
|
|
||||||
uvicorn>=0.24.0.post1
|
|
||||||
TTS>=0.21.3
|
|
||||||
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
|
|
||||||
@@ -16,18 +16,28 @@ import numpy as np
|
|||||||
import soundfile as sf
|
import soundfile as sf
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
######################################
|
||||||
|
#### ALLTALK ALLOWED STARTUP TIME ####
|
||||||
|
######################################
|
||||||
|
startup_wait_time = 120
|
||||||
|
|
||||||
|
# You can change the above setting to a larger number to allow AllTAlk more time to start up. The default setting is 120 seconds (2 minutes).
|
||||||
|
# On some older systems you may need to allow AllTalk more time. So you could set it to 240 (4 minutes) which will give AllTalk more to load.
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
#### LOAD PARAMS FROM confignew.json - REQUIRED FOR BRANDING ####
|
#### LOAD PARAMS FROM confignew.json - REQUIRED FOR BRANDING ####
|
||||||
#################################################################
|
#################################################################
|
||||||
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
|
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
|
||||||
this_dir = Path(__file__).parent.resolve()
|
this_dir = Path(__file__).parent.resolve()
|
||||||
|
|
||||||
|
|
||||||
# load config file in and get settings
|
# load config file in and get settings
|
||||||
def load_config(file_path):
|
def load_config(file_path):
|
||||||
with open(file_path, "r") as config_file:
|
with open(file_path, "r") as config_file:
|
||||||
config = json.load(config_file)
|
config = json.load(config_file)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
config_file_path = this_dir / "confignew.json"
|
config_file_path = this_dir / "confignew.json"
|
||||||
# Load the params dictionary from the confignew.json file
|
# Load the params dictionary from the confignew.json file
|
||||||
params = load_config(config_file_path)
|
params = load_config(config_file_path)
|
||||||
@@ -48,6 +58,7 @@ except ModuleNotFoundError:
|
|||||||
# IMPORT - Attempt Importing DeepSpeed (required for displaying Deepspeed checkbox in gradio)
|
# IMPORT - Attempt Importing DeepSpeed (required for displaying Deepspeed checkbox in gradio)
|
||||||
try:
|
try:
|
||||||
import deepspeed
|
import deepspeed
|
||||||
|
|
||||||
deepspeed_installed = True
|
deepspeed_installed = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
deepspeed_installed = False
|
deepspeed_installed = False
|
||||||
@@ -60,6 +71,7 @@ try:
|
|||||||
from modules.logging_colors import logger
|
from modules.logging_colors import logger
|
||||||
from modules.ui import create_refresh_button
|
from modules.ui import create_refresh_button
|
||||||
from modules.utils import gradio
|
from modules.utils import gradio
|
||||||
|
|
||||||
# This is set to check if the script is being run within text generation webui or as a standalone script. False is running as part of text gen web ui or a gradio interface
|
# This is set to check if the script is being run within text generation webui or as a standalone script. False is running as part of text gen web ui or a gradio interface
|
||||||
running_in_standalone = False
|
running_in_standalone = False
|
||||||
output_folder_wav = params["output_folder_wav"]
|
output_folder_wav = params["output_folder_wav"]
|
||||||
@@ -73,17 +85,19 @@ except ModuleNotFoundError:
|
|||||||
#### STARTUP VARIABLES ####
|
#### STARTUP VARIABLES ####
|
||||||
###########################
|
###########################
|
||||||
# STARTUP VARIABLE - Import languges file for Gradio to be able to display them in the interface
|
# STARTUP VARIABLE - Import languges file for Gradio to be able to display them in the interface
|
||||||
with open(this_dir / "languages.json", encoding="utf8") as f:
|
with open(this_dir / "system" / "config" / "languages.json", encoding="utf8") as f:
|
||||||
languages = json.load(f)
|
languages = json.load(f)
|
||||||
# Create a global lock
|
# Create a global lock
|
||||||
process_lock = threading.Lock()
|
process_lock = threading.Lock()
|
||||||
# Base setting for a possible FineTuned model existing and the loader being available
|
# Base setting for a possible FineTuned model existing and the loader being available
|
||||||
tts_method_xtts_ft = False
|
tts_method_xtts_ft = False
|
||||||
|
|
||||||
|
|
||||||
# Gather the voice files
|
# Gather the voice files
|
||||||
def get_available_voices():
|
def get_available_voices():
|
||||||
return sorted([voice.name for voice in Path(f"{this_dir}/voices").glob("*.wav")])
|
return sorted([voice.name for voice in Path(f"{this_dir}/voices").glob("*.wav")])
|
||||||
|
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
#### LICENSE DISPLAY ####
|
#### LICENSE DISPLAY ####
|
||||||
#########################
|
#########################
|
||||||
@@ -141,6 +155,7 @@ def check_required_files():
|
|||||||
subprocess.run(["python", str(download_script_path)])
|
subprocess.run(["python", str(download_script_path)])
|
||||||
print(f"[{params['branding']}Startup] All required files are present.")
|
print(f"[{params['branding']}Startup] All required files are present.")
|
||||||
|
|
||||||
|
|
||||||
# STARTUP Call Check routine
|
# STARTUP Call Check routine
|
||||||
check_required_files()
|
check_required_files()
|
||||||
|
|
||||||
@@ -155,7 +170,9 @@ finetuned_model = trained_model_directory.exists()
|
|||||||
# If true, this will add a extra option in the Gradio interface for loading Xttsv2 FT
|
# If true, this will add a extra option in the Gradio interface for loading Xttsv2 FT
|
||||||
if finetuned_model:
|
if finetuned_model:
|
||||||
required_files = ["model.pth", "config.json", "vocab.json"]
|
required_files = ["model.pth", "config.json", "vocab.json"]
|
||||||
finetuned_model = all((trained_model_directory / file).exists() for file in required_files)
|
finetuned_model = all(
|
||||||
|
(trained_model_directory / file).exists() for file in required_files
|
||||||
|
)
|
||||||
if finetuned_model:
|
if finetuned_model:
|
||||||
print(f"[{params['branding']}Startup] Finetuned model \033[93mDetected\033[0m")
|
print(f"[{params['branding']}Startup] Finetuned model \033[93mDetected\033[0m")
|
||||||
|
|
||||||
@@ -173,6 +190,7 @@ elif params["tts_method_xtts_local"] == True:
|
|||||||
# Set the default for Narrated text without asterisk or quotes to be Narrator
|
# Set the default for Narrated text without asterisk or quotes to be Narrator
|
||||||
non_quoted_text_is = True
|
non_quoted_text_is = True
|
||||||
|
|
||||||
|
|
||||||
######################
|
######################
|
||||||
#### GRADIO STUFF ####
|
#### GRADIO STUFF ####
|
||||||
######################
|
######################
|
||||||
@@ -230,17 +248,23 @@ def signal_handler(sig, frame):
|
|||||||
|
|
||||||
# Attach the signal handler to the SIGINT signal (Ctrl+C)
|
# Attach the signal handler to the SIGINT signal (Ctrl+C)
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
# Check if we're running in docker
|
||||||
|
if os.path.isfile("/.dockerenv"):
|
||||||
|
print(
|
||||||
|
f"[{params['branding']}Startup] \033[94mRunning in Docker. Please wait.\033[0m"
|
||||||
|
)
|
||||||
|
else:
|
||||||
# Start the subprocess
|
# Start the subprocess
|
||||||
process = subprocess.Popen(["python", script_path])
|
process = subprocess.Popen(["python", script_path])
|
||||||
|
|
||||||
# Check if the subprocess has started successfully
|
# Check if the subprocess has started successfully
|
||||||
if process.poll() is None:
|
if process.poll() is None:
|
||||||
print(f"[{params['branding']}Startup] TTS Subprocess starting")
|
print(f"[{params['branding']}Startup] TTS Subprocess starting")
|
||||||
|
print(f"[{params['branding']}Startup]")
|
||||||
print(
|
print(
|
||||||
f"[{params['branding']}Startup] Readme available here:",
|
f"[{params['branding']}Startup] \033[94m {params['branding']}Settings & Documentation:\033[00m",
|
||||||
f"http://{params['ip_address']}:{params['port_number']}",
|
f"\033[92mhttp://{params['ip_address']}:{params['port_number']}\033[00m",
|
||||||
)
|
)
|
||||||
|
print(f"[{params['branding']}Startup]")
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess Webserver failing to start process"
|
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess Webserver failing to start process"
|
||||||
@@ -264,7 +288,7 @@ else:
|
|||||||
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
|
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
timeout = 120 # Adjust the timeout as needed
|
timeout = startup_wait_time # Gather timeout setting from startup_wait_time
|
||||||
|
|
||||||
# Introduce a delay before starting the check loop
|
# Introduce a delay before starting the check loop
|
||||||
time.sleep(26) # Wait 26 secs before checking if the tts_server.py has started up.
|
time.sleep(26) # Wait 26 secs before checking if the tts_server.py has started up.
|
||||||
@@ -277,12 +301,24 @@ while time.time() - start_time < timeout:
|
|||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
# Print the exception for debugging purposes
|
# Print the exception for debugging purposes
|
||||||
print(
|
print(
|
||||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess has NOT started up yet, Will keep trying for 120 seconds maximum. Please wait."
|
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess has NOT started up yet, Will keep trying for {timeout} seconds maximum. Please wait."
|
||||||
)
|
)
|
||||||
time.sleep(4)
|
time.sleep(5)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f"[{params['branding']}Startup] Startup timed out. Check the server logs for more information."
|
f"\n[{params['branding']}Startup] Startup timed out. Full help available here \033[92mhttps://github.com/erew123/alltalk_tts#-help-with-problems\033[0m"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"[{params['branding']}Startup] On older system you may wish to open and edit \033[94mscript.py\033[0m with a text editor and changing the"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"[{params['branding']}Startup] \033[94mstartup_wait_time = 120\033[0m setting to something like \033[94mstartup_wait_time = 240\033[0m as this will allow"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"[{params['branding']}Startup] AllTalk more time to try load the model into your VRAM. Otherise please visit the Github for"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"[{params['branding']}Startup] a list of other possible troubleshooting options."
|
||||||
)
|
)
|
||||||
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
|
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -311,26 +347,26 @@ def send_reload_request(tts_method):
|
|||||||
params["tts_method_xtts_local"] = False
|
params["tts_method_xtts_local"] = False
|
||||||
params["tts_method_api_tts"] = True
|
params["tts_method_api_tts"] = True
|
||||||
params["deepspeed_activate"] = False
|
params["deepspeed_activate"] = False
|
||||||
audio_path = this_dir / "templates" / "apitts.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "apitts.wav"
|
||||||
tts_method_xtts_ft = False
|
tts_method_xtts_ft = False
|
||||||
elif tts_method == "API Local":
|
elif tts_method == "API Local":
|
||||||
params["tts_method_api_tts"] = False
|
params["tts_method_api_tts"] = False
|
||||||
params["tts_method_xtts_local"] = False
|
params["tts_method_xtts_local"] = False
|
||||||
params["tts_method_api_local"] = True
|
params["tts_method_api_local"] = True
|
||||||
params["deepspeed_activate"] = False
|
params["deepspeed_activate"] = False
|
||||||
audio_path = this_dir / "templates" / "apilocal.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "apilocal.wav"
|
||||||
tts_method_xtts_ft = False
|
tts_method_xtts_ft = False
|
||||||
elif tts_method == "XTTSv2 Local":
|
elif tts_method == "XTTSv2 Local":
|
||||||
params["tts_method_api_tts"] = False
|
params["tts_method_api_tts"] = False
|
||||||
params["tts_method_api_local"] = False
|
params["tts_method_api_local"] = False
|
||||||
params["tts_method_xtts_local"] = True
|
params["tts_method_xtts_local"] = True
|
||||||
audio_path = this_dir / "templates" / "xttslocal.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "xttslocal.wav"
|
||||||
tts_method_xtts_ft = False
|
tts_method_xtts_ft = False
|
||||||
elif tts_method == "XTTSv2 FT":
|
elif tts_method == "XTTSv2 FT":
|
||||||
params["tts_method_api_tts"] = False
|
params["tts_method_api_tts"] = False
|
||||||
params["tts_method_api_local"] = False
|
params["tts_method_api_local"] = False
|
||||||
params["tts_method_xtts_local"] = False
|
params["tts_method_xtts_local"] = False
|
||||||
audio_path = this_dir / "templates" / "xttsfinetuned.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "xttsfinetuned.wav"
|
||||||
tts_method_xtts_ft = True
|
tts_method_xtts_ft = True
|
||||||
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
|
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
@@ -340,6 +376,7 @@ def send_reload_request(tts_method):
|
|||||||
)
|
)
|
||||||
return {"status": "error", "message": str(e)}
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
#### LOW VRAM ####
|
#### LOW VRAM ####
|
||||||
##################
|
##################
|
||||||
@@ -348,9 +385,9 @@ def send_lowvram_request(low_vram):
|
|||||||
try:
|
try:
|
||||||
params["tts_model_loaded"] = False
|
params["tts_model_loaded"] = False
|
||||||
if low_vram:
|
if low_vram:
|
||||||
audio_path = this_dir / "templates" / "lowvramenabled.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "lowvramenabled.wav"
|
||||||
else:
|
else:
|
||||||
audio_path = this_dir / "templates" / "lowvramdisabled.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "lowvramdisabled.wav"
|
||||||
url = f"{base_url}/api/lowvramsetting?new_low_vram_value={low_vram}"
|
url = f"{base_url}/api/lowvramsetting?new_low_vram_value={low_vram}"
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
response = requests.post(url, headers=headers)
|
response = requests.post(url, headers=headers)
|
||||||
@@ -377,9 +414,9 @@ def send_deepspeed_request(deepspeed_param):
|
|||||||
try:
|
try:
|
||||||
params["tts_model_loaded"] = False
|
params["tts_model_loaded"] = False
|
||||||
if deepspeed_param:
|
if deepspeed_param:
|
||||||
audio_path = this_dir / "templates" / "deepspeedenabled.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "deepspeedenabled.wav"
|
||||||
else:
|
else:
|
||||||
audio_path = this_dir / "templates" / "deepspeeddisabled.wav"
|
audio_path = this_dir / "system" / "at_sounds" / "deepspeeddisabled.wav"
|
||||||
|
|
||||||
url = f"{base_url}/api/deepspeed?new_deepspeed_value={deepspeed_param}"
|
url = f"{base_url}/api/deepspeed?new_deepspeed_value={deepspeed_param}"
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
@@ -454,9 +491,13 @@ def combine(audio_files, output_folder, state):
|
|||||||
|
|
||||||
# Save the combined audio to a file with a specified sample rate
|
# Save the combined audio to a file with a specified sample rate
|
||||||
if "character_menu" in state:
|
if "character_menu" in state:
|
||||||
output_file_path = os.path.join(output_folder, f'{state["character_menu"]}_{int(time.time())}_combined.wav')
|
output_file_path = os.path.join(
|
||||||
|
output_folder, f'{state["character_menu"]}_{int(time.time())}_combined.wav'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
output_file_path = os.path.join(output_folder, f'TTSOUT_{int(time.time())}_combined.wav')
|
output_file_path = os.path.join(
|
||||||
|
output_folder, f"TTSOUT_{int(time.time())}_combined.wav"
|
||||||
|
)
|
||||||
sf.write(output_file_path, audio, samplerate=sample_rate)
|
sf.write(output_file_path, audio, samplerate=sample_rate)
|
||||||
# Clean up unnecessary files
|
# Clean up unnecessary files
|
||||||
for audio_file in audio_files:
|
for audio_file in audio_files:
|
||||||
@@ -470,7 +511,7 @@ def combine(audio_files, output_folder, state):
|
|||||||
################################
|
################################
|
||||||
# PREVIEW VOICE - Generate Random Sentence if Voice Preview box is empty
|
# PREVIEW VOICE - Generate Random Sentence if Voice Preview box is empty
|
||||||
def random_sentence():
|
def random_sentence():
|
||||||
with open(this_dir / "harvard_sentences.txt") as f:
|
with open(this_dir / "system" / "config" / "harvard_sentences.txt") as f:
|
||||||
return random.choice(list(f))
|
return random.choice(list(f))
|
||||||
|
|
||||||
|
|
||||||
@@ -487,12 +528,19 @@ def voice_preview(string):
|
|||||||
output_file = Path(params["output_folder_wav"]) / "voice_preview.wav"
|
output_file = Path(params["output_folder_wav"]) / "voice_preview.wav"
|
||||||
# Generate the audio
|
# Generate the audio
|
||||||
language_code = languages.get(params["language"])
|
language_code = languages.get(params["language"])
|
||||||
|
temperature = params["local_temperature"]
|
||||||
|
repetition_penalty = params["local_repetition_penalty"]
|
||||||
# Convert the WindowsPath object to a string before using it in JSON payload
|
# Convert the WindowsPath object to a string before using it in JSON payload
|
||||||
output_file_str = output_file.as_posix()
|
output_file_str = output_file.as_posix()
|
||||||
# Lock before making the generate request
|
# Lock before making the generate request
|
||||||
with process_lock:
|
with process_lock:
|
||||||
generate_response = send_generate_request(
|
generate_response = send_generate_request(
|
||||||
string, params["voice"], language_code, output_file_str
|
string,
|
||||||
|
params["voice"],
|
||||||
|
language_code,
|
||||||
|
temperature,
|
||||||
|
repetition_penalty,
|
||||||
|
output_file_str,
|
||||||
)
|
)
|
||||||
# Check if lock is already acquired
|
# Check if lock is already acquired
|
||||||
if process_lock.locked():
|
if process_lock.locked():
|
||||||
@@ -509,8 +557,82 @@ def voice_preview(string):
|
|||||||
return f"[{params['branding']}Server] Audio generation failed. Status: {generate_response.get('status')}"
|
return f"[{params['branding']}Server] Audio generation failed. Status: {generate_response.get('status')}"
|
||||||
|
|
||||||
|
|
||||||
def replace_asterisk(match):
|
#######################
|
||||||
return match.group(0) + '"<*'
|
#### TEXT CLEANING ####
|
||||||
|
#######################
|
||||||
|
|
||||||
|
def process_text(text):
|
||||||
|
# Normalize HTML encoded quotes
|
||||||
|
text = html.unescape(text)
|
||||||
|
|
||||||
|
# Replace ellipsis with a single dot
|
||||||
|
text = re.sub(r"\.{3,}", ".", text)
|
||||||
|
|
||||||
|
# Pattern to identify combined narrator and character speech
|
||||||
|
combined_pattern = r'(\*[^*"]+\*|"[^"*]+")'
|
||||||
|
|
||||||
|
# List to hold parts of speech along with their type
|
||||||
|
ordered_parts = []
|
||||||
|
|
||||||
|
# Track the start of the next segment
|
||||||
|
start = 0
|
||||||
|
|
||||||
|
# Find all matches
|
||||||
|
for match in re.finditer(combined_pattern, text):
|
||||||
|
# Add the text before the match, if any, as ambiguous
|
||||||
|
if start < match.start():
|
||||||
|
ambiguous_text = text[start : match.start()].strip()
|
||||||
|
if ambiguous_text:
|
||||||
|
ordered_parts.append(("ambiguous", ambiguous_text))
|
||||||
|
|
||||||
|
# Add the matched part as either narrator or character
|
||||||
|
matched_text = match.group(0)
|
||||||
|
if matched_text.startswith("*") and matched_text.endswith("*"):
|
||||||
|
ordered_parts.append(("narrator", matched_text.strip("*").strip()))
|
||||||
|
elif matched_text.startswith('"') and matched_text.endswith('"'):
|
||||||
|
ordered_parts.append(("character", matched_text.strip('"').strip()))
|
||||||
|
else:
|
||||||
|
# In case of mixed or improperly formatted parts
|
||||||
|
if "*" in matched_text:
|
||||||
|
ordered_parts.append(("narrator", matched_text.strip("*").strip('"')))
|
||||||
|
else:
|
||||||
|
ordered_parts.append(("character", matched_text.strip('"').strip("*")))
|
||||||
|
|
||||||
|
# Update the start of the next segment
|
||||||
|
start = match.end()
|
||||||
|
|
||||||
|
# Add any remaining text after the last match as ambiguous
|
||||||
|
if start < len(text):
|
||||||
|
ambiguous_text = text[start:].strip()
|
||||||
|
if ambiguous_text:
|
||||||
|
ordered_parts.append(("ambiguous", ambiguous_text))
|
||||||
|
|
||||||
|
return ordered_parts
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
#### IMAGE CLEANING ####
|
||||||
|
########################
|
||||||
|
|
||||||
|
img_pattern = r'<img[^>]*src\s*=\s*["\'][^"\'>]+["\'][^>]*>'
|
||||||
|
|
||||||
|
def extract_and_remove_images(text):
|
||||||
|
"""
|
||||||
|
Extracts all image data from the text and removes it for clean TTS processing.
|
||||||
|
Returns the cleaned text and the extracted image data.
|
||||||
|
"""
|
||||||
|
img_matches = re.findall(img_pattern, text)
|
||||||
|
img_info = "\n".join(img_matches) # Store extracted image data
|
||||||
|
cleaned_text = re.sub(img_pattern, '', text) # Remove images from text
|
||||||
|
return cleaned_text, img_info
|
||||||
|
|
||||||
|
def reinsert_images(text, img_info):
|
||||||
|
"""
|
||||||
|
Reinserts the previously extracted image data back into the text.
|
||||||
|
"""
|
||||||
|
if img_info: # Check if there are images to reinsert
|
||||||
|
text += f"\n\n{img_info}"
|
||||||
|
return text
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
#### TTS STANDARD GENERATION ####
|
#### TTS STANDARD GENERATION ####
|
||||||
@@ -519,102 +641,104 @@ def replace_asterisk(match):
|
|||||||
def output_modifier(string, state):
|
def output_modifier(string, state):
|
||||||
if not params["activate"]:
|
if not params["activate"]:
|
||||||
return string
|
return string
|
||||||
original_string = string
|
img_info = ""
|
||||||
cleaned_string = before_audio_generation(string, params)
|
cleaned_text, img_info = extract_and_remove_images(string)
|
||||||
|
# print("Cleaned STRING IS:", cleaned_text)
|
||||||
|
cleaned_string = before_audio_generation(cleaned_text, params)
|
||||||
if cleaned_string is None:
|
if cleaned_string is None:
|
||||||
return
|
return
|
||||||
string = cleaned_string
|
|
||||||
language_code = languages.get(params["language"])
|
language_code = languages.get(params["language"])
|
||||||
|
temperature = params["local_temperature"]
|
||||||
|
repetition_penalty = params["local_repetition_penalty"]
|
||||||
# Create a list to store generated audio paths
|
# Create a list to store generated audio paths
|
||||||
audio_files = []
|
audio_files = []
|
||||||
if process_lock.acquire(blocking=False):
|
if process_lock.acquire(blocking=False):
|
||||||
try:
|
try:
|
||||||
if params["narrator_enabled"]:
|
if params["narrator_enabled"]:
|
||||||
# Do Some basic stripping and remove any double CR's
|
processed_parts = process_text(cleaned_string)
|
||||||
processed_string = (
|
|
||||||
original_string
|
|
||||||
.replace("***", "*")
|
|
||||||
.replace("**", "*")
|
|
||||||
.replace("\n\n", "\n")
|
|
||||||
.replace("\n", "")
|
|
||||||
)
|
|
||||||
processed_string = re.sub(r'\.\*\n\*', '. ', processed_string)
|
|
||||||
processed_string = (processed_string .replace('"\n\n*', '"<*'))
|
|
||||||
processed_string = (processed_string .replace('"\n', '< '))
|
|
||||||
processed_string = (processed_string .replace("'", "'"))
|
|
||||||
processed_string = (processed_string .replace("\n", " "))
|
|
||||||
processed_string = (processed_string .replace('"', '"<'))
|
|
||||||
processed_string = (processed_string .replace('"', '"<'))
|
|
||||||
#pattern = re.compile(r'(?<=[a-zA-Z!])"<(?=[a-zA-Z])')
|
|
||||||
pattern = re.compile(r'(?<=[a-zA-Z!?\.])"<(?=[a-zA-Z])')
|
|
||||||
processed_string = pattern.sub('" ', processed_string)
|
|
||||||
pattern = re.compile(r'(?<=[a-zA-Z])\*(?=[a-zA-Z])')
|
|
||||||
processed_string = pattern.sub('*"', processed_string)
|
|
||||||
processed_string = processed_string.replace('"<. *', '"< *"')
|
|
||||||
processed_string = processed_string.replace('< *"', '< *')
|
|
||||||
processed_string = processed_string.replace('. *', '< *')
|
|
||||||
processed_string = processed_string.replace('! *', '"< *')
|
|
||||||
processed_string = processed_string.replace('? *', '< *')
|
|
||||||
processed_string = processed_string.replace('* ', '* "<')
|
|
||||||
processed_string = processed_string.replace('*. ', '* "<')
|
|
||||||
processed_string = re.sub(r'\*(?=[a-zA-Z])', replace_asterisk, processed_string)
|
|
||||||
# Set up a tracking of the individual wav files.
|
|
||||||
audio_files_all_paragraphs = []
|
audio_files_all_paragraphs = []
|
||||||
# Split the line using " and ".* " (so end of sentences, leaving special characters added to the start of all OTHER sentences, bar possibly the first one if its starting with a *
|
for part_type, part in processed_parts:
|
||||||
parts = re.split(r'"|\.\*', processed_string)
|
|
||||||
audio_files_paragraph = []
|
|
||||||
for i, part in enumerate(parts):
|
|
||||||
# Skip parts that are too short
|
# Skip parts that are too short
|
||||||
if len(part.strip()) <= 3:
|
if len(part.strip()) <= 3:
|
||||||
continue
|
continue
|
||||||
# Figure out which type of line it is, then replace characters as necessary to avoid TTS trying to pronunce them, htmlunescape after.
|
|
||||||
# Character will always be a < with a letter immediately after it
|
# Determine the voice to use based on the part type
|
||||||
if '<' in part and '< *' not in part and '<*' not in part and '< *' not in part and '< ' not in part and '< ' not in part:
|
if part_type == "narrator":
|
||||||
cleaned_part = html.unescape(part.replace('<', ''))
|
|
||||||
voice_to_use = params["voice"]
|
|
||||||
#Narrator will always be an * or < with an * a position or two after it.
|
|
||||||
elif '<*' in part or '< *' in part or '< *' in part or '*' in part:
|
|
||||||
cleaned_part = html.unescape(part.replace('<*', '').replace('< *', '').replace('< *', '').replace('*', ''))
|
|
||||||
voice_to_use = params["narrator_voice"]
|
voice_to_use = params["narrator_voice"]
|
||||||
#If the other two dont capture it, aka, the AI gave no * or " on the line, use non_quoted_text_is aka user interface, user can choose Char or Narrator
|
print(
|
||||||
elif non_quoted_text_is:
|
f"[{params['branding']}TTSGen] \033[92mNarrator\033[0m"
|
||||||
cleaned_part = html.unescape(part.replace('< ', '').replace('< ', '').replace('< ', ''))
|
) # Green
|
||||||
|
elif part_type == "character":
|
||||||
voice_to_use = params["voice"]
|
voice_to_use = params["voice"]
|
||||||
|
print(
|
||||||
|
f"[{params['branding']}TTSGen] \033[36mCharacter\033[0m"
|
||||||
|
) # Yellow
|
||||||
else:
|
else:
|
||||||
cleaned_part = html.unescape(part.replace('< ', '').replace('< ', '').replace('< ', ''))
|
# Handle ambiguous parts based on user preference
|
||||||
voice_to_use = params["narrator_voice"]
|
voice_to_use = (
|
||||||
# Generate that TTS and output to a file
|
params["voice"]
|
||||||
|
if non_quoted_text_is
|
||||||
|
else params["narrator_voice"]
|
||||||
|
)
|
||||||
|
voice_description = (
|
||||||
|
"\033[36mCharacter (Text-not-inside)\033[0m"
|
||||||
|
if non_quoted_text_is
|
||||||
|
else "\033[92mNarrator (Text-not-inside)\033[0m"
|
||||||
|
)
|
||||||
|
print(f"[{params['branding']}TTSGen] {voice_description}")
|
||||||
|
|
||||||
|
# Replace multiple exclamation marks, question marks, or other punctuation with a single instance
|
||||||
|
cleaned_part = re.sub(r"([!?.])\1+", r"\1", part)
|
||||||
|
# Further clean to remove any other unwanted characters
|
||||||
|
cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0100-\u017F\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171\u4E00-\u9FFF\u3400-\u4DBF\u20000-\u2A6DF\u3000-\u303F\$]', '', cleaned_part)
|
||||||
|
# Remove all newline characters (single or multiple)
|
||||||
|
cleaned_part = re.sub(r"\n+", " ", cleaned_part)
|
||||||
|
|
||||||
|
# Generate TTS and output to a file
|
||||||
output_filename = get_output_filename(state)
|
output_filename = get_output_filename(state)
|
||||||
generate_response = send_generate_request(
|
generate_response = send_generate_request(
|
||||||
cleaned_part, voice_to_use, language_code, output_filename
|
cleaned_part,
|
||||||
|
voice_to_use,
|
||||||
|
language_code,
|
||||||
|
temperature,
|
||||||
|
repetition_penalty,
|
||||||
|
output_filename,
|
||||||
)
|
)
|
||||||
audio_path = generate_response.get("data", {}).get("audio_path")
|
audio_path = generate_response.get("data", {}).get("audio_path")
|
||||||
audio_files_paragraph.append(audio_path)
|
audio_files_all_paragraphs.append(audio_path)
|
||||||
# Accumulate audio files within the paragraph
|
|
||||||
audio_files_all_paragraphs.extend(audio_files_paragraph)
|
|
||||||
# Combine audio files across paragraphs
|
# Combine audio files across paragraphs
|
||||||
final_output_file = combine(
|
final_output_file = combine(
|
||||||
audio_files_all_paragraphs, params["output_folder_wav"], state
|
audio_files_all_paragraphs, params["output_folder_wav"], state
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
processed_string = (
|
# Decode HTML entities first
|
||||||
original_string
|
cleaned_part = html.unescape(cleaned_string)
|
||||||
.replace("***", "")
|
# Replace multiple instances of certain punctuation marks with a single instance
|
||||||
.replace("**", "")
|
cleaned_part = re.sub(r"([!?.])\1+", r"\1", cleaned_part)
|
||||||
.replace("*", "")
|
# Further clean to remove any other unwanted characters
|
||||||
.replace("\n\n", "\n")
|
cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0100-\u017F\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171\u4E00-\u9FFF\u3400-\u4DBF\u20000-\u2A6DF\u3000-\u303F\$]', '', cleaned_part)
|
||||||
.replace("'", "'")
|
# Remove all newline characters (single or multiple)
|
||||||
)
|
cleaned_part = re.sub(r"\n+", " ", cleaned_part)
|
||||||
cleaned_part = html.unescape(processed_string)
|
|
||||||
# Process the part and give it a non-character name if being used vai API or standalone.
|
# Process the part and give it a non-character name if being used vai API or standalone.
|
||||||
if "character_menu" in state:
|
if "character_menu" in state:
|
||||||
output_file = Path(f'{params["output_folder_wav"]}/{state["character_menu"]}_{int(time.time())}.wav')
|
output_file = Path(
|
||||||
|
f'{params["output_folder_wav"]}/{state["character_menu"]}_{int(time.time())}.wav'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
output_file = Path(f'{params["output_folder_wav"]}/TTSOUT_{int(time.time())}.wav')
|
output_file = Path(
|
||||||
|
f'{params["output_folder_wav"]}/TTSOUT_{int(time.time())}.wav'
|
||||||
|
)
|
||||||
output_file_str = output_file.as_posix()
|
output_file_str = output_file.as_posix()
|
||||||
output_file = get_output_filename(state)
|
output_file = get_output_filename(state)
|
||||||
generate_response = send_generate_request(
|
generate_response = send_generate_request(
|
||||||
cleaned_part, params["voice"], language_code, output_file_str
|
cleaned_part,
|
||||||
|
params["voice"],
|
||||||
|
language_code,
|
||||||
|
temperature,
|
||||||
|
repetition_penalty,
|
||||||
|
output_file_str,
|
||||||
)
|
)
|
||||||
audio_path = generate_response.get("data", {}).get("audio_path")
|
audio_path = generate_response.get("data", {}).get("audio_path")
|
||||||
final_output_file = audio_path
|
final_output_file = audio_path
|
||||||
@@ -633,42 +757,40 @@ def output_modifier(string, state):
|
|||||||
if audio_path:
|
if audio_path:
|
||||||
# Handle Gradio and playback
|
# Handle Gradio and playback
|
||||||
autoplay = "autoplay" if params["autoplay"] else ""
|
autoplay = "autoplay" if params["autoplay"] else ""
|
||||||
string = (
|
string = (f'<audio src="file/{final_output_file}" controls {autoplay}></audio>')
|
||||||
f'<audio src="file/{final_output_file}" controls {autoplay}></audio>'
|
|
||||||
)
|
|
||||||
|
|
||||||
if params["show_text"]:
|
if params["show_text"]:
|
||||||
string += f"\n\n{original_string}"
|
string += reinsert_images(cleaned_string, img_info)
|
||||||
shared.processing_message = "*Is typing...*"
|
shared.processing_message = "*Is typing...*"
|
||||||
|
|
||||||
return string
|
return string
|
||||||
else:
|
else:
|
||||||
print(
|
print(f"[{params['branding']}Server] \033[91mWarning\033[0m No audio path in the response.")
|
||||||
f"[{params['branding']}Server] \033[91mWarning\033[0m No audio path in the response."
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
print(
|
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Audio generation failed. Status:", generate_response.get("message"),)
|
||||||
f"[{params['branding']}Server] \033[91mWarning\033[0m Audio generation failed. Status:",
|
|
||||||
generate_response.get("message"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_output_filename(state):
|
def get_output_filename(state):
|
||||||
if "character_menu" in state:
|
if "character_menu" in state:
|
||||||
return Path(f'{params["output_folder_wav"]}/{state["character_menu"]}_{str(uuid.uuid4())[:8]}.wav').as_posix()
|
return Path(
|
||||||
|
f'{params["output_folder_wav"]}/{state["character_menu"]}_{str(uuid.uuid4())[:8]}.wav'
|
||||||
|
).as_posix()
|
||||||
else:
|
else:
|
||||||
return Path(f'{params["output_folder_wav"]}/TTSOUT_{str(uuid.uuid4())[:8]}.wav').as_posix()
|
return Path(
|
||||||
|
f'{params["output_folder_wav"]}/TTSOUT_{str(uuid.uuid4())[:8]}.wav'
|
||||||
|
).as_posix()
|
||||||
|
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
#### SEND GENERATION REQUEST TO TTS ENGINE ####
|
#### SEND GENERATION REQUEST TO TTS ENGINE ####
|
||||||
###############################################
|
###############################################
|
||||||
def send_generate_request(text, voice, language, output_file):
|
def send_generate_request(
|
||||||
|
text, voice, language, temperature, repetition_penalty, output_file
|
||||||
|
):
|
||||||
url = f"{base_url}/api/generate"
|
url = f"{base_url}/api/generate"
|
||||||
payload = {
|
payload = {
|
||||||
"text": text,
|
"text": text,
|
||||||
"voice": voice,
|
"voice": voice,
|
||||||
"language": language,
|
"language": language,
|
||||||
|
"temperature": temperature,
|
||||||
|
"repetition_penalty": repetition_penalty,
|
||||||
"output_file": output_file,
|
"output_file": output_file,
|
||||||
}
|
}
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
@@ -693,12 +815,14 @@ def state_modifier(state):
|
|||||||
state["stream"] = False
|
state["stream"] = False
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
def update_narrator_enabled(value):
|
def update_narrator_enabled(value):
|
||||||
if value == "Enabled":
|
if value == "Enabled":
|
||||||
params["narrator_enabled"] = True
|
params["narrator_enabled"] = True
|
||||||
elif value == "Disabled":
|
elif value == "Disabled":
|
||||||
params["narrator_enabled"] = False
|
params["narrator_enabled"] = False
|
||||||
|
|
||||||
|
|
||||||
def update_non_quoted_text_is(value):
|
def update_non_quoted_text_is(value):
|
||||||
global non_quoted_text_is
|
global non_quoted_text_is
|
||||||
if value == "Narrator":
|
if value == "Narrator":
|
||||||
@@ -706,6 +830,7 @@ def update_non_quoted_text_is(value):
|
|||||||
elif value == "Char":
|
elif value == "Char":
|
||||||
non_quoted_text_is = True
|
non_quoted_text_is = True
|
||||||
|
|
||||||
|
|
||||||
def input_modifier(string, state):
|
def input_modifier(string, state):
|
||||||
if not params["activate"]:
|
if not params["activate"]:
|
||||||
return string
|
return string
|
||||||
@@ -713,42 +838,56 @@ def input_modifier(string, state):
|
|||||||
shared.processing_message = "*Is recording a voice message...*"
|
shared.processing_message = "*Is recording a voice message...*"
|
||||||
return string
|
return string
|
||||||
|
|
||||||
def custom_css():
|
|
||||||
path_to_css = Path(f"{this_dir}/style.css")
|
|
||||||
return open(path_to_css, "r").read()
|
|
||||||
|
|
||||||
|
|
||||||
def ui():
|
def ui():
|
||||||
with gr.Accordion(params["branding"] + " TTS (XTTSv2)"):
|
with gr.Accordion(params["branding"] + " TTS (XTTSv2)"):
|
||||||
|
# Activate alltalk_tts, Enable autoplay, Show text
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
activate = gr.Checkbox(value=params["activate"], label="Activate TTS")
|
activate = gr.Checkbox(value=params["activate"], label="Enable TTS")
|
||||||
autoplay = gr.Checkbox(
|
autoplay = gr.Checkbox(value=params["autoplay"], label="Autoplay TTS")
|
||||||
value=params["autoplay"], label="Play TTS automatically"
|
show_text = gr.Checkbox(value=params["show_text"], label="Show Text")
|
||||||
)
|
|
||||||
|
|
||||||
|
# Low vram enable, Deepspeed enable, Remove trailing dots
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
show_text = gr.Checkbox(
|
low_vram = gr.Checkbox(
|
||||||
value=params["show_text"], label="Show message text under audio player"
|
value=params["low_vram"], label="Enable Low VRAM Mode"
|
||||||
)
|
)
|
||||||
|
low_vram_play = gr.HTML(visible=False)
|
||||||
|
deepspeed_checkbox = gr.Checkbox(
|
||||||
|
value=params["deepspeed_activate"],
|
||||||
|
label="Enable DeepSpeed",
|
||||||
|
visible=deepspeed_installed,
|
||||||
|
)
|
||||||
|
deepspeed_checkbox_play = gr.HTML(visible=False)
|
||||||
remove_trailing_dots = gr.Checkbox(
|
remove_trailing_dots = gr.Checkbox(
|
||||||
value=params["remove_trailing_dots"],
|
value=params["remove_trailing_dots"], label='Remove trailing "."'
|
||||||
label='Remove trailing "." from text segments before generation',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TTS method, Character voice selection
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
|
model_loader_choices = ["API TTS", "API Local", "XTTSv2 Local"]
|
||||||
|
if finetuned_model:
|
||||||
|
model_loader_choices.append("XTTSv2 FT")
|
||||||
|
tts_radio_buttons = gr.Radio(
|
||||||
|
choices=model_loader_choices,
|
||||||
|
label="TTS Method (Each method sounds slightly different)",
|
||||||
|
value=gr_modelchoice, # Set the default value
|
||||||
|
)
|
||||||
|
tts_radio_buttons_play = gr.HTML(visible=False)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
available_voices = get_available_voices()
|
available_voices = get_available_voices()
|
||||||
default_voice = params["voice"]
|
default_voice = params[
|
||||||
# Check if the default voice is in the list of available voices
|
"voice"
|
||||||
|
] # Check if the default voice is in the list of available voices
|
||||||
|
|
||||||
if default_voice not in available_voices:
|
if default_voice not in available_voices:
|
||||||
# Handle the case where the default voice is not in the list (choose a default value or update it)
|
|
||||||
default_voice = available_voices[
|
default_voice = available_voices[
|
||||||
0
|
0
|
||||||
] # Choose the first available voice as the default
|
] # Choose the first available voice as the default
|
||||||
# Add allow_custom_value=True to the Dropdown
|
# Add allow_custom_value=True to the Dropdown
|
||||||
voice = gr.Dropdown(
|
voice = gr.Dropdown(
|
||||||
available_voices,
|
available_voices,
|
||||||
label="Default Voice",
|
label="Character Voice",
|
||||||
value=default_voice,
|
value=default_voice,
|
||||||
allow_custom_value=True,
|
allow_custom_value=True,
|
||||||
)
|
)
|
||||||
@@ -762,14 +901,11 @@ def ui():
|
|||||||
"refresh-button",
|
"refresh-button",
|
||||||
)
|
)
|
||||||
|
|
||||||
language = gr.Dropdown(
|
# Language, Narrator voice
|
||||||
languages.keys(),
|
|
||||||
label="Language",
|
|
||||||
allow_custom_value=True,
|
|
||||||
value=params["language"],
|
|
||||||
)
|
|
||||||
|
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
|
language = gr.Dropdown(
|
||||||
|
languages.keys(), label="Language", value=params["language"]
|
||||||
|
)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
narrator_voice_gr = gr.Dropdown(
|
narrator_voice_gr = gr.Dropdown(
|
||||||
get_available_voices(),
|
get_available_voices(),
|
||||||
@@ -786,43 +922,42 @@ def ui():
|
|||||||
},
|
},
|
||||||
"refresh-button",
|
"refresh-button",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Temperature, Repetition Penalty
|
||||||
|
with gr.Row():
|
||||||
|
local_temperature_gr = gr.Slider(
|
||||||
|
minimum=0.05,
|
||||||
|
maximum=1,
|
||||||
|
step=0.05,
|
||||||
|
label="Temperature",
|
||||||
|
value=params["local_temperature"],
|
||||||
|
)
|
||||||
|
local_repetition_penalty_gr = gr.Slider(
|
||||||
|
minimum=0.5,
|
||||||
|
maximum=20,
|
||||||
|
step=0.5,
|
||||||
|
label="Repetition Penalty",
|
||||||
|
value=params["local_repetition_penalty"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Narrator enable, Non quoted text, Explanation text
|
||||||
|
with gr.Row():
|
||||||
|
with gr.Row():
|
||||||
narrator_enabled_gr = gr.Radio(
|
narrator_enabled_gr = gr.Radio(
|
||||||
choices={"Enabled": "true", "Disabled": "false"},
|
choices={"Enabled": "true", "Disabled": "false"},
|
||||||
label="Narrator Activation",
|
label="Narrator",
|
||||||
value="Enabled" if params.get("narrator_enabled") else "Disabled",
|
value="Enabled" if params.get("narrator_enabled") else "Disabled",
|
||||||
)
|
)
|
||||||
non_quoted_text_is_gr = gr.Radio(
|
non_quoted_text_is_gr = gr.Radio(
|
||||||
choices={"Char": "true", "Narrator": "false"},
|
choices={"Character": "true", "Narrator": "false"},
|
||||||
label='Text NOT inside of * or " is',
|
label='Unmarked text NOT inside of * or " is',
|
||||||
value="Char" if non_quoted_text_is else "Narrator",
|
value="Character" if non_quoted_text_is else "Narrator",
|
||||||
)
|
)
|
||||||
|
|
||||||
with gr.Row():
|
|
||||||
low_vram = gr.Checkbox(
|
|
||||||
value=params["low_vram"], label="Low VRAM mode (Read NOTE)"
|
|
||||||
)
|
|
||||||
low_vram_play = gr.HTML(visible=False)
|
|
||||||
deepspeed_checkbox = gr.Checkbox(
|
|
||||||
value=params["deepspeed_activate"],
|
|
||||||
label="Activate DeepSpeed (Read NOTE)",
|
|
||||||
visible=deepspeed_installed,
|
|
||||||
)
|
|
||||||
deepspeed_checkbox_play = gr.HTML(visible=False)
|
|
||||||
|
|
||||||
with gr.Row():
|
|
||||||
model_loader_choices=["API TTS", "API Local", "XTTSv2 Local"]
|
|
||||||
if finetuned_model:
|
|
||||||
model_loader_choices.append("XTTSv2 FT")
|
|
||||||
tts_radio_buttons = gr.Radio(
|
|
||||||
choices=model_loader_choices,
|
|
||||||
label="Select TTS Generation Method (Read NOTE)",
|
|
||||||
value=gr_modelchoice, # Set the default value
|
|
||||||
)
|
|
||||||
tts_radio_buttons_play = gr.HTML(visible=False)
|
|
||||||
explanation_text = gr.HTML(
|
explanation_text = gr.HTML(
|
||||||
f"<p>⚙️ <a href='http://{params['ip_address']}:{params['port_number']}'>Click here for the Settings page, help & instructions</a><a href='http://{params['ip_address']}:{params['port_number']}'></a>⚙️<br>NOTE: Switching Model Type, Low VRAM & DeepSpeed, each takes 15 seconds. Each TTS generation method has a slightly different sound. DeepSpeed checkbox is only visible if DeepSpeed is installed on your system."
|
f"<p>⚙️ <a href='http://{params['ip_address']}:{params['port_number']}'>Settings and Documentation Page</a><a href='http://{params['ip_address']}:{params['port_number']}'></a>⚙️<br>- Low VRAM Mode and Deepspeed take 15 seconds to be enabled or disabled.<br>- The DeepSpeed checkbox is only visible if DeepSpeed is present.</p>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Preview speech
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
preview_text = gr.Text(
|
preview_text = gr.Text(
|
||||||
show_label=False,
|
show_label=False,
|
||||||
@@ -892,18 +1027,34 @@ def ui():
|
|||||||
autoplay.change(lambda x: params.update({"autoplay": x}), autoplay, None)
|
autoplay.change(lambda x: params.update({"autoplay": x}), autoplay, None)
|
||||||
low_vram.change(lambda x: params.update({"low_vram": x}), low_vram, None)
|
low_vram.change(lambda x: params.update({"low_vram": x}), low_vram, None)
|
||||||
low_vram.change(lambda x: send_lowvram_request(x), low_vram, low_vram_play, None)
|
low_vram.change(lambda x: send_lowvram_request(x), low_vram, low_vram_play, None)
|
||||||
tts_radio_buttons.change(send_reload_request, tts_radio_buttons, tts_radio_buttons_play, None)
|
tts_radio_buttons.change(
|
||||||
deepspeed_checkbox.change(send_deepspeed_request, deepspeed_checkbox, deepspeed_checkbox_play, None)
|
send_reload_request, tts_radio_buttons, tts_radio_buttons_play, None
|
||||||
|
)
|
||||||
|
deepspeed_checkbox.change(
|
||||||
|
send_deepspeed_request, deepspeed_checkbox, deepspeed_checkbox_play, None
|
||||||
|
)
|
||||||
remove_trailing_dots.change(
|
remove_trailing_dots.change(
|
||||||
lambda x: params.update({"remove_trailing_dots": x}), remove_trailing_dots, None
|
lambda x: params.update({"remove_trailing_dots": x}), remove_trailing_dots, None
|
||||||
)
|
)
|
||||||
voice.change(lambda x: params.update({"voice": x}), voice, None)
|
voice.change(lambda x: params.update({"voice": x}), voice, None)
|
||||||
language.change(lambda x: params.update({"language": x}), language, None)
|
language.change(lambda x: params.update({"language": x}), language, None)
|
||||||
|
|
||||||
|
# TSS Settings
|
||||||
|
local_temperature_gr.change(
|
||||||
|
lambda x: params.update({"local_temperature": x}), local_temperature_gr, None
|
||||||
|
)
|
||||||
|
local_repetition_penalty_gr.change(
|
||||||
|
lambda x: params.update({"local_repetition_penalty": x}),
|
||||||
|
local_repetition_penalty_gr,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
# Narrator selection actions
|
# Narrator selection actions
|
||||||
narrator_enabled_gr.change(update_narrator_enabled, narrator_enabled_gr, None)
|
narrator_enabled_gr.change(update_narrator_enabled, narrator_enabled_gr, None)
|
||||||
non_quoted_text_is_gr.change(update_non_quoted_text_is, non_quoted_text_is_gr, None)
|
non_quoted_text_is_gr.change(update_non_quoted_text_is, non_quoted_text_is_gr, None)
|
||||||
narrator_voice_gr.change(lambda x: params.update({"narrator_voice": x}), narrator_voice_gr, None)
|
narrator_voice_gr.change(
|
||||||
|
lambda x: params.update({"narrator_voice": x}), narrator_voice_gr, None
|
||||||
|
)
|
||||||
|
|
||||||
# Play preview
|
# Play preview
|
||||||
preview_text.submit(voice_preview, preview_text, preview_audio)
|
preview_text.submit(voice_preview, preview_text, preview_audio)
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
.SDAP .hires_opts input[type="number"] {
|
|
||||||
width: 6em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* silero_tts preview */
|
|
||||||
.form:has(> #silero_preview_text) {
|
|
||||||
min-width: 75%
|
|
||||||
}
|
|
||||||
|
After Width: | Height: | Size: 440 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -89,25 +89,25 @@
|
|||||||
<h3>AllTalk Startup Settings</h3><br>
|
<h3>AllTalk Startup Settings</h3><br>
|
||||||
<form action="/update-settings" method="post">
|
<form action="/update-settings" method="post">
|
||||||
|
|
||||||
<label for="activate" style="color: #33cc33;">Activate TTS:</label>
|
<label for="activate" style="color: #b273fa;">TG-webui Activate TTS:</label>
|
||||||
<select id="activate" name="activate" required="">
|
<select id="activate" name="activate" required="">
|
||||||
<option {% if data.activate %}selected{% endif %} value="true">True</option>
|
<option {% if data.activate %}selected{% endif %} value="true">True</option>
|
||||||
<option {% if not data.activate %}selected{% endif %} value="false">False</option>
|
<option {% if not data.activate %}selected{% endif %} value="false">False</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="autoplay" style="color: #33cc33;"> Autoplay TTS output:</label>
|
<label for="autoplay" style="color: #b273fa;"> TG-webui Autoplay TTS:</label>
|
||||||
<select id="autoplay" name="autoplay" required="">
|
<select id="autoplay" name="autoplay" required="">
|
||||||
<option {% if data.autoplay %}selected{% endif %} value="true">True</option>
|
<option {% if data.autoplay %}selected{% endif %} value="true">True</option>
|
||||||
<option {% if not data.autoplay %}selected{% endif %} value="false">False</option>
|
<option {% if not data.autoplay %}selected{% endif %} value="false">False</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="show_text" style="color: #33cc33;"> Show Text on generation:</label>
|
<label for="show_text" style="color: #b273fa;">TG-webui Show Text:</label>
|
||||||
<select id="show_text" name="show_text" required="">
|
<select id="show_text" name="show_text" required="">
|
||||||
<option {% if data.show_text %}selected{% endif %} value="true">True</option>
|
<option {% if data.show_text %}selected{% endif %} value="true">True</option>
|
||||||
<option {% if not data.show_text %}selected{% endif %} value="false">False</option>
|
<option {% if not data.show_text %}selected{% endif %} value="false">False</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="voice" style="color: #33cc33;"> Default voice:</label>
|
<label for="voice" style="color: #b273fa;"> TG-webui Default voice:</label>
|
||||||
<select id="voice" name="voice" required="">
|
<select id="voice" name="voice" required="">
|
||||||
{% for file in wav_files %}
|
{% for file in wav_files %}
|
||||||
<option value="{{ file }}" {% if data.voice==file %}selected{% endif %}>{{ file }}</option>
|
<option value="{{ file }}" {% if data.voice==file %}selected{% endif %}>{{ file }}</option>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<label for="language" style="color: #33cc33;">Default Language:</label>
|
<label for="language" style="color: #b273fa;">TG-webui Default Language:</label>
|
||||||
<select id="language" name="language" required="">
|
<select id="language" name="language" required="">
|
||||||
<option value="Arabic" {% if data.language=='Arabic' %}selected{% endif %}>Arabic</option>
|
<option value="Arabic" {% if data.language=='Arabic' %}selected{% endif %}>Arabic</option>
|
||||||
<option value="Chinese" {% if data.language=='Chinese' %}selected{% endif %}>Chinese</option>
|
<option value="Chinese" {% if data.language=='Chinese' %}selected{% endif %}>Chinese</option>
|
||||||
@@ -135,20 +135,20 @@
|
|||||||
<option value="Turkish" {% if data.language=='Turkish' %}selected{% endif %}>Turkish</option>
|
<option value="Turkish" {% if data.language=='Turkish' %}selected{% endif %}>Turkish</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="narrator_voice" style="color: #33cc33;"> Narrator voice:</label>
|
<label for="narrator_voice" style="color: #b273fa;"> TG-webui Narrator voice:</label>
|
||||||
<select id="narrator_voice" name="narrator_voice" required="">
|
<select id="narrator_voice" name="narrator_voice" required="">
|
||||||
{% for file in wav_files %}
|
{% for file in wav_files %}
|
||||||
<option value="{{ file }}" {% if data.narrator_voice==file %}selected{% endif %}>{{ file }}</option>
|
<option value="{{ file }}" {% if data.narrator_voice==file %}selected{% endif %}>{{ file }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="remove_trailing_dots" style="color: #33cc33;"> Remove Trailing Dots:</label>
|
<label for="remove_trailing_dots" style="color: #b273fa;">TG-webui Remove Trailing Dots:</label>
|
||||||
<select id="remove_trailing_dots" name="remove_trailing_dots" required="">
|
<select id="remove_trailing_dots" name="remove_trailing_dots" required="">
|
||||||
<option {% if data.remove_trailing_dots %}selected{% endif %} value="true">True</option>
|
<option {% if data.remove_trailing_dots %}selected{% endif %} value="true">True</option>
|
||||||
<option {% if not data.remove_trailing_dots %}selected{% endif %} value="false">False</option>
|
<option {% if not data.remove_trailing_dots %}selected{% endif %} value="false">False</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="narrator_enabled" style="color: #33cc33;"> Narrator enabled:</label>
|
<label for="narrator_enabled" style="color: #b273fa;"> TG-webui Narrator enabled:</label>
|
||||||
<select id="narrator_enabled" name="narrator_enabled" required="">
|
<select id="narrator_enabled" name="narrator_enabled" required="">
|
||||||
<option {% if data.narrator_enabled %}selected{% endif %} value="true">True</option>
|
<option {% if data.narrator_enabled %}selected{% endif %} value="true">True</option>
|
||||||
<option {% if not data.narrator_enabled %}selected{% endif %} value="false">False</option>
|
<option {% if not data.narrator_enabled %}selected{% endif %} value="false">False</option>
|
||||||
|
After Width: | Height: | Size: 445 KiB |
|
Before Width: | Height: | Size: 476 KiB After Width: | Height: | Size: 476 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 547 KiB After Width: | Height: | Size: 547 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,869 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
import textwrap
|
||||||
|
from functools import cached_property
|
||||||
|
|
||||||
|
import pypinyin
|
||||||
|
import torch
|
||||||
|
from hangul_romanize import Transliter
|
||||||
|
from hangul_romanize.rule import academic
|
||||||
|
from num2words import num2words
|
||||||
|
from spacy.lang.ar import Arabic
|
||||||
|
from spacy.lang.en import English
|
||||||
|
from spacy.lang.es import Spanish
|
||||||
|
from spacy.lang.ja import Japanese
|
||||||
|
from spacy.lang.zh import Chinese
|
||||||
|
from tokenizers import Tokenizer
|
||||||
|
|
||||||
|
from TTS.tts.layers.xtts.zh_num2words import TextNorm as zh_num2words
|
||||||
|
|
||||||
|
|
||||||
|
def get_spacy_lang(lang):
|
||||||
|
if lang == "zh":
|
||||||
|
return Chinese()
|
||||||
|
elif lang == "ja":
|
||||||
|
return Japanese()
|
||||||
|
elif lang == "ar":
|
||||||
|
return Arabic()
|
||||||
|
elif lang == "es":
|
||||||
|
return Spanish()
|
||||||
|
else:
|
||||||
|
# For most languages, Enlish does the job
|
||||||
|
return English()
|
||||||
|
|
||||||
|
|
||||||
|
def split_sentence(text, lang, text_split_length=250):
|
||||||
|
"""Preprocess the input text"""
|
||||||
|
text_splits = []
|
||||||
|
if text_split_length is not None and len(text) >= text_split_length:
|
||||||
|
text_splits.append("")
|
||||||
|
nlp = get_spacy_lang(lang)
|
||||||
|
nlp.add_pipe("sentencizer")
|
||||||
|
doc = nlp(text)
|
||||||
|
for sentence in doc.sents:
|
||||||
|
if len(text_splits[-1]) + len(str(sentence)) <= text_split_length:
|
||||||
|
# if the last sentence + the current sentence is less than the text_split_length
|
||||||
|
# then add the current sentence to the last sentence
|
||||||
|
text_splits[-1] += " " + str(sentence)
|
||||||
|
text_splits[-1] = text_splits[-1].lstrip()
|
||||||
|
elif len(str(sentence)) > text_split_length:
|
||||||
|
# if the current sentence is greater than the text_split_length
|
||||||
|
for line in textwrap.wrap(
|
||||||
|
str(sentence),
|
||||||
|
width=text_split_length,
|
||||||
|
drop_whitespace=True,
|
||||||
|
break_on_hyphens=False,
|
||||||
|
tabsize=1,
|
||||||
|
):
|
||||||
|
text_splits.append(str(line))
|
||||||
|
else:
|
||||||
|
text_splits.append(str(sentence))
|
||||||
|
|
||||||
|
if len(text_splits) > 1:
|
||||||
|
if text_splits[0] == "":
|
||||||
|
del text_splits[0]
|
||||||
|
else:
|
||||||
|
text_splits = [text.lstrip()]
|
||||||
|
|
||||||
|
return text_splits
|
||||||
|
|
||||||
|
|
||||||
|
_whitespace_re = re.compile(r"\s+")
|
||||||
|
|
||||||
|
# List of (regular expression, replacement) pairs for abbreviations:
|
||||||
|
_abbreviations = {
|
||||||
|
"en": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("mrs", "misess"),
|
||||||
|
("mr", "mister"),
|
||||||
|
("dr", "doctor"),
|
||||||
|
("st", "saint"),
|
||||||
|
("co", "company"),
|
||||||
|
("jr", "junior"),
|
||||||
|
("maj", "major"),
|
||||||
|
("gen", "general"),
|
||||||
|
("drs", "doctors"),
|
||||||
|
("rev", "reverend"),
|
||||||
|
("lt", "lieutenant"),
|
||||||
|
("hon", "honorable"),
|
||||||
|
("sgt", "sergeant"),
|
||||||
|
("capt", "captain"),
|
||||||
|
("esq", "esquire"),
|
||||||
|
("ltd", "limited"),
|
||||||
|
("col", "colonel"),
|
||||||
|
("ft", "fort"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"es": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("sra", "señora"),
|
||||||
|
("sr", "señor"),
|
||||||
|
("dr", "doctor"),
|
||||||
|
("dra", "doctora"),
|
||||||
|
("st", "santo"),
|
||||||
|
("co", "compañía"),
|
||||||
|
("jr", "junior"),
|
||||||
|
("ltd", "limitada"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"fr": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("mme", "madame"),
|
||||||
|
("mr", "monsieur"),
|
||||||
|
("dr", "docteur"),
|
||||||
|
("st", "saint"),
|
||||||
|
("co", "compagnie"),
|
||||||
|
("jr", "junior"),
|
||||||
|
("ltd", "limitée"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"de": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("fr", "frau"),
|
||||||
|
("dr", "doktor"),
|
||||||
|
("st", "sankt"),
|
||||||
|
("co", "firma"),
|
||||||
|
("jr", "junior"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"pt": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("sra", "senhora"),
|
||||||
|
("sr", "senhor"),
|
||||||
|
("dr", "doutor"),
|
||||||
|
("dra", "doutora"),
|
||||||
|
("st", "santo"),
|
||||||
|
("co", "companhia"),
|
||||||
|
("jr", "júnior"),
|
||||||
|
("ltd", "limitada"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"it": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
# ("sig.ra", "signora"),
|
||||||
|
("sig", "signore"),
|
||||||
|
("dr", "dottore"),
|
||||||
|
("st", "santo"),
|
||||||
|
("co", "compagnia"),
|
||||||
|
("jr", "junior"),
|
||||||
|
("ltd", "limitata"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"pl": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("p", "pani"),
|
||||||
|
("m", "pan"),
|
||||||
|
("dr", "doktor"),
|
||||||
|
("sw", "święty"),
|
||||||
|
("jr", "junior"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ar": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
# There are not many common abbreviations in Arabic as in English.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"zh": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
# Chinese doesn't typically use abbreviations in the same way as Latin-based scripts.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"cs": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("dr", "doktor"), # doctor
|
||||||
|
("ing", "inženýr"), # engineer
|
||||||
|
("p", "pan"), # Could also map to pani for woman but no easy way to do it
|
||||||
|
# Other abbreviations would be specialized and not as common.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ru": [
|
||||||
|
(re.compile("\\b%s\\b" % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("г-жа", "госпожа"), # Mrs.
|
||||||
|
("г-н", "господин"), # Mr.
|
||||||
|
("д-р", "доктор"), # doctor
|
||||||
|
# Other abbreviations are less common or specialized.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"nl": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("dhr", "de heer"), # Mr.
|
||||||
|
("mevr", "mevrouw"), # Mrs.
|
||||||
|
("dr", "dokter"), # doctor
|
||||||
|
("jhr", "jonkheer"), # young lord or nobleman
|
||||||
|
# Dutch uses more abbreviations, but these are the most common ones.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"tr": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("b", "bay"), # Mr.
|
||||||
|
("byk", "büyük"), # büyük
|
||||||
|
("dr", "doktor"), # doctor
|
||||||
|
# Add other Turkish abbreviations here if needed.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"hu": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("dr", "doktor"), # doctor
|
||||||
|
("b", "bácsi"), # Mr.
|
||||||
|
("nőv", "nővér"), # nurse
|
||||||
|
# Add other Hungarian abbreviations here if needed.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ko": [
|
||||||
|
(re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
# Korean doesn't typically use abbreviations in the same way as Latin-based scripts.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ja": [
|
||||||
|
(re.compile("\\b%s\\b" % x[0]), x[1])
|
||||||
|
for x in [
|
||||||
|
("氏", "さん"), # Mr.
|
||||||
|
("夫人", "おんなのひと"), # Mrs.
|
||||||
|
("博士", "はかせ"), # Doctor or PhD
|
||||||
|
("株", "株式会社"), # Corporation
|
||||||
|
("有", "有限会社"), # Limited company
|
||||||
|
("大学", "だいがく"), # University
|
||||||
|
("先生", "せんせい"), # Teacher/Professor/Master
|
||||||
|
("君", "くん") # Used at the end of boys' names to express familiarity or affection.
|
||||||
|
]
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def expand_abbreviations_multilingual(text, lang="en"):
|
||||||
|
for regex, replacement in _abbreviations[lang]:
|
||||||
|
text = re.sub(regex, replacement, text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
_symbols_multilingual = {
|
||||||
|
"en": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " and "),
|
||||||
|
("@", " at "),
|
||||||
|
("%", " percent "),
|
||||||
|
("#", " hash "),
|
||||||
|
("$", " dollar "),
|
||||||
|
("£", " pound "),
|
||||||
|
("°", " degree "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"es": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " y "),
|
||||||
|
("@", " arroba "),
|
||||||
|
("%", " por ciento "),
|
||||||
|
("#", " numeral "),
|
||||||
|
("$", " dolar "),
|
||||||
|
("£", " libra "),
|
||||||
|
("°", " grados "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"fr": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " et "),
|
||||||
|
("@", " arobase "),
|
||||||
|
("%", " pour cent "),
|
||||||
|
("#", " dièse "),
|
||||||
|
("$", " dollar "),
|
||||||
|
("£", " livre "),
|
||||||
|
("°", " degrés "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"de": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " und "),
|
||||||
|
("@", " at "),
|
||||||
|
("%", " prozent "),
|
||||||
|
("#", " raute "),
|
||||||
|
("$", " dollar "),
|
||||||
|
("£", " pfund "),
|
||||||
|
("°", " grad "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"pt": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " e "),
|
||||||
|
("@", " arroba "),
|
||||||
|
("%", " por cento "),
|
||||||
|
("#", " cardinal "),
|
||||||
|
("$", " dólar "),
|
||||||
|
("£", " libra "),
|
||||||
|
("°", " graus "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"it": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " e "),
|
||||||
|
("@", " chiocciola "),
|
||||||
|
("%", " per cento "),
|
||||||
|
("#", " cancelletto "),
|
||||||
|
("$", " dollaro "),
|
||||||
|
("£", " sterlina "),
|
||||||
|
("°", " gradi "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"pl": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " i "),
|
||||||
|
("@", " małpa "),
|
||||||
|
("%", " procent "),
|
||||||
|
("#", " krzyżyk "),
|
||||||
|
("$", " dolar "),
|
||||||
|
("£", " funt "),
|
||||||
|
("°", " stopnie "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ar": [
|
||||||
|
# Arabic
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " و "),
|
||||||
|
("@", " على "),
|
||||||
|
("%", " في المئة "),
|
||||||
|
("#", " رقم "),
|
||||||
|
("$", " دولار "),
|
||||||
|
("£", " جنيه "),
|
||||||
|
("°", " درجة "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"zh": [
|
||||||
|
# Chinese
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " 和 "),
|
||||||
|
("@", " 在 "),
|
||||||
|
("%", " 百分之 "),
|
||||||
|
("#", " 号 "),
|
||||||
|
("$", " 美元 "),
|
||||||
|
("£", " 英镑 "),
|
||||||
|
("°", " 度 "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"cs": [
|
||||||
|
# Czech
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " a "),
|
||||||
|
("@", " na "),
|
||||||
|
("%", " procento "),
|
||||||
|
("#", " křížek "),
|
||||||
|
("$", " dolar "),
|
||||||
|
("£", " libra "),
|
||||||
|
("°", " stupně "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ru": [
|
||||||
|
# Russian
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " и "),
|
||||||
|
("@", " собака "),
|
||||||
|
("%", " процентов "),
|
||||||
|
("#", " номер "),
|
||||||
|
("$", " доллар "),
|
||||||
|
("£", " фунт "),
|
||||||
|
("°", " градус "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"nl": [
|
||||||
|
# Dutch
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " en "),
|
||||||
|
("@", " bij "),
|
||||||
|
("%", " procent "),
|
||||||
|
("#", " hekje "),
|
||||||
|
("$", " dollar "),
|
||||||
|
("£", " pond "),
|
||||||
|
("°", " graden "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"tr": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " ve "),
|
||||||
|
("@", " at "),
|
||||||
|
("%", " yüzde "),
|
||||||
|
("#", " diyez "),
|
||||||
|
("$", " dolar "),
|
||||||
|
("£", " sterlin "),
|
||||||
|
("°", " derece "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"hu": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " és "),
|
||||||
|
("@", " kukac "),
|
||||||
|
("%", " százalék "),
|
||||||
|
("#", " kettőskereszt "),
|
||||||
|
("$", " dollár "),
|
||||||
|
("£", " font "),
|
||||||
|
("°", " fok "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ko": [
|
||||||
|
# Korean
|
||||||
|
(re.compile(r"%s" % re.escape(x[0]), re.IGNORECASE), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " 그리고 "),
|
||||||
|
("@", " 에 "),
|
||||||
|
("%", " 퍼센트 "),
|
||||||
|
("#", " 번호 "),
|
||||||
|
("$", " 달러 "),
|
||||||
|
("£", " 파운드 "),
|
||||||
|
("°", " 도 "),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"ja": [
|
||||||
|
(re.compile(r"%s" % re.escape(x[0])), x[1])
|
||||||
|
for x in [
|
||||||
|
("&", " と "),
|
||||||
|
("@", " アットマーク "),
|
||||||
|
("%", " パーセント "),
|
||||||
|
("#", " ナンバー "),
|
||||||
|
("$", " ドル "),
|
||||||
|
("£", " ポンド "),
|
||||||
|
("°", " 度"),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def expand_symbols_multilingual(text, lang="en"):
|
||||||
|
for regex, replacement in _symbols_multilingual[lang]:
|
||||||
|
text = re.sub(regex, replacement, text)
|
||||||
|
text = text.replace(" ", " ") # Ensure there are no double spaces
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
|
||||||
|
_ordinal_re = {
|
||||||
|
"en": re.compile(r"([0-9]+)(st|nd|rd|th)"),
|
||||||
|
"es": re.compile(r"([0-9]+)(º|ª|er|o|a|os|as)"),
|
||||||
|
"fr": re.compile(r"([0-9]+)(º|ª|er|re|e|ème)"),
|
||||||
|
"de": re.compile(r"([0-9]+)(st|nd|rd|th|º|ª|\.(?=\s|$))"),
|
||||||
|
"pt": re.compile(r"([0-9]+)(º|ª|o|a|os|as)"),
|
||||||
|
"it": re.compile(r"([0-9]+)(º|°|ª|o|a|i|e)"),
|
||||||
|
"pl": re.compile(r"([0-9]+)(º|ª|st|nd|rd|th)"),
|
||||||
|
"ar": re.compile(r"([0-9]+)(ون|ين|ث|ر|ى)"),
|
||||||
|
"cs": re.compile(r"([0-9]+)\.(?=\s|$)"), # In Czech, a dot is often used after the number to indicate ordinals.
|
||||||
|
"ru": re.compile(r"([0-9]+)(-й|-я|-е|-ое|-ье|-го)"),
|
||||||
|
"nl": re.compile(r"([0-9]+)(de|ste|e)"),
|
||||||
|
"tr": re.compile(r"([0-9]+)(\.|inci|nci|uncu|üncü|\.)"),
|
||||||
|
"hu": re.compile(r"([0-9]+)(\.|adik|edik|odik|edik|ödik|ödike|ik)"),
|
||||||
|
"ko": re.compile(r"([0-9]+)(번째|번|차|째)"),
|
||||||
|
"ja": re.compile(r"([0-9]+)(番|回|つ|目|等|位)")
|
||||||
|
}
|
||||||
|
_number_re = re.compile(r"[0-9]+")
|
||||||
|
_currency_re = {
|
||||||
|
"USD": re.compile(r"((\$[0-9\.\,]*[0-9]+)|([0-9\.\,]*[0-9]+\$))"),
|
||||||
|
"GBP": re.compile(r"((£[0-9\.\,]*[0-9]+)|([0-9\.\,]*[0-9]+£))"),
|
||||||
|
"EUR": re.compile(r"(([0-9\.\,]*[0-9]+€)|((€[0-9\.\,]*[0-9]+)))"),
|
||||||
|
}
|
||||||
|
|
||||||
|
_comma_number_re = re.compile(r"\b\d{1,3}(,\d{3})*(\.\d+)?\b")
|
||||||
|
_dot_number_re = re.compile(r"\b\d{1,3}(.\d{3})*(\,\d+)?\b")
|
||||||
|
_decimal_number_re = re.compile(r"([0-9]+[.,][0-9]+)")
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_commas(m):
|
||||||
|
text = m.group(0)
|
||||||
|
if "," in text:
|
||||||
|
text = text.replace(",", "")
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_dots(m):
|
||||||
|
text = m.group(0)
|
||||||
|
if "." in text:
|
||||||
|
text = text.replace(".", "")
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def _expand_decimal_point(m, lang="en"):
|
||||||
|
amount = m.group(1).replace(",", ".")
|
||||||
|
return num2words(float(amount), lang=lang if lang != "cs" else "cz")
|
||||||
|
|
||||||
|
|
||||||
|
def _expand_currency(m, lang="en", currency="USD"):
|
||||||
|
amount = float((re.sub(r"[^\d.]", "", m.group(0).replace(",", "."))))
|
||||||
|
full_amount = num2words(amount, to="currency", currency=currency, lang=lang if lang != "cs" else "cz")
|
||||||
|
|
||||||
|
and_equivalents = {
|
||||||
|
"en": ", ",
|
||||||
|
"es": " con ",
|
||||||
|
"fr": " et ",
|
||||||
|
"de": " und ",
|
||||||
|
"pt": " e ",
|
||||||
|
"it": " e ",
|
||||||
|
"pl": ", ",
|
||||||
|
"cs": ", ",
|
||||||
|
"ru": ", ",
|
||||||
|
"nl": ", ",
|
||||||
|
"ar": ", ",
|
||||||
|
"tr": ", ",
|
||||||
|
"hu": ", ",
|
||||||
|
"ko": ", ",
|
||||||
|
}
|
||||||
|
|
||||||
|
if amount.is_integer():
|
||||||
|
last_and = full_amount.rfind(and_equivalents[lang])
|
||||||
|
if last_and != -1:
|
||||||
|
full_amount = full_amount[:last_and]
|
||||||
|
|
||||||
|
return full_amount
|
||||||
|
|
||||||
|
|
||||||
|
def _expand_ordinal(m, lang="en"):
|
||||||
|
return num2words(int(m.group(1)), ordinal=True, lang=lang if lang != "cs" else "cz")
|
||||||
|
|
||||||
|
|
||||||
|
def _expand_number(m, lang="en"):
|
||||||
|
return num2words(int(m.group(0)), lang=lang if lang != "cs" else "cz")
|
||||||
|
|
||||||
|
|
||||||
|
def expand_numbers_multilingual(text, lang="en"):
|
||||||
|
if lang == "zh":
|
||||||
|
text = zh_num2words()(text)
|
||||||
|
else:
|
||||||
|
if lang in ["en", "ru"]:
|
||||||
|
text = re.sub(_comma_number_re, _remove_commas, text)
|
||||||
|
else:
|
||||||
|
text = re.sub(_dot_number_re, _remove_dots, text)
|
||||||
|
try:
|
||||||
|
text = re.sub(_currency_re["GBP"], lambda m: _expand_currency(m, lang, "GBP"), text)
|
||||||
|
text = re.sub(_currency_re["USD"], lambda m: _expand_currency(m, lang, "USD"), text)
|
||||||
|
text = re.sub(_currency_re["EUR"], lambda m: _expand_currency(m, lang, "EUR"), text)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if lang != "tr":
|
||||||
|
text = re.sub(_decimal_number_re, lambda m: _expand_decimal_point(m, lang), text)
|
||||||
|
text = re.sub(_ordinal_re[lang], lambda m: _expand_ordinal(m, lang), text)
|
||||||
|
text = re.sub(_number_re, lambda m: _expand_number(m, lang), text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def lowercase(text):
|
||||||
|
return text.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def collapse_whitespace(text):
|
||||||
|
return re.sub(_whitespace_re, " ", text)
|
||||||
|
|
||||||
|
|
||||||
|
def multilingual_cleaners(text, lang):
|
||||||
|
text = text.replace('"', "")
|
||||||
|
if lang == "tr":
|
||||||
|
text = text.replace("İ", "i")
|
||||||
|
text = text.replace("Ö", "ö")
|
||||||
|
text = text.replace("Ü", "ü")
|
||||||
|
text = lowercase(text)
|
||||||
|
text = expand_numbers_multilingual(text, lang)
|
||||||
|
text = expand_abbreviations_multilingual(text, lang)
|
||||||
|
text = expand_symbols_multilingual(text, lang=lang)
|
||||||
|
text = collapse_whitespace(text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def basic_cleaners(text):
|
||||||
|
"""Basic pipeline that lowercases and collapses whitespace without transliteration."""
|
||||||
|
text = lowercase(text)
|
||||||
|
text = collapse_whitespace(text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def chinese_transliterate(text):
|
||||||
|
return "".join(
|
||||||
|
[p[0] for p in pypinyin.pinyin(text, style=pypinyin.Style.TONE3, heteronym=False, neutral_tone_with_five=True)]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def japanese_cleaners(text, katsu):
|
||||||
|
text = katsu.romaji(text)
|
||||||
|
text = lowercase(text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def korean_transliterate(text):
|
||||||
|
r = Transliter(academic)
|
||||||
|
return r.translit(text)
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_VOCAB_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../data/tokenizer.json")
|
||||||
|
|
||||||
|
|
||||||
|
class VoiceBpeTokenizer:
|
||||||
|
def __init__(self, vocab_file=None):
|
||||||
|
self.tokenizer = None
|
||||||
|
if vocab_file is not None:
|
||||||
|
self.tokenizer = Tokenizer.from_file(vocab_file)
|
||||||
|
self.char_limits = {
|
||||||
|
"en": 250,
|
||||||
|
"de": 253,
|
||||||
|
"fr": 273,
|
||||||
|
"es": 239,
|
||||||
|
"it": 213,
|
||||||
|
"pt": 203,
|
||||||
|
"pl": 224,
|
||||||
|
"zh": 82,
|
||||||
|
"ar": 166,
|
||||||
|
"cs": 186,
|
||||||
|
"ru": 182,
|
||||||
|
"nl": 251,
|
||||||
|
"tr": 226,
|
||||||
|
"ja": 71,
|
||||||
|
"hu": 224,
|
||||||
|
"ko": 95,
|
||||||
|
}
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def katsu(self):
|
||||||
|
import cutlet
|
||||||
|
|
||||||
|
return cutlet.Cutlet()
|
||||||
|
|
||||||
|
def check_input_length(self, txt, lang):
|
||||||
|
lang = lang.split("-")[0] # remove the region
|
||||||
|
limit = self.char_limits.get(lang, 250)
|
||||||
|
if len(txt) > limit:
|
||||||
|
print(
|
||||||
|
f"[!] Warning: The text length exceeds the character limit of {limit} for language '{lang}', this might cause truncated audio."
|
||||||
|
)
|
||||||
|
|
||||||
|
def preprocess_text(self, txt, lang):
|
||||||
|
if lang in {"ar", "cs", "de", "en", "es", "fr", "hu", "it", "nl", "pl", "pt", "ru", "tr", "zh", "ko"}:
|
||||||
|
txt = multilingual_cleaners(txt, lang)
|
||||||
|
if lang == "zh":
|
||||||
|
txt = chinese_transliterate(txt)
|
||||||
|
if lang == "ko":
|
||||||
|
txt = korean_transliterate(txt)
|
||||||
|
elif lang == "ja":
|
||||||
|
txt = japanese_cleaners(txt, self.katsu)
|
||||||
|
elif lang == "hi":
|
||||||
|
# @manmay will implement this
|
||||||
|
txt = basic_cleaners(txt)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"Language '{lang}' is not supported.")
|
||||||
|
return txt
|
||||||
|
|
||||||
|
def encode(self, txt, lang):
|
||||||
|
lang = lang.split("-")[0] # remove the region
|
||||||
|
self.check_input_length(txt, lang)
|
||||||
|
txt = self.preprocess_text(txt, lang)
|
||||||
|
lang = "zh-cn" if lang == "zh" else lang
|
||||||
|
txt = f"[{lang}]{txt}"
|
||||||
|
txt = txt.replace(" ", "[SPACE]")
|
||||||
|
return self.tokenizer.encode(txt).ids
|
||||||
|
|
||||||
|
def decode(self, seq):
|
||||||
|
if isinstance(seq, torch.Tensor):
|
||||||
|
seq = seq.cpu().numpy()
|
||||||
|
txt = self.tokenizer.decode(seq, skip_special_tokens=False).replace(" ", "")
|
||||||
|
txt = txt.replace("[SPACE]", " ")
|
||||||
|
txt = txt.replace("[STOP]", "")
|
||||||
|
txt = txt.replace("[UNK]", "")
|
||||||
|
return txt
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return self.tokenizer.get_vocab_size()
|
||||||
|
|
||||||
|
def get_number_tokens(self):
|
||||||
|
return max(self.tokenizer.get_vocab().values()) + 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_expand_numbers_multilingual():
|
||||||
|
test_cases = [
|
||||||
|
# English
|
||||||
|
("In 12.5 seconds.", "In twelve point five seconds.", "en"),
|
||||||
|
("There were 50 soldiers.", "There were fifty soldiers.", "en"),
|
||||||
|
("This is a 1st test", "This is a first test", "en"),
|
||||||
|
("That will be $20 sir.", "That will be twenty dollars sir.", "en"),
|
||||||
|
("That will be 20€ sir.", "That will be twenty euro sir.", "en"),
|
||||||
|
("That will be 20.15€ sir.", "That will be twenty euro, fifteen cents sir.", "en"),
|
||||||
|
("That's 100,000.5.", "That's one hundred thousand point five.", "en"),
|
||||||
|
# French
|
||||||
|
("En 12,5 secondes.", "En douze virgule cinq secondes.", "fr"),
|
||||||
|
("Il y avait 50 soldats.", "Il y avait cinquante soldats.", "fr"),
|
||||||
|
("Ceci est un 1er test", "Ceci est un premier test", "fr"),
|
||||||
|
("Cela vous fera $20 monsieur.", "Cela vous fera vingt dollars monsieur.", "fr"),
|
||||||
|
("Cela vous fera 20€ monsieur.", "Cela vous fera vingt euros monsieur.", "fr"),
|
||||||
|
("Cela vous fera 20,15€ monsieur.", "Cela vous fera vingt euros et quinze centimes monsieur.", "fr"),
|
||||||
|
("Ce sera 100.000,5.", "Ce sera cent mille virgule cinq.", "fr"),
|
||||||
|
# German
|
||||||
|
("In 12,5 Sekunden.", "In zwölf Komma fünf Sekunden.", "de"),
|
||||||
|
("Es gab 50 Soldaten.", "Es gab fünfzig Soldaten.", "de"),
|
||||||
|
("Dies ist ein 1. Test", "Dies ist ein erste Test", "de"), # Issue with gender
|
||||||
|
("Das macht $20 Herr.", "Das macht zwanzig Dollar Herr.", "de"),
|
||||||
|
("Das macht 20€ Herr.", "Das macht zwanzig Euro Herr.", "de"),
|
||||||
|
("Das macht 20,15€ Herr.", "Das macht zwanzig Euro und fünfzehn Cent Herr.", "de"),
|
||||||
|
# Spanish
|
||||||
|
("En 12,5 segundos.", "En doce punto cinco segundos.", "es"),
|
||||||
|
("Había 50 soldados.", "Había cincuenta soldados.", "es"),
|
||||||
|
("Este es un 1er test", "Este es un primero test", "es"),
|
||||||
|
("Eso le costará $20 señor.", "Eso le costará veinte dólares señor.", "es"),
|
||||||
|
("Eso le costará 20€ señor.", "Eso le costará veinte euros señor.", "es"),
|
||||||
|
("Eso le costará 20,15€ señor.", "Eso le costará veinte euros con quince céntimos señor.", "es"),
|
||||||
|
# Italian
|
||||||
|
("In 12,5 secondi.", "In dodici virgola cinque secondi.", "it"),
|
||||||
|
("C'erano 50 soldati.", "C'erano cinquanta soldati.", "it"),
|
||||||
|
("Questo è un 1° test", "Questo è un primo test", "it"),
|
||||||
|
("Ti costerà $20 signore.", "Ti costerà venti dollari signore.", "it"),
|
||||||
|
("Ti costerà 20€ signore.", "Ti costerà venti euro signore.", "it"),
|
||||||
|
("Ti costerà 20,15€ signore.", "Ti costerà venti euro e quindici centesimi signore.", "it"),
|
||||||
|
# Portuguese
|
||||||
|
("Em 12,5 segundos.", "Em doze vírgula cinco segundos.", "pt"),
|
||||||
|
("Havia 50 soldados.", "Havia cinquenta soldados.", "pt"),
|
||||||
|
("Este é um 1º teste", "Este é um primeiro teste", "pt"),
|
||||||
|
("Isso custará $20 senhor.", "Isso custará vinte dólares senhor.", "pt"),
|
||||||
|
("Isso custará 20€ senhor.", "Isso custará vinte euros senhor.", "pt"),
|
||||||
|
(
|
||||||
|
"Isso custará 20,15€ senhor.",
|
||||||
|
"Isso custará vinte euros e quinze cêntimos senhor.",
|
||||||
|
"pt",
|
||||||
|
), # "cêntimos" should be "centavos" num2words issue
|
||||||
|
# Polish
|
||||||
|
("W 12,5 sekundy.", "W dwanaście przecinek pięć sekundy.", "pl"),
|
||||||
|
("Było 50 żołnierzy.", "Było pięćdziesiąt żołnierzy.", "pl"),
|
||||||
|
("To będzie kosztować 20€ panie.", "To będzie kosztować dwadzieścia euro panie.", "pl"),
|
||||||
|
("To będzie kosztować 20,15€ panie.", "To będzie kosztować dwadzieścia euro, piętnaście centów panie.", "pl"),
|
||||||
|
# Arabic
|
||||||
|
("في الـ 12,5 ثانية.", "في الـ اثنا عشر , خمسون ثانية.", "ar"),
|
||||||
|
("كان هناك 50 جنديًا.", "كان هناك خمسون جنديًا.", "ar"),
|
||||||
|
# ("ستكون النتيجة $20 يا سيد.", 'ستكون النتيجة عشرون دولار يا سيد.', 'ar'), # $ and € are mising from num2words
|
||||||
|
# ("ستكون النتيجة 20€ يا سيد.", 'ستكون النتيجة عشرون يورو يا سيد.', 'ar'),
|
||||||
|
# Czech
|
||||||
|
("Za 12,5 vteřiny.", "Za dvanáct celá pět vteřiny.", "cs"),
|
||||||
|
("Bylo tam 50 vojáků.", "Bylo tam padesát vojáků.", "cs"),
|
||||||
|
("To bude stát 20€ pane.", "To bude stát dvacet euro pane.", "cs"),
|
||||||
|
("To bude 20.15€ pane.", "To bude dvacet euro, patnáct centů pane.", "cs"),
|
||||||
|
# Russian
|
||||||
|
("Через 12.5 секунды.", "Через двенадцать запятая пять секунды.", "ru"),
|
||||||
|
("Там было 50 солдат.", "Там было пятьдесят солдат.", "ru"),
|
||||||
|
("Это будет 20.15€ сэр.", "Это будет двадцать евро, пятнадцать центов сэр.", "ru"),
|
||||||
|
("Это будет стоить 20€ господин.", "Это будет стоить двадцать евро господин.", "ru"),
|
||||||
|
# Dutch
|
||||||
|
("In 12,5 seconden.", "In twaalf komma vijf seconden.", "nl"),
|
||||||
|
("Er waren 50 soldaten.", "Er waren vijftig soldaten.", "nl"),
|
||||||
|
("Dat wordt dan $20 meneer.", "Dat wordt dan twintig dollar meneer.", "nl"),
|
||||||
|
("Dat wordt dan 20€ meneer.", "Dat wordt dan twintig euro meneer.", "nl"),
|
||||||
|
# Chinese (Simplified)
|
||||||
|
("在12.5秒内", "在十二点五秒内", "zh"),
|
||||||
|
("有50名士兵", "有五十名士兵", "zh"),
|
||||||
|
# ("那将是$20先生", '那将是二十美元先生', 'zh'), currency doesn't work
|
||||||
|
# ("那将是20€先生", '那将是二十欧元先生', 'zh'),
|
||||||
|
# Turkish
|
||||||
|
# ("12,5 saniye içinde.", 'On iki virgül beş saniye içinde.', 'tr'), # decimal doesn't work for TR
|
||||||
|
("50 asker vardı.", "elli asker vardı.", "tr"),
|
||||||
|
("Bu 1. test", "Bu birinci test", "tr"),
|
||||||
|
# ("Bu 100.000,5.", 'Bu yüz bin virgül beş.', 'tr'),
|
||||||
|
# Hungarian
|
||||||
|
("12,5 másodperc alatt.", "tizenkettő egész öt tized másodperc alatt.", "hu"),
|
||||||
|
("50 katona volt.", "ötven katona volt.", "hu"),
|
||||||
|
("Ez az 1. teszt", "Ez az első teszt", "hu"),
|
||||||
|
# Korean
|
||||||
|
("12.5 초 안에.", "십이 점 다섯 초 안에.", "ko"),
|
||||||
|
("50 명의 병사가 있었다.", "오십 명의 병사가 있었다.", "ko"),
|
||||||
|
("이것은 1 번째 테스트입니다", "이것은 첫 번째 테스트입니다", "ko"),
|
||||||
|
]
|
||||||
|
for a, b, lang in test_cases:
|
||||||
|
out = expand_numbers_multilingual(a, lang=lang)
|
||||||
|
assert out == b, f"'{out}' vs '{b}'"
|
||||||
|
|
||||||
|
|
||||||
|
def test_abbreviations_multilingual():
|
||||||
|
test_cases = [
|
||||||
|
# English
|
||||||
|
("Hello Mr. Smith.", "Hello mister Smith.", "en"),
|
||||||
|
("Dr. Jones is here.", "doctor Jones is here.", "en"),
|
||||||
|
# Spanish
|
||||||
|
("Hola Sr. Garcia.", "Hola señor Garcia.", "es"),
|
||||||
|
("La Dra. Martinez es muy buena.", "La doctora Martinez es muy buena.", "es"),
|
||||||
|
# French
|
||||||
|
("Bonjour Mr. Dupond.", "Bonjour monsieur Dupond.", "fr"),
|
||||||
|
("Mme. Moreau est absente aujourd'hui.", "madame Moreau est absente aujourd'hui.", "fr"),
|
||||||
|
# German
|
||||||
|
("Frau Dr. Müller ist sehr klug.", "Frau doktor Müller ist sehr klug.", "de"),
|
||||||
|
# Portuguese
|
||||||
|
("Olá Sr. Silva.", "Olá senhor Silva.", "pt"),
|
||||||
|
("Dra. Costa, você está disponível?", "doutora Costa, você está disponível?", "pt"),
|
||||||
|
# Italian
|
||||||
|
("Buongiorno, Sig. Rossi.", "Buongiorno, signore Rossi.", "it"),
|
||||||
|
# ("Sig.ra Bianchi, posso aiutarti?", 'signora Bianchi, posso aiutarti?', 'it'), # Issue with matching that pattern
|
||||||
|
# Polish
|
||||||
|
("Dzień dobry, P. Kowalski.", "Dzień dobry, pani Kowalski.", "pl"),
|
||||||
|
("M. Nowak, czy mogę zadać pytanie?", "pan Nowak, czy mogę zadać pytanie?", "pl"),
|
||||||
|
# Czech
|
||||||
|
("P. Novák", "pan Novák", "cs"),
|
||||||
|
("Dr. Vojtěch", "doktor Vojtěch", "cs"),
|
||||||
|
# Dutch
|
||||||
|
("Dhr. Jansen", "de heer Jansen", "nl"),
|
||||||
|
("Mevr. de Vries", "mevrouw de Vries", "nl"),
|
||||||
|
# Russian
|
||||||
|
("Здравствуйте Г-н Иванов.", "Здравствуйте господин Иванов.", "ru"),
|
||||||
|
("Д-р Смирнов здесь, чтобы увидеть вас.", "доктор Смирнов здесь, чтобы увидеть вас.", "ru"),
|
||||||
|
# Turkish
|
||||||
|
("Merhaba B. Yılmaz.", "Merhaba bay Yılmaz.", "tr"),
|
||||||
|
("Dr. Ayşe burada.", "doktor Ayşe burada.", "tr"),
|
||||||
|
# Hungarian
|
||||||
|
("Dr. Szabó itt van.", "doktor Szabó itt van.", "hu"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for a, b, lang in test_cases:
|
||||||
|
out = expand_abbreviations_multilingual(a, lang=lang)
|
||||||
|
assert out == b, f"'{out}' vs '{b}'"
|
||||||
|
|
||||||
|
|
||||||
|
def test_symbols_multilingual():
|
||||||
|
test_cases = [
|
||||||
|
("I have 14% battery", "I have 14 percent battery", "en"),
|
||||||
|
("Te veo @ la fiesta", "Te veo arroba la fiesta", "es"),
|
||||||
|
("J'ai 14° de fièvre", "J'ai 14 degrés de fièvre", "fr"),
|
||||||
|
("Die Rechnung beträgt £ 20", "Die Rechnung beträgt pfund 20", "de"),
|
||||||
|
("O meu email é ana&joao@gmail.com", "O meu email é ana e joao arroba gmail.com", "pt"),
|
||||||
|
("linguaggio di programmazione C#", "linguaggio di programmazione C cancelletto", "it"),
|
||||||
|
("Moja temperatura to 36.6°", "Moja temperatura to 36.6 stopnie", "pl"),
|
||||||
|
("Mám 14% baterie", "Mám 14 procento baterie", "cs"),
|
||||||
|
("Těším se na tebe @ party", "Těším se na tebe na party", "cs"),
|
||||||
|
("У меня 14% заряда", "У меня 14 процентов заряда", "ru"),
|
||||||
|
("Я буду @ дома", "Я буду собака дома", "ru"),
|
||||||
|
("Ik heb 14% batterij", "Ik heb 14 procent batterij", "nl"),
|
||||||
|
("Ik zie je @ het feest", "Ik zie je bij het feest", "nl"),
|
||||||
|
("لدي 14% في البطارية", "لدي 14 في المئة في البطارية", "ar"),
|
||||||
|
("我的电量为 14%", "我的电量为 14 百分之", "zh"),
|
||||||
|
("Pilim %14 dolu.", "Pilim yüzde 14 dolu.", "tr"),
|
||||||
|
("Az akkumulátorom töltöttsége 14%", "Az akkumulátorom töltöttsége 14 százalék", "hu"),
|
||||||
|
("배터리 잔량이 14%입니다.", "배터리 잔량이 14 퍼센트입니다.", "ko"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for a, b, lang in test_cases:
|
||||||
|
out = expand_symbols_multilingual(a, lang=lang)
|
||||||
|
assert out == b, f"'{out}' vs '{b}'"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_expand_numbers_multilingual()
|
||||||
|
test_abbreviations_multilingual()
|
||||||
|
test_symbols_multilingual()
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
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.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,7 +1,8 @@
|
|||||||
numpy>=1.22.0
|
numpy>=1.22.0
|
||||||
soundfile>=0.12.1
|
soundfile>=0.12.1
|
||||||
uvicorn>=0.24.0.post1
|
uvicorn>=0.24.0.post1
|
||||||
TTS>=0.21.3
|
transformers>=4.37.1
|
||||||
|
TTS>=0.22.0
|
||||||
torch>=2.1.0+cu118
|
torch>=2.1.0+cu118
|
||||||
torchaudio>=2.1.0+cu118
|
torchaudio>=2.1.0+cu118
|
||||||
fastapi>=0.104.1
|
fastapi>=0.104.1
|
||||||
@@ -13,3 +14,11 @@ packaging>=23.2
|
|||||||
pydantic>=1.10.13
|
pydantic>=1.10.13
|
||||||
sounddevice>=0.4.6
|
sounddevice>=0.4.6
|
||||||
python-multipart>=0.0.6
|
python-multipart>=0.0.6
|
||||||
|
cutlet>=0.3.0
|
||||||
|
unidic-lite>=1.0.8
|
||||||
|
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
|
||||||
@@ -0,0 +1,833 @@
|
|||||||
|
import { doExtrasFetch, getApiUrl, modules } from '../../extensions.js';
|
||||||
|
import { saveTtsProviderSettings } from './index.js';
|
||||||
|
|
||||||
|
export { AllTalkTtsProvider };
|
||||||
|
|
||||||
|
class AllTalkTtsProvider {
|
||||||
|
//########//
|
||||||
|
// Config //
|
||||||
|
//########//
|
||||||
|
|
||||||
|
settings = {};
|
||||||
|
constructor() {
|
||||||
|
// Initialize with default settings if they are not already set
|
||||||
|
this.settings = {
|
||||||
|
provider_endpoint: this.settings.provider_endpoint || 'http://localhost:7851',
|
||||||
|
language: this.settings.language || 'en',
|
||||||
|
voiceMap: this.settings.voiceMap || {},
|
||||||
|
at_generation_method: this.settings.at_generation_method || 'standard_generation',
|
||||||
|
narrator_enabled: this.settings.narrator_enabled || 'false',
|
||||||
|
at_narrator_text_not_inside: this.settings.at_narrator_text_not_inside || 'narrator',
|
||||||
|
narrator_voice_gen: this.settings.narrator_voice_gen || 'female_01.wav',
|
||||||
|
finetuned_model: this.settings.finetuned_model || 'false'
|
||||||
|
};
|
||||||
|
// Separate property for dynamically updated settings from the server
|
||||||
|
this.dynamicSettings = {
|
||||||
|
modelsAvailable: [],
|
||||||
|
currentModel: '',
|
||||||
|
deepspeed_available: false,
|
||||||
|
deepSpeedEnabled: false,
|
||||||
|
lowVramEnabled: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ready = false;
|
||||||
|
voices = [];
|
||||||
|
separator = '. ';
|
||||||
|
audioElement = document.createElement('audio');
|
||||||
|
|
||||||
|
languageLabels = {
|
||||||
|
'Arabic': 'ar',
|
||||||
|
'Brazilian Portuguese': 'pt',
|
||||||
|
'Chinese': 'zh-cn',
|
||||||
|
'Czech': 'cs',
|
||||||
|
'Dutch': 'nl',
|
||||||
|
'English': 'en',
|
||||||
|
'French': 'fr',
|
||||||
|
'German': 'de',
|
||||||
|
'Italian': 'it',
|
||||||
|
'Polish': 'pl',
|
||||||
|
'Russian': 'ru',
|
||||||
|
'Spanish': 'es',
|
||||||
|
'Turkish': 'tr',
|
||||||
|
'Japanese': 'ja',
|
||||||
|
'Korean': 'ko',
|
||||||
|
'Hungarian': 'hu',
|
||||||
|
'Hindi': 'hi',
|
||||||
|
};
|
||||||
|
|
||||||
|
get settingsHtml() {
|
||||||
|
let html = `<div class="at-settings-separator">AllTalk Settings</div>`;
|
||||||
|
|
||||||
|
html += `<div class="at-settings-row">
|
||||||
|
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="at_generation_method">AllTalk TTS Generation Method</label>
|
||||||
|
<select id="at_generation_method">
|
||||||
|
<option value="standard_generation">Standard Audio Generation (AT Narrator - Optional)</option>
|
||||||
|
<option value="streaming_enabled">Streaming Audio Generation (AT Narrator - Disabled)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
html += `<div class="at-settings-row">
|
||||||
|
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="at_narrator_enabled">AT Narrator</label>
|
||||||
|
<select id="at_narrator_enabled">
|
||||||
|
<option value="true">Enabled</option>
|
||||||
|
<option value="false">Disabled</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="at_narrator_text_not_inside">Text Not Inside * or " is</label>
|
||||||
|
<select id="at_narrator_text_not_inside">
|
||||||
|
<option value="narrator">Narrator</option>
|
||||||
|
<option value="character">Character</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
html += `<div class="at-settings-row">
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="narrator_voice">Narrator Voice</label>
|
||||||
|
<select id="narrator_voice">`;
|
||||||
|
if (this.voices) {
|
||||||
|
for (let voice of this.voices) {
|
||||||
|
html += `<option value="${voice.voice_id}">${voice.name}</option>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += `</select>
|
||||||
|
</div>
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="language_options">Language</label>
|
||||||
|
<select id="language_options">`;
|
||||||
|
for (let language in this.languageLabels) {
|
||||||
|
html += `<option value="${this.languageLabels[language]}" ${this.languageLabels[language] === this.settings?.language ? 'selected="selected"' : ''}>${language}</option>`;
|
||||||
|
}
|
||||||
|
html += `</select>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
|
||||||
|
html += `<div class="at-model-endpoint-row">
|
||||||
|
<div class="at-model-option">
|
||||||
|
<label for="switch_model">Switch Model</label>
|
||||||
|
<select id="switch_model">
|
||||||
|
<option value="api_tts">API TTS</option>
|
||||||
|
<option value="api_local">API Local</option>
|
||||||
|
<option value="xttsv2_local">XTTSv2 Local</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="at-endpoint-option">
|
||||||
|
<label for="at_server">AllTalk Endpoint:</label>
|
||||||
|
<input id="at_server" type="text" class="text_pole" maxlength="80" value="${this.settings.provider_endpoint}"/>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
|
||||||
|
html += `<div class="at-model-endpoint-row">
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="low_vram">Low VRAM</label>
|
||||||
|
<input id="low_vram" type="checkbox"/>
|
||||||
|
</div>
|
||||||
|
<div class="at-settings-option">
|
||||||
|
<label for="deepspeed">DeepSpeed</label>
|
||||||
|
<input id="deepspeed" type="checkbox"/>
|
||||||
|
</div>
|
||||||
|
<div class="at-settings-option status-option">
|
||||||
|
<span>Status: <span id="status_info">Ready</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="at-settings-option empty-option">
|
||||||
|
<!-- This div remains empty for spacing -->
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
|
||||||
|
html += `<div class="at-website-row">
|
||||||
|
<div class="at-website-option">
|
||||||
|
<span>AllTalk <a target="_blank" href="${this.settings.provider_endpoint}">Config & Docs</a>.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="at-website-option">
|
||||||
|
<span>AllTalk <a target="_blank" href="https://github.com/erew123/alltalk_tts/">Website</a>.</span>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
html += `<div class="at-website-row">
|
||||||
|
<div class="at-website-option">
|
||||||
|
<span><strong>Text-generation-webui</strong> users - Uncheck <strong>Enable TTS</strong> in Text-generation-webui.</span>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#################//
|
||||||
|
// Startup ST & AT //
|
||||||
|
//#################//
|
||||||
|
|
||||||
|
async loadSettings(settings) {
|
||||||
|
updateStatus('Offline');
|
||||||
|
|
||||||
|
if (Object.keys(settings).length === 0) {
|
||||||
|
console.info('Using default AllTalk TTS Provider settings');
|
||||||
|
} else {
|
||||||
|
// Populate settings with provided values, ignoring server-provided settings
|
||||||
|
for (const key in settings) {
|
||||||
|
if (key in this.settings) {
|
||||||
|
this.settings[key] = settings[key];
|
||||||
|
} else {
|
||||||
|
console.debug(`Ignoring non-user-configurable setting: ${key}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update UI elements to reflect the loaded settings
|
||||||
|
$('#at_server').val(this.settings.provider_endpoint);
|
||||||
|
$('#language_options').val(this.settings.language);
|
||||||
|
//$('#voicemap').val(this.settings.voiceMap);
|
||||||
|
$('#at_generation_method').val(this.settings.at_generation_method);
|
||||||
|
$('#at_narrator_enabled').val(this.settings.narrator_enabled);
|
||||||
|
$('#at_narrator_text_not_inside').val(this.settings.at_narrator_text_not_inside);
|
||||||
|
$('#narrator_voice').val(this.settings.narrator_voice_gen);
|
||||||
|
|
||||||
|
console.debug('AllTalkTTS: Settings loaded');
|
||||||
|
try {
|
||||||
|
// Check if TTS provider is ready
|
||||||
|
await this.checkReady();
|
||||||
|
await this.updateSettingsFromServer(); // Fetch dynamic settings from the TTS server
|
||||||
|
await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready
|
||||||
|
this.updateNarratorVoicesDropdown();
|
||||||
|
this.updateLanguageDropdown();
|
||||||
|
this.setupEventListeners();
|
||||||
|
this.applySettingsToHTML();
|
||||||
|
updateStatus('Ready');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading settings:", error);
|
||||||
|
updateStatus('Offline');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applySettingsToHTML() {
|
||||||
|
// Apply loaded settings or use defaults
|
||||||
|
const narratorVoiceSelect = document.getElementById('narrator_voice');
|
||||||
|
const atNarratorSelect = document.getElementById('at_narrator_enabled');
|
||||||
|
const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
|
||||||
|
const generationMethodSelect = document.getElementById('at_generation_method');
|
||||||
|
this.settings.narrator_voice = this.settings.narrator_voice_gen;
|
||||||
|
// Apply settings to Narrator Voice dropdown
|
||||||
|
if (narratorVoiceSelect && this.settings.narrator_voice) {
|
||||||
|
narratorVoiceSelect.value = this.settings.narrator_voice.replace('.wav', '');
|
||||||
|
}
|
||||||
|
// Apply settings to AT Narrator Enabled dropdown
|
||||||
|
if (atNarratorSelect) {
|
||||||
|
// Sync the state with the checkbox in index.js
|
||||||
|
const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks'); // Access the checkbox from index.js
|
||||||
|
const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted'); // Access the checkbox from index.js
|
||||||
|
const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js
|
||||||
|
// Sync the state with the checkbox in index.js
|
||||||
|
if (this.settings.narrator_enabled) {
|
||||||
|
ttsPassAsterisksCheckbox.checked = false;
|
||||||
|
$('#tts_pass_asterisks').click(); // Simulate a click event
|
||||||
|
$('#tts_pass_asterisks').trigger('change');
|
||||||
|
}
|
||||||
|
if (!this.settings.narrator_enabled) {
|
||||||
|
ttsPassAsterisksCheckbox.checked = true;
|
||||||
|
$('#tts_pass_asterisks').click(); // Simulate a click event
|
||||||
|
$('#tts_pass_asterisks').trigger('change');
|
||||||
|
}
|
||||||
|
// Uncheck and set tts_narrate_quoted to false if narrator is enabled
|
||||||
|
if (this.settings.narrator_enabledd) {
|
||||||
|
ttsNarrateQuotedCheckbox.checked = true;
|
||||||
|
ttsNarrateDialoguesCheckbox.checked = true;
|
||||||
|
// Trigger click events instead of change events
|
||||||
|
$('#tts_narrate_quoted').click();
|
||||||
|
$('#tts_narrate_quoted').trigger('change');
|
||||||
|
$('#tts_narrate_dialogues').click();
|
||||||
|
$('#tts_narrate_dialogues').trigger('change');
|
||||||
|
}
|
||||||
|
atNarratorSelect.value = this.settings.narrator_enabled.toString();
|
||||||
|
this.settings.narrator_enabled = this.settings.narrator_enabled.toString();
|
||||||
|
}
|
||||||
|
// Apply settings to the Language dropdown
|
||||||
|
const languageSelect = document.getElementById('language_options');
|
||||||
|
if (languageSelect && this.settings.language) {
|
||||||
|
languageSelect.value = this.settings.language;
|
||||||
|
}
|
||||||
|
// Apply settings to Text Not Inside dropdown
|
||||||
|
if (textNotInsideSelect && this.settings.text_not_inside) {
|
||||||
|
textNotInsideSelect.value = this.settings.text_not_inside;
|
||||||
|
this.settings.at_narrator_text_not_inside = this.settings.text_not_inside;
|
||||||
|
}
|
||||||
|
// Apply settings to Generation Method dropdown
|
||||||
|
if (generationMethodSelect && this.settings.at_generation_method) {
|
||||||
|
generationMethodSelect.value = this.settings.at_generation_method;
|
||||||
|
}
|
||||||
|
// Additional logic to disable/enable dropdowns based on the selected generation method
|
||||||
|
const isStreamingEnabled = this.settings.at_generation_method === 'streaming_enabled';
|
||||||
|
if (isStreamingEnabled) {
|
||||||
|
// Disable certain dropdowns when streaming is enabled
|
||||||
|
if (atNarratorSelect) atNarratorSelect.disabled = true;
|
||||||
|
if (textNotInsideSelect) textNotInsideSelect.disabled = true;
|
||||||
|
if (narratorVoiceSelect) narratorVoiceSelect.disabled = true;
|
||||||
|
} else {
|
||||||
|
// Enable dropdowns for standard generation
|
||||||
|
if (atNarratorSelect) atNarratorSelect.disabled = false;
|
||||||
|
if (textNotInsideSelect) textNotInsideSelect.disabled = !this.settings.narrator_enabled;
|
||||||
|
if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
|
||||||
|
}
|
||||||
|
const modelSelect = document.getElementById('switch_model');
|
||||||
|
if (this.settings.finetuned_model === 'true') {
|
||||||
|
const ftOption = document.createElement('option');
|
||||||
|
ftOption.value = 'XTTSv2 FT';
|
||||||
|
ftOption.textContent = 'XTTSv2 FT';
|
||||||
|
modelSelect.appendChild(ftOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//##############################//
|
||||||
|
// Check AT Server is Available //
|
||||||
|
//##############################//
|
||||||
|
|
||||||
|
async checkReady() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/ready`);
|
||||||
|
// Check if the HTTP request was successful
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
const statusText = await response.text();
|
||||||
|
// Check if the response is 'Ready'
|
||||||
|
if (statusText === 'Ready') {
|
||||||
|
this.ready = true; // Set the ready flag to true
|
||||||
|
console.log('TTS service is ready.');
|
||||||
|
} else {
|
||||||
|
this.ready = false;
|
||||||
|
console.log('TTS service is not ready.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error checking TTS service readiness:', error);
|
||||||
|
this.ready = false; // Ensure ready flag is set to false in case of error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//######################//
|
||||||
|
// Get Available Voices //
|
||||||
|
//######################//
|
||||||
|
|
||||||
|
async fetchTtsVoiceObjects() {
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/voices`);
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
const voices = data.voices.map(filename => {
|
||||||
|
const voiceName = filename.replace('.wav', '');
|
||||||
|
return {
|
||||||
|
name: voiceName,
|
||||||
|
voice_id: voiceName,
|
||||||
|
preview_url: null, // Preview URL will be dynamically generated
|
||||||
|
lang: 'en' // Default language
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.voices = voices; // Assign to the class property
|
||||||
|
return voices; // Also return this list
|
||||||
|
}
|
||||||
|
|
||||||
|
//##########################################//
|
||||||
|
// Get Current AT Server Config & Update ST //
|
||||||
|
//##########################################//
|
||||||
|
|
||||||
|
async updateSettingsFromServer() {
|
||||||
|
try {
|
||||||
|
// Fetch current settings
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/currentsettings`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch current settings: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
const currentSettings = await response.json();
|
||||||
|
// Update internal settings
|
||||||
|
this.settings.modelsAvailable = currentSettings.models_available;
|
||||||
|
this.settings.currentModel = currentSettings.current_model_loaded;
|
||||||
|
this.settings.deepspeed_available = currentSettings.deepspeed_available;
|
||||||
|
this.settings.deepSpeedEnabled = currentSettings.deepspeed_status;
|
||||||
|
this.settings.lowVramEnabled = currentSettings.low_vram_status;
|
||||||
|
this.settings.finetuned_model = currentSettings.finetuned_model
|
||||||
|
// Update HTML elements
|
||||||
|
this.updateModelDropdown();
|
||||||
|
this.updateCheckboxes();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error updating settings from server: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//###################################################//
|
||||||
|
// Get Current AT Server Config & Update ST (Models) //
|
||||||
|
//###################################################//
|
||||||
|
|
||||||
|
updateModelDropdown() {
|
||||||
|
const modelSelect = document.getElementById('switch_model');
|
||||||
|
if (modelSelect) {
|
||||||
|
modelSelect.innerHTML = ''; // Clear existing options
|
||||||
|
this.settings.modelsAvailable.forEach(model => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = model.model_name;
|
||||||
|
option.textContent = model.model_name; // Use model_name instead of name
|
||||||
|
option.selected = model.model_name === this.settings.currentModel;
|
||||||
|
modelSelect.appendChild(option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#######################################################//
|
||||||
|
// Get Current AT Server Config & Update ST (DS and LVR) //
|
||||||
|
//#######################################################//
|
||||||
|
|
||||||
|
updateCheckboxes() {
|
||||||
|
const deepspeedCheckbox = document.getElementById('deepspeed');
|
||||||
|
const lowVramCheckbox = document.getElementById('low_vram');
|
||||||
|
if (lowVramCheckbox) lowVramCheckbox.checked = this.settings.lowVramEnabled;
|
||||||
|
if (deepspeedCheckbox) {
|
||||||
|
deepspeedCheckbox.checked = this.settings.deepSpeedEnabled;
|
||||||
|
deepspeedCheckbox.disabled = !this.settings.deepspeed_available; // Disable checkbox if deepspeed is not available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//###############################################################//
|
||||||
|
// Get Current AT Server Config & Update ST (AT Narrator Voices) //
|
||||||
|
//###############################################################//
|
||||||
|
|
||||||
|
updateNarratorVoicesDropdown() {
|
||||||
|
const narratorVoiceSelect = document.getElementById('narrator_voice');
|
||||||
|
if (narratorVoiceSelect && this.voices) {
|
||||||
|
// Clear existing options
|
||||||
|
narratorVoiceSelect.innerHTML = '';
|
||||||
|
// Add new options
|
||||||
|
for (let voice of this.voices) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = voice.voice_id;
|
||||||
|
option.textContent = voice.name;
|
||||||
|
narratorVoiceSelect.appendChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//######################################################//
|
||||||
|
// Get Current AT Server Config & Update ST (Languages) //
|
||||||
|
//######################################################//
|
||||||
|
|
||||||
|
updateLanguageDropdown() {
|
||||||
|
const languageSelect = document.getElementById('language_options');
|
||||||
|
if (languageSelect) {
|
||||||
|
// Ensure default language is set
|
||||||
|
this.settings.language = this.settings.language;
|
||||||
|
|
||||||
|
languageSelect.innerHTML = '';
|
||||||
|
for (let language in this.languageLabels) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = this.languageLabels[language];
|
||||||
|
option.textContent = language;
|
||||||
|
if (this.languageLabels[language] === this.settings.language) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
languageSelect.appendChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//########################################//
|
||||||
|
// Start AT TTS extenstion page listeners //
|
||||||
|
//########################################//
|
||||||
|
|
||||||
|
setupEventListeners() {
|
||||||
|
|
||||||
|
let debounceTimeout;
|
||||||
|
const debounceDelay = 500; // Milliseconds
|
||||||
|
|
||||||
|
// Define the event handler function
|
||||||
|
const onModelSelectChange = async (event) => {
|
||||||
|
console.log("Model select change event triggered"); // Debugging statement
|
||||||
|
const selectedModel = event.target.value;
|
||||||
|
console.log(`Selected model: ${selectedModel}`); // Debugging statement
|
||||||
|
// Set status to Processing
|
||||||
|
updateStatus('Processing');
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/reload?tts_method=${encodeURIComponent(selectedModel)}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP Error: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("POST response data:", data); // Debugging statement
|
||||||
|
// Set status to Ready if successful
|
||||||
|
updateStatus('Ready');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("POST request error:", error); // Debugging statement
|
||||||
|
// Set status to Error in case of failure
|
||||||
|
updateStatus('Error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle response or error
|
||||||
|
};
|
||||||
|
|
||||||
|
const debouncedModelSelectChange = (event) => {
|
||||||
|
clearTimeout(debounceTimeout);
|
||||||
|
debounceTimeout = setTimeout(() => {
|
||||||
|
onModelSelectChange(event);
|
||||||
|
}, debounceDelay);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Switch Model Listener
|
||||||
|
const modelSelect = document.getElementById('switch_model');
|
||||||
|
if (modelSelect) {
|
||||||
|
// Remove the event listener if it was previously added
|
||||||
|
modelSelect.removeEventListener('change', debouncedModelSelectChange);
|
||||||
|
// Add the debounced event listener
|
||||||
|
modelSelect.addEventListener('change', debouncedModelSelectChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepSpeed Listener
|
||||||
|
const deepspeedCheckbox = document.getElementById('deepspeed');
|
||||||
|
if (deepspeedCheckbox) {
|
||||||
|
deepspeedCheckbox.addEventListener('change', async (event) => {
|
||||||
|
const deepSpeedValue = event.target.checked ? 'True' : 'False';
|
||||||
|
// Set status to Processing
|
||||||
|
updateStatus('Processing');
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/deepspeed?new_deepspeed_value=${deepSpeedValue}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP Error: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("POST response data:", data); // Debugging statement
|
||||||
|
// Set status to Ready if successful
|
||||||
|
updateStatus('Ready');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("POST request error:", error); // Debugging statement
|
||||||
|
// Set status to Error in case of failure
|
||||||
|
updateStatus('Error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low VRAM Listener
|
||||||
|
const lowVramCheckbox = document.getElementById('low_vram');
|
||||||
|
if (lowVramCheckbox) {
|
||||||
|
lowVramCheckbox.addEventListener('change', async (event) => {
|
||||||
|
const lowVramValue = event.target.checked ? 'True' : 'False';
|
||||||
|
// Set status to Processing
|
||||||
|
updateStatus('Processing');
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/lowvramsetting?new_low_vram_value=${lowVramValue}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP Error: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("POST response data:", data); // Debugging statement
|
||||||
|
// Set status to Ready if successful
|
||||||
|
updateStatus('Ready');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("POST request error:", error); // Debugging statement
|
||||||
|
// Set status to Error in case of failure
|
||||||
|
updateStatus('Error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Narrator Voice Dropdown Listener
|
||||||
|
const narratorVoiceSelect = document.getElementById('narrator_voice');
|
||||||
|
if (narratorVoiceSelect) {
|
||||||
|
narratorVoiceSelect.addEventListener('change', (event) => {
|
||||||
|
this.settings.narrator_voice_gen = `${event.target.value}.wav`;
|
||||||
|
this.onSettingsChange(); // Save the settings after change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
|
||||||
|
if (textNotInsideSelect) {
|
||||||
|
textNotInsideSelect.addEventListener('change', (event) => {
|
||||||
|
this.settings.text_not_inside = event.target.value;
|
||||||
|
this.onSettingsChange(); // Save the settings after change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// AT Narrator Dropdown Listener
|
||||||
|
const atNarratorSelect = document.getElementById('at_narrator_enabled');
|
||||||
|
const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks'); // Access the checkbox from index.js
|
||||||
|
const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted'); // Access the checkbox from index.js
|
||||||
|
const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js
|
||||||
|
|
||||||
|
if (atNarratorSelect && textNotInsideSelect && narratorVoiceSelect) {
|
||||||
|
atNarratorSelect.addEventListener('change', (event) => {
|
||||||
|
const isNarratorEnabled = event.target.value === 'true';
|
||||||
|
this.settings.narrator_enabled = isNarratorEnabled; // Update the setting here
|
||||||
|
textNotInsideSelect.disabled = !isNarratorEnabled;
|
||||||
|
narratorVoiceSelect.disabled = !isNarratorEnabled;
|
||||||
|
|
||||||
|
// Sync the state with the checkbox in index.js
|
||||||
|
if (isNarratorEnabled) {
|
||||||
|
ttsPassAsterisksCheckbox.checked = false;
|
||||||
|
$('#tts_pass_asterisks').click(); // Simulate a click event
|
||||||
|
$('#tts_pass_asterisks').trigger('change');
|
||||||
|
}
|
||||||
|
if (!isNarratorEnabled) {
|
||||||
|
ttsPassAsterisksCheckbox.checked = true;
|
||||||
|
$('#tts_pass_asterisks').click(); // Simulate a click event
|
||||||
|
$('#tts_pass_asterisks').trigger('change');
|
||||||
|
}
|
||||||
|
// Uncheck and set tts_narrate_quoted to false if narrator is enabled
|
||||||
|
if (isNarratorEnabled) {
|
||||||
|
ttsNarrateQuotedCheckbox.checked = true;
|
||||||
|
ttsNarrateDialoguesCheckbox.checked = true;
|
||||||
|
// Trigger click events instead of change events
|
||||||
|
$('#tts_narrate_quoted').click();
|
||||||
|
$('#tts_narrate_quoted').trigger('change');
|
||||||
|
$('#tts_narrate_dialogues').click();
|
||||||
|
$('#tts_narrate_dialogues').trigger('change');
|
||||||
|
}
|
||||||
|
this.onSettingsChange(); // Save the settings after change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Event Listener for AT Generation Method Dropdown
|
||||||
|
const atGenerationMethodSelect = document.getElementById('at_generation_method');
|
||||||
|
const atNarratorEnabledSelect = document.getElementById('at_narrator_enabled');
|
||||||
|
if (atGenerationMethodSelect) {
|
||||||
|
atGenerationMethodSelect.addEventListener('change', (event) => {
|
||||||
|
const selectedMethod = event.target.value;
|
||||||
|
|
||||||
|
if (selectedMethod === 'streaming_enabled') {
|
||||||
|
// Disable and unselect AT Narrator
|
||||||
|
atNarratorEnabledSelect.disabled = true;
|
||||||
|
atNarratorEnabledSelect.value = 'false';
|
||||||
|
textNotInsideSelect.disabled = true;
|
||||||
|
narratorVoiceSelect.disabled = true;
|
||||||
|
} else if (selectedMethod === 'standard_generation') {
|
||||||
|
// Enable AT Narrator
|
||||||
|
atNarratorEnabledSelect.disabled = false;
|
||||||
|
}
|
||||||
|
this.settings.at_generation_method = selectedMethod; // Update the setting here
|
||||||
|
this.onSettingsChange(); // Save the settings after change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listener for Language Dropdown
|
||||||
|
const languageSelect = document.getElementById('language_options');
|
||||||
|
if (languageSelect) {
|
||||||
|
languageSelect.addEventListener('change', (event) => {
|
||||||
|
this.settings.language = event.target.value;
|
||||||
|
this.onSettingsChange(); // Save the settings after change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listener for AllTalk Endpoint Input
|
||||||
|
const atServerInput = document.getElementById('at_server');
|
||||||
|
if (atServerInput) {
|
||||||
|
atServerInput.addEventListener('input', (event) => {
|
||||||
|
this.settings.provider_endpoint = event.target.value;
|
||||||
|
this.onSettingsChange(); // Save the settings after change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//#############################//
|
||||||
|
// Store ST interface settings //
|
||||||
|
//#############################//
|
||||||
|
|
||||||
|
onSettingsChange() {
|
||||||
|
// Update settings based on the UI elements
|
||||||
|
//this.settings.provider_endpoint = $('#at_server').val();
|
||||||
|
this.settings.language = $('#language_options').val();
|
||||||
|
//this.settings.voiceMap = $('#voicemap').val();
|
||||||
|
this.settings.at_generation_method = $('#at_generation_method').val();
|
||||||
|
this.settings.narrator_enabled = $('#at_narrator_enabled').val();
|
||||||
|
this.settings.at_narrator_text_not_inside = $('#at_narrator_text_not_inside').val();
|
||||||
|
this.settings.narrator_voice_gen = $('#narrator_voice').val();
|
||||||
|
// Save the updated settings
|
||||||
|
saveTtsProviderSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#########################//
|
||||||
|
// ST Handle Reload button //
|
||||||
|
//#########################//
|
||||||
|
|
||||||
|
async onRefreshClick() {
|
||||||
|
await this.checkReady(); // Check if the TTS provider is ready
|
||||||
|
await this.loadSettings(this.settings); // Reload the settings
|
||||||
|
// Additional actions as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################//
|
||||||
|
// Preview AT Voice //
|
||||||
|
//##################//
|
||||||
|
|
||||||
|
async previewTtsVoice(voiceName) {
|
||||||
|
try {
|
||||||
|
// Prepare data for POST request
|
||||||
|
const postData = new URLSearchParams();
|
||||||
|
postData.append("voice", `${voiceName}.wav`);
|
||||||
|
// Making the POST request
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/api/previewvoice/`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: postData,
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
console.error(`[previewTtsVoice] Error Response Text:`, errorText);
|
||||||
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
||||||
|
}
|
||||||
|
// Assuming the server returns a URL to the .wav file
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.output_file_url) {
|
||||||
|
// Use an audio element to play the .wav file
|
||||||
|
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");
|
||||||
|
throw new Error("No output file URL received in the response");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[previewTtsVoice] Exception caught during preview generation:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#####################//
|
||||||
|
// Populate ST voices //
|
||||||
|
//#####################//
|
||||||
|
|
||||||
|
async getVoice(voiceName, generatePreview = false) {
|
||||||
|
// Ensure this.voices is populated
|
||||||
|
if (this.voices.length === 0) {
|
||||||
|
// Fetch voice objects logic
|
||||||
|
}
|
||||||
|
// Find the object where the name matches voiceName
|
||||||
|
const match = this.voices.find(voice => voice.name === voiceName);
|
||||||
|
if (!match) {
|
||||||
|
// Error handling
|
||||||
|
}
|
||||||
|
// Generate preview URL only if requested
|
||||||
|
if (!match.preview_url && generatePreview) {
|
||||||
|
// Generate preview logic
|
||||||
|
}
|
||||||
|
return match; // Return the found voice object
|
||||||
|
}
|
||||||
|
|
||||||
|
//##########################################//
|
||||||
|
// Generate TTS Streaming or call Standard //
|
||||||
|
//##########################################//
|
||||||
|
|
||||||
|
async generateTts(inputText, voiceId) {
|
||||||
|
try {
|
||||||
|
if (this.settings.at_generation_method === 'streaming_enabled') {
|
||||||
|
// Construct the streaming URL
|
||||||
|
const streamingUrl = `${this.settings.provider_endpoint}/api/tts-generate-streaming?text=${encodeURIComponent(inputText)}&voice=${encodeURIComponent(voiceId)}.wav&language=${encodeURIComponent(this.settings.language)}&output_file=stream_output.wav`;
|
||||||
|
console.log("Streaming URL:", streamingUrl);
|
||||||
|
|
||||||
|
// Return the streaming URL directly
|
||||||
|
return streamingUrl;
|
||||||
|
} else {
|
||||||
|
// For standard method
|
||||||
|
const outputUrl = await this.fetchTtsGeneration(inputText, voiceId);
|
||||||
|
const audioResponse = await fetch(outputUrl);
|
||||||
|
if (!audioResponse.ok) {
|
||||||
|
throw new Error(`HTTP ${audioResponse.status}: Failed to fetch audio data`);
|
||||||
|
}
|
||||||
|
return audioResponse; // Return the fetch response directly
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in generateTts:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//####################//
|
||||||
|
// Generate Standard //
|
||||||
|
//####################//
|
||||||
|
|
||||||
|
async fetchTtsGeneration(inputText, voiceId) {
|
||||||
|
// Prepare the request payload
|
||||||
|
const requestBody = new URLSearchParams({
|
||||||
|
'text_input': inputText,
|
||||||
|
'text_filtering': "standard",
|
||||||
|
'character_voice_gen': voiceId + ".wav",
|
||||||
|
'narrator_enabled': this.settings.narrator_enabled,
|
||||||
|
'narrator_voice_gen': this.settings.narrator_voice_gen + ".wav",
|
||||||
|
'text_not_inside': this.settings.at_narrator_text_not_inside,
|
||||||
|
'language': this.settings.language,
|
||||||
|
'output_file_name': "st_output",
|
||||||
|
'output_file_timestamp': "true",
|
||||||
|
'autoplay': "false",
|
||||||
|
'autoplay_volume': "0.8"
|
||||||
|
}).toString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await doExtrasFetch(
|
||||||
|
`${this.settings.provider_endpoint}/api/tts-generate`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
},
|
||||||
|
body: requestBody
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
console.error(`[fetchTtsGeneration] Error Response Text:`, errorText);
|
||||||
|
// toastr.error(response.statusText, 'TTS Generation Failed');
|
||||||
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
const outputUrl = data.output_file_url;
|
||||||
|
return outputUrl; // Return only the output_file_url
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[fetchTtsGeneration] Exception caught:", error);
|
||||||
|
throw error; // Rethrow the error for further handling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#########################//
|
||||||
|
// Update Status Messages //
|
||||||
|
//#########################//
|
||||||
|
|
||||||
|
function updateStatus(message) {
|
||||||
|
const statusElement = document.getElementById('status_info');
|
||||||
|
if (statusElement) {
|
||||||
|
statusElement.textContent = message;
|
||||||
|
switch (message) {
|
||||||
|
case 'Offline':
|
||||||
|
statusElement.style.color = 'red';
|
||||||
|
break;
|
||||||
|
case 'Ready':
|
||||||
|
statusElement.style.color = 'lightgreen';
|
||||||
|
break;
|
||||||
|
case 'Processing':
|
||||||
|
statusElement.style.color = 'blue';
|
||||||
|
break;
|
||||||
|
case 'Error':
|
||||||
|
statusElement.style.color = 'red';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import platform
|
||||||
|
import site
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
# version 0.8
|
||||||
|
|
||||||
|
def find_files_in_path_with_wildcard(pattern):
|
||||||
|
# Get the site-packages directory of the current Python environment
|
||||||
|
site_packages_path = site.getsitepackages()
|
||||||
|
found_paths = []
|
||||||
|
# Adjust the sub-directory based on the operating system
|
||||||
|
sub_directory = "nvidia/cublas"
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
sub_directory = os.path.join(sub_directory, "lib")
|
||||||
|
else:
|
||||||
|
sub_directory = os.path.join(sub_directory, "bin")
|
||||||
|
|
||||||
|
# Iterate over each site-packages directory (there can be more than one)
|
||||||
|
for directory in site_packages_path:
|
||||||
|
# Construct the search directory path
|
||||||
|
search_directory = os.path.join(directory, sub_directory)
|
||||||
|
# Use glob to find all files matching the pattern in this directory
|
||||||
|
for file_path in glob.glob(os.path.join(search_directory, pattern)):
|
||||||
|
if os.path.isfile(file_path): # Ensure it's a file
|
||||||
|
found_paths.append(file_path)
|
||||||
|
return found_paths
|
||||||
|
|
||||||
|
def detect_cublas():
|
||||||
|
# Use different file patterns based on the operating system
|
||||||
|
file_name_pattern = 'cublas64_11.*' if platform.system() == "Windows" else 'libcublas.so.11*'
|
||||||
|
found_paths = find_files_in_path_with_wildcard(file_name_pattern)
|
||||||
|
if found_paths:
|
||||||
|
print("[AllTalk TTSDiff] \033[94mCublas:\033[0m \033[92mDetected\033[0m", found_paths)
|
||||||
|
else:
|
||||||
|
print("[AllTalk TTSDiff] \033[94mCublas:\033[0m \033[91mERROR Not Detected\033[0m")
|
||||||
|
print("[AllTalk TTSDiff] \033[94mPlease install Cublas from the Nvidia CUDA Toolkit \033[0mhttps://developer.nvidia.com/cuda-downloads")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Compare TTS output with the original text using detailed comparison.")
|
||||||
|
parser.add_argument("--threshold", type=int, default=98, help="Similarity threshold for considering a match (default: 98)")
|
||||||
|
parser.add_argument("--ttslistpath", help="Path to the ttsList.json file")
|
||||||
|
parser.add_argument("--wavfilespath", help="Path to the wav outputs folder")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not args.ttslistpath:
|
||||||
|
parser.error("[AllTalk TTSDiff] Please specify the path to the ttslist.json file using the --ttslistpath argument.")
|
||||||
|
if not args.wavfilespath:
|
||||||
|
parser.error("[AllTalk TTSDiff] Please specify the path to the wavs output folder file using the --wavfilespath argument.")
|
||||||
|
|
||||||
|
json_file_path = Path(args.ttslistpath).resolve()
|
||||||
|
wav_file_path = Path(args.wavfilespath).resolve()
|
||||||
|
accuracy_threshold = args.threshold
|
||||||
|
|
||||||
|
def disclaimer_text():
|
||||||
|
print(f"\nDESCRIPTION: ")
|
||||||
|
print(f" This script is designed to assist in identifying bad TTS generation ID's from the TTS Generator.\n")
|
||||||
|
print(f" This will download the Whisper Large-v2 model (if not already downloaded), and use it to compare your text to")
|
||||||
|
print(f" to the generated TTS. If it finds an issue, it will flag the ID number that has the issue. This does NOT 100%")
|
||||||
|
print(f" ensure that all TTS generated is perfect, sounds good etc, but it should flag up glaring issues and help with")
|
||||||
|
print(f" the process of identifying bad TTS generations.")
|
||||||
|
print(f"\nNOTES ON USE: ")
|
||||||
|
print(f" - Ensure AllTalk is running in its own command prompt/terminal.")
|
||||||
|
print(f" - This script should be running in its own command prompt/terminal window in the same Python Environment that")
|
||||||
|
print(f" AllTalk is running in.")
|
||||||
|
print(f" - After generating your text in the TTS Generator, you need to `Export List to JSON` and save the file in the")
|
||||||
|
print(f" same folder/directory this script is running from.")
|
||||||
|
print(f" - You can use `--threshold` with a numerical value from 1 to 100 to set accuracy detection. For example it may")
|
||||||
|
print(f" detect/transcribe `their` as `there`, which of course, both words sound the same. If you want 100% accuracy")
|
||||||
|
print(f" you will set 100 as the threshold. You will more than likely want a number in the high 90's. Default is set")
|
||||||
|
print(f" at 98, which gives a little flexibility.")
|
||||||
|
print(f" - The JSON file must be named \033[93mttsList.json\033[0m")
|
||||||
|
print(f" - When you have your ID list, go back into the TTS Generator, correct any lines and regenerate them. If you")
|
||||||
|
print(f" want to re-test everthing again after re-generating, you will need to export your list again and re-run this")
|
||||||
|
print(f" script again, against your newly exported JSON list.")
|
||||||
|
print(f" - This requires access to \033[93mcublas64_11\033[0m, the same as Finetuning.")
|
||||||
|
print(f" https://github.com/erew123/alltalk_tts/tree/main?#-important-requirements-cuda-118\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from faster_whisper import WhisperModel
|
||||||
|
import re
|
||||||
|
import string
|
||||||
|
import spacy
|
||||||
|
import torch
|
||||||
|
from fuzzywuzzy import fuzz
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"[AllTalk TTSDiff] ERROR STARTING SCRIPT:")
|
||||||
|
print("[AllTalk TTSDiff] An error occurred importing one or more required libraries.")
|
||||||
|
print("[AllTalk TTSDiff] Please ensure you have \033[94mactivated your Python environment \033[0mand \033[94minstalled all requirements.\033[0m")
|
||||||
|
print("[AllTalk TTSDiff] \033[94mMissing library:\033[93m", str(e), "\033[0m")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Attempt to load the spaCy model
|
||||||
|
try:
|
||||||
|
# Load a medium-sized spaCy model, adjust to "en_core_web_md" or "en_core_web_lg" as needed
|
||||||
|
nlp = spacy.load("en_core_web_md")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[AllTalk TTSDiff] ERROR STARTING SCRIPT:")
|
||||||
|
print("[AllTalk TTSDiff] Failed to load the spaCy language model.")
|
||||||
|
|
||||||
|
# Attempt to download the spaCy model automatically
|
||||||
|
try:
|
||||||
|
print("[AllTalk TTSDiff] Attempting to automatically download the spaCy language model...")
|
||||||
|
subprocess.run([sys.executable, "-m", "spacy", "download", "en_core_web_md"], check=True)
|
||||||
|
|
||||||
|
# Try to load the model again after downloading
|
||||||
|
nlp = spacy.load("en_core_web_md")
|
||||||
|
print("[AllTalk TTSDiff] Model downloaded and loaded successfully.")
|
||||||
|
except Exception as download_exception:
|
||||||
|
print("[AllTalk TTSDiff] Automatic download failed.")
|
||||||
|
print("[AllTalk TTSDiff] Please manually install the spaCy language model by running:")
|
||||||
|
print("[AllTalk TTSDiff] \033[93mpython -m spacy download en_core_web_md\033[0m")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def texts_are_similar(text1, text2, threshold=0.8):
|
||||||
|
# Preliminary check for short texts
|
||||||
|
if len(text1) < 10 or len(text2) < 10:
|
||||||
|
ratio = fuzz.ratio(text1, text2) / 100.0 # Use FuzzyWuzzy for short texts
|
||||||
|
return ratio > threshold
|
||||||
|
|
||||||
|
# Process the texts through the NLP model for longer texts
|
||||||
|
doc1 = nlp(text1)
|
||||||
|
doc2 = nlp(text2)
|
||||||
|
|
||||||
|
# Compute semantic similarity
|
||||||
|
similarity = doc1.similarity(doc2)
|
||||||
|
|
||||||
|
return similarity >= threshold
|
||||||
|
|
||||||
|
def normalize_text(text):
|
||||||
|
# Normalize or remove CRLF and other non-standard whitespaces
|
||||||
|
text = text.replace("\r\n", " ").replace("\n", " ").replace("\r", " ")
|
||||||
|
|
||||||
|
# Convert to lowercase
|
||||||
|
text = text.lower()
|
||||||
|
|
||||||
|
# Standardize and then remove quotation marks
|
||||||
|
text = text.replace("“", '"').replace("”", '"').replace("‘", "'").replace("’", "'")
|
||||||
|
text = text.translate(str.maketrans('', '', '"\''))
|
||||||
|
|
||||||
|
# Remove all other punctuation except hyphens to preserve compound words
|
||||||
|
text = text.translate(str.maketrans('', '', string.punctuation.replace("-", "")))
|
||||||
|
|
||||||
|
# Collapse any sequence of whitespace (including spaces) into a single space
|
||||||
|
text = re.sub(r'\s+', ' ', text)
|
||||||
|
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
spoken_punctuation_mapping = {
|
||||||
|
"dot": ".",
|
||||||
|
"comma": ",",
|
||||||
|
# Add more mappings as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
def contains_spoken_punctuation(transcribed_text):
|
||||||
|
for spoken, punctuation in spoken_punctuation_mapping.items():
|
||||||
|
if spoken in transcribed_text:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def detailed_comparison(original_text, transcribed_text, threshold=98):
|
||||||
|
original_clean = normalize_text(original_text)
|
||||||
|
transcribed_clean = normalize_text(transcribed_text)
|
||||||
|
ratio = fuzz.ratio(original_clean, transcribed_clean)
|
||||||
|
return ratio > threshold
|
||||||
|
|
||||||
|
def access_local_file(url):
|
||||||
|
# Extract the file name from the URL
|
||||||
|
file_name = url.split('/')[-1]
|
||||||
|
# Construct the full path to the file on disk
|
||||||
|
file_path = wav_file_path / file_name
|
||||||
|
# Check if the file exists
|
||||||
|
if not file_path.exists():
|
||||||
|
print(f"[AllTalk TTSDiff] File does not exist: {file_path}")
|
||||||
|
return None
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
def transcribe_and_compare(file_url, original_text, model, item_id, flagged_ids):
|
||||||
|
audio_file_path = access_local_file(file_url)
|
||||||
|
if audio_file_path is None:
|
||||||
|
print(f"[AllTalk TTSDiff] Could not access local file for URL: {file_url}")
|
||||||
|
return # Skip this file if it can't be accessed
|
||||||
|
|
||||||
|
try:
|
||||||
|
segments, info = model.transcribe(str(audio_file_path), beam_size=5)
|
||||||
|
transcribed_text = " ".join([segment.text for segment in segments])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[AllTalk TTSDiff] Error transcribing file {audio_file_path}: {e}")
|
||||||
|
return # Skip this file if transcription fails
|
||||||
|
|
||||||
|
segments, info = model.transcribe(str(audio_file_path), beam_size=5)
|
||||||
|
transcribed_text = " ".join([segment.text for segment in segments])
|
||||||
|
|
||||||
|
# Normalize texts for comparison
|
||||||
|
original_text_normalized = normalize_text(original_text)
|
||||||
|
transcribed_text_normalized = normalize_text(transcribed_text)
|
||||||
|
|
||||||
|
# Enhanced comparison using detailed fuzzy matching
|
||||||
|
is_detailed_match = detailed_comparison(original_text_normalized, transcribed_text_normalized, args.threshold)
|
||||||
|
has_spoken_punctuation = contains_spoken_punctuation(transcribed_text_normalized) and not contains_spoken_punctuation(original_text_normalized)
|
||||||
|
|
||||||
|
# Adjust is_match based on detailed comparison and spoken punctuation check
|
||||||
|
is_match = is_detailed_match and not has_spoken_punctuation
|
||||||
|
|
||||||
|
# Only log and flag IDs for review if there's a mismatch or detected issues
|
||||||
|
if not is_match:
|
||||||
|
#print(f"\033[93mMismatch Detected - ID:\033[0m {item_id}")
|
||||||
|
print(f"[AllTalk TTSDiff] \033[93mText:\033[0m {original_text}")
|
||||||
|
print(f"[AllTalk TTSDiff] \033[91mTTS :\033[0m{transcribed_text}")
|
||||||
|
if has_spoken_punctuation:
|
||||||
|
print(f"[AllTalk TTSDiff] Note: Potential incorrect spoken punctuation detected.")
|
||||||
|
flagged_ids.append(item_id) # Track the ID for review
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"[AllTalk TTSDiff]")
|
||||||
|
print(f"[AllTalk TTSDiff]")
|
||||||
|
print("[AllTalk TTSDiff] \033[92mStarting Compare of Text vs TTS:\033[0m")
|
||||||
|
print("[AllTalk TTSDiff]")
|
||||||
|
print("[AllTalk TTSDiff] \033[94mJSON file :\033[92m", json_file_path, "\033[0m")
|
||||||
|
print("[AllTalk TTSDiff] \033[94mWAV files :\033[92m", wav_file_path, "\033[0m")
|
||||||
|
print("[AllTalk TTSDiff] \033[94mAccuracy :\033[92m", accuracy_threshold, "%", "\033[0m")
|
||||||
|
detect_cublas()
|
||||||
|
model_size = "large-v2"
|
||||||
|
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||||
|
model = WhisperModel(model_size, device=device, compute_type="float32")
|
||||||
|
|
||||||
|
flagged_ids = [] # Initialize the list to track IDs needing review
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||||
|
tts_list = json.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"[AllTalk TTSDiff] ERROR STARTING SCRIPT:")
|
||||||
|
print("[AllTalk TTSDiff] Error: \033[93mttsList.json\033[0m file not found.")
|
||||||
|
print("[AllTalk TTSDiff] Please ensure you follow these steps:")
|
||||||
|
print("[AllTalk TTSDiff] After generating your text in the TTS Generator, you need to `Export List to JSON` and save the file in the")
|
||||||
|
print("[AllTalk TTSDiff] same folder/directory this script is running from.")
|
||||||
|
print("[AllTalk TTSDiff] The JSON file must be named \033[93mttsList.json\033[0m")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print(f"[AllTalk TTSDiff]")
|
||||||
|
|
||||||
|
for item in tts_list:
|
||||||
|
print(f"[AllTalk TTSDiff] Processing ID: {item['id']}")
|
||||||
|
transcribe_and_compare(item['fileUrl'], item['text'], model, item['id'], flagged_ids)
|
||||||
|
|
||||||
|
print(f"[AllTalk TTSDiff]")
|
||||||
|
# Print summary information at the end
|
||||||
|
if flagged_ids:
|
||||||
|
print(f"[AllTalk TTSDiff] \033[94mIDs needing review:\033[0m", ', '.join(map(str, flagged_ids)))
|
||||||
|
print(f"[AllTalk TTSDiff]")
|
||||||
|
print(f"[AllTalk TTSDiff] Review ID's and correct any lines by editing & regenerating as necessary.")
|
||||||
|
else:
|
||||||
|
print("[AllTalk TTSDiff] \033[94mIDs needing review:\033[0m No issues detected.")
|
||||||
|
summary_data = {
|
||||||
|
"flagged_ids": flagged_ids
|
||||||
|
}
|
||||||
|
with open(wav_file_path / "analysis_summary.json", "w") as summary_file:
|
||||||
|
json.dump(summary_data, summary_file)
|
||||||
|
print("[AllTalk TTSDiff]")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
export interface CrunkerConstructorOptions {
|
||||||
|
/**
|
||||||
|
* Sample rate for Crunker's internal audio context.
|
||||||
|
*
|
||||||
|
* @default 44100
|
||||||
|
*/
|
||||||
|
sampleRate: number;
|
||||||
|
}
|
||||||
|
export type CrunkerInputTypes = string | File | Blob;
|
||||||
|
/**
|
||||||
|
* An exported Crunker audio object.
|
||||||
|
*/
|
||||||
|
export interface ExportedCrunkerAudio {
|
||||||
|
blob: Blob;
|
||||||
|
url: string;
|
||||||
|
element: HTMLAudioElement;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Crunker is the simple way to merge, concatenate, play, export and download audio files using the Web Audio API.
|
||||||
|
*/
|
||||||
|
export default class Crunker {
|
||||||
|
private readonly _sampleRate;
|
||||||
|
private readonly _context;
|
||||||
|
/**
|
||||||
|
* Creates a new instance of Crunker with the provided options.
|
||||||
|
*
|
||||||
|
* If `sampleRate` is not defined, it will auto-select an appropriate sample rate
|
||||||
|
* for the device being used.
|
||||||
|
*/
|
||||||
|
constructor({ sampleRate }?: Partial<CrunkerConstructorOptions>);
|
||||||
|
/**
|
||||||
|
* Creates Crunker's internal AudioContext.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _createContext;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The internal AudioContext used by Crunker.
|
||||||
|
*/
|
||||||
|
get context(): AudioContext;
|
||||||
|
/**
|
||||||
|
* Asynchronously fetches multiple audio files and returns an array of AudioBuffers.
|
||||||
|
*/
|
||||||
|
fetchAudio(...filepaths: CrunkerInputTypes[]): Promise<AudioBuffer[]>;
|
||||||
|
/**
|
||||||
|
* Merges (layers) multiple AudioBuffers into a single AudioBuffer.
|
||||||
|
*
|
||||||
|
* **Visual representation:**
|
||||||
|
*
|
||||||
|
* 
|
||||||
|
*/
|
||||||
|
mergeAudio(buffers: AudioBuffer[]): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Concatenates multiple AudioBuffers into a single AudioBuffer.
|
||||||
|
*
|
||||||
|
* **Visual representation:**
|
||||||
|
*
|
||||||
|
* 
|
||||||
|
*/
|
||||||
|
concatAudio(buffers: AudioBuffer[]): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Pads a specified AudioBuffer with silence from a specified start time,
|
||||||
|
* for a specified length of time.
|
||||||
|
*
|
||||||
|
* Accepts float values as well as whole integers.
|
||||||
|
*
|
||||||
|
* @param buffer AudioBuffer to pad
|
||||||
|
* @param padStart Time to start padding (in seconds)
|
||||||
|
* @param seconds Duration to pad for (in seconds)
|
||||||
|
*/
|
||||||
|
padAudio(buffer: AudioBuffer, padStart?: number, seconds?: number): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Slices an AudioBuffer from the specified start time to the end time, with optional fade in and out.
|
||||||
|
*
|
||||||
|
* @param buffer AudioBuffer to slice
|
||||||
|
* @param start Start time (in seconds)
|
||||||
|
* @param end End time (in seconds)
|
||||||
|
* @param fadeIn Fade in duration (in seconds, default is 0)
|
||||||
|
* @param fadeOut Fade out duration (in seconds, default is 0)
|
||||||
|
*/
|
||||||
|
sliceAudio(buffer: AudioBuffer, start: number, end: number, fadeIn?: number, fadeOut?: number): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Plays the provided AudioBuffer in an AudioBufferSourceNode.
|
||||||
|
*/
|
||||||
|
play(buffer: AudioBuffer): AudioBufferSourceNode;
|
||||||
|
/**
|
||||||
|
* Exports the specified AudioBuffer to a Blob, Object URI and HTMLAudioElement.
|
||||||
|
*
|
||||||
|
* Note that changing the MIME type does not change the actual file format. The
|
||||||
|
* file format will **always** be a WAVE file due to how audio is stored in the
|
||||||
|
* browser.
|
||||||
|
*
|
||||||
|
* @param buffer Buffer to export
|
||||||
|
* @param type MIME type (default: `audio/wav`)
|
||||||
|
*/
|
||||||
|
export(buffer: AudioBuffer, type?: string): ExportedCrunkerAudio;
|
||||||
|
/**
|
||||||
|
* Downloads the provided Blob.
|
||||||
|
*
|
||||||
|
* @param blob Blob to download
|
||||||
|
* @param filename An optional file name to use for the download (default: `crunker`)
|
||||||
|
*/
|
||||||
|
download(blob: Blob, filename?: string): HTMLAnchorElement;
|
||||||
|
/**
|
||||||
|
* Executes a callback if the browser does not support the Web Audio API.
|
||||||
|
*
|
||||||
|
* Returns the result of the callback, or `undefined` if the Web Audio API is supported.
|
||||||
|
*
|
||||||
|
* @param callback callback to run if the browser does not support the Web Audio API
|
||||||
|
*/
|
||||||
|
notSupported<T>(callback: () => T): T | undefined;
|
||||||
|
/**
|
||||||
|
* Closes Crunker's internal AudioContext.
|
||||||
|
*/
|
||||||
|
close(): this;
|
||||||
|
/**
|
||||||
|
* Returns the largest duration of the longest AudioBuffer.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _maxDuration;
|
||||||
|
/**
|
||||||
|
* Returns the largest number of channels in an array of AudioBuffers.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _maxNumberOfChannels;
|
||||||
|
/**
|
||||||
|
* Returns the sum of the lengths of an array of AudioBuffers.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _totalLength;
|
||||||
|
/**
|
||||||
|
* Returns whether the browser supports the Web Audio API.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _isSupported;
|
||||||
|
/**
|
||||||
|
* Writes the WAV headers for the specified Float32Array.
|
||||||
|
*
|
||||||
|
* Returns a DataView containing the WAV headers and file content.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _writeHeaders;
|
||||||
|
/**
|
||||||
|
* Converts a Float32Array to 16-bit PCM.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _floatTo16BitPCM;
|
||||||
|
/**
|
||||||
|
* Writes a string to a DataView at the specified offset.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _writeString;
|
||||||
|
/**
|
||||||
|
* Converts an AudioBuffer to a Float32Array.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _interleave;
|
||||||
|
/**
|
||||||
|
* Creates an HTMLAudioElement whose source is the specified Blob.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _renderAudioElement;
|
||||||
|
/**
|
||||||
|
* Creates an Object URL for the specified Blob.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _renderURL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
var e={d:(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};function n(e){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(e)}function r(e){return function(e){if(Array.isArray(e))return a(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return a(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return a(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,(o=a.key,i=void 0,i=function(e,t){if("object"!==n(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var a=r.call(e,t||"default");if("object"!==n(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(o,"string"),"symbol"===n(i)?i:String(i)),a)}var o,i}e.d(t,{Z:()=>u});var u=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.sampleRate;o(this,e),this._context=this._createContext(n),n||(n=this._context.sampleRate),this._sampleRate=n}var t,n,a;return t=e,n=[{key:"_createContext",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:44100;return window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext,new AudioContext({sampleRate:e})}},{key:"context",get:function(){return this._context}},{key:"fetchAudio",value:async function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return await Promise.all(n.map((async function(t){var n;return n=t instanceof File||t instanceof Blob?await t.arrayBuffer():await fetch(t).then((function(e){return e.headers.has("Content-Type")&&!e.headers.get("Content-Type").includes("audio/")&&console.warn("Crunker: Attempted to fetch an audio file, but its MIME type is `".concat(e.headers.get("Content-Type").split(";")[0],"`. We'll try and continue anyway. (file: \"").concat(t,'")')),e.arrayBuffer()})),await e._context.decodeAudioData(n)})))}},{key:"mergeAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._sampleRate*this._maxDuration(e),this._sampleRate);return e.forEach((function(e){for(var n=0;n<e.numberOfChannels;n++){for(var r=t.getChannelData(n),a=e.getChannelData(n),o=e.getChannelData(n).length-1;o>=0;o--)r[o]+=a[o];t.getChannelData(n).set(r)}})),t}},{key:"concatAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._totalLength(e),this._sampleRate),n=0;return e.forEach((function(e){for(var r=0;r<e.numberOfChannels;r++)t.getChannelData(r).set(e.getChannelData(r),n);n+=e.length})),t}},{key:"padAudio",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(0===n)return e;if(t<0)throw new Error('Crunker: Parameter "padStart" in padAudio must be positive');if(n<0)throw new Error('Crunker: Parameter "seconds" in padAudio must be positive');for(var r=this._context.createBuffer(e.numberOfChannels,Math.ceil(e.length+n*e.sampleRate),e.sampleRate),a=0;a<e.numberOfChannels;a++){var o=e.getChannelData(a);r.getChannelData(a).set(o.subarray(0,Math.ceil(t*e.sampleRate)+1),0),r.getChannelData(a).set(o.subarray(Math.ceil(t*e.sampleRate)+2,r.length+1),Math.ceil((t+n)*e.sampleRate))}return r}},{key:"sliceAudio",value:function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0;if(t>=n)throw new Error('Crunker: "start" time should be less than "end" time in sliceAudio method');for(var o=Math.round((n-t)*this._sampleRate),i=Math.round(t*this._sampleRate),u=this._context.createBuffer(e.numberOfChannels,o,this._sampleRate),l=0;l<e.numberOfChannels;l++)for(var s=e.getChannelData(l),c=u.getChannelData(l),f=0;f<o;f++)c[f]=s[i+f],f<r*this._sampleRate&&(c[f]*=f/(r*this._sampleRate)),f>o-a*this._sampleRate&&(c[f]*=(o-f)/(a*this._sampleRate));return u}},{key:"play",value:function(e){var t=this._context.createBufferSource();return t.buffer=e,t.connect(this._context.destination),t.start(),Line truncated
|
||||||
|
//# sourceMappingURL=crunker.esm.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"crunker.esm.js","mappings":"AACA,IAAIA,EAAsB,CCA1BA,EAAwB,CAACC,EAASC,KACjC,IAAI,IAAIC,KAAOD,EACXF,EAAoBI,EAAEF,EAAYC,KAASH,EAAoBI,EAAEH,EAASE,IAC5EE,OAAOC,eAAeL,EAASE,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,IAE1E,ECNDH,EAAwB,CAACS,EAAKC,IAAUL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,I,8jDCoBlF,IAGqBI,EAAO,WAU1B,aAAqE,6DAAJ,CAAC,EAApDC,EAAU,EAAVA,WAAU,UACtBC,KAAKC,SAAWD,KAAKE,eAAeH,GAEpCA,IAAAA,EAAeC,KAAKC,SAASF,YAE7BC,KAAKG,YAAcJ,CACrB,C,UA6YC,O,EA3YD,E,EAAA,6BAKA,WAAkE,IAA3CA,EAAqB,UAAH,6CAAG,MAE1C,OADAK,OAAOC,aAAeD,OAAOC,cAAiBD,OAAeE,oBAAuBF,OAAeG,gBAC5F,IAAIF,aAAa,CAAEN,WAAAA,GAC5B,GAEA,mBAIA,WACE,OAAOC,KAAKC,QACd,GAEA,wBAGAO,iBAA4E,kCAAxDC,EAAS,yBAATA,EAAS,gBAC3B,aAAaC,QAAQC,IACnBF,EAAUG,KAAIJ,eAAOK,GACnB,IAAIC,EAkBJ,OAfEA,EADED,aAAoBE,MAAQF,aAAoBG,WACnCH,EAASI,oBAETC,MAAML,GAAUM,MAAK,SAACC,GASnC,OARIA,EAASC,QAAQC,IAAI,kBAAoBF,EAASC,QAAQ7B,IAAI,gBAAiB+B,SAAS,WAC1FC,QAAQC,KAAK,oEAAD,OAERL,EAASC,QAAQ7B,IAAI,gBAAiBkC,MAAM,KAAK,GAAE,sDACPb,EAAQ,OAInDO,EAASH,aAClB,UAGW,EAAKhB,SAAS0B,gBAAgBb,EAC7C,IAEJ,GAEA,wBAOA,SAAWc,GACT,IAAMC,EAAS7B,KAAKC,SAAS6B,aAC3B9B,KAAK+B,qBAAqBH,GAC1B5B,KAAKG,YAAcH,KAAKgC,aAAaJ,GACrC5B,KAAKG,aAgBP,OAbAyB,EAAQK,SAAQ,SAACnB,GACf,IAAK,IAAIoB,EAAgB,EAAGA,EAAgBpB,EAAOqB,iBAAkBD,IAAiB,CAIpF,IAHA,IAAME,EAAaP,EAAOQ,eAAeH,GACnCI,EAAaxB,EAAOuB,eAAeH,GAEhCK,EAAIzB,EAAOuB,eAAeH,GAAeM,OAAS,EAAGD,GAAK,EAAGA,IACpEH,EAAWG,IAAMD,EAAWC,GAG9BV,EAAOQ,eAAeH,GAAeO,IAAIL,EAC3C,CACF,IAEOP,CACT,GAEA,yBAOA,SAAYD,GACV,IAAMC,EAAS7B,KAAKC,SAAS6B,aAC3B9B,KAAK+B,qBAAqBH,GAC1B5B,KAAK0C,aAAad,GAClB5B,KAAKG,aAEHwC,EAAS,EAUb,OARAf,EAAQK,SAAQ,SAACnB,GACf,IAAK,IAAIoB,EAAgB,EAAGA,EAAgBpB,EAAOqB,iBAAkBD,IACnEL,EAAOQ,eAAeH,GAAeO,IAAI3B,EAAOuB,eAAeH,GAAgBS,GAGjFA,GAAU7B,EAAO0B,MACnB,IAEOX,CACT,GAEA,sBAUA,SAASf,GAA6E,IAAxD8B,EAAmB,UAAH,6CAAG,EAAGC,EAAkB,UAAH,6CAAG,EACpE,GAAgB,IAAZA,EAAe,OAAO/B,EAE1B,GAAI8B,EAAW,EAAG,MAAM,IAAIE,MAAM,8DAClC,GAAID,EAAU,EAAG,MAAM,IAAIC,MAAM,6DAQjC,IANA,IAAMC,EAAgB/C,KAAKC,SAAS6B,aAClChB,EAAOqB,iBACPa,KAAKC,KAAKnC,EAAO0B,OAASK,EAAU/B,EAAOf,YAC3Ce,EAAOf,YAGAmC,EAAgB,EAAGA,EAAgBpB,EAAOqB,iBAAkBD,IAAiB,CACpF,IAAMgB,EAAcpC,EAAOuB,eAAeH,GAC1Ca,EACGV,eAAeH,GACfO,IAAIS,EAAYC,SAAS,EAAGH,KAAKC,KAAKL,EAAW9B,EAAOf,YAAc,GAAI,GAE7EgD,EACGV,eAAeH,GACfO,IACCS,EAAYC,SAASH,KAAKC,KAAKL,EAAW9B,EAAOf,YAAc,EAAGgD,EAAcP,OAAS,GACzFQ,KAAKC,MAAML,EAAWC,GAAW/B,EAAOf,YAE9C,CAEA,OAAOgD,CACT,GAEA,wBASA,SAAWjC,EAAqBsC,EAAeC,GAAmE,IAAtDC,EAAiB,UAAH,6CAAG,EAAGC,EAAkB,UAAH,6CAAG,EAChG,GAAIH,GAASC,EAAK,MAAM,IAAIP,MAAM,6EAMlC,IAJA,IAAMN,EAASQ,KAAKQ,OAAOH,EAAMD,GAASpD,KAAKG,aACzCwC,EAASK,KAAKQ,MAAMJ,EAAQpD,KAAKG,aACjCsD,EAAYzD,KAAKC,SAAS6B,aAAahB,EAAOqB,iBAAkBK,EAAQxC,KAAKG,aAE1EuD,EAAU,EAAGA,EAAU5C,EAAOqB,iBAAkBuB,IAIvD,IAHA,IAAMC,EAAY7C,EAAOuB,eAAeqB,GAClCtB,EAAaqB,EAAUpB,eAAeqB,GAEnCnB,EAAI,EAAGA,EAAIC,EAAQD,IAC1BH,EAAWG,GAAKoB,EAAUhB,EAASJ,GAG/BA,EAAIe,EAAStD,KAAKG,cACpBiC,EAAWG,IAAMA,GAAKe,EAAStD,KAAKG,cAIlCoC,EAAIC,EAASe,EAAUvD,KAAKG,cAC9BiC,EAAWG,KAAOC,EAASD,IAAMgB,EAAUvD,KAAKG,cAKtD,OAAOsD,CACT,GAEA,kBAGA,SAAK3C,GACH,IAAM8C,EAAS5D,KAAKC,SAAS4D,qBAM7B,OAJAD,EAAO9C,OAASA,EAChB8C,EAAOE,QAAQ9D,KAAKC,SAAS8D,aAC7BH,EAAOR,QAEAQ,CACT,GAEA,oBAUA,SAAO9C,GAAuE,IAAlDkD,EAAe,UAAH,6CAAG,YACnCC,EAAWjE,KAAKkE,YAAYpD,GAC5BqD,EAAWnE,KAAKoE,cAAcH,EAAUnD,EAAOqB,iBAAkBrB,EAAOf,YACxEsE,EAAY,IAAIrD,KAAK,CAACmD,GAAW,CAAEH,KAAAA,IAEzC,MAAO,CACLM,KAAMD,EACNE,IAAKvE,KAAKwE,WAAWH,GACrBI,QAASzE,KAAK0E,oBAAoBL,GAEtC,GAEA,sBAMA,SAASC,GAA6D,IAAjDK,EAAmB,UAAH,6CAAG,UAChCC,EAAIC,SAASC,cAAc,KAOjC,OALAF,EAAEG,MAAMC,QAAU,OAClBJ,EAAEK,KAAOjF,KAAKwE,WAAWF,GACzBM,EAAEM,SAAW,GAAH,OAAMP,EAAQ,YAAIL,EAAKN,KAAKtC,MAAM,KAAK,IACjDkD,EAAEO,QAEKP,CACT,GAEA,0BAOA,SAAgBQ,GACd,OAAOpF,KAAKqF,oBAAiBC,EAAYF,GAC3C,GAEA,mBAGA,WAEE,OADApF,KAAKC,SAASsF,QACPvF,IACT,GAEA,0BAKA,SAAqB4B,GACnB,OAAOoB,KAAKwC,IAAG,MAARxC,KAAI,EAAQpB,EAAQhB,KAAI,SAACE,GAAM,OAAKA,EAAO2E,QAAQ,KAC5D,GAEA,kCAKA,SAA6B7D,GAC3B,OAAOoB,KAAKwC,IAAG,MAARxC,KAAI,EAAQpB,EAAQhB,KAAI,SAACE,GAAM,OAAKA,EAAOqB,gBAAgB,KACpE,GAEA,0BAKA,SAAqBP,GACnB,OAAOA,EAAQhB,KAAI,SAACE,GAAM,OAAKA,EAAO0B,MAAM,IAAEkD,QAAO,SAACd,EAAGe,GAAC,OAAKf,EAAIe,CAAC,GAAE,EACxE,GAEA,0BAKA,WACE,MAAO,iBAAkBvF,QAAU,uBAAwBA,QAAU,oBAAqBA,MAC5F,GAEA,2BAOA,SAAsBU,EAAsB8E,EAAuB7F,GACjE,IAEM8F,EADiBC,EACJF,EAIbG,EALiBD,EAKDhF,EAAO0B,OACvBwD,EAFkB,GAEiBD,EAEnC9E,EAAc,IAAIgF,YALD,EAK8BD,GAC/CE,EAAO,IAAIC,SAASlF,GAgB1B,OAdAjB,KAAKoG,aAAaF,EAAM,EAAG,QAC3BA,EAAKG,UAAU,EAAGL,GAAgB,GAClChG,KAAKoG,aAAaF,EAAM,EAAG,QAC3BlG,KAAKoG,aAAaF,EAAM,GAAI,QAC5BA,EAAKG,UAAU,GAAI,IAAI,GACvBH,EAAKI,UAAU,GAAI,GAAG,GACtBJ,EAAKI,UAAU,GAAIV,GAAe,GAClCM,EAAKG,UAAU,GAAItG,GAAY,GAC/BmG,EAAKG,UAAU,GAAItG,EAAa8F,GAAY,GAC5CK,EAAKI,UAAU,GAAIT,GAAY,GAC/BK,EAAKI,UAAU,GAtBE,IAsBY,GAC7BtG,KAAKoG,aAAaF,EAAM,GAAI,QAC5BA,EAAKG,UAAU,GAAIN,GAAe,GAE3B/F,KAAKuG,iBAAiBL,EAAMpF,EAAQ0F,GAC7C,GAEA,8BAKA,SAAyBrC,EAAoBrD,EAAsB6B,GACjE,IAAK,IAAIJ,EAAI,EAAGA,EAAIzB,EAAO0B,OAAQD,IAAKI,GAAU,EAAG,CACnD,IAAM8D,EAAMzD,KAAKwC,KAAK,EAAGxC,KAAK0D,IAAI,EAAG5F,EAAOyB,KAC5C4B,EAASwC,SAAShE,EAAQ8D,EAAM,EAAU,MAANA,EAAqB,MAANA,GAAc,EACnE,CAEA,OAAOtC,CACT,GAEA,0BAKA,SAAqBA,EAAoBxB,EAAgBiE,GACvD,IAAK,IAAIrE,EAAI,EAAGA,EAALine truncated
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
/*! howler.js v2.2.4 | (c) 2013-2020, James Simpson of GoldFire Studios | MIT License | howlerjs.com */
|
||||||
|
!function(){"use strict";var e=function(){this.init()};e.prototype={init:function(){var e=this||n;return e._counter=1e3,e._html5AudioPool=[],e.html5PoolSize=10,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.autoUnlock=!0,e._setup(),e},volume:function(e){var o=this||n;if(e=parseFloat(e),o.ctx||_(),void 0!==e&&e>=0&&e<=1){if(o._volume=e,o._muted)return o;o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var t=0;t<o._howls.length;t++)if(!o._howls[t]._webAudio)for(var r=o._howls[t]._getSoundIds(),a=0;a<r.length;a++){var u=o._howls[t]._soundById(r[a]);u&&u._node&&(u._node.volume=u._volume*e)}return o}return o._volume},mute:function(e){var o=this||n;o.ctx||_(),o._muted=e,o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e?0:o._volume,n.ctx.currentTime);for(var t=0;t<o._howls.length;t++)if(!o._howls[t]._webAudio)for(var r=o._howls[t]._getSoundIds(),a=0;a<r.length;a++){var u=o._howls[t]._soundById(r[a]);u&&u._node&&(u._node.muted=!!e||u._muted)}return o},stop:function(){for(var e=this||n,o=0;o<e._howls.length;o++)e._howls[o].stop();return e},unload:function(){for(var e=this||n,o=e._howls.length-1;o>=0;o--)e._howls[o].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"suspended":"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var o=new Audio;void 0===o.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var o=new Audio;o.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,o=null;try{o="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!o||"function"!=typeof o.canPlayType)return e;var t=o.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator?e._navigator.userAgent:"",a=r.match(/OPR\/(\d+)/g),u=a&&parseInt(a[0].split("/")[1],10)<33,d=-1!==r.indexOf("Safari")&&-1===r.indexOf("Chrome"),i=r.match(/Version\/(.*?) /),_=d&&i&&parseInt(i[1],10)<15;return e._codecs={mp3:!(u||!t&&!o.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!t,opus:!!o.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!(o.canPlayType('audio/wav; codecs="1"')||o.canPlayType("audio/wav")).replace(/^no$/,""),aac:!!o.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!o.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(o.canPlayType("audio/x-m4a;")||o.canPlayType("audio/m4a;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),m4b:!!(o.canPlayType("audio/x-m4b;")||o.canPlayType("audio/m4b;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(o.canPlayType("audio/x-mp4;")||o.canPlayType("audio/mp4;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),webm:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),dolby:!!o.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(o.canPlayType("audio/x-flac;")||o.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||n;if(!e._audioUnlocked&&e.ctx){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var o=function(n){for(;e._html5AudioPool.length<e.html5PoolSize;)try{var t=new Audio;t._unlocked=!0,e._releaseHtml5Audio(t)}catch(n){e.noAudio=!0;break}for(var r=0;r<e._howls.length;r++)if(!e._howls[r]._webAudio)for(var a=e._howls[r]._getSoundIds(),u=0;u<a.length;u++){var d=e._howls[r]._soundById(a[u]);d&&d._node&&!d._node._unlocked&&(d._node._unlocked=!0,d._node.load())}e._autoResume();var i=e.ctx.createBufferSource();i.buffer=e._scratchBuffer,i.connect(e.ctx.destination),void 0===i.start?i.noteOn(0):i.start(0),"function"==typeof e.ctx.resume&&e.ctx.resume(),i.onended=function(){i.disconnect(0),e._audioUnlocked=!0,document.removeEventListener("touchstart",o,!0),document.removeEventListener("touchend",o,!0),document.removeEventListener("click",o,!0),document.removeEventListener("keydown",o,!0);for(var n=0;n<e._howls.length;n++)e._howls[n]._emit("unlock")}};return document.addEventListener("touchstart",o,!0),document.addEventListener("touchend",o,!0),document.addEventListener("click",o,!0),document.addEventListener("keydown",o,!0),e}},_obtainHtml5Audio:function(){var e=this||n;if(e._html5AudioPool.length)return e._html5AudioPool.pop();var o=(new Audio).play();return o&&"undefined"!=typeof Promise&&(o instanceof Promise||"function"==typeof o.then)&&o.catch(function(){console.warn("HTML5 Audio pool eLine truncated
|
||||||
|
/*! Spatial Plugin */
|
||||||
|
!function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(e){var n=this;if(!n.ctx||!n.ctx.listener)return n;for(var t=n._howls.length-1;t>=0;t--)n._howls[t].stereo(e);return n},HowlerGlobal.prototype.pos=function(e,n,t){var r=this;return r.ctx&&r.ctx.listener?(n="number"!=typeof n?r._pos[1]:n,t="number"!=typeof t?r._pos[2]:t,"number"!=typeof e?r._pos:(r._pos=[e,n,t],void 0!==r.ctx.listener.positionX?(r.ctx.listener.positionX.setTargetAtTime(r._pos[0],Howler.ctx.currentTime,.1),r.ctx.listener.positionY.setTargetAtTime(r._pos[1],Howler.ctx.currentTime,.1),r.ctx.listener.positionZ.setTargetAtTime(r._pos[2],Howler.ctx.currentTime,.1)):r.ctx.listener.setPosition(r._pos[0],r._pos[1],r._pos[2]),r)):r},HowlerGlobal.prototype.orientation=function(e,n,t,r,o,i){var a=this;if(!a.ctx||!a.ctx.listener)return a;var p=a._orientation;return n="number"!=typeof n?p[1]:n,t="number"!=typeof t?p[2]:t,r="number"!=typeof r?p[3]:r,o="number"!=typeof o?p[4]:o,i="number"!=typeof i?p[5]:i,"number"!=typeof e?p:(a._orientation=[e,n,t,r,o,i],void 0!==a.ctx.listener.forwardX?(a.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.forwardY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.forwardZ.setTargetAtTime(t,Howler.ctx.currentTime,.1),a.ctx.listener.upX.setTargetAtTime(r,Howler.ctx.currentTime,.1),a.ctx.listener.upY.setTargetAtTime(o,Howler.ctx.currentTime,.1),a.ctx.listener.upZ.setTargetAtTime(i,Howler.ctx.currentTime,.1)):a.ctx.listener.setOrientation(e,n,t,r,o,i),a)},Howl.prototype.init=function(e){return function(n){var t=this;return t._orientation=n.orientation||[1,0,0],t._stereo=n.stereo||null,t._pos=n.pos||null,t._pannerAttr={coneInnerAngle:void 0!==n.coneInnerAngle?n.coneInnerAngle:360,coneOuterAngle:void 0!==n.coneOuterAngle?n.coneOuterAngle:360,coneOuterGain:void 0!==n.coneOuterGain?n.coneOuterGain:0,distanceModel:void 0!==n.distanceModel?n.distanceModel:"inverse",maxDistance:void 0!==n.maxDistance?n.maxDistance:1e4,panningModel:void 0!==n.panningModel?n.panningModel:"HRTF",refDistance:void 0!==n.refDistance?n.refDistance:1,rolloffFactor:void 0!==n.rolloffFactor?n.rolloffFactor:1},t._onstereo=n.onstereo?[{fn:n.onstereo}]:[],t._onpos=n.onpos?[{fn:n.onpos}]:[],t._onorientation=n.onorientation?[{fn:n.onorientation}]:[],e.call(this,n)}}(Howl.prototype.init),Howl.prototype.stereo=function(n,t){var r=this;if(!r._webAudio)return r;if("loaded"!==r._state)return r._queue.push({event:"stereo",action:function(){r.stereo(n,t)}}),r;var o=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof n)return r._stereo;r._stereo=n,r._pos=[n,0,0]}for(var i=r._getSoundIds(t),a=0;a<i.length;a++){var p=r._soundById(i[a]);if(p){if("number"!=typeof n)return p._stereo;p._stereo=n,p._pos=[n,0,0],p._node&&(p._pannerAttr.panningModel="equalpower",p._panner&&p._panner.pan||e(p,o),"spatial"===o?void 0!==p._panner.positionX?(p._panner.positionX.setValueAtTime(n,Howler.ctx.currentTime),p._panner.positionY.setValueAtTime(0,Howler.ctx.currentTime),p._panner.positionZ.setValueAtTime(0,Howler.ctx.currentTime)):p._panner.setPosition(n,0,0):p._panner.pan.setValueAtTime(n,Howler.ctx.currentTime)),r._emit("stereo",p._id)}}return r},Howl.prototype.pos=function(n,t,r,o){var i=this;if(!i._webAudio)return i;if("loaded"!==i._state)return i._queue.push({event:"pos",action:function(){i.pos(n,t,r,o)}}),i;if(t="number"!=typeof t?0:t,r="number"!=typeof r?-.5:r,void 0===o){if("number"!=typeof n)return i._pos;i._pos=[n,t,r]}for(var a=i._getSoundIds(o),p=0;p<a.length;p++){var s=i._soundById(a[p]);if(s){if("number"!=typeof n)return s._pos;s._pos=[n,t,r],s._node&&(s._panner&&!s._panner.pan||e(s,"spatial"),void 0!==s._panner.positionX?(s._panner.positionX.setValueAtTime(n,Howler.ctx.currentTime),s._panner.positionY.setValueAtTime(t,Howler.ctx.currentTime),s._panner.positionZ.setValueAtTime(r,Howler.ctx.currentTime)):s._panner.setPosition(n,t,r)),i._emit("pos",s._id)}}return i},Howl.prototype.orientation=function(n,t,r,o){var i=this;if(!i._webAudio)return i;if("loaded"!==i._state)return i._queue.push({event:"orientation",action:function(){i.orientation(n,t,r,o)}}),i;if(t="number"!=typeof t?i._orientation[1]:t,r="number"!=typeof r?i._orientation[2]:r,void 0===o){if("number"!=typeof n)return i._orientation;i._orientation=[n,t,r]}for(var a=i._getSoundIds(o),p=0;p<a.length;p++){var s=i._soundById(a[p]);if(s){if("number"!=typeof n)return s._orientation;s._orientation=[n,t,r],s._node&&(s._panner||(s._pos||(s._pos=i._pos||[0,0,-.5]),e(s,"spatial")),void 0!==s._panner.orientationX?(s._panner.orientationX.setValueAtTime(n,Howler.ctx.currentTime),s._panner.orientationY.setValueAtTime(t,Howler.ctx.currentTime),s._panner.orientationZ.setValueAtTime(r,Howler.ctx.currentTime)):s._panner.setOrientation(n,t,r)),i._emit("orientation",s._id)}}return i},Howl.prototype.pannerAttr=function(){var n,t,r,o=this,i=arguments;if(!o._webAudioLine truncated
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import soundfile as sf
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Compare TTS output with the original text using detailed comparison.")
|
||||||
|
parser.add_argument("--ttslistpath", help="Path to the ttsList.json file")
|
||||||
|
parser.add_argument("--wavfilespath", help="Path to the wav outputs folder")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not args.ttslistpath:
|
||||||
|
parser.error("[AllTalk TTSSRT] Please specify the path to the ttslist.json file using the --ttslistpath argument.")
|
||||||
|
if not args.wavfilespath:
|
||||||
|
parser.error("[AllTalk TTSSRT] Please specify the path to the wavs output folder file using the --wavfilespath argument.")
|
||||||
|
|
||||||
|
json_file_path = Path(args.ttslistpath).resolve()
|
||||||
|
audio_files_base_path = Path(args.wavfilespath).resolve()
|
||||||
|
|
||||||
|
print(f"[AllTalk TTSSRT]")
|
||||||
|
print("[AllTalk TTSSRT] \033[92mStarting SRT Subtitle generation:\033[0m")
|
||||||
|
print("[AllTalk TTSSRT]")
|
||||||
|
print("[AllTalk TTSSRT] \033[94mJSON file :\033[92m", json_file_path, "\033[0m")
|
||||||
|
print("[AllTalk TTSSRT] \033[94mWAV files :\033[92m", audio_files_base_path, "\033[0m")
|
||||||
|
print("[AllTalk TTSSRT]")
|
||||||
|
|
||||||
|
# Function to convert time in seconds to SRT time format
|
||||||
|
def format_srt_time(seconds):
|
||||||
|
hours = int(seconds // 3600)
|
||||||
|
minutes = int((seconds % 3600) // 60)
|
||||||
|
seconds = seconds % 60
|
||||||
|
milliseconds = int((seconds - int(seconds)) * 1000)
|
||||||
|
return f"{hours:02}:{minutes:02}:{int(seconds):02},{milliseconds:03}"
|
||||||
|
|
||||||
|
# Load the JSON data
|
||||||
|
with open(json_file_path, 'r') as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
|
||||||
|
# Initialize start time and SRT lines
|
||||||
|
start_time = 0.0
|
||||||
|
srt_lines = []
|
||||||
|
|
||||||
|
# Loop through the JSON data to build SRT entries
|
||||||
|
for entry in data:
|
||||||
|
file_name = Path(entry['fileUrl']).name # Get the file name from the URL
|
||||||
|
file_path = audio_files_base_path / file_name
|
||||||
|
print(f"[AllTalk TTSSRT] Processing file: {file_name}")
|
||||||
|
|
||||||
|
if not file_path.exists():
|
||||||
|
print(f"[AllTalk TTSSRT] Audio file does not exist: {file_path}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use soundfile to read the duration of the WAV file
|
||||||
|
with sf.SoundFile(str(file_path), 'r') as f:
|
||||||
|
duration = len(f) / f.samplerate
|
||||||
|
end_time = start_time + duration
|
||||||
|
|
||||||
|
# Format the SRT entry
|
||||||
|
start_timestamp = format_srt_time(start_time)
|
||||||
|
end_timestamp = format_srt_time(end_time)
|
||||||
|
srt_lines.append(f"{len(srt_lines)+1}\n{start_timestamp} --> {end_timestamp}\n{entry['text']}\n")
|
||||||
|
|
||||||
|
# Update the start time for the next entry
|
||||||
|
start_time = end_time
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(f"[AllTalk TTSSRT] Error reading {file_path}: {e}")
|
||||||
|
|
||||||
|
# Join all SRT lines into the final SRT content
|
||||||
|
srt_content = "\n".join(srt_lines)
|
||||||
|
|
||||||
|
# Save the SRT content to a file
|
||||||
|
srt_file_path = audio_files_base_path / "subtitles.srt"
|
||||||
|
with open(srt_file_path, "w") as srt_file:
|
||||||
|
srt_file.write(srt_content)
|
||||||
|
|
||||||
|
print("[AllTalk TTSSRT]")
|
||||||
|
print(f"[AllTalk TTSSRT] \033[94mSRT file created at \033[0m{srt_file_path}")
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/*! For license information please see 1995fcd6d39cade7d871.js.LICENSE.txt */
|
||||||
|
function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}function _regeneratorRuntime(){"use strict";_regeneratorRuntime=function(){return e};var t,e={},r=Object.prototype,n=r.hasOwnProperty,o=Object.defineProperty||function(t,e,r){t[e]=r.value},i="function"==typeof Symbol?Symbol:{},a=i.iterator||"@@iterator",c=i.asyncIterator||"@@asyncIterator",u=i.toStringTag||"@@toStringTag";function l(t,e,r){return Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{l({},"")}catch(t){l=function(t,e,r){return t[e]=r}}function f(t,e,r,n){var i=e&&e.prototype instanceof m?e:m,a=Object.create(i.prototype),c=new G(n||[]);return o(a,"_invoke",{value:S(t,r,c)}),a}function s(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}e.wrap=f;var h="suspendedStart",p="suspendedYield",y="executing",d="completed",v={};function m(){}function g(){}function w(){}var x={};l(x,a,(function(){return this}));var E=Object.getPrototypeOf,b=E&&E(E(B([])));b&&b!==r&&n.call(b,a)&&(x=b);var T=w.prototype=m.prototype=Object.create(x);function _(t){["next","throw","return"].forEach((function(e){l(t,e,(function(t){return this._invoke(e,t)}))}))}function L(t,e){function r(o,i,a,c){var u=s(t[o],t,i);if("throw"!==u.type){var l=u.arg,f=l.value;return f&&"object"==_typeof(f)&&n.call(f,"__await")?e.resolve(f.__await).then((function(t){r("next",t,a,c)}),(function(t){r("throw",t,a,c)})):e.resolve(f).then((function(t){l.value=t,a(l)}),(function(t){return r("throw",t,a,c)}))}c(u.arg)}var i;o(this,"_invoke",{value:function(t,n){function o(){return new e((function(e,o){r(t,n,e,o)}))}return i=i?i.then(o,o):o()}})}function S(e,r,n){var o=h;return function(i,a){if(o===y)throw new Error("Generator is already running");if(o===d){if("throw"===i)throw a;return{value:t,done:!0}}for(n.method=i,n.arg=a;;){var c=n.delegate;if(c){var u=I(c,n);if(u){if(u===v)continue;return u}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===h)throw o=d,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=y;var l=s(e,r,n);if("normal"===l.type){if(o=n.done?d:p,l.arg===v)continue;return{value:l.arg,done:n.done}}"throw"===l.type&&(o=d,n.method="throw",n.arg=l.arg)}}}function I(e,r){var n=r.method,o=e.iterator[n];if(o===t)return r.delegate=null,"throw"===n&&e.iterator.return&&(r.method="return",r.arg=t,I(e,r),"throw"===r.method)||"return"!==n&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+n+"' method")),v;var i=s(o,e.iterator,r.arg);if("throw"===i.type)return r.method="throw",r.arg=i.arg,r.delegate=null,v;var a=i.arg;return a?a.done?(r[e.resultName]=a.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,v):a:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,v)}function O(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function j(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function G(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(O,this),this.reset(!0)}function B(e){if(e||""===e){var r=e[a];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,i=function r(){for(;++o<e.length;)if(n.call(e,o))return r.value=e[o],r.done=!1,r;return r.value=t,r.done=!0,r};return i.next=i}}throw new TypeError(_typeof(e)+" is not iterable")}return g.prototype=w,o(T,"constructor",{value:w,configurable:!0}),o(w,"constructor",{value:g,configurable:!0}),g.displayName=l(w,u,"GeneratorFunction"),e.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===g||"GeneratorFunction"===(e.displayName||e.name))},e.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,w):(t.__proto__=w,l(t,u,"GeneratorFunction")),t.prototype=Object.create(T),t},e.awrap=function(t){return{__await:t}},_(L.prototype),l(L.prototype,c,(function(){return this})),e.AsyncIterator=L,e.async=function(t,r,n,o,i){void 0===i&&(i=Promise);var a=new L(f(t,r,n,o),i);return e.isGeneratorFunction(r)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},_(T),l(T,u,"Generator"),l(T,a,(function(){return this})),l(T,"toString",(function(){return"[object Generator]"})),e.keys=function(t){var e=Object(t),r=[];for(var n in e)r.push(n);return r.reverse(),function t(){for(;r.length;){var n=r.pop();if(n in e)return t.value=n,t.done=!1,t}return t.done=!0,t}},e.values=B,G.prototype={constructor:G,reset:function(e){if(this.prev=0,this.next=0,this.sent=this._sent=t,this.done=!1,this.delegate=null,this.method="next",this.arg=t,this.tryEntries.forEach(j),!e)for(var r in this)"t"===r.charAt(0)&&n.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=t)},stop:function(){this.done=!0;var t=this.tryELine truncated
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||||
|
* See LICENSE in the project root for license information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__header {
|
||||||
|
padding: 20px;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
padding-top: 100px;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__main {
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
-webkit-flex-wrap: nowrap;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-flex: 1 0 0;
|
||||||
|
flex: 1 0 0;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__main > h2 {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__features {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__features.ms-List .ms-ListItem {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__features.ms-List .ms-ListItem > .ms-Icon {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-welcome__action.ms-Button--hero {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-Button.ms-Button--hero .ms-Button-label {
|
||||||
|
color: #0078d7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-Button.ms-Button--hero:hover .ms-Button-label,
|
||||||
|
.ms-Button.ms-Button--hero:focus .ms-Button-label{
|
||||||
|
color: #005a9e;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 839 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 99 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<!doctype html><html><head><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><script src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script><script defer="defer" src="polyfill.js"></script><script defer="defer" src="commands.js"></script></head><body></body></html>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
!function(){var e={};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),Office.onReady((function(){})),("undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==e.g?e.g:void 0).action=function(e){var n={type:Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,message:"Performed action.",icon:"Icon.80x80",persistent:!0};Office.context.mailbox.item.notificationMessages.replaceAsync("action",n),e.completed()}}();
|
||||||
|
//# sourceMappingURL=commands.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"commands.js","mappings":"YACA,IAAIA,EAAsB,CAAC,ECD3BA,EAAoBC,EAAI,WACvB,GAA0B,iBAAfC,WAAyB,OAAOA,WAC3C,IACC,OAAOC,MAAQ,IAAIC,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAXC,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCOxBC,OAAOC,SAAQ,WACb,KAuBuB,oBAATC,KACVA,KACkB,oBAAXH,OACPA,YACkB,IAAXI,EAAAA,EACPA,EAAAA,OACAC,GAMJC,OA5BF,SAAgBC,GACd,IAAMC,EAAU,CACdC,KAAMR,OAAOS,aAAaC,4BAA4BC,qBACtDJ,QAAS,oBACTK,KAAM,aACNC,YAAY,GAIdb,OAAOc,QAAQC,QAAQC,KAAKC,qBAAqBC,aAAa,SAAUX,GAGxED,EAAMa,WACR,C","sources":["webpack://office-addin-taskpane-js/webpack/bootstrap","webpack://office-addin-taskpane-js/webpack/runtime/global","webpack://office-addin-taskpane-js/./src/commands/commands.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","/*\n * Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n * See LICENSE in the project root for license information.\n */\n\n/* global global, Office, self, window */\n\nOffice.onReady(() => {\n // If needed, Office.js is ready to be called\n});\n\n/**\n * Shows a notification when the add-in command is executed.\n * @param event {Office.AddinCommands.Event}\n */\nfunction action(event) {\n const message = {\n type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,\n message: \"Performed action.\",\n icon: \"Icon.80x80\",\n persistent: true,\n };\n\n // Show a notification message\n Office.context.mailbox.item.notificationMessages.replaceAsync(\"action\", message);\n\n // Be sure to indicate when the add-in command function is complete\n event.completed();\n}\n\nfunction getGlobal() {\n return typeof self !== \"undefined\"\n ? self\n : typeof window !== \"undefined\"\n ? window\n : typeof global !== \"undefined\"\n ? global\n : undefined;\n}\n\nconst g = getGlobal();\n\n// The add-in command functions need to be available in global scope\ng.action = action;\n"],"names":["__webpack_require__","g","globalThis","this","Function","e","window","Office","onReady","self","global","undefined","action","event","message","type","MailboxEnums","ItemNotificationMessageType","InformationalMessage","icon","persistent","context","mailbox","item","notificationMessages","replaceAsync","completed"],"sourceRoot":""}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
|
||||||
|
<Id>68b6ad53-4f72-42a8-a971-a9643c2f409a</Id>
|
||||||
|
<Version>1.0.0.0</Version>
|
||||||
|
<ProviderName>AllTalk</ProviderName>
|
||||||
|
<DefaultLocale>en-US</DefaultLocale>
|
||||||
|
<DisplayName DefaultValue="AllTalk TTS"/>
|
||||||
|
<Description DefaultValue="Enhance your document creation with AllTalk TTS's advanced text-to-voice functionality. Requires connection to AllTalk server."/>
|
||||||
|
<IconUrl DefaultValue="http://127.0.0.1:7851/api/word_addin/assets/icon-32.png"/>
|
||||||
|
<HighResolutionIconUrl DefaultValue="http://127.0.0.1:7851/api/word_addin/assets/icon-64.png"/>
|
||||||
|
<SupportUrl DefaultValue="https://github.com/erew123/alltalk_tts/issues"/>
|
||||||
|
<AppDomains>
|
||||||
|
<AppDomain>https://www.contoso.com</AppDomain>
|
||||||
|
</AppDomains>
|
||||||
|
<Hosts>
|
||||||
|
<Host Name="Document"/>
|
||||||
|
</Hosts>
|
||||||
|
<DefaultSettings>
|
||||||
|
<SourceLocation DefaultValue="http://127.0.0.1:7851/api/word_addin/taskpane.html"/>
|
||||||
|
</DefaultSettings>
|
||||||
|
<Permissions>ReadWriteDocument</Permissions>
|
||||||
|
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
|
||||||
|
<Hosts>
|
||||||
|
<Host xsi:type="Document">
|
||||||
|
<DesktopFormFactor>
|
||||||
|
<!-- You can add GetStarted information here if needed -->
|
||||||
|
<FunctionFile resid="Commands.Url"/>
|
||||||
|
<ExtensionPoint xsi:type="PrimaryCommandSurface">
|
||||||
|
<OfficeTab id="TabHome">
|
||||||
|
<Group id="AllTalkGroup">
|
||||||
|
<Label resid="AllTalkGroup.Label"/>
|
||||||
|
<Icon>
|
||||||
|
<bt:Image size="16" resid="Icon.16x16"/>
|
||||||
|
<bt:Image size="32" resid="Icon.32x32"/>
|
||||||
|
<bt:Image size="80" resid="Icon.80x80"/>
|
||||||
|
</Icon>
|
||||||
|
<Control xsi:type="Button" id="AllTalkTaskpaneButton">
|
||||||
|
<Label resid="AllTalkTaskpaneButton.Label"/>
|
||||||
|
<Supertip>
|
||||||
|
<Title resid="AllTalkTaskpaneButton.Label"/>
|
||||||
|
<Description resid="AllTalkTaskpaneButton.Tooltip"/>
|
||||||
|
</Supertip>
|
||||||
|
<Icon>
|
||||||
|
<bt:Image size="16" resid="Icon.16x16"/>
|
||||||
|
<bt:Image size="32" resid="Icon.32x32"/>
|
||||||
|
<bt:Image size="80" resid="Icon.80x80"/>
|
||||||
|
</Icon>
|
||||||
|
<Action xsi:type="ShowTaskpane">
|
||||||
|
<TaskpaneId>ButtonId1</TaskpaneId>
|
||||||
|
<SourceLocation resid="Taskpane.Url"/>
|
||||||
|
</Action>
|
||||||
|
</Control>
|
||||||
|
</Group>
|
||||||
|
</OfficeTab>
|
||||||
|
</ExtensionPoint>
|
||||||
|
</DesktopFormFactor>
|
||||||
|
</Host>
|
||||||
|
</Hosts>
|
||||||
|
<Resources>
|
||||||
|
<bt:Images>
|
||||||
|
<bt:Image id="Icon.16x16" DefaultValue="http://127.0.0.1:7851/api/word_addin/assets/icon-16.png"/>
|
||||||
|
<bt:Image id="Icon.32x32" DefaultValue="http://127.0.0.1:7851/api/word_addin/assets/icon-32.png"/>
|
||||||
|
<bt:Image id="Icon.80x80" DefaultValue="http://127.0.0.1:7851/api/word_addin/assets/icon-80.png"/>
|
||||||
|
</bt:Images>
|
||||||
|
<bt:Urls>
|
||||||
|
<!-- Ensure that these URLs are pointing to valid locations -->
|
||||||
|
<bt:Url id="Commands.Url" DefaultValue="http://127.0.0.1:7851/api/word_addin/commands.html"/>
|
||||||
|
<bt:Url id="Taskpane.Url" DefaultValue="http://127.0.0.1:7851/api/word_addin/taskpane.html"/>
|
||||||
|
</bt:Urls>
|
||||||
|
<bt:ShortStrings>
|
||||||
|
<bt:String id="AllTalkGroup.Label" DefaultValue="AllTalk Controls"/>
|
||||||
|
<bt:String id="AllTalkTaskpaneButton.Label" DefaultValue="Open AllTalk"/>
|
||||||
|
</bt:ShortStrings>
|
||||||
|
<bt:LongStrings>
|
||||||
|
<bt:String id="AllTalkTaskpaneButton.Tooltip" DefaultValue="Open the AllTalk task pane to start using the add-in."/>
|
||||||
|
</bt:LongStrings>
|
||||||
|
</Resources>
|
||||||
|
</VersionOverrides>
|
||||||
|
</OfficeApp>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
!function(){var t={35666:function(t){var r=function(t){"use strict";var r,e=Object.prototype,n=e.hasOwnProperty,i=Object.defineProperty||function(t,r,e){t[r]=e.value},o="function"==typeof Symbol?Symbol:{},u=o.iterator||"@@iterator",a=o.asyncIterator||"@@asyncIterator",c=o.toStringTag||"@@toStringTag";function s(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{s({},"")}catch(t){s=function(t,r,e){return t[r]=e}}function f(t,r,e,n){var o=r&&r.prototype instanceof y?r:y,u=Object.create(o.prototype),a=new j(n||[]);return i(u,"_invoke",{value:R(t,e,a)}),u}function l(t,r,e){try{return{type:"normal",arg:t.call(r,e)}}catch(t){return{type:"throw",arg:t}}}t.wrap=f;var h="suspendedStart",p="suspendedYield",v="executing",g="completed",d={};function y(){}function m(){}function b(){}var x={};s(x,u,(function(){return this}));var w=Object.getPrototypeOf,E=w&&w(w(P([])));E&&E!==e&&n.call(E,u)&&(x=E);var S=b.prototype=y.prototype=Object.create(x);function A(t){["next","throw","return"].forEach((function(r){s(t,r,(function(t){return this._invoke(r,t)}))}))}function O(t,r){function e(i,o,u,a){var c=l(t[i],t,o);if("throw"!==c.type){var s=c.arg,f=s.value;return f&&"object"==typeof f&&n.call(f,"__await")?r.resolve(f.__await).then((function(t){e("next",t,u,a)}),(function(t){e("throw",t,u,a)})):r.resolve(f).then((function(t){s.value=t,u(s)}),(function(t){return e("throw",t,u,a)}))}a(c.arg)}var o;i(this,"_invoke",{value:function(t,n){function i(){return new r((function(r,i){e(t,n,r,i)}))}return o=o?o.then(i,i):i()}})}function R(t,r,e){var n=h;return function(i,o){if(n===v)throw new Error("Generator is already running");if(n===g){if("throw"===i)throw o;return k()}for(e.method=i,e.arg=o;;){var u=e.delegate;if(u){var a=T(u,e);if(a){if(a===d)continue;return a}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if(n===h)throw n=g,e.arg;e.dispatchException(e.arg)}else"return"===e.method&&e.abrupt("return",e.arg);n=v;var c=l(t,r,e);if("normal"===c.type){if(n=e.done?g:p,c.arg===d)continue;return{value:c.arg,done:e.done}}"throw"===c.type&&(n=g,e.method="throw",e.arg=c.arg)}}}function T(t,e){var n=e.method,i=t.iterator[n];if(i===r)return e.delegate=null,"throw"===n&&t.iterator.return&&(e.method="return",e.arg=r,T(t,e),"throw"===e.method)||"return"!==n&&(e.method="throw",e.arg=new TypeError("The iterator does not provide a '"+n+"' method")),d;var o=l(i,t.iterator,e.arg);if("throw"===o.type)return e.method="throw",e.arg=o.arg,e.delegate=null,d;var u=o.arg;return u?u.done?(e[t.resultName]=u.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=r),e.delegate=null,d):u:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,d)}function I(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r)}function M(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r}function j(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(I,this),this.reset(!0)}function P(t){if(t){var e=t[u];if(e)return e.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var i=-1,o=function e(){for(;++i<t.length;)if(n.call(t,i))return e.value=t[i],e.done=!1,e;return e.value=r,e.done=!0,e};return o.next=o}}return{next:k}}function k(){return{value:r,done:!0}}return m.prototype=b,i(S,"constructor",{value:b,configurable:!0}),i(b,"constructor",{value:m,configurable:!0}),m.displayName=s(b,c,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return!!r&&(r===m||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,b):(t.__proto__=b,s(t,c,"GeneratorFunction")),t.prototype=Object.create(S),t},t.awrap=function(t){return{__await:t}},A(O.prototype),s(O.prototype,a,(function(){return this})),t.AsyncIterator=O,t.async=function(r,e,n,i,o){void 0===o&&(o=Promise);var u=new O(f(r,e,n,i),o);return t.isGeneratorFunction(e)?u:u.next().then((function(t){return t.done?t.value:u.next()}))},A(S),s(S,c,"Generator"),s(S,u,(function(){return this})),s(S,"toString",(function(){return"[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=P,j.prototype={constructor:j,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=r,this.done=!1,this.delegate=null,this.method="next",this.arg=r,this.tryEntries.forEach(M),!t)for(var e in this)"t"===e.charAt(0)&&n.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=r)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var e=this;function i(n,i){return a.type="throw",a.arg=t,e.next=n,i&&(e.method="next",e.arg=r),!!i}for(var o=this.tryEntries.length-1;o>=0;--o){var u=this.tryEntries[o],aLine truncated
|
||||||
|
//# sourceMappingURL=polyfill.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"polyfill.js","mappings":"qCAOA,IAAIA,EAAW,SAAUC,GACvB,aAEA,IAGIC,EAHAC,EAAKC,OAAOC,UACZC,EAASH,EAAGI,eACZC,EAAiBJ,OAAOI,gBAAkB,SAAUC,EAAKC,EAAKC,GAAQF,EAAIC,GAAOC,EAAKC,KAAO,EAE7FC,EAA4B,mBAAXC,OAAwBA,OAAS,CAAC,EACnDC,EAAiBF,EAAQG,UAAY,aACrCC,EAAsBJ,EAAQK,eAAiB,kBAC/CC,EAAoBN,EAAQO,aAAe,gBAE/C,SAASC,EAAOZ,EAAKC,EAAKE,GAOxB,OANAR,OAAOI,eAAeC,EAAKC,EAAK,CAC9BE,MAAOA,EACPU,YAAY,EACZC,cAAc,EACdC,UAAU,IAELf,EAAIC,EACb,CACA,IAEEW,EAAO,CAAC,EAAG,GACb,CAAE,MAAOI,GACPJ,EAAS,SAASZ,EAAKC,EAAKE,GAC1B,OAAOH,EAAIC,GAAOE,CACpB,CACF,CAEA,SAASc,EAAKC,EAASC,EAASC,EAAMC,GAEpC,IAAIC,EAAiBH,GAAWA,EAAQvB,qBAAqB2B,EAAYJ,EAAUI,EAC/EC,EAAY7B,OAAO8B,OAAOH,EAAe1B,WACzC8B,EAAU,IAAIC,EAAQN,GAAe,IAMzC,OAFAtB,EAAeyB,EAAW,UAAW,CAAErB,MAAOyB,EAAiBV,EAASE,EAAMM,KAEvEF,CACT,CAaA,SAASK,EAASC,EAAI9B,EAAK+B,GACzB,IACE,MAAO,CAAEC,KAAM,SAAUD,IAAKD,EAAGG,KAAKjC,EAAK+B,GAC7C,CAAE,MAAOf,GACP,MAAO,CAAEgB,KAAM,QAASD,IAAKf,EAC/B,CACF,CAlBAxB,EAAQyB,KAAOA,EAoBf,IAAIiB,EAAyB,iBACzBC,EAAyB,iBACzBC,EAAoB,YACpBC,EAAoB,YAIpBC,EAAmB,CAAC,EAMxB,SAASf,IAAa,CACtB,SAASgB,IAAqB,CAC9B,SAASC,IAA8B,CAIvC,IAAIC,EAAoB,CAAC,EACzB7B,EAAO6B,EAAmBnC,GAAgB,WACxC,OAAOoC,IACT,IAEA,IAAIC,EAAWhD,OAAOiD,eAClBC,EAA0BF,GAAYA,EAASA,EAASG,EAAO,MAC/DD,GACAA,IAA4BnD,GAC5BG,EAAOoC,KAAKY,EAAyBvC,KAGvCmC,EAAoBI,GAGtB,IAAIE,EAAKP,EAA2B5C,UAClC2B,EAAU3B,UAAYD,OAAO8B,OAAOgB,GAgBtC,SAASO,EAAsBpD,GAC7B,CAAC,OAAQ,QAAS,UAAUqD,SAAQ,SAASC,GAC3CtC,EAAOhB,EAAWsD,GAAQ,SAASnB,GACjC,OAAOW,KAAKS,QAAQD,EAAQnB,EAC9B,GACF,GACF,CA+BA,SAASqB,EAAc5B,EAAW6B,GAChC,SAASC,EAAOJ,EAAQnB,EAAKwB,EAASC,GACpC,IAAIC,EAAS5B,EAASL,EAAU0B,GAAS1B,EAAWO,GACpD,GAAoB,UAAhB0B,EAAOzB,KAEJ,CACL,IAAI0B,EAASD,EAAO1B,IAChB5B,EAAQuD,EAAOvD,MACnB,OAAIA,GACiB,iBAAVA,GACPN,EAAOoC,KAAK9B,EAAO,WACdkD,EAAYE,QAAQpD,EAAMwD,SAASC,MAAK,SAASzD,GACtDmD,EAAO,OAAQnD,EAAOoD,EAASC,EACjC,IAAG,SAASxC,GACVsC,EAAO,QAAStC,EAAKuC,EAASC,EAChC,IAGKH,EAAYE,QAAQpD,GAAOyD,MAAK,SAASC,GAI9CH,EAAOvD,MAAQ0D,EACfN,EAAQG,EACV,IAAG,SAASI,GAGV,OAAOR,EAAO,QAASQ,EAAOP,EAASC,EACzC,GACF,CAzBEA,EAAOC,EAAO1B,IA0BlB,CAEA,IAAIgC,EAgCJhE,EAAe2C,KAAM,UAAW,CAAEvC,MA9BlC,SAAiB+C,EAAQnB,GACvB,SAASiC,IACP,OAAO,IAAIX,GAAY,SAASE,EAASC,GACvCF,EAAOJ,EAAQnB,EAAKwB,EAASC,EAC/B,GACF,CAEA,OAAOO,EAaLA,EAAkBA,EAAgBH,KAChCI,EAGAA,GACEA,GACR,GAKF,CA0BA,SAASpC,EAAiBV,EAASE,EAAMM,GACvC,IAAIuC,EAAQ/B,EAEZ,OAAO,SAAgBgB,EAAQnB,GAC7B,GAAIkC,IAAU7B,EACZ,MAAM,IAAI8B,MAAM,gCAGlB,GAAID,IAAU5B,EAAmB,CAC/B,GAAe,UAAXa,EACF,MAAMnB,EAKR,OAAOoC,GACT,CAKA,IAHAzC,EAAQwB,OAASA,EACjBxB,EAAQK,IAAMA,IAED,CACX,IAAIqC,EAAW1C,EAAQ0C,SACvB,GAAIA,EAAU,CACZ,IAAIC,EAAiBC,EAAoBF,EAAU1C,GACnD,GAAI2C,EAAgB,CAClB,GAAIA,IAAmB/B,EAAkB,SACzC,OAAO+B,CACT,CACF,CAEA,GAAuB,SAAnB3C,EAAQwB,OAGVxB,EAAQ6C,KAAO7C,EAAQ8C,MAAQ9C,EAAQK,SAElC,GAAuB,UAAnBL,EAAQwB,OAAoB,CACrC,GAAIe,IAAU/B,EAEZ,MADA+B,EAAQ5B,EACFX,EAAQK,IAGhBL,EAAQ+C,kBAAkB/C,EAAQK,IAEpC,KAA8B,WAAnBL,EAAQwB,QACjBxB,EAAQgD,OAAO,SAAUhD,EAAQK,KAGnCkC,EAAQ7B,EAER,IAAIqB,EAAS5B,EAASX,EAASE,EAAMM,GACrC,GAAoB,WAAhB+B,EAAOzB,KAAmB,CAO5B,GAJAiC,EAAQvC,EAAQiD,KACZtC,EACAF,EAEAsB,EAAO1B,MAAQO,EACjB,SAGF,MAAO,CACLnC,MAAOsD,EAAO1B,IACd4C,KAAMjD,EAAQiD,KAGlB,CAA2B,UAAhBlB,EAAOzB,OAChBiC,EAAQ5B,EAGRX,EAAQwB,OAAS,QACjBxB,EAAQK,IAAM0B,EAAO1B,IAEzB,CACF,CACF,CAMA,SAASuC,EAAoBF,EAAU1C,GACrC,IAAIkD,EAAalD,EAAQwB,OACrBA,EAASkB,EAAS7D,SAASqE,GAC/B,GAAI1B,IAAWzD,EAOb,OAHAiC,EAAQ0C,SAAW,KAGA,UAAfQ,GAA0BR,EAAS7D,SAAiB,SAGtDmB,EAAQwB,OAAS,SACjBxB,EAAQK,IAAMtC,EACd6E,EAAoBF,EAAU1C,GAEP,UAAnBA,EAAQwB,SAMK,WAAf0B,IACFlD,EAAQwB,OAAS,QACjBxB,EAAQK,IAAM,IAAI8C,UAChB,oCAAsCD,EAAa,aAN5CtC,EAYb,IAAImB,EAAS5B,EAASqB,EAAQkB,EAAS7D,SAAUmB,EAAQK,KAEzD,GAAoB,UAAhB0B,EAAOzB,KAIT,OAHAN,EAAQwB,OAAS,QACjBxB,EAAQK,IAAM0B,EAAO1B,IACrBL,EAAQ0C,SAAW,KACZ9B,EAGT,IAAIwC,EAAOrB,EAAO1B,IAElB,OAAM+C,EAOFA,EAAKH,MAGPjD,EAAQ0C,EAASW,YAAcD,EAAK3E,MAGpCuB,EAAQsD,KAAOZ,EAASa,QAQD,WAAnBvD,EAAQwB,SACVxB,EAAQwB,OAAS,OACjBxB,EAAQK,IAAMtC,GAUlBiC,EAAQ0C,SAAW,KACZ9B,GANEwC,GA3BPpD,EAAQwB,OAAS,QACjBxB,EAAQK,IAAM,IAAI8C,UAAU,oCAC5BnD,EAAQ0C,SAAW,KACZ9B,EA+BX,CAqBA,SAAS4C,EAAaC,GACpB,IAAIC,EAAQ,CAAEC,OAAQF,EAAK,IAEvB,KAAKA,IACPC,EAAME,SAAWH,EAAK,IAGpB,KAAKA,IACPC,EAAMG,WAAaJ,EAAK,GACxBC,EAAMI,SAAWL,EAAK,IAGxBzC,KAAK+C,WAAWC,KAAKN,EACvB,CAEA,SAASO,EAAcP,GACrB,IAAI3B,EAAS2B,EAAMQ,YAAc,CAAC,EAClCnC,EAAOzB,KAAO,gBACPyB,EAAO1B,IACdqD,EAAMQ,WAAanC,CACrB,CAEA,SAAS9B,EAAQN,GAIfqB,KAAK+C,WAAa,CAAC,CAAEJ,OAAQ,SAC7BhE,EAAY4B,QAAQiC,EAAcxC,MAClCA,KAAKmD,OAAM,EACb,CA8BA,SAAS/C,EAAOgD,GACd,GAAIA,EAAU,CACZ,IAAIC,EAAiBD,EAASxF,GAC9B,GAAIyF,EACF,OAAOA,EAAe9D,KAAK6D,GAG7B,GAA6B,mBAAlBA,EAASd,KAClB,OAAOc,EAGT,IAAKE,MAAMF,EAASG,QAAS,CAC3B,IAAIC,GAAK,EAAGlB,EAAO,SAASA,IAC1B,OAASkB,EAAIJ,EAASG,QACpB,GAAIpG,EAAOoC,KAAK6D,EAAUI,GAGxB,OAFAlB,EAAK7E,MAAQ2F,EAASI,GACtBlB,EAAKL,MAAO,EACLK,EAOX,OAHAA,EAAK7E,MAAQV,EACbuF,EAAKL,MAAO,EAELK,CACT,EAEA,OAAOA,EAAKA,KAAOA,CACrB,CACF,CAGA,MAAO,CAAEA,KAAMb,EACjB,CAGA,SAASA,IACP,MAAO,CAAEhE,MAAOV,EAAWkF,MAAM,EACnC,CA8MA,OAnnBApC,EAAkB3C,UAAY4C,EAC9BzC,EAAegD,EAAI,cAAe,CAAE5C,MAAOqC,EAA4B1B,cAAc,IACrFf,EACEyC,EACA,cACA,CAAErC,MAAOoC,EAAmBzB,cAAc,IAE5CyB,EAAkB4D,YAAcvF,EAC9B4B,EACA9B,EACA,qBAaFlB,EAAQ4G,oBAAsB,SLine truncated
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>AllTalk TTS Add-in</title>
|
||||||
|
<script src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css" />
|
||||||
|
<link href="1fda685b81e1123773f6.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
label {
|
||||||
|
font-weight: 700;
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.nice-button {
|
||||||
|
background-color: #0078d4;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: background-color .3s ease
|
||||||
|
}
|
||||||
|
|
||||||
|
.nice-button:hover {
|
||||||
|
background-color: #005a9e
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioSource {
|
||||||
|
width: 300px;
|
||||||
|
height: 50px
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-right: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: start;
|
||||||
|
align-items: flex-end
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group>.input-container {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script defer="defer" src="polyfill.js"></script>
|
||||||
|
<script defer="defer" src="taskpane.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="ms-font-m ms-welcome ms-Fabric">
|
||||||
|
<header class="ms-welcome__header ms-bgColor-neutralLighter"><img width="90" height="90"
|
||||||
|
src="http://127.0.0.1:7851/api/word_addin/assets/logo-filled.png" alt="AllTalk TTS" title="AllTalk TTS" />
|
||||||
|
<h1 class="ms-font-su">AllTalk TTS</h1>
|
||||||
|
</header>
|
||||||
|
<main class="ms-welcome__main"><textarea id="text" rows="4" placeholder="Enter text here"
|
||||||
|
style="display:none"></textarea> <label for="voice">Voice:</label> <select id="voice" name="voice"
|
||||||
|
required></select> <label for="language">Language:</label> <select id="language" name="language"
|
||||||
|
value="English" required>
|
||||||
|
<option value="en" selected="selected">English</option>
|
||||||
|
<option value="ar">Arabic</option>
|
||||||
|
<option value="zh-cn">Chinese</option>
|
||||||
|
<option value="cs">Czech</option>
|
||||||
|
<option value="nl">Dutch</option>
|
||||||
|
<option value="fr">French</option>
|
||||||
|
<option value="de">German</option>
|
||||||
|
<option value="hu">Hungarian</option>
|
||||||
|
<option value="it">Italian</option>
|
||||||
|
<option value="ja">Japanese</option>
|
||||||
|
<option value="ko">Korean</option>
|
||||||
|
<option value="pl">Polish</option>
|
||||||
|
<option value="pt">Portuguese</option>
|
||||||
|
<option value="ru">Russian</option>
|
||||||
|
<option value="es">Spanish</option>
|
||||||
|
<option value="tr">Turkish</option>
|
||||||
|
</select><br><audio id="audioSource" controls autoplay></audio><br><button id="sendTextButton"
|
||||||
|
class="nice-button">Send Text to TTS</button><br><br><br><br>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-container"><label for="serverIP">Server IP:</label> <input id="serverIP" name="serverIP"
|
||||||
|
value="127.0.0.1" required></div>
|
||||||
|
<div class="input-container"><label for="portNumber">Port Number:</label> <input type="number"
|
||||||
|
id="portNumber" name="portNumber" value="7851" required></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<script src="1995fcd6d39cade7d871.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/*! For license information please see taskpane.js.LICENSE.txt */
|
||||||
|
!function(){var t={27091:function(t){"use strict";t.exports=function(t,e){return e||(e={}),t?(t=String(t.__esModule?t.default:t),e.hash&&(t+=e.hash),e.maybeNeedQuotes&&/[\t\n\f\r "'=<>`]/.test(t)?'"'.concat(t,'"'):t):t}},44944:function(t,e,r){"use strict";t.exports=r.p+"assets/logo-filled.png"},36076:function(t,e,r){"use strict";t.exports=r.p+"1995fcd6d39cade7d871.js"},60806:function(t,e,r){"use strict";t.exports=r.p+"1fda685b81e1123773f6.css"}},e={};function r(n){var o=e[n];if(void 0!==o)return o.exports;var i=e[n]={exports:{}};return t[n](i,i.exports,r),i.exports}r.m=t,r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,{a:e}),e},r.d=function(t,e){for(var n in e)r.o(e,n)&&!r.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},function(){var t;r.g.importScripts&&(t=r.g.location+"");var e=r.g.document;if(!t&&e&&(e.currentScript&&(t=e.currentScript.src),!t)){var n=e.getElementsByTagName("script");if(n.length)for(var o=n.length-1;o>-1&&!t;)t=n[o--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),r.p=t}(),r.b=document.baseURI||self.location.href,function(){function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(){"use strict";e=function(){return n};var r,n={},o=Object.prototype,i=o.hasOwnProperty,c=Object.defineProperty||function(t,e,r){t[e]=r.value},a="function"==typeof Symbol?Symbol:{},u=a.iterator||"@@iterator",f=a.asyncIterator||"@@asyncIterator",s=a.toStringTag||"@@toStringTag";function l(t,e,r){return Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{l({},"")}catch(r){l=function(t,e,r){return t[e]=r}}function h(t,e,r,n){var o=e&&e.prototype instanceof w?e:w,i=Object.create(o.prototype),a=new k(n||[]);return c(i,"_invoke",{value:I(t,r,a)}),i}function p(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}n.wrap=h;var y="suspendedStart",v="suspendedYield",d="executing",m="completed",g={};function w(){}function b(){}function x(){}var E={};l(E,u,(function(){return this}));var L=Object.getPrototypeOf,_=L&&L(L(T([])));_&&_!==o&&i.call(_,u)&&(E=_);var j=x.prototype=w.prototype=Object.create(E);function O(t){["next","throw","return"].forEach((function(e){l(t,e,(function(t){return this._invoke(e,t)}))}))}function S(e,r){function n(o,c,a,u){var f=p(e[o],e,c);if("throw"!==f.type){var s=f.arg,l=s.value;return l&&"object"==t(l)&&i.call(l,"__await")?r.resolve(l.__await).then((function(t){n("next",t,a,u)}),(function(t){n("throw",t,a,u)})):r.resolve(l).then((function(t){s.value=t,a(s)}),(function(t){return n("throw",t,a,u)}))}u(f.arg)}var o;c(this,"_invoke",{value:function(t,e){function i(){return new r((function(r,o){n(t,e,r,o)}))}return o=o?o.then(i,i):i()}})}function I(t,e,n){var o=y;return function(i,c){if(o===d)throw new Error("Generator is already running");if(o===m){if("throw"===i)throw c;return{value:r,done:!0}}for(n.method=i,n.arg=c;;){var a=n.delegate;if(a){var u=P(a,n);if(u){if(u===g)continue;return u}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===y)throw o=m,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=d;var f=p(t,e,n);if("normal"===f.type){if(o=n.done?m:v,f.arg===g)continue;return{value:f.arg,done:n.done}}"throw"===f.type&&(o=m,n.method="throw",n.arg=f.arg)}}}function P(t,e){var n=e.method,o=t.iterator[n];if(o===r)return e.delegate=null,"throw"===n&&t.iterator.return&&(e.method="return",e.arg=r,P(t,e),"throw"===e.method)||"return"!==n&&(e.method="throw",e.arg=new TypeError("The iterator does not provide a '"+n+"' method")),g;var i=p(o,t.iterator,e.arg);if("throw"===i.type)return e.method="throw",e.arg=i.arg,e.delegate=null,g;var c=i.arg;return c?c.done?(e[t.resultName]=c.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=r),e.delegate=null,g):c:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,g)}function B(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function N(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function k(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(B,this),this.reset(!0)}function T(e){if(e||""===e){var n=e[u];if(n)return n.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,c=function t(){for(;++o<e.length;)if(i.call(e,o))return t.value=e[o],t.done=!1,t;return t.value=r,t.done=!0,t};return c.next=c}}throw new TLine truncated
|
||||||
|
//# sourceMappingURL=taskpane.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"taskpane.js","mappings":";kDAEAA,EAAOC,QAAU,SAAUC,EAAKC,GAM9B,OALKA,IAEHA,EAAU,CAAC,GAGRD,GAKLA,EAAME,OAAOF,EAAIG,WAAaH,EAAII,QAAUJ,GAExCC,EAAQI,OAEVL,GAAOC,EAAQI,MAGbJ,EAAQK,iBAAmB,oBAAoBC,KAAKP,GAC/C,IAAKQ,OAAOR,EAAK,KAGnBA,GAfEA,CAgBX,wOCxBIS,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAab,QAGrB,IAAID,EAASW,EAAyBE,GAAY,CAGjDZ,QAAS,CAAC,GAOX,OAHAe,EAAoBH,GAAUb,EAAQA,EAAOC,QAASW,GAG/CZ,EAAOC,OACf,CAGAW,EAAoBK,EAAID,ECxBxBJ,EAAoBM,EAAI,SAASlB,GAChC,IAAImB,EAASnB,GAAUA,EAAOK,WAC7B,WAAa,OAAOL,EAAgB,OAAG,EACvC,WAAa,OAAOA,CAAQ,EAE7B,OADAY,EAAoBQ,EAAED,EAAQ,CAAEE,EAAGF,IAC5BA,CACR,ECNAP,EAAoBQ,EAAI,SAASnB,EAASqB,GACzC,IAAI,IAAIC,KAAOD,EACXV,EAAoBY,EAAEF,EAAYC,KAASX,EAAoBY,EAAEvB,EAASsB,IAC5EE,OAAOC,eAAezB,EAASsB,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,IAG3E,ECPAX,EAAoBiB,EAAI,WACvB,GAA0B,iBAAfC,WAAyB,OAAOA,WAC3C,IACC,OAAOC,MAAQ,IAAIC,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAXC,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCAxBtB,EAAoBY,EAAI,SAASW,EAAKC,GAAQ,OAAOX,OAAOY,UAAUC,eAAeC,KAAKJ,EAAKC,EAAO,aCAtG,IAAII,EACA5B,EAAoBiB,EAAEY,gBAAeD,EAAY5B,EAAoBiB,EAAEa,SAAW,IACtF,IAAIC,EAAW/B,EAAoBiB,EAAEc,SACrC,IAAKH,GAAaG,IACbA,EAASC,gBACZJ,EAAYG,EAASC,cAAcC,MAC/BL,GAAW,CACf,IAAIM,EAAUH,EAASI,qBAAqB,UAC5C,GAAGD,EAAQE,OAEV,IADA,IAAIC,EAAIH,EAAQE,OAAS,EAClBC,GAAK,IAAMT,GAAWA,EAAYM,EAAQG,KAAKJ,GAExD,CAID,IAAKL,EAAW,MAAM,IAAIU,MAAM,yDAChCV,EAAYA,EAAUW,QAAQ,OAAQ,IAAIA,QAAQ,QAAS,IAAIA,QAAQ,YAAa,KACpFvC,EAAoBwC,EAAIZ,KClBxB5B,EAAoByC,EAAIV,SAASW,SAAWC,KAAKb,SAASc,gRCC1DC,EAAA,kBAAAxB,CAAA,MAAAyB,EAAAzB,EAAA,GAAA0B,EAAAlC,OAAAY,UAAAnB,EAAAyC,EAAArB,eAAAd,EAAAC,OAAAC,gBAAA,SAAAgC,EAAAzB,EAAA0B,GAAAD,EAAAzB,GAAA0B,EAAAC,KAAA,EAAAX,EAAA,mBAAAY,OAAAA,OAAA,GAAAxC,EAAA4B,EAAAa,UAAA,aAAAC,EAAAd,EAAAe,eAAA,kBAAAC,EAAAhB,EAAAiB,aAAA,yBAAAC,EAAAT,EAAAzB,EAAA0B,GAAA,OAAAlC,OAAAC,eAAAgC,EAAAzB,EAAA,CAAA2B,MAAAD,EAAAhC,YAAA,EAAAyC,cAAA,EAAAC,UAAA,IAAAX,EAAAzB,EAAA,KAAAkC,EAAA,aAAAT,GAAAS,EAAA,SAAAT,EAAAzB,EAAA0B,GAAA,OAAAD,EAAAzB,GAAA0B,CAAA,WAAAW,EAAAZ,EAAAzB,EAAA0B,EAAAzC,GAAA,IAAA+B,EAAAhB,GAAAA,EAAAI,qBAAAkC,EAAAtC,EAAAsC,EAAAlD,EAAAI,OAAA+C,OAAAvB,EAAAZ,WAAA0B,EAAA,IAAAU,EAAAvD,GAAA,WAAAM,EAAAH,EAAA,WAAAuC,MAAAc,EAAAhB,EAAAC,EAAAI,KAAA1C,CAAA,UAAAsD,EAAAjB,EAAAzB,EAAA0B,GAAA,WAAAiB,KAAA,SAAAC,IAAAnB,EAAAnB,KAAAN,EAAA0B,GAAA,OAAAD,GAAA,OAAAkB,KAAA,QAAAC,IAAAnB,EAAA,EAAAzB,EAAAqC,KAAAA,EAAA,IAAAQ,EAAA,iBAAAC,EAAA,iBAAAC,EAAA,YAAAC,EAAA,YAAAC,EAAA,YAAAX,IAAA,UAAAY,IAAA,UAAAC,IAAA,KAAAhC,EAAA,GAAAe,EAAAf,EAAA/B,GAAA,8BAAAD,EAAAK,OAAA4D,eAAAC,EAAAlE,GAAAA,EAAAA,EAAAmE,EAAA,MAAAD,GAAAA,IAAA3B,GAAAzC,EAAAqB,KAAA+C,EAAAjE,KAAA+B,EAAAkC,GAAA,IAAAzD,EAAAuD,EAAA/C,UAAAkC,EAAAlC,UAAAZ,OAAA+C,OAAApB,GAAA,SAAAoC,EAAA9B,GAAA,0BAAA+B,SAAA,SAAAxD,GAAAkC,EAAAT,EAAAzB,GAAA,SAAAyB,GAAA,YAAAgC,QAAAzD,EAAAyB,EAAA,gBAAAiC,EAAAjC,EAAAzB,GAAA,SAAA2D,EAAAjC,EAAAnC,EAAAyB,EAAA5B,GAAA,IAAA0C,EAAAY,EAAAjB,EAAAC,GAAAD,EAAAlC,GAAA,aAAAuC,EAAAa,KAAA,KAAAX,EAAAF,EAAAc,IAAAC,EAAAb,EAAAL,MAAA,OAAAkB,GAAA,UAAAe,EAAAf,IAAA5D,EAAAqB,KAAAuC,EAAA,WAAA7C,EAAA6D,QAAAhB,EAAAiB,SAAAC,MAAA,SAAAtC,GAAAkC,EAAA,OAAAlC,EAAAT,EAAA5B,EAAA,aAAAqC,GAAAkC,EAAA,QAAAlC,EAAAT,EAAA5B,EAAA,IAAAY,EAAA6D,QAAAhB,GAAAkB,MAAA,SAAAtC,GAAAO,EAAAL,MAAAF,EAAAT,EAAAgB,EAAA,aAAAP,GAAA,OAAAkC,EAAA,QAAAlC,EAAAT,EAAA5B,EAAA,IAAAA,EAAA0C,EAAAc,IAAA,KAAAlB,EAAAnC,EAAA,gBAAAoC,MAAA,SAAAF,EAAAxC,GAAA,SAAA+E,IAAA,WAAAhE,GAAA,SAAAA,EAAA0B,GAAAiC,EAAAlC,EAAAxC,EAAAe,EAAA0B,EAAA,WAAAA,EAAAA,EAAAA,EAAAqC,KAAAC,EAAAA,GAAAA,GAAA,aAAAvB,EAAAzC,EAAA0B,EAAAzC,GAAA,IAAAM,EAAAsD,EAAA,gBAAA7B,EAAA5B,GAAA,GAAAG,IAAAwD,EAAA,UAAA9B,MAAA,mCAAA1B,IAAAyD,EAAA,cAAAhC,EAAA,MAAA5B,EAAA,OAAAuC,MAAAF,EAAAwC,MAAA,OAAAhF,EAAAiF,OAAAlD,EAAA/B,EAAA2D,IAAAxD,IAAA,KAAA0C,EAAA7C,EAAAkF,SAAA,GAAArC,EAAA,KAAAE,EAAAoC,EAAAtC,EAAA7C,GAAA,GAAA+C,EAAA,IAAAA,IAAAiB,EAAA,gBAAAjB,CAAA,cAAA/C,EAAAiF,OAAAjF,EAAAoF,KAAApF,EAAAqF,MAAArF,EAAA2D,SAAA,aAAA3D,EAAAiF,OAAA,IAAA3E,IAAAsD,EAAA,MAAAtD,EAAAyD,EAAA/D,EAAA2D,IAAA3D,EAAAsF,kBAAAtF,EAAA2D,IAAA,gBAAA3D,EAAAiF,QAAAjF,EAAAuF,OAAA,SAAAvF,EAAA2D,KAAArD,EAAAwD,EAAA,IAAA5B,EAAAuB,EAAA1C,EAAA0B,EAAAzC,GAAA,cAAAkC,EAAAwB,KAAA,IAAApD,EAAAN,EAAAgF,KAAAjB,EAAAF,EAAA3B,EAAAyB,MAAAK,EAAA,gBAAAtB,MAAAR,EAAAyB,IAAAqB,KAAAhF,EAAAgF,KAAA,WAAA9C,EAAAwB,OAAApD,EAAAyD,EAAA/D,EAAAiF,OAAA,QAAAjF,EAAA2D,IAAAzB,EAAAyB,IAAA,YAAAwB,EAAApE,EAAA0B,GAAA,IAAAzC,EAAAyC,EAAAwC,OAAA3E,EAAAS,EAAA6B,SAAA5C,GAAA,GAAAM,IAAAkC,EAAA,OAAAC,EAAAyC,SAAA,eAAAlF,GAAAe,EAAA6B,SAAA4C,SAAA/C,EAAAwC,OAAA,SAAAxC,EAAAkB,IAAAnB,EAAA2C,EAAApE,EAAA0B,GAAA,UAAAA,EAAAwC,SAAA,WAAAjF,IAAAyC,EAAAwC,OAAA,QAAAxC,EAAAkB,IAAA,IAAA8B,UAAA,oCAAAzF,EAAA,aAAAgE,EAAA,IAAAjC,EAAA0B,EAAAnD,EAAAS,EAAA6B,SAAAH,EAAAkB,KAAA,aAAA5B,EAAA2B,KAAA,OAAAjB,EAAAwC,OAAA,QAAAxC,EAAAkB,IAAA5B,EAAA4B,IAAAlB,EAAAyC,SAAA,KAAAlB,EAAA,IAAA7D,EAAA4B,EAAA4B,IAAA,OAAAxD,EAAAA,EAAA6E,MAAAvC,EAAA1B,EAAA2E,YAAAvF,EAAAuC,MAAAD,EAAAkD,KAAA5E,EAAA6E,QAAA,WAAAnD,EAAAwC,SAAAxC,EAAAwC,OAAA,OAAAxC,EAAAkB,IAAAnB,GAAAC,EAAAyC,SAAA,KAAAlB,GAAA7D,GAAAsC,EAAAwC,OAAA,QAAAxC,EAAAkB,IAAA,IAAA8B,UAAA,oCAAAhD,EAAAyC,SAAA,KAAAlB,EAAA,UAAA6B,EAAArD,GAAA,IAAAzB,EAAA,CAAA+ELine truncated
|
||||||
@@ -9,4 +9,6 @@ Author BBC
|
|||||||
This file is licensed under the Creative Commons Attribution 3.0 Unported license.
|
This file is licensed under the Creative Commons Attribution 3.0 Unported license.
|
||||||
https://creativecommons.org/licenses/by/3.0/deed.en
|
https://creativecommons.org/licenses/by/3.0/deed.en
|
||||||
|
|
||||||
Downsampled to 22050hz, mono and cut shorter
|
Downsampled to 22050hz, mono and cut shorter.
|
||||||
|
|
||||||
|
This license applies to both the original file ( «Clint_Eastwood CC3.wav» ) and it's derivative, the enhanced file ( «Clint_Eastwood (enhanced)CC3.wav» ).
|
||||||