Example: Websocket example, asynchronous client with iterator¶
This example shows:
How to open a websocket connection using an async context manager.
Generate a take.
How to iterate over the resulting status and audio messages using
iter_request()
.How to make a request with and without chunks enabled. (Add argument
--chunks
.)
Example output¶
$ python3 -m examples.websocket_example_async_iter
Found Daisys Speak API version=1 minor=0
[0.002] Take status was changed to: WAITING.
[0.024] Take status was changed to: STARTED.
[0.761] New part being received.
[0.761] Received audio chunk of size 245760.
[1.197] Take status was changed to: PROGRESS_50.
[1.200] New part being received.
[1.200] Received audio chunk of size 108544.
[2.595] Take status was changed to: READY.
Deleting take t01jqrj756qrvrqaw59zgyxpcrw: True
Example output (chunks enabled)¶
$ python3 -m examples.websocket_example_async_iter --chunks
Found Daisys Speak API version=1 minor=0
[0.002] Take status was changed to: WAITING.
[0.023] Take status was changed to: STARTED.
[0.318] New part being received.
[0.318] Received audio chunk of size 4096.
[0.331] Received audio chunk of size 4096.
[0.344] Received audio chunk of size 4096.
[0.358] Received audio chunk of size 4096.
[0.371] Received audio chunk of size 4096.
[0.384] Received audio chunk of size 4096.
[0.397] Received audio chunk of size 4096.
[0.411] Received audio chunk of size 4096.
[0.424] Received audio chunk of size 4096.
[0.437] Received audio chunk of size 4096.
[0.450] Received audio chunk of size 4096.
[0.463] Received audio chunk of size 4096.
[0.472] Received audio chunk of size 4096.
[0.482] Received audio chunk of size 4096.
[0.492] Received audio chunk of size 4096.
[0.503] Received audio chunk of size 4096.
[0.513] Received audio chunk of size 4096.
[0.523] Received audio chunk of size 4096.
[0.533] Received audio chunk of size 4096.
[0.543] Received audio chunk of size 4096.
[0.553] Received audio chunk of size 4096.
[0.564] Received audio chunk of size 4096.
[0.575] Received audio chunk of size 4096.
[0.584] Received audio chunk of size 4096.
[0.595] Received audio chunk of size 4096.
[0.605] Received audio chunk of size 4096.
[0.615] Received audio chunk of size 4096.
[0.626] Received audio chunk of size 4096.
[0.636] Received audio chunk of size 4096.
[0.646] Received audio chunk of size 1024.
[1.002] Take status was changed to: PROGRESS_50.
[1.005] New part being received.
[1.005] Received audio chunk of size 4096.
[1.015] Received audio chunk of size 4096.
[1.024] Received audio chunk of size 4096.
[1.033] Received audio chunk of size 4096.
[1.043] Received audio chunk of size 4096.
[1.053] Received audio chunk of size 4096.
[1.064] Received audio chunk of size 4096.
[1.074] Received audio chunk of size 4096.
[1.084] Received audio chunk of size 4096.
[1.095] Received audio chunk of size 4096.
[1.105] Received audio chunk of size 4096.
[1.115] Received audio chunk of size 4096.
[1.125] Received audio chunk of size 4096.
[1.135] Received audio chunk of size 2048.
[2.641] Take status was changed to: READY.
Deleting take t01jqrk04k7fhrdgs764bv6h7p1: True
examples/websocket_example_async_iter.py¶
1import sys, os, asyncio, time
2from typing import Optional
3from daisys import DaisysAPI
4from daisys.v1.speak import (DaisysWebsocketGenerateError, HTTPStatusError, Status, TakeResponse,
5 StreamOptions, StreamMode)
6
7# Override DAISYS_EMAIL and DAISYS_PASSWORD with your details!
8EMAIL = os.environ.get('DAISYS_EMAIL', 'user@example.com')
9PASSWORD = os.environ.get('DAISYS_PASSWORD', 'pw')
10
11# Please see tokens_example.py for how to use an access token instead of a password.
12
13async def main(chunks):
14 async with DaisysAPI('speak', email=EMAIL, password=PASSWORD) as speak:
15 print('Found Daisys Speak API', await speak.version())
16
17 # A buffer to receive parts; we initialize with a single empty bytes()
18 # because we will use it to accumulate chunks of the current wav file
19 # there. In total we will end with a list of wav files, one for each
20 # part. Parts are bits of speech, usually full sentences, that end with
21 # silence.
22 audio_wavs = [bytes()]
23
24 # Assume at least one voice is available
25 voice = (await speak.get_voices())[0]
26
27 async with speak.websocket(voice_id=voice.voice_id) as ws:
28 # Time the latency from when we submit the request until each part
29 # is received.
30 t0 = time.time()
31
32 # Submit a request to generate a take over the websocket connection.
33 generate_request_id = await ws.generate_take(
34 voice_id=voice.voice_id,
35 text='Hello from Daisys websockets! How may I help you?',
36
37 # Optional
38 stream_options=StreamOptions(mode=StreamMode.CHUNKS) if chunks else None,
39 )
40
41 # The use of an interator simplifies streaming, here we show how to
42 # get both status and audio chunks from the same iterator.
43 async for take_id, take, header, audio in ws.iter_request(generate_request_id):
44 now = time.time() - t0
45 if take is not None:
46 print(f'[{now:.03f}] Take status was changed to: {take.status.name}.')
47 if header is not None:
48 print(f'[{now:.03f}] New part being received.')
49 if audio is not None:
50 print(f'[{now:.03f}] Received audio chunk of size {len(audio)}.')
51
52 # Delete the take
53 if take_id:
54 print(f'Deleting take {take_id}:', await speak.delete_take(take_id))
55
56if __name__=='__main__':
57 try:
58 asyncio.run(main('--chunks' in sys.argv[1:]))
59 except HTTPStatusError as e:
60 try:
61 print(f'HTTP error status {e.response.status_code}: {e.response.json()["detail"]}, {e.request.url}')
62 except:
63 print(f'HTTP error status {e.response.status_code}: {e.response.text}, {e.request.url}')