79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
"use client";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { toast } from "sonner";
|
|
export function PromptTranslateButton({
|
|
prompt,
|
|
model,
|
|
onApply,
|
|
}: {
|
|
prompt: string;
|
|
model?: string;
|
|
onApply: (text: string) => void;
|
|
}) {
|
|
const [busy, setBusy] = useState(false),
|
|
[result, setResult] = useState("");
|
|
const controller = useRef<AbortController | null>(null);
|
|
useEffect(() => () => controller.current?.abort(), []);
|
|
return (
|
|
<>
|
|
<button
|
|
type="button"
|
|
disabled={busy || !prompt.trim()}
|
|
className="rounded px-2 py-1 text-sm disabled:opacity-40"
|
|
onClick={async () => {
|
|
const request = new AbortController();
|
|
controller.current = request;
|
|
setBusy(true);
|
|
try {
|
|
const response = await fetch("/api/canvas/prompt-tools", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ mode: "translate", prompt, model }),
|
|
signal: AbortSignal.any([request.signal, AbortSignal.timeout(100000)]),
|
|
});
|
|
const body = await response.json();
|
|
if (!response.ok || !body.success || !body.data?.text)
|
|
throw Error(body.error || "翻译没有返回结果");
|
|
if (!request.signal.aborted) setResult(body.data.text);
|
|
} catch (error) {
|
|
if (!request.signal.aborted)
|
|
toast.error(error instanceof Error ? error.message : "翻译失败");
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}}
|
|
>
|
|
{busy ? "翻译中…" : "翻译"}
|
|
</button>
|
|
{result ? (
|
|
<div
|
|
role="dialog"
|
|
aria-label="翻译结果"
|
|
className="fixed inset-4 z-[700] flex flex-col gap-3 rounded-xl border border-white/20 bg-[#222] p-5 text-white"
|
|
>
|
|
<textarea
|
|
aria-label="翻译内容"
|
|
className="min-h-0 flex-1 resize-none bg-transparent"
|
|
value={result}
|
|
onChange={(event) => setResult(event.target.value)}
|
|
/>
|
|
<div className="flex justify-end gap-3">
|
|
<button type="button" onClick={() => setResult("")}>
|
|
放弃
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
onApply(result);
|
|
setResult("");
|
|
}}
|
|
>
|
|
应用翻译
|
|
</button>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</>
|
|
);
|
|
}
|