AioTraceMoeAPI
A simple but extensible asynchronous Python wrapper for the trace.moe API.
Key Features
- Async: Built on top of
httpx. - Typed: Fully typed (ships
py.typed), with Pydantic v2 models for every response. - Complete: Search by URL, file, bytes or ColorLayout vector (including batch search),
/mequota and usage history, preview URL helpers. - Precise errors: A dedicated exception for every API error, with optional automatic retries.
Installation
Python 3.10+ is required.
uv add aiotracemoeapi
or
pip install aiotracemoeapi
Usage
Search by URL, file or bytes
import asyncio
from aiotracemoeapi import TraceMoe
async def main():
async with TraceMoe() as api:
# URLs are detected automatically
response = await api.search("https://images.plurk.com/32B15UXxymfSMwKGTObY5e.jpg")
# A local file path, pathlib.Path, bytes or a binary file object work too
# response = await api.search("image.jpg")
# response = await api.search(open("image.jpg", "rb"))
best = response.best_result
if best is None:
print("No results found.")
return
print(f"Anime: {best.anilist_info.title.romaji}") # AniList info is included by default
print(f"Episode: {best.episode_start}")
print(f"Scene: {best.anime_from:.1f}s - {best.anime_to:.1f}s, best frame at {best.at:.1f}s")
print(f"Similarity: {best.short_similarity()}") # below 90% is most likely a wrong result
print(f"Preview: {best.video_url(size='l', mute=True)}") # preview URLs expire in 5 minutes
print(f"Quota used: {response.quota_used}/{response.quota}")
if __name__ == "__main__":
asyncio.run(main())
Search options:
from aiotracemoeapi import CutBorders
await api.search(
"image.jpg",
anilist_id=21034, # search only within one anime
anilist_info=False, # return only AniList IDs (faster)
cut_borders=CutBorders.BOTH, # search with both the original and the cut image (may cost 2 credits)
)
Search by ColorLayout vector
If you already have the 33-dimensional MPEG-7 ColorLayout vector (see trace.moe-id), search by the vector directly. This is faster and saves bandwidth:
response = await api.search_vector("gwebWzth7oPe2UIubOJmozi1NDFp") # base64 hash or 33 numbers
# Batch search: up to 10 vectors, each one costs 1 search credit
batch = await api.search_vectors([vector1, vector2])
for best in batch.best_results:
print(best)
Account quota and usage
async def main():
# Get your API key at https://trace.moe/account; without a key you are identified by your IP address
async with TraceMoe(token="your_token_here") as api:
me = await api.me()
print(f"Priority: {me.priority}, concurrency: {me.concurrency}")
print(f"Quota: {me.quota_used}/{me.quota} used in the last 24 hours, {me.quota_left} left")
for slot in await api.usage("day"):
print(slot.time, slot.total, slot.by_status)
Error handling and retries
Every API error has its own exception. All of them subclass TraceMoeAPIError:
| Exception | Parent | When |
|---|---|---|
InvalidImageUrl, FailedProcessImage |
BadRequest |
Bad URL or image that cannot be decoded |
InvalidVector, TooManyVectors |
BadRequest |
Bad vector search input |
FailedFetchImage |
TraceMoeAPIError |
The server could not download the URL |
SearchQuotaDepleted, ConcurrencyLimitExceeded |
PaymentRequired |
24h quota depleted / too many parallel requests |
InvalidAPIKey |
ForbiddenError |
Wrong API key |
PayloadTooLarge |
TraceMoeAPIError |
File larger than 25MB |
TooManyRequests |
TraceMoeAPIError |
More than 100 requests per minute |
SearchQueueFull |
ServiceUnavailable |
Server is busy |
InternalServerError, GatewayTimeout |
TraceMoeAPIError |
Server errors |
from aiotracemoeapi import SearchQuotaDepleted, TraceMoe, TraceMoeAPIError
# Retry up to 3 times on concurrency limit, rate limit, full queue or overload errors
async with TraceMoe(max_retries=3, retry_delay=1.0) as api:
try:
response = await api.search("image.jpg")
except SearchQuotaDepleted as e:
print(f"Quota depleted: {e.quota_used}/{e.quota}")
except TraceMoeAPIError as e:
print(f"API error {e.status_code}: {e.text}")
Custom HTTP client or server
import httpx
async with httpx.AsyncClient(proxy="http://localhost:8080") as client:
api = TraceMoe(client=client) # your client is not closed by the wrapper
...
api = TraceMoe(base_url="https://trace.example.com") # self-hosted trace.moe-api
Examples
The examples folder has ready-to-run scripts: a command-line search, quota and usage report, searching a whole folder in parallel, vector search, downloading previews and a Telegram bot on aiogram 3.
uv run examples/console.py https://images.plurk.com/32B15UXxymfSMwKGTObY5e.jpg
uv run examples/batch_folder.py ./screenshots results.csv
BOT_TOKEN=123:abc uv run examples/telegram_bot.py
Development
uv sync
make check # ruff, mypy and pytest
See CHANGELOG.md for the list of changes, including how to migrate from 3.x.
Metadata
Release files for aiotracemoeapi 4.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aiotracemoeapi-4.0.1.tar.gz | 12.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aiotracemoeapi-4.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.8 kB
Release files / aiotracemoeapi-4.0.1.tar.gz
| Download URL | aiotracemoeapi-4.0.1.tar.gz |
|---|---|
| Size | 12.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a16ecb4227a727788545392cac34c6d9e38f6d510f1e211a4d037628858ef461
|
|
BLAKE2b-256 checksum How to use checksums |
96ea6e9a931ec7687661d8897da0ff7ee5a3b5a46e6c924a2edec3f50d38972c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / aiotracemoeapi-4.0.1-py3-none-any.whl
| Download URL | aiotracemoeapi-4.0.1-py3-none-any.whl |
|---|---|
| Size | 15.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ebe32074d81e1f95ea6dbb0903eb50f0f3171252a22834992018ab70f2661470
|
|
BLAKE2b-256 checksum How to use checksums |
1964a88b13416cb38615f694ad1f4e8376e8dacc7394f2048a96ea7ab0dd0e6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|