# 读声 Readcue > 读声(https://readcue.top)把小说和文稿做成多角色、有情绪的有声书:AI 识别说话人、按句标注情绪与停顿,再整章一键生成(Fish Audio TTS),最后导出 MP3。本文件写给代表用户操作读声的 AI 助手(agent)。 把这份说明交给你的 AI 助手,再在读声「账号设置 → AI 助手接入」里创建一个 API 令牌发给它。助手就能替你完成整本书,你只需要听结果。 ## 给 agent 的约定 - 只处理用户本人有权使用的文本;不要用读声模仿真实人物的声音。 - 令牌只能访问签发账号拥有的项目及其片段、候选、音频和导出,不含管理与账号设置;管理员签发的个人令牌也不能访问其他账号的作品。不要把令牌写进公开位置,也不要回显给第三方。 - 用户有每日免费额度,额度按字节和次数计。生成失败或额度不足时,如实告诉用户原因,不要反复重试。 - 轮询间隔不少于 10 秒;每个令牌每分钟最多 120 次请求。 - 完整技能说明(可作为 agent skill 安装):https://readcue.top/agent/SKILL.md ## 鉴权 所有请求都加请求头:`Authorization: Bearer rc_...`。基础地址:`https://readcue.top/api`。请求和响应都是 JSON(音频下载除外)。 ## 最短路径:一键成书 1. 创建项目:`POST /api/projects`,body 为 `{"text":""}`,返回 `{id, title, segments: [...]}`。`title` 可省略/null/空白,默认取正文首个可见非空行(最多30个Unicode字符,过长加“…”;兜底“未命名作品”)。已知书名/文件名时可显式传入,非空标题最多200字符,不静默截断;不调用模型或自动生成音频。保存后 `PATCH /api/projects/{id}`,body `{"expected_title":"读取时原名","title":"新名"}`;新名须含可见字符且最多200字符,409时先GET核对,保留草稿,不盲目覆盖。个人令牌仍限本人项目。 2. (可选)挑音色:`GET /api/voices?q=<关键词>&language=zh|en|ja&page=1` 搜公开音色,记下 `id` 和 `title`。 3. 先 `GET /api/projects/{id}/autopilot/preflight`,核对范围、准入及 `start_fingerprint`,再启动 `POST /api/projects/{id}/autopilot`。以下描述新版接口契约,不表示任何外部服务已经部署;body 示例: ```json {"request_key":"<本次授权UUID>","fingerprint":"<预检start_fingerprint>","emotion": "standard", "voices": {"narrator": {"voice_id": "<音色id>", "voice_title": "<音色名>"}, "roles": {"林渊": {"voice_id": "...", "voice_title": "..."}}}, "pause_for_voices": true} ``` - `emotion`:`off` / `subtle` / `standard` / `dramatic`。 - `genre`:`female`(女频)/ `male`(男频)/ `general`(通用,默认)。没有音色的角色和旁白会按题材预设自动配好,之后都可以改。 - 开始前`GET /api/projects/{id}/autopilot/preflight`:查看`next_bytes/next_requests`、日余额、并发及结构化`blockers`。`daily_capacity`仅为日额度容量,不能表示已完成或整批预算已获准。 - `waiting_voices` 或 `resume_requires:"voices"` 时读取实时 `speaker_review` 与 `GET /api/projects/{id}/roles`,核对 roles.version 与 speaker_review.roles_version,检查人物、role_examples 与全部未指派数量。只自动采用非空高置信建议;低置信、未知、遗漏或失败即使 pause_for_voices=false 也强制确认。例外:识别写明原因判为「不是对白」的引号内容(绰号、网名、拟声、信件、招牌等,`not_dialogue:true` 且原因不含「有人 / 台下 / 喊」等)计入 `speaker_review.narration_count`,由旁白读、不单独停下;这类超过本次对白 30% 时仍须确认。选音色后 `POST /api/projects/{id}/autopilot/{run_id}/resume`,body `{"request_key":"<本次继续命令UUID>","expected_dialogue_fingerprint":"<本次核对的fingerprint>","allow_narrator_for_unassigned":false,"voices":{...}}`。未知须先处理,或取得用户对本次全部未指派使用旁白的明确授权后设true;角色未选独立音色的旁白兜底也须说明。 - 人物或对白变化使旧确认409;保留音色草稿并明确重读,不用轮询指纹扩大旧授权。在人物阶段手动暂停仍保留 `resume_requires:"voices"` 的完整确认要求;只有没有此要求的 `paused_quota` 或 `paused_user` 才仅提交 `{"request_key":"<本次继续命令UUID>"}`。每个命令在发送前保存完整原 body。 - 默认 `health_retry=false`,规则体检不追加 TTS。启用前须取得用户对本书范围、次数、费用承担方及报价上限的明确授权:先GET项目和preflight,再随启动请求带 `{"health_retry":true,"health_retry_scope":[{"segment_id":"<本书片段UUID>","revision":1}],"health_retry_credential":"platform","health_retry_max_takes":1,"health_retry_max_usd":"0.100000"}`。scope列全本书刚核对的ID/修订,类别为`platform|owner`;不匹配409,不能自动扩大旧授权。 - 仅一轮,每原片段最多一个额外整段候选;按已知报价可负担的确定前缀受理,受次数和平台USD上限约束。初次生成另计;BYOK平台0不代表供应商免费,外部账单不受此USD上限约束。历史缺冻结授权只检查;失败、持续异常、配额或并发阻断不再追加轮次。 4. 每10–20秒只读轮询原 run ID:`GET /api/projects/{id}/autopilot/{run_id}`。本次完成事实来自 `progress`:generation 分列 queued/running/ready/failed/uncertain/cancelled/not_submitted/reused_ready,采用为 adopted_segments,导出为 export.id/status/ready;rows 提供固定范围/修订、原候选、复用/采用和块完成数,waiting 为当前等待原因。scope_known=false 或 null 保持历史未知,不按当前项目补零。quota 仅为项目当前准入,daily_capacity 只是日额度容量,均不是本次完成数。七个 steps 在终态也保留各自 status 与 reason,不把跳过或取消说成完成,不猜全局百分比或 ETA。 - 只执行 `allowed_actions` 中的 pause/resume/cancel。`paused_user` 是手动暂停,必须明确恢复;`paused_quota` 按 blockers/reset_at 核对当前准入,不能把预算、配置或报价问题说成次日恢复。running 仅受 concurrency 阻断时等空位,不重新启动。 - `POST .../autopilot/{run_id}/pause` 或 `/cancel` body 为 `{"request_key":"<本次命令UUID>"}`。停止后不自动采用或导出;未发送部分停止并释放对应预算,但已占日额度不退。已发送请求可能完成和计费,不能强行撤回。control.unsent_cancelled/in_flight/unsettled_count/released_usd 报告实际事实;终态仍有 in_flight/unsettled_count 时继续只读观察。不触及独立手工请求。 5. 完成后,`result.audio_url` 就是整本 MP3(同样带令牌下载),`result.subtitle_url` 是字幕(如有)。 ## 质量事实与额外重做计量 - 分开报告候选生成`status`、`review.rule_check`、`asr.status`、`review.human_status`、`review.approval_source/delivery_approved`及`accepted_take_id`。规则结果为`not_ready/unjudgeable/clear/partial/flagged`;短文/缺时长可无法判断。语速启发式不验证逐字、读音或听感。 - 自动采用仍为待人工听,不写人工听过历史;历史来源未知不反推人工确认。ASR失败可保留ready音频,ASR须另行估价、明确提交,不隐式重跑TTS。 - `health.candidate_submissions/completed_candidates`区分额外受理与就绪,`provider_chunks/provider_chunks_completed`区分计划与已成功上游块数,另报`tts_input_utf8_bytes/quoted_usd`。仍异常或重做失败须停人工处理,不把已提交说成已完成,不为补齐结果另开付费流程。 - 只有用户实际完整试听后的明确确认才提交人工`review`;只选已有交付依据的版本用`accept`,不伪造听过。较新的人工采用、重开判断与重读意图会阻止旧自动任务覆盖。 ## 独立说话人识别 - `GET /api/projects/{id}/dialogue/scan` 核对全量、未指派、本次范围与遗漏、`output_tokens/reserve_usd` 和独立分析次数。确认后POST `{"request_key":"<新UUID>","fingerprint":"<刚核对的fingerprint>"}`;只补未指派,范围外不自动分页收费。 - 只读查看 `latest`:姓名/依据/置信度是模型建议,null是未知;失败和全部未知不能冒充没有人物。采用或人工订正用 `POST .../dialogue/scan/apply`,body为 `{"run_id":"<扫描UUID>","expected_roles_version":1,"accept":[{"segment_id":"<段UUID>","quote_index":0,"speaker":"<确认姓名>"}]}`。低置信须明确选择,人工可订正为已有或新人物;核对真实 `applied/skipped/created_roles`,跳过项保留选择并核查。 - 扫描响应丢失只按下方统一恢复接口 GET 原键;latest 不能证明原请求。采用等免费写或继续命令不确定时保留草稿并先只读核对。保存后刷新失败不代表回滚;历史提交证据未知不能猜测原授权。 ## 返修(用户听完提出修改时) - 逐句数据:`GET /api/projects/{id}/listen`,返回每段每句的说话人、音色、情绪标签、在音频中的起止时间,以及问题标记:`unassigned_dialogue`(对话未指派说话人)、段的 `health`(仅文本/时长的语速异常提示,不能确诊漏读或杂音)、`outdated_reasons`(设置已改,需要重新生成)。 - 单句原子返修:`PUT /api/segments/{segment_id}/sentence`,body 为 `{"index":1,"expected_revision":1,"expected_text":"","expected_tag":null,"expected_pause":"none","tag":"happy","pause":"short"}`。核对当前目标句并合并,保留其他手工标注。 - 指派对话说话人需同时带原 `expected_role_id` 和新 `role_id`(null 表示不指派);创建并指派改用 `new_role_name` 加原 `expected_role_id`。角色创建、整条对话行归属、目标句情绪/停顿同事务保存;仅改情绪/旁白时省略说话人字段。 - 单句 409 保留草稿并核对当前值,不自动重建原始条件覆盖。成功保存后的预览刷新失败不代表回滚;保存响应不确定时先读取核对,不盲重发。 - 改说话人:`PUT /api/projects/{id}/speakers`,body 为 `{"assignments": [{"segment_id", "expected_revision", "quote_index", "role_id"}]}`。角色表用 `GET /api/projects/{id}/roles` 读取,用 `PUT /api/projects/{id}/roles` 修改(需带 `expected_version`)。 - 改情绪和停顿:`PUT /api/projects/{id}/emotion/segments/{segment_id}/cues`,body 为 `{"expected_revision", "cues": [{"index", "tag", "pause": "none|short|long"}]}`,需提交整段的全部标注。 - `tag` 只能用 Fish 官方标准词(英文):情绪如 `happy` `sad` `angry` `excited` `calm` `nervous` `scared` `surprised` `confused` `disdainful` `sarcastic` `gentle` `cold` 等,可加 `slightly ` / `very ` 前缀;语气 `whispering` `soft tone` `shouting` `in a hurry tone` `emphasis`;音效 `sighing` `laughing` `chuckling` `sobbing` `gasping` `panting`。最多一个情绪再加一个语气或音效,用 `+` 连接,例如 `sad+whispering`。其他写法会被拒绝(422)。 - 旁白尽量不加标签;不足 6 个字的短句加了也不起作用。 - 某段读得不好、但内容不用改:`POST /api/segments/{segment_id}/redo-mark` 标记重读,它会出现在 `listen` 的 `needs_redo` 和 `outdated_reasons` 里。 - 统一修改影响:`GET /api/projects/{id}/rework/preview`,`segments` 按段合并原因和参照候选,`initial_segments` 单列无 ready 音频引用的段(不代表没有历史费用)。 - `input_changed` 为 true / false / null(无法确定);false 时仍可能有修订或明确重读要求。原因用 `reasons[].code/message` 表示,另有 `warnings`、逐段的 `can_generate`、`blocked_reasons`。预览只读;生成前仍须重新估价确认整批费用。 - 选段估价:`POST /api/projects/{id}/batch-takes/estimate`,body 为 `{"segment_ids":["<段 UUID>"],"auto_adopt":false}`。显式集合非空、不重复、全部属于作品且当前修订无在途任务;省略或 null 使用默认待生成范围,两种范围不能交换确认。 - 估价返回段数、每段/整批供应商请求数与 UTF-8 字节、金额、报价 `policy` 的来源/有效期、`remaining_usd`、费用承担方 `credential` 及阻断原因。金额 null 是未知;owner 的平台金额为零不表示供应商免费,须展示 `billing_note`。供应商请求数与平台按候选提交计次不同。 - 确认:`POST /api/projects/{id}/batch-takes`,带新 UUID `request_key`、同一范围、同一 `auto_adopt` 和原 `fingerprint`;输入/报价/费用来源变化须重新估价。返回 `queued`、`skipped_count`、`stop_reason`;可能只受理前缀,必须报告实际数量和停止原因,排队不等于生成或人工试听通过。 - 不确定响应先按下方统一恢复接口 GET 原键。用户明确重放后才 POST 原键与完整原确认内容;此前未到达时可能首次受理并产生费用。原回执重放不扩充批次;同键换范围/策略/指纹会被拒绝。补做剩余段须核对历史、重新估价并明确授权新键;不能为恢复旧请求换键。 - 新候选的 `request_snapshot.rework_reference_take_id` 保存有依据的旧采用参照,需同段、ready 且有音频;`parent_take_id` 不等于旧采用。最新候选失败或待确认时仍保留旧音频,不能据此声称本次生成成功。 - 原因 `adoption` 表示就绪返修候选待决定,不要求再次付费。用户实际完整试听并确认后,才对当前修订候选 `PUT /api/takes/{take_id}/review`,带 `expected_revision`、当前 `expected_version`、`item_id:null`、`decision:"confirmed"`。只选版本时,已有 `review.delivery_approved:true` 可 `POST /api/takes/{take_id}/accept`,不写人工听过;保留较早的当前有效采用版本也须保存明确决定,不确定响应先读取核对。 - 已知输入漂移会拒绝采用或新交付;历史输入未知不等于一致,也不因此强制付费重做。导出 `POST /api/projects/{id}/exports` 必须在发送前保存完整 `{"request_key":"<本次导出UUID>","expected_take_ids":["<按片段position顺序的当前采用候选UUID>"]}`,列全原采用集合。丢失响应沿用原键恢复,不能改为最新采用集合;旧 Export 文件与清单保留。 - 免费导出已核实失败或取消、采用集合和本页确认的原Export ID一致时,才可明确授权新UUID尝试一次;未知、运行或ready回执不适用。另一客户端已有较新回执时恢复它,不按旧确认再创建。此例外不适用于付费请求。 - 另行明确授权重新运行时,先读取新 preflight,再提交 `{"request_key":"<新授权UUID>","fingerprint":"<新start_fingerprint>","speakers":false,"emotion":"off"}`。不是显式选段批次的重试,也不能用于恢复不确定请求。 ## 统一原请求恢复 - 所有计费提交(autopilot、单段/批量TTS、ASR、文章解读、说话人/读音/情绪扫描)、导出及父命令,在 POST 之前持久保存账号、项目、kind、UUID、原 endpoint/body、报价、范围和策略;不存令牌或凭据。未确认授权不换 UUID,不重新估价替换原语义。 - 自动恢复仅 `GET /api/projects/{project_id}/operations/{request_key}?kind=...`。kind 为 autopilot/take/batch/asr/interpretation/speaker_scan/lexicon_scan/emotion_scan/export/autopilot_resume/autopilot_pause/autopilot_cancel。 - 恢复仅限项目所属账号;管理员Cookie跨账号巡查也不能恢复他人的授权,知道UUID不等于获得权限。 - 返回 `{kind,request_key,resource_id,submitted,result}`:核对精确 kind/key/原资源与所有原字段,只允许补充服务端默认值,不允许改数组范围或策略。batch resource_id 为原受理前缀首个候选,result.queued 保留原顺序;扫描 result 为该原扫描在 latest 的状态。submitted:null 必须报告历史原语义证据未知,不能声称完全验证。 - 404或读失败不能证明原 POST 被拒绝。保留原键与内容,只读核对后提供用户明确选择的同键原内容重放,并解释原请求若从未到达,此次可能首次提交并计费。不得自动 POST、新键或用 unrelated latest 恢复。start_fingerprint 保护过期的并发启动确认。 ## 状态与额度 - 今日额度:`GET /api/usage`。 - 项目列表:`GET /api/projects`;项目详情:`GET /api/projects/{id}`。 ## 错误 - 401:令牌无效或已撤销。请用户在网页里重新创建令牌。 - 403:令牌不能做管理或账号操作。 - 404:资源不存在或不属于签发账号;不要换 ID 或路径尝试访问其他账号的作品。 - 409:资源状态已变化(例如版本号过期),重新读取后再试;一键成书已在运行时也返回 409。 - 429:请求太频繁,按 `Retry-After` 等待。 - AI错误分别标明功能与HTTP/连接/超时/截断/拒答/JSON/领域约束原因。只接受完整裸JSON或单个独占完整JSON围栏,不猜补缺失数据;失败不应用或自动重付,已知请求标识/usage与费用预留保留待核对。 - 返回体 `{"detail": "..."}` 是给人看的中文原因,可以直接转述给用户。