diff --git a/app/(admin)/settings/_components/local-ai-sections/image-pipeline-sections.tsx b/app/(admin)/settings/_components/local-ai-sections/image-pipeline-sections.tsx index c2ef656c8..cffff1672 100644 --- a/app/(admin)/settings/_components/local-ai-sections/image-pipeline-sections.tsx +++ b/app/(admin)/settings/_components/local-ai-sections/image-pipeline-sections.tsx @@ -5,13 +5,17 @@ import { ArrowUp, Check, Layers, + Loader2, Menu, Move3D, Plus, RefreshCw, Save, + Sparkles, Trash2, + Upload, } from "lucide-react"; +import { CanvasToolbarIcon } from "@/components/canvas/CanvasToolbarIcon"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -26,6 +30,10 @@ import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Textarea } from "@/components/ui/textarea"; +import { + AI_WASH_CONTROL_ORDER, + type AiWashControlId, +} from "@/lib/ai-wash/config"; import { ENHANCE_PRO_KREA_DEFAULT_BASE_URL, ENHANCE_PRO_KREA_DEFAULT_MODEL, @@ -45,6 +53,7 @@ import { } from "../local-ai-section-shell"; export function LocalAiImagePipelineSections({ + modelsData, rmbgConfig, setRmbgConfig, enhanceConfig, @@ -63,6 +72,9 @@ export function LocalAiImagePipelineSections({ selectedEnhanceProPreset, selectedEnhanceProPresetIndex, draggingEnhanceProPresetId, + aiWashConfig, + setAiWashConfig, + aiWashModeIconUploading, extendConfig, setExtendConfig, watermarkRemoveConfig, @@ -87,11 +99,26 @@ export function LocalAiImagePipelineSections({ handleEnhanceProPresetDragEnd, handleEnhanceProPresetDrop, handleMoveEnhanceProPreset, + handleAiWashModeIconUpload, + handleSaveAiWashConfig, handleSaveExtendConfig, handleSaveWatermarkRemoveConfig, handleSaveAngleEditConfig, handleSaveLayerSplitConfig, }: LocalAiImagePipelineSectionsProps) { + const availableImageModels = (modelsData?.models || []).filter( + (model) => model.supportsImageGen && model.isEnabled && !model.isHidden + ); + const getAiWashControlToneCopy = (controlId: AiWashControlId) => { + if (controlId === "creativity") { + return "每档可以单独指定模型;如果留空,前台才会开放模型下拉选择。"; + } + if (controlId === "detail") { + return "每档可以补充默认提示词,决定细节精修的强弱。"; + } + return "每档可以补充默认提示词,决定光影、氛围与空间塑造。"; + }; + return ( <> {/* 抠图API配置 */} @@ -1385,8 +1412,775 @@ export function LocalAiImagePipelineSections({ - + + + + 配置无限画布“AI洗图”子页面使用的生图模型与提示词。前台会基于同一张原图并行生成多组洗图结果,并支持拖动对比。 + + } + expanded={isLocalAiSectionExpanded("ai-wash")} + id="local-ai-section-ai-wash" + onToggle={() => toggleLocalAiSection("ai-wash")} + summary={ + preset.enabled).length} 个启用预设`, + tone: + aiWashConfig.presets.some( + (preset) => + preset.enabled && preset.modelId.trim() && preset.prompt.trim() + ) + ? "enabled" + : "warning", + }, + { + label: aiWashConfig.modeLabel || "AI洗图", + tone: "neutral", + }, + ]} + /> + } + title="AI洗图配置" + > +
+
+ +
+ 开启后,图像增强模式顶部会新增一个“AI洗图”入口,用户可上传底图并批量对比洗图结果。 +
+
+
+ + setAiWashConfig((prev) => ({ + ...prev, + enabled: checked, + })) + } + /> + + {aiWashConfig.enabled ? "已开启" : "已关闭"} + +
+
+ +
+
+
+
+
前台入口名称与图标
+
+ 会同步到图像增强顶部的 AI洗图模式按钮,也会用于洗图工作区标题。 +
+
+
+ + {aiWashConfig.modeIconUrl ? ( + + ) : null} +
+ { + const file = event.target.files?.[0]; + if (file) { + await handleAiWashModeIconUpload(file); + } + event.target.value = ""; + }} + type="file" + /> +
+ +
+
+ + + setAiWashConfig((prev) => ({ + ...prev, + modeLabel: event.target.value, + })) + } + placeholder="AI洗图" + value={aiWashConfig.modeLabel} + /> +
+
+ +
+
+ + {aiWashConfig.modeLabel || "AI洗图"} +
+
+ + {aiWashConfig.modeLabel || "AI洗图"} +
+
+
+
+
+
+ + +
+
+ + + setAiWashConfig((prev) => ({ + ...prev, + historyLimit: Number(event.target.value || 8), + })) + } + type="number" + value={aiWashConfig.historyLimit} + /> +
+
+
+
启用提示词扩写
+
+ 会将预设提示词交给生图供应商做额外 prompt enhance。 +
+
+ + setAiWashConfig((prev) => ({ + ...prev, + promptExtend: checked, + })) + } + /> +
+
+ +
+
+
+
洗图预设
+
+ 前台会横向展示启用中的预设结果。建议至少配置 2 到 3 个不同风格的结果卡位。 +
+
+
+ 共 {aiWashConfig.presets.length} 个预设 +
+
+ +
+ {aiWashConfig.presets.map((preset, index) => ( +
+
+
+
{preset.title || `预设 ${index + 1}`}
+
+ 这个卡位会在前台结果区展示成一张独立的可拖动对比卡片。 +
+
+
+ +
+ + setAiWashConfig((prev) => ({ + ...prev, + presets: prev.presets.map((item, itemIndex) => + itemIndex === index + ? { ...item, enabled: checked } + : item + ), + })) + } + /> + + {preset.enabled ? "启用" : "停用"} + +
+
+
+ +
+
+ + + setAiWashConfig((prev) => ({ + ...prev, + presets: prev.presets.map((item, itemIndex) => + itemIndex === index + ? { ...item, title: event.target.value } + : item + ), + })) + } + placeholder="例如:质感提升(细节更精准)" + value={preset.title} + /> +
+
+ + +
+ 如果这里指定了模型,前台默认不再展示生图模型下拉;创造力档位里若再指定模型,会以档位模型优先。 +
+
+
+ +
+
+ +