Skip to main content

NekoAI-API

PyPI version Python versions License Downloads CI

An async, fully typed Python client for the NovelAI API, covering image generation (with first-class support for the V4.5 model family), text generation, Director image tools, and account utilities.

Request payloads are validated with pydantic and verified field-by-field against payloads captured from the NovelAI web client, so what this library sends is what the website sends.

Features

  • Image generation — text-to-image, img2img, inpainting, and vibe transfer (reference images are encoded through /ai/encode-vibe automatically, with caching) for every model from V3 to V4.5.
  • V4.5 support — multi-character prompts with canvas positioning, character-level undesired content, and real-time streaming of denoising steps.
  • Text generation — story continuation with Erato, Kayra, and Clio. Plain text in, plain text out, with optional token-by-token streaming.
  • Director tools — line art, sketch, background removal, declutter, colorize, and emotion change, each as a single method call.
  • Utilities — upscaling, tag autocompletion, ControlNet annotation, and subscription/Anlas queries.
  • Robust by default — automatic retry with backoff on rate limits, optional client-side request throttling, and typed exceptions.
  • CLI — the nekoai command exposes generation, tools, and account queries for shell usage and scripting.
  • Custom hosts — every endpoint group can be pointed at a reverse proxy or self-hosted gateway.

Installation

Requires Python 3.10 or later.

pip install -U nekoai-api
# or
uv add nekoai-api

Quick Start

import asyncio

from nekoai import Model, NovelAI, Resolution


async def main():
    # Reads the token from the NAI_TOKEN environment variable when omitted
    async with NovelAI(token="your_access_token") as client:
        images = await client.generate_image(
            prompt="1girl, silver hair, blue eyes, white dress, flower garden",
            model=Model.V4_5,
            res_preset=Resolution.NORMAL_PORTRAIT,
        )
        for image in images:
            image.save("output")


asyncio.run(main())

Authentication

The client accepts either an access token or account credentials:

NovelAI(token="...")                            # explicit token
NovelAI()                                       # token from $NAI_TOKEN
NovelAI(username="user@example.com", password="...")

To obtain a persistent token, log in once and store the result:

nekoai login <username> <password>

Image Generation

generate_image accepts either a prepared Metadata object or keyword arguments, and returns a list of Image objects. All parameters are validated before the request is sent; see the Metadata docstring for the full set.

Models

Model Enum Inpainting variant
NAI Diffusion V4.5 Full (recommended) Model.V4_5 Model.V4_5_INP
NAI Diffusion V4.5 Curated Model.V4_5_CUR Model.V4_5_CUR_INP
NAI Diffusion V4 Full Model.V4 Model.V4_INP
NAI Diffusion V4 Curated Model.V4_CUR Model.V4_CUR_INP
NAI Diffusion V3 Model.V3 Model.V3_INP
NAI Diffusion Furry V3 Model.FURRY Model.FURRY_INP

Common parameters

images = await client.generate_image(
    prompt="1girl, cute",
    model=Model.V4_5,               # default: Model.V4_5
    res_preset=Resolution.NORMAL_SQUARE,  # or width=..., height=...
    steps=28,
    scale=6.0,                      # prompt guidance
    seed=1234567890,                # random when omitted
    n_samples=1,
    negative_prompt="lowres",
    qualityToggle=True,             # append model quality tags
    ucPreset=0,                     # undesired-content preset (varies by model)
)

Multi-character prompts (V4/V4.5)

Each character gets its own prompt, undesired content, and canvas position:

from nekoai import CharacterPrompt, PositionCoords

images = await client.generate_image(
    prompt="two people standing together, park background",
    model=Model.V4_5,
    res_preset=Resolution.NORMAL_LANDSCAPE,
    characterPrompts=[
        CharacterPrompt(
            prompt="girl, red hair, red dress",
            uc="bad hands, bad anatomy",
            center=PositionCoords(x=0.3, y=0.5),
        ),
        CharacterPrompt(
            prompt="boy, blue hair, blue uniform",
            uc="bad hands, bad anatomy",
            center=PositionCoords(x=0.7, y=0.5),
        ),
    ],
)

Real-time streaming (V4/V4.5)

generate_image_stream yields events for every denoising step, which is useful for progress UIs and timelapses:

from nekoai import EventType

async for event in client.generate_image_stream(
    prompt="1girl, cute, anime style",
    model=Model.V4_5,
    res_preset=Resolution.NORMAL_PORTRAIT,
):
    if event.event_type == EventType.INTERMEDIATE:
        print(f"step {event.step_ix} (sigma={event.sigma:.2f})")
    elif event.event_type == EventType.FINAL:
        event.image.save("output", "final.png")

