Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: configurable timeout #18

Merged
merged 7 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion ovos_tts_plugin_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ def verify_ssl(self) -> bool:
"""Whether or not to verify SSL certificates when connecting to the server. Defaults to True."""
return self.config.get("verify_ssl", True)

@property
def tts_timeout(self) -> int:
"""Timeout for the TTS server. Defaults to 5 seconds."""
return self.config.get("tts_timeout", 5)

def get_tts(
self,
sentence,
Expand Down Expand Up @@ -81,7 +86,9 @@ def _fetch_audio_data(self, params: dict, sentence: str, servers: list) -> bytes
params["utterance"] = sentence
else:
url = f"{url}/synthesize/{sentence}"
r: requests.Response = requests.get(url=url, params=params, verify=self.verify_ssl, timeout=30)
r: requests.Response = requests.get(
url=url, params=params, verify=self.verify_ssl, timeout=self.tts_timeout
)
if r.ok:
return r.content
self.log.error(f"Failed to get audio, response from {url}: {r.text}")
Expand Down
8 changes: 7 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ pip install ovos-tts-plugin-server
"ovos-tts-plugin-server": {"host": "https://0.0.0.0:9666"},
"host": "https://tts.smartgic.io/piper",
"v2": true,
"verify_ssl": true
"verify_ssl": true,
"tts_timeout": 5,
}
```

- host: the url of the tts server. `/synthesize` will be appended to it in the code
- v2: use the v2 api, if available
- verify_ssl: verify the ssl certificate of the server. If you use a self-signed certificate, you can set this to false, [but it is not recommended](#security-warning)
- tts_timeout: timeout for the request to the server. Defaults to 5 seconds.

### As of ovos-tts-server 0.0.3a10

If using a TTS plugin with v2, you can use the `/v2` config option
Expand Down
14 changes: 14 additions & 0 deletions tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

pip install -r requirements-dev.txt
pip install .

black --line-length=119 .
bandit -ll -r ovos_tts_plugin_server
flake8 --max-line-length=119 ovos_tts_plugin_server
isort --profile black .
ruff ovos_tts_plugin_server
mypy --ignore-missing-imports --exclude tests ovos_tts_plugin_server
safety check --ignore=58755 --continue-on-error

pytest
8 changes: 2 additions & 6 deletions tests/e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
from ovos_tts_plugin_server import OVOSServerTTS


def requests_retry_session(
retries=3, backoff_factor=0.3, status_forcelist=(500, 502, 503, 504)
):
def requests_retry_session(retries=3, backoff_factor=0.3, status_forcelist=(500, 502, 503, 504)):
session = requests.Session()
retry = Retry(
total=retries,
Expand All @@ -26,9 +24,7 @@ def requests_retry_session(


def test_tts_plugin_e2e():
tts_instance = OVOSServerTTS(
config={"host": "http://localhost:9666"}
)
tts_instance = OVOSServerTTS(config={"host": "http://localhost:9666"})
tts_instance.get_tts(sentence="Hello%20world", wav_file="test.wav")
assert os.path.exists(path="test.wav")
assert os.path.getsize(filename="test.wav") > 0
Expand Down
48 changes: 20 additions & 28 deletions tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,17 @@ def test_host_property(tts_instance, tts_instance_factory):
assert custom_tts_instance.host == custom_host


@pytest.mark.parametrize(
"host,expected", [(None, True), ("https://customhost.com", False)]
)
def test_tts_timeout_property(tts_instance):
# Default behavior - No timeout set
assert tts_instance.tts_timeout == 5

# Custom timeout set
custom_timeout = 10
tts_instance.config["tts_timeout"] = custom_timeout
assert tts_instance.tts_timeout == custom_timeout


@pytest.mark.parametrize("host,expected", [(None, True), ("https://customhost.com", False)])
def test_v2_property(tts_instance, host, expected):
tts_instance.config["host"] = host
assert tts_instance.v2 is expected
Expand All @@ -62,9 +70,7 @@ def test_verify_ssl_property(tts_instance):
assert tts_instance.verify_ssl is True


@patch(
"ovos_tts_plugin_server.OVOSServerTTS._fetch_audio_data", return_value=b"audio data"
)
@patch("ovos_tts_plugin_server.OVOSServerTTS._fetch_audio_data", return_value=b"audio data")
@patch("ovos_tts_plugin_server.OVOSServerTTS._write_audio_file")
def test_get_tts(mock_write_audio, mock_fetch_audio, tts_instance):
sentence = "test sentence"
Expand Down Expand Up @@ -151,40 +157,28 @@ def test_validator(tts_instance):
assert tts_instance.validator.get_tts_class() == OVOSServerTTS


@patch(
"ovos_tts_plugin_server.OVOSServerTTS._fetch_audio_data", return_value=b"audio data"
)
@patch("ovos_tts_plugin_server.OVOSServerTTS._fetch_audio_data", return_value=b"audio data")
@patch("ovos_tts_plugin_server.OVOSServerTTS._write_audio_file")
def test_get_tts_param_change(_, fetch_audio_data, tts_instance):
tts_instance.get_tts(
sentence="test", wav_file="test.wav", lang="en-us", voice="default"
)
tts_instance.get_tts(sentence="test", wav_file="test.wav", lang="en-us", voice="default")
fetch_audio_data.assert_called_with({"lang": "en-us"}, "test", PUBLIC_TTS_SERVERS)
fetch_audio_data.reset_mock()

tts_instance.get_tts(sentence="test", wav_file="test.wav", lang="en-us")
fetch_audio_data.assert_called_with({"lang": "en-us"}, "test", PUBLIC_TTS_SERVERS)
fetch_audio_data.reset_mock()

tts_instance.get_tts(
sentence="test", wav_file="test.wav", lang="en-us", voice="apope-low"
)
fetch_audio_data.assert_called_with(
{"lang": "en-us", "voice": "apope-low"}, "test", PUBLIC_TTS_SERVERS
)
tts_instance.get_tts(sentence="test", wav_file="test.wav", lang="en-us", voice="apope-low")
fetch_audio_data.assert_called_with({"lang": "en-us", "voice": "apope-low"}, "test", PUBLIC_TTS_SERVERS)


@patch(
"ovos_tts_plugin_server.OVOSServerTTS._fetch_audio_data", return_value=b"audio data"
)
@patch("ovos_tts_plugin_server.OVOSServerTTS._fetch_audio_data", return_value=b"audio data")
@patch("ovos_tts_plugin_server.OVOSServerTTS._write_audio_file")
def test_get_tts_server_lists(_, fetch_audio_data, tts_instance_factory):
# Default behavior - No host set
tts_instance = tts_instance_factory(config={})
tts_instance.get_tts("test", "test.wav")
fetch_audio_data.assert_called_with(
{"lang": "en-us"}, "test", tts_instance.public_servers
)
fetch_audio_data.assert_called_with({"lang": "en-us"}, "test", tts_instance.public_servers)
fetch_audio_data.reset_mock()
# Custom host set
custom_host = "https://customhost.com"
Expand All @@ -207,14 +201,12 @@ def test_v2_property_passing(_, mock_requests, tts_instance_factory):
assert tts_instance.v2 is True

# Custom host set
tts_instance = tts_instance_factory(
config={"v2": False, "host": "https://customhost.com"}
)
tts_instance = tts_instance_factory(config={"v2": False, "host": "https://customhost.com"})
assert tts_instance.v2 is False
tts_instance.get_tts("test", "test.wav")
mock_requests.assert_called_with(
url="https://customhost.com/synthesize/test",
params={"lang": "en-us"},
verify=True,
timeout=30,
timeout=5,
)