Compare commits

...
198 Commits
Author SHA1 Message Date
Paladinium 3d4b94be7d Merge pull request #567 from Paladinium/main_improve_github_actions
Improve paths-filter for Docker github action
2025-03-19 21:50:25 +01:00
ekoc 1c66968873 Improve paths-filter for Docker github action 2025-03-19 21:49:34 +01:00
erew123 492dbe58c0 Merge pull request #543 from Paladinium/main
Adding Github actions for building Docker to main
2025-02-27 06:40:00 +00:00
ekoc 871a100a8a Adding Github actions for building the docker images 2025-02-26 21:28:48 +01:00
ekoc 3aacf3f27f Adding Github actions for building the docker images 2025-02-26 20:21:46 +01:00
ekoc fbd09a24b6 Adding Github actions for building the docker images 2025-02-22 16:40:25 +01:00
erew123 f6669c912c Update feature_request.md 2024-12-08 03:17:17 +00:00
erew123 6a45c03b04 Update python-ci.yml 2024-11-27 19:45:22 +00:00
erew123 84a28ca95c Update publish-docker.yml 2024-11-27 19:45:01 +00:00
erew123 6fda08cb53 Delete .github/workflows/main.yml 2024-11-27 03:55:36 +00:00
erew123 754cfeed9e Create python-ci.yml 2024-11-27 03:53:39 +00:00
erew123 e61aaca243 Create main.yml 2024-11-27 03:51:26 +00:00
erew123 8828ecb3af Update publish-docker.yml 2024-11-27 03:15:00 +00:00
erew123 abd1e4f13f Update README.md 2024-11-24 22:24:40 +00:00
erew123 a6b3a77fd8 Update README.md 2024-11-24 22:24:10 +00:00
erew123 d304032279 Update README.md 2024-11-24 20:23:49 +00:00
erew123 f4bc0081f4 Update README.md 2024-11-11 14:08:06 +00:00
erew123 1ff02ce1a4 Update README.md 2024-10-16 00:27:20 +01:00
erew123 5e39b546ef Update README.md 2024-10-16 00:26:30 +01:00
erew123 a39a4ebb89 Update README.md 2024-10-05 23:34:54 +01:00
erew123 510bc2d1a3 Update README.md 2024-08-15 09:27:17 +01:00
erew123 4ca5ae68ea Update requirements_textgen.txt 2024-08-15 09:03:58 +01:00
erew123 1a8a20f4ee Add files via upload 2024-07-01 09:57:58 +01:00
erew123 80eb4e5302 Merge pull request #249 from dpkirchner/tune-docker
Tune docker
2024-06-19 10:50:14 +01:00
erew123 9ff0bf10ab Wrong upload (no actual change here)
Must be careful to watch github swapping between branches when uploading!
2024-06-17 21:02:19 +01:00
erew123 d020a0f9a2 removed debug lines 2024-06-17 21:00:08 +01:00
erew123 012b987ab8 Force PyTorch 2.2.1 2024-06-14 13:10:17 +01:00
David Kirchner 24a0a457a1 Add a health check to docker compose (monitor with docker ps) 2024-06-11 10:47:25 -07:00
David Kirchner 663e267d4c Allow user to specify a docker image using compose
This makes it easier to test local changes. Usage is basically:

$ docker build -t whatever:latest .
$ IMAGE=whatever:latest docker compose up -d
2024-06-11 09:36:26 -07:00
David Kirchner f174a61aee Reorder dockerfile to avoid rebuilding modules on all code changes 2024-06-11 09:28:55 -07:00
erew123 c9b5aef80b Update README.md 2024-06-06 23:23:18 +01:00
erew123 f107173b58 Update README.md 2024-06-06 21:16:39 +01:00
erew123 9b530eda75 Update README.md 2024-06-06 21:16:20 +01:00
erew123 7c7cb72c13 Updated to deal with Gradio 4.xx versions 2024-05-14 21:01:38 +01:00
erew123 3a105ce922 Update tts_server.py
Set API Local to use float as Transformers demands it
2024-05-14 18:19:29 +01:00
erew123 690018c4ab Test code rework to allow custom file names.
Contains a box to add a custom file name. Files are generated in the format {custom-file-name}_{ID_number_XXXXX}_{uuid}

This allows up to 99,999 files generated in 1x single session. 

The uuid needs to be applied to ensure files are not over-written and handle browser based caching of wav files.
2024-05-12 14:00:10 +01:00
erew123 6808439ca1 nailed text-gen-webui spacy version
Added spacy>=3.7.2 to stop the requirements installation hunting around for Spacy versions so much.

Tested this on a fresh install of Text-gen-webui and it ran through without issue.
2024-05-06 23:40:39 +01:00
erew123 8cf56faad2 run dos2unix to repair crlf to lf 2024-05-06 01:39:01 +01:00
erew123 cb7d486288 run dos2unix to repair crlf to lf 2024-05-06 01:38:04 +01:00
erew123 086999fc1b Update atsetup.sh 2024-05-02 23:26:42 +01:00
erew123 a1b889108f Faster narration generation w/low vram
Moved the memory management of the TTS model into the narrator so that it doesnt shift the model backwards and forwards VRAM<>System ram on each portion of the generation. Only the beginning and end. Only benefits when Low VRAM is enabled, but should shave a few seconds of generation of your average generation.
2024-05-01 16:09:59 +01:00
erew123 9f18b24465 Changed how dvae weights are copied. 2024-05-01 02:38:24 +01:00
erew123 a3f157249c Small change to splitting of text 2024-04-28 21:14:25 +01:00
erew123 eb08d31509 Added Streaming Stopping
Currently this is in testing. 

curl -X POST http://localhost:7851/api/stop-generation

Would stop the current streaming generation.

This is more a v2 feature that is just getting tried out by someone else ATM.
2024-04-28 20:37:41 +01:00
erew123 1e1b7fdd8c Merge pull request #190 from ytt246/main
Edited text cleaning to support some commonly used fullwidth/CJK punctuations
2024-04-28 11:12:32 +01:00
IAUSHYJ 5aad7bcc45 tts generater split fix 2024-04-28 00:15:29 +04:00
erew123 dd52597f49 Grad acc steps min setting 2024-04-26 20:50:52 +01:00
erew123 5f836e08b8 Various updates
additional documentation
learning rate selectable
custom folder paths for saving model
selectable model on saving
2024-04-26 15:30:53 +01:00
IAUSHYJ b89b6cdc1d small fix 2024-04-26 13:23:23 +04:00
IAUSHYJ 558aed1888 stop cleaning common chinese punctuations 2024-04-26 03:40:20 +04:00
erew123 5eab3d28df Add files via upload 2024-04-25 21:25:29 +01:00
erew123 fd76f496a0 re-jigged language support/filters 2024-04-25 21:24:44 +01:00
erew123 4d9b44d9a0 Update tts_generator.html 2024-04-25 18:06:49 +01:00
erew123 951df5a239 Update atsetup.bat 2024-04-24 18:40:38 +01:00
erew123 0a35ee2310 Update atsetup.bat 2024-04-24 18:38:32 +01:00
erew123 efeb2e67e0 Add files via upload 2024-04-20 14:54:33 +01:00
erew123 131f14de76 Add files via upload 2024-04-20 14:49:03 +01:00
erew123 4e67931fe9 bug fix 2024-04-20 10:28:18 +01:00
erew123 785525327d Update README.md 2024-04-18 20:07:20 +01:00
erew123 d4647573cd Add files via upload 2024-04-18 19:58:31 +01:00
erew123 c3895b602c Hindi Support 2024-04-18 18:43:25 +01:00
erew123 f18eb9a4a0 Hindi Support 2024-04-18 18:39:10 +01:00
erew123 2834778e8f Added Hindi finetune.py 2024-04-18 18:32:10 +01:00
erew123 2f42c69d25 Update README.md 2024-04-18 15:57:32 +01:00
erew123 8c65f026e6 ST AllTalk FT Model
changed a value for detecting FT model.
2024-04-09 01:17:03 +01:00
erew123 fff01107c8 Update tts_server.py - API request console output 2024-04-06 11:45:32 +01:00
erew123 0bdc66f6e5 Add files via upload 2024-04-05 12:28:59 +01:00
erew123 1c3fc86085 Delete system/at_admin/textnotinside-min.jpg 2024-04-05 12:28:38 +01:00
erew123 d9eb0876a6 Delete system/at_admin/pythonrequirementswindows-min.jpg 2024-04-05 12:28:30 +01:00
erew123 9b4130a8eb Delete system/at_admin/pythonenvironment-min.jpg 2024-04-05 12:28:22 +01:00
erew123 8fb5b4f695 Delete system/at_admin/deepspeedexample-min.jpg 2024-04-05 12:28:14 +01:00
erew123 65e306a198 Delete system/at_admin/atandsdplugin-min.jpg 2024-04-05 12:28:07 +01:00
erew123 3dabb63656 Delete system/at_admin/4abed1ca-min.jpg 2024-04-05 12:27:59 +01:00
erew123 241fa91473 Delete system/at_admin/3c6fde566d6a-min.jpg 2024-04-05 12:27:50 +01:00
erew123 2a5c8dd58a Add files via upload 2024-04-05 12:17:28 +01:00
erew123 2bfa10d7be Fix Windows 10 issue with path/environment. 2024-04-05 12:07:46 +01:00
erew123 3501e2e2f3 Fix crunker bug over networks
Crunker had an update to resolve bad performance over networks. This would affect only the TTS Generator when used remotely from AllTalk.
2024-04-05 10:26:33 +01:00
erew123 679e3a0982 Update atsetup.bat
encapsulate SET path
2024-04-04 19:11:59 +01:00
erew123 35d05c7689 Add files via upload 2024-04-04 11:07:21 +01:00
erew123 084cc2d2a2 Add files via upload 2024-04-04 11:02:59 +01:00
erew123 a96c82ff01 Add files via upload 2024-04-04 10:58:35 +01:00
erew123 aa7ff1940a Add files via upload 2024-04-04 10:30:45 +01:00
erew123 58465ae14e Update Dockerfile 2024-04-04 10:25:33 +01:00
erew123 2f49f61645 Add files via upload 2024-04-04 10:16:30 +01:00
erew123 58a70caebc Update README.md 2024-04-04 01:58:04 +01:00
erew123 d0d470db0f Update README.md 2024-04-04 01:57:02 +01:00
erew123 068fc72346 Update README.md 2024-04-04 01:55:10 +01:00
erew123 fc5c8c748f Standalone reminder re scripts 2024-04-04 00:39:20 +01:00
erew123 24f86d08b7 Update README.md 2024-04-03 11:10:40 +01:00
erew123 99e402664c Update feature_request.md 2024-04-02 16:57:21 +01:00
erew123 24cf9eae59 Update bug-report-support-request.md 2024-04-02 16:56:43 +01:00
erew123 18b1582d2a Fix curl being funny on re-apply requirements 2024-04-02 16:16:10 +01:00
erew123 96d9df9438 Update README.md 2024-04-02 16:13:26 +01:00
erew123 4ca156a032 Waning/Documentation messages
Added a routine to both atsetups to warn about paths with spaces in them.
Added notes to finetune to make certain aspects clearer
Changed a note in readme
2024-04-02 13:39:08 +01:00
erew123 5aecb5b7fd Spelling/Colour correction 2024-04-01 15:24:20 +01:00
erew123 63c308ff05 Fix wav file deletion display 2024-04-01 14:52:31 +01:00
erew123 e6e4b0b47f Merge pull request #156 from erew123/dev
Dev to main
2024-04-01 13:55:59 +01:00
erew123 af4c63f1ee Update README.md 2024-04-01 13:53:10 +01:00
erew123 bedc8148ad Update README.md 2024-04-01 13:52:32 +01:00
erew123 21cd171719 Add files via upload 2024-04-01 13:11:09 +01:00
erew123 856c0c1baa Add files via upload 2024-04-01 13:04:24 +01:00
erew123 09977956f5 Tidy up model download message 2024-04-01 12:44:22 +01:00
erew123 2c7feb31e5 Add files via upload 2024-04-01 12:34:09 +01:00
erew123 cead53a808 Config file checker & clean start-up
Cleaned up the start-up screen & added mini diags
Added a config file updater that can be used to add/remove things from the confignew.json file if ever needed.
2024-04-01 12:28:32 +01:00
erew123 e7996ebc7a Add files via upload 2024-04-01 12:26:42 +01:00
erew123 6815ba0f2e Minor documentation update 2024-04-01 11:00:38 +01:00
erew123 51fa4ce9e9 Cleaner Start-up & mini diags
Updated various bits of code to clean up the AllTalk start-up messages.
2024-04-01 10:48:36 +01:00
erew123 043648e24a Merge pull request #155 from erew123/main
Pull from main to dev
2024-04-01 10:44:21 +01:00
erew123 b76ff028f8 Fixed DeepSpeed again (sorry)
Missed a digit off the Pytorch download and fluffed the version of DeepSpeed.
2024-04-01 03:05:27 +01:00
erew123 14214cc141 Update README.md 2024-03-30 10:48:13 +00:00
erew123 872638a198 Update README.md 2024-03-30 10:46:06 +00:00
erew123 5d2720c118 Update README.md 2024-03-30 10:44:29 +00:00
erew123 460216819a Update README.md 2024-03-29 22:36:10 +00:00
erew123 412d1442a6 Corrected DeepSpeed Path
Hopefully Github takes this file this time. It was changed/updated yesterday, but for whatever reason, the Github didnt have the updated version.
2024-03-29 21:42:23 +00:00
erew123 5a1dd31ab6 Add files via upload 2024-03-29 21:36:16 +00:00
erew123 ce84f153ca Update README.md 2024-03-29 13:07:14 +00:00
erew123 ab3570c899 Update README.md 2024-03-29 12:58:42 +00:00
erew123 42f08cd19c Update README.md 2024-03-29 02:34:22 +00:00
erew123 21fb1b58d9 Update README.md 2024-03-29 02:17:01 +00:00
erew123 d4741edf94 Update atsetup.bat
deepspeed version
2024-03-29 02:04:58 +00:00
erew123 e3c7144272 Update README.md 2024-03-29 01:54:05 +00:00
erew123 27a4fe2338 Update README.md 2024-03-29 01:15:12 +00:00
erew123 a0913db3c9 Update atsetup.sh 2024-03-29 00:43:47 +00:00
erew123 645c0d3a67 Update atsetup.bat
force pytorch upgrade
2024-03-29 00:42:54 +00:00
erew123 e3878b595b Update requirements_googlecolab.txt 2024-03-28 23:25:34 +00:00
erew123 825e4a7d12 Add files via upload 2024-03-28 23:14:02 +00:00
erew123 6c20f45154 Add files via upload 2024-03-28 21:51:42 +00:00
erew123 97cda27c7e Delete finetune/put-voice-samples-in-here directory 2024-03-28 21:51:11 +00:00
erew123 a075495a0a Large Update
TTS Generator - Various interface bugs & filtering options cleaned up.
TTS Generator - TTSDiff now scans generated text and TTS for errors.
TTS Generator - TTSSRT now creates subtitle files for video production e.g. a Youtube video.
Finetune - Now uses a customised tokenizer to deal with Japanese.
Finetune - Pre flight check and warning messages.
Finetune - Extra documentation and warnings.
Entire file structure has been re-organised to simplify management and future changes.
Documentation (built in and Github) has been rewritten/tidied up.
Requirements files have been cleaned up and simplified.
ATsetup has been re-written as necessary with additional options.
DeepSpeed moved up to version 14.
Standalone Application moved to PyTorch 2.2.1.
Nvidia CUDA Toolkit installation is NO LONGER needed (other than to compile DeepSpeed on Linux)

Tested on Linux and Windows.
2024-03-28 21:49:33 +00:00
erew123 b205657be3 Delete finetune/compact.py 2024-03-28 21:38:03 +00:00
erew123 483d6c8e79 Delete harvard_sentences.txt 2024-03-28 21:37:52 +00:00
erew123 9bd4665e6b Delete languages.json 2024-03-28 21:37:45 +00:00
erew123 62e1ab7e89 Delete requirements_other.txt 2024-03-28 21:37:35 +00:00
erew123 740c54db1c Delete requirements_nvidia.txt 2024-03-28 21:37:27 +00:00
erew123 e188467730 Delete requirements_finetune.txt 2024-03-28 21:37:12 +00:00
erew123 743f23240e Delete templates directory 2024-03-28 21:36:51 +00:00
erew123 66dadbca25 Finetune - further tidy up
Amended instructions.
Tidied up Pre-Flight check.
Added  dropdowns refresh button for step 3.
2024-03-25 14:09:35 +00:00
erew123 8125b46dbe Update README.md 2024-03-24 14:38:08 +00:00
erew123 d4bd46f203 Update README.md 2024-03-24 14:00:14 +00:00
erew123 f13d6d336b Update README.md 2024-03-24 11:37:33 +00:00
erew123 1fa2f2e110 Update README.md 2024-03-24 11:16:45 +00:00
erew123 9ad4005e52 Update bug-report-support-request.md 2024-03-23 23:06:59 +00:00
erew123 6d6b92d4b2 Update README.md 2024-03-23 12:18:09 +00:00
erew123 bf5d913cae Delete Deepspeed-Windows directory 2024-03-23 12:03:21 +00:00
erew123 f52ccd3931 Update README.md 2024-03-23 11:57:13 +00:00
erew123 37e7c8002d Update README.md 2024-03-22 17:23:12 +00:00
erew123 ad7382ee68 Update README.md 2024-03-22 14:53:28 +00:00
erew123 2428bfe357 Update README.md 2024-03-22 13:59:00 +00:00
erew123 74f3acc51f Update README.md
Large documentation update
2024-03-22 13:53:28 +00:00
erew123 90a98f140b Update ttsgencomp.py 2024-03-20 16:56:59 +00:00
erew123 885311ecd8 ttsgencomp added --threshold
gives a little flexibility to deal with words that sound the same when transcribed.
2024-03-20 16:28:15 +00:00
erew123 c2952e9758 Add files via upload 2024-03-20 15:50:02 +00:00
erew123 7e6e18c6d9 TTSGEN Compare - Work in progress
A BETA test/Proof of concept script to compare Speech that was generated in TTS Generator to the original Text and flag issues.

