88 lines
3.0 KiB
TypeScript
88 lines
3.0 KiB
TypeScript
import { json } from "@sveltejs/kit";
|
|
import type { RequestHandler } from "./$types";
|
|
import { putObject } from "$lib/helpers/minio";
|
|
import { generateImage } from "$lib/helpers/stability";
|
|
import sharp from "sharp";
|
|
|
|
|
|
async function compressImage(imageName: string, imageBuffer: Buffer) {
|
|
|
|
const ja = performance.now()
|
|
const jpgBuffer = await sharp(imageBuffer)
|
|
.jpeg({ quality: 70 })
|
|
.withMetadata()
|
|
.toBuffer();
|
|
|
|
await putObject(imageName.replace(".png", ".jpg"), jpgBuffer, { "Content-Type": "image/jpeg" });
|
|
|
|
const jb = performance.now() - ja;
|
|
console.log(`[AI] JPG compression took ${jb}ms`)
|
|
|
|
const wa = performance.now()
|
|
const webpBuffer = await sharp(imageBuffer)
|
|
.webp({ quality: 70 })
|
|
.withMetadata()
|
|
.toBuffer()
|
|
|
|
await putObject(imageName.replace(".png", ".webp"), webpBuffer, { "Content-Type": "image/webp" });
|
|
const wb = performance.now() - wa;
|
|
console.log(`[AI] WebP compression took ${wb}ms`)
|
|
|
|
const aa = performance.now()
|
|
const aviBuffer = await sharp(imageBuffer)
|
|
.avif({ quality: 70 })
|
|
.withMetadata()
|
|
.toBuffer()
|
|
|
|
await putObject(imageName.replace(".png", ".avif"), aviBuffer, { "Content-Type": "image/avif" });
|
|
const ab = performance.now() - aa;
|
|
console.log(`[AI] AVIF compression took ${ab}ms`)
|
|
}
|
|
|
|
export const POST: RequestHandler = async ({ params, request }) => {
|
|
|
|
const inputName = params.name;
|
|
if (!inputName) {
|
|
throw new Error("Missing name");
|
|
}
|
|
if (inputName.length > 100) {
|
|
throw new Error("Name too long");
|
|
}
|
|
|
|
const { hairType, hairColor, hairLength, skinColor, name } = await request.json();
|
|
|
|
console.log(`[AI] Generating image for ${inputName} ${JSON.stringify({ hairType, hairColor, hairLength, skinColor, inputName })}`)
|
|
if (!hairType || !hairColor || !hairLength) {
|
|
throw new Error("Missing hairType, hairColor or hairLength");
|
|
}
|
|
|
|
const prompt = `realistic sharp portrait oil painting of a masked ${inputName}, baroque, in the style of Charles Vess, masked ball attire, opulence, mystery, elegance, ${hairLength} ${hairType} ${hairColor} hair, ${skinColor} skin`;
|
|
const negativePrompt = "blurry, multiple persons, picture frame, nsfw"
|
|
|
|
const a = performance.now()
|
|
const image = await generateImage(prompt, negativePrompt);
|
|
const d = performance.now() - a;
|
|
console.log(`[AI] Image generation took ${d}ms`)
|
|
|
|
|
|
const imageName = `${Math.random().toString(16).substring(3, 10)}-${inputName.toLowerCase().split(" ").slice(0, 5).join("-").slice(0, 25)}.png`
|
|
|
|
const imageBuffer = Buffer.from(image.base64, 'base64');
|
|
|
|
const a2 = performance.now()
|
|
const pngBuffer = await sharp(imageBuffer)
|
|
.png({ compressionLevel: 9, adaptiveFiltering: true, force: true })
|
|
.withMetadata()
|
|
.toBuffer()
|
|
|
|
await putObject(imageName, pngBuffer, { "Content-Type": "image/png" });
|
|
const d2 = performance.now() - a2;
|
|
console.log(`[AI] PNG compression took ${d2}ms`)
|
|
|
|
await compressImage(imageName, imageBuffer)
|
|
|
|
return json({
|
|
url: `https://s3-s24.max-richter.dev/silvester24/${imageName}`
|
|
})
|
|
}
|