bithuman
Run a bitHuman avatar on your own machine, in your own process.
pip install bithuman
DEMO=$(python -c 'import bithuman,os; print(os.path.join(os.path.dirname(bithuman.__file__), "assets", "demo_sample.wav"))')
python -m bithuman render sofia-ramirez "$DEMO" # -> sofia-ramirez.mp4
Two arguments — an avatar and some audio — and a video you can play (with
your API secret in BITHUMAN_API_SECRET; see the key). The
avatar is a showcase name (python -m bithuman list), your agent's ten-character
code (python -m bithuman list --mine; fetched once, which is free), or a file
you already have. The audio above is 15 s of speech that ships with this package,
so the first run needs nothing you do not already have. The commands are
spelled as in the separate bithuman CLI: render <avatar> <audio> [-o out.mp4] [--limit N] [--json] and list [--mine]. If you signed in with that CLI
(bithuman login, which this package does not install), the secret it saved is
read here too.
In your own program it is the same two things. The command above fetched the
avatar to ~/.cache/bithuman/showcase/:
import bithuman, os
speech = os.path.join(os.path.dirname(bithuman.__file__),
"assets", "demo_sample.wav") # 15 s, ships in the wheel
avatar_file = os.path.expanduser("~/.cache/bithuman/showcase/sofia-ramirez.imx")
avatar = bithuman.open(avatar_file)
frames = 0
for image in avatar.render(speech): # each image: (height, width, 3) uint8, RGB
frames += 1
print(frames, "frames")
That is the whole thing: open an avatar, then render audio through it.
every family, the same two lines
Essence 1, Essence 2 (full body essence-2, or face only essence-2f)
and Expression 2 avatars are opened and rendered by the code above,
unchanged. Nothing you write says which one you have, and you do not have to
know.
Two families need one extra package on the machine:
pip install "bithuman[essence-2]" # the new Essence 2
pip install "bithuman[expression-2]" # Expression 2
Open one of those avatars without its extra and the refusal says so, and says that line. Nothing else differs.
from the command line
python -m bithuman render <avatar> speech.wav # -> <avatar>.mp4
python -m bithuman render <avatar> speech.wav --mode face # new Essence 2: face only
python -m bithuman pull <avatar> # fetch it now, render later with no network
python -m bithuman pack redeem # install a prepaid offline pack on this machine
With an offline pack installed, a machine renders with no network and no API secret until the pack is spent; an avatar fetched before is used as it is.
The surface
| you write | it means |
|---|---|
bithuman.open(source) |
open the avatar file on this machine; returns an Avatar |
avatar.render(audio) |
yield the frames for that audio |
Avatar |
what open gives you |
AvatarError |
catch this for any refusal |
InvalidAvatar |
we cannot find it, or it is not a usable avatar |
NotSupported |
this avatar cannot run here |
NotAuthorised |
the key is missing, invalid, or out of credit |
Failed |
we could not do it — the message says which |
There is nothing to configure: this package runs the avatar on this machine.
For a live conversation, where audio arrives as it is spoken, use
AsyncBithuman (streaming below).
audio in
audio is 16 kHz mono, and it is either a buffer or a stream — the same call:
avatar.render(speech) # an audio file path
avatar.render(samples) # int16 or float32 in [-1, 1]
avatar.render(raw_bytes) # 16 kHz mono, signed 16-bit
avatar.render(microphone()) # any iterable of the above
frames out
Each frame is a (height, width, 3) uint8 array in RGB order, in order, at
the avatar's own frame rate, which is a property of the avatar, not something
to choose: 25 per second for Essence 2, 20 per second for Expression 2.
import cv2
for image in avatar.render(speech):
cv2.imshow("avatar", image[:, :, ::-1]) # OpenCV wants BGR
cv2.waitKey(1)
stopping early
Someone interrupting the avatar is "stop consuming and close the iterator":
images = avatar.render(speech)
for n, image in enumerate(images):
if n == 50: # e.g. the user started talking
images.close()
break
releasing it
with frees everything at the end of the block; without it, the avatar is
freed when it is garbage collected.
with bithuman.open(avatar_file) as avatar:
for image in avatar.render(speech):
frames += 1
streaming a live conversation
AsyncBithuman takes audio as it arrives and yields frames with their audio,
paced at the avatar's play rate:
from bithuman import AsyncBithuman # inside an async function:
avatar = await AsyncBithuman.create(model_path=avatar_file) # reads BITHUMAN_API_SECRET
await avatar.push_audio(pcm16_bytes, 16000, last_chunk=False) # as the audio arrives
await avatar.flush() # end of the reply
async for frame in avatar.run():
if frame.has_image:
show(frame.bgr_image) # BGR numpy array
if frame.audio_chunk:
play(frame.audio_chunk.array) # the audio that goes with this frame
await avatar.shutdown()
The full example is at https://docs.bithuman.ai/platforms/python/app.
The four refusals
Each one leads to a different fix, and none of them asks you to know anything about how we are built.
try:
avatar = bithuman.open(avatar_file)
for image in avatar.render(speech):
pass
except bithuman.InvalidAvatar:
... # fix the path or the code, or fetch the avatar again
except bithuman.NotSupported:
... # use the cloud package, or another device
except bithuman.NotAuthorised:
... # fix the credential
except bithuman.Failed:
... # retry, then report it
Every one of them is an AvatarError, so except bithuman.AvatarError catches
all four.
The key
Rendering is metered, and the key belongs in the environment rather than in your code:
export BITHUMAN_API_SECRET=...
Without one, render refuses with NotAuthorised before it hands you a
frame. Get a key at https://www.bithuman.ai/developer/api-keys.
python -m bithuman also reads a .env file in the current directory; that is
deprecated and will stop, so export the variable instead. What is already in
the environment always wins.
Where it runs
| Python | 3.10 – 3.14 |
| macOS | Apple silicon |
| Linux | x86-64 and arm64 |
| Windows | Windows 11, x86-64 (64-bit Python) |
| Intel Macs, Windows on Arm | no wheel — pip install refuses rather than quietly giving you an old release |
ffmpeg is used to read an audio file when it is on your PATH; when it is
not, the decoder this package already installs reads the same file in this
process, so it is not something to install first.
Three environment variables:
BITHUMAN_API_SECRET |
your API secret, from https://www.bithuman.ai/developer/api-keys — rendering is metered, so it is required unless you pass api_secret=. BITHUMAN_API_KEY is read as a deprecated alias |
BITHUMAN_CACHE_DIR |
where a prepared avatar is kept (default ~/.cache/bithuman) |
BITHUMAN_AVATAR_CACHE_GB |
the most space prepared avatars may take (default 10). One copy is kept per avatar file content; the least recently used ones that no process has open are removed above it |
This package never puts a command on your PATH
pip install bithuman installs a library and nothing else — and
python -m bithuman is why that costs you nothing: a module needs no script,
cannot collide with one, and is there the moment pip finishes. The full
bithuman command-line tool (a live avatar, a conversation) is a different
artifact and is not installed with pip:
curl -fsSL https://install.bithuman.ai | sh
brew tap bithuman/bithuman https://gitlab.com/bithuman/sdk/homebrew-bithuman \
&& brew install bithuman/bithuman/bithuman-cli # macOS, equivalently (always tap with the URL)
That is on purpose: a pip-installed command named bithuman would overwrite
the one the CLI installer or Homebrew put at the same path.
Using it from a LiveKit agent
The LiveKit integration is a separate package, livekit-plugins-bithuman,
published by LiveKit out of github.com/livekit/agents:
pip install livekit-plugins-bithuman "bithuman[expression-2]"
Do not give that plugin your account API secret. Up to and including
1.8.4, the plugin copies the secret it is given into the avatar's participant
attributes, which every participant in the LiveKit room can read. Keep the
secret on your server under another name (BITHUMAN_MASTER_SECRET), mint a
one-hour runtime token per session (POST /v1/runtime-tokens/mint) and pass
that token to the plugin instead. The worker is at
https://docs.bithuman.ai/platforms/livekit.
Licence
Proprietary — this package carries the runtime. See LICENSE.
Metadata
Release files for bithuman 2.12.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| bithuman-2.12.2-cp314-cp314-win_amd64.whl | CPython 3.14 | CPython 3.14 | Windows x86-64 | Details |
| bithuman-2.12.2-cp313-cp313-win_amd64.whl | CPython 3.13 | CPython 3.13 | Windows x86-64 | Details |
| bithuman-2.12.2-cp312-cp312-win_amd64.whl | CPython 3.12 | CPython 3.12 | Windows x86-64 | Details |
| bithuman-2.12.2-cp311-cp311-win_amd64.whl | CPython 3.11 | CPython 3.11 | Windows x86-64 | Details |
| bithuman-2.12.2-cp310-cp310-win_amd64.whl | CPython 3.10 | CPython 3.10 | Windows x86-64 | Details |
Total release size: 66.4 MB
Release files / bithuman-2.12.2-cp314-cp314-win_amd64.whl
| Download URL | bithuman-2.12.2-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 13.5 MB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
e138051af186f323bcd53bf9b05c4bf5d5c712ed16a965a532af06dc2fc2d7c4
|
|
BLAKE2b-256 checksum How to use checksums |
d5da55089afe4fd931213a98aa4e372378f22d727193adf1b0ea7f4587be2644
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / bithuman-2.12.2-cp313-cp313-win_amd64.whl
| Download URL | bithuman-2.12.2-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
e7c8602bfd777553572fa0aa94dd482c171e2a10883e8d4093c7bd33a118206d
|
|
BLAKE2b-256 checksum How to use checksums |
c3d65443c4430100a9b4815fc394eca748618b6c757ea8e0d58dce3e7f52c95f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / bithuman-2.12.2-cp312-cp312-win_amd64.whl
| Download URL | bithuman-2.12.2-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
2ec844b85b4a1181df2152ffdb7f1ede3c37acfc97aefaaae5132f228736ef6b
|
|
BLAKE2b-256 checksum How to use checksums |
0e2eef3670df1cb2190a9beabd54b2016fd6724451994fcad9acfef7c6cf326f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / bithuman-2.12.2-cp311-cp311-win_amd64.whl
| Download URL | bithuman-2.12.2-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
eedbf7cc71d6ceaf306184cf4fe1cd3fca10655ee6de9340abdd5153b9699214
|
|
BLAKE2b-256 checksum How to use checksums |
d2ae62d18d68da24b1bfa2ba366415f3c10325f1306f409205622cf10ce19bff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / bithuman-2.12.2-cp310-cp310-win_amd64.whl
| Download URL | bithuman-2.12.2-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
b323ac18d66c4fb1d0f9ec5d82947e2ec38cc7886b346f3bd090ca445b527a5d
|
|
BLAKE2b-256 checksum How to use checksums |
e5d17702bcc58683b64d827d1392ffb0b2a34578e16333bc6d58ce27c0eaa1b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|