# web.rest.aiImage

轻量通用文生图 / 图像编辑客户端：**同步调用、一次取一张图、成功返回本地文件路径**。适合调用方只知道用户填写的 `url`、`key`、`model` 的场景；需要完整 GPT Image 特性的应用请直接调用原生协议，参考[AI 范例 - 图像](file://~/examples/AI/image/.aar)。

示例：

```aardio
import web.rest.aiImage;

var ai = web.rest.aiImage(
    url="https://api.openai.com/v1";
    key="YOUR_API_KEY";
    model="gpt-image-1.5";
);

var path,err = ai.generate("一只在窗边睡觉的猫",{
    size="1024x1024";
    quality="medium";
});

if(path) print(path);
else print(err);
ai.close();
```

[通用文生图 - 图形界面](file://~/examples/AI/image/aiImage.html)

## 编辑原图

与 `savePath` 一样，把原图放在 `generate()` 的选项表中：

```aardio
import web.rest.aiImage;

var ai = web.rest.aiImage(
    url="https://api-inference.modelscope.cn/v1";
    key=string.getenv("MODELSCOPE_API_KEY");
    model="Qwen/Qwen-Image-2.1";
);

var path,err = ai.generate("把红色圆形改成蓝色，保持位置、大小和背景不变",{
    originalImage="/source.png";
    savePath="/edited.png";
});
ai.close();

if(path) print(path);
else print(err);
```

- `originalImage` 支持本地文件路径、HTTP(S) 图片 URL、Base64 Data URL、PNG/JPEG/WebP/GIF `buffer`、现有 `gdip.bitmap` 对象，或由这些图像组成的数组。多图示例：`originalImage=["/one.png","/two.jpg"]`。
- 省略 `originalImage` 或设为 `null` 时仍是普通文生图；空数组或无效原图会报错，不会悄悄退回文生图。
- 本地文件和 buffer 会按实际文件头识别 MIME 并转为 Data URL，**不会把本地路径发送给服务端**。仅 Google 会先下载远程原图，其他协议直接透传远程 URL。图片下载使用独立、不带 API 授权的客户端。
- 魔搭最多接收 3 张原图。其他供应商的数量、格式及大小限制由具体模型决定；不能据此假设每个模型都支持所有格式。
- `ai.edit(prompt,original[,opts])` 保留为兼容入口；新代码推荐统一使用 `generate(prompt,{originalImage=...})`。

## 参数与协议

- `ai.generate(prompt[,opts])`：`opts` 可为保存文件路径，或 `{originalImage,savePath,size,quality,outputFormat,background,extraParameters}`。不传 `savePath` 时创建临时文件，**调用方自行决定何时删除**。结果支持 PNG/JPEG/WebP，格式按实际返回的图像识别。
- `quality` 使用 `auto/low/medium/high/xhigh/max`。错误写法会在调用者的选项表上就地纠正（如 `hd` → `high`），便于工具调用者看到修正结果，不应把错误别名当作公开规范。
- `outputFormat="jpg"` 会规范为 API 使用的 `jpeg`；保存路径同时接受 `.jpg` 和 `.jpeg`。指定的扩展名必须与实际返回的格式一致，本库不会自动转码。
- 本客户端继承 `web.rest.jsonClient`（及 `web.rest.client`）的方法，直接调用 `ai.setHeaders()`、`ai.setTimeouts()`、`ai.lastResponseObject()` 等，不使用 `ai.http`。
- `cfg`：必须提供 `url`；通常需要 `model`，可选 `key,proxy,protocol,size,quality,outputFormat,background,extraHeaders,extraParameters,timeoutMs,pollIntervalMs`。`protocol` 可选 `openai,openrouter,google,modelscope,fal`；网址包含 `openai` 时强制使用 `openai`。额外参数仅用于自行了解原生协议时透传，不能把不同供应商的原生字段认为可互换。
- OpenAI：填 API 根路径（通常 `/v1`）或完整 `/images/generations`；未知 URL 默认此协议。`xhigh/max` 统一降级为 `high`。
- OpenRouter：填 `https://openrouter.ai/api/v1`，使用独立 `/images` 接口，模型 ID 使用其路由名称。
- Google：填 `https://generativelanguage.googleapis.com/v1beta`，使用 Gemini `generateContent`，`size` 只映射为近似宽高比，**不保证精确像素数**。
- 魔搭：填 `https://api-inference.modelscope.cn/v1`；为兼容现有生图接口发送异步任务请求，但 `generate()` 在内部轮询 `task_id` 后同步返回文件路径；`quality` 非 `auto` 时按 `low/medium/high/xhigh/max → 15/30/40/45/50` 映射 `steps`，不同模型实际步数要求可能不同，可用 `extraParameters.steps` 覆盖。
- fal.ai：`url` 可填 `https://fal.run/fal-ai/flux/dev`，也可填 `https://fal.run` 并指定 `model="fal-ai/flux/dev"`；直接同步 HTTP 调用，`quality` 不自动翻译成模型专有的步数。常见像素尺寸近似映射为 `square_hd` 等 fal 预设；不同模型的 `image_size` 格式可能不同，可用 `extraParameters.image_size` 手动指定。

**图像编辑接口：**魔搭仍调用 `/v1/images/generations`，传 `image_url` 数组，自动等待任务完成；OpenRouter 走 `/images` 的 `input_references`；Google 使用 `generateContent` 的 `inlineData`；OpenAI 使用 `/images/edits` 的 JSON `images`（要求服务端支持该格式）。fal.ai 各模型图像字段不同，暂不支持通用 `originalImage`，会明确返回错误。

**额外参数：**按 `ai.extraParameters` → `config.extraParameters` → `opts.extraParameters` 顺序合并，后者优先；普通 `size/quality/outputFormat` 等显式选项继续覆盖其自动映射字段。Google 的 `generationConfig`、`imageConfig` 分层合并，数组整体替换；显式原生 `aspectRatio` 优先于 `size` 的近似映射。合并后检查 `n` 等数量参数，不能用额外参数绕过单张结果限制。

## 轻量校验与超时

- 原图和生成结果只检查文件头及基本长度；Data URL 最多解码前 64 个 Base64 字符以检查头部与 MIME。不使用 `gdip.bitmap` 加载图片，不检查像素、CRC 或完整文件结构。需要严格验证时由调用方负责。
- `timeoutMs` 是魔搭**任务轮询等待**的期限，默认 300000 毫秒；`pollIntervalMs` 默认 3000 毫秒。到期不再发起新轮询，也不接受到期后才返回的成功结果。
- `timeoutMs` 不含提交任务和下载图片，也不会打断已在执行的 HTTP 请求。API 单次网络超时用 `ai.setTimeouts()` 设置，默认 `15000,300000,300000`；独立图片下载用 `ai.downloadHttp.setTimeouts()` 设置，默认 `15000,60000,60000`。

**限制：**不自动探查/重试 404（避免额外请求和错误协议判断）；不实现进度、多张结果/流式、队列管理。魔搭的任务轮询是为了对调用方保持同步返回。指定的 `savePath` 文件扩展名须与实际图像格式一致。下载图像使用不含 API 密钥的独立 HTTP 客户端；建议仅使用可信供应商接口。
