How to play a Downloaded Audio-file, automatically

Hello guys, i have been working on a text-to-speech app for an AI. I am using GTTS (Google Text To Speech). Now, when i type something in the text box, it sends that text to my python code using uplink and returns an audio-file containing the speech and it is downloaded by anvil. To play the audio-file, i have to open and play it. So, i was wondering if there is a way to play it instantly after it is returned.
Here is my Server code(Thanks David And Campopianoa)-

from io import BytesIO
import anvil.server
from gtts import gTTS

anvil.server.connect("<My Uplink Key>")

@anvil.server.callable()
def speak(audio_string):
    mp3_fp = BytesIO()
    tts = gTTS(audio_string, lang='en')
    tts.write_to_fp(mp3_fp)

    # The file saved is fine. I can play it.
    tts.save("my_file.mp3")
    data = open('my_file.mp3', 'rb').read()
    tts_blob = anvil.BlobMedia('audio/mpeg', data, name='audio.mp3')

    return tts_blob
anvil.server.wait_forever()

Here is my code-

from ._anvil_designer import Form1Template
from anvil import *
import anvil.server

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Any code you write here will run when the form opens.

  def text_box_1_pressed_enter(self, **event_args):
    text=self.text_box_1.text
    tts_blob = anvil.server.call("speak",text)
    anvil.media.download(tts_blob)
    """This method is called when the user presses Enter in this text box"""
    pass

So, i want to know, how i can play the downloaded file then itself…Thank You

You could try the option suggested here:

1 Like

Where exactly is the java Script function…I’m new to anvil and i don’t know where most of the stuff are… :sweat_smile:…could you please give me step-by-step instruction to make it work

good question - I put this one on the assets/standard-page.html because for this use case it seemed sensible.

You could also move it to the native libraries or create a custom-html form and put in there.

here’s some linked documentation to help paint the picture
https://anvil.works/docs/client/javascript

for your example, it’s a little more tricky because you have the media object in python rather than in the assets… so I think -

  • you’ll need the url of the tts_blob object
  • send this to the javascript function
  • set the src of the <audio> tags to be the url you sent over
  • then play the sound with javascript…

But i’ve not done it so I’m sure

If and when you get stuck try to create an example that doesn’t require your uplink code. i.e. use the upload component or already have the audio stored in the assets. This way you can share a clone link and we can help out…

@stucork is right. You would need the url of the tts_blob object. If you aren’t storing the media file in a data table there is no url.

To get around this you could:

  • Generate a unique key for the session (something with enough entropy to not be duplicated within your needed timeframe)
  • Send this key to your uplink code
  • Return your media file with the key to your Anvil app
  • Store the key along with your media file in a data table
  • Use the key to find the media object in the data table and get the url
  • Continue doing what @stucork suggested

That might seem overly complex, but I’m not sure there is another way to do it. You would think it would be possible to pass the media blob directly to the javascript player in the client…

Also, you should make a background task that periodically removes the media files.

Its pretty hard to get my head around this but let me check

i’m getting millions of error. So, can you guys please tell me how to modify the code below to make it suitable for my needs… :grimacing:

<script>
function PlaySound() {
          var sound = document.getElementById("audio");
          sound.play()
      }
  
</script>

Hi,

that is too vague for anyone to offer meaningful help, so your responses are likely going to be limited.

This is a good read : How to ask a good question

as is this, where @meredydd explains to a user what is wrong with their question and how to make it better : How to access a drop down list from an ItemTemplate form

Remember most people here are just volunteers with day jobs, and will feel more inclined to help people who show they have done some research and testing, and clearly show what’s gone wrong. Your code snippet relies on others to try and guess what else you’ve done.

Please don’t take offence to what I’ve written, but if you read the links I pasted above and follow the advice, you’ll find people on here very helpful.

Oh i’m Sorry…I was just soo irritated when the code was not working

It can be very frustrating when things don’t work, so we do understand. Just be mindful that we are also wrestling with our own bugs and development issues.

Hey i’m getting somewhere :smile: but can somebody tell me how to get the url of tts_blob…:thinking:… you’ll need the url of the tts_blob object

1 Like

This is a bit long-winded but one way to get a url of a media object…

Okay. Let me try it out

1 Like

So it is possible to get a temp URL I suppose. It seems for your purposes you only need a temp URL anyways.

Also, if you choose to use data tables to store the media, the need for a unique key I mentioned above is unnecessary. You can first create the row, get the unique ID (see the code below), and then just leave the media field empty. Then populate it when the server returns it.

# 'jane_smith' is a Row object from the 'people' table
janes_id = jane_smith.get_id()

r = app_tables.people.get_by_id(janes_id)

# r and jane_smith are equal, as they both
# point to the same row.
# (jane_smith == r)

This is from the docs: https://anvil.works/docs/data-tables/data-tables-in-code#getting-one-row-from-a-table

Thank you Robert and sc459 but i don’t that wouldn’t be necessary… but i just had a crazy idea and started from square one with pyttsx3 (no specific reasons)… I used a completely different structure and IT WORKED!!!.Here is the code-
The actual need for this project was for my AI, so you might notice some changes in the code below-
(server code)

import pyttsx3
import anvil.server

anvil.server.connect("<uplink_key>")

engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id)
@anvil.server.callable()
def say(text):
    # This function will pronounce the string which u passed to it
    engine.say(text)
    engine.runAndWait()
@anvil.server.callable()
def speak():
    i="hello"                         # This is how I actually wanted the text to be for the AI
    f= "I am baymax"
    return i,f;
anvil.server.wait_forever()

(client code)

from ._anvil_designer import Form1Template
from anvil import *
import anvil.server

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Any code you write here will run when the form opens.

  def button_1_click(self, **event_args):
    
    w=anvil.server.call("speak")
    anvil.server.call("say",w)
    """This method is called when the button is clicked"""
    pass

If you were wondering that this is a whole new code and doesn’t even relate to the topic, it was because, when i was just sending a text to the speak function to speak, it would work as a python code but not with anvil;it would stop working after the first time i called the function. So with the help of David and Campopianoa, we came up with a totally different code using GTTS which sent an audio-file to anvil…and you know the rest.

So, anyway, thank you sc549,robert and david, for helping me out.

1 Like

Glad you got it working.

Does the code you show above play the TTS in the browser without downloading it?

Actually, David,for a change, i didn’t use GTTS for this one; rather, i use pyttsx3. It does the text-to- speech in my server code itself engine.say(text)

I understand that, but one of your criteria was to have it play without downloading. Did you manage to achieve that?

I only ask out of curiosity, because I don’t see anything in the code you posted above that would do it.

Yeah. Sorry, i should have mentioned that, you don’t need to download or save any file on pyttsx3, that is only for GTTS which we were using earlier. As i got this working, i’ll just forget about GTTS… :sweat_smile:

Great! It looks like you’ve got a new approach.

You’re using anvil as an IoT to control your pc. ie this isn’t being played as audio on the browser but audio on your local machine.

1 Like