Add ability to play audio on server

This commit is contained in:
Michael Hansen 2022-06-07 16:51:41 -04:00
commit 70177bcfc5
4 changed files with 34 additions and 6 deletions

View file

@ -19,6 +19,8 @@ import dataclasses
import json import json
import logging import logging
import re import re
import shlex
import subprocess
import typing import typing
from pathlib import Path from pathlib import Path
from queue import Queue from queue import Queue
@ -163,7 +165,7 @@ def get_app(args: argparse.Namespace, request_queue: Queue, temp_dir: str):
) )
@app.route("/api/tts", methods=["GET", "POST"]) @app.route("/api/tts", methods=["GET", "POST"])
async def app_tts() -> Response: async def app_tts() -> typing.Union[Response, str]:
"""Speak text to WAV.""" """Speak text to WAV."""
tts_args: typing.Dict[str, typing.Any] = { tts_args: typing.Dict[str, typing.Any] = {
"length_scale": args.length_scale, "length_scale": args.length_scale,
@ -224,7 +226,15 @@ def get_app(args: argparse.Namespace, request_queue: Queue, temp_dir: str):
TextToWavParams(text=text, **tts_args), no_cache=no_cache TextToWavParams(text=text, **tts_args), no_cache=no_cache
) )
return Response(wav_bytes, mimetype="audio/wav") audio_target = request.args.get("audioTarget", "client").strip().lower()
if audio_target == "client":
return Response(wav_bytes, mimetype="audio/wav")
# Play audio on server
play_cmd = shlex.split(args.play_program)
subprocess.run(play_cmd, input=wav_bytes, check=True)
return "OK"
@app.route("/api/voices", methods=["GET"]) @app.route("/api/voices", methods=["GET"])
async def api_voices(): async def api_voices():

View file

@ -90,6 +90,9 @@ def get_args(argv=None) -> argparse.Namespace:
"--default-voice", "--default-voice",
help="Default voice key to select in web interface", help="Default voice key to select in web interface",
) )
parser.add_argument(
"--play-program", default="aplay -q", help="Program to play WAV audio on server"
)
parser.add_argument( parser.add_argument(
"--no-show-openapi", action="store_true", help="Don't show OpenAPI link" "--no-show-openapi", action="store_true", help="Don't show OpenAPI link"
) )

View file

@ -115,6 +115,15 @@
<button id="copy-voice" class="btn btn-info btn-sm" title="Copy voice key to clipboard">Copy</button> <button id="copy-voice" class="btn btn-info btn-sm" title="Copy voice key to clipboard">Copy</button>
</div> </div>
</div> </div>
<div class="row mt-3">
<div class="col-auto">
<label for="audio-target" title="Audio target">Play audio on:</label>
<select id="audio-target" name="audio-target">
<option value="client" selected>Client</value>
<option value="server">Server</value>
</select>
</div>
</div>
<div id="audio-message" class="row mt-3" hidden> <div id="audio-message" class="row mt-3" hidden>
<div class="col"> <div class="col">
<audio id="audio" preload="none" controls autoplay hidden></audio> <audio id="audio" preload="none" controls autoplay hidden></audio>
@ -302,6 +311,8 @@
var ssml = q('#ssml').checked || 'false' var ssml = q('#ssml').checked || 'false'
var audioTarget = q('#audio-target').value || 'client'
q('#audio-message').hidden = false q('#audio-message').hidden = false
q('#audio').pause() q('#audio').pause()
@ -313,7 +324,8 @@
'&noiseScale=' + encodeURIComponent(noiseScale) + '&noiseScale=' + encodeURIComponent(noiseScale) +
'&noiseW=' + encodeURIComponent(noiseW) + '&noiseW=' + encodeURIComponent(noiseW) +
'&lengthScale=' + encodeURIComponent(lengthScale) + '&lengthScale=' + encodeURIComponent(lengthScale) +
'&ssml=' + encodeURIComponent(ssml), '&ssml=' + encodeURIComponent(ssml) +
'&audioTarget=' + encodeURIComponent(audioTarget),
{cache: 'no-cache'}) {cache: 'no-cache'})
if (res.ok) { if (res.ok) {
@ -322,8 +334,11 @@
q('#message').innerHTML = (elapsedTime / 1000).toFixed(3) + ' second(s)' q('#message').innerHTML = (elapsedTime / 1000).toFixed(3) + ' second(s)'
q('#speak-button').disabled = false q('#speak-button').disabled = false
q('#audio').src = URL.createObjectURL(blob)
q('#audio').hidden = false if (audioTarget != 'server') {
q('#audio').src = URL.createObjectURL(blob)
q('#audio').hidden = false
}
} else { } else {
message = await res.text() message = await res.text()
q('#message').textContent = message q('#message').textContent = message

View file

@ -1 +1 @@
0.2.0 0.2.1