Supergiovane / node-red-contrib-sonospollytts

Play speech TTS using Sonos.
https://www.facebook.com/supergiovaneDev
MIT License
12 stars 6 forks source link

Support for Google Speech #43

Closed dxdc closed 3 years ago

dxdc commented 4 years ago

This plugin works terrific with Polly. What are your thoughts on making a new config type for Google parameters? This would expand the possible TTS platforms.

This is a working python version I wrote for Google, so it needs some updates for node as well as the 'service_account.json' credentials, but could be a really nice addition. Also, this needs to be set up in Google Console (similar to AWS set up).

If you like, I can also post screenshots for users on how to properly set up the AWS credentials for Polly... could be useful to amend the docs. Thanks for considering!

#/usr/bin/env python
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = os.path.dirname(os.path.realpath(__file__)) + "/service_account.json"

from google.cloud import texttospeech

# Instantiates a client
client = texttospeech.TextToSpeechClient()

# Set the text input to be synthesized
s = """Just a simple test of a speech generator."""

synthesis_input = texttospeech.types.SynthesisInput(text=s)

# Build the voice request, select the language code ("en-US") 
# and the ssml voice gender ("neutral")
voice = texttospeech.types.VoiceSelectionParams(
    language_code='en-US',
    name='en-US-Wavenet-E',
    ssml_gender=texttospeech.enums.SsmlVoiceGender.FEMALE)

# Select the type of audio file you want returned
audio_config = texttospeech.types.AudioConfig(
    audio_encoding=texttospeech.enums.AudioEncoding.MP3)

# Perform the text-to-speech request on the text input with the selected
# voice parameters and audio file type
response = client.synthesize_speech(synthesis_input, voice, audio_config)

# The response's audio_content is binary.
with open('output.mp3', 'wb') as out:
    # Write the response to the output file.
    out.write(response.audio_content)
    print('Audio content written to file "output.mp3"')
Supergiovane commented 4 years ago

Thank you DX, i'll take a look in the next days...

Supergiovane commented 3 years ago

Hi dx after some considerations, i think i need to develop another node using google, because of some issues i found..

dxdc commented 3 years ago

Thanks for still considering this @Supergiovane !

Supergiovane commented 3 years ago

I need a suggestion. There are basically two ways to get TTS audio. 1) One is using translate.google.com. Is limited but very simple to implement for the end user. 2) The second one is using the google api + credientials, way more complex.

You suggested the google TTS integration, so i think you are ahead of me in that, so i need your help to choose the right path to develop the node. What is the best way?

dxdc commented 3 years ago

Sure. I suggest Google TTS integration, it gives user the ability for longer sentences, more realistic voices, etc.

Supergiovane commented 3 years ago

Ok, thanks.

Supergiovane commented 3 years ago

The new node will be here https://github.com/Supergiovane/node-red-contrib-tts-ultimate and will handle amazon polly and google tts. Stay tuned. Bye.

Supergiovane commented 3 years ago

Hi Dx, TTS-Ultimate is out. https://github.com/Supergiovane/node-red-contrib-tts-ultimate Sorry for taking so long in the development.

dxdc commented 3 years ago

@Supergiovane it works great!! thanks so much for implementing this.

One of the other really funny things is that you can have Google read english in other languages, and it comes out with a very realistic accent.

A few notes, since I had some minor problems configuring it:

  1. I am uploading a Google JSON key from a web browser on a different machine. It kept telling me the file was not found. Then, I decided to proceed anyway and saw this message. I copied my JSON file into this path and then everything worked.
Screen Shot 2020-12-24 at 7 56 44 AM
  1. In the status (below the node itself), it shows "Downloading from Amazon". This should vary depending on if user is downloading from Amazon or Google.

  2. If I send a message when the node is initialized, but before Sonos is connected, it says the message is rejected because Sonos is offline. If I attach a debug node, you can see how many "undefined" messages are being sent also though. These should probably all be changed to null instead of undefined so that there is no message sent?

image

Supergiovane commented 3 years ago

Hi Dx, what’s your name? Point 1: i tested with safari and chrome on a mac, on another machine, and it works. What browser/system are you using?

2: yes, already fixed and ready with the next version.

3: the payload is undefined, but if you set the debug node to display the full message, you’ll see the error reported. I’ll change this behaviour by adding a second output pin, where it send only errors, like i’ve done, for example, with hikvision ultimate node. i’ll keep you advised as soon as the new version is out.

dxdc commented 3 years ago

i tested with safari and chrome on a mac, on another machine, and it works. What browser/system are you using?

yes, already fixed and ready with the next version.

Great!

the payload is undefined, but if you set the debug node to display the full message, you’ll see the error reported.

I see. Thanks! That would be a nice addition. I was thinking even just one output node to track failed messages only. This way, they could be re-injected into the queue - presuming the msg object is in the same format? I would suggest adding some kind of other property (e.g., "attempts"), which gets incremented each time. This way if attempts > 5 for example we could decide to abandon the message.

