# AI Studio：网页 AI、图片图库与 Prompt 模板

AI Studio 是控制台内置的网页端 AI 体验,用于在浏览器里聊天、生成/编辑图片、管理图库和 Prompt 模板。它不是公开模型网关 API:终端、SDK、Claude Code、Codex、Grok 仍使用你创建的 API Key 和 [API 参考](#/api-usage) 里的端点。

> AI Studio 受站点开关控制。关闭时用户侧功能不可用,常见错误为 `AI_STUDIO_DISABLED` / `ai studio feature is disabled`。

---

## 页面入口

| 页面 | 路由 | 用途 |
|---|---|---|
| AI Studio 首页 | `/ai` | 重定向到 `/ai/chat` |
| 网页 AI 对话 | `/ai/chat` | 浏览器内对话、会话管理、Prompt 模板复用 |
| 图片生成/编辑 | `/ai/image` | 文生图、图像编辑、尺寸/风格配置 |
| 图片图库 | `/ai/gallery` | 查看历史作品、复制 prompt、公开/私有管理 |
| Prompt 模板库 | `/ai/prompts` | 创建、编辑、克隆、复用 Prompt |

入口不可见通常表示当前站点未开启、你的账号无权限,或站点临时关闭了 AI Studio。

---

## 运行时能力 `/user/ai/runtime`

进入 AI Studio 后,前端会先请求 `/user/ai/runtime` 判断可用能力。重点字段:

| 字段 | 说明 |
|---|---|
| `source_domain` | 当前控制台来源域 |
| `lines[]` | 可选线路/分组列表 |
| `lines[].group_id` / `label` / `platform` | 线路 ID、显示名、平台类型 |
| `lines[].keys[]` / `key_ids[]` / `key_count` / `default_key_id` | 可用 Key 和默认 Key |
| `lines[].default_mapped_model` | 默认映射模型 |
| `default_line` | 默认线路 |
| `models[]` | 可见模型列表 |
| `media.enabled` | 媒体存储是否开启 |
| `media.public_base_url` | 公开资源基址 |
| `media.max_upload_size_bytes` | 最大上传大小 |
| `media.default_visibility` | 默认公开/私有 |
| `media.upload_endpoint` | 上传入口 |
| `media.download_endpoint_template` / `thumbnail_download_template` | 私有下载/缩略图下载模板 |
| `image_edit.enabled` | 图片编辑是否开启 |
| `chat.supported_entries` / `forced_entry` | 聊天可用入口:Responses 或 Chat Completions |

如果你能打开页面但发送失败,先刷新 runtime:Key、线路、媒体能力或聊天入口可能已经变化。

`forced_entry` 不为空时,前端应按服务端指定入口发送,不要根据浏览器缓存或旧开关自行改成另一条路径。常见情况是强制走 Responses,以便使用工具、多模态或统一用量记录；手工重放请求时,请保留 `use_responses` 与 runtime 展示一致。

---

## 网页 AI 对话

相关端点:

| 方法 | 端点 | 用途 |
|---|---|---|
| `GET` | `/user/ai/sessions` | 会话列表 |
| `POST` | `/user/ai/sessions` | 创建会话 |
| `GET` | `/user/ai/sessions/:id` | 会话详情 |
| `PUT` | `/user/ai/sessions/:id` | 更新标题/状态/system prompt |
| `DELETE` | `/user/ai/sessions/:id` | 删除会话 |
| `GET` | `/user/ai/sessions/:id/messages` | 消息列表 |
| `POST` | `/user/ai/sessions/:id/messages` | 写入消息 |
| `POST` | `/user/ai/chat` | 发起一次实际聊天 |

`POST /user/ai/chat` 请求体示例:

```json
{
  "session_id": 123,
  "prompt": "帮我总结这段代码",
  "line_id": 10,
  "key_id": 99,
  "prompt_template_id": 5,
  "history": [
    { "role": "user", "content": "上一轮问题" },
    { "role": "assistant", "content": "上一轮回答" }
  ],
  "use_responses": true
}
```

后端会按 `use_responses` 与 runtime 配置桥接到 OpenAI-compatible `/openai/v1/responses` 或 `/openai/v1/chat/completions`,并把 user/assistant 消息保存回会话。`prompt` 为空会返回 `Prompt is required` 或 `AI_MESSAGE_INPUT_REQUIRED`。

---

## Prompt 模板

新版模板接口和兼容旧入口同时存在:

| 方法 | 端点 | 用途 |
|---|---|---|
| `GET` | `/user/ai/prompt-templates` | 新版模板列表 |
| `POST` | `/user/ai/prompt-templates` | 创建新版模板 |
| `GET` | `/user/ai/prompt-templates/:id` | 模板详情 |
| `PUT` | `/user/ai/prompt-templates/:id` | 更新模板 |
| `DELETE` | `/user/ai/prompt-templates/:id` | 删除模板 |
| `GET` | `/user/ai/prompts` | 兼容/个人 Prompt 列表 |
| `POST` | `/user/ai/prompts` | 创建个人 Prompt |
| `PUT` | `/user/ai/prompts/:id` | 编辑 Prompt |
| `DELETE` | `/user/ai/prompts/:id` | 删除 Prompt |
| `POST` | `/user/ai/prompts/:id/clone` | 克隆公开模板 |

列表常用 query:`page`、`page_size`、`scope=mine|library|all`、`visibility=public|private`、`status`、`moderation_state`、`search`、`group_id`/`line_id`。

创建字段:

```json
{
  "title": "代码审查模板",
  "content": "请审查以下 diff,指出风险和可改进点...",
  "description": "用于 PR review",
  "tags": ["code", "review"],
  "visibility": "private",
  "status": "draft",
  "line_id": 10
}
```

常见状态包括 `draft`、`published`、`archived`、`hidden`;可见性为 `public` 或 `private`。标题或内容缺失会返回 `AI_PROMPT_TEMPLATE_TITLE_REQUIRED`、`AI_PROMPT_TEMPLATE_INPUT_REQUIRED` 或 `Invalid request body`。

---

## 图片生成、编辑与图库

| 方法 | 端点 | 用途 |
|---|---|---|
| `GET` | `/user/ai/generation-jobs` | 生成任务列表 |
| `POST` | `/user/ai/generation-jobs` | 创建生成任务记录 |
| `GET` | `/user/ai/generation-jobs/:id` | 生成任务详情 |
| `GET` | `/user/ai/gallery` | 图库列表 |
| `GET` | `/user/ai/artworks` | 图库别名/作品列表 |
| `POST` | `/user/ai/artworks` | 文生图 |
| `POST` | `/user/ai/artworks/edit` | 图片编辑 |
| `PUT` | `/user/ai/artworks/:id` | 更新作品信息 |
| `DELETE` | `/user/ai/artworks/:id` | 软删除作品 |
| `GET` | `/user/ai/assets/:id` | 媒体资源详情 |

普通用户前端常用图库筛选是 `page`、`page_size`、`search`、`visibility`、`status`、`line_id`;前端会把 `line_id` 归一化为后端查询的 `group_id`,并把图库筛选里的 `succeeded` 归一化为 `ready`。后端图库高级筛选还支持 `moderation_state`、`generation_job_id`、`session_id`、`prompt_template_id`、`group_id`;普通 `/user/ai/generation-jobs` 列表只支持 `status`、`session_id`、`prompt_template_id`、`group_id`。`featured` 属于旧元数据或高级筛选,普通用户侧页面不要当成稳定筛选承诺。Prompt library 场景会把 `scope=library` 固定成 `visibility=public`。看不到某张图时,先确认它是 public 还是 private、asset status 是否 `pending/ready/hidden/deleted`、任务 status 是否 `queued/running/succeeded/failed/canceled`、当前 Key/线路是否属于你。

生成任务和资源 ID 要区分:`/user/ai/generation-jobs/:id` 查的是异步任务;`/user/ai/assets/:id` 查的是最终媒体资源。图库 `/user/ai/gallery`/`/user/ai/artworks` 展示的是 asset/artwork 视图,可能来自已完成任务,也可能来自旧桥接路径。排查“任务完成但图库没有”时,同时保留 job id、asset id、request_id、line_id/group_id 和 status。

文生图请求示例:

```json
{
  "title": "产品宣传图",
  "prompt": "一个极简风格的 SaaS 控制台截图海报",
  "negative_prompt": "不要杂乱背景",
  "visibility": "private",
  "mode": "generate",
  "line_id": 10,
  "key_id": 99,
  "size": "1024x1024",
  "style": "product",
  "tags": ["product", "banner"],
  "prompt_template_id": 5
}
```

图片编辑额外需要 `source_image`,可选 `mask_image`:

```json
{
  "mode": "edit",
  "prompt": "把背景换成深色科技风",
  "source_image": "https://example.com/source.png",
  "mask_image": "https://example.com/mask.png"
}
```

内部会桥接到 OpenAI Images 形态的 `/openai/v1/images/generations` 或 `/openai/v1/images/edits`,并把生成结果保存为 asset/artwork。公开图可返回 public URL;私有图通常通过签名下载 URL 访问。公开 API 的 Images 用法见 [Images](#/api-images),Codex 生图见 [Codex 生图](#/codex-image)。

---

## 常见报错

| 报错 / 现象 | 常见原因 | 处理 |
|---|---|---|
| `AI_STUDIO_DISABLED` | AI Studio 未开放 | 以控制台当前开放状态为准 |
| `User not authenticated` | 登录失效 | 重新登录控制台 |
| `Invalid request body` | JSON 不合法或字段缺失 | 检查必填字段 |
| `Prompt is required` | `/user/ai/chat` 的 `prompt` 为空 | 输入内容后再发送 |
| `Invalid session ID` / `Invalid template ID` / `Invalid artwork ID` / `Invalid asset ID` | URL ID 不是正整数或记录不可见 | 刷新列表,确认权限 |
| `AI_KEY_NOT_FOUND` | 当前线路没有可用 Key | 创建/启用 Key 或切换线路 |
| `AI_KEY_FORBIDDEN` | 选择了不属于当前用户的 Key | 切回自己的 Key |
| `AI_KEY_GROUP_INVALID` | Key 未绑定有效分组 | 检查 Key 绑定分组 |
| `AI_LINE_MISMATCH` | `key_id` 不属于所选 `line_id` | 同时切换线路和 Key,清掉旧 URL query |
| `AI_GATEWAY_EMPTY_CHAT_RESPONSE` | 上游成功但没有可提取文本 | 换模型/线路,带 request_id 提工单 |
| `AI_ARTWORK_SOURCE_IMAGE_REQUIRED` | 编辑模式缺少原图 | 上传或填写 `source_image` |
| `AI_GATEWAY_IMAGE_DATA_MISSING` / `AI_GATEWAY_IMAGE_URL_MISSING` | 上游图片响应无法解析 | 换模型/线路,保留 request_id |
| `MEDIA_STORAGE_DISABLED` | 媒体存储关闭 | 图库/私有下载能力受限 |
| `MEDIA_FILE_TOO_LARGE` | 图片超过限制 | 压缩图片,参考 runtime 的 `max_upload_size_bytes` |
| `MEDIA_VISIBILITY_INVALID` | visibility 非 `public/private` | 改成 `public` 或 `private` |

---

## 实用场景

1. **新手先在网页端验证模型**:打开 `/ai/chat`,选择线路和 Key,发送 `ping`,再到 [用量明细](#/console-usage) 核对模型和扣费。
2. **把常用 Prompt 做成模板**:在 `/ai/prompts` 创建私有模板,后续聊天或 CLI 里复制复用。
3. **先在控制台试图,再迁移到 API**:在 `/ai/image` 调好 prompt/size/style,再迁移到 [Images](#/api-images)。
4. **用图库沉淀素材**:在 `/ai/gallery` 找历史图,复用 prompt、尺寸、风格作为下一次生成参考。
5. **编辑已有图片**:切到编辑模式,上传 `source_image`,可选 `mask_image`,输入编辑描述,结果会进入图库。
