feat: auto-api-pricing-config技能(文档→uapi接口配置+定价YAML)
从sage生产真实数据提炼: 协议模板库+定价模板库 - SKILL.md: 工作流+模板语法约定+定价硬规则 - references/uapi-templates.md: openai_compat流式/多模态/dashscope异步/任务轮询/特殊响应 - references/pricing-patterns.md: token/缓存/视频秒/按次/积分 五类模板+单位换算
This commit is contained in:
parent
567e4cc0cc
commit
d8c6355514
@ -0,0 +1,65 @@
|
||||
---
|
||||
name: auto-api-pricing-config
|
||||
description: 从API文档/报价文档自动生成uapi接口配置(headers/data/params/response)和定价(pricing YAML)。内部agent配置接口或报价时必读。
|
||||
capability: auto_api_pricing
|
||||
tools: [fetch_model_doc, extract_llm_api_spec, apply_llm_config, platform_llm_status]
|
||||
---
|
||||
|
||||
# 接口与报价自动配置(文档 → uapi + pricing)
|
||||
|
||||
两条自动配置链路:**API 文档 → 接口配置**(upapp + uapi + uapiio),
|
||||
**报价文档 → 定价配置**(pricing_program + pricing_program_timing YAML)。
|
||||
定价只允许来自文档原文,禁止编造。
|
||||
|
||||
## 目标表(pipeline 库,均已存在)
|
||||
|
||||
| 表 | 用途 | 关键字段 |
|
||||
|---|---|---|
|
||||
| upapp | 供应商系统 | name, baseurl, secretkey(AES), dynamic_func |
|
||||
| uapi | 接口定义 | upappid, name, title, path, httpmethod, stream(sync/async/stream/false), chunk_match, headers/data/params/response(Jinja2模板), ioid |
|
||||
| uapiio | 输入字段定义 | name, input_fields(JSON数组或类型schema) |
|
||||
| pricing_program | 定价项目 | name(模型名), providerid, pricing_belong(provider/llm), currency |
|
||||
| pricing_program_timing | 定价数据 | ppid, pricing_data(YAML), enabled_date, expired_date |
|
||||
| upappkey | 供应商密钥 | upappid, apikey(AES加密)——**永远由人工补录,不自动生成** |
|
||||
|
||||
## 工作流
|
||||
|
||||
1. `fetch_model_doc` 抓取 API 文档 + 报价页面
|
||||
2. `extract_llm_api_spec` 提取规格(端点/鉴权/请求体/响应体/定价)
|
||||
3. **接口配置**:按「协议模板库」生成 uapi 记录(见 references/uapi-templates.md)
|
||||
- 先查 upapp 是否已有该供应商(按 baseurl 匹配),没有才新建
|
||||
- stream 接口:chunk_match 填流式分块匹配串(OpenAI 系为 `data: `)
|
||||
- async 接口:chunk_match 填任务 id 字段名(如 `task_id`),response 模板必须输出 `taskid`+`status`
|
||||
- 异步接口通常需要配对的**状态查询接口**(`{name}status`,GET,响应输出最终产物 + usage)
|
||||
4. **报价配置**:按「定价生成规则」生成 pricing_program_timing YAML(见 references/pricing-patterns.md)
|
||||
5. 把生成结果摘要(端点/鉴权方式/每模型定价)给用户确认后再落库
|
||||
6. 落库后用 `platform_llm_status` / CRUD 查询复核,回报结果
|
||||
|
||||
## uapi 模板语法约定(Jinja2)
|
||||
|
||||
- 占位变量:`{{apikey}}`(供应商密钥,运行时注入)、`{{model}}`、`{{prompt}}`、`{{taskid}}`
|
||||
- 字符串字段必须 `{{json.dumps(prompt, ensure_ascii=False)}}`,防引号注入
|
||||
- 多媒体输入用 `{{b64media2url(request, image_file)}}`(base64→临时URL),产物输出用
|
||||
`{{downloadfile2url(request, output.video_url)}}`(下载到平台存储再给URL)
|
||||
- 流式响应模板区分 `object == "chat.completion"`(message)与 chunk(delta),
|
||||
用 `{% if usage %}` 判断结束并输出 `"finish": "1"`
|
||||
- 条件参数用 `{% if xxx %}...{% endif %}`(sys_prompt/image_file/tools 等可选字段)
|
||||
|
||||
## 定价生成规则(硬规则)
|
||||
|
||||
- 单位:YAML 里 `unit_prices` 用人类可读值 + `unit: 百万` + `unit_values: {百万: 1000000}`;
|
||||
文档「元/百万tokens」直接落数值,「元/千tokens」×1000 换算
|
||||
- **区间下界含 0 必须用 `=~`**(`0 =~ 128000`);`~=` 会排除 0 值导致计费为 0
|
||||
- 键名是 `pricings`(复数);`unit_values` 只放实际用到的单位
|
||||
- 缓存价:阿里云系缓存命中 = 输入价 × 0.2(以文档为准);拆 `uncache_tokens`/`cached_tokens` 两个因子
|
||||
- 模型名映射:API 返回带点版本号(`doubao-seedance-2.0`)而定价用连字符(`doubao-seedance-2-0`)时,
|
||||
必须在 `model_mappings` 加映射,否则静默匹配失败
|
||||
- YAML 布尔陷阱:过滤值 `no/yes/true/false` 必须加引号(`"no"`)
|
||||
- 文档没写的价格 → 不生成该定价项并明确标注「文档未列价,需人工补录」,禁止编造
|
||||
- 阶梯价:同一档位的所有因子项(输入/缓存/输出)都要带相同的区间过滤条件
|
||||
|
||||
## 参考
|
||||
|
||||
- `references/uapi-templates.md` — 协议模板库(从生产真实配置提炼):openai_compat 流式/多模态、
|
||||
dashscope 异步、任务轮询型、音乐/3D 特殊响应、upapp/uapiio 样例
|
||||
- `references/pricing-patterns.md` — 定价 YAML 五类模板(token/缓存/视频秒/按次/积分)+ 单位换算表
|
||||
@ -0,0 +1,179 @@
|
||||
# 定价 YAML 模板库(生产真实配置提炼)
|
||||
|
||||
定价落 `pricing_program_timing.pricing_data`(YAML 字符串),引擎按 `pricings` 数组匹配。
|
||||
先看报价文档是哪种计费形态,选对应模板。
|
||||
|
||||
## 数据模型(落库三层)
|
||||
|
||||
```
|
||||
pricing_program 一个模型/产品一个定价项目
|
||||
├─ name 模型名(如 "通义千问 qwen3.7-max")
|
||||
├─ providerid 供应商 id(关联 upapp)
|
||||
├─ pricing_belong provider | llm
|
||||
└─ currency CNY | USD
|
||||
pricing_program_timing 生效时段 + 定价数据
|
||||
├─ ppid 关联 pricing_program.id
|
||||
├─ pricing_data YAML(见下)
|
||||
├─ enabled_date / expired_date
|
||||
pricing_item(旧表,参考) spec_value / pricing_unit / pricing_amount / cost_amount
|
||||
```
|
||||
|
||||
新配置统一走 `pricing_data` YAML;`pricing_item` 是历史遗留,了解即可。
|
||||
|
||||
## 单位换算表(元 → YAML unit_prices)
|
||||
|
||||
| 文档单位 | 换算 | YAML 落法 |
|
||||
|---|---|---|
|
||||
| 元/百万tokens | 直接 | `unit_prices: 6.0` + `unit: 百万` + `unit_values:{百万:1000000}` |
|
||||
| 元/千tokens | ×1000 | `unit_prices: 6.0` + `unit: 百万`(先×1000 再落百万) |
|
||||
| 元/秒(视频/音频) | 直接 | `unit_prices: 1.6` + `unit: 秒` |
|
||||
| 元/次 | 直接 | `unit_prices: 0.2` + `unit: 次` |
|
||||
| 元/张(图片) | 直接 | `unit_prices: 0.2` + `unit: 次`(按张=按次) |
|
||||
|
||||
**禁止** `6e-06` 这种科学计数法——引擎会二次除法算错。
|
||||
|
||||
## 模板 1:文本模型 token 计价(含缓存拆分)
|
||||
|
||||
阿里云系缓存命中 = 输入价 × 0.2(以文档为准)。真实样例(qwen3.7-max,限时5折后):
|
||||
|
||||
```yaml
|
||||
unit_values:
|
||||
百万: 1000000
|
||||
|
||||
fields:
|
||||
price_factors: {type: string, role: factor, label: 计价因子}
|
||||
unit_prices: {type: float, role: factor, label: 单位定价}
|
||||
unit: {type: string, role: factor, label: 计价单位}
|
||||
uncache_tokens:
|
||||
type: int, role: factor, label: 非缓存tokens
|
||||
derived: prompt_tokens - prompt_tokens_details.cached_tokens
|
||||
cached_tokens:
|
||||
type: int, role: factor, label: 缓存tokens
|
||||
derived: prompt_tokens_details.cached_tokens
|
||||
completion_tokens: {type: int, role: factor, label: 输出tokens}
|
||||
model: {type: string, role: filter, label: 模型}
|
||||
|
||||
pricings:
|
||||
- price_factors: uncache_tokens
|
||||
unit_prices: 6.0 # 输入 6元/百万(限时5折后)
|
||||
unit: 百万
|
||||
filters: [{model: qwen3.7-max}]
|
||||
- price_factors: cached_tokens
|
||||
unit_prices: 1.2 # 缓存 = 6 × 0.2
|
||||
unit: 百万
|
||||
filters: [{model: qwen3.7-max}]
|
||||
- price_factors: completion_tokens
|
||||
unit_prices: 18.0 # 输出 18元/百万
|
||||
unit: 百万
|
||||
filters: [{model: qwen3.7-max}]
|
||||
```
|
||||
|
||||
派生字段 `uncache_tokens`/`cached_tokens` 引擎自动算,**不要**手动预填到 usage。
|
||||
|
||||
## 模板 2:阶梯价(区间过滤)
|
||||
|
||||
同一档位的所有因子项都要带相同区间条件。下界含 0 必须 `=~`。
|
||||
|
||||
```yaml
|
||||
pricings:
|
||||
- price_factors: uncache_tokens
|
||||
unit_prices: 2.0
|
||||
unit: 百万
|
||||
filters:
|
||||
- model: qwen3.7-plus
|
||||
prompt_tokens: 0 =~ 256000 # ← 下界0用 =~
|
||||
value_mode: between
|
||||
- price_factors: cached_tokens
|
||||
unit_prices: 0.4
|
||||
unit: 百万
|
||||
filters:
|
||||
- model: qwen3.7-plus
|
||||
prompt_tokens: 0 =~ 256000 # ← 同区间
|
||||
value_mode: between
|
||||
- price_factors: completion_tokens
|
||||
unit_prices: 8.0
|
||||
unit: 百万
|
||||
filters:
|
||||
- model: qwen3.7-plus
|
||||
prompt_tokens: 0 =~ 256000 # ← 同区间(输出也随档位变)
|
||||
value_mode: between
|
||||
```
|
||||
|
||||
**新增区间过滤键**必须同步加进 `fields`(type: int, role: filter, value_mode: between),
|
||||
否则区间过滤静默失效 → 计费为 0。
|
||||
|
||||
## 模板 3:视频/音频按秒(分辨率多档)
|
||||
|
||||
真实样例(万相视频,720P/1080P 分档):
|
||||
|
||||
```yaml
|
||||
unit_values:
|
||||
秒: 1
|
||||
|
||||
pricings:
|
||||
- price_factors: duration
|
||||
unit_prices: 0.6 # 720P 0.6元/秒
|
||||
unit: 秒
|
||||
filters: [{model: wan2.6-t2v, resolution: "720P"}]
|
||||
- price_factors: duration
|
||||
unit_prices: 1.0 # 1080P 1.0元/秒
|
||||
unit: 秒
|
||||
filters: [{model: wan2.6-t2v, resolution: "1080P"}]
|
||||
```
|
||||
|
||||
过滤值(resolution)必须与 uapi 查询响应里 `usage.update` 塞的值**逐字符一致**。
|
||||
|
||||
## 模板 4:按次计费(图片/音频/单任务)
|
||||
|
||||
```yaml
|
||||
unit_values:
|
||||
次: 1
|
||||
|
||||
pricings:
|
||||
- price_factors: flat
|
||||
unit_prices: 0.2 # 0.2元/张
|
||||
unit: 次
|
||||
filters: [{model: qwen-image-2.0}]
|
||||
```
|
||||
|
||||
`price_factors: flat` + 固定 `unit_prices` = 按次;`usage` 里给 `{"count": 1}`。
|
||||
|
||||
## 模板 5:积分制 / total_tokens
|
||||
|
||||
```yaml
|
||||
pricings:
|
||||
- price_factors: total_tokens # 按总 token
|
||||
unit_prices: 24.0
|
||||
unit: 百万
|
||||
filters: [{model: doubao-seedance-2-0}]
|
||||
# 或积分制
|
||||
- price_factors: credits
|
||||
unit_prices: 0.05
|
||||
unit: 次
|
||||
```
|
||||
|
||||
## 模型名映射(必查)
|
||||
|
||||
API 返回带点版本号、定价用连字符时必须加映射,否则静默不匹配:
|
||||
|
||||
```yaml
|
||||
model_mappings:
|
||||
doubao-seedance-2.0: doubao-seedance-2-0
|
||||
doubao-seedance-2.0-fast: doubao-seedance-2-0-fast
|
||||
```
|
||||
|
||||
## YAML 布尔陷阱
|
||||
|
||||
过滤值 `no/yes/true/false` 必须加引号(`"no"`),否则被解析成布尔导致匹配失败。
|
||||
|
||||
## 生成后自检清单
|
||||
|
||||
- [ ] `unit_prices` 是人类可读值(6.0 不是 6e-06)
|
||||
- [ ] `unit_values` 只含用到的单位
|
||||
- [ ] 下界含 0 的区间用 `=~`(不是 `~=`)
|
||||
- [ ] 键名 `pricings`(复数)
|
||||
- [ ] 区间过滤键已加进 `fields` 且带 `value_mode: between`
|
||||
- [ ] 模型名与 API 返回逐字符一致(或加 model_mappings)
|
||||
- [ ] 布尔过滤值已加引号
|
||||
- [ ] 文档没写的价格 → 不生成 + 标注「需人工补录」,未编造
|
||||
- [ ] 用 factor=0 测一遍确认仍匹配
|
||||
@ -0,0 +1,232 @@
|
||||
# uapi 协议模板库(生产真实配置提炼)
|
||||
|
||||
生成 uapi 记录时按协议族选模板。以下为真实生产配置的规范化版本,占位符保持 `{{xxx}}` Jinja2 语法。
|
||||
|
||||
## 1. OpenAI 兼容 · 流式文本(stream=stream)
|
||||
|
||||
适用:deepseek / moonshot / stepfun / 智谱 / Grok / 通义兼容端点 等 `/chat/completions` 流式接口。
|
||||
|
||||
```json
|
||||
upapp.baseurl = "https://api.deepseek.com" // 供应商根地址,不带 path
|
||||
uapi:
|
||||
name = "t2t", title = "文生文"
|
||||
path = "/chat/completions", httpmethod = "POST"
|
||||
stream = "stream", chunk_match = "data: "
|
||||
headers = {"Authorization": "Bearer {{apikey}}", "Content-Type": "application/json"}
|
||||
```
|
||||
|
||||
data 模板(含 tools/多模态可选字段):
|
||||
|
||||
```
|
||||
{
|
||||
{% if stream %}
|
||||
"stream_options":{"include_usage": true},
|
||||
{% endif %}
|
||||
{% if tools %}
|
||||
"tools": {{json.dumps(tools, ensure_ascii=False)}},
|
||||
{% endif %}
|
||||
{% if tool_choice %}
|
||||
"tool_choice": "{{tool_choice}}",
|
||||
{% endif %}
|
||||
{% if messages %}
|
||||
"messages": {{json.dumps(messages, ensure_ascii=False)}},
|
||||
{% else %}
|
||||
"messages": [
|
||||
{% if sys_prompt %}
|
||||
{"role": "system", "content": {{json.dumps(sys_prompt, ensure_ascii=False)}}},
|
||||
{% endif %}
|
||||
{"role": "user", "content": {{json.dumps(prompt, ensure_ascii=False)}}}
|
||||
],
|
||||
{% endif %}
|
||||
{% if stream %}
|
||||
"stream": true,
|
||||
{% endif %}
|
||||
"model": "{{model}}"
|
||||
}
|
||||
```
|
||||
|
||||
response 模板(流式通用):
|
||||
|
||||
```
|
||||
{
|
||||
"model": "{{model}}",
|
||||
{% if object == "chat.completion" %}
|
||||
"reasoning_content": {{json.dumps(choices[0].message.reasoning_content, ensure_ascii=False)}},
|
||||
"content": {{json.dumps(choices[0].message.content, ensure_ascii=False)}},
|
||||
{% elif len(choices)>0 %}
|
||||
"reasoning_content": {{json.dumps(choices[0].delta.reasoning_content, ensure_ascii=False)}},
|
||||
"content": {{json.dumps(choices[0].delta.content, ensure_ascii=False)}},
|
||||
{% endif %}
|
||||
{% if usage %}
|
||||
"finish": "1",
|
||||
"usage": {{json.dumps(usage)}}
|
||||
{% else %}
|
||||
"finish": "0"
|
||||
{% endif %}
|
||||
}
|
||||
```
|
||||
|
||||
多模态变体(tm2t/ti2t):user.content 改数组,按 `{% if image_file %}` 插入
|
||||
`{"type": "image_url", "image_url": "{{b64media2url(request, image_file)}}"}`,
|
||||
video_file/audio_file 同理(type 为 video_url/audio_url),最后附 `{"type": "text", "text": {{json.dumps(prompt, ensure_ascii=False)}}}`。
|
||||
|
||||
## 2. 阿里云 DashScope · 原生异步(stream=async)
|
||||
|
||||
适用:通义万相视频生成(`/api/v1`),头需 `X-DashScope-Async: enable`。
|
||||
|
||||
```json
|
||||
uapi:
|
||||
name = "t2v"/"2i2v", path = "/services/aigc/video-generation/video-synthesis"
|
||||
httpmethod = "POST", stream = "async", chunk_match = ""
|
||||
headers = {"X-DashScope-Async": "enable", "Authorization": "Bearer {{apikey}}", "Content-Type": "application/json"}
|
||||
```
|
||||
|
||||
data 模板(首尾帧示例):
|
||||
|
||||
```
|
||||
{
|
||||
"model": "{{model}}",
|
||||
"input": {
|
||||
"prompt": {{json.dumps(prompt)}},
|
||||
{% if negative_prompt %}
|
||||
"negative_prompt": {{json.dumps(negative_prompt)}},
|
||||
{% endif %}
|
||||
{% if image2_file %}
|
||||
"last_frame_url": "{{b64media2url(request, image2_file)}}",
|
||||
{% endif %}
|
||||
"first_frame_url": "{{b64media2url(request, image1_file)}}"
|
||||
},
|
||||
"parameters": {
|
||||
"resolution": "{{resolution or '1080P'}}",
|
||||
"prompt_extend": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
提交响应模板(异步必须输出 taskid + status):
|
||||
|
||||
```
|
||||
{
|
||||
{% if output %}
|
||||
"taskid": "{{output.task_id}}",
|
||||
"status": "{{output.task_status}}"
|
||||
{% else %}
|
||||
"status": "FAILED",
|
||||
"error": "{{code}}.{{message}}"
|
||||
{% endif %}
|
||||
}
|
||||
```
|
||||
|
||||
**配对状态查询接口**(同供应商必配):
|
||||
|
||||
```
|
||||
name = "{t2v}status", path = "/tasks/{{taskid}}", httpmethod = "GET", stream = "sync"
|
||||
headers = {"Authorization": "Bearer {{apikey}}"}
|
||||
response:
|
||||
{
|
||||
{% if output.task_status == 'SUCCEEDED' %}
|
||||
"video": "{{downloadfile2url(request, output.video_url)}}",
|
||||
"usage": {{json.dumps(usage)}},
|
||||
{% elif output.task_status == 'FAILED' %}
|
||||
"error": "{{output.code}}:{{output.message}}",
|
||||
{% endif %}
|
||||
"status": "{{output.task_status}}"
|
||||
}
|
||||
```
|
||||
|
||||
文生图同理:`"image": "{{downloadfile2url(request, output.results[0].url)}}"`。
|
||||
|
||||
## 3. 任务型 API(POST 建任务 + GET 查结果)
|
||||
|
||||
适用:seedance / 即梦 / Vidu 等(`/contents/generations/tasks`)。
|
||||
|
||||
```
|
||||
提交: path = "/contents/generations/tasks", POST, stream = "async", chunk_match = "task_id"
|
||||
headers = {"Content-Type": "application/json", "Authorization": "Bearer {{apikey}}"}
|
||||
response:
|
||||
{
|
||||
{% if id %}
|
||||
"status": "CREATED", "taskid": "{{id}}"
|
||||
{% else %}
|
||||
"status": "FAILED", "error": "{{error.code}}.{{error.message}}"
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
查询: path = "/contents/generations/tasks/{{taskid}}", GET, stream = "sync"
|
||||
response:
|
||||
{
|
||||
{% if status=='succeeded' %}
|
||||
"taskid": "{{id}}", "status": "SUCCEEDED",
|
||||
{% set v=usage.update({'model': model, 'has_video':'no', 'resolution': resolution}) %}
|
||||
"usage": {{json.dumps(usage)}},
|
||||
"video": "{{downloadfile2url(request, content.video_url)}}"
|
||||
{% elif status == "failed" or status == 'expired' %}
|
||||
"status": "FAILED", "error": "{{error.code}}.{{error.message}}"
|
||||
{% else %}
|
||||
"status": "{{status}}"
|
||||
{% endif %}
|
||||
}
|
||||
```
|
||||
|
||||
注意 usage.update 里塞入计费过滤字段(has_video/resolution)——定价 filters 依赖这些值,
|
||||
字段名和值必须与 pricing_data 的 filters 完全一致(最常见的计费失败根因)。
|
||||
|
||||
## 4. 同步功能型接口(stream=sync)
|
||||
|
||||
适用:翻译 / neo4j / milvus 等。
|
||||
|
||||
```
|
||||
翻译: path = "/translate", POST
|
||||
data = {"text": {{json.dumps(prompt)}}, "src_lang": "{{src_lang}}", "tgt_lang": "{{tgt_lang}}"}
|
||||
response = {"content": {{json.dumps(data.translation)}}, "status": "SUCCEEDED"}
|
||||
```
|
||||
|
||||
## 5. 特殊响应形态
|
||||
|
||||
音乐(MiniMax `/music_generation`):
|
||||
|
||||
```
|
||||
data: {"model": "{{model}}", "prompt": {{json.dumps(prompt)}}, "lyrics": {{json.dumps(lyrics)}},
|
||||
"output_format": "url", "audio_setting": {"sample_rate": 44100, "format": "wav", "bitrate": 256000}}
|
||||
response:
|
||||
{% if base_resp.status_code == 0 %}
|
||||
"status": "SUCCEEDED", "usage": {"count": 1},
|
||||
"audio": "{{downloadfile2url(request, data.audio)}}"
|
||||
{% else %}
|
||||
"status": "FAILED", "error": "{{base_resp.status_code}}:{{base_resp.status_msg}}"
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
混元3D(`/v1/ai3d/query`,轮询 JobId):状态字段在 `Response.Status`(DONE/FAIL),
|
||||
产物 `Response.ResultFile3Ds[]` 按 Type=='GLB' 取 `downloadfile2url(request, rzt.Url)`。
|
||||
|
||||
## 6. upapp 样例(供应商注册)
|
||||
|
||||
```
|
||||
upapp:
|
||||
id: 小写可读名(如 "ali-qwen"、"minimax"、"vidu")
|
||||
name: 展示名(如 "阿里百炼"、"MiniMax")
|
||||
baseurl: API 根地址(通义万相原生 = https://dashscope.aliyuncs.com/api/v1;
|
||||
兼容端点 = https://dashscope.aliyuncs.com/compatible-mode/v1)
|
||||
ownerid: "0"
|
||||
dynamic_func: 仅 AK/SK 签名类填(如 "volcengine_ark_sign"),Bearer 类留空
|
||||
```
|
||||
|
||||
## 7. uapiio 样例(输入字段定义)
|
||||
|
||||
`input_fields` 两种格式(历史并存,新配置用数组格式):
|
||||
|
||||
```json
|
||||
// 数组格式(表单驱动)
|
||||
[
|
||||
{"name": "prompt", "label": "提示词", "uitype": "text", "required": true},
|
||||
{"name": "image1_file", "label": "首帧图片", "uitype": "image", "required": true},
|
||||
{"name": "resolution", "label": "分辨率", "uitype": "code",
|
||||
"data": [{"value": "720p"}, {"value": "1080p"}], "defaultvalue": "720p"},
|
||||
{"name": "duration", "label": "视频长度", "uitype": "int", "defaultvalue": 10}
|
||||
]
|
||||
// uitype 可选: text/textarea/image/video/audio/str/int/number/code(下拉)/switch
|
||||
```
|
||||
|
||||
标准 io 可直接复用已有记录(按 ioid 关联):文本会话 `Is8l4TGkcZcqFSjbbeIK2`、
|
||||
asr `JaEJTylQmzGmyRiI1VfzO` 等——先查 uapiio 现有记录再决定是否新建。
|
||||
Loading…
x
Reference in New Issue
Block a user