import { $ } from "bun" import path from "path" import { Hono } from "hono" import { openai, createFile } from "./src/openai" import { serveStatic } from "hono/bun" import fs from "fs" const CAMERA = process.env.IAGO_CAMERA || "Set IAGO_CAMERA environment variable" const PROMPT = "What text do you see in this image?" const IMAGE_PATH = "./photo.jpg" const app = new Hono() // Serve static files from public directory app.use("/*", serveStatic({ root: "./public" })) app.get("/", (c) => { return c.json({ message: "Hello World" }) }) // you know app.get("/status", async (c) => { if (!(await checkImagesnap())) return c.json({ status: "imagesnap not found", devices: [], camera: CAMERA }) const devices = await getDevices() return c.json({ devices, camera: CAMERA, status: devices.includes(CAMERA) ? "camera found" : "camera not found" }) }) // take a picture with the camera app.get("/capture", async (c) => { try { await runImagesnap() const image = await Bun.file(IMAGE_PATH).arrayBuffer() return new Response(image, { headers: { "Content-Type": "image/jpeg" }, }) } catch (err: any) { return c.json({ error: err.message }, 500) } }) // capture and analyze image app.get("/analyze", async (c) => { try { // await runImagesnap() const fileId = await createFile(IMAGE_PATH) const result = await openai.responses.create({ model: "gpt-4o", input: [ { role: "user", content: [ { type: "input_text", text: PROMPT }, { type: "input_image", file_id: fileId, detail: "high" } ] } ] }) return c.json({ result: result.output_text }) } catch (err: any) { return c.json({ error: err.message }, 500) } }) app.get("/speak", async (c) => { const mp3 = await openai.audio.speech.create({ model: "gpt-4o-mini-tts", voice: "ash", instructions: "Speak in an upbeat and goofy tone!", input: "I put the MAN in MAN-UH!" }) const buffer = Buffer.from(await mp3.arrayBuffer()) return new Response(buffer, { headers: { "Content-Type": "audio/mpeg", "Content-Disposition": "inline; filename=speak.mp3" }, }) }) app.get("/talk", async (c) => { return c.redirect("/talk.html") }) app.post("/transcribe", async (c) => { try { const formData = await c.req.formData() const audioFile = formData.get("audio") as File if (!audioFile) { return c.json({ error: "No audio file provided" }, 400) } // Convert File to Buffer const arrayBuffer = await audioFile.arrayBuffer() const buffer = Buffer.from(arrayBuffer) // Create a temporary file const tempPath = `./temp_audio_${Date.now()}.webm` await Bun.write(tempPath, buffer) const transcription = await openai.audio.transcriptions.create({ file: Bun.file(tempPath), model: "gpt-4o-transcribe", response_format: "text", }) // Clean up temporary file await fs.promises.unlink(tempPath) console.log(transcription) return c.json({ transcription }) } catch (err: any) { console.error("Transcription error:", err) return c.json({ error: err.message }, 500) } }) // Capture image using Bun.spawn async function runImagesnap(): Promise { const proc = await $`imagesnap -d ${CAMERA} ${IMAGE_PATH}` if (proc.exitCode !== 0) throw new Error("imagesnap failed") } // Check if imagesnap exists using Bun.spawnSync async function checkImagesnap(): Promise { const result = await $`which imagesnap` return result.exitCode === 0 } // Get devices using imagesnap async function getDevices(): Promise { const result = await $`imagesnap -l` return result.stdout.toString().split("\n").filter(line => line.startsWith("=> ")).map(line => line.replace("=> ", "")) } export default { port: 3000, fetch: app.fetch, }