feat: add watermark removal to detail results
This commit is contained in:
parent
2b82d57f73
commit
528968d74d
@ -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<ReplacementRerunTarget | null>(null);
|
||||
const [replacementRerunPrompt, setReplacementRerunPrompt] = useState("");
|
||||
const [detailWatermarkRemoveCardIds, setDetailWatermarkRemoveCardIds] =
|
||||
useState<Set<string>>(() => 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 (
|
||||
<div
|
||||
key={`${card.id}-result`}
|
||||
@ -7144,6 +7217,27 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
>
|
||||
重新生图
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={isAnyGenerationRunning || isWatermarkRemoving}
|
||||
onClick={() =>
|
||||
void handleRemoveDetailResultWatermark({
|
||||
cardId: card.id,
|
||||
imageUrl: card.resultUrl!,
|
||||
})
|
||||
}
|
||||
className={cn(
|
||||
IMAGE_OVERLAY_ACTION_CLASS,
|
||||
"inline-flex items-center gap-1.5 disabled:cursor-not-allowed disabled:opacity-45"
|
||||
)}
|
||||
>
|
||||
{isWatermarkRemoving ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Droplet className="h-3.5 w-3.5" />
|
||||
)}
|
||||
<span>{isWatermarkRemoving ? "去水印中" : "去水印"}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user