fix: align AI retouch template rules
This commit is contained in:
@@ -86,10 +86,10 @@ GET /api/yf-handset-app/photog/travel-album/ai-retouch-options?user_equity_trave
|
||||
|
||||
| `scope` | 使用场景 |
|
||||
|---|---|
|
||||
| `batch` | 网格多选 AI 修图 |
|
||||
| `all_variants` | 预览页无 Tab,或当前是原图 Tab |
|
||||
| `refined_only` | 当前是精修后 Tab |
|
||||
| `atmosphere_only` | 当前是氛围感 Tab |
|
||||
| `batch` | 网格多选 AI 修图,或预览页尚无 AI 结果 Tab 时首次修图 |
|
||||
| `all_variants` | 预览页已有 AI 结果 Tab;当前为原图、精修后或氛围感均使用此范围 |
|
||||
| `refined_only` | 仅重修精修结果的接口能力,当前客户端无独立入口 |
|
||||
| `atmosphere_only` | 仅重修氛围感结果的接口能力,当前客户端无独立入口 |
|
||||
|
||||
`user_equity_travel_id`、`scope` 和 `source_count` 均必填。`source_count` 用于计算封面模板是否显示和必选。
|
||||
|
||||
@@ -226,7 +226,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.4.2 预览页原图 Tab
|
||||
#### 5.4.2 预览页已有 AI 结果 Tab
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -234,10 +234,6 @@ Content-Type: application/json
|
||||
"scope": "all_variants",
|
||||
"source_material_ids": ["2031"],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "refined",
|
||||
"template_id": "tpl_refined_15"
|
||||
},
|
||||
{
|
||||
"type": "atmosphere",
|
||||
"template_id": "tpl_atmosphere_09"
|
||||
@@ -246,7 +242,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
如用户未选氛围感模板,`outputs` 中不传 `atmosphere`。缺失表示“本次不处理”,不表示删除现有氛围感图。
|
||||
已有精修或氛围感结果时,无论当前位于原图、精修后还是氛围感 Tab,精修和氛围感模板均为选填,但至少选择一种。`outputs` 只传本次选中的结果类型;缺失表示“本次不处理”,不表示删除或覆盖对应的已有结果。
|
||||
|
||||
#### 5.4.3 只重新精修
|
||||
|
||||
@@ -285,7 +281,7 @@ Content-Type: application/json
|
||||
| `scope` | 原图数 | 精修 | 氛围感 | 封面 |
|
||||
|---|---:|---|---|---|
|
||||
| `batch` | 1 至 50 | 必选 | 可选 | 少于 4 张禁止;4 张及以上必选 |
|
||||
| `all_variants` | 必须为 1 | 必选 | 可选 | 禁止 |
|
||||
| `all_variants` | 必须为 1 | 可选(与氛围感至少一项) | 可选(与精修至少一项) | 禁止 |
|
||||
| `refined_only` | 必须为 1 | 必选 | 禁止 | 禁止 |
|
||||
| `atmosphere_only` | 必须为 1 | 禁止 | 必选 | 禁止 |
|
||||
|
||||
|
||||
@@ -114,9 +114,9 @@ Cell 左上角展示稳定的修图状态:
|
||||
| 当前情况 | 模板要求 | 生成与覆盖规则 |
|
||||
|---|---|---|
|
||||
| 不显示 Tab | 精修必选,氛围感可选 | 首次生成关联的精修图,可选生成氛围感图 |
|
||||
| 已显示 Tab,当前为“原图” | 精修必选,氛围感可选 | 重新生成精修图;如选氛围感则也重新生成。新结果成功后原子替换对应旧结果 |
|
||||
| 已显示 Tab,当前为“精修后” | 精修必选 | 只重新生成精修图,成功后覆盖旧精修图,不影响氛围感图 |
|
||||
| 已显示 Tab,当前为“氛围感” | 氛围感必选 | 只重新生成氛围感图,成功后覆盖旧氛围感图,不影响精修图 |
|
||||
| 已显示 Tab,当前为“原图” | 精修、氛围感均可选,至少选择一种 | 只重新生成本次选中的结果类型;新结果成功后替换对应旧结果,未选类型保持不变 |
|
||||
| 已显示 Tab,当前为“精修后” | 精修、氛围感均可选,至少选择一种 | 只重新生成本次选中的结果类型;新结果成功后替换对应旧结果,未选类型保持不变 |
|
||||
| 已显示 Tab,当前为“氛围感” | 精修、氛围感均可选,至少选择一种 | 只重新生成本次选中的结果类型;新结果成功后替换对应旧结果,未选类型保持不变 |
|
||||
|
||||
重新修图期间应保留上一版成功图片可见;只有新结果成功时才原子替换当前版本。失败时继续保留旧版本,并返回可展示的错误信息。
|
||||
|
||||
|
||||
@@ -387,14 +387,13 @@ enum TravelAlbumAIRetouchWorkflow: Sendable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
/// 当前分组是否允许不选择;首次修图和原图 Tab 覆盖重修的氛围感模板选填。
|
||||
/// 当前分组是否允许不选择;首次修图仅氛围感选填,已有 AI 结果的预览重修两类模板均选填。
|
||||
func isOptional(_ category: TravelAlbumAIRetouchTemplateCategory) -> Bool {
|
||||
guard category == .atmosphere else { return false }
|
||||
switch self {
|
||||
case .initial:
|
||||
return true
|
||||
return category == .atmosphere
|
||||
case .reretouch(_, _, .all):
|
||||
return true
|
||||
return category == .refined || category == .atmosphere
|
||||
case .reretouch:
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ struct TravelAlbumPreviewProject: Identifiable, Sendable, Hashable {
|
||||
self.assets = assets.filter { seenKinds.insert($0.kind).inserted }
|
||||
}
|
||||
|
||||
/// 根据当前 Tab 生成首次修图或覆盖重修工作流。
|
||||
/// 根据是否已有 AI 结果生成首次修图或双模板覆盖重修工作流。
|
||||
func aiRetouchWorkflow(
|
||||
albumId: Int,
|
||||
selectedKind: TravelAlbumPreviewAssetKind
|
||||
@@ -183,16 +183,8 @@ struct TravelAlbumPreviewProject: Identifiable, Sendable, Hashable {
|
||||
guard hasVariants else {
|
||||
return .initial(albumId: albumId, materialIds: [originalMaterialId])
|
||||
}
|
||||
switch selectedKind {
|
||||
case .original:
|
||||
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .all)
|
||||
case .retouched:
|
||||
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .refined)
|
||||
case .atmosphere:
|
||||
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .atmosphere)
|
||||
case .cover:
|
||||
return nil
|
||||
}
|
||||
guard selectedKind != .cover else { return nil }
|
||||
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .all)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-4
@@ -90,7 +90,8 @@ final class TravelAlbumAIRetouchTemplateViewModel {
|
||||
case .refined, .atmosphere:
|
||||
return 1
|
||||
case .all:
|
||||
return 1 + (selectedAtmosphereTemplateId == nil ? 0 : 1)
|
||||
return (selectedRefinedTemplateId == nil ? 0 : 1)
|
||||
+ (selectedAtmosphereTemplateId == nil ? 0 : 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +110,11 @@ final class TravelAlbumAIRetouchTemplateViewModel {
|
||||
return unavailableMessage(for: category)
|
||||
}
|
||||
}
|
||||
if case .reretouch(_, _, .all) = workflow,
|
||||
selectedRefinedTemplateId == nil,
|
||||
selectedAtmosphereTemplateId == nil {
|
||||
return "请至少选择一个修图模板"
|
||||
}
|
||||
guard let remainingQuota else {
|
||||
return "剩余修图次数获取失败,请刷新后重试"
|
||||
}
|
||||
@@ -146,7 +152,9 @@ final class TravelAlbumAIRetouchTemplateViewModel {
|
||||
atmosphereTemplates = response.atmosphereTemplates
|
||||
coverTemplates = response.coverTemplates
|
||||
remainingQuota = response.remainingQuota
|
||||
selectedRefinedTemplateId = visibleCategories.contains(.refined) ? refinedTemplates.first?.id : nil
|
||||
selectedRefinedTemplateId = visibleCategories.contains(.refined) && !isOptional(.refined)
|
||||
? refinedTemplates.first?.id
|
||||
: nil
|
||||
selectedAtmosphereTemplateId = visibleCategories.contains(.atmosphere) && !isOptional(.atmosphere)
|
||||
? atmosphereTemplates.first?.id
|
||||
: nil
|
||||
@@ -188,14 +196,14 @@ final class TravelAlbumAIRetouchTemplateViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// 选择模板;仅选填分组允许再次点击取消,必选分组保持单选。
|
||||
/// 选择模板;选填分组允许再次点击取消,必选分组保持单选。
|
||||
func toggleTemplate(id: Int, category: TravelAlbumAIRetouchTemplateCategory) {
|
||||
guard visibleCategories.contains(category),
|
||||
templates(for: category).contains(where: { $0.id == id })
|
||||
else { return }
|
||||
switch category {
|
||||
case .refined:
|
||||
selectedRefinedTemplateId = id
|
||||
selectedRefinedTemplateId = isOptional(category) && selectedRefinedTemplateId == id ? nil : id
|
||||
case .atmosphere:
|
||||
selectedAtmosphereTemplateId = isOptional(category) && selectedAtmosphereTemplateId == id ? nil : id
|
||||
case .cover:
|
||||
|
||||
Reference in New Issue
Block a user