Skip to content

Commit

Permalink
Nb/update python example (#68)
Browse files Browse the repository at this point in the history
Co-authored-by: Norman Bukingolts <norman@hume.ai>
  • Loading branch information
norman-codes and Norman Bukingolts authored Jun 23, 2024
1 parent 2958001 commit 497667c
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 68 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
evi-python-example/.env
evi-python-example/__pycache__
1 change: 1 addition & 0 deletions evi-python-example/.env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
HUME_API_KEY="PASTE_HUME_API_KEY_HERE"
HUME_SECRET_KEY="PASTE_HUME_SECRET_KEY_HERE"
94 changes: 43 additions & 51 deletions evi-python-example/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# evi-python-example

This is a short example of streaming a session with EVI using your device's microphone. Install the [dependencies](#dependencies) listed below and then run `python run-evi.py` to run the example.
This is a short example of streaming a session with EVI using your device's microphone. Install the [dependencies](#dependencies) listed below and then run `python run_evi.py` to run the example.

NOTE: The Python SDK is currently supported on Mac and Linux, and not yet on Windows.

Expand Down Expand Up @@ -33,17 +33,18 @@ To install it, run:
pip install python-dotenv
```

### 2. Microphone
### 2. SDK module

To use microphone functionality in the `MicrophoneInterface` as shown below on either Mac or Linux, run:
The `hume` package contains the classes you need to use EVI, with and without message handling and audio playback.

To install it, run:
```bash
pip install "hume[microphone]"
pip install "hume"
```

### 3. Audio playback

For audio playback, install the following dependencies:
For audio playback, install the following system dependencies:

#### Mac

Expand All @@ -69,54 +70,67 @@ sudo apt-get --yes install libasound2-dev libportaudio2 ffmpeg

Not yet supported.

## Explanation of code in `run-evi.py`
## Explanation of code in `run_evi.py`

### 1. Import libraries

First we import the required Hume libraries, as well as `load_dotenv` to enable the use of `.env` files to store environment variables, and asyncio for asynchronous functions calls.

```python
import os
from hume import HumeVoiceClient, MicrophoneInterface
from hume import HumeVoiceClient, MicrophoneInterface, VoiceSocket
from dotenv import load_dotenv
import asyncio
```

### 2. Authenticate and Connect

In the `run-evi.py` code, the API key has been saved to an environment variable. Avoid hard coding secrets in your project to prevent them from being leaked.
To get your API key,log into the portal and visit the [API keys page](https://beta.hume.ai/settings/keys).

`run_evi.py` uses an environment variable to access your API key and Secret key for token authentification.
> Learn more about authentication strategies with EVI [here](https://dev.hume.ai/docs/introduction/api-key).
You can set the environment variable in two ways:
Set the environment variable by editing the provided placeholder `.env` file, which is a persistent local store of your API key. To prevent API key leakage, it is set in the `.gitignore` file to not be committed to GitHub. The included `.env` file in this repo just reads:

1. **Manual method:** You can set an environment variable in the terminal by running this command prior to running the code. Note that you will need to run this every time you have a new terminal session, for example if you close the window or after restarting the computer.
`HUME_API_KEY="PASTE_HUME_API_KEY_HERE"`

`HUME_SECRET_KEY="PASTE_HUME_SECRET_KEY_HERE"`

`export HUME_API_KEY="PASTE_HUME_API_KEY_HERE"`
> `.gitignore` is a hidden file, so on Mac you would need to hit `COMMAND-SHIFT .` to make it viewable in the finder.
By using this method, environment variables are automatically set regardless of where the code is executed. As such, they are consistently available across different execution environments.

2. **.env file method:** Alternatively, you can edit the provided placeholder `.env` file (Note: it's a hidden file so on Mac you would need to hit `COMMAND-SHIFT .` to make them viewable in the finder). The `.env` file is a persistent local store of your API key, and it's set in the `.gitignore` file to not be committed to GitHub. The included `.env` file in this repo just reads:
**NOTE:** Your API key is like your password. Do not post any code containing it to any public forum such as Discord, and do not commit it to GitHub.

`HUME_API_KEY="PASTE_HUME_API_KEY_HERE"`
```python
async def main() -> None:
# Retrieve any environment variables stored in the .env file
load_dotenv()

—and you can edit it to save your API key.
# Retrieve the Hume API key from the environment variables
HUME_API_KEY = os.getenv("HUME_API_KEY")
HUME_SECRET_KEY = os.getenv("HUME_SECRET_KEY")

By using this method, environment variables are auotmatically set regardless of where the code is executed. As such, they are consistently available across different execution environments. This can be more convenient than using the `export` command above, since you don't have to run it every time you start a new terminal.
# Connect and authenticate with Hume
client = HumeVoiceClient(HUME_API_KEY, HUME_SECRET_KEY)

> For example, environment variables set in the terminal do not persist when you run a Jupyter notebook.
# Start streaming EVI over your device's microphone and speakers
async with client.connect_with_handlers(
on_open=on_open, # Handler for when the connection is opened
on_message=on_message, # Handler for when a message is received
on_error=on_error, # Handler for when an error occurs
on_close=on_close, # Handler for when the connection is closed
enable_audio=True, # Flag to enable playback (True by default)
) as socket:
# Start the microphone interface in the background; add "device=NUMBER" to specify device
microphone_task = asyncio.create_task(MicrophoneInterface.start(socket))

To get your API key,log into the portal and visit the [API keys page](https://beta.hume.ai/settings/keys).
# Start the user input handler
user_input_task = asyncio.create_task(user_input_handler(socket))

**NOTE:** Your API key is like your password. Do not post any code containing it to any public forum such as Discord, and do not commit it to GitHub.
# The gather function is used to run both async tasks simultaneously
await asyncio.gather(microphone_task, user_input_task)

```python
async def main() -> None:
# Retrieve the Hume API key from the environment variables
HUME_API_KEY = os.getenv("HUME_API_KEY")
# Connect and authenticate with Hume
client = HumeVoiceClient(HUME_API_KEY)

# Start streaming EVI over your device's microphone and speakers
async with client.connect() as socket:
await MicrophoneInterface.start(socket)
```

#### Optional: Specify device
Expand Down Expand Up @@ -159,26 +173,4 @@ Initialize, execute, and manage the lifecycle of the event loop in the asyncio-b

```python
asyncio.run(main())
```

## Putting it all together

Here is the complete code from the steps above to run this example:

```python
import os
from hume import HumeVoiceClient, MicrophoneInterface
from dotenv import load_dotenv
import asyncio

async def main() -> None:
# Retrieve the Hume API key from the environment variables
HUME_API_KEY = os.getenv("HUME_API_KEY")
# Connect and authenticate with Hume
client = HumeVoiceClient(HUME_API_KEY)

# Start streaming EVI over your device's microphone and speakers
async with client.connect() as socket:
await MicrophoneInterface.start(socket)
asyncio.run(main())
```
```
36 changes: 36 additions & 0 deletions evi-python-example/helper_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import sounddevice as sd

# UI Helper Functions
def print_ascii_art(msg: str):
# Print ASCII art of 'EVI' and app purpose statement
print("=" * 60)
print(
rf"""
███████ ██ ██ ██
██ ██ ██ ██
█████ ██ ██ ██
██ ██ ██ ██
███████ ████ ██
{msg}
"""
)
print("=" * 60)


def list_capture_devices():
# Log available capture audio devices (devices with input channels) and their indices
print("-" * 60)
print("Available CAPTURE (input) devices:")
devices = sd.query_devices()
for idx, device in enumerate(devices):
if device['max_input_channels'] > 0:
print(f"{idx}: {device['name']}")
print("-" * 60)

def list_audio_devices():
# Log available input and output audio devices
print("-" * 60)
print("ALL available audio devices:")
print(sd.query_devices())
print("-" * 60)
17 changes: 0 additions & 17 deletions evi-python-example/run-evi.py

This file was deleted.

Loading

0 comments on commit 497667c

Please sign in to comment.