generate_image works with every model and returns the final images; streaming requires a V4/V4.5 model.

Image to image

from nekoai import Action, parse_image

width, height, base64_image = parse_image("input/source.png")

images = await client.generate_image(
    prompt="1girl, fantasy outfit",
    model=Model.V4_5,
    action=Action.IMG2IMG,
    width=width,
    height=height,
    image=base64_image,
    strength=0.5,  # lower = closer to the original
    noise=0.1,
)

Inpainting

Provide a base image and a black/white mask (white areas are repainted) and use an inpainting model:

from nekoai import Action, parse_image

width, height, base64_image = parse_image("input/portrait.png")
_, _, base64_mask = parse_image("input/mask.png")

images = await client.generate_image(
    prompt="1girl, detailed background",
    model=Model.V4_5_INP,
    action=Action.INPAINT,
    width=width,
    height=height,
    image=base64_image,
    mask=base64_mask,
    add_original_image=True,  # overlay untouched pixels from the original
)

Vibe transfer

Borrow the style and mood of reference images. For V4/V4.5 models the client encodes references through /ai/encode-vibe automatically (2 Anlas per new image; results are cached for the client's lifetime, and the Metadata object can be reused across calls):

from nekoai import parse_image

_, _, reference = parse_image("input/style_reference.png")

images = await client.generate_image(
    prompt="landscape, mountains, sunset",
    model=Model.V4_5,
    res_preset=Resolution.NORMAL_LANDSCAPE,
    reference_image_multiple=[reference],
    reference_information_extracted_multiple=[1.0],
    reference_strength_multiple=[0.7],
)

Text Generation

Continue a story with NovelAI's text models. Input and output are plain text — no tokenizer required. Declared parameters are validated, and any additional sampling parameter accepted by the API (mirostat, cfg, phrase repetition penalty, ...) passes through unchanged:

from nekoai import TextModel

output = await client.generate_text(
    "The dragon circled the tower once more,",
    model=TextModel.ERATO,          # llama-3-erato-v1 (default)
    max_length=150,
    temperature=1.0,
)

# Stream tokens as they are generated:
async for token in client.generate_text_stream("Once upon a time,", max_length=50):
    print(token, end="", flush=True)
Model Enum Identifier
Erato (recommended) TextModel.ERATO llama-3-erato-v1
Kayra TextModel.KAYRA kayra-v1
Clio TextModel.CLIO clio-v1

Other model identifiers can be passed as plain strings. Note that generate_until_sentence (enabled by default) lets the model run slightly past max_length to finish a sentence; disable it for hard caps.

Director Tools

Every Director tool is a single method call. Image inputs accept a file path, pathlib.Path, raw bytes, a file-like object, or a base64 string.

from nekoai import EmotionLevel, EmotionOptions

result = await client.lineart("image.png")             # image to line art
result = await client.sketch("image.png")              # image to sketch
result = await client.background_removal("image.png")  # remove background (costs Anlas)
result = await client.declutter("image.png")           # remove text/artifacts
result = await client.colorize("lineart.png", prompt="silver hair", defry=0)

result = await client.change_emotion(
    "image.png",
    emotion=EmotionOptions.HAPPY,
    emotion_level=EmotionLevel.NORMAL,
)

result.save("output")

Utilities

# Upscale 2x or 4x (costs Anlas)
upscaled = await client.upscale("image.png", scale=4)

# Tag autocompletion
tags = await client.suggest_tags("blue hai")  # [{"tag": "blue hair", ...}, ...]

# ControlNet condition masks (edge/depth preprocessing).
# Note: ControlNet-guided generation is a V1/V2-era feature not supported by V3+.
from nekoai import Controlnet
mask = await client.annotate_image("image.png", model=Controlnet.SCRIBBLER)

# Subscription tier and Anlas balance
subscription = await client.get_subscription()
user_data = await client.get_user_data()

Command Line Interface

Authentication comes from --token, the NAI_TOKEN environment variable, or --username/--password.

Command Purpose
nekoai login <user> <pass> Exchange credentials for an access token
nekoai generate <prompt> Generate images (txt2img, img2img, inpaint, vibe)
nekoai text <prompt> Generate a text continuation
nekoai tool <name> <image> Run a Director or annotation tool
nekoai upscale <image> Upscale an image 2x or 4x
nekoai tags <partial> Suggest completions for a partial tag
nekoai subscription Show subscription info and Anlas balance
export NAI_TOKEN="your_access_token"

nekoai generate "1girl, cute" -m v4_5 -s 832x1216 --steps 28 -n 2
nekoai generate "1girl, cute" --stream                        # live step progress
nekoai generate "1girl, fantasy outfit" --image src.png --strength 0.5   # img2img
nekoai generate "detailed background" --image base.png --mask mask.png   # inpaint
nekoai generate "landscape, sunset" --reference-image style.png          # vibe

nekoai text "Once upon a time," --max-length 80 --stream

nekoai tool lineart image.png
nekoai tool emotion image.png --emotion happy
nekoai upscale image.png --scale 4

Configuration

Custom hosts

Every host can point at a custom base URL (reverse proxy, self-hosted gateway). host serves image and account endpoints, text_host serves text generation, and api_host covers the endpoints still served only by the legacy API host (upscale, ControlNet annotation):

client = NovelAI(
    token="...",
    host="https://your-image-proxy.example.com",      # default: https://image.novelai.net
    text_host="https://your-text-proxy.example.com",  # default: https://text.novelai.net
    api_host="https://your-api-proxy.example.com",    # default: https://api.novelai.net
)

Rate limiting and retries

Requests that hit the rate limit (HTTP 429) are retried with exponential backoff (max_retries, default 2). For batch workloads, rate_limit enforces a minimum spacing between requests client-side:

client = NovelAI(token="...", rate_limit=10)  # at least 10 seconds between requests

Timeouts and connection lifetime

client = NovelAI(token="...")
await client.init(timeout=60)                       # per-request timeout in seconds
await client.init(auto_close=True, close_delay=300) # close idle connections

Error Handling

All exceptions derive from nekoai.NovelAIError:

Exception Raised on
AuthError Invalid or expired credentials (HTTP 401)
APIError Request validation failure (HTTP 400)
NotEnoughCreditsError Insufficient Anlas or no active subscription (HTTP 402)
ConcurrentError Rate limit exceeded after retries (HTTP 429)
TimeoutError Request exceeded the client timeout
ImageProcessingError Unreadable or unsupported input image
from nekoai import NovelAI, NovelAIError

try:
    images = await client.generate_image(prompt="1girl")
except NovelAIError as e:
    print(f"generation failed: {e}")

Examples

One runnable script per feature lives in examples/requests/, each reading NAI_TOKEN from the environment. See its README for the full index and per-feature Anlas costs. NovelAI allows one concurrent generation per account, so run examples one at a time.

Development

The project uses uv for dependency management and ruff for linting and formatting:

uv sync                 # install dependencies (including the dev group)
uv run pytest           # run the test suite
uv run ruff check .     # lint
uv run ruff format .    # format

Payload-shape tests compare generated request bodies against real payloads captured from the NovelAI web client (examples/payloads/); please keep them green when touching Metadata serialization.

License

Licensed under AGPL-3.0. Originally inspired by HanaokaYuzu/NovelAI-API and adopts a copyleft license accordingly.

References

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nekoai_api-0.5.0.tar.gz (50.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nekoai_api-0.5.0-py3-none-any.whl (51.9 kB view details)

Uploaded Python 3

File details

Details for the file nekoai_api-0.5.0.tar.gz.

File metadata

  • Download URL: nekoai_api-0.5.0.tar.gz
  • Upload date:
  • Size: 50.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nekoai_api-0.5.0.tar.gz
Algorithm Hash digest
SHA256 4ea36e16af37572e8533ba6ed84a2c7de9df721e70a1c30b59b1545eb7b86f89
MD5 3295470c5c2735f98a5dbc49f6ce829e
BLAKE2b-256 1c786bafaa7b805de80834163da7254b1c4d04cd1dad45da5858728a6505fa9d

See more details on using hashes here.

Provenance

The following attestation bundles were made for nekoai_api-0.5.0.tar.gz:

Publisher: publish.yml on Nya-Foundation/NekoAI-API

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nekoai_api-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: nekoai_api-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 51.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nekoai_api-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2e6a3ccfd1b16e434ff8b80e07939e03dd07277dfba34fbc8116c0473ad5cbb5
MD5 ea16c1892b044cd0efde3d6a8a8b6e60
BLAKE2b-256 b141e830fc8b2736aa5a024617cccd4f2a2578b0b1d0a5490e01a33478248b7a

See more details on using hashes here.

Provenance

The following attestation bundles were made for nekoai_api-0.5.0-py3-none-any.whl:

Publisher: publish.yml on Nya-Foundation/NekoAI-API

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page