# Python

URL: https://docs.bithuman.ai/platforms/python

> Render Essence 2 and Expression 2 avatars from your own Python code.

A file in and frames out, or a live stream of audio in and frames out, on your own machine.

## Before you start

To run an avatar without code, use the [CLI](https://docs.bithuman.ai/platforms/cli).

> **Note:** On Linux and Windows, Python renders both models on the CPU alone, no GPU. On macOS it renders on Apple silicon. Windows has its own page: [Windows](https://docs.bithuman.ai/platforms/windows). See [CPU only (no GPU)](https://docs.bithuman.ai/deploy/cpu).

| Detail | Expression 2 | Essence 2 |
|---|---|---|
| **Renders** | [any character from one portrait](https://docs.bithuman.ai/models/expression-2) | [a photoreal person from one portrait](https://docs.bithuman.ai/models/essence-2) |
| **Install** | `pip install "bithuman[expression-2]"` | included in the same install |
| **Frames** | RGB `numpy` arrays, `(height, width, 3)` `uint8` | the same |

| You need | Check |
|---|---|
| Python 3.10–3.14 | `python3 --version` |
| macOS 14+ on Apple silicon, Linux x86_64 or Linux arm64, or [Windows 11 x86_64](https://docs.bithuman.ai/platforms/windows) | `python3 -c "import platform; print(platform.system(), platform.machine())"` |
| An API secret | [Your API secret](https://docs.bithuman.ai/start/api-secret) |
| A paid plan (Creator or higher): usage bills per second while the avatar runs | [Pricing](https://docs.bithuman.ai/pricing) |
| About 1 GB of disk (570 MB package, 118–190 MB per avatar) | `df -h .` |

## Install

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install "bithuman[expression-2]"
```

Install into a virtual environment: Debian and Ubuntu refuse a system-wide `pip install` (`externally-managed-environment`). If `venv` is missing, run `sudo apt install -y python3-venv` first. The package installs no command-line tool.

## Authenticate

Set `BITHUMAN_API_SECRET` in the shell that runs Python (`bithuman.open` reads it), or pass `api_secret=` to `AsyncBithuman.create()`. Downloading a sample avatar needs no account.

## Run your first avatar

```bash
export BITHUMAN_API_SECRET="<your API secret>"
curl -fL -o wise-pup.imx "https://api.bithuman.ai/v1/agent/A23WJF0199/model/download?model=expression-2"
curl -fsSLo speech.wav https://docs.bithuman.ai/samples/speech.wav
```

```python
import bithuman
bithuman.open("wise-pup.imx").render("speech.wav", out_mp4="out.mp4")
# → out.mp4: wise-pup speaking the sample, 416×720, 15 s
```

Open `out.mp4` to watch it talk. `out_mp4=` needs no `ffmpeg`, and `render` returns the number of frames written. It takes a path to an audio file (WAV, MP3 and the other common formats), or already-decoded 16 kHz mono audio (`int16` or `float32` arrays, or raw 16-bit bytes). The same call opens Essence 2 and Essence 1 `.imx` files: for a photoreal person, download the `sofia-ramirez` Essence 2 sample with `curl -fL -o sofia-ramirez.imx "https://api.bithuman.ai/v1/agent/A52DHS2219/model/download?model=essence-2"` and render it the same way (1080×1920).

To process the frames yourself, iterate over `render` without `out_mp4=`:

```python
import bithuman

with bithuman.open("wise-pup.imx") as avatar:
    frames = [image for image in avatar.render("speech.wav")]
print(len(frames), "frames of", frames[0].shape)
# → 300 frames of (720, 416, 3)
```

Frames are RGB; OpenCV expects BGR, so write one with `cv2.imwrite("frame.png", image[:, :, ::-1])`.

<div class="fig-end">

*Capture: The sofia-ramirez avatar speaking in a window opened by the Python SDK on a Mac. Captured on an Apple M4 Mac (macOS) · Python SDK 2.11.6 · sofia-ramirez (Essence 2) · 2026-09-23.* (https://docs.bithuman.ai/examples/python-macos/clip.mp4)

## Performance

| Configuration | Hardware | Essence 2 | Expression 2 |
|---|---|---|---|
| Linux · Python · CPU only (no GPU) | Intel Core i7-13700F (x86_64) | 1.9× real time | 2.3× real time |
| macOS · Python | Apple M4 | 6.9× real time | 8.4× real time |

× real time: seconds of video rendered per second; 1.0× or more holds a live conversation ([method](https://docs.bithuman.ai/performance#desktop)).

A finished `render` logs its own rate on the `bithuman` logger at INFO.

## Continue

The rest of this platform, inlined so one fetch covers it: [Build a Python app](https://docs.bithuman.ai/platforms/python/app.md) · [Python troubleshooting](https://docs.bithuman.ai/platforms/python/troubleshooting.md).

---

# Build a Python app

URL: https://docs.bithuman.ai/platforms/python/app

> Stream audio into an avatar from Python and take its frames live.

## Integrate into your app

For a live conversation, `AsyncBithuman` takes audio as it arrives and yields frames and audio at the model's rate:

```python
# excerpt: show() and play() are your own display and audio output
import asyncio, soundfile as sf
from bithuman import AsyncBithuman

async def main():
    avatar = await AsyncBithuman.create(model_path="wise-pup.imx")   # reads BITHUMAN_API_SECRET
    pcm, rate = sf.read("speech.wav", dtype="int16")

    async def speak():
        for i in range(0, len(pcm), rate // 10):                     # 100 ms chunks, as they arrive
            await avatar.push_audio(pcm[i:i + rate // 10].tobytes(), rate, last_chunk=False)
        await avatar.flush()                                          # end of the reply

    task = asyncio.create_task(speak())
    try:
        async for frame in avatar.run():                              # paced at the model's play rate
            if frame.has_image:
                show(frame.bgr_image)                                 # BGR numpy array
            if frame.audio_chunk:
                play(frame.audio_chunk.array)                         # audio in sync with the frame
    finally:
        task.cancel()
        await avatar.shutdown()                                       # frees the model and the credential

asyncio.run(main())
```

| Job | Call |
|---|---|
| Stream audio | `await avatar.push_audio(int16_bytes, sample_rate, last_chunk=False)` |
| End of a reply | `await avatar.flush()` |
| Interrupt the reply | `avatar.interrupt()` |
| Idle between replies | keep reading `run()`: it yields idle frames when there is no speech |
| Stop | `await avatar.shutdown()` in a `finally` (`stop()` keeps the model loaded) |

A voice agent on your own LiveKit server: [Voice agent in Python](https://docs.bithuman.ai/build/voice-agent/python).

## Complete example

The quickstart from the examples repository: open an avatar and watch it speak in a window.

### Requirements

| You need | Notes |
|---|---|
| Python 3.10–3.14 | on macOS (Apple silicon) or Linux (x86_64, arm64) |
| An [API secret](https://docs.bithuman.ai/start/api-secret) | |
| A desktop session | the example opens a window |

### Run it

```bash
git clone https://gitlab.com/bithuman/sdk/bithuman-examples.git
cd bithuman-examples/python/quickstart
python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
export BITHUMAN_API_SECRET="<your API secret>"
python local-avatar.py
```

### Expected output

A window titled **bitHuman avatar** opens and the avatar speaks the bundled `speech.wav`. The first run downloads the sample avatar (about 150 MB). To write an MP4 instead of opening a window, run `python -m bithuman render sofia-ramirez speech.wav`: it downloads the `sofia-ramirez` sample and writes `sofia-ramirez.mp4`.

### Make it your own

- **Your own avatar:** pass `--model` with your agent's `.imx`, downloaded with the [Agents API](https://docs.bithuman.ai/api/agents#download-an-agents-model) or `bithuman pull <AGENT_CODE>`.
- **Your own audio:** pass any audio file; or stream microphone audio with `AsyncBithuman` ([Integrate into your app](https://docs.bithuman.ai/platforms/python/app#integrate-into-your-app)).
- **A conversation:** `cloud-avatar.py` in the same folder connects the avatar to an OpenAI voice agent over LiveKit ([LiveKit](https://docs.bithuman.ai/platforms/livekit)).
- **A desktop companion:** `conversation.py` in the same folder talks with you through OpenAI Realtime, with your OpenAI key ([Companion app](https://docs.bithuman.ai/build/companion-app)).
- **A web app:** send the frames from `render()` to your own video stream, or use the [web embed](https://docs.bithuman.ai/platforms/web).

## Platform notes

- The first Essence 2 render downloads a shared audio encoder (about 66 MB) to `~/.bithuman/deps`, once.
- `BITHUMAN_CACHE_DIR` moves the download cache from `~/.cache/bithuman`.
- `python -m bithuman render <AGENT_CODE> <audio>` downloads your own agent's model by code and renders it.
- A process with no API secret, or with a rejected one, refuses at `open` with `NotAuthorised`.

## Reference

- [Python API reference](https://docs.bithuman.ai/platforms/python/reference): every public class and function.
- [Python examples](https://gitlab.com/bithuman/sdk/bithuman-examples/-/tree/main/python): quickstart, local conversation, cloud with LiveKit.
- [Changelog](https://docs.bithuman.ai/changelog) and [Downloads & versions](https://docs.bithuman.ai/downloads).

---

# Python troubleshooting

URL: https://docs.bithuman.ai/platforms/python/troubleshooting

> Fix Python install, secret and rendering errors by symptom.

| Symptom | Cause | Fix |
|---|---|---|
| `error: externally-managed-environment` | `pip` targeted the system Python | create and activate a venv |
| `ModuleNotFoundError: No module named 'bithuman'` | the venv is not active in this terminal | `source .venv/bin/activate` |
| `pip` finds no wheel | Intel Mac, Windows on Arm, musl, or Python outside 3.10–3.14 | use a supported platform ([Windows](https://docs.bithuman.ai/platforms/windows) needs 64-bit Python on x86_64) |
| `NotSupported` opening an Expression 2 file | the extra is missing | `pip install "bithuman[expression-2]"` |
| `NotAuthorised`: *no credential was supplied* (first frame) or *no API secret was found* (`open`) | no secret in this shell | `export BITHUMAN_API_SECRET=…`; nothing is rendered or written |
| `NotAuthorised` at `open`: *that API secret was not accepted* | the secret was rejected; from 2026-10-12, a Free account | create a new one under [API secrets](https://www.bithuman.ai/developer/api-keys); on Free, [choose a plan](https://www.bithuman.ai/pricing?from=docs) |
| An MP4 with sound and no picture | a refused render through the deprecated `render_offline` leaves the audio track | render with `bithuman.open(path).render(audio, out_mp4=...)`, which refuses before it writes anything; check the frame count it returns |
| Many `Removing initializer` warnings and short bracketed diagnostic lines during an Essence 2 render | runtime diagnostics | expected |
| Frames look blue | frames are RGB and your display wants BGR | `image[:, :, ::-1]` |
| Raw audio plays slow and long | decoded audio must be 16 kHz mono | pass a file path, or resample to 16 kHz |
| `404 NOT_FOUND` downloading a model | not your agent and not a sample avatar | check the code under [your agents](https://docs.bithuman.ai/api/agents) |
| The example window never opens (`GUI: NONE`) | the headless OpenCV build won the install | `pip install --force-reinstall --no-deps opencv-python` |
