import { put } from "@vercel/blob"; import { db } from "../src/db"; import { Effect, Schedule } from "effect"; import { products as products_table, categories as categories_table, subcategories as subcategories_table, } from "../src/db/schema"; import { eq } from "drizzle-orm"; const generateImage = (prompt: string) => Effect.gen(function* () { const res = yield* Effect.tryPromise(() => fetch("https://api.getimg.ai/v1/stable-diffusion/text-to-image", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.GETIMG_API_KEY}`, }, body: JSON.stringify({ prompt, negative_prompt: "blurry", width: 512, height: 512, response_format: "url", }), }), ); const json = yield* Effect.tryPromise(() => res.json()); console.log(json); return json; }); const uploadImage = (imageUrl: string, path: string) => Effect.gen(function* () { const res = yield* Effect.tryPromise(() => fetch(imageUrl)); const blob = yield* Effect.tryPromise(() => res.blob()); return yield* Effect.tryPromise(() => put(path, blob, { access: "public" }), ); }); const main = Effect.gen(function* () { const products = yield* Effect.tryPromise(() => db.query.products.findMany({ where: (products, { isNull }) => isNull(products.image_url), }), ); console.log(`found ${products.length} products`); yield* Effect.all( products.map((product) => Effect.gen(function* () { console.log(`generating image for ${product.name}`); const imageRes = yield* generateImage(` Generate a product photo for this product: Product Name: ${product.name} Product Description: ${product.description}`); const imageUrl = imageRes.url; if (!imageUrl) { return yield* Effect.fail("no image"); } console.log(`uploading image for ${product.name} - ${imageUrl}`); const { url } = yield* uploadImage( imageUrl, `products/${product.slug}`, ); console.log(`uploaded image for ${product.name}`); yield* Effect.tryPromise(() => db .update(products_table) .set({ image_url: url }) .where(eq(products_table.slug, product.slug)), ); }), ), { concurrency: 10 }, ); const categories = yield* Effect.tryPromise(() => db.query.categories.findMany({ where: (categories, { isNull }) => isNull(categories.image_url), }), ); console.log(`found ${categories.length} categories`); yield* Effect.all( categories.map((category) => Effect.gen(function* () { console.log(`generating image for ${category.name}`); const imageRes = yield* generateImage(` Generate a product photo for this product category: Category Name: ${category.name}`); const imageUrl = imageRes.url; if (!imageUrl) { return yield* Effect.fail("no image"); } console.log(`uploading image for ${category.name} - ${imageUrl}`); const { url } = yield* uploadImage( imageUrl, `categories/${category.slug}`, ); console.log(`uploaded image for ${category.name}`); yield* Effect.tryPromise(() => db .update(categories_table) .set({ image_url: url }) .where(eq(categories_table.slug, category.slug)), ); }), ), { concurrency: 10 }, ); const subcategories = yield* Effect.tryPromise(() => db.query.subcategories.findMany({ where: (subcategories, { isNull }) => isNull(subcategories.image_url), }), ); console.log(`found ${subcategories.length} subcategories`); yield* Effect.all( subcategories.map((category) => Effect.gen(function* () { console.log(`generating image for ${category.name}`); const imageRes = yield* generateImage(` Generate a product photo for this product category: Category Name: ${category.name}`); const imageUrl = imageRes.url; if (!imageUrl) { return yield* Effect.fail("no image"); } console.log(`uploading image for ${category.name} - ${imageUrl}`); const { url } = yield* uploadImage( imageUrl, `subcategories/${category.slug}`, ); console.log(`uploaded image for ${category.name}`); yield* Effect.tryPromise(() => db .update(subcategories_table) .set({ image_url: url }) .where(eq(subcategories_table.slug, category.slug)), ); }), ), { concurrency: 10 }, ); }); const exit = await Effect.runPromiseExit( main.pipe(Effect.retry({ schedule: Schedule.spaced("10 seconds") })), ); console.log(exit.toString());