design-evals / lib /task-reference-image.ts
alejandro
feat: send image-to-code reference image as multimodal base64
c6129e3
import { promises as fs } from "node:fs";
import path from "node:path";
import type { GenerationReferenceImage } from "@/lib/generation-types";
import {
getImageToCodeReference,
type TaskContext,
type TaskContextById,
type TaskId,
} from "@/lib/tasks";
const MIME_BY_EXTENSION: Record<string, string> = {
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".webp": "image/webp",
".gif": "image/gif",
".svg": "image/svg+xml",
};
function normalizePublicAssetPath(assetPath: string): string | null {
const stripped = assetPath.startsWith("/") ? assetPath.slice(1) : assetPath;
const normalized = path.posix.normalize(stripped);
if (!normalized || normalized === "." || normalized.startsWith("../")) {
return null;
}
return normalized;
}
function resolveImageMimeType(assetPath: string): string | null {
const extension = path.extname(assetPath).toLowerCase();
return MIME_BY_EXTENSION[extension] ?? null;
}
async function readAssetFromPublic(relativeAssetPath: string): Promise<Buffer> {
const candidateRoots = [
path.resolve(process.env.PROJECT_ROOT ?? process.cwd()),
path.resolve(process.cwd()),
];
const uniqueRoots = [...new Set(candidateRoots)];
const segments = relativeAssetPath.split("/").filter(Boolean);
for (const root of uniqueRoots) {
const absoluteAssetPath = path.join(root, "public", ...segments);
try {
return await fs.readFile(absoluteAssetPath);
} catch (error) {
const code = (error as NodeJS.ErrnoException).code;
if (code === "ENOENT") {
continue;
}
throw error;
}
}
throw new Error(`Reference image asset was not found: ${relativeAssetPath}`);
}
export async function buildTaskReferenceImage(
taskId: TaskId,
taskContext: TaskContext,
): Promise<GenerationReferenceImage | null> {
if (taskId !== "image_to_code") {
return null;
}
const imageContext = taskContext as TaskContextById["image_to_code"];
const reference = getImageToCodeReference(imageContext.imageId);
const relativeAssetPath = normalizePublicAssetPath(reference.assetPath);
if (!relativeAssetPath) {
return null;
}
const mimeType = resolveImageMimeType(reference.assetPath);
if (!mimeType) {
return null;
}
const bytes = await readAssetFromPublic(relativeAssetPath);
return {
mimeType,
base64Data: bytes.toString("base64"),
};
}