feat: add recover ai route
This commit is contained in:
parent
a8cf13157b
commit
84987129e6
16
pb_migrations/1700739396_updated_invites.js
Normal file
16
pb_migrations/1700739396_updated_invites.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/// <reference path="../pb_data/types.d.ts" />
|
||||||
|
migrate((db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("zfbbb4gbdk9dh6k")
|
||||||
|
|
||||||
|
collection.viewRule = ""
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
}, (db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("zfbbb4gbdk9dh6k")
|
||||||
|
|
||||||
|
collection.viewRule = null
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
})
|
16
pb_migrations/1700739818_updated_invites.js
Normal file
16
pb_migrations/1700739818_updated_invites.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/// <reference path="../pb_data/types.d.ts" />
|
||||||
|
migrate((db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("zfbbb4gbdk9dh6k")
|
||||||
|
|
||||||
|
collection.updateRule = ""
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
}, (db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("zfbbb4gbdk9dh6k")
|
||||||
|
|
||||||
|
collection.updateRule = null
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
})
|
31
pb_migrations/1700739877_updated_invites.js
Normal file
31
pb_migrations/1700739877_updated_invites.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/// <reference path="../pb_data/types.d.ts" />
|
||||||
|
migrate((db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("zfbbb4gbdk9dh6k")
|
||||||
|
|
||||||
|
// add
|
||||||
|
collection.schema.addField(new SchemaField({
|
||||||
|
"system": false,
|
||||||
|
"id": "6j9gxbgv",
|
||||||
|
"name": "skin_color",
|
||||||
|
"type": "text",
|
||||||
|
"required": false,
|
||||||
|
"presentable": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"pattern": ""
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
}, (db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("zfbbb4gbdk9dh6k")
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.schema.removeField("6j9gxbgv")
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
})
|
@ -9,6 +9,16 @@ export async function getPublicPortraits() {
|
|||||||
})).items
|
})).items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getInvite(id: string) {
|
||||||
|
return pb.collection("invites").getOne(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setInvitePortrait(id: string, url: string) {
|
||||||
|
return pb.collection("invites").update(id, {
|
||||||
|
portrait: url
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function createPerson({ name, confidence, portrait, portrait_public, noble_name, hair_color, hair_type, hair_length, skin_color }: { name: string, portrait: string, portrait_public: boolean, hair_type: string, hair_length: string, hair_color: string, confidence: number, noble_name: string, skin_color: string }) {
|
export function createPerson({ name, confidence, portrait, portrait_public, noble_name, hair_color, hair_type, hair_length, skin_color }: { name: string, portrait: string, portrait_public: boolean, hair_type: string, hair_length: string, hair_color: string, confidence: number, noble_name: string, skin_color: string }) {
|
||||||
return pb.collection("invites").create({
|
return pb.collection("invites").create({
|
||||||
name,
|
name,
|
||||||
|
@ -57,7 +57,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 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"
|
const negativePrompt = "blurry, multiple persons, picture frame, nsfw"
|
||||||
|
|
||||||
const a = performance.now()
|
const a = performance.now()
|
||||||
const image = await generateImage(prompt, negativePrompt);
|
const image = await generateImage(prompt, negativePrompt);
|
||||||
|
91
src/routes/api/ai/recover/[id]/+server.ts
Normal file
91
src/routes/api/ai/recover/[id]/+server.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
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";
|
||||||
|
import * as pb from "$lib/helpers/pb"
|
||||||
|
|
||||||
|
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 GET: RequestHandler = async ({ params }) => {
|
||||||
|
|
||||||
|
const inputId = params.id;
|
||||||
|
if (!inputId) {
|
||||||
|
throw new Error("Missing name");
|
||||||
|
}
|
||||||
|
|
||||||
|
const invite = await pb.getInvite(inputId);
|
||||||
|
if (!invite) {
|
||||||
|
throw new Error("Invite not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { hair_color, hair_type, hair_length, noble_name, skin_color, name } = invite;
|
||||||
|
|
||||||
|
console.log(`[AI] Generating image for ${name} ${JSON.stringify({ hair_type, hair_color, hair_length, skin_color, name })}`)
|
||||||
|
if (!hair_type || !hair_color || !hair_length || !noble_name || !skin_color) {
|
||||||
|
throw new Error("Missing hairType, hairColor or hairLength");
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = `realistic sharp portrait oil painting of a masked ${noble_name}, baroque, in the style of Charles Vess, masked ball attire, opulence, mystery, elegance, ${hair_length} ${hair_type} ${hair_color} hair, ${skin_color} 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)}-${noble_name.toLowerCase().split(" ").slice(0, 5).join("-").slice(0, 25).split("-").filter(l => l.length).join("-")}.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)
|
||||||
|
|
||||||
|
await pb.setInvitePortrait(inputId, `https://s3.max-richter.dev/silvester23/${imageName}`);
|
||||||
|
|
||||||
|
return json({
|
||||||
|
url: `https://s3.max-richter.dev/silvester23/${imageName}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user