OpenWriterControle/.opencode/tool/gemini-multiple.ts

109 lines
No EOL
3.4 KiB
TypeScript

import { tool } from "@opencode-ai/plugin"
async function parseImageInput(input: string) {
// Accepts file path ("./img.png") or data URL ("data:image/png;base64,...")
if (input.startsWith("data:")) {
const base64 = input.split(",")[1]
const mime = input.substring(5, input.indexOf(";"))
return { mime, base64 }
}
// Treat as file path
const file = Bun.file(input)
const arr = await file.arrayBuffer()
const base64 = Buffer.from(arr).toString("base64")
// Best-effort mime
const mime = file.type || "image/png"
return { mime, base64 }
}
async function callGeminiAPI(mime: string, base64: string, prompt: string) {
const apiKey = process.env.GEMINI_API_KEY
if (!apiKey) throw new Error("Set GEMINI_API_KEY in your environment")
const res = await fetch(
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-goog-api-key": apiKey,
},
body: JSON.stringify({
inputs: [{ mimeType: mime, data: base64 }],
contents: [{ parts: [{ text: prompt }]}],
}),
}
)
if (!res.ok) throw new Error(`API error: ${await res.text()}`)
const json = await res.json()
const b64 = json?.candidates?.[0]?.content?.parts?.[0]?.inlineData?.data
if (!b64) throw new Error("No image data returned")
return b64
}
export const edit = tool({
description: "Edit an image using Gemini with file path or data URL",
args: {
image: tool.schema.string().describe("File path or data URL"),
prompt: tool.schema.string().describe("Edit instruction"),
output: tool.schema.string().optional().describe("Output filename (default edited.png)"),
},
async execute(args, context) {
try {
const { mime, base64 } = await parseImageInput(args.image)
const resultBase64 = await callGeminiAPI(mime, base64, args.prompt)
const out = args.output || "edited.png"
await Bun.write(out, Buffer.from(resultBase64, "base64"))
return `Saved edited image to ${out}`
} catch (error) {
return `Error: ${error.message}`
}
},
})
export const analyze = tool({
description: "Analyze an image using Gemini without editing",
args: {
image: tool.schema.string().describe("File path or data URL"),
question: tool.schema.string().describe("What to analyze about the image"),
},
async execute(args, context) {
try {
const { mime, base64 } = await parseImageInput(args.image)
const apiKey = process.env.GEMINI_API_KEY
if (!apiKey) return "Set GEMINI_API_KEY in your environment"
const res = await fetch(
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-goog-api-key": apiKey,
},
body: JSON.stringify({
contents: [{
parts: [
{ text: args.question },
{ inlineData: { mimeType: mime, data: base64 } }
]
}],
}),
}
)
if (!res.ok) return `API error: ${await res.text()}`
const json = await res.json()
const text = json?.candidates?.[0]?.content?.parts?.[0]?.text
if (!text) return "No analysis returned"
return text
} catch (error) {
return `Error: ${error.message}`
}
},
})