mirror of https://github.com/coqui-ai/TTS.git
Make running the server easier
parent
649312fc78
commit
d62234e06e
|
@ -1,9 +1,34 @@
|
|||
## TTS example web-server
|
||||
Steps to run:
|
||||
1. Download one of the models given on the main page. Click [here](https://drive.google.com/drive/folders/1Q6BKeEkZyxSGsocK2p_mqgzLwlNvbHFJ?usp=sharing) for the lastest model.
|
||||
2. Checkout the corresponding commit history or use ```server``` branch if you like to use the latest model.
|
||||
3. Set the paths and the other options in the file ```server/conf.json```.
|
||||
4. Run the server ```python server/server.py -c server/conf.json```. (Requires Flask)
|
||||
5. Go to ```localhost:[given_port]``` and enjoy.
|
||||
|
||||
For high quality results, please use the library versions shown in the ```requirements.txt``` file.
|
||||
You'll need a model package (Zip file, includes TTS Python wheel, model files, server configuration, and optional nginx/uwsgi configs). Publicly available models are listed [here](https://github.com/mozilla/TTS/wiki/Released-Models).
|
||||
|
||||
Instructions below are based on a Ubuntu 18.04 machine, but it should be simple to adapt the package names to other distros if needed. Python 3.6 is recommended, as some of the dependencies' versions predate Python 3.7 and will force building from source, which requires extra dependencies and is not guaranteed to work.
|
||||
|
||||
Development server:
|
||||
|
||||
1. apt-get install -y espeak libsndfile1 python3-venv
|
||||
2. python3 -m venv /tmp/venv
|
||||
3. source /tmp/venv/bin/activate
|
||||
4. pip install -U pip setuptools wheel
|
||||
5. # Download model package
|
||||
6. unzip model.zip
|
||||
7. pip install -U ./TTS*.whl
|
||||
8. python -m TTS.server.server
|
||||
|
||||
You can now browse to http://localhost:5002
|
||||
|
||||
Running with nginx/uwsgi:
|
||||
|
||||
1. apt-get install -y uwsgi uwsgi-plugin-python3 nginx espeak libsndfile1 python3-venv
|
||||
2. python3 -m venv /tmp/venv
|
||||
3. source /tmp/venv/bin/activate
|
||||
4. pip install -U pip setuptools wheel
|
||||
5. # Download model package
|
||||
6. unzip model.zip
|
||||
7. pip install -U ./TTS*.whl
|
||||
8. cp tts_site_nginx /etc/nginx/sites-enabled/default
|
||||
9. service nginx restart
|
||||
10. uwsgi --ini uwsgi.ini
|
||||
|
||||
You can now browse to http://localhost:80 (edit the port in /etc/nginx/sites-enabled/tts_site_nginx).
|
||||
Configure number of workers (number of requests that will be processed in parallel) in uwsgi.ini, `processes` setting.
|
||||
|
|
|
@ -1,17 +1,45 @@
|
|||
#!flask/bin/python
|
||||
import argparse
|
||||
from synthesizer import Synthesizer
|
||||
from TTS.utils.generic_utils import load_config
|
||||
import os
|
||||
|
||||
from flask import Flask, request, render_template, send_file
|
||||
from TTS.server.synthesizer import Synthesizer
|
||||
|
||||
|
||||
def create_argparser():
|
||||
def convert_boolean(x):
|
||||
return x.lower() in ['true', '1', 'yes']
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--tts_checkpoint', type=str, help='path to TTS checkpoint file')
|
||||
parser.add_argument('--tts_config', type=str, help='path to TTS config.json file')
|
||||
parser.add_argument('--tts_speakers', type=str, help='path to JSON file containing speaker ids, if speaker ids are used in the model')
|
||||
parser.add_argument('--wavernn_lib_path', type=str, help='path to WaveRNN project folder to be imported. If this is not passed, model uses Griffin-Lim for synthesis.')
|
||||
parser.add_argument('--wavernn_file', type=str, help='path to WaveRNN checkpoint file.')
|
||||
parser.add_argument('--wavernn_config', type=str, help='path to WaveRNN config file.')
|
||||
parser.add_argument('--is_wavernn_batched', type=convert_boolean, default=False, help='true to use batched WaveRNN.')
|
||||
parser.add_argument('--port', type=int, default=5002, help='port to listen on.')
|
||||
parser.add_argument('--use_cuda', type=convert_boolean, default=False, help='true to use CUDA.')
|
||||
parser.add_argument('--debug', type=convert_boolean, default=False, help='true to enable Flask debug mode.')
|
||||
return parser
|
||||
|
||||
|
||||
config = None
|
||||
synthesizer = None
|
||||
|
||||
embedded_model_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'model')
|
||||
checkpoint_file = os.path.join(embedded_model_folder, 'checkpoint.pth.tar')
|
||||
config_file = os.path.join(embedded_model_folder, 'config.json')
|
||||
|
||||
if os.path.isfile(checkpoint_file) and os.path.isfile(config_file):
|
||||
# Use default config with embedded model files
|
||||
config = create_argparser().parse_args([])
|
||||
config.tts_checkpoint = checkpoint_file
|
||||
config.tts_config = config_file
|
||||
synthesizer = Synthesizer(config)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'-c', '--config_path', type=str, help='path to config file for training')
|
||||
args = parser.parse_args()
|
||||
|
||||
config = load_config(args.config_path)
|
||||
app = Flask(__name__)
|
||||
synthesizer = Synthesizer(config)
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
|
@ -27,4 +55,8 @@ def tts():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not config or not synthesizer:
|
||||
args = create_argparser().parse_args()
|
||||
synthesizer = Synthesizer(args)
|
||||
|
||||
app.run(debug=config.debug, host='0.0.0.0', port=config.port)
|
||||
|
|
|
@ -24,19 +24,20 @@ class Synthesizer(object):
|
|||
def __init__(self, config):
|
||||
self.wavernn = None
|
||||
self.config = config
|
||||
self.use_cuda = config.use_cuda
|
||||
self.use_cuda = self.config.use_cuda
|
||||
if self.use_cuda:
|
||||
assert torch.cuda.is_available(), "CUDA is not availabe on this machine."
|
||||
self.load_tts(self.config.tts_path, self.config.tts_file, self.config.tts_config, config.use_cuda)
|
||||
self.load_tts(self.config.tts_checkpoint, self.config.tts_config,
|
||||
self.config.use_cuda)
|
||||
if self.config.wavernn_lib_path:
|
||||
self.load_wavernn(config.wavernn_lib_path, config.wavernn_path, config.wavernn_file, config.wavernn_config, config.use_cuda)
|
||||
self.load_wavernn(self.config.wavernn_lib_path, self.config.wavernn_path,
|
||||
self.config.wavernn_file, self.config.wavernn_config,
|
||||
self.config.use_cuda)
|
||||
|
||||
def load_tts(self, model_path, model_file, model_config, use_cuda):
|
||||
tts_config = os.path.join(model_path, model_config)
|
||||
self.model_file = os.path.join(model_path, model_file)
|
||||
def load_tts(self, tts_checkpoint, tts_config, use_cuda):
|
||||
print(" > Loading TTS model ...")
|
||||
print(" | > model config: ", tts_config)
|
||||
print(" | > model file: ", model_file)
|
||||
print(" | > checkpoint file: ", tts_checkpoint)
|
||||
self.tts_config = load_config(tts_config)
|
||||
self.use_phonemes = self.tts_config.use_phonemes
|
||||
self.ap = AudioProcessor(**self.tts_config.audio)
|
||||
|
@ -52,7 +53,8 @@ class Synthesizer(object):
|
|||
num_speakers = 0
|
||||
self.tts_model = setup_model(self.input_size, num_speakers=num_speakers, c=self.tts_config)
|
||||
# load model state
|
||||
cp = torch.load(self.model_file)
|
||||
map_location = None if use_cuda else torch.device('cpu')
|
||||
cp = torch.load(tts_checkpoint, map_location=map_location)
|
||||
# load the model
|
||||
self.tts_model.load_state_dict(cp['model'])
|
||||
if use_cuda:
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
<div class="row">
|
||||
<div class="col-lg-12 text-center">
|
||||
<img class="mt-5" src="https://user-images.githubusercontent.com/1402048/52643646-c2102980-2edd-11e9-8c37-b72f3c89a640.png" alt=></img>
|
||||
<h1 class="mt-5">Mozilla TTS</h1>
|
||||
<ul class="list-unstyled">
|
||||
</ul>
|
||||
<input id="text" placeholder="Type here..." size=45 type="text" name="text">
|
||||
|
@ -68,12 +69,10 @@
|
|||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"></script>
|
||||
<script>
|
||||
function q(selector) {return document.querySelector(selector)}
|
||||
q('#text').focus()
|
||||
q('#speak-button').addEventListener('click', function(e) {
|
||||
function do_tts(e) {
|
||||
text = q('#text').value
|
||||
if (text) {
|
||||
q('#message').textContent = 'Synthesizing...'
|
||||
|
@ -83,6 +82,12 @@
|
|||
}
|
||||
e.preventDefault()
|
||||
return false
|
||||
}
|
||||
q('#speak-button').addEventListener('click', do_tts)
|
||||
q('#text').addEventListener('keyup', function(e) {
|
||||
if (e.keyCode == 13) { // enter
|
||||
do_tts(e)
|
||||
}
|
||||
})
|
||||
function synthesize(text) {
|
||||
fetch('/api/tts?text=' + encodeURIComponent(text), {cache: 'no-cache'})
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[build_py]
|
||||
build-lib=temp_build
|
||||
|
||||
[bdist_wheel]
|
||||
bdist-dir=temp_build
|
||||
|
||||
[install_lib]
|
||||
build-dir=temp_build
|
50
setup.py
50
setup.py
|
@ -1,10 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
import setuptools.command.develop
|
||||
import setuptools.command.build_py
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('--checkpoint', type=str, help='Path to checkpoint file to embed in wheel.')
|
||||
parser.add_argument('--model_config', type=str, help='Path to model configuration file to embed in wheel.')
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
|
||||
# Remove our arguments from argv so that setuptools doesn't see them
|
||||
sys.argv = [sys.argv[0]] + unknown_args
|
||||
|
||||
version = '0.0.1'
|
||||
|
||||
|
@ -42,20 +55,17 @@ class develop(setuptools.command.develop.develop):
|
|||
setuptools.command.develop.develop.run(self)
|
||||
|
||||
|
||||
def create_readme_rst():
|
||||
try:
|
||||
subprocess.check_call(
|
||||
[
|
||||
"pandoc", "--from=markdown", "--to=rst", "--output=README.rst",
|
||||
"README.md"
|
||||
],
|
||||
cwd=cwd)
|
||||
print("Generated README.rst from README.md using pandoc.")
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
package_data = ['server/templates/*']
|
||||
|
||||
if 'bdist_wheel' in unknown_args and args.checkpoint and args.model_config:
|
||||
print('Embedding model in wheel file...')
|
||||
model_dir = os.path.join('server', 'model')
|
||||
os.makedirs(model_dir, exist_ok=True)
|
||||
embedded_checkpoint_path = os.path.join(model_dir, 'checkpoint.pth.tar')
|
||||
shutil.copy(args.checkpoint, embedded_checkpoint_path)
|
||||
embedded_config_path = os.path.join(model_dir, 'config.json')
|
||||
shutil.copy(args.model_config, embedded_config_path)
|
||||
package_data.extend([embedded_checkpoint_path, embedded_config_path])
|
||||
|
||||
setup(
|
||||
name='TTS',
|
||||
|
@ -65,6 +75,9 @@ setup(
|
|||
license='MPL-2.0',
|
||||
package_dir={'': 'tts_namespace'},
|
||||
packages=find_packages('tts_namespace'),
|
||||
package_data={
|
||||
'TTS': package_data,
|
||||
},
|
||||
project_urls={
|
||||
'Documentation': 'https://github.com/mozilla/TTS/wiki',
|
||||
'Tracker': 'https://github.com/mozilla/TTS/issues',
|
||||
|
@ -75,12 +88,13 @@ setup(
|
|||
'build_py': build_py,
|
||||
'develop': develop,
|
||||
},
|
||||
setup_requires=["numpy==1.15.4"],
|
||||
install_requires=[
|
||||
"scipy >=0.19.0",
|
||||
"torch >= 0.4.1",
|
||||
"scipy>=0.19.0",
|
||||
"torch>=0.4.1",
|
||||
"numpy==1.15.4",
|
||||
"librosa==0.6.2",
|
||||
"unidecode==0.4.20",
|
||||
"attrdict",
|
||||
"tensorboardX",
|
||||
"matplotlib",
|
||||
"Pillow",
|
||||
|
|
Loading…
Reference in New Issue