Example: Hello Daisys, synchronous client

This example shows:

  1. How to create the synchronous client using a context manager.

  2. Get a list of voices.

  3. If there are none, how to generate a voice.

  4. Reference the voice to generate audio (a “take”) for some text.

  5. Download the resulting audio.

Example output
$ python3 -m examples.hello_daisys
Found Daisys Speak API version=1 minor=0
Found voices: []
Not enough voices!
Using model "shakespeare"
Generating a voice.
Sally speaking!
Read 198700 bytes of wav data, wrote "hello_daisys.wav".
Checking take: True
Checking list of takes: True
Deleting take t01hbbgw0zz4e9y6pb9qdxnrmag: True
Deleting voice v01hbbgtrvk50pxwyjvvsxygbza: True
examples/hello_daisys.py
  1import os, asyncio, json
  2from daisys import DaisysAPI
  3from daisys.v1.speak import VoiceGender, SimpleProsody, DaisysTakeGenerateError, HTTPStatusError
  4
  5# Override DAISYS_EMAIL and DAISYS_PASSWORD with your details!
  6EMAIL = os.environ.get('DAISYS_EMAIL', 'user@example.com')
  7PASSWORD = os.environ.get('DAISYS_PASSWORD', 'pw')
  8
  9# Please see tokens_example.py for how to use an access token instead of a password.
 10
 11def load_tokens():
 12    """A function to access and refresh tokens from a local file.  In practice you might
 13    store this somewhere more global like in a database, to re-use between sessions."""
 14    try:
 15        with open('daisys_tokens.json') as tokens_file:
 16            tokens = json.load(tokens_file)
 17            print('Loaded tokens from "daisys_tokens.json".')
 18            return tokens['access_token'], tokens['refresh_token']
 19    except (FileNotFoundError, json.JSONDecodeError):
 20        return None, None
 21
 22ACCESS_TOKEN, REFRESH_TOKEN = load_tokens()
 23
 24def main():
 25    with DaisysAPI('speak', email=EMAIL, password=PASSWORD) as speak:
 26        print('Found Daisys Speak API', speak.version())
 27
 28        # The following is an example of how to use the Daisys API for generating a voice
 29        # and then using it in a speech generation task.  The API generates "takes"
 30        # representing one or more sentences from a speaker.  The same example is possible
 31        # with the synchronous client, where the 'await' keywords should be removed.
 32
 33        # Get a list of all voices
 34        voices = speak.get_voices()
 35        print('Found voices:', [voice.name for voice in voices])
 36
 37        # Choose one
 38        if len(voices) > 0:
 39            voice = voices[-1]
 40            delete_voice = False
 41        else:
 42            print('Not enough voices!')
 43
 44            # Okay, let's generate a voice.
 45
 46            # First we need to know the model.
 47            models = speak.get_models()
 48            if len(models) > 0:
 49                model = models[0]
 50                print(f'Using model "{model.displayname}"')
 51            else:
 52                print('No models found!')
 53                return
 54
 55            print('Generating a voice.')
 56            voice = speak.generate_voice(name='Lucy', gender=VoiceGender.FEMALE, model=model.name)
 57            delete_voice = True
 58
 59            # Try to modify the voice's name
 60            voice.name = 'Sally'
 61            speak.update_voice(**dict(voice))
 62            voice = speak.get_voice(voice.voice_id)
 63
 64        # Now we have a voice.
 65        print(voice.name, 'speaking!')
 66
 67        try:
 68            # Synthesize some audio from text
 69            take = speak.generate_take(voice_id=voice.voice_id, text="Hello there, I am Daisys!",
 70                                       prosody=SimpleProsody(pace=-3, pitch=2, expression=10))
 71        except DaisysTakeGenerateError as e:
 72            print('Error generating take:', str(e))
 73            return
 74
 75        # The take is now READY.  We get its associated audio file.  We provide a filename
 76        # so that it gets written to disk, but it is also returned.
 77        audio_wav = speak.get_take_audio(take.take_id, file='hello_daisys.mp3', format='mp3')
 78
 79        print(f'Read {len(audio_wav)} bytes of wav data, wrote "hello_daisys.wav".')
 80
 81        # Let's check if we can get info on it again.
 82        check_take = speak.get_take(take.take_id)
 83        print('Checking take:', check_take == take)
 84
 85        # Let's check if we can find it in the most recent 5 takes.
 86        last_5_takes = speak.get_takes(length=5)
 87        print('Checking list of takes:', take.take_id in [t.take_id for t in last_5_takes])
 88
 89        # Delete the take
 90        print(f'Deleting take {take.take_id}:', speak.delete_take(take.take_id))
 91
 92        # Delete the voice
 93        if delete_voice:
 94            print(f'Deleting voice {voice.voice_id}:', speak.delete_voice(voice.voice_id))
 95
 96if __name__=='__main__':
 97    try:
 98        main()
 99    except HTTPStatusError as e:
100        try:
101            print(f'HTTP error status {e.response.status_code}: {e.response.json()["detail"]}, {e.request.url}')
102        except:
103            print(f'HTTP error status {e.response.status_code}: {e.response.text}, {e.request.url}')