import { useEffect, useState } from "react"; import { Alert, Button, Input, Modal, Spin } from "antd"; import { FileText, RefreshCw, WandSparkles, X } from "lucide-react"; export type CanvasImageTextLine = { original: string; text: string; location: string }; export type CanvasImageTextEditPayload = { lines: CanvasImageTextLine[] }; export function buildCanvasTextEditPrompt(lines: CanvasImageTextLine[]) { const changed = lines.filter((line) => line.text.trim() && line.text !== line.original); return `编辑提供的原图,仅修改指定位置的文字。保持原图构图、字体风格、字号、颜色、排版、材质和其他画面细节不变,不要新增水印或其他文字。${changed.map((line) => `在“${line.location}”位置,将“${line.original}”改为“${line.text}”。`).join("\n")}`; } export function CanvasNodeTextEditDialog({ dataUrl, open, onClose, onDetect, onConfirm, }: { dataUrl: string; open: boolean; onClose: () => void; onDetect: () => Promise; onConfirm: (payload: CanvasImageTextEditPayload) => void; }) { const [lines, setLines] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const detect = async () => { setLoading(true); setError(""); try { const detected = await onDetect(); setLines(detected.map((line) => ({ ...line, text: line.text || line.original }))); } catch (reason) { setError(reason instanceof Error ? reason.message : "文字识别失败"); } finally { setLoading(false); } }; useEffect(() => { if (!open) return; setLines([]); void detect(); // 只在打开或切换源图时识别,避免输入文字触发重复识别。 // eslint-disable-next-line react-hooks/exhaustive-deps }, [dataUrl, open]); const changed = lines.some((line) => line.text.trim() && line.text !== line.original); return (
待编辑图片

识别图片文字

逐行修改文字,位置描述只用于帮助模型定位。

{loading ?
正在识别图片文字…
: error ?
: lines.length ?
{lines.map((line, index) =>
第 {index + 1} 行 · {line.location}
setLines((current) => current.map((item, itemIndex) => itemIndex === index ? { ...item, text: event.target.value } : item))} />
)}
:
没有识别到可编辑文字
}
); }