feat(image): integrate PoloX image editing workflows
Add WaveSpeed image editing and image tools plugins, canvas image editing workflows, layer selection, and Cloud Agent image tools with approval-safe transient references.
This commit is contained in:
72
web/src/components/canvas/canvas-node-image-edit-dialog.tsx
Normal file
72
web/src/components/canvas/canvas-node-image-edit-dialog.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button, Input, Modal } from "antd";
|
||||
import { WandSparkles, X } from "lucide-react";
|
||||
import { ModelPicker } from "@/components/model-picker";
|
||||
import type { AiConfig } from "@/stores/use-config-store";
|
||||
import { defaultImageParamsForModel } from "@/lib/model-selection";
|
||||
|
||||
export type CanvasImageEditPayload = { prompt: string; generationConfig?: Partial<Pick<AiConfig, "model" | "imageModel" | "size" | "quality">> };
|
||||
|
||||
export function CanvasNodeImageEditDialog({
|
||||
dataUrl,
|
||||
open,
|
||||
config,
|
||||
preset,
|
||||
onClose,
|
||||
onConfirm,
|
||||
}: {
|
||||
dataUrl: string;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onConfirm: (payload: CanvasImageEditPayload) => void;
|
||||
config: AiConfig;
|
||||
preset?: "remove-background" | null;
|
||||
}) {
|
||||
const [prompt, setPrompt] = useState(preset === "remove-background" ? "移除图片背景,保留主体完整轮廓、细节和边缘,输出透明背景。" : "");
|
||||
const [generationConfig, setGenerationConfig] = useState<AiConfig>(config);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) setPrompt(preset === "remove-background" ? "移除图片背景,保留主体完整轮廓、细节和边缘,输出透明背景。" : "");
|
||||
if (open) setGenerationConfig(config);
|
||||
}, [config, open, dataUrl]);
|
||||
|
||||
return (
|
||||
<Modal open={open && Boolean(dataUrl)} onCancel={onClose} footer={null} centered destroyOnHidden width={860} title="图片编辑">
|
||||
<div className="grid gap-5 md:grid-cols-[minmax(0,1fr)_300px]">
|
||||
<div className="grid min-h-[320px] place-items-center overflow-hidden rounded-xl bg-black/5 p-3 dark:bg-white/[0.04]">
|
||||
<img src={dataUrl} alt="待编辑图片" className="max-h-[58vh] max-w-full object-contain" draggable={false} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">{preset === "remove-background" ? "去除背景" : "描述你要修改的内容"}</h3>
|
||||
<p className="mt-1 text-sm opacity-60">保留主体和构图,只修改你描述的部分。</p>
|
||||
</div>
|
||||
<Input.TextArea
|
||||
autoFocus
|
||||
rows={7}
|
||||
value={prompt}
|
||||
placeholder="例如:把背景换成黄昏海边,保持人物姿势和服装不变"
|
||||
onChange={(event) => setPrompt(event.target.value)}
|
||||
/>
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm font-medium opacity-75">编辑模型</div>
|
||||
<ModelPicker
|
||||
config={generationConfig}
|
||||
value={generationConfig.imageModel || generationConfig.model}
|
||||
capability="image"
|
||||
fullWidth
|
||||
showSelectedPrice={false}
|
||||
onChange={(model) => setGenerationConfig((current) => ({ ...current, model, imageModel: model, ...defaultImageParamsForModel(current, model) }))}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-auto flex justify-end gap-2">
|
||||
<Button icon={<X className="size-4" />} onClick={onClose}>取消</Button>
|
||||
<Button type="primary" icon={<WandSparkles className="size-4" />} disabled={!prompt.trim()} onClick={() => onConfirm({ prompt: prompt.trim(), generationConfig: { model: generationConfig.model, imageModel: generationConfig.imageModel, size: generationConfig.size, quality: generationConfig.quality } })}>
|
||||
开始编辑
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user