# 官方协议兼容

已有支持 NovelAI 绘图协议的客户端，可以配置以下地址和本站 API Key，继续使用官方请求字段。需要客户端允许自定义服务地址和 Bearer Token。

```text
Base URL: https://api.hamubox.com/v1/novelai
Authorization: Bearer sk-your-hamubox-api-key
```

Base URL 必须包含 `/v1/novelai`，客户端在其后追加官方原生路径，例如 `/ai/generate-image`。有的客户端分别配置 API 服务地址与图片服务地址，两处都填写上述地址。拼接地址时应保留此前缀，不能用站点根路径覆盖它。本站不接受 NovelAI 官网登录密码或 PST 作为本站鉴权，不代理官方登录、支付、故事、文本生成、语音或云端图片库；本章覆盖 V3、V4、V4.5、V5 的绘图协议。可用模型仍受本站 Key、分组与账号权限约束。

## 路径与格式

| 方法 | 本站完整路径 | 成功响应 |
| --- | --- | --- |
| POST | `/v1/novelai/ai/generate-image` | `application/zip`，单张生成图片 |
| POST | `/v1/novelai/ai/generate-image-stream` | `application/msgpack`，长度帧事件；见[流式协议](https://api.hamubox.com/docs/novelai/streaming/) |
| POST | `/v1/novelai/ai/augment-image` | `application/zip`，Director 处理结果 |
| POST | `/v1/novelai/ai/upscale` | `application/zip`，放大结果 |
| POST | `/v1/novelai/ai/encode-vibe` | 原始编码二进制，不是图片、JSON 或 Base64 文本 |
| POST | `/v1/novelai/ai/generate-image/request-price` | `costPerPrompt`、`numPrompts`、`freePrompts` 等报价字段 |
| GET | `/v1/novelai/ai/generate-image/suggest-tags?model=...&prompt=...` | 原始标签建议 JSON |
| GET | `/v1/novelai/user/data` | 兼容的 `subscription`、`priority` 与本站余额说明 |
| GET | `/v1/novelai/user/subscription` | 兼容的订阅字段 |
| GET | `/v1/novelai/user/priority` | 兼容的优先级字段 |

柏宝绘等客户端误加 `/ai` 前缀的 `GET /v1/novelai/ai/user/subscription` 也可用，与正常订阅路径返回相同结构并要求本站 API Key；这不是官方账户路径，也不代表其他 `/ai/user/*` 路径可用。

同步生图与报价入口兼容部分客户端固定发送的 `parameters.stream: "msgpack"`，忽略该传输提示，分别保持 ZIP 和 JSON 响应。真正的流式生成请使用 `/ai/generate-image-stream`。其他无效 `stream` 值仍会拒绝；异步任务接口中的 `stream: false` 与 `parameters.stream: "msgpack"` 仍视为冲突。

`generate-image` 和 `generate-image-stream` 提交前都会执行[生成结构校验](https://api.hamubox.com/docs/novelai/models/#必填结构与提交校验)。普通 V5 / V4.5 Full 文生图不能只传 `input`：还需要两个结构化提示词对象，没有角色时 `caption.char_captions` 填 `[]`。`request-price` 仍可只传计费所需参数，报价成功不代表生成字段完整。此区别也适用于酒馆插件等第三方客户端；不需要为了报价虚构提示词。

## 完整请求示例

原生生成请求**不加** `operation`、`payload` 包装。下载[原生文生图 JSON](https://api.hamubox.com/docs/examples/novelai-native-generate.json)后直接发送：

```json title="novelai-native-generate.json"
{
  "model": "nai-diffusion-5-curated",
  "input": "a blue ceramic cup on a wooden table, soft daylight, illustration",
  "action": "generate",
  "parameters": {
    "params_version": 4,
    "width": 832,
    "height": 1216,
    "steps": 23,
    "scale": 5,
    "sampler": "k_euler_ancestral",
    "noise_schedule": "karras",
    "seed": 42,
    "n_samples": 1,
    "image_format": "png",
    "uc": "lowres, blurry",
    "v4_prompt": {
      "caption": {
        "base_caption": "a blue ceramic cup on a wooden table, soft daylight, illustration",
        "char_captions": []
      },
      "use_coords": false,
      "use_order": true
    },
    "v4_negative_prompt": {
      "caption": {
        "base_caption": "lowres, blurry",
        "char_captions": []
      },
      "use_coords": false,
      "use_order": false
    }
  }
}
```

```bash
curl --fail-with-body 'https://api.hamubox.com/v1/novelai/ai/generate-image' \
  -H "Authorization: Bearer $HAMUBOX_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary @novelai-native-generate.json \
  --dump-header result-headers.txt --output result.zip
```

以下下载均为完整原生请求体。素材示例中的 `https://example.com/...` 需替换为实际文件直链，不能直接用于生成。

| 操作 | 请求路径 | 请求 JSON | 成功内容 |
| --- | --- | --- | --- |
| 图生图 | `/v1/novelai/ai/generate-image` | [novelai-native-img2img.json](https://api.hamubox.com/docs/examples/novelai-native-img2img.json) | ZIP |
| 局部重绘 | `/v1/novelai/ai/generate-image` | [novelai-native-inpaint.json](https://api.hamubox.com/docs/examples/novelai-native-inpaint.json) | ZIP |
| Director 提取线稿 | `/v1/novelai/ai/augment-image` | [novelai-native-director.json](https://api.hamubox.com/docs/examples/novelai-native-director.json) | ZIP |
| 放大 | `/v1/novelai/ai/upscale` | [novelai-native-upscale.json](https://api.hamubox.com/docs/examples/novelai-native-upscale.json) | ZIP |
| 氛围编码 | `/v1/novelai/ai/encode-vibe` | [novelai-native-vibe.json](https://api.hamubox.com/docs/examples/novelai-native-vibe.json) | 编码二进制 |

例如放大请求：

```bash
curl --fail-with-body 'https://api.hamubox.com/v1/novelai/ai/upscale' \
  -H "Authorization: Bearer $HAMUBOX_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary @novelai-native-upscale.json \
  --dump-header result-headers.txt --output result.zip
```

图生图、局部重绘、角色提示词等按共用的[绘图参数](https://api.hamubox.com/docs/novelai/models/)填写。原生局部重绘的 `model` 填写实际 inpainting 模型；V5 Curated 对应 `nai-diffusion-4-5-curated-inpainting`。

Director/Upscale 官方请求不要求模型；本站从当前 Key 已开放的 NAI 模型中选择路由，也支持额外提供 `model` 明确指定，下载示例采用后一种方式。JSON 与官方 `multipart/form-data` 均可用：`request` 为 JSON 或 JSON Blob，素材字段引用其余二进制 part 的名称，见[完整 multipart 示例](https://api.hamubox.com/docs/novelai/streaming/#multipart-素材)。显式 `0`、`false`、专业参数与未知绘图参数不会因兼容转换而丢失。

## 生成张数与费用

本站暂时仅支持每次生成一张图片，原生普通接口、流式接口、报价接口及异步任务入口均相同。`parameters.n_samples` 可以省略（默认 1），填写时必须为 `1`。其他张数会在发起生成和预扣前返回 HTTP 400，不会自动截成一张，也不会拆成多个请求。

需要多张图片时，由客户端分别发起单张请求；每次请求独立排队、计费并记录任务 ID。这样可以避免一次批量生成引入额外 Anlas 费用，但高分辨率、步数和参考功能等仍可能产生费用。

普通响应仍使用官方 ZIP 格式，流式成品帧保留 `samp_ix` 字段。基础费用按单张收取，Anlas 按实际消耗结算；使用相同的用户余额、NAI 点数、Key 限额和分组倍率。

## 参考素材缓存

支持 `image_cache_secret_key`、`mask_cache_secret_key`、`reference_image_cache_secret_key`，以及 `reference_image_multiple_cached[]`、`director_reference_images_cached[]` 中的 `cache_secret_key`。

Vibe 和精准参考的普通 / 缓存数组为 `[]`、`null` 或省略时，表示没有参考图；非空数组仍校验模型能力。V5 目前不支持这两类参考，不能通过填写零计数来绕过限制。

首次请求同时带素材数据和缓存键。素材进入本站文件服务后，只缓存其文件地址，缓存按本站用户隔离、有效期一小时，容量不足或服务重启也可能提前失效。后续可只提交缓存键，本站恢复素材后再交给本次调度的账号，不依赖上一次使用的上游账号。

缓存失效时，生成尚未提交，响应为 HTTP 400：

```json
{
  "statusCode": 400,
  "message": "INVALID_CACHE_KEYS",
  "error": "INVALID_CACHE_KEYS",
  "details": {"invalidKeys": ["the-client-cache-key"]}
}
```

客户端补传这些键对应的原始素材即可。缓存键不写入任务参数或日志，也不会转发给上游。

## 账户与报价

`/v1/novelai/user/data`、`/v1/novelai/user/subscription` 返回的是**本站虚拟兼容账户**。`tier: 3` 用于让客户端显示绘图功能，不代表赠送官方会员、免费生成或展示平台上游账号。不会返回平台账号的真实 Anlas、V5 电量或会员到期时间。

`trainingStepsLeft.purchasedTrainingSteps` 按 **1000 个兼容显示单位 = 1 美元**换算本站可用余额和已启用的 NAI 点数，并受当前 Key 额度上限约束。某些客户端会把此字段标为 Anlas；它不是官方 Anlas。订阅等特殊资金来源的实际可用额，以本站预扣检查为准。

报价请求保留官方形状：

```json
{
  "tier": "OPUS",
  "request": {
    "input": "a blue ceramic cup",
    "model": "nai-diffusion-5-curated",
    "action": "generate",
    "parameters": {"width": 832, "height": 1216, "steps": 23, "n_samples": 1}
  }
}
```

响应的 `costPerPrompt` 使用同一套兼容显示单位，包含本站基础费用和实际倍率；向上取整后的显示值可能略高于实际预估。`numPrompts` 为 1，`freePrompts` 为 0；调用方传入的 `tier` 不改变售价。扩展字段 `hamubox.estimatedCostUSD` 提供准确的美元预估，最终费用见任务的 `usage.actual_cost_usd`。

## 留档与中断恢复

原生生成仍创建任务日志并保存参考素材和结果，资产库与任务详情的展示规则见[常见问题](https://api.hamubox.com/docs/novelai/faq/#参考素材是否进入资产库)。返回头 `X-NovelAI-Task-Id` 可用于 [GET 任务接口](https://api.hamubox.com/docs/novelai/tasks/#查询与恢复)查询结果和结算，客户端只能查询自己所属用户的任务。

成图校验后优先交付客户端，后台继续转存和结算。临时快速交付缓存最多保留十分钟；结果超过 32 MiB 或缓存不可用时，等待持久化后交付。PNG 元数据会保留或补齐，显式 WebP 保留原始格式。

客户端断线不会取消已提交任务。同步连接最长等待十分钟；超时并不证明任务失败，必须先查已有任务。不要自动重发 POST，以免重复生成和计费。原生错误使用 `statusCode`、`message`、字符串 `error`；流式开始后的错误使用流内 `error` 事件。

例如缺少负向提示词对象时，提交前返回 HTTP 400，不预扣、不创建生成任务；`message` 与 `error` 保持相同字符串，便于原生客户端展示：

```json
{
  "statusCode": 400,
  "message": "invalid NovelAI generation parameters: parameters.v4_negative_prompt is required; provide caption.char_captions: [] when there are no characters",
  "error": "invalid NovelAI generation parameters: parameters.v4_negative_prompt is required; provide caption.char_captions: [] when there are no characters"
}
```
