Files
at-mintel/packages/payload-ai/src/components/AiMediaButtons.tsx

164 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import React, { useState } from "react";
import { useDocumentInfo, toast } from "@payloadcms/ui";
type Action = "upscale" | "recover";
interface ActionState {
loading: boolean;
resultId?: string | number;
}
export const AiMediaButtons: React.FC = () => {
const { id } = useDocumentInfo();
const [upscale, setUpscale] = useState<ActionState>({ loading: false });
const [recover, setRecover] = useState<ActionState>({ loading: false });
if (!id) return null; // Only show on existing documents
const runAction = async (action: Action) => {
const setter = action === "upscale" ? setUpscale : setRecover;
setter({ loading: true });
const label = action === "upscale" ? "AI Upscale" : "AI Recover";
toast.info(
`${label} started this can take 3090 seconds, please wait…`,
);
try {
// The API path is hardcoded here and assuming that's where the host app registers the endpoint.
const response = await fetch(`/api/media/${id}/ai-process`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action }),
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error || `${label} failed`);
}
setter({ loading: false, resultId: result.mediaId });
toast.success(
`${label} erfolgreich! Neues Bild (ID: ${result.mediaId}) wurde gespeichert.`,
);
} catch (err: any) {
console.error(`[AiMediaButtons] ${action} error:`, err);
toast.error(
err instanceof Error ? err.message : `${label} fehlgeschlagen`,
);
setter({ loading: false });
}
};
const buttonStyle: React.CSSProperties = {
background: "var(--theme-elevation-150)",
border: "1px solid var(--theme-elevation-200)",
color: "var(--theme-text)",
padding: "8px 14px",
borderRadius: "4px",
fontSize: "13px",
fontWeight: 500,
display: "inline-flex",
alignItems: "center",
gap: "6px",
transition: "opacity 0.15s ease",
};
const disabledStyle: React.CSSProperties = {
opacity: 0.55,
cursor: "not-allowed",
};
return (
<div
style={{
display: "flex",
flexWrap: "wrap",
gap: "10px",
marginBottom: "1.5rem",
marginTop: "0.5rem",
}}
>
{/* AI Upscale */}
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
<button
type="button"
disabled={upscale.loading || recover.loading}
onClick={() => runAction("upscale")}
style={{
...buttonStyle,
...(upscale.loading || recover.loading ? disabledStyle : { cursor: "pointer" }),
}}
>
{upscale.loading ? "⏳ AI Upscale läuft…" : "✨ AI Upscale"}
</button>
{upscale.resultId && (
<a
href={`/admin/collections/media/${upscale.resultId}`}
target="_blank"
rel="noopener noreferrer"
style={{
fontSize: "12px",
color: "var(--theme-elevation-500)",
textDecoration: "underline",
}}
>
Neues Bild öffnen (ID: {upscale.resultId})
</a>
)}
</div>
{/* AI Recover */}
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
<button
type="button"
disabled={upscale.loading || recover.loading}
onClick={() => runAction("recover")}
style={{
...buttonStyle,
...(upscale.loading || recover.loading ? disabledStyle : { cursor: "pointer" }),
}}
>
{recover.loading ? "⏳ AI Recover läuft…" : "🔄 AI Recover"}
</button>
{recover.resultId && (
<a
href={`/admin/collections/media/${recover.resultId}`}
target="_blank"
rel="noopener noreferrer"
style={{
fontSize: "12px",
color: "var(--theme-elevation-500)",
textDecoration: "underline",
}}
>
Neues Bild öffnen (ID: {recover.resultId})
</a>
)}
</div>
<p
style={{
width: "100%",
fontSize: "0.8rem",
color: "var(--theme-elevation-500)",
margin: 0,
lineHeight: 1.4,
}}
>
<strong>AI Upscale</strong> verbessert die Auflösung via{" "}
<code>google/upscaler</code>. <strong>AI Recover</strong> restauriert
alte/beschädigte Fotos via{" "}
<code>microsoft/bringing-old-photos-back-to-life</code>. Das
Ergebnis wird als neues Medium gespeichert.
</p>
</div>
);
};