diff --git a/docs/superpowers/specs/2026-06-04-extended-visual-ratio-settings-design.md b/docs/superpowers/specs/2026-06-04-extended-visual-ratio-settings-design.md
new file mode 100644
index 0000000..63eccf1
--- /dev/null
+++ b/docs/superpowers/specs/2026-06-04-extended-visual-ratio-settings-design.md
@@ -0,0 +1,511 @@
+# 扩展可视化倍率设置设计文档
+
+> **创建日期**:2026-06-04
+> **状态**:待实施
+> **相关组件**:ModelSettingsVisualEditor.jsx
+
+## 需求概述
+
+在现有的 `ModelSettingsVisualEditor` 组件中添加高级倍率字段支持,允许用户为每个模型单独设置缓存、图片、音频相关的倍率。
+
+### 当前限制
+
+现有的可视化倍率设置只能设置:
+- 模型倍率
+- 补全倍率
+
+### 目标
+
+新增以下5个高级倍率字段:
+- 缓存读取倍率
+- 缓存创建倍率
+- 图片倍率
+- 音频输入倍率
+- 音频输出倍率
+
+## 设计方案
+
+### 界面设计
+
+#### 主表格(保持不变)
+
+表格列结构保持现有的简洁布局:
+
+| 列名 | 说明 |
+|------|------|
+| 模型名称 | 显示模型名称,如有矛盾显示红色标签 |
+| 模型固定价格 | 按次计费的价格输入框 |
+| 模型倍率 | 按量计费的模型倍率 |
+| 补全倍率 | 按量计费的补全倍率 |
+| 操作 | 编辑、删除按钮 |
+
+#### 编辑弹窗(新增"高级比例"区域)
+
+在现有的表单结构中,在"定价模式"和"价格设置方式"区域之后,增加一个新的表单区域:
+
+```jsx
+{pricingMode === 'per-token' && (
+ <>
+ {/* 现有的价格设置方式区域 */}
+
+ ...
+
+
+ {/* 新增:高级比例区域 */}
+
+
+
+
+
+
+
+ >
+)}
+```
+
+**设计决策**:
+- 只在"按量计费"模式下显示高级比例字段
+- 按次计费模式不需要这些倍率
+- 使用 `Form.InputNumber` 确保输入的是有效数字
+- `placeholder` 显示默认值提示
+- `step={0.01}` 允许小数点后两位精度
+
+### 数据结构
+
+#### 内部状态扩展
+
+在 `models` 状态数组中,每个模型对象增加5个字段:
+
+```javascript
+{
+ name: 'gpt-4',
+ price: '',
+ ratio: '',
+ completionRatio: '',
+ cacheRatio: '', // 新增
+ cacheCreationRatio: '', // 新增
+ imageRatio: '', // 新增
+ audioRatio: '', // 新增
+ audioCompletionRatio: '', // 新增
+ hasConflict: false
+}
+```
+
+#### 数据初始化
+
+```javascript
+useEffect(() => {
+ try {
+ const modelPrice = JSON.parse(props.options.ModelPrice || '{}');
+ const modelRatio = JSON.parse(props.options.ModelRatio || '{}');
+ const completionRatio = JSON.parse(props.options.CompletionRatio || '{}');
+ // 新增:解析高级倍率字段
+ const cacheRatio = JSON.parse(props.options.CacheRatio || '{}');
+ const createCacheRatio = JSON.parse(props.options.CreateCacheRatio || '{}');
+ const imageRatio = JSON.parse(props.options.ImageRatio || '{}');
+ const audioRatio = JSON.parse(props.options.AudioRatio || '{}');
+ const audioCompletionRatio = JSON.parse(props.options.AudioCompletionRatio || '{}');
+
+ // 合并所有模型名称
+ const modelNames = new Set([
+ ...Object.keys(modelPrice),
+ ...Object.keys(modelRatio),
+ ...Object.keys(completionRatio),
+ ...Object.keys(cacheRatio),
+ ...Object.keys(createCacheRatio),
+ ...Object.keys(imageRatio),
+ ...Object.keys(audioRatio),
+ ...Object.keys(audioCompletionRatio),
+ ]);
+
+ const modelData = Array.from(modelNames).map((name) => {
+ return {
+ name,
+ price: modelPrice[name] === undefined ? '' : modelPrice[name],
+ ratio: modelRatio[name] === undefined ? '' : modelRatio[name],
+ completionRatio: completionRatio[name] === undefined ? '' : completionRatio[name],
+ cacheRatio: cacheRatio[name] === undefined ? '' : cacheRatio[name],
+ cacheCreationRatio: createCacheRatio[name] === undefined ? '' : createCacheRatio[name],
+ imageRatio: imageRatio[name] === undefined ? '' : imageRatio[name],
+ audioRatio: audioRatio[name] === undefined ? '' : audioRatio[name],
+ audioCompletionRatio: audioCompletionRatio[name] === undefined ? '' : audioCompletionRatio[name],
+ hasConflict: modelPrice[name] !== '' && (modelRatio[name] !== '' || completionRatio[name] !== ''),
+ };
+ });
+
+ setModels(modelData);
+ } catch (error) {
+ console.error('JSON解析错误:', error);
+ }
+}, [props.options]);
+```
+
+#### API 请求结构
+
+保存时将5个新增字段序列化到对应的 JSON 字段:
+
+```javascript
+const SubmitData = async () => {
+ setLoading(true);
+ const output = {
+ ModelPrice: {},
+ ModelRatio: {},
+ CompletionRatio: {},
+ CacheRatio: {}, // 新增
+ CreateCacheRatio: {}, // 新增
+ ImageRatio: {}, // 新增
+ AudioRatio: {}, // 新增
+ AudioCompletionRatio: {} // 新增
+ };
+
+ try {
+ // 数据转换
+ models.forEach((model) => {
+ if (model.price !== '') {
+ output.ModelPrice[model.name] = parseFloat(model.price);
+ } else {
+ if (model.ratio !== '')
+ output.ModelRatio[model.name] = parseFloat(model.ratio);
+ if (model.completionRatio !== '')
+ output.CompletionRatio[model.name] = parseFloat(model.completionRatio);
+ }
+
+ // 新增:处理高级倍率字段
+ if (model.cacheRatio !== '')
+ output.CacheRatio[model.name] = parseFloat(model.cacheRatio);
+ if (model.cacheCreationRatio !== '')
+ output.CreateCacheRatio[model.name] = parseFloat(model.cacheCreationRatio);
+ if (model.imageRatio !== '')
+ output.ImageRatio[model.name] = parseFloat(model.imageRatio);
+ if (model.audioRatio !== '')
+ output.AudioRatio[model.name] = parseFloat(model.audioRatio);
+ if (model.audioCompletionRatio !== '')
+ output.AudioCompletionRatio[model.name] = parseFloat(model.audioCompletionRatio);
+ });
+
+ // 准备API请求数组
+ const finalOutput = {
+ ModelPrice: JSON.stringify(output.ModelPrice, null, 2),
+ ModelRatio: JSON.stringify(output.ModelRatio, null, 2),
+ CompletionRatio: JSON.stringify(output.CompletionRatio, null, 2),
+ CacheRatio: JSON.stringify(output.CacheRatio, null, 2),
+ CreateCacheRatio: JSON.stringify(output.CreateCacheRatio, null, 2),
+ ImageRatio: JSON.stringify(output.ImageRatio, null, 2),
+ AudioRatio: JSON.stringify(output.AudioRatio, null, 2),
+ AudioCompletionRatio: JSON.stringify(output.AudioCompletionRatio, null, 2),
+ };
+
+ const requestQueue = Object.entries(finalOutput).map(([key, value]) => {
+ return API.put('/api/option/', { key, value });
+ });
+
+ // 批量处理请求
+ const results = await Promise.all(requestQueue);
+
+ // 验证结果(保持现有逻辑)
+ // ...
+ } catch (error) {
+ // 错误处理
+ } finally {
+ setLoading(false);
+ }
+};
+```
+
+### 交互逻辑
+
+#### 1. 编辑模型
+
+编辑现有模型时,需要在弹窗中正确回显高级倍率字段的值:
+
+```javascript
+const editModel = (record) => {
+ setIsEditMode(true);
+
+ // 现有的定价模式设置逻辑
+ // ...
+
+ // 创建模型副本
+ const modelCopy = { ...record };
+
+ // 如果有倍率数据,转换为 token price(现有逻辑)
+ if (record.ratio) {
+ modelCopy.tokenPrice = calculateTokenPriceFromRatio(parseFloat(record.ratio)).toString();
+ if (record.completionRatio) {
+ modelCopy.completionTokenPrice = (
+ parseFloat(modelCopy.tokenPrice) * parseFloat(record.completionRatio)
+ ).toString();
+ }
+ }
+
+ // 设置当前模型
+ setCurrentModel(modelCopy);
+ setVisible(true);
+
+ // 设置表单值
+ setTimeout(() => {
+ if (formRef.current) {
+ formRef.current.setValues({
+ name: modelCopy.name,
+ // 现有字段
+ ratioInput: modelCopy.ratio,
+ completionRatioInput: modelCopy.completionRatio,
+ modelTokenPrice: modelCopy.tokenPrice,
+ completionTokenPrice: modelCopy.completionTokenPrice,
+ // 新增:高级倍率字段
+ cacheRatio: modelCopy.cacheRatio,
+ cacheCreationRatio: modelCopy.cacheCreationRatio,
+ imageRatio: modelCopy.imageRatio,
+ audioRatio: modelCopy.audioRatio,
+ audioCompletionRatio: modelCopy.audioCompletionRatio,
+ });
+ }
+ }, 0);
+};
+```
+
+#### 2. 添加/更新模型
+
+在 `addOrUpdateModel` 函数中处理高级倍率字段:
+
+```javascript
+const addOrUpdateModel = (values) => {
+ const existingModelIndex = models.findIndex(
+ (model) => model.name === values.name,
+ );
+
+ const updatedModel = {
+ name: values.name,
+ price: values.price || '',
+ ratio: values.ratio || '',
+ completionRatio: values.completionRatio || '',
+ // 新增:高级倍率字段
+ cacheRatio: values.cacheRatio || '',
+ cacheCreationRatio: values.cacheCreationRatio || '',
+ imageRatio: values.imageRatio || '',
+ audioRatio: values.audioRatio || '',
+ audioCompletionRatio: values.audioCompletionRatio || '',
+ };
+
+ updatedModel.hasConflict =
+ updatedModel.price !== '' &&
+ (updatedModel.ratio !== '' || updatedModel.completionRatio !== '');
+
+ if (existingModelIndex >= 0) {
+ // 更新现有模型
+ setModels((prev) =>
+ prev.map((model, index) =>
+ index !== existingModelIndex ? model : updatedModel
+ )
+ );
+ setVisible(false);
+ showSuccess(t('更新成功'));
+ } else {
+ // 添加新模型
+ if (models.some((model) => model.name === values.name)) {
+ showError(t('模型名称已存在'));
+ return;
+ }
+ setModels((prev) => [updatedModel, ...prev]);
+ setVisible(false);
+ showSuccess(t('添加成功'));
+ }
+};
+```
+
+#### 3. 输入验证
+
+在 `updateModel` 函数中增加对高级倍率字段的验证:
+
+```javascript
+const updateModel = (name, field, value) => {
+ if (isNaN(value) && value !== '') { // 允许空字符串
+ showError(t('请输入数字'));
+ return;
+ }
+ setModels((prev) =>
+ prev.map((model) => {
+ if (model.name !== name) return model;
+ const updated = { ...model, [field]: value };
+ updated.hasConflict =
+ updated.price !== '' &&
+ (updated.ratio !== '' || updated.completionRatio !== '');
+ return updated;
+ }),
+ );
+};
+```
+
+### 默认值处理策略
+
+**前端处理默认值**:用户输入框留空时,保存为空字符串,后端使用全局默认值。
+
+**默认值映射**:
+- 缓存读取倍率:1.0
+- 缓存创建倍率:1.25
+- 图片倍率:1.0
+- 音频输入倍率:1.0
+- 音频输出倍率:1.0
+
+**实现方式**:
+- 输入框使用 `placeholder` 提示默认值
+- 提交时空字符串保持为空,不转换
+- 后端处理空值时返回对应的默认值
+
+### 模型能力处理
+
+**策略**:全部显示,用户自行判断
+
+- 所有5个高级倍率字段始终显示在编辑弹窗中
+- 用户根据自己使用的模型判断是否填写相应字段
+- 不在前端进行模型能力验证或字段隐藏
+
+**设计理由**:
+- 简化实现,避免维护复杂的模型能力映射
+- 给用户更多控制权,允许为任意模型设置任意倍率
+- 与渠道价格设置的实现方式保持一致
+
+## 实现要点
+
+### 1. 字段映射
+
+确保前端字段名与后端 `options` 表中的 key 一致:
+
+| 前端字段名 | 后端 Option Key | 默认值 |
+|-----------|----------------|--------|
+| cacheRatio | CacheRatio | 1.0 |
+| cacheCreationRatio | CreateCacheRatio | 1.25 |
+| imageRatio | ImageRatio | 1.0 |
+| audioRatio | AudioRatio | 1.0 |
+| audioCompletionRatio | AudioCompletionRatio | 1.0 |
+
+### 2. 数值验证
+
+- 输入时验证为有效数字:`if (isNaN(value) && value !== '')`
+- 范围验证:`min={0}` 确保非负数
+- 小数精度:`step={0.01}` 允许两位小数
+
+### 3. 空值处理
+
+- 空字符串视为未设置,保存时保持为空字符串
+- 后端处理时如果值为空,返回对应的全局默认值
+- 前端解析 JSON 时,如果字段不存在,默认为空字符串:`cacheRatio[name] === undefined ? '' : cacheRatio[name]`
+
+### 4. 样式统一
+
+- 使用与现有字段一致的 `Form.InputNumber` 组件
+- 保持相同的 `label`、`placeholder` 样式
+- 表单区域使用 `Form.Section` 包裹,标题为"高级比例(留空使用默认值)"
+
+### 5. 国际化支持
+
+需要为新增的文本添加翻译:
+
+**中文 (zh-CN.json)**:
+```json
+{
+ "高级比例(留空使用默认值)": "高级比例(留空使用默认值)",
+ "缓存读取倍率": "缓存读取倍率",
+ "缓存创建倍率(5分钟)": "缓存创建倍率(5分钟)",
+ "图片倍率": "图片倍率",
+ "音频输入倍率": "音频输入倍率",
+ "音频输出倍率": "音频输出倍率",
+ "默认值:1.0": "默认值:1.0",
+ "默认值:1.25": "默认值:1.25"
+}
+```
+
+**英文 (en.json)**:
+```json
+{
+ "高级比例(留空使用默认值)": "Advanced Ratios (Leave empty for defaults)",
+ "缓存读取倍率": "Cache Read Ratio",
+ "缓存创建倍率(5分钟)": "Cache Creation Ratio (5min)",
+ "图片倍率": "Image Ratio",
+ "音频输入倍率": "Audio Input Ratio",
+ "音频输出倍率": "Audio Output Ratio",
+ "默认值:1.0": "Default: 1.0",
+ "默认值:1.25": "Default: 1.25"
+}
+```
+
+## 测试要点
+
+### 1. 数据初始化测试
+
+- 测试从空 options 初始化,确保所有字段为空字符串
+- 测试从已有数据初始化,确保正确解析所有倍率值
+
+### 2. 编辑功能测试
+
+- 测试编辑现有模型,确保高级倍率字段正确回显
+- 测试添加新模型,确保所有字段可以正常输入
+- 测试删除模型,确保相关数据正确清理
+
+### 3. 保存功能测试
+
+- 测试只填写部分高级倍率字段,确保正确保存
+- 测试所有高级倍率字段都留空,确保保存为空字符串
+- 测试填写数值超出范围,确保验证生效
+
+### 4. 默认值测试
+
+- 测试留空字段,确保后端使用默认值
+- 测试输入 0,确保保存为数值 0 而不是默认值
+
+### 5. 边界情况测试
+
+- 测试输入负数,确保被拒绝(min={0})
+- 测试输入非数字字符,确保显示错误提示
+- 测试输入非常多小数位,确保 step={0.01} 生效
+
+## 参考实现
+
+本设计参考了 `feat/channel-pricing-extended` 分支中的 `ChannelPricingView.jsx` 实现,特别是:
+
+1. **表单结构**:使用 `Form.Section` 包裹高级比例字段
+2. **字段命名**:使用与后端 Option Key 一致的字段名
+3. **默认值处理**:使用 placeholder 提示默认值,空字符串表示使用默认值
+4. **输入验证**:使用 `Form.InputNumber` 配合 `min` 和 `step` 属性
+
+## 实施检查清单
+
+- [ ] 修改 `ModelSettingsVisualEditor.jsx`,增加高级比例表单区域
+- [ ] 更新数据初始化逻辑,解析新增的5个 JSON 字段
+- [ ] 更新保存逻辑,序列化并提交新增的5个字段
+- [ ] 更新编辑模型逻辑,正确回显高级倍率字段
+- [ ] 更新添加/更新模型逻辑,处理高级倍率字段
+- [ ] 添加输入验证,确保输入有效数字
+- [ ] 添加国际化文本(中英文)
+- [ ] 测试数据初始化、编辑、保存功能
+- [ ] 测试边界情况和默认值处理