parent
fef7aff245
commit
ae226a5b01
8 changed files with 229 additions and 0 deletions
|
@ -9,6 +9,7 @@ reported only starting from v0.20.2.
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added [Wallabag integration](https://git.platypush.tech/platypush/platypush/issues/224).
|
- Added [Wallabag integration](https://git.platypush.tech/platypush/platypush/issues/224).
|
||||||
|
- Added [Mimic3 TTS integration](https://git.platypush.tech/platypush/platypush/issues/226).
|
||||||
|
|
||||||
## [0.23.6] - 2022-09-19
|
## [0.23.6] - 2022-09-19
|
||||||
|
|
||||||
|
|
5
docs/source/platypush/plugins/tts.mimic3.rst
Normal file
5
docs/source/platypush/plugins/tts.mimic3.rst
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
``tts.mimic3``
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. automodule:: platypush.plugins.tts.mimic3
|
||||||
|
:members:
|
|
@ -132,6 +132,7 @@ Plugins
|
||||||
platypush/plugins/trello.rst
|
platypush/plugins/trello.rst
|
||||||
platypush/plugins/tts.rst
|
platypush/plugins/tts.rst
|
||||||
platypush/plugins/tts.google.rst
|
platypush/plugins/tts.google.rst
|
||||||
|
platypush/plugins/tts.mimic3.rst
|
||||||
platypush/plugins/tv.samsung.ws.rst
|
platypush/plugins/tv.samsung.ws.rst
|
||||||
platypush/plugins/twilio.rst
|
platypush/plugins/twilio.rst
|
||||||
platypush/plugins/udp.rst
|
platypush/plugins/udp.rst
|
||||||
|
|
46
platypush/backend/http/app/routes/plugins/tts/mimic3.py
Normal file
46
platypush/backend/http/app/routes/plugins/tts/mimic3.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import requests
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
from flask import abort, request, Blueprint
|
||||||
|
|
||||||
|
from platypush.backend.http.app import template_folder
|
||||||
|
|
||||||
|
mimic3 = Blueprint('mimic3', __name__, template_folder=template_folder)
|
||||||
|
|
||||||
|
# Declare routes list
|
||||||
|
__routes__ = [
|
||||||
|
mimic3,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@mimic3.route('/tts/mimic3/say', methods=['GET'])
|
||||||
|
def proxy_tts_request():
|
||||||
|
"""
|
||||||
|
This route is used to proxy the POST request to the Mimic3 TTS server
|
||||||
|
through a GET, so it can be easily processed as a URL through a media
|
||||||
|
plugin.
|
||||||
|
"""
|
||||||
|
required_args = {
|
||||||
|
'text',
|
||||||
|
'server_url',
|
||||||
|
'voice',
|
||||||
|
}
|
||||||
|
|
||||||
|
missing_args = required_args.difference(set(request.args.keys()))
|
||||||
|
if missing_args:
|
||||||
|
abort(400, f'Missing parameters: {missing_args}')
|
||||||
|
|
||||||
|
args = {arg: request.args[arg] for arg in required_args}
|
||||||
|
|
||||||
|
rs = requests.post(
|
||||||
|
urljoin(args['server_url'], '/api/tts'),
|
||||||
|
data=args['text'],
|
||||||
|
params={
|
||||||
|
'voice': args['voice'],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return rs.content
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
119
platypush/plugins/tts/mimic3/__init__.py
Normal file
119
platypush/plugins/tts/mimic3/__init__.py
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
import requests
|
||||||
|
from typing import Optional
|
||||||
|
from urllib.parse import urljoin, urlencode
|
||||||
|
from platypush.backend.http.app.utils import get_local_base_url
|
||||||
|
|
||||||
|
from platypush.context import get_backend
|
||||||
|
from platypush.plugins import action
|
||||||
|
from platypush.plugins.tts import TtsPlugin
|
||||||
|
from platypush.schemas.tts.mimic3 import Mimic3VoiceSchema
|
||||||
|
|
||||||
|
|
||||||
|
class TtsMimic3Plugin(TtsPlugin):
|
||||||
|
"""
|
||||||
|
TTS plugin that uses the `Mimic3 webserver
|
||||||
|
<https://github.com/MycroftAI/mimic3>`_ provided by `Mycroft
|
||||||
|
<https://mycroft.ai/>`_ as a text-to-speech engine.
|
||||||
|
|
||||||
|
The easiest way to deploy a Mimic3 instance is probably via Docker:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mkdir -p "$HOME/.local/share/mycroft/mimic3"
|
||||||
|
$ chmod a+rwx "$HOME/.local/share/mycroft/mimic3"
|
||||||
|
$ docker run --rm \
|
||||||
|
-p 59125:59125 \
|
||||||
|
-v "%h/.local/share/mycroft/mimic3:/home/mimic3/.local/share/mycroft/mimic3" \
|
||||||
|
'mycroftai/mimic3'
|
||||||
|
|
||||||
|
Requires:
|
||||||
|
|
||||||
|
* At least a *media plugin* (see
|
||||||
|
:class:`platypush.plugins.media.MediaPlugin`) enabled/configured -
|
||||||
|
used for speech playback.
|
||||||
|
* The ``http`` backend (:class:`platypush.backend.http.HttpBackend`)
|
||||||
|
enabled - used for proxying the API calls.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
server_url: str,
|
||||||
|
voice: str = 'en_UK/apope_low',
|
||||||
|
media_plugin: Optional[str] = None,
|
||||||
|
player_args: Optional[dict] = None,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
:param server_url: Base URL of the web server that runs the Mimic3 engine.
|
||||||
|
:param voice: Default voice to be used (default: ``en_UK/apope_low``).
|
||||||
|
You can get a full list of the voices available on the server
|
||||||
|
through :method:`.voices`.
|
||||||
|
:param media_plugin: Media plugin to be used for audio playback. Supported:
|
||||||
|
|
||||||
|
- ``media.gstreamer``
|
||||||
|
- ``media.omxplayer``
|
||||||
|
- ``media.mplayer``
|
||||||
|
- ``media.mpv``
|
||||||
|
- ``media.vlc``
|
||||||
|
|
||||||
|
:param player_args: Optional arguments that should be passed to the player plugin's
|
||||||
|
:meth:`platypush.plugins.media.MediaPlugin.play` method.
|
||||||
|
"""
|
||||||
|
super().__init__(media_plugin=media_plugin, player_args=player_args, **kwargs)
|
||||||
|
|
||||||
|
self.server_url = server_url
|
||||||
|
self.voice = voice
|
||||||
|
|
||||||
|
@action
|
||||||
|
def say(
|
||||||
|
self,
|
||||||
|
text: str,
|
||||||
|
server_url: Optional[str] = None,
|
||||||
|
voice: Optional[str] = None,
|
||||||
|
player_args: Optional[dict] = None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Say some text.
|
||||||
|
|
||||||
|
:param text: Text to say.
|
||||||
|
:param server_url: Default ``server_url`` override.
|
||||||
|
:param voice: Default ``voice`` override.
|
||||||
|
:param player_args: Default ``player_args`` override.
|
||||||
|
"""
|
||||||
|
server_url = server_url or self.server_url
|
||||||
|
voice = voice or self.voice
|
||||||
|
player_args = player_args or self.player_args
|
||||||
|
http = get_backend('http')
|
||||||
|
assert http, 'http backend not configured'
|
||||||
|
assert self.media_plugin, 'No media plugin configured'
|
||||||
|
|
||||||
|
url = (
|
||||||
|
urljoin(get_local_base_url(), '/tts/mimic3/say')
|
||||||
|
+ '?'
|
||||||
|
+ urlencode(
|
||||||
|
{
|
||||||
|
'text': text,
|
||||||
|
'server_url': server_url,
|
||||||
|
'voice': voice,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.media_plugin.play(url, **player_args)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def voices(self, server_url: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
List the voices available on the server.
|
||||||
|
|
||||||
|
:param server_url: Default ``server_url`` override.
|
||||||
|
:return: .. schema:: tts.mimi3.Mimic3VoiceSchema(many=True)
|
||||||
|
"""
|
||||||
|
server_url = server_url or self.server_url
|
||||||
|
rs = requests.get(urljoin(server_url, '/api/voices'))
|
||||||
|
rs.raise_for_status()
|
||||||
|
return Mimic3VoiceSchema().dump(rs.json(), many=True)
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
6
platypush/plugins/tts/mimic3/manifest.yaml
Normal file
6
platypush/plugins/tts/mimic3/manifest.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
manifest:
|
||||||
|
events: {}
|
||||||
|
install:
|
||||||
|
pip: []
|
||||||
|
package: platypush.plugins.tts.mimic3
|
||||||
|
type: plugin
|
51
platypush/schemas/tts/mimic3.py
Normal file
51
platypush/schemas/tts/mimic3.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
from marshmallow import Schema, fields
|
||||||
|
|
||||||
|
|
||||||
|
class Mimic3Schema(Schema):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Mimic3VoiceSchema(Mimic3Schema):
|
||||||
|
key = fields.String(
|
||||||
|
required=True,
|
||||||
|
dump_only=True,
|
||||||
|
metadata={
|
||||||
|
'description': 'Unique voice ID',
|
||||||
|
'example': 'en_UK/apope_low',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
language = fields.String(
|
||||||
|
required=True,
|
||||||
|
dump_only=True,
|
||||||
|
metadata={
|
||||||
|
'example': 'en_UK',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
language_english = fields.String(
|
||||||
|
metadata={
|
||||||
|
'description': 'Name of the language (in English)',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
language_native = fields.String(
|
||||||
|
metadata={
|
||||||
|
'description': 'Name of the language (in the native language)',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
name = fields.String(
|
||||||
|
metadata={
|
||||||
|
'example': 'apope_low',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
sample_text = fields.String(
|
||||||
|
metadata={
|
||||||
|
'example': 'Some text',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
description = fields.String()
|
||||||
|
aliases = fields.List(fields.String)
|
Loading…
Reference in a new issue