diff --git a/apps/web/src/components/admin/SystemSettingsClient.tsx b/apps/web/src/components/admin/SystemSettingsClient.tsx index 59d0baa..f1e5f83 100644 --- a/apps/web/src/components/admin/SystemSettingsClient.tsx +++ b/apps/web/src/components/admin/SystemSettingsClient.tsx @@ -96,6 +96,13 @@ export function SystemSettingsClient() { const [dalleEndpoint, setDalleEndpoint] = useState(""); const [dalleApiKey, setDalleApiKey] = useState(""); + // Gemini / Image generation settings + type ImageProvider = "dalle" | "gemini"; + const [imageProvider, setImageProvider] = useState("dalle"); + const [geminiApiKey, setGeminiApiKey] = useState(""); + const [geminiModel, setGeminiModel] = useState(""); + const [imageSaved, setImageSaved] = useState(false); + // SMTP settings const [smtpHost, setSmtpHost] = useState(""); const [smtpPort, setSmtpPort] = useState(587); @@ -144,6 +151,9 @@ export function SystemSettingsClient() { // DALL-E setDalleDeployment(settings.azureDalleDeployment ?? ""); setDalleEndpoint(settings.azureDalleEndpoint ?? ""); + // Image provider / Gemini + setImageProvider((settings.imageProvider ?? "dalle") as ImageProvider); + setGeminiModel(settings.geminiModel ?? ""); // SMTP setSmtpHost(settings.smtpHost ?? ""); setSmtpPort(settings.smtpPort ?? 587); @@ -240,6 +250,13 @@ export function SystemSettingsClient() { }, }); + const saveImageMutation = trpc.settings.updateSystemSettings.useMutation({ + onSuccess: () => { + setImageSaved(true); + setTimeout(() => setImageSaved(false), 3000); + }, + }); + function handleSaveSmtp() { saveSmtpMutation.mutate({ smtpHost: smtpHost || undefined, @@ -259,6 +276,19 @@ export function SystemSettingsClient() { saveTimelineMutation.mutate({ timelineUndoMaxSteps: undoMaxSteps }); } + function handleSaveImage() { + saveImageMutation.mutate({ + imageProvider, + // DALL-E fields + azureDalleDeployment: dalleDeployment || undefined, + azureDalleEndpoint: provider === "azure" && dalleEndpoint ? dalleEndpoint : undefined, + ...(dalleApiKey ? { azureDalleApiKey: dalleApiKey } : {}), + // Gemini fields + ...(geminiApiKey ? { geminiApiKey } : {}), + geminiModel: geminiModel || undefined, + }); + } + function handleSaveAnonymization() { saveAnonymizationMutation.mutate({ anonymizationEnabled, @@ -295,9 +325,6 @@ export function SystemSettingsClient() { aiTemperature: temperature, aiSummaryPrompt: summaryPrompt || undefined, ...(apiKey ? { azureOpenAiApiKey: apiKey } : {}), - azureDalleDeployment: dalleDeployment, - azureDalleEndpoint: provider === "azure" && dalleEndpoint ? dalleEndpoint : undefined, - ...(dalleApiKey ? { azureDalleApiKey: dalleApiKey } : {}), }); } @@ -1018,67 +1045,159 @@ export function SystemSettingsClient() { - {/* ── DALL-E Image Generation ────────────────────────────────── */} + {/* ── Image Generation ────────────────────────────────── */}

- DALL-E Image Generation + Image Generation

- Used to generate AI cover art for projects. Leave blank to disable AI cover generation. + Used to generate AI cover art for projects. Configure at least one provider below.

-
-
-
diff --git a/apps/web/src/components/projects/CoverArtSection.tsx b/apps/web/src/components/projects/CoverArtSection.tsx index a5a4142..4917bb9 100644 --- a/apps/web/src/components/projects/CoverArtSection.tsx +++ b/apps/web/src/components/projects/CoverArtSection.tsx @@ -25,7 +25,7 @@ export function CoverArtSection({ projectId, coverImageUrl, coverFocusY = 50, pr const fileInputRef = useRef(null); const utils = trpc.useUtils(); - const { data: dalleStatus } = trpc.project.isDalleConfigured.useQuery(); + const { data: imageGenStatus } = trpc.project.isImageGenConfigured.useQuery(); const generateMutation = trpc.project.generateCover.useMutation(); const uploadMutation = trpc.project.uploadCover.useMutation(); const removeMutation = trpc.project.removeCover.useMutation(); @@ -207,7 +207,7 @@ export function CoverArtSection({ projectId, coverImageUrl, coverFocusY = 50, pr )} {/* Generate with AI */} - {dalleStatus?.configured && ( + {imageGenStatus?.configured && (