File size: 5,148 Bytes
f021ebf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | #!/usr/bin/env python3
"""
PocketTTS OpenAI-Compatible Server
A drop-in replacement for OpenAI's TTS API using the pocket-tts model.
Supports streaming, custom voices, and runs on CPU.
Usage:
python server.py [OPTIONS]
# Or with environment variables:
POCKET_TTS_PORT=8080 python server.py
"""
import argparse
import os
import sys
from app import create_app, init_tts_service
from app.config import Config
from app.logging_config import get_logger
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description='PocketTTS OpenAI-Compatible Server',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Start with defaults
python server.py
# Custom port and voices directory
python server.py --port 8080 --voices-dir ./my_voices
# Load French model with quantization
python server.py --language french_24l --quantize
Environment Variables:
POCKET_TTS_HOST Server host (default: 0.0.0.0)
POCKET_TTS_PORT Server port (default: 49112)
POCKET_TTS_MODEL_PATH Path to model config file
POCKET_TTS_LANGUAGE Model language (e.g., english, french_24l)
POCKET_TTS_QUANTIZE Enable int8 quantization (default: false)
POCKET_TTS_VOICES_DIR Path to voices directory
POCKET_TTS_STREAM_DEFAULT Enable streaming by default
POCKET_TTS_TEXT_PREPROCESS_DEFAULT Enable text preprocessing by default
POCKET_TTS_LOG_DIR Log directory path
""",
)
parser.add_argument(
'--host', type=str, default=Config.HOST, help=f'Host to bind to (default: {Config.HOST})'
)
parser.add_argument(
'--port', type=int, default=Config.PORT, help=f'Port to listen on (default: {Config.PORT})'
)
parser.add_argument(
'--model-path',
type=str,
default=Config.MODEL_PATH,
dest='model_path',
help='Path to model config file (.yaml) or variant name',
)
parser.add_argument(
'--voices-dir',
type=str,
default=Config.VOICES_DIR,
dest='voices_dir',
help='Directory containing voice files',
)
parser.add_argument(
'--stream',
action='store_true',
default=Config.STREAM_DEFAULT,
help='Enable streaming by default for all requests',
)
parser.add_argument(
'--text-preprocess',
action='store_true',
default=Config.TEXT_PREPROCESS_DEFAULT,
help='Enable text preprocessing for all requests',
)
parser.add_argument(
'--language',
type=str,
default=Config.LANGUAGE,
dest='language',
help='Model language (e.g., english, french_24l, german_24l, portuguese, italian, spanish_24l). Incompatible with --model-path.',
)
parser.add_argument(
'--quantize',
action='store_true',
default=Config.QUANTIZE,
help='Apply dynamic int8 quantization to reduce memory usage and improve speed.',
)
parser.add_argument(
'--log-level',
type=str,
default=Config.LOG_LEVEL,
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
dest='log_level',
help='Logging level',
)
return parser.parse_args()
def main():
"""Main entry point."""
args = parse_args()
# Update config from args (environment takes precedence via Config class)
os.environ.setdefault('POCKET_TTS_LOG_LEVEL', args.log_level)
# Create app
app = create_app(
{'STREAM_DEFAULT': args.stream, 'TEXT_PREPROCESS_DEFAULT': args.text_preprocess}
)
logger = get_logger()
# Validate mutually exclusive options
if args.language and args.model_path:
logger.error('--language and --model-path are mutually exclusive. Use one or the other.')
sys.exit(1)
# Validate --language against supported list (prevents cryptic pocket-tts errors).
if args.language and args.language not in Config.SUPPORTED_LANGUAGES:
logger.error(
f"Unknown language '{args.language}'. "
f'Supported: {", ".join(Config.SUPPORTED_LANGUAGES)}'
)
sys.exit(1)
# Initialize TTS service
try:
init_tts_service(
model_path=args.model_path,
voices_dir=args.voices_dir,
language=args.language,
quantize=args.quantize,
)
except Exception as e:
logger.error(f'Failed to initialize TTS service: {e}')
sys.exit(1)
# Start server with Waitress (production WSGI server)
try:
from waitress import serve
logger.info(f'Starting PocketTTS server on http://{args.host}:{args.port}')
logger.info('Press Ctrl+C to stop')
serve(app, host=args.host, port=args.port, threads=4, url_scheme='http')
except ImportError:
logger.warning('Waitress not installed, falling back to Flask dev server')
logger.warning('Install waitress for production: pip install waitress')
app.run(host=args.host, port=args.port, debug=False, threaded=True)
if __name__ == '__main__':
main()
|