diff --git a/components/agents/AgentGenerationWorkspaceDarkV2.tsx b/components/agents/AgentGenerationWorkspaceDarkV2.tsx index 28438d987..b09742e5f 100644 --- a/components/agents/AgentGenerationWorkspaceDarkV2.tsx +++ b/components/agents/AgentGenerationWorkspaceDarkV2.tsx @@ -18,6 +18,7 @@ import { motion, AnimatePresence } from "framer-motion"; import { ArrowUp, CheckCircle2, + Droplet, RefreshCw, ChevronDown, ChevronUp, @@ -67,6 +68,7 @@ import { useAgentStylePerformanceMonitor } from "@/components/agents/use-agent-s import { ImageAnnotator } from "@/components/image-annotator"; import { useCanvasStore } from "@/store/canvas"; import { fetchUploadWithRetry } from "@/lib/client/upload-with-retry"; +import { requestLongTaskResult } from "@/lib/client/long-task"; import { buildImageProxyUrl } from "@/lib/image-delivery"; import { extractImageUrlsFromText } from "@/lib/image-url"; import { @@ -1457,6 +1459,8 @@ export function AgentGenerationWorkspaceDarkV2({ const [replacementRerunTarget, setReplacementRerunTarget] = useState(null); const [replacementRerunPrompt, setReplacementRerunPrompt] = useState(""); + const [detailWatermarkRemoveCardIds, setDetailWatermarkRemoveCardIds] = + useState>(() => new Set()); const closePsdTemplateDialog = useCallback(() => { setIsPsdTemplateDialogOpen(false); setPsdTemplateDialogSourceUrl(null); @@ -3859,6 +3863,74 @@ export function AgentGenerationWorkspaceDarkV2({ title: String(params.title || "").trim() || "待改字结果", }); }, []); + const handleRemoveDetailResultWatermark = useCallback( + async (params: { + cardId: string; + imageUrl: string; + }) => { + const rawUrl = String(params.imageUrl || "").trim(); + const cardId = String(params.cardId || "").trim(); + if (!cardId || !/^https?:\/\//i.test(rawUrl)) { + toast.error("结果图地址无效,无法去水印"); + return; + } + if (isAnyGenerationRunning) { + toast.info("当前仍有生成任务处理中,完成后再去水印"); + return; + } + if (detailWatermarkRemoveCardIds.has(cardId)) { + return; + } + + setDetailWatermarkRemoveCardIds((current) => { + const next = new Set(current); + next.add(cardId); + return next; + }); + toast.info("正在去水印..."); + + try { + const payload = await requestLongTaskResult({ + endpoint: "/api/watermark-remove", + payload: { + image_url: rawUrl, + }, + }); + if (!payload?.success) { + throw new Error(payload?.error || payload?.detail || "去水印失败"); + } + const nextUrl = String(payload.original_url || payload.thumbnail_url || "").trim(); + if (!/^https?:\/\//i.test(nextUrl)) { + throw new Error("去水印完成但结果地址无效"); + } + + handleUpdateReplacementResultRecord({ + modeType: "detail_replacement", + cardId, + url: nextUrl, + text: "已完成去水印处理。", + status: "completed", + }); + setActiveResultModeType("detail_replacement"); + setSelectedResultUrl(nextUrl); + toast.success("去水印完成,已更新当前结果图"); + } catch (error) { + console.error("[AgentGenerationWorkspaceDarkV2] 去水印失败:", error); + toast.error(error instanceof Error ? error.message : "去水印失败,请稍后重试"); + } finally { + setDetailWatermarkRemoveCardIds((current) => { + const next = new Set(current); + next.delete(cardId); + return next; + }); + } + }, + [ + detailWatermarkRemoveCardIds, + handleUpdateReplacementResultRecord, + isAnyGenerationRunning, + ] + ); const getReplacementExecutionCards = useCallback( (params: { modeType: ReplacementModeType; @@ -7057,6 +7129,7 @@ export function AgentGenerationWorkspaceDarkV2({ const statusMeta = getReplacementCardStatusMeta(card.status); const isPending = card.status === "generating" || card.status === "queued"; const hasResult = Boolean(card.resultUrl) && !isPending; + const isWatermarkRemoving = detailWatermarkRemoveCardIds.has(card.id); return (
重新生图 +
) : (