My idea is something like this:

Maybe even better, the use of msg.reset could be tied to the incoming flow to ttsultimate, meaning, any time a new message is played, it will delete any failed messages.

image

i’ll keep you advised as soon as the new version is out.

Thanks for your work!!

[
  {
    "crontab": "", 
    "id": "493d64c2.13e88c", 
    "name": "Hello World", 
    "once": false, 
    "onceDelay": 0.1, 
    "payload": "Hello World.", 
    "payloadType": "str", 
    "repeat": "", 
    "topic": "", 
    "type": "inject", 
    "wires": [
      [
        "e8013253.35922"
      ]
    ], 
    "x": 270, 
    "y": 2500, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "config": "a0cf44f1.95c618", 
    "id": "e8013253.35922", 
    "name": "", 
    "property": "payload", 
    "propertyType": {}, 
    "rules": [], 
    "sonoshailing": "Hailing_ComputerCall.mp3", 
    "sonosipaddress": "192.168.86.43", 
    "sonosvolume": "40", 
    "ssml": false, 
    "type": "ttsultimate", 
    "voice": "fr-CA-Standard-A#fr-CA#FEMALE", 
    "wires": [
      [
        "d6eaff67.1b453"
      ]
    ], 
    "x": 470, 
    "y": 2500, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "checkall": "true", 
    "id": "d6eaff67.1b453", 
    "name": "payload.attempts < 5?", 
    "outputs": 2, 
    "property": "payload.attempts", 
    "propertyType": "msg", 
    "repair": false, 
    "rules": [
      {
        "t": "lt", 
        "v": "5", 
        "vt": "str"
      }, 
      {
        "t": "eq", 
        "v": "", 
        "vt": "str"
      }
    ], 
    "type": "switch", 
    "wires": [
      [
        "339fe41f.c39a2c"
      ], 
      [
        "b4b61bb2.a411c8"
      ]
    ], 
    "x": 700, 
    "y": 2500, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "active": true, 
    "complete": "payload", 
    "console": false, 
    "id": "b4b61bb2.a411c8", 
    "name": "failed", 
    "statusType": "auto", 
    "statusVal": "", 
    "targetType": "msg", 
    "tosidebar": true, 
    "tostatus": false, 
    "type": "debug", 
    "wires": [], 
    "x": 910, 
    "y": 2540, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "bytopic": "all", 
    "duration": "5", 
    "extend": false, 
    "id": "339fe41f.c39a2c", 
    "name": "", 
    "op1": "", 
    "op1type": "nul", 
    "op2": "", 
    "op2type": "payl", 
    "outputs": 1, 
    "overrideDelay": false, 
    "reset": "", 
    "topic": "topic", 
    "type": "trigger", 
    "units": "s", 
    "wires": [
      [
        "e8013253.35922"
      ]
    ], 
    "x": 760, 
    "y": 2400, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "action": "", 
    "from": "", 
    "id": "be026407.32ee88", 
    "name": "", 
    "property": "", 
    "reg": false, 
    "rules": [
      {
        "p": "reset", 
        "pt": "msg", 
        "t": "set", 
        "to": "true", 
        "tot": "bool"
      }
    ], 
    "to": "", 
    "type": "change", 
    "wires": [
      [
        "339fe41f.c39a2c"
      ]
    ], 
    "x": 680, 
    "y": 2580, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "id": "35924ed2.dca792", 
    "info": "", 
    "name": "(linked to 'success' output)", 
    "type": "comment", 
    "wires": [], 
    "x": 470, 
    "y": 2580, 
    "z": "431a0dd9.b9eea4"
  }, 
  {
    "id": "a0cf44f1.95c618", 
    "name": "Google", 
    "noderedipaddress": "localhost", 
    "noderedport": "1980", 
    "purgediratrestart": "leave", 
    "ttsservice": "googletts", 
    "type": "ttsultimate-config"
  }
]
dxdc commented 3 years ago

Point 1: i tested with safari and chrome on a mac, on another machine, and it works. What browser/system are you using?

Not sure it matters.... but actually thinking about it, I did the following:

  1. Created new Amazon config
  2. Created new Google config
  3. Deployed node

So, I created a second config before deploying.

Supergiovane commented 3 years ago

Hi Dx About the configuration.json file, i found the issue. The problem apperas if you've created a new config-node without prior saving it. The config-node must be the first ever created. I'll add some notifications about that to the users.

Supergiovane commented 3 years ago

Hi Dx V. 1.0.3 is out. Please use the output PIN 2 to handle/cohordinate messages arriving to tts-ultimate before Sonos connection is established. Anyway, this should not be a big deal, because tts-ultimate connects to Sonos very quickly.

dxdc commented 3 years ago

thanks!