feat: Gemini image generation test button in admin settings

API: new testGeminiConnection adminProcedure
- Generates a simple test image via Gemini API
- Returns { ok, model } on success, { ok: false, error } on failure
- Audit logged: "Gemini test succeeded/failed"

UI: "Test Gemini" button next to "Save Image Settings"
- Only visible when Gemini provider is selected
- Shows green success or red error result below the buttons
- Displays the model name on success

Model: gemini-2.0-flash-preview-image-generation (correct name)

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-03-23 15:11:28 +01:00
parent 502ecba9e9
commit 3ceba38ac8
2 changed files with 70 additions and 1 deletions
+42
View File
@@ -319,6 +319,48 @@ export const settingsRouter = createTRPCRouter({
return result;
}),
testGeminiConnection: adminProcedure.mutation(async ({ ctx }) => {
const settings = await ctx.db.systemSettings.findUnique({
where: { id: "singleton" },
select: { geminiApiKey: true, geminiModel: true },
});
if (!settings?.geminiApiKey) {
return { ok: false, error: "Gemini API key is not configured." };
}
try {
const { generateGeminiImage } = await import("../gemini-client.js");
const model = settings.geminiModel ?? "gemini-2.0-flash-preview-image-generation";
// Generate a tiny test image with a simple prompt
const dataUrl = await generateGeminiImage(
settings.geminiApiKey,
"A simple blue circle on white background, minimal, 256x256",
model,
);
const hasImage = dataUrl.startsWith("data:image/");
void createAuditEntry({
db: ctx.db,
entityType: "SystemSettings",
entityId: "singleton",
entityName: "Gemini Connection Test",
action: "UPDATE",
userId: ctx.dbUser?.id,
after: { testResult: hasImage ? "success" : "failed" },
source: "ui",
summary: hasImage ? "Gemini image generation test succeeded" : "Gemini test returned no image",
});
return { ok: hasImage, model, preview: hasImage ? dataUrl.slice(0, 100) + "..." : undefined };
} catch (err) {
const { parseGeminiError } = await import("../gemini-client.js");
return { ok: false, error: parseGeminiError(err) };
}
}),
getAiConfigured: protectedProcedure.query(async ({ ctx }) => {
const settings = await ctx.db.systemSettings.findUnique({
where: { id: "singleton" },