Anyone reading this, you are welcome to try it, the readme instructions are in the folder, however, I am not providing support on this while it is BETA/Proof of concept.
2024-03-20 15:26:36 +00:00
erew123 47eafafeda Update README.md 2024-03-19 12:35:15 +00:00
erew123 5edaab1356 Update README.md 2024-03-19 12:20:44 +00:00
erew123 7bde34d2ce Update README.md 2024-03-19 12:03:32 +00:00
erew123 0aa4638f68 Update README.md 2024-03-19 11:54:50 +00:00
erew123 22dd9c741c Update README.md 2024-03-19 11:51:03 +00:00
erew123 e000b8bb87 Update README.md 2024-03-19 11:10:00 +00:00
erew123 2d26f309df Update README.md 2024-03-19 11:06:04 +00:00
erew123 22d3e53a28 Update bug-report-support-request.md 2024-03-19 10:42:56 +00:00
erew123 0ea646dbf3 Update bug-report-support-request.md 2024-03-19 10:41:42 +00:00
erew123 282e3ce84c Update bug-report-support-request.md 2024-03-19 10:41:04 +00:00
erew123 772afd47a1 Update README.md 2024-03-19 10:11:29 +00:00
erew123 1612835c5d Update README.md 2024-03-19 09:55:50 +00:00
erew123 ea551d3a84 ID Playing reset on stop - corrected
Corrected the ID playing from resetting when the Stop button is pressed.
2024-03-17 12:51:41 +00:00
erew123 47001203cd Added DeepSpeed v14 for CUDA 11.8 w/PT 2.2.1 2024-03-16 13:21:25 +00:00
erew123 27ff5a12b0 Delete templates/tokenizer/__pycache__ directory 2024-03-16 11:16:01 +00:00
erew123 0a89407e4d Custom tokenizer for Japanese
Replaces the standard TTS tokenizer within Finetuning.
2024-03-16 11:15:01 +00:00
erew123 a579c5e6d2 Additional checks, documentation & tokenizer
Added warnings if PFC is not passed.
Added a custom tokenizer to better handle Japanese.
2024-03-16 11:14:07 +00:00
erew123 5a21d14672 Update atsetup.bat
TTS version updated to 0.22.0
2024-03-16 02:35:58 +00:00
erew123 f4f5f82bb0 Update atsetup.sh
TTS version updated to 0.22.0
2024-03-16 02:35:39 +00:00
erew123 7b03804f9e Finetune updated
Now uses TTS 0.22.0
Pre-flight check system & help documentation.
Cleaned up the interface a little
More yet to do re documentation.
2024-03-16 02:34:17 +00:00
erew123 f46493e6d8 Updated diagnostic checks
Added a few additional checks
Simplified screen output
Cleaned up log file output
2024-03-15 02:14:58 +00:00
erew123 2a64f6ad2b Merge pull request #127 from arthurwolf/arthurwolf-patch-2-clint-cleaned
Added a cleaned up version of the Clint Eastwood file.
2024-03-14 19:21:04 +00:00
erew123 3368f8b016 Merge pull request #126 from arthurwolf/patch-1
Add note about the project's rate.
2024-03-14 19:19:57 +00:00
Arthur Wolf 121585ae84 Update Clint_Eastwood CC3.txt to mention the updated file. 2024-03-14 14:53:40 +01:00
Arthur Wolf 3e6c11740d Uploading new version of the enhanced clint file, with correct bitrate.
Previous version of the file had wrong bitrate.
2024-03-14 14:51:06 +01:00
Arthur Wolf 6b111494b3 Delete voices/Clint_Eastwood CC3 (enhanced).wav
It had the wrong bitrate, replacing.
2024-03-14 14:50:35 +01:00
Arthur Wolf b376a27da2 Added a cleaned up version of the Clint Eastwood file.
As it's a derivative of the original file, it's automatically under the same license.
2024-03-14 14:42:41 +01:00
Arthur Wolf eeec4de703 Add note about the project's rate.
If this is not set correctly, the file will be saved as the incorrect rate despite the resampling (had to search docs for 30 minutes before solving this one...)
2024-03-14 14:07:45 +01:00
erew123 49f98033b3 Added a few extra notes to instructions 2024-03-13 20:15:40 +00:00
erew123 c1470930f4 Update README.md 2024-03-13 09:26:00 +00:00
erew123 1dec4f027b Added Windows DeepSpeed update for PyTorch 2.2.1 2024-03-12 11:34:35 +00:00
erew123 a9ef8edcb4 Update README.md 2024-03-11 13:33:01 +00:00
erew123 299238be7d Update README.md 2024-03-11 13:13:26 +00:00
erew123 29c7ea1526 Update README.md 2024-03-11 13:00:33 +00:00
erew123 e974e14a10 Links update
Just a minor update to make the links to TTS generator dynamic
2024-03-11 12:51:56 +00:00
erew123 59c654bacd Update README.md 2024-03-11 12:21:58 +00:00
erew123 969b4e3f46 Text-gen-webui - SD Image filtering
AllTalk will now strip any image from TTS and re-add the image data after TTS. 

This is so that when used with Stable Diffusion Image generation within Text-generation-webui, AllTalk isnt trying to generate the Image data as TTS.
2024-03-11 11:22:50 +00:00
erew123 86c64fc9ba Documentation & Japanese support
Improved some areas of the documentation to clarify some issues.
Dropped worker threads down ONLY when Japanese is used, due to limitations of the translation.
2024-03-10 15:17:31 +00:00
erew123 b8c0db6f56 Merge pull request #114 from johnbenac/16_to_32_for_1070
Made compatible with older GPUs (1070)
2024-03-10 15:12:42 +00:00
erew123 57982cb810 Update README.md 2024-03-10 14:54:47 +00:00
erew123 6387007f56 Update README.md 2024-03-10 14:53:26 +00:00
erew123 cdf8d695e2 Update README.md 2024-03-10 14:45:20 +00:00
erew123 833bf3da4f Update README.md 2024-03-10 13:52:41 +00:00
erew123 f68086db0b Update requirements_finetune.txt 2024-03-10 11:58:27 +00:00
johnbenac 1f7842ef5a Made compatible with older GPUs (1070) 2024-03-09 20:42:01 -05:00
97 changed files with 11082 additions and 9035 deletions

No files matched your search

@@ -1,13 +1,14 @@
---
name: Bug report/Support request
about: Create a report to help us improve
name: Support Request/Issue
about: Use this to create a support request or report a bug/issue
title: ''
labels: ''
assignees: ''
---
🔴 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
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+4 -1
View File
@@ -1,12 +1,15 @@
---
name: Feature request
about: Suggest an idea for this project
about: Use this to create a Feature request
title: ''
labels: ''
assignees: ''
---
**Please confirm you have read the current Features request list**
https://github.com/erew123/alltalk_tts/discussions/74
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+73
View File
@@ -0,0 +1,73 @@
name: 'Setting up docker'
inputs:
DOCKERHUB_USERNAME:
description: "Docker hub username"
required: true
DOCKERHUB_REPO_NAME:
description: "Docker hub repo name"
required: true
DOCKERHUB_TOKEN:
description: "Docker hub token"
required: true
runs:
using: "composite"
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: true
swap-storage: false
large-packages: false
- name: Read variables
shell: bash
run: |
source ./docker/variables.sh
for key in "${!ALLTALK_VARS[@]}"
do
echo "${key}=${ALLTALK_VARS[${key}]}"
echo "${key}=${ALLTALK_VARS[${key}]}" >> $GITHUB_ENV
done
- name: Extract version from Git Tag
shell: bash {0}
run: |
# Use the git tag if existing, otherwise 'latest':
DOCKER_TAG=$( echo "${{ github.ref }}" | grep -q tags | cut -d'/' -f 3 )
if [ -z "${DOCKER_TAG}" ]; then
DOCKER_TAG="latest"
fi
echo "Using DOCKER_TAG=${DOCKER_TAG}"
echo "DOCKER_TAG=${DOCKER_TAG}" >> $GITHUB_ENV
- name: Extract Docker Hub User and Repo Name
shell: bash
env:
DOCKERHUB_USERNAME: ${{ inputs.DOCKERHUB_USERNAME }}
DOCKERHUB_REPO_NAME: ${{ inputs.DOCKERHUB_REPO_NAME }}
run: |
if [ -n "${DOCKERHUB_USERNAME}" ]; then
echo "Using Github repository variable 'DOCKERHUB_USERNAME' as Docker hub username with value: '${DOCKERHUB_USERNAME}'"
echo "DOCKERHUB_USERNAME=${DOCKERHUB_USERNAME}" >> $GITHUB_ENV
else
echo "Using Github repository name as Docker hub username"
echo "DOCKERHUB_USERNAME=$(echo ${{ github.repository }} | cut -d'/' -f 1)" >> $GITHUB_ENV
fi
if [ -n "${DOCKERHUB_REPO_NAME}" ]; then
echo "Using Github repository variable 'DOCKERHUB_REPO_NAME' as Docker hub repo name with value: '${DOCKERHUB_REPO_NAME}'"
echo "DOCKERHUB_REPO_NAME=${DOCKERHUB_REPO_NAME}" >> $GITHUB_ENV
else
echo "Using Github repository name as Docker hub repo name"
echo "DOCKERHUB_REPO_NAME=$(echo ${{ github.repository }} | cut -d'/' -f 2)" >> $GITHUB_ENV
fi
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ inputs.DOCKERHUB_USERNAME }}
password: ${{ inputs.DOCKERHUB_TOKEN }}
+124
View File
@@ -0,0 +1,124 @@
name: Publish Docker v2
on:
workflow_dispatch:
release:
types: [ published ]
push:
branches:
- 'alltalkbeta'
tags:
- 'v*'
# Limit the concurrency of entire workflow runs for a specific branch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build_base_environment_docker_image:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup docker
uses: ./.github/actions/docker-setup
with:
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
DOCKERHUB_REPO_NAME: ${{ vars.DOCKERHUB_REPO_NAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}_environment
tags: |
# Use sematic versioning on push tag event:
type=semver,pattern={{version}}
# set latest tag for main and alltalkbeta branch:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') || github.ref == format('refs/heads/{0}', 'alltalkbeta') }}
- uses: dorny/paths-filter@v3
id: changes
with:
base: 'alltalkbeta'
filters: |
docker-base:
- 'docker/variables.sh'
- 'docker/base/Dockerfile'
docker-workflow:
- '.github/workflows/publish-docker*.yml'
- name: Build and push base Docker image
if: |
steps.changes.outputs.docker-base == 'true' ||
steps.changes.outputs.docker-workflow == 'true' ||
github.event_name == 'release' ||
(github.event_name == 'push' && contains(github.ref, 'refs/tags/'))
uses: docker/build-push-action@v6
with:
context: ./docker/base
file: ./docker/base/Dockerfile
platforms: "linux/amd64"
push: true
build-args: |
CUDA_VERSION=${{ env.CUDA_VERSION }}
PYTHON_VERSION=${{ env.PYTHON_VERSION }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}_environment:buildcache
cache-to: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}_environment:buildcache,mode=max
build_main_docker_image:
needs: build_base_environment_docker_image
runs-on: ubuntu-latest
strategy:
matrix:
tts: [ xtts, vits, piper ]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup docker
uses: ./.github/actions/docker-setup
with:
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
DOCKERHUB_REPO_NAME: ${{ vars.DOCKERHUB_REPO_NAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}
flavor: |
suffix=-${{ matrix.tts }},onlatest=true
tags: |
# Use sematic versioning on push tag event:
type=semver,pattern={{version}}
# set latest tag for main and alltalkbeta branch:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') || github.ref == format('refs/heads/{0}', 'alltalkbeta') }}
- name: Build and push base Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: "linux/amd64"
push: true
build-args: |
TTS_MODEL=${{ matrix.tts }}
ALLTALK_DIR=${{ env.ALLTALK_DIR }}
DEEPSPEED_VERSION=${{ env.DEEPSPEED_VERSION }}
DOCKER_TAG=${{ env.DOCKER_TAG }}
DOCKER_REPOSITORY=${{ env.DOCKERHUB_USERNAME }}/
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}:buildcache-${{ matrix.tts }}
cache-to: type=registry,ref=${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_REPO_NAME }}:buildcache-${{ matrix.tts }},mode=max
+3 -3
View File
@@ -1,8 +1,8 @@
name: Publish Docker image
name: Publish Docker image (main branch)
on:
push:
branches: [main]
# push:
# branches: [main]
release:
types: [published]
workflow_dispatch:
+53
View File
@@ -0,0 +1,53 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
name: Python CI
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11.9
uses: actions/setup-python@v3
if: ${{ hashFiles('./test') != '' }}
with:
python-version: "3.11.9"
- name: Install dependencies
if: ${{ hashFiles('./test') != '' }}
run: |
python -m pip install --upgrade pip
if [ -f system/requirements/requirements_unit_test.txt ]; then
pip install -r system/requirements/requirements_unit_test.txt;
fi
- name: Test with pytest
if: ${{ hashFiles('./test') != '' }}
run: |
pytest test --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
- name: Surface failing tests
if: always()
uses: pmeier/pytest-results-action@v0.6.0
with:
# A list of JUnit XML files, directories containing the former, and wildcard
# patterns to process.
# See @actions/glob for supported patterns.
path: junit/test-results.xml
# (Optional) Add a summary of the results at the top of the report
summary: true
# (Optional) Select which results should be included in the report.
# Follows the same syntax as `pytest -r`
display-options: fEX
# (Optional) Fail the workflow if no JUnit XML was found.
fail-on-empty: false
# (Optional) Title of the test results section in the workflow summary
title: Test results
@@ -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);
}
File diff suppressed because it is too large. Load diff
@@ -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);
}
File diff suppressed because it is too large. Load diff
@@ -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()
-18
View File
@@ -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
+11 -3
View File
@@ -1,12 +1,20 @@
FROM ubuntu:22.04
FROM nvidia/cuda:12.1.1-devel-ubuntu22.04
ENV HOST 0.0.0.0
RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y git build-essential portaudio19-dev \
python3 python3-pip gcc wget \
ocl-icd-opencl-dev opencl-headers clinfo \
libclblast-dev libopenblas-dev libaio-dev \
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
&& ln -s /usr/bin/python3 /usr/bin/python
WORKDIR /app
ENV CUDA_DOCKER_ARCH=all
COPY system/requirements/requirements_docker.txt system/requirements/requirements_docker.txt
RUN pip install --no-cache-dir --no-deps -r system/requirements/requirements_docker.txt && \
pip install --no-cache-dir deepspeed
COPY . .
RUN pip install --no-cache-dir -r requirements_other.txt
EXPOSE 7851
EXPOSE 7851 7852
RUN chmod +x launch.sh
ENTRYPOINT ["sh", "-c", "./launch.sh"]
+1484 -967
View File
File diff suppressed because it is too large. Load diff
+285 -130
View File
@@ -1,7 +1,7 @@
@echo off
cd /D "%~dp0"
set PATH=%PATH%;%SystemRoot%\system32
setlocal enabledelayedexpansion
@set "PATH=%PATH%;%SystemRoot%\system32"
:: Generate the ESC character
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
@@ -25,6 +25,15 @@ set "L_CYAN=%ESC%[96m"
set "L_WHITE=%ESC%[97m"
set "RESET=%ESC%[0m"
echo "%CD%"| findstr /C:" " >nul && echo. && echo %L_BLUE%ALLTALK WINDOWS SETUP UTILITY%RESET% && echo. && echo. && echo You are trying to install AllTalk in a folder that has a space in the folder path e.g. && echo. && echo C:\%L_RED%program files%RESET%\alltalk_tts && echo. && echo This causes errors with Conda and Python scripts. Please follow this link for reference: && echo. && echo %L_CYAN%https://docs.anaconda.com/free/working-with-conda/reference/faq/#installing-anaconda%RESET% && echo. && echo Please use a folder path that has no spaces in it e.g. && echo. && echo C:\myfiles\alltalk_tts\ && echo. && echo. && pause && goto :end
@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 Check if curl is available
curl --version >nul 2>&1
if "%ERRORLEVEL%" NEQ "0" (
@@ -61,28 +70,36 @@ echo environment. If you have NOT done this, please run %L_GREEN%cmd_windows.
echo in the %L_GREEN%text-generation-webui%RESET% folder and then re-run this script.
echo.
echo BASE REQUIREMENTS
echo 1) Install the requirements for a %L_GREEN%Nvidia machine%RESET%.
echo 2) Install the requirements for a %L_GREEN%AMD or MAC machine%RESET%.
echo 1) Apply/Re-Apply the requirements for %L_GREEN%Text-generation-webui%RESET%.
echo.
echo OPTIONAL
echo 3) Install the Finetuning requirements.
echo 4) Install DeepSpeed v11.2 for CUDA %L_GREEN%11.8%RESET% and Python-3.11.x.
echo 5) Install DeepSpeed v11.2 for CUDA %L_GREEN%12.1%RESET% and Python-3.11.x.
echo 6) Uninstall DeepSpeed.
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 7) Generate a diagnostics file.
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 InstallOtherTextGen
if "%WebUIOption%"=="3" goto InstallFinetuneTextGen
if "%WebUIOption%"=="2" goto TGGitpull
if "%WebUIOption%"=="4" goto InstallDeepSpeed118TextGen
if "%WebUIOption%"=="5" goto InstallDeepSpeed121TextGen
if "%WebUIOption%"=="6" goto UnInstallDeepSpeed
if "%WebUIOption%"=="7" goto GenerateDiagsTextGen
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
@@ -95,27 +112,33 @@ echo BASE REQUIREMENTS
echo 1) Install AllTalk as a Standalone Application
echo.
echo OPTIONAL
echo 2) Delete AllTalk's custom Python environment
echo 3) Install the Finetuning requirements
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 4) Generate a diagnostics file
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 DeleteCustomStandalone
if "%StandaloneOption%"=="3" goto InstallFinetuneStandalone
if "%StandaloneOption%"=="4" goto GenerateDiagsStandalone
if "%StandaloneOption%"=="9" goto End
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 EndStandalone
goto StandaloneMenu
:InstallNvidiaTextGen
pip install -r requirements_nvidia.txt
pip install -r system\requirements\requirements_textgen.txt
if %ERRORLEVEL% neq 0 (
echo.
echo There was an error installing the Nvidia requirements.
echo There was an error installing the requirements.
echo Have you started your Text-gen-webui Python environment
echo with cmd_{yourOS} before running atsetup.bat?
echo Press any key to return to the menu.
echo.
pause
@@ -123,46 +146,28 @@ if %ERRORLEVEL% neq 0 (
)
Echo.
echo.
Echo Nvidia machine requirements installed successfully.
Echo Requirements installed successfully.
Echo.
pause
goto WebUIMenu
:InstallOtherTextGen
pip install -r requirements_other.txt
:TGGitpull
git pull
if %ERRORLEVEL% neq 0 (
echo.
echo There was an error installing the Other requirements.
echo.
echo There was an error pulling from Github.
echo Press any key to return to the menu.
echo.
pause
goto WebUIMenu
)
Echo.
echo.
Echo Other machine requirements installed successfully.
echo AllTalk Updated from Github. Please re-apply
echo the latest requirements file. Option 1
Echo.
pause
goto WebUIMenu
:InstallFinetuneTextGen
pip install -r requirements_finetune.txt
if %ERRORLEVEL% neq 0 (
echo.
echo There was an error installing the Finetune requirements.
echo Press any key to return to the menu.
echo.
pause
goto WebUIMenu
)
Echo.
Echo Finetune requirements installed successfully. Please ensure you have installed CUDA 11.8.
Echo Finetune needs access to %L_GREEN%cublas64_11.dll%RESET% and will error if this is not setup correctly.
Echo Please see here for details %L_GREEN%https://github.com/erew123/alltalk_tts#-finetuning-a-model%RESET%
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
@@ -227,6 +232,70 @@ 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 (
@@ -320,49 +389,20 @@ if not exist "%INSTALL_ENV_DIR%\python.exe" ( echo. && echo Conda environment is
@rem activate installer env
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" || ( echo. && echo Miniconda hook not found. && goto end )
@rem Ask user for the type of requirements to install
echo.
echo %L_BLUE%Choose the type of requirements to install%RESET%
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.
echo 1. Nvidia graphics card machines
echo 2. Other machines (mac, amd, etc)
pip install torch==2.2.2+cu121 torchaudio>=2.2.2+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
echo Installing other requirements.
echo.
set /p UserChoice="Enter your choice (1 or 2): "
pip install -r system\requirements\requirements_standalone.txt
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
echo Installing DeepSpeed...
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
@rem Install requirements based on user choice
if "%UserChoice%" == "1" (
echo.
echo Installing Nvidia requirements...
echo Downloading Pytorch with CUDA..
pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cu121
pip install numpy==1.24.4
pip install typing-extensions>=4.8.0
pip install networkx<3.0.0,>=2.5.0
pip install fsspec>=2023.6.0
pip install soundfile==0.12.1
pip install uvicorn==0.24.0.post1
pip install transformers>=4.37.1
pip install TTS==0.21.3
pip install fastapi==0.104.1
pip install Jinja2==3.1.2
pip install requests==2.31.0
pip install tqdm==4.66.1
pip install importlib-metadata==4.8.1
pip install packaging==23.2
pip install pydantic==1.10.13
pip install sounddevice==0.4.6
pip install python-multipart==0.0.6
pip install cutlet>=0.3.0
pip install unidic-lite>=1.0.8
echo Downloading DeepSpeed...
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
) else (
echo Installing requirements for other machines...
pip install -r requirements_other.txt
)
@rem Create start_environment.bat to run AllTalk environment
echo @echo off > start_environment.bat
@@ -377,14 +417,22 @@ 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 start_alltalk.bat has been created.
Echo You can now start AllTalk with %L_YELLOW%start_alltalk.bat%RESET%
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
:DeleteCustomStandalone
:STDeleteCustomStandalone
@rem Check if the alltalk_environment directory exists
if not exist "%cd%\alltalk_environment\" (
echo.
@@ -418,47 +466,6 @@ Echo.
pause
goto StandaloneMenu
:InstallFinetuneStandalone
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 Proceed with installing requirements
pip install -r requirements_finetune.txt
if %ERRORLEVEL% neq 0 (
echo.
echo There was an error installing the Finetune requirements.
echo Press any key to return to the menu.
echo.
pause
goto StandaloneMenu
)
Echo.
Echo Finetune requirements installed successfully. Please ensure you have installed CUDA 11.8.
Echo Finetune needs access to %L_GREEN%cublas64_11.dll%RESET% and will error if this is not setup correctly.
Echo Please see here for details %L_GREEN%https://github.com/erew123/alltalk_tts#-finetuning-a-model%RESET%
Echo.
pause
goto StandaloneMenu
:GenerateDiagsStandalone
cd /D "%~dp0"
set CONDA_ROOT_PREFIX=%cd%\alltalk_environment\conda
@@ -499,6 +506,154 @@ 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.2+cu121 torchaudio>=2.2.2+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
echo Installing other requirements.
echo.
pip install -r system\requirements\requirements_standalone.txt
C:/Windows/system32/curl.exe -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
echo Installing DeepSpeed...
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
if %ERRORLEVEL% neq 0 (
echo.
echo There was an error.
echo Press any key to return to the menu.
echo.
pause
goto StandaloneMenu
)
Echo.
Echo.
Echo Requirements have been re-applied/updated.
Echo.
pause
goto 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
:EndStandalone
echo Exiting AllTalk Setup Utility...
echo.
Echo Remember, after installation you can....
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.
exit /b
:End
echo Exiting AllTalk Setup Utility...
exit /b
+188 -111
View File
@@ -28,6 +28,40 @@ check_curl() {
fi
}
# Check if the current directory path contains a space
containsSpace=false
currentPath=$(pwd)
if echo "$currentPath" | grep -q ' '; then
containsSpace=true
fi
if [ "$containsSpace" = true ]; then
echo
echo -e " ${L_BLUE}ALLTALK LINUX SETUP UTILITY${NC}"
echo
echo
echo -e " You are trying to install AllTalk in a folder that has a space in the"
echo -e " folder path e.g."
echo
echo -e " /home/${L_RED}program files${NC}/alltalk_tts"
echo
echo -e " This causes errors with Conda and Python scripts. Please follow this"
echo -e " link for reference:"
echo
echo -e " ${L_CYAN}https://docs.anaconda.com/free/working-with-conda/reference/faq/#installing-anaconda${NC}"
echo
echo -e " Please use a folder path that has no spaces in it e.g."
echo
echo -e " /home/myfiles/alltalk_tts/"
echo
echo
read -p "Press Enter to continue..."
exit 1
else
# Continue with the main menu
echo "Continue with the main menu."
fi
# Main Menu
main_menu() {
while true; do
@@ -64,11 +98,12 @@ webui_menu() {
echo -e " in the ${L_GREEN}text-generation-webui${NC} folder and then re-run this script."
echo
echo " BASE REQUIREMENTS"
echo -e " 1) Install the AllTalk requirements for an ${L_GREEN}Nvidia GPU machine.${NC}"
echo -e " 2) Install the AllTalk requirements for an ${L_GREEN}AMD or MAC machine.${NC}"
echo -e " 1) Apply/Re-Apply the requirements for an ${L_GREEN}Text-generation-webui${NC}"
echo
echo " OPTIONAL"
echo " 3) Install the Finetuning requirements."
echo " 2) Git Pull the latest AllTalk updates from Github"
echo
echo " DEEPSPEED"
echo " 4) Install DeepSpeed."
echo " 5) Uninstall DeepSpeed."
echo
@@ -81,8 +116,7 @@ webui_menu() {
case $webui_option in
1) install_nvidia_textgen ;;
2) install_other_textgen ;;
3) install_finetune_textgen ;;
2) tg_gitpull ;;
4) install_deepspeed ;;
5) uninstall_deepspeed ;;
6) generate_diagnostics_textgen ;;
@@ -93,52 +127,40 @@ webui_menu() {
}
install_nvidia_textgen() {
local requirements_file="requirements_nvidia.txt"
echo " Installing Finetune requirements from $requirements_file..."
local requirements_file="system/requirements/requirements_textgen.txt"
echo " Installing Requirements from $requirements_file..."
if ! pip install -r "$requirements_file"; then
echo " There was an error installing the Nvidia requirements."
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 " Nvidia requirements installed successfully."
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
}
install_other_textgen() {
local requirements_file="requirements_other.txt"
echo " Installing Other machine requirements from $requirements_file..."
if ! pip install -r "$requirements_file"; then
echo " There was an error installing the Other requirements."
echo " Please check the output for details."
read -p " Press any key to return to the menu. " -n 1
echo
return
fi
echo " Other machine requirements installed successfully."
read -p " Press any key to continue. " -n 1
tg_gitpull() {
echo
}
install_finetune_textgen() {
local requirements_file="requirements_finetune.txt"
echo " Installing Finetune requirements from $requirements_file..."
if ! pip install -r "$requirements_file"; then
echo " There was an error installing the Finetune requirements."
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 " Finetune base requirements installed successfully."
echo
echo -e " Finetuning requires access to ${GREEN}Cublas${NC} from the ${GREEN}Nvidia CUDA Toolkit${NC}, so will need installing."
echo
echo -e " Instructions can be found here:"
echo -e " ${GREEN}https://github.com/erew123/alltalk_tts?#-finetuning-a-model${NC}"
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
@@ -185,12 +207,16 @@ 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
}
@@ -198,13 +224,17 @@ uninstall_deepspeed() {
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 " Diagnostics completed successfully."
echo
echo " Diagnostics log file generated successfully."
echo " Please see diagnostics.log"
echo
read -p " Press any key to continue. " -n 1
echo
}
@@ -220,12 +250,16 @@ standalone_menu() {
echo " 1) Install AllTalk as a Standalone Application"
echo
echo " OPTIONAL"
echo " 2) Delete AllTalk's custom Python environment"
echo " 3) Install the Finetuning requirements"
echo " 4) Install DeepSpeed."
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 " 5) Generate a diagnostics file"
echo " 8) Generate a diagnostics file"
echo
echo -e " 9)${L_RED} Exit/Quit${NC}"
echo
@@ -233,16 +267,19 @@ standalone_menu() {
case $standalone_option in
1) install_custom_standalone ;;
2) delete_custom_standalone ;;
3) install_finetune_standalone ;;
4) install_deepspeed ;;
5) generate_diagnostics_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]}")"
@@ -284,39 +321,15 @@ install_custom_standalone() {
# Activate the environment and install requirements
source "${CONDA_ROOT_PREFIX}/etc/profile.d/conda.sh"
conda activate "${INSTALL_ENV_DIR}"
echo
echo -e " ${L_BLUE}Choose the type of requirements to install${NC}"
echo " Downloading and installing PyTorch. This step can take a long time"
echo " depending on your internet connection and hard drive speed. Please"
echo " be patient."
pip install torch==2.2.1+cu121 torchaudio==2.2.1+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
echo
echo " 1. Nvidia graphics card machines"
echo " 2. Other machines (mac, amd, etc)"
echo " Installing additional requirements."
echo
read -p " Enter your choice (1 or 2): " user_choice
if [ "$user_choice" == "1" ]; then
pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cu121
pip install numpy==1.24.4
pip install typing-extensions>=4.8.0
pip install networkx<3.0.0,>=2.5.0
pip install fsspec>=2023.6.0
pip install soundfile==0.12.1
pip install uvicorn==0.24.0.post1
pip install transformers>=4.37.1
pip install TTS==0.21.3
pip install fastapi==0.104.1
pip install Jinja2==3.1.2
pip install requests==2.31.0
pip install tqdm==4.66.1
pip install importlib-metadata==4.8.1
pip install packaging==23.2
pip install pydantic==1.10.13
pip install sounddevice==0.4.6
pip install python-multipart==0.0.6
pip install cutlet>=0.3.0
pip install unidic-lite>=1.0.8
else
pip install -r requirements_other.txt
fi
pip install -r system/requirements/requirements_standalone.txt
# Create start_environment.sh to run AllTalk
cat << EOF > start_environment.sh
#!/bin/bash
@@ -333,27 +346,42 @@ 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 " start_alltalk.sh has been created."
echo -e " You can now start AllTalk with ${L_YELLOW}./start_alltalk.sh${NC}"
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
@@ -380,47 +408,15 @@ delete_custom_standalone() {
echo
}
install_finetune_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 " The Conda environment at '${install_env_dir}' does not exist."
echo " Please install the environment before proceeding."
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}"
local requirements_file="requirements_finetune.txt"
echo "Installing Finetune requirements from $requirements_file..."
if ! pip install -r "$requirements_file"; then
echo " There was an error installing the Finetune requirements."
echo " Please check the output for details."
read -p " Press any key to return to the menu. " -n 1
echo
return
fi
echo
echo " Finetune base requirements installed successfully."
echo
echo -e " Finetuning requires access to ${GREEN}Cublas${NC} from the ${GREEN}Nvidia CUDA Toolkit${NC}, so will need installing."
echo
echo -e " Instructions can be found here:"
echo -e " ${GREEN}https://github.com/erew123/alltalk_tts?#-finetuning-a-model${NC}"
echo
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
@@ -428,16 +424,97 @@ generate_diagnostics_standalone() {
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 --upgrade --force-reinstall --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
+122 -36
View File
@@ -8,12 +8,15 @@ try:
import re
import sys
import glob
import site
import textwrap
import torch
import packaging.version
import packaging.specifiers
from packaging.specifiers import SpecifierSet
from packaging.specifiers import SpecifierSet
from packaging.version import parse as parse_version
from pathlib import Path
except ImportError as e:
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")
@@ -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")
exit(1)
this_dir = Path(__file__).parent
try:
import psutil
except ImportError:
@@ -29,24 +34,30 @@ except ImportError:
import psutil
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:
print("\033[91mNo requirements files found.\033[0m")
return None
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):
print(f"{i}. {file}")
for i, file_path in enumerate(requirements_files, start=1):
print(f" {i}. {file_path.name}") # Only print the filename
choice = input("\nEnter the number of your choice: ")
try:
choice = int(choice) - 1
return requirements_files[choice]
return str(requirements_files[choice]) # Return the full path as a string
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'
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
def get_gpu_info():
@@ -55,6 +66,22 @@ def get_gpu_info():
return result.stdout
except FileNotFoundError:
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
def is_port_in_use(port):
@@ -73,6 +100,38 @@ def satisfies_wildcard(installed_version, required_version):
return True
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
def log_system_info():
# System information
@@ -88,6 +147,9 @@ def log_system_info():
# 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
try:
@@ -123,6 +185,10 @@ def log_system_info():
search_path = sys.path
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
requirements_file = get_requirements_file()
if requirements_file:
@@ -146,52 +212,72 @@ def log_system_info():
logging.info(f"NOTE {requirements_file} not found. Skipping version checks.")
# Log and print information
logging.info(f"OS Version: {os_version}")
logging.info(f"Note: Windows 11 will list as build is 10.x.22xxx")
logging.info(f"Torch Version: {torch_version}")
logging.info(f"System RAM: {system_ram}")
logging.info(f"CUDA_HOME: {cuda_home}")
logging.info(f"Port Status: {port_status}")
logging.info(f"Python Version: {platform.python_version()}")
logging.info(f"Python Version Info: {python_version_info}")
logging.info(f"Python Executable: {python_executable}")
logging.info(f"Python Virtual Environment: {python_virtual_env} (Should be N/A when in Text-generation-webui Conda Python environment)")
logging.info(f"Conda Environment: {conda_env}")
logging.info(f"OPERATING SYSTEM:")
logging.info(f" OS Version: {os_version}")
logging.info(f" Note: Windows 11 will list as build is 10.x.22xxx")
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"\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("\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 Info: {python_version_info}")
logging.info(f" Python Executable: {python_executable}")
logging.info(f" Python Virtual Environment: {python_virtual_env} (Should be N/A when in Text-generation-webui Conda Python environment)")
logging.info(f" Conda Environment: {conda_env}")
logging.info("\nPython Search Path:")
for path in search_path:
logging.info(f" {path}")
logging.info("\nOS PATH Environment Variable:")
logging.info("\nOS SEARCHPATH ENVIRONMENT:")
for path in path_env.split(';'):
logging.info(f" {path}")
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())
for package_name, (operator, required_version) in required_packages.items():
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"GPU Information:\n{gpu_info}")
logging.info("Package Versions:")
logging.info(f" {package_name.ljust(max_package_length)} Required: {operator} {required_version.ljust(12)} Installed: {installed_version}")
logging.info("\nPYTHON PACKAGES:")
for package, version in package_versions.items():
logging.info(f"{package}>= {version}")
logging.info(f" {package}>= {version}")
# Print to screen
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[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[94mPort Status:\033[0m \033[92m{port_status}\033[0m")
print(f"\033[94mTorch Version:\033[0m \033[92m{torch_version}\033[0m")
for disk in disk_info:
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 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 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"\n\033[94mPython Search Path:\033[0m")
for path in search_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
print("\033[94m\nRequirements file package comparison:\033[0m")
max_package_length = max(len(package) for package in required_packages.keys())
@@ -214,7 +300,7 @@ def log_system_info():
color_installed = "\033[92m" if condition_met else "\033[91m"
# 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")
@@ -231,9 +317,9 @@ def log_system_info():
""")
print(explanation.strip())
print("")
print(f"GPU Information:{gpu_info}")
print(f"\033[94mDiagnostic log created:\033[0m \033[92mdiagnostics.log\033[0m")
print(f"\033[94mPlease upload the log file with any support ticket.\033[0m")
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[94mscreen. Please see the log file for more detail.\033[0m")
print(f"\033[94m\nPlease upload the log file with any support ticket.\033[0m")
if __name__ == "__main__":
log_system_info()
log_system_info()
+15 -1
View File
@@ -1,13 +1,27 @@
version: '3.8'
services:
alltalk-tts:
image: erew123/alltalk_tts:cpu
image: ${IMAGE:-alltalk:v1-9c}
restart: unless-stopped
ports:
- "7851:7851"
- "7852:7852"
volumes:
- ./outputs:/app/outputs/
- ./models:/app/models/
- ./voices:/app/voices/
- ./finetune/put-voice-samples-in-here:/app/finetune/put-voice-samples-in-here
- ./dockerconfig.json:/app/confignew.json
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:7851/api/ready"]
interval: 1m30s
timeout: 30s
retries: 5
start_period: 30s
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [ gpu ]
+821 -294
View File
File diff suppressed because it is too large. Load diff
-26
View File
@@ -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.")
+102 -54
View File
@@ -1,10 +1,13 @@
import os
import sys
from pathlib import Path
import requests
from requests.exceptions import ConnectionError
from tqdm import tqdm
import importlib.metadata as metadata
import json
from packaging import version
from datetime import datetime
#################################################################
#### LOAD PARAMS FROM confignew.json - REQUIRED FOR BRANDING ####
@@ -12,14 +15,12 @@ from packaging import version
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
this_dir = Path(__file__).parent.resolve()
# load standard config file in and get settings
def load_config(file_path):
with open(file_path, "r") as config_file:
config = json.load(config_file)
return config
config_file_path = this_dir / "confignew.json"
params = load_config(config_file_path)
@@ -37,34 +38,26 @@ if modeldownload_config_file_path.exists():
files_to_download = settings.get("files_to_download", {})
else:
# Default settings if the JSON file doesn't exist or is empty
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m modeldownload.json is missing so please re-download it and save it in the coquii_tts main folder."
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m API Local and XTTSv2 Local will error unless this is corrected."
)
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m modeldownload.json is missing so please re-download it and save it in the coquii_tts main folder.")
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m API Local and XTTSv2 Local will error unless this is corrected.")
# Read the version specifier from requirements_nvidia.txt
with open(this_dir / "requirements_nvidia.txt", "r") as req_file:
with open(this_dir / "system" / "requirements" / "requirements_standalone.txt", "r") as req_file:
requirements = req_file.readlines()
tts_version_required = None
for req in requirements:
if req.startswith("TTS>="):
tts_version_required = req.strip().split(">=")[1]
if req.startswith("TTS=="):
tts_version_required = req.strip().split("==")[1]
break
if tts_version_required is None:
raise ValueError(
f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements_nvidia.txt"
)
raise ValueError(f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements file")
def create_directory_if_not_exists(directory):
if not directory.exists():
directory.mkdir(parents=True)
def download_file(url, destination):
response = requests.get(url, stream=True)
total_size_in_bytes = int(response.headers.get("content-length", 0))
@@ -83,63 +76,118 @@ def download_file(url, destination):
def check_tts_version():
try:
tts_version = metadata.version("tts")
print(
f"[{params['branding']}Startup] TTS version installed: \033[93m"
+ tts_version
+ "\033[0m"
)
print(f"[{params['branding']}Startup] \033[92mCurrent TTS Version : \033[93m"+tts_version+"\033[0m")
if version.parse(tts_version) < version.parse(tts_version_required):
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS version is too old. Please upgrade to version \033[93m"
+ tts_version_required
+ "\033[0m or later.\033[0m"
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m At your terminal/command prompt \033[94mpip install --upgrade tts\033[0m"
)
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS version is too old. Please upgrade to version \033[93m"+tts_version_required+"\033[0m or later.\033[0m")
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m At your terminal/command prompt \033[94mpip install --upgrade tts\033[0m")
else:
print(f"[{params['branding']}Startup] TTS version is up to date.")
print(f"[{params['branding']}Startup] \033[92mCurrent TTS Version is :\033[93m Up to date\033[0m")
except metadata.PackageNotFoundError:
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS is not installed."
)
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS is not installed")
def check_torch_version():
import torch
pytorch_version = torch.__version__
cuda_version = torch.version.cuda
major, minor, micro = sys.version_info[:3]
python_version = f"{major}.{minor}.{micro}"
print(f"[{params['branding']}Startup] \033[92mCurrent Python Version :\033[93m {python_version}\033[0m")
print(f"[{params['branding']}Startup] \033[92mCurrent PyTorch Version:\033[93m {pytorch_version}\033[0m")
if cuda_version is None:
print(f"[{params['branding']}Startup] \033[92mCurrent CUDA Version :\033[91m CUDA is not available\033[0m")
else:
print(f"[{params['branding']}Startup] \033[92mCurrent CUDA Version :\033[93m {cuda_version}\033[0m")
def ordinal(n):
return "%d%s" % (n, "th" if 4 <= n % 100 <= 20 else {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th"))
def format_datetime(iso_str):
# Parse the ISO 8601 string to datetime
dt = datetime.strptime(iso_str, "%Y-%m-%dT%H:%M:%SZ")
# Format the datetime into a more readable string
return dt.strftime(f"{ordinal(dt.day)} %B %Y at %H:%M")
def fetch_latest_commit_sha_and_date(owner, repo):
url = f"https://api.github.com/repos/{owner}/{repo}/commits"
try:
response = requests.get(url)
if response.status_code == 200:
latest_commit = response.json()[0]
latest_commit_sha = latest_commit['sha']
latest_commit_date = latest_commit['commit']['committer']['date']
return latest_commit_sha, latest_commit_date
else:
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[91m Failed to fetch the latest commits due to an unexpected response from GitHub")
return None, None
except ConnectionError:
# This block is executed when a connection error occurs
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[91m Could not reach GitHub to check for updates\033[0m")
return None, None
def read_or_initialize_sha(file_path):
if os.path.exists(file_path):
with open(file_path, 'r') as file:
data = json.load(file)
return data.get("last_known_commit_sha")
else:
# File doesn't exist, fetch the latest SHA and create the file
latest_commit_sha = fetch_latest_commit_sha_and_date(github_site, github_repository)
if latest_commit_sha:
with open(file_path, 'w') as file:
json.dump({"last_known_commit_sha": latest_commit_sha}, file)
return latest_commit_sha
else:
# Handle the case where GitHub couldn't be reached
return None
def update_sha_file(file_path, new_sha):
with open(file_path, 'w') as file:
json.dump({"last_known_commit_sha": new_sha}, file)
# Check and create directories
if str(base_path) == "models":
create_directory_if_not_exists(this_dir / base_path / model_path)
else:
create_directory_if_not_exists(base_path / model_path)
print(
f"[{params['branding']}Startup] \033[94mInfo\033[0m Custom path set in \033[93mmodeldownload.json\033[0m. Using the following settings:"
)
print(
f"[{params['branding']}Startup] \033[94mInfo\033[0m Base folder Path:\033[93m",
base_path,
"\033[0m",
)
print(
f"[{params['branding']}Startup] \033[94mInfo\033[0m Model folder Path:\033[93m",
model_path,
"\033[0m",
)
print(
f"[{params['branding']}Startup] \033[94mInfo\033[0m Full Path:\033[93m",
base_path / model_path,
"\033[0m",
)
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Custom path set in \033[93mmodeldownload.json\033[0m. Using the following settings:")
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Base folder Path:\033[93m",base_path,"\033[0m",)
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Model folder Path:\033[93m",model_path,"\033[0m",)
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Full Path:\033[93m",base_path / model_path,"\033[0m",)
# Download files if they don't exist
print("[" + params["branding"] + "Startup] Checking Model is Downloaded.")
print(f"[{params['branding']}Startup] \033[92mModel is available :\033[93m Checking\033[0m")
for filename, url in files_to_download.items():
if str(base_path) == "models":
destination = this_dir / base_path / model_path / filename
else:
destination = Path(base_path) / model_path / filename
if not destination.exists():
print(f"[{params['branding']}Startup] Downloading " + filename + "...")
print(f"[{params['branding']}Startup] \033[92mModel Downloading file : \033[93m" + filename + "\033[0m")
download_file(url, destination)
print(f"[{params['branding']}Startup] \033[92mModel is available :\033[93m Checked\033[0m")
github_site = "erew123"
github_repository = "alltalk_tts"
check_torch_version()
check_tts_version()
# Define the file path based on your directory structure
sha_file_path = this_dir / "system" / "config" / "at_github_sha.json"
# Read or initialize the SHA (adjusted for handling both SHA and date)
last_known_commit_sha = read_or_initialize_sha(sha_file_path) # Assuming adjustment for date
# Assuming you have fetched the latest commit SHA and date
latest_commit_sha, latest_commit_date = fetch_latest_commit_sha_and_date(github_site, github_repository)
formatted_date = format_datetime(latest_commit_date) if latest_commit_date else "an unknown date"
if latest_commit_sha and latest_commit_sha != last_known_commit_sha:
#print(f"There's an update available for alltalk_tts.")
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[93m {formatted_date}\033[0m")
# Update the file with the new SHA
update_sha_file(sha_file_path, latest_commit_sha)
elif latest_commit_sha == last_known_commit_sha:
#print(f"Your alltalk_tts software is up to date.")
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[93m {formatted_date}\033[0m")
+21 -19
View File
@@ -1,20 +1,22 @@
FROM nvidia/cuda:12.1.1-devel-ubuntu22.04
ENV HOST 0.0.0.0
RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y git build-essential portaudio19-dev \
python3 python3-pip gcc wget \
ocl-icd-opencl-dev opencl-headers clinfo \
libclblast-dev libopenblas-dev \
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
&& ln -s /usr/bin/python3 /usr/bin/python
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
FROM nvidia/cuda:12.1.1-devel-ubuntu22.04
ENV HOST 0.0.0.0
RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y git build-essential portaudio19-dev \
python3 python3-pip gcc wget \
ocl-icd-opencl-dev opencl-headers clinfo \
libclblast-dev libopenblas-dev \
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
&& ln -s /usr/bin/python3 /usr/bin/python
RUN mkdir /app/pip_cache
ENV PIP_CACHE_DIR=/app/pip_cache
WORKDIR /app
COPY . .
ENV CUDA_DOCKER_ARCH=all
RUN pip install --no-cache-dir --no-deps -r system/requirements/requirements_standalone.txt --cache-dir=/app/pip_cache && \
pip install --no-cache-dir deepspeed --cache-dir=/app/pip_cache
EXPOSE 7851
RUN chmod +x launch.sh
ENTRYPOINT ["sh", "-c", "./launch.sh"]
-7
View File
@@ -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
-18
View File
@@ -1,18 +0,0 @@
numpy>=1.22.0
soundfile>=0.12.1
uvicorn>=0.24.0.post1
transformers>=4.37.1
TTS>=0.21.3
torch>=2.1.0+cu118
torchaudio>=2.1.0+cu118
fastapi>=0.104.1
Jinja2>=3.1.2
requests>=2.31.0
tqdm>=4.66.1
importlib-metadata>=4.8.1
packaging>=23.2
pydantic>=1.10.13
sounddevice>=0.4.6
python-multipart>=0.0.6
cutlet>=0.3.0
unidic-lite>=1.0.8
+173 -142
View File
@@ -9,12 +9,16 @@ import threading
import signal
import sys
import atexit
import shutil
from pathlib import Path
from datetime import datetime, timedelta
import re
import numpy as np
import soundfile as sf
import uuid
import logging
# Store the current disable level
current_disable_level = logging.getLogger().manager.disable
######################################
#### ALLTALK ALLOWED STARTUP TIME ####
@@ -30,43 +34,109 @@ startup_wait_time = 120
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
this_dir = Path(__file__).parent.resolve()
# load config file in and get settings
def load_config(file_path):
with open(file_path, "r") as config_file:
config = json.load(config_file)
return config
config_file_path = this_dir / "confignew.json"
# Load the params dictionary from the confignew.json file
params = load_config(config_file_path)
print(f"[{params['branding']}Startup]\033[94m _ _ _ \033[1;35m_____ _ _ \033[0m _____ _____ ____ ")
print(f"[{params['branding']}Startup]\033[94m / \ | | |\033[1;35m_ _|_ _| | | __ \033[0m |_ _|_ _/ ___| ")
print(f"[{params['branding']}Startup]\033[94m / _ \ | | |\033[1;35m | |/ _` | | |/ / \033[0m | | | | \___ \ ")
print(f"[{params['branding']}Startup]\033[94m / ___ \| | |\033[1;35m | | (_| | | < \033[0m | | | | ___) |")
print(f"[{params['branding']}Startup]\033[94m /_/ \_\_|_|\033[1;35m |_|\__,_|_|_|\_\ \033[0m |_| |_| |____/ ")
print(f"[{params['branding']}Startup]")
##############################################
#### Update any changes to confignew.json ####
##############################################
update_config_path = this_dir / "system" / "config" / "at_configupdate.json"
downgrade_config_path = this_dir / "system" / "config" / "at_configdowngrade.json"
def changes_needed(main_config, update_config, downgrade_config):
"""Check if there are any changes to be made to the main configuration."""
for key in downgrade_config.keys():
if key in main_config:
return True
for key, value in update_config.items():
if key not in main_config:
return True
return False
def update_config(config_file_path, update_config_path, downgrade_config_path):
try:
with open(config_file_path, 'r') as file:
main_config = json.load(file)
with open(update_config_path, 'r') as file:
update_config = json.load(file)
with open(downgrade_config_path, 'r') as file:
downgrade_config = json.load(file)
# Determine if changes are needed
if changes_needed(main_config, update_config, downgrade_config):
# Backup with timestamp to avoid overwriting
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
backup_path = config_file_path.with_suffix(f".{timestamp}.bak")
logging.info(f"Creating backup of the main config to {backup_path}")
shutil.copy(config_file_path, backup_path)
# Proceed with updates and downgrades
for key, value in update_config.items():
if key not in main_config:
main_config[key] = value
for key in downgrade_config.keys():
if key in main_config:
del main_config[key]
# Save the updated configuration
with open(config_file_path, 'w') as file:
json.dump(main_config, file, indent=4)
print(f"[{params['branding']}Startup] \033[92mConfig file check : \033[91mUpdates applied\033[0m")
else:
print(f"[{params['branding']}Startup] \033[92mConfig file check : \033[93mNo Updates required\033[0m")
except Exception as e:
print(f"[{params['branding']}Startup] \033[92mConfig file check : \033[91mError updating\033[0m")
# Update the configuration
update_config(config_file_path, update_config_path, downgrade_config_path)
# Re-Load the params dictionary from the confignew.json file
params = load_config(config_file_path)
#########################################
#### Continue on with Startup Checks ####
#########################################
# Required for sentence splitting
try:
from TTS.api import TTS
from TTS.utils.synthesizer import Synthesizer
except ModuleNotFoundError:
logger.error(
f"[{params['branding']}]\033[91mWarning\033[0m Could not find the TTS module. Make sure to install the requirements for the {params['branding']} extension."
f"[{params['branding']}]\033[91mWarning\033[0m Linux / Mac:\npip install -r /alltalk_tts/requirements.txt\n"
f"[{params['branding']}]\033[91mWarning\033[0m Windows:\npip install -r \\alltalk_tts\\requirements.txt\n"
f"[{params['branding']}]\033[91mWarning\033[0m If you used the one-click installer, paste the command above in the terminal window launched after running the cmd_ script. On Windows, that's cmd_windows.bat."
)
raise
# Inform the user about the missing module and suggest next steps
print(f"[{params['branding']}]\033[91mWarning\033[0m Could not find the TTS module. Make sure to install the requirements for the {params['branding']} extension.")
print(f"[{params['branding']}]\033[91mWarning\033[0m Please use the ATSetup utility or check the Github installation instructions.")
# Re-raise the ModuleNotFoundError to stop the program and print the traceback
raise
# IMPORT - Attempt Importing DeepSpeed (required for displaying Deepspeed checkbox in gradio)
# Suppress logging
logging.disable(logging.ERROR)
try:
import deepspeed
deepspeed_installed = True
except ImportError:
deepspeed_installed = False
# Restore previous logging level
logging.disable(current_disable_level)
# Import gradio if being used within text generation webUI
try:
import gradio as gr
from modules import chat, shared, ui_chat
from modules.logging_colors import logger
from modules.ui import create_refresh_button
@@ -75,9 +145,10 @@ try:
# 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
output_folder_wav = params["output_folder_wav"]
print(f"[{params['branding']}Startup] \033[92m{params['branding']}startup Mode : \033[93mText-Gen-webui mode\033[0m")
except ModuleNotFoundError:
output_folder_wav = params["output_folder_wav_standalone"]
print(f"[{params['branding']}Startup] Running script.py in standalone mode")
print(f"[{params['branding']}Startup] \033[92m{params['branding']}startup Mode : \033[93mStandalone mode\033[0m")
# This is set to check if the script is being run within text generation webui or as a standalone script. true means standalone
running_in_standalone = True
@@ -85,7 +156,7 @@ except ModuleNotFoundError:
#### STARTUP VARIABLES ####
###########################
# 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)
# Create a global lock
process_lock = threading.Lock()
@@ -98,23 +169,12 @@ def get_available_voices():
return sorted([voice.name for voice in Path(f"{this_dir}/voices").glob("*.wav")])
#########################
#### LICENSE DISPLAY ####
#########################
# STARTUP Display Licence Information
print(f"[{params['branding']}Startup] \033[94mCoqui Public Model License\033[0m")
print(f"[{params['branding']}Startup] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
############################################
#### DELETE OLD OUTPUT WAV FILES IF SET ####
############################################
def delete_old_files(folder_path, days_to_keep):
current_time = datetime.now()
print(
f"[{params['branding']}Startup] Deletion of old output folder WAV files is currently enabled and set at",
delete_output_wavs_setting,
)
print(f"[{params['branding']}Startup] \033[92mWAV file deletion :\033[93m", delete_output_wavs_setting,"\033[0m")
for file_name in os.listdir(folder_path):
file_path = os.path.join(folder_path, file_name)
if os.path.isfile(file_path):
@@ -130,20 +190,18 @@ output_folder_wav = os.path.normpath(output_folder_wav)
# Check and perform file deletion
if delete_output_wavs_setting.lower() == "disabled":
print(
"["
+ params["branding"]
+ "Startup] Old output wav file deletion is set to disabled."
)
print("["+ params["branding"]+"Startup] \033[92mWAV file deletion :\033[93m Disabled\033[0m")
else:
try:
days_to_keep = int(delete_output_wavs_setting.split()[0])
delete_old_files(output_folder_wav, days_to_keep)
except ValueError:
print(
f"[{params['branding']}Startup] Invalid setting for deleting old wav files. Please use 'Disabled' or 'X Days' format."
)
print(f"[{params['branding']}Startup] \033[92mWAV file deletion :\033[93m Invalid setting for deleting old wav files. Please use 'Disabled' or 'X Days' format\033[0m")
if deepspeed_installed:
print(f"[{params['branding']}Startup] \033[92mDeepSpeed version :\033[93m",deepspeed.__version__,"\033[0m")
else:
print(f"[{params['branding']}Startup] \033[92mDeepSpeed version :\033[91m Not Detected\033[0m")
########################
#### STARTUP CHECKS ####
@@ -153,8 +211,6 @@ def check_required_files():
this_dir = Path(__file__).parent.resolve()
download_script_path = this_dir / "modeldownload.py"
subprocess.run(["python", str(download_script_path)])
print(f"[{params['branding']}Startup] All required files are present.")
# STARTUP Call Check routine
check_required_files()
@@ -174,7 +230,7 @@ if finetuned_model:
(trained_model_directory / file).exists() for file in required_files
)
if finetuned_model:
print(f"[{params['branding']}Startup] Finetuned model \033[93mDetected\033[0m")
print(f"[{params['branding']}Startup] \033[92mFinetuned model :\033[93m Detected\033[0m")
####################################################
#### SET GRADIO BUTTONS BASED ON confignew.json ####
@@ -190,7 +246,6 @@ elif params["tts_method_xtts_local"] == True:
# Set the default for Narrated text without asterisk or quotes to be Narrator
non_quoted_text_is = True
######################
#### GRADIO STUFF ####
######################
@@ -237,9 +292,7 @@ script_path = this_dir / "tts_server.py"
def signal_handler(sig, frame):
print(
f"[{params['branding']}Shutdown] \033[94mReceived Ctrl+C, terminating subprocess\033[92m"
)
print(f"[{params['branding']}Shutdown] \033[94mReceived Ctrl+C, terminating subprocess\033[92m")
if process.poll() is None:
process.terminate()
process.wait() # Wait for the subprocess to finish
@@ -258,33 +311,20 @@ else:
process = subprocess.Popen(["python", script_path])
# Check if the subprocess has started successfully
if process.poll() is None:
print(f"[{params['branding']}Startup] TTS Subprocess starting")
print(f"[{params['branding']}Startup] \033[92mTTS Subprocess :\033[93m Starting up\033[0m")
print(f"[{params['branding']}Startup]")
print(
f"[{params['branding']}Startup] \033[94m {params['branding']}Settings & Documentation:\033[00m",
f"[{params['branding']}Startup] \033[94m{params['branding']}Settings & Documentation:\033[00m",
f"\033[92mhttp://{params['ip_address']}:{params['port_number']}\033[00m",
)
print(f"[{params['branding']}Startup]")
else:
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess Webserver failing to start process"
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m It could be that you have something on port:",
params["port_number"],
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m Or you have not started in a Python environement with all the necesssary bits installed"
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m Check you are starting Text-generation-webui with either the start_xxxxx file or the Python environment with cmd_xxxxx file."
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m xxxxx is the type of OS you are on e.g. windows, linux or mac."
)
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m Alternatively, you could check no other Python processes are running that shouldnt be e.g. Restart your computer is the simple way."
)
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess Webserver failing to start process")
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m It could be that you have something on port:",params["port_number"],)
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m Or you have not started in a Python environement with all the necesssary bits installed")
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m Check you are starting Text-generation-webui with either the start_xxxxx file or the Python environment with cmd_xxxxx file.")
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m xxxxx is the type of OS you are on e.g. windows, linux or mac.")
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m Alternatively, you could check no other Python processes are running that shouldnt be e.g. Restart your computer is the simple way.")
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
sys.exit(1)
@@ -300,26 +340,14 @@ else:
break
except requests.RequestException as e:
# Print the exception for debugging purposes
print(
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess has NOT started up yet, Will keep trying for {timeout} seconds maximum. Please wait."
)
print(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(5)
else:
print(
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."
)
print(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
sys.exit(1)
@@ -347,33 +375,31 @@ def send_reload_request(tts_method):
params["tts_method_xtts_local"] = False
params["tts_method_api_tts"] = True
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
elif tts_method == "API Local":
params["tts_method_api_tts"] = False
params["tts_method_xtts_local"] = False
params["tts_method_api_local"] = True
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
elif tts_method == "XTTSv2 Local":
params["tts_method_api_tts"] = False
params["tts_method_api_local"] = False
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
elif tts_method == "XTTSv2 FT":
params["tts_method_api_tts"] = False
params["tts_method_api_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
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
except requests.exceptions.RequestException as e:
# Handle the HTTP request error
print(
f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}"
)
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}")
return {"status": "error", "message": str(e)}
@@ -385,9 +411,9 @@ def send_lowvram_request(low_vram):
try:
params["tts_model_loaded"] = False
if low_vram:
audio_path = this_dir / "templates" / "lowvramenabled.wav"
audio_path = this_dir / "system" / "at_sounds" / "lowvramenabled.wav"
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}"
headers = {"Content-Type": "application/json"}
response = requests.post(url, headers=headers)
@@ -400,9 +426,7 @@ def send_lowvram_request(low_vram):
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
except requests.exceptions.RequestException as e:
# Handle the HTTP request error
print(
f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}"
)
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}")
return {"status": "error", "message": str(e)}
@@ -414,10 +438,9 @@ def send_deepspeed_request(deepspeed_param):
try:
params["tts_model_loaded"] = False
if deepspeed_param:
audio_path = this_dir / "templates" / "deepspeedenabled.wav"
audio_path = this_dir / "system" / "at_sounds" / "deepspeedenabled.wav"
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}"
headers = {"Content-Type": "application/json"}
response = requests.post(url, headers=headers)
@@ -430,9 +453,7 @@ def send_deepspeed_request(deepspeed_param):
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
except requests.exceptions.RequestException as e:
# Handle the HTTP request error
print(
f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}"
)
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}")
return {"status": "error", "message": str(e)}
@@ -465,9 +486,7 @@ Synthesizer.split_into_sentences = new_split_into_sentences
def before_audio_generation(string, params):
# Check Model is loaded into cuda or cpu and error if not
if not params["tts_model_loaded"]:
print(
f"[{params['branding']}Model] \033[91mWarning\033[0m Model is still loading, please wait before trying to generate TTS"
)
print(f"[{params['branding']}Model] \033[91mWarning\033[0m Model is still loading, please wait before trying to generate TTS")
return
string = html.unescape(string) or random_sentence()
if string == "":
@@ -491,13 +510,9 @@ def combine(audio_files, output_folder, state):
# Save the combined audio to a file with a specified sample rate
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:
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)
# Clean up unnecessary files
for audio_file in audio_files:
@@ -511,7 +526,7 @@ def combine(audio_files, output_folder, state):
################################
# PREVIEW VOICE - Generate Random Sentence if Voice Preview box is empty
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))
@@ -544,9 +559,7 @@ def voice_preview(string):
)
# Check if lock is already acquired
if process_lock.locked():
print(
f"[{params['branding']}Model] \033[91mWarning\033[0m Audio generation is already in progress. Please wait."
)
print(f"[{params['branding']}Model] \033[91mWarning\033[0m Audio generation is already in progress. Please wait.")
return
if generate_response.get("status") == "generate-success":
# Handle Gradio and playback
@@ -557,6 +570,10 @@ def voice_preview(string):
return f"[{params['branding']}Server] Audio generation failed. Status: {generate_response.get('status')}"
#######################
#### TEXT CLEANING ####
#######################
def process_text(text):
# Normalize HTML encoded quotes
text = html.unescape(text)
@@ -606,6 +623,30 @@ def process_text(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 ####
#################################
@@ -613,12 +654,12 @@ def process_text(text):
def output_modifier(string, state):
if not params["activate"]:
return string
original_string = string
# print("ORIGINAL STRING IS:", original_string)
cleaned_string = before_audio_generation(string, params)
img_info = ""
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:
return
string = cleaned_string
language_code = languages.get(params["language"])
temperature = params["local_temperature"]
repetition_penalty = params["local_repetition_penalty"]
@@ -627,7 +668,7 @@ def output_modifier(string, state):
if process_lock.acquire(blocking=False):
try:
if params["narrator_enabled"]:
processed_parts = process_text(original_string)
processed_parts = process_text(cleaned_string)
audio_files_all_paragraphs = []
for part_type, part in processed_parts:
@@ -638,14 +679,10 @@ def output_modifier(string, state):
# Determine the voice to use based on the part type
if part_type == "narrator":
voice_to_use = params["narrator_voice"]
print(
f"[{params['branding']}TTSGen] \033[92mNarrator\033[0m"
) # Green
print(f"[{params['branding']}TTSGen] \033[92mNarrator\033[0m") # Green
elif part_type == "character":
voice_to_use = params["voice"]
print(
f"[{params['branding']}TTSGen] \033[36mCharacter\033[0m"
) # Yellow
print(f"[{params['branding']}TTSGen] \033[36mCharacter\033[0m") # Yellow
else:
# Handle ambiguous parts based on user preference
voice_to_use = (
@@ -661,9 +698,11 @@ def output_modifier(string, state):
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)
cleaned_part = re.sub(r"([!?.\u3002\uFF1F\uFF01\uFF0C])\1+", r"\1", part)
# Replace "Chinese ellipsis" with a single dot
cleaned_part = re.sub(r"\u2026{1,2}", ". ", cleaned_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)
cleaned_part = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_part)
# Remove all newline characters (single or multiple)
cleaned_part = re.sub(r"\n+", " ", cleaned_part)
@@ -686,11 +725,13 @@ def output_modifier(string, state):
)
else:
# Decode HTML entities first
cleaned_part = html.unescape(original_string)
cleaned_part = html.unescape(cleaned_string)
# Replace multiple instances of certain punctuation marks with a single instance
cleaned_part = re.sub(r"([!?.])\1+", r"\1", cleaned_part)
cleaned_part = re.sub(r"([!?.\u3002\uFF1F\uFF01\uFF0C])\1+", r"\1", cleaned_part)
# Replace "Chinese ellipsis" with a single dot
cleaned_part = re.sub(r"\u2026{1,2}", ". ", cleaned_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)
cleaned_part = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_part)
# Remove all newline characters (single or multiple)
cleaned_part = re.sub(r"\n+", " ", cleaned_part)
# Process the part and give it a non-character name if being used vai API or standalone.
@@ -729,25 +770,15 @@ def output_modifier(string, state):
if audio_path:
# Handle Gradio and playback
autoplay = "autoplay" if params["autoplay"] else ""
string = (
f'<audio src="file/{final_output_file}" controls {autoplay}></audio>'
)
string = (f'<audio src="file/{final_output_file}" controls {autoplay}></audio>')
if params["show_text"]:
string += f"\n\n{original_string}"
string += reinsert_images(cleaned_string, img_info)
shared.processing_message = "*Is typing...*"
return string
else:
print(
f"[{params['branding']}Server] \033[91mWarning\033[0m No audio path in the response."
)
print(f"[{params['branding']}Server] \033[91mWarning\033[0m No audio path in the response.")
else:
print(
f"[{params['branding']}Server] \033[91mWarning\033[0m Audio generation failed. Status:",
generate_response.get("message"),
)
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Audio generation failed. Status:", generate_response.get("message"),)
def get_output_filename(state):
if "character_menu" in state:
+2617
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@@ -89,25 +89,25 @@
<h3>AllTalk Startup Settings</h3><br>
<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="">
<option {% if data.activate %}selected{% endif %} value="true">True</option>
<option {% if not data.activate %}selected{% endif %} value="false">False</option>
</select>
<label for="autoplay" style="color: #33cc33;">&nbsp; &nbsp; Autoplay TTS output:</label>
<label for="autoplay" style="color: #b273fa;">&nbsp; &nbsp; TG-webui Autoplay TTS:</label>
<select id="autoplay" name="autoplay" required="">
<option {% if data.autoplay %}selected{% endif %} value="true">True</option>
<option {% if not data.autoplay %}selected{% endif %} value="false">False</option>
</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="">
<option {% if data.show_text %}selected{% endif %} value="true">True</option>
<option {% if not data.show_text %}selected{% endif %} value="false">False</option>
</select>
<label for="voice" style="color: #33cc33;">&nbsp; &nbsp; Default voice:</label>
<label for="voice" style="color: #b273fa;">&nbsp; &nbsp; TG-webui Default voice:</label>
<select id="voice" name="voice" required="">
{% for file in wav_files %}
<option value="{{ file }}" {% if data.voice==file %}selected{% endif %}>{{ file }}</option>
@@ -115,7 +115,7 @@
</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="">
<option value="Arabic" {% if data.language=='Arabic' %}selected{% endif %}>Arabic</option>
<option value="Chinese" {% if data.language=='Chinese' %}selected{% endif %}>Chinese</option>
@@ -124,6 +124,7 @@
<option value="English" {% if data.language=='English' %}selected{% endif %}>English</option>
<option value="French" {% if data.language=='French' %}selected{% endif %}>French</option>
<option value="German" {% if data.language=='German' %}selected{% endif %}>German</option>
<option value="Hindi" {% if data.language=='Hindi' %}selected{% endif %}>Hindi</option>
<option value="Hungarian" {% if data.language=='Hungarian' %}selected{% endif %}>Hungarian</option>
<option value="Italian" {% if data.language=='Italian' %}selected{% endif %}>Italian</option>
<option value="Japanese" {% if data.language=='Japanese' %}selected{% endif %}>Japanese</option>
@@ -135,20 +136,20 @@
<option value="Turkish" {% if data.language=='Turkish' %}selected{% endif %}>Turkish</option>
</select>
<label for="narrator_voice" style="color: #33cc33;">&nbsp; &nbsp; Narrator voice:</label>
<label for="narrator_voice" style="color: #b273fa;">&nbsp; &nbsp; TG-webui Narrator voice:</label>
<select id="narrator_voice" name="narrator_voice" required="">
{% for file in wav_files %}
<option value="{{ file }}" {% if data.narrator_voice==file %}selected{% endif %}>{{ file }}</option>
{% endfor %}
</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="">
<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>
</select>
<label for="narrator_enabled" style="color: #33cc33;">&nbsp; &nbsp; Narrator enabled:</label>
<label for="narrator_enabled" style="color: #b273fa;">&nbsp; &nbsp; TG-webui Narrator enabled:</label>
<select id="narrator_enabled" name="narrator_enabled" required="">
<option {% if data.narrator_enabled %}selected{% endif %} value="true">True</option>
<option {% if not data.narrator_enabled %}selected{% endif %} value="false">False</option>
Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
View File
@@ -0,0 +1,2 @@
{
}
+2
View File
@@ -0,0 +1,2 @@
{
}
File renamed without changes.
@@ -6,6 +6,7 @@
"English": "en",
"French": "fr",
"German": "de",
"Hindi": "hi",
"Hungarian": "hu",
"Italian": "it",
"Japanese": "ja",
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+869
View File
@@ -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()
+173
View File
@@ -0,0 +1,173 @@
absl-py==2.1.0
aiofiles==23.2.1
aiohttp==3.9.3
aiosignal==1.3.1
altair==5.2.0
annotated-types==0.6.0
anyascii==0.3.2
anyio==4.3.0
attrs==23.2.0
audioread==3.0.1
av==11.0.0
Babel==2.14.0
bangla==0.0.2
blinker==1.7.0
blis==0.7.11
bnnumerizer==0.0.2
bnunicodenormalizer==0.1.6
catalogue==2.0.10
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
cloudpathlib==0.16.0
colorama==0.4.6
coloredlogs==15.0.1
confection==0.1.4
contourpy==1.2.0
coqpit==0.0.17
ctranslate2==4.1.0
cutlet==0.4.0
cycler==0.12.1
cymem==2.0.8
Cython==3.0.9
dateparser==1.1.8
decorator==5.1.1
docopt==0.6.2
einops==0.7.0
encodec==0.1.1
exceptiongroup
fastapi==0.110.0
faster-whisper==1.0.1
ffmpy==0.3.2
filelock==3.13.3
Flask==3.0.2
flatbuffers==24.3.25
fonttools==4.50.0
frozenlist==1.4.1
fsspec==2024.3.1
fugashi==1.3.1
fuzzywuzzy>=0.18.0
g2pkk==0.1.2
gradio==3.50.2
gradio_client==0.6.1
grpcio==1.62.1
gruut==2.2.3
gruut-ipa==0.13.0
gruut-lang-de==2.0.0
gruut-lang-en==2.0.0
gruut-lang-es==2.0.0
gruut-lang-fr==2.0.2
h11==0.14.0
hangul-romanize==0.1.0
httpcore==1.0.4
httpx==0.27.0
huggingface-hub==0.22.1
humanfriendly==10.0
idna==3.6
importlib_metadata==7.1.0
importlib_resources==6.4.0
inflect==7.0.0
itsdangerous==2.1.2
jaconv==0.3.4
jamo==0.4.1
jieba==0.42.1
Jinja2==3.1.3
joblib==1.3.2
jsonlines==1.2.0
jsonschema==4.21.1
jsonschema-specifications==2023.12.1
kiwisolver==1.4.5
langcodes==3.3.0
lazy_loader==0.3
librosa==0.10.1
llvmlite==0.42.0
Markdown==3.6
MarkupSafe==2.1.5
matplotlib==3.8.3
mojimoji==0.0.13
mpmath==1.3.0
msgpack==1.0.8
multidict==6.0.5
murmurhash==1.0.10
networkx==2.8.8
nltk==3.8.1
num2words==0.5.13
numba==0.59.1
numpy==1.26.4
nvidia-cublas-cu11>=11.11.3.6
nvidia-cudnn-cu11>=9.0.0.312
onnxruntime==1.17.1
orjson==3.9.15
packaging==24.0
pandas==1.5.3
pillow==10.2.0
platformdirs==4.2.0
pooch==1.8.1
preshed==3.0.9
protobuf==5.26.0
psutil==5.9.8
pycparser==2.21
pydantic==2.6.4
pydantic_core==2.16.3
pydub==0.25.1
pynndescent==0.5.11
pyparsing==3.1.2
pypinyin==0.51.0
pyreadline3==3.4.1
pysbd==0.3.4
python-crfsuite==0.9.10
python-dateutil==2.9.0.post0
python-Levenshtein>=0.25.0
python-multipart==0.0.9
pytz==2024.1
PyYAML==6.0.1
referencing==0.34.0
regex==2023.12.25
requests==2.31.0
rpds-py==0.18.0
safetensors==0.4.2
scikit-learn==1.4.1.post1
scipy==1.12.0
semantic-version==2.10.0
six==1.16.0
smart-open==6.4.0
sniffio==1.3.1
sounddevice==0.4.6
soundfile==0.12.1
soxr==0.3.7
spacy==3.7.4
spacy-legacy==3.0.12
spacy-loggers==1.0.5
srsly==2.4.8
starlette==0.36.3
SudachiDict-core==20240109
SudachiPy==0.6.8
sympy==1.12
tensorboard==2.16.2
tensorboard-data-server==0.7.2
thinc==8.2.3
threadpoolctl==3.4.0
tokenizers==0.15.2
toolz==0.12.1
torch>=2.2.0
torchaudio>=2.2.0
tqdm==4.66.2
trainer==0.0.36
transformers==4.39.1
TTS==0.22.0
typer==0.9.4
typing_extensions==4.10.0
tzdata==2024.1
tzlocal==5.2
umap-learn==0.5.5
Unidecode==1.3.8
unidic-lite==1.0.8
urllib3==2.2.1
uvicorn==0.29.0
wasabi==1.1.2
weasel==0.3.4
websockets==11.0.3
Werkzeug==3.0.1
yarl==1.9.4
zipp==3.18.1
@@ -0,0 +1,171 @@
absl-py==2.1.0
aiofiles==23.2.1
aiohttp==3.9.3
aiosignal==1.3.1
altair==5.2.0
annotated-types==0.6.0
anyascii==0.3.2
anyio==4.3.0
attrs==23.2.0
audioread==3.0.1
av==11.0.0
Babel==2.14.0
bangla==0.0.2
blinker==1.7.0
blis==0.7.11
bnnumerizer==0.0.2
bnunicodenormalizer==0.1.6
catalogue==2.0.10
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
cloudpathlib==0.16.0
colorama==0.4.6
coloredlogs==15.0.1
confection==0.1.4
contourpy==1.2.0
coqpit==0.0.17
ctranslate2==4.1.0
cutlet==0.4.0
cycler==0.12.1
cymem==2.0.8
Cython==3.0.9
dateparser==1.1.8
decorator==5.1.1
docopt==0.6.2
einops==0.7.0
encodec==0.1.1
fastapi==0.110.0
faster-whisper==1.0.1
ffmpy==0.3.2
filelock==3.13.3
Flask==3.0.2
flatbuffers==24.3.25
fonttools==4.50.0
frozenlist==1.4.1
fsspec==2024.3.1
fugashi==1.3.1
fuzzywuzzy>=0.18.0
g2pkk==0.1.2
gradio==3.50.2
gradio_client==0.6.1
grpcio==1.62.1
gruut==2.2.3
gruut-ipa==0.13.0
gruut-lang-de==2.0.0
gruut-lang-en==2.0.0
gruut-lang-es==2.0.0
gruut-lang-fr==2.0.2
h11==0.14.0
hangul-romanize==0.1.0
httpcore==1.0.4
httpx==0.27.0
huggingface-hub==0.22.1
humanfriendly==10.0
idna==3.6
importlib_metadata==7.1.0
importlib_resources==6.4.0
inflect==7.0.0
itsdangerous==2.1.2
jaconv==0.3.4
jamo==0.4.1
jieba==0.42.1
Jinja2==3.1.3
joblib==1.3.2
jsonlines==1.2.0
jsonschema==4.21.1
jsonschema-specifications==2023.12.1
kiwisolver==1.4.5
langcodes==3.3.0
lazy_loader==0.3
librosa==0.10.1
llvmlite==0.42.0
Markdown==3.6
MarkupSafe==2.1.5
matplotlib==3.8.3
mojimoji==0.0.13
mpmath==1.3.0
msgpack==1.0.8
multidict==6.0.5
murmurhash==1.0.10
networkx==2.8.8
nltk==3.8.1
num2words==0.5.13
numba==0.59.1
numpy>=1.17.0,<1.29.0
nvidia-cublas-cu11>=11.11.3.6
nvidia-cudnn-cu11>=9.0.0.312
onnxruntime==1.17.1
orjson==3.9.15
packaging==24.0
pandas==1.5.3
pillow==10.2.0
platformdirs==4.2.0
pooch==1.8.1
preshed==3.0.9
protobuf==5.26.0
psutil==5.9.8
pycparser==2.21
pydantic==2.6.4
pydantic_core==2.16.3
pydub==0.25.1
pynndescent==0.5.11
pyparsing==3.1.2
pypinyin==0.51.0
pyreadline3==3.4.1
pysbd==0.3.4
python-crfsuite==0.9.10
python-dateutil==2.9.0.post0
python-Levenshtein>=0.25.0
python-multipart==0.0.9
pytz==2024.1
PyYAML==6.0.1
referencing==0.34.0
regex==2023.12.25
requests==2.31.0
rpds-py==0.18.0
safetensors==0.4.2
scikit-learn==1.4.1.post1
scipy==1.12.0
semantic-version==2.10.0
six==1.16.0
smart-open==6.4.0
sniffio==1.3.1
sounddevice==0.4.6
soundfile==0.12.1
soxr==0.3.7
spacy==3.7.4
spacy-legacy==3.0.12
spacy-loggers==1.0.5
srsly==2.4.8
starlette==0.36.3
SudachiDict-core==20240109
SudachiPy==0.6.8
sympy==1.12
tensorboard==2.16.2
tensorboard-data-server==0.7.2
thinc==8.2.3
threadpoolctl==3.4.0
tokenizers==0.15.2
toolz==0.12.1
torch>=2.2.0
torchaudio>=2.2.0
tqdm==4.66.2
trainer==0.0.36
transformers==4.39.1
typer==0.9.4
typing_extensions==4.10.0
tzdata==2024.1
tzlocal==5.2
umap-learn==0.5.5
Unidecode==1.3.8
unidic-lite==1.0.8
urllib3==2.2.1
uvicorn==0.29.0
wasabi==1.1.2
weasel==0.3.4
websockets==11.0.3
Werkzeug==3.0.1
yarl==1.9.4
zipp==3.18.1
@@ -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
@@ -2,7 +2,7 @@ numpy>=1.22.0
soundfile>=0.12.1
uvicorn>=0.24.0.post1
transformers>=4.37.1
TTS>=0.21.3
TTS>=0.22.0
torch>=2.1.0
torchaudio>=2.1.0
fastapi>=0.104.1
@@ -16,3 +16,10 @@ sounddevice>=0.4.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
spacy>=3.7.2
@@ -281,7 +281,7 @@ class AllTalkTtsProvider {
if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
}
const modelSelect = document.getElementById('switch_model');
if (this.settings.finetuned_model === 'true') {
if (this.settings.finetuned_model === true) {
const ftOption = document.createElement('option');
ftOption.value = 'XTTSv2 FT';
ftOption.textContent = 'XTTSv2 FT';
@@ -830,4 +830,4 @@ function updateStatus(message) {
break;
}
}
}
}
File renamed without changes.
@@ -1,159 +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;
#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;
}
+269
View File
@@ -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()
@@ -1,179 +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:**
*
* ![](https://user-images.githubusercontent.com/12958674/88806278-968f0680-d186-11ea-9cb5-8ef2606ffcc7.png)
*/
mergeAudio(buffers: AudioBuffer[]): AudioBuffer;
/**
* Concatenates multiple AudioBuffers into a single AudioBuffer.
*
* **Visual representation:**
*
* ![](https://user-images.githubusercontent.com/12958674/88806297-9d1d7e00-d186-11ea-8cd2-c64cb0324845.png)
*/
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;
}
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:**
*
* ![](https://user-images.githubusercontent.com/12958674/88806278-968f0680-d186-11ea-9cb5-8ef2606ffcc7.png)
*/
mergeAudio(buffers: AudioBuffer[]): AudioBuffer;
/**
* Concatenates multiple AudioBuffers into a single AudioBuffer.
*
* **Visual representation:**
*
* ![](https://user-images.githubusercontent.com/12958674/88806297-9d1d7e00-d186-11ea-8cd2-c64cb0324845.png)
*/
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;
}
@@ -1,2 +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
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
+1
View File
@@ -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,UAoZC,O,EAlZD,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
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,4 +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 */
/*! 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
@@ -366,6 +366,11 @@
/* Other styles for highlighting */
}
.problematic {
background-color: rgb(179, 104, 104);
/* Or any light red color of your choice */
}
.highlight-count {
color: #ff7300;
/* Change to the color you want */
@@ -390,6 +395,13 @@
font-size: 0.8em;
}
/*Disable and enable buttons*/
button:disabled {
background-color: #919191;
color: #666;
cursor: not-allowed;
}
.edit-input {
/* Styles for the edit input field */
margin-top: 5px;
@@ -520,6 +532,7 @@
<option value="en" selected>English</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="hi">Hindi</option>
<option value="hu">Hungarian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
@@ -562,7 +575,7 @@
<div class="setting slider-setting-wrapper">
<label for="volume">Volume:</label>
<div class="slider-container">
<input type="range" id="volume" name="volume" class="slider-setting" min="0.0" max="1.0" step="0.1"
<input type="range" id="volume" name="volume" class="slider-setting" min="0.1" max="1.0" step="0.1"
value="0.8" oninput="updateVolumeValue(this.value)">
<span id="volumeValue">0.8</span>
</div>
@@ -595,14 +608,17 @@
<div id="ttsListSection" class="tts-list-section">
<h2>Generated TTS List</h2>
<input type="number" id="startFromId" value="1" min="1" autocomplete="off" style="width: 60px; margin-right: 10px;">
<button id="playPauseList" onclick="togglePlayPauseList()" style="margin-right: 10px;">Play List</button>
<button onclick="stopPlayback()" style="margin-right: 10px;">Stop Playback</button>
<button id="clearList" onclick="clearTTSList()" style="margin-right: 10px;">Clear List</button>
<button onclick="exportToJSON()" style="margin-right: 10px;">Export List as JSON</button>
<button onclick="importFromJSON()" style="margin-right: 10px;">Import JSON to list</button>
<button onclick="exportMP3()" style="margin-right: 10px;">Export to Wav</button>
<label for="splitEvery">Split every:</label>
<select id="splitEvery" name="splitEvery">
<button class="conditional-btn" id="playPauseList" onclick="togglePlayPauseList()" style="margin-right: 10px;">Play
List</button>
<button class="conditional-btn" onclick="stopPlayback()" style="margin-right: 10px;">Stop Playback</button>
<button class="conditional-btn" id="clearList" onclick="clearTTSList()" style="margin-right: 40px;">Clear
List</button>
<button onclick="importFromJSON()" style="margin-right: 10px;">Import JSON</button>
<button class="conditional-btn" onclick="exportToJSON()" style="margin-right: 10px;">Export JSON</button>
<button class="conditional-btn" id="exportsrttitles" style="margin-right: 10px;">Export SRT</button>
<button class="conditional-btn" onclick="exportMP3()" style="margin-right: 10px;">Export to WAV</button>
<label for="splitEvery">Export Split:</label>
<select id="splitEvery" name="splitEvery" style="margin-right: 40px;">
<option value="100">100</option>
<option value="200">200</option>
<option value="300">300</option>
@@ -610,22 +626,38 @@
<option value="500" selected>500</option>
<option value="600">600</option>
</select>
<button class="conditional-btn" id="saveAndAnalyzeTTS" style="margin-right: 10px;">Analyze TTS</button>
<label for="AnalyzeAccuracy">% Accuracy:</label>
<select id="AnalyzeAccuracy" name="AnalyzeAccuracy" style="margin-right: 10px;">
<option value="99">99</option>
<option value="98" selected>98</option>
<option value="97">97</option>
<option value="96">96</option>
<option value="95">95</option>
<option value="94">94</option>
<option value="93">93</option>
<option value="92">92</option>
<option value="91">91</option>
<option value="90">90</option>
</select>
<div id="paginationControls">
<button id="prevPage" class="pagination-btn">Previous</button>
<button class="conditional-btn pagination-btn" id="prevPage">Previous</button>
<span id="pageIndicator">Page 1 of X</span>
<button id="nextPage" class="pagination-btn">Next</button>
<input type="number" id="jumpToPage" class="pagination-input" min="1" placeholder="Jump to Page">
<button id="jumpButton" class="pagination-btn">Go</button>
<button class="conditional-btn pagination-btn" id="nextPage">Next</button>
<input type="number" id="jumpToPage" class="conditional-btn pagination-input" min="1"
placeholder="Jump to Page">
<button class="conditional-btn pagination-btn" id="jumpButton">Go</button>
</div>
<div id="ttsListDisplay" class="tts-list-display">
<!-- Dynamically populated TTS details will go here -->
</div>
<div id="paginationControls1">
<button id="prevPage1" class="pagination-btn">Previous</button>
<button class="conditional-btn pagination-btn" id="prevPage1">Previous</button>
<span id="pageIndicator1">Page 1 of X</span>
<button id="nextPage1" class="pagination-btn">Next</button>
<input type="number" id="jumpToPage1" class="pagination-input" min="1" placeholder="Jump to Page">
<button id="jumpButton1" class="pagination-btn">Go</button>
<button class="conditional-btn pagination-btn" id="nextPage1">Next</button>
<input type="number" id="jumpToPage1" class="conditional-btn pagination-input" min="1"
placeholder="Jump to Page">
<button class="conditional-btn pagination-btn" id="jumpButton1">Go</button>
</div>
</div>
</div>
@@ -686,8 +718,6 @@
</script>
<script>
/////////////////////////////////////////
@@ -704,6 +734,7 @@
let isStreamInitialized = false;
let characterVoice = document.getElementById("character_voice_gen").value;
let ttsList = []; // Global list to store TTS details
let problematicIds = []; // Global list to store ProblematicIDs
const howlInstances = {};
let listPlaying = false;
let listPlayIndex = 0;
@@ -759,6 +790,123 @@
}
//////////////////////////////////
//////// Compare TTS list ////////
//////////////////////////////////
document.getElementById('saveAndAnalyzeTTS').addEventListener('click', async function () {
showProgress(); // Call this function to show the progress indicator at the start of the process
try {
// Serialize the ttsList data structure to a JSON string
const ttsDataJSON = JSON.stringify(ttsList);
// Send the serialized ttsList to the '/save-tts-data' endpoint
const saveResponse = await fetch('/api/save-tts-data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: ttsDataJSON // Use the serialized JSON string as the request body
});
const saveData = await saveResponse.json();
// Log the server's response
console.log(saveData.message);
// If the server confirms the data was saved successfully, trigger analysis
if (saveData.message === "Data saved successfully") {
const accuracy = parseInt(document.getElementById('AnalyzeAccuracy').value) || 98;
const analyzeResponse = await fetch(`/api/trigger-analysis?threshold=${accuracy}`);
const analyzeData = await analyzeResponse.json();
if (analyzeData.summary.flagged_ids && analyzeData.summary.flagged_ids.length > 0) {
// Update the global problematicIds array with the new flagged IDs
problematicIds = analyzeData.summary.flagged_ids;
console.log("Initial problematicIds from analysis:", problematicIds); // Debugging: Check the initial array after receiving analysis results
// Call highlightProblems with the array of flagged IDs
highlightProblems(problematicIds);
} else {
console.log("No problematic IDs or error retrieving data.");
// Clear the problematicIds array since there are no problematic IDs
problematicIds = [];
highlightProblems(problematicIds);
}
// Optionally, you might want to provide feedback in the UI about the analysis status
} else {
throw new Error('Data save was unsuccessful.');
}
} catch (error) {
// Handle any errors that occurred during the fetch process
console.error('Error:', error);
} finally {
hideProgress(); // Hide the progress indicator when the process is complete or if an error occurs
}
});
function highlightProblems(idsToHighlight) {
// First, clear all previous 'problematic' highlights
document.querySelectorAll('.problematic').forEach(item => {
item.classList.remove('problematic');
});
// Now, highlight all the IDs that should still be problematic
idsToHighlight.forEach(id => {
const itemElement = document.getElementById(`item-${id}`);
if (itemElement) {
itemElement.classList.add('problematic');
}
});
}
/////////////////////////////////
//////// Export SRT Subs ////////
/////////////////////////////////
document.getElementById('exportsrttitles').addEventListener('click', async function () {
showProgress(); // Call this function to show the progress indicator at the start of the process
try {
const ttsDataJSON = JSON.stringify(ttsList);
const saveResponse = await fetch('/api/save-tts-data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: ttsDataJSON
});
const saveData = await saveResponse.json();
console.log(saveData.message);
if (saveData.message === "Data saved successfully") {
// Trigger the SRT generation and handle file download
const analyzeResponse = await fetch(`/api/srt-generation`);
if (analyzeResponse.ok) {
// Create a temporary anchor element
const a = document.createElement('a');
// Create a blob URL from the response
const blob = await analyzeResponse.blob();
const url = window.URL.createObjectURL(blob);
a.href = url;
// Set the download name for the file
a.download = "subtitles.srt";
// Append the anchor to the document
document.body.appendChild(a);
// Trigger the download
a.click();
// Clean up by removing the anchor element and revoking the blob URL
window.URL.revokeObjectURL(url);
a.remove();
} else {
console.log("Error running SRT generation.");
}
} else {
throw new Error('Data save was unsuccessful.');
}
} catch (error) {
console.error('Error:', error);
} finally {
hideProgress(); // Hide the progress indicator when the process is complete or if an error occurs
}
});
///////////////////////////////////////////
//////// TTS Generation Activities ////////
///////////////////////////////////////////
@@ -774,11 +922,21 @@
const playType = document.getElementById('playType').value; // Play type (chunk or stream)
playModeValue = document.getElementById('playMode').value;
let cleanedText = textInput.replace(/ \- | \– /g, ' ');
let cleanedText = textInput.replace(/ \\- | \\– /g, ' ');
cleanedText = cleanedText.replace(/%/g, " percent");
cleanedText = cleanedText.replace(/\.\s'/g, ".'");
cleanedText = cleanedText.replace(/[^a-zA-Z0-9\s\.,;:!?\-\'"À-ÿ\u0400-\u04FF\u0150\u0151\u0170\u0171]\$/g, '');
let sentences = cleanedText.split(/(?<=[.!?:])\s+/);
cleanedText = cleanedText.replace(/\\.\\s'/g, ".'");
cleanedText = cleanedText.replace(/(?<!\\w)\['\]+(?!\\w)/g, '');
cleanedText = cleanedText.replace(/"/g, "'");
cleanedText = cleanedText.replace(/[^a-zA-Z0-9\s.,;:!?\-'"$À-ÿ\u0400-\u04FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u2026\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]/g, '');
cleanedText = cleanedText.replace(/-\\s/g, '; ');
cleanedText = cleanedText.replace(/--/g, '; ');
// Split by Fullwidth/CJK punctuation regardless of if there are spaces behind them
// Please test if it works properly. In my test they it should be
// (?<=[.!?:])\s+ instead of
// (?<=\[.!?:\])\\s+
// so I don't know whats going on here
// let sentences = cleanedText.split(/(?<=[\[.!?:\]])\s+|(?<=[\u3002\uFF01\uFF1A\uFF1F])/);
let sentences = cleanedText.split(/(?<=[\[.!?:\]]['"\u2018\u2019\u201C\u201D]*)\s+|(?<=[\u3002\uFF01\uFF1A\uFF1F])/);
if (!sentences) {
console.error("No sentences found in the input text.");
@@ -886,6 +1044,7 @@
// Refresh the list display to reflect the new pagination state
updateUIList();
updateButtonStyles()
// Update the audio queue and UI
const sound = new Howl({
@@ -902,11 +1061,50 @@
playNextLocalChunk();
}
}
return result
} catch (error) {
console.error("Error in generateAndCache:", error);
}
}
async function regenerateTTS(id) {
console.log("Before regeneration:", problematicIds); // Debugging: Check the array before regeneration
// Find the details of the TTS to regenerate
const ttsDetails = ttsList.find(item => item.id === id);
if (!ttsDetails) return;
// Retrieve the current volume setting from the HTML input
const currentVolume = parseFloat(document.getElementById("volume").value);
// Call the TTS generation with the same details and current volume
const result = await generateAndCache(ttsDetails.text, ttsDetails.language, ttsDetails.characterVoice, currentVolume, id);
if (result && result.status === "generate-success") {
const index = problematicIds.indexOf(id);
if (index !== -1) {
problematicIds.splice(index, 1); // Remove the id from problematicIds
console.log(`ID ${id} removed from problematicIds. Updated array:`, problematicIds); // Debugging: Check the array after removing an ID
}
// Find the element for this ID and remove the 'problematic' class
const problemItemElement = document.getElementById(`item-${id}`);
if (problemItemElement) {
problemItemElement.classList.remove('problematic');
}
} else {
console.log(`Regeneration failed for ID ${id}.`, result); // If regeneration fails, log the result
}
// Refresh the UI list to reflect the new data
updateUIList(); // Assume this function exists and it updates the display list
// Reapply highlighting to the items still in problematicIds
highlightProblems(problematicIds);
console.log("After regeneration and re-highlighting:", problematicIds); // Debugging: Check the array after re-highlighting
}
async function generateWithoutPlayback(chunk, language, characterVoice, id = null) {
// Perform the generation process as usual but do not play the audio
try {
@@ -972,19 +1170,6 @@
}
}
async function regenerateTTS(id) {
// Find the details of the TTS to regenerate
const ttsDetails = ttsList.find(item => item.id === id);
if (!ttsDetails) return;
// Retrieve the current volume setting from the HTML input
const currentVolume = parseFloat(document.getElementById("volume").value);
// Call the TTS generation with the same details and current volume
await generateAndCache(ttsDetails.text, ttsDetails.language, ttsDetails.characterVoice, currentVolume, id);
}
function updateUIList() {
const listDisplay = document.getElementById('ttsListDisplay');
if (!listDisplay) {
@@ -1029,7 +1214,9 @@
document.getElementById('pageIndicator').innerText = `Page ${currentPage} of ${lastPage}`;
document.getElementById('pageIndicator1').innerText = `Page ${currentPage} of ${lastPage}`;
document.getElementById('prevPage').disabled = (currentPage === 1);
document.getElementById('prevPage1').disabled = (currentPage === 1);
document.getElementById('nextPage').disabled = (currentPage === lastPage);
document.getElementById('nextPage1').disabled = (currentPage === lastPage);
}
@@ -1240,7 +1427,7 @@
} else {
// In chunk mode, toggle the chunk play/pause
if (isPlaying && currentlyPlayingIndex > 0) {
let currentSound = audioQueue[currentlyPlayingIndex - 1];
let currentSound = audioQueue[currentlyPlayingIndex - 3];
if (currentSound.playing()) {
currentSound.pause();
} else {
@@ -1267,16 +1454,6 @@
}
}
function stopPlayback() {
Howler.stop();
audioQueue = [];
// Unload each sound in the queue
audioQueue.forEach(sound => sound.unload());
currentlyPlayingIndex = 0;
isPlaying = false;
}
function updatePlaybackButton() {
const playbackButton = document.querySelector(".toggle-playback");
@@ -1451,38 +1628,64 @@
if (pageIndicator1) {
pageIndicator1.textContent = 'Page 1 of 1';
}
updateButtonStyles()
}
function encodeHtmlEntities(text) {
return text.replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}
function decodeHtmlEntities(text) {
var textArea = document.createElement('textarea');
textArea.innerHTML = text;
return textArea.value;
}
function editText(id) {
console.log(`Initiating edit for ID: ${id}`);
console.log("Before edit, ttsList:", JSON.parse(JSON.stringify(ttsList)));
// First, check if we're already editing and should save the current value
const existingInput = document.getElementById(`edit-input-${id}`);
if (existingInput) {
console.log(`Existing input found for ID: ${id}, triggering blur event to save.`);
existingInput.blur(); // This will trigger the blur event, saving the current value
return; // Don't proceed further since we're just saving the existing input
}
const entryDiv = document.getElementById(`item-${id}`);
if (!entryDiv) {
console.error(`Item with ID ${id} not found.`);
return;
}
const textPreviewSpan = entryDiv.querySelector('.text-preview');
const fullText = textPreviewSpan.getAttribute('data-fulltext');
// Retrieve the full text and immediately encode it
let fullText = textPreviewSpan.getAttribute('data-fulltext');
fullText = decodeHtmlEntities(fullText);
//fullText = encodeHtmlEntities(fullText);
console.log(`Current full text for ID: ${id} is: ${fullText}`);
// Create an input field for editing
const inputField = document.createElement('input');
inputField.type = 'text';
// The value is already encoded at this point
inputField.value = fullText;
inputField.classList.add('edit-input');
inputField.id = `edit-input-${id}`; // Assign an ID to the input field for later access
// Handle saving the edited text
inputField.addEventListener('blur', function () {
console.log(`Saving edited text for ID: ${id}: ${this.value}`);
// Update the text in the ttsList array and the data-fulltext attribute
const itemIndex = ttsList.findIndex(item => item.id === id);
if (itemIndex !== -1) {
console.log(`Updating ttsList with new text for ID: ${id}`);
ttsList[itemIndex].text = this.value;
// If this item is in the list of problematic IDs, un-highlight it
if (problematicIds.includes(id)) {
console.log(`ID: ${id} is problematic, removing highlight class`);
const problemItemElement = document.getElementById(`item-${id}`);
problemItemElement.classList.remove('problematic');
}
}
// Create a new span element to replace the input field
@@ -1494,15 +1697,18 @@
newTextPreviewSpan.textContent = displayText;
// Replace the input field with the new span
console.log(`Replacing input field with text span for ID: ${id}`);
inputField.replaceWith(newTextPreviewSpan);
});
// Replace the span with the input field
console.log(`Replacing text span with input field for ID: ${id}`);
textPreviewSpan.replaceWith(inputField);
// Focus the input field and select its content to facilitate editing
inputField.focus();
inputField.select();
console.log("After edit, ttsList:", JSON.parse(JSON.stringify(ttsList)));
}
////////////////////////////////////////
@@ -1550,6 +1756,7 @@
ttsList = jsonData;
currentPage = 1; // Reset to the first page
updateUIList();
updateButtonStyles()
updatePaginationControls(); // Update pagination controls
} catch (error) {
console.error('Error parsing JSON:', error);
@@ -1563,34 +1770,42 @@
function updatePaginationControls() {
const lastPage = Math.ceil(ttsList.length / itemsPerPage);
const pageIndicator = document.getElementById('pageIndicator');
if (pageIndicator) {
pageIndicator.textContent = `Page ${currentPage} of ${lastPage}`;
}
const prevPageButtons = document.querySelectorAll('.pagination-btn[id^="prevPage"]');
const nextPageButtons = document.querySelectorAll('.pagination-btn[id^="nextPage"]');
const prevPageButton = document.getElementById('prevPage');
if (prevPageButton) {
prevPageButton.disabled = (currentPage === 1);
}
// Update page indicators and buttons
prevPageButtons.forEach(btn => btn.disabled = (currentPage === 1));
nextPageButtons.forEach(btn => btn.disabled = (currentPage === lastPage));
const nextPageButton = document.getElementById('nextPage');
if (nextPageButton) {
nextPageButton.disabled = (currentPage === lastPage);
}
// Assuming the page indicators are consistent with button IDs
document.querySelectorAll('span[id^="pageIndicator"]').forEach(indicator => {
indicator.textContent = `Page ${currentPage} of ${lastPage}`;
});
// Similar updates for any additional pagination controls if you have them
// ...
// Update 'Jump to Page' inputs and 'Go' buttons
const jumpToPageInputs = document.querySelectorAll('.pagination-input[id^="jumpToPage"]');
const jumpButtons = document.querySelectorAll('.pagination-btn[id^="jumpButton"]');
const moreThanOnePage = lastPage > 1;
jumpToPageInputs.forEach(input => input.disabled = !moreThanOnePage);
jumpButtons.forEach(button => button.disabled = !moreThanOnePage);
}
//////////////////////////////
//////// Other Things ////////
//////////////////////////////
function updateButtonStyles() {
const ttsList = document.getElementById('ttsListDisplay');
const buttons = document.querySelectorAll('.conditional-btn');
if (!ttsList.hasChildNodes()) { // Check if the list is empty
buttons.forEach(button => button.disabled = true); // Disable buttons
} else {
buttons.forEach(button => button.disabled = false); // Enable buttons
}
}
function updateLanguage(language) {
// Update the language in your application logic
console.log("Selected language:", language);
@@ -1663,10 +1878,10 @@
function stopPlayback() {
Howler.stop();
audioQueue = [];
currentlyPlayingIndex = 0;
//currentlyPlayingIndex = 0;
isPlaying = false;
highlightPlaying(null);
document.getElementById('startFromId').value = '1'; // Reset the startFromId input to 1
//highlightPlaying(null);
//document.getElementById('startFromId').value = '1'; // Reset the startFromId input to 1
}
function displayOutput(result) {
@@ -1836,6 +2051,7 @@
function setupPage() {
// Fetch voices or other initial data
fetchVoices();
updateButtonStyles()
// Check for dark mode preference in localStorage, default to enabled if not set
let isDarkModeEnabled = localStorage.getItem('darkMode');
@@ -1989,11 +2205,11 @@
setupPage();
hideProgress(); // Ensure the progress indicator is hidden on page load
if (window.location.protocol !== 'http:' && window.location.protocol !== 'https:') {
alert('AllTalk TTS Generator is not designed to be run from your disk folder. Please run it from the correct URL e.g. http://127.0.0.1:7851/static/tts_chunk_player/tts_chunk_player.html');
}
alert('AllTalk TTS Generator is not designed to be run from your disk folder. Please run it from the correct URL e.g. http://127.0.0.1:7851/static/tts_chunk_player/tts_chunk_player.html');
}
};
</script>
</body>
</html>
</html>
File diff suppressed because it is too large. Load diff
+77
View File
@@ -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}")
@@ -1,2 +1,2 @@
/*! For license information please see 1995fcd6d39cade7d871.js.LICENSE.txt */
/*! 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
@@ -1 +1 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
@@ -1,80 +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;
/*
* 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;
}
File renamed without changes.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 839 B

After

Width:  |  Height:  |  Size: 839 B

File renamed without changes.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

File renamed without changes.
@@ -1,2 +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()}}();
!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
File renamed without changes.
@@ -1,79 +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>
<?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>
@@ -1,2 +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
!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
File renamed without changes.
File renamed without changes.
@@ -1,3 +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
/*! 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
@@ -1 +1 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
File renamed without changes.
-1631
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

@@ -1 +0,0 @@
{"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
+130 -32
View File
@@ -8,7 +8,8 @@ from TTS.tts.configs.xtts_config import XttsConfig
from TTS.tts.models.xtts import Xtts
import io
import wave
import logging
logging.disable(logging.WARNING)
##########################
#### Webserver Imports####
##########################
@@ -19,6 +20,7 @@ from fastapi import (
Response,
Depends,
HTTPException,
Query,
)
from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse, FileResponse, StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
@@ -34,7 +36,7 @@ this_dir = Path(__file__).parent.resolve()
# STARTUP VARIABLE - Set "device" to cuda if exists, otherwise cpu
device = "cuda" if torch.cuda.is_available() else "cpu"
# 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)
# Base setting for a possible FineTuned model existing and the loader being available
tts_method_xtts_ft = False
@@ -119,12 +121,6 @@ try:
deepspeed_available = True
except ImportError:
pass
if deepspeed_available:
print(f"[{params['branding']}Startup] DeepSpeed \033[93mDetected\033[0m")
print(f"[{params['branding']}Startup] Activate DeepSpeed in {params['branding']}settings")
else:
print(f"[{params['branding']}Startup] DeepSpeed \033[93mNot Detected\033[0m. See https://github.com/microsoft/DeepSpeed")
@asynccontextmanager
async def startup_shutdown(no_actual_value_it_demanded_something_be_here):
@@ -186,9 +182,8 @@ async def setup():
# Calculate start time minus end time
generate_elapsed_time = generate_end_time - generate_start_time
# Print out the result of the load time
print(
f"[{params['branding']}Model] \033[94mModel Loaded in \033[93m{generate_elapsed_time:.2f} seconds.\033[0m"
)
print(f"[{params['branding']}Model] \033[94mModel Loaded in \033[93m{generate_elapsed_time:.2f} seconds.\033[0m")
print(f"[{params['branding']}Model] Ready")
# Set "tts_model_loaded" to true
params["tts_model_loaded"] = True
# Set the output path for wav files
@@ -222,6 +217,8 @@ async def api_manual_load_model():
model_path=modeldownload_base_path / modeldownload_model_path,
config_path=modeldownload_base_path / modeldownload_model_path / "config.json",
).to(device)
print(f"[{params['branding']}Model] \033[94mCoqui Public Model License\033[0m")
print(f"[{params['branding']}Model] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
return model
@@ -251,6 +248,8 @@ async def xtts_manual_load_model():
use_deepspeed=params["deepspeed_activate"],
)
model.to(device)
print(f"[{params['branding']}Model] \033[94mCoqui Public Model License\033[0m")
print(f"[{params['branding']}Model] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
return model
# MODEL LOADER For "XTTSv2 FT"
@@ -269,6 +268,8 @@ async def xtts_ft_manual_load_model():
use_deepspeed=params["deepspeed_activate"],
)
model.to(device)
print(f"[{params['branding']}Model] \033[94mCoqui Public Model License\033[0m")
print(f"[{params['branding']}Model] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
return model
# MODEL UNLOADER
@@ -475,6 +476,11 @@ async def deepspeed(request: Request, new_deepspeed_value: bool):
########################
#### TTS GENERATION ####
########################
debug_generate_audio = False
tts_stop_generation = False # Called to stop generation of the current text at whatever stage its at. currently only set for streaming.
tts_generation_lock = False # Tracks locking of the generaetion process.
tts_narrator_generatingtts = False # Tracks if the current tts processes are narrator based, to avoid moving model on each chunk of text generated.
# Not in use tts_queue_behaviour = False # True is to queue the current generation request. False is to cancel the current generation and start a new one.
# TTS VOICE GENERATION METHODS (called from voice_preview and output_modifer)
async def generate_audio(text, voice, language, temperature, repetition_penalty, output_file, streaming=False):
@@ -485,9 +491,11 @@ async def generate_audio(text, voice, language, temperature, repetition_penalty,
return response
async for _ in response:
pass
async def generate_audio_internal(text, voice, language, temperature, repetition_penalty, output_file, streaming):
global model
global model, tts_stop_generation, tts_generation_lock
tts_generation_lock = True
if params["low_vram"] and device == "cpu":
await switch_device()
generate_start_time = time.time() # Record the start time of generating TTS
@@ -538,6 +546,12 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
yield wav_buf.read()
for i, chunk in enumerate(output):
if tts_stop_generation:
print(f"[{params['branding']}TTSGen] Stopping audio generation.")
file_chunks.clear() # Clear the file_chunks list
tts_stop_generation = False
tts_generation_lock = False
break
file_chunks.append(chunk)
if isinstance(chunk, list):
chunk = torch.cat(chunk, dim=0)
@@ -546,6 +560,7 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
chunk = np.clip(chunk, -1, 1)
chunk = (chunk * 32767).astype(np.int16)
yield chunk.tobytes()
print(f"[{params['branding']}Debug] Stream audio generation: Yielded audio chunk {i}.") if debug_generate_audio else None
else:
# Non-streaming-specific operation
torchaudio.save(output_file, torch.tensor(output["wav"]).unsqueeze(0), 24000)
@@ -564,9 +579,9 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
file_path=output_file,
speaker_wav=[f"{this_dir}/voices/{voice}"],
language=language,
temperature=temperature,
length_penalty=model.config.length_penalty,
repetition_penalty=repetition_penalty,
temperature=float(temperature),
length_penalty=float(model.config.length_penalty),
repetition_penalty=float(repetition_penalty),
top_k=model.config.top_k,
top_p=model.config.top_p,
)
@@ -588,12 +603,11 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
# Print Generation time and settings
generate_end_time = time.time() # Record the end time to generate TTS
generate_elapsed_time = generate_end_time - generate_start_time
print(
f"[{params['branding']}TTSGen] \033[93m{generate_elapsed_time:.2f} seconds. \033[94mLowVRAM: \033[33m{params['low_vram']} \033[94mDeepSpeed: \033[33m{params['deepspeed_activate']}\033[0m"
)
print(f"[{params['branding']}TTSGen] \033[93m{generate_elapsed_time:.2f} seconds. \033[94mLowVRAM: \033[33m{params['low_vram']} \033[94mDeepSpeed: \033[33m{params['deepspeed_activate']}\033[0m")
# Move model back to cpu system ram if needed.
if params["low_vram"] and device == "cuda":
if params["low_vram"] and device == "cuda" and tts_narrator_generatingtts == False:
await switch_device()
tts_generation_lock = False
return
@@ -638,7 +652,7 @@ def list_files(directory):
#############################
# Create an instance of Jinja2Templates for rendering HTML templates
templates = Jinja2Templates(directory=this_dir / "templates")
templates = Jinja2Templates(directory=this_dir / "system")
# Create a dependency to get the current JSON data
def get_json_data():
@@ -653,7 +667,7 @@ async def get_settings(request: Request):
wav_files = list_files(this_dir / "voices")
# Render the template with the current JSON data and list of WAV files
return templates.TemplateResponse(
"generate_form.html",
"/at_admin/at_settings.html",
{
"request": request,
"data": get_json_data(),
@@ -663,7 +677,7 @@ async def get_settings(request: Request):
)
# Define an endpoint to serve static files
app.mount("/static", StaticFiles(directory=str(this_dir / "templates")), name="static")
app.mount("/static", StaticFiles(directory=str(this_dir / "system")), name="static")
@app.post("/update-settings")
async def update_settings(
@@ -853,6 +867,13 @@ async def tts_generate_streaming(request: Request, text: str = Form(...), voice:
print(f"An error occurred: {e}")
return JSONResponse(content={"error": "An error occurred"}, status_code=500)
@app.put("/api/stop-generation")
async def stop_generation_endpoint():
global tts_stop_generation, tts_generation_lock
if tts_generation_lock and not tts_stop_generation:
tts_stop_generation = True
return {"message": "Generation stopped"}
##############################
#### Standard Generation ####
##############################
@@ -870,7 +891,7 @@ except OSError:
print(f"[{params['branding']}Startup] \033[91mInfo\033[0m On Linux, you can use the following command to install PortAudio:")
print(f"[{params['branding']}Startup] \033[91mInfo\033[0m sudo apt-get install portaudio19-dev")
from typing import Union, Dict
from typing import Union, Dict, List
from pydantic import BaseModel, ValidationError, Field
def play_audio(file_path, volume):
@@ -889,7 +910,7 @@ class JSONInput(BaseModel):
narrator_enabled: bool = Field(..., description="narrator_enabled needs to be true or false.")
narrator_voice_gen: str = Field(..., pattern="^.*\.wav$", description="narrator_voice_gen needs to be the name of a wav file e.g. mysample.wav.")
text_not_inside: str = Field(..., pattern="^(character|narrator)$", description="text_not_inside needs to be 'character' or 'narrator'.")
language: str = Field(..., pattern="^(ar|zh-cn|cs|nl|en|fr|de|hu|it|ja|ko|pl|pt|ru|es|tr)$", description="language needs to be one of the following ar|zh-cn|cs|nl|en|fr|de|hu|it|ja|ko|pl|pt|ru|es|tr.")
language: str = Field(..., pattern="^(ar|zh-cn|cs|nl|en|fr|de|hu|hi|it|ja|ko|pl|pt|ru|es|tr)$", description="language needs to be one of the following ar|zh-cn|cs|nl|en|fr|de|hu|hi|it|ja|ko|pl|pt|ru|es|tr.")
output_file_name: str = Field(..., pattern="^[a-zA-Z0-9_]+$", description="output_file_name needs to be the name without any special characters or file extension e.g. 'filename'")
output_file_timestamp: bool = Field(..., description="output_file_timestamp needs to be true or false.")
autoplay: bool = Field(..., description="autoplay needs to be a true or false value.")
@@ -1028,12 +1049,17 @@ async def tts_generate(
"autoplay_volume": autoplay_volume,
"streaming": streaming,
}
global tts_narrator_generatingtts
JSONresult = TTSGenerator.validate_json_input(json_input_data)
if JSONresult is None:
pass
else:
print(f"[{params['branding']}API] \033[91mError with API request:\033[0m", JSONresult)
return JSONResponse(content={"error": JSONresult}, status_code=400)
if narrator_enabled:
if params["low_vram"] and device == "cpu":
await switch_device()
tts_narrator_generatingtts = True
processed_parts = process_text(text_input)
audio_files_all_paragraphs = []
for part_type, part in processed_parts:
@@ -1053,9 +1079,11 @@ async def tts_generate(
voice_description = "\033[36mCharacter (Text-not-inside)\033[0m" if text_not_inside == "character" 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)
cleaned_part = re.sub(r'([!?.\u3002\uFF1F\uFF01\uFF0C])\1+', r'\1', part)
# Replace "Chinese ellipsis" with a single dot
cleaned_part = re.sub(r"\u2026{1,2}", ". ", cleaned_part)
# Further clean to remove any other unwanted characters
cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171]\$', '', cleaned_part)
cleaned_part = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_part)
# Remove all newline characters (single or multiple)
cleaned_part = re.sub(r'\n+', ' ', cleaned_part)
output_file = this_dir / "outputs" / f"{output_file_name}_{uuid.uuid4()}_{int(time.time())}.wav"
@@ -1065,6 +1093,10 @@ async def tts_generate(
audio_files_all_paragraphs.append(audio_path)
# Combine audio files across paragraphs
output_file_path, output_file_url, output_cache_url = combine(output_file_timestamp, output_file_name, audio_files_all_paragraphs)
tts_narrator_generatingtts = False
# Move model back to cpu system ram if needed.
if params["low_vram"] and device == "cuda":
await switch_device()
else:
if output_file_timestamp:
timestamp = int(time.time())
@@ -1084,15 +1116,19 @@ async def tts_generate(
output_cache_url = f'http://{params["ip_address"]}:{params["port_number"]}/audiocache/{output_file_name}.wav'
if text_filtering == "html":
cleaned_string = html.unescape(standard_filtering(text_input))
cleaned_string = re.sub(r'([!?.])\1+', r'\1', text_input)
cleaned_string = re.sub(r'([!?.\u3002\uFF1F\uFF01\uFF0C])\1+', r'\1', text_input)
# Replace "Chinese ellipsis" with a single dot
cleaned_string = re.sub(r"\u2026{1,2}", ". ", cleaned_string)
# Further clean to remove any other unwanted characters
cleaned_string = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171]\$', '', cleaned_string)
cleaned_string = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_string)
# Remove all newline characters (single or multiple)
cleaned_string = re.sub(r'\n+', ' ', cleaned_string)
elif text_filtering == "standard":
cleaned_string = re.sub(r'([!?.])\1+', r'\1', text_input)
cleaned_string = re.sub(r'([!?.\u3002\uFF1F\uFF01\uFF0C])\1+', r'\1', text_input)
# Replace "Chinese ellipsis" with a single dot
cleaned_string = re.sub(r"\u2026{1,2}", ". ", cleaned_string)
# Further clean to remove any other unwanted characters
cleaned_string = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171]\$', '', cleaned_string)
cleaned_string = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_string)
# Remove all newline characters (single or multiple)
cleaned_string = re.sub(r'\n+', ' ', cleaned_string)
else:
@@ -1145,7 +1181,69 @@ def get_current_settings():
#### Word Add-in Sharing ####
#############################
# Mount the static files from the 'word_addin' directory
app.mount("/api/word_addin", StaticFiles(directory=os.path.join(this_dir / 'templates' / 'word_addin')), name="word_addin")
app.mount("/api/word_addin", StaticFiles(directory=os.path.join(this_dir / 'system' / 'word_addin')), name="word_addin")
#############################################
#### TTS Generator Comparision Endpoints ####
#############################################
import subprocess
import aiofiles
class TTSItem(BaseModel):
id: int
fileUrl: str
text: str
characterVoice: str
language: str
class TTSData(BaseModel):
ttsList: List[TTSItem]
@app.post("/api/save-tts-data")
async def save_tts_data(tts_data: List[TTSItem]):
# Convert the list of Pydantic models to a list of dictionaries
tts_data_list = [item.dict() for item in tts_data]
# Serialize the list of dictionaries to a JSON string
tts_data_json = json.dumps(tts_data_list, indent=4)
async with aiofiles.open(this_dir / "outputs" / "ttsList.json", 'w') as f:
await f.write(tts_data_json)
return {"message": "Data saved successfully"}
import sys
@app.get("/api/trigger-analysis")
async def trigger_analysis(threshold: int = Query(default=98)):
venv_path = sys.prefix
env = os.environ.copy()
env["PATH"] = os.path.join(venv_path, "bin") + ":" + env["PATH"]
ttslist_path = this_dir / "outputs" / "ttsList.json"
wavfile_path = this_dir / "outputs"
subprocess.run(["python", "tts_diff.py", f"--threshold={threshold}", f"--ttslistpath={ttslist_path}", f"--wavfilespath={wavfile_path}"], cwd=this_dir / "system" / "tts_diff", env=env)
# Read the analysis summary
try:
with open(this_dir / "outputs" / "analysis_summary.json", "r") as summary_file:
summary_data = json.load(summary_file)
except FileNotFoundError:
summary_data = {"error": "Analysis summary file not found."}
return {"message": "Analysis Completed", "summary": summary_data}
#################################################
#### TTS Generator SRT Subtitiles generation ####
#################################################
@app.get("/api/srt-generation")
async def srt_generation():
venv_path = sys.prefix
env = os.environ.copy()
env["PATH"] = os.path.join(venv_path, "bin") + ":" + env["PATH"]
ttslist_path = this_dir / "outputs" / "ttsList.json"
wavfile_path = this_dir / "outputs"
subprocess.run(["python", "tts_srt.py", f"--ttslistpath={ttslist_path}", f"--wavfilespath={wavfile_path}"], cwd=this_dir / "system" / "tts_srt", env=env)
srt_file_path = this_dir / "outputs" / "subtitles.srt"
if not srt_file_path.exists():
raise HTTPException(status_code=404, detail="Subtitle file not found.")
return FileResponse(path=srt_file_path, filename="subtitles.srt", media_type='application/octet-stream')
###################################################
#### Webserver Startup & Initial model Loading ####
Binary file not shown.
+3 -1
View File
@@ -9,4 +9,6 @@ Author BBC
This file is licensed under the Creative Commons Attribution 3.0 Unported license.
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» ).