import wrapper from "https://esm.town/v/substrate/substrateBadgeMiddleware";
import { ComputeJSON, ComputeText, GenerateImage, sb, Substrate } from "npm:substrate";
import { z } from "npm:zod";
import { zodToJsonSchema } from "npm:zod-to-json-schema";
async function handler(req: Request): Promise<Response> {
const searchParams = new URL(req.url).searchParams;
const { prompt = "modernism" } = Object.fromEntries(searchParams);
const substrate = new Substrate({ apiKey: Deno.env.get("SUBSTRATE_API_KEY") });
const Topic = z
.object({
concepts: z.array(z.string()).min(2).max(2).describe(
"List of deeper concepts or ideas. Keep them short, less than 5 words.",
),
})
.describe("Deeper concepts or ideas related to a topic.");
const c1 = new ComputeJSON({
prompt: `List deeper concepts or ideas related to: ${prompt}`,
json_schema: zodToJsonSchema(Topic),
});
const prompt1 = new ComputeText({
prompt: sb.interpolate`generate a description of an image of ${
c1.future.json_object.get("concepts").at(0)
}. Be concise and terse. Include details on the background, angle & framing, and style.`,
});
const prompt2 = new ComputeText({
prompt: sb.interpolate`generate a description of an image of ${
c1.future.json_object.get("concepts").at(1)
}. Be concise and terse. Include details on the background, angle & framing, and style.`,
});
const caption1 = new ComputeText({
prompt: sb.interpolate`write a short paragraph relating ${
c1.future.json_object.get("concepts").at(0)
} to ${prompt}`,
});
const caption2 = new ComputeText({
prompt: sb.interpolate`write a short paragraph relating ${
c1.future.json_object.get("concepts").at(1)
} to ${prompt}. It should be meaningfully different from the following content:
${caption1.future.text}`,
}, { cache_age: 800 });
const image1 = new GenerateImage({ prompt: prompt1.future.text });
const image2 = new GenerateImage({ prompt: prompt2.future.text });
const c2 = new ComputeJSON({
prompt: sb.interpolate`List deeper concepts or ideas related to: ${c1.future.json_object.get("concepts").at(0)}
The items must NOT be in this list:[${c1.future.json_object.get("concepts").at(0)}, ${
c1.future.json_object.get("concepts").at(1)
}]`,
json_schema: zodToJsonSchema(Topic),
});
const prompt3 = new ComputeText({
prompt: sb.interpolate`generate a description of an image of ${
c2.future.json_object.get("concepts").at(0)
}. Be creative depicting abstract topics with extra detail. Include details on the background, angle & framing, and style.`,
});
const prompt4 = new ComputeText({
prompt: sb.interpolate`generate a description of an image of ${
c2.future.json_object.get("concepts").at(1)
}. Be creative depicting abstract topics with extra detail. Include details on the background, angle & framing, and style.`,
});
const caption3 = new ComputeText({
prompt: sb.interpolate`write a short paragraph relating ${
c2.future.json_object.get("concepts").at(0)
} to ${prompt}. It should be meaningfully different from the following content:
${caption1.future.text}
${caption2.future.text}`,
});
const caption4 = new ComputeText({
prompt: sb.interpolate`write a short paragraph relating ${
c2.future.json_object.get("concepts").at(1)
} to ${prompt}. It should be meaninfully different from the following content:
${caption1.future.text}
${caption2.future.text}
${caption3.future.text}`,
});
const image3 = new GenerateImage({ prompt: prompt3.future.text });
const image4 = new GenerateImage({ prompt: prompt4.future.text });
const nodes = [image1, caption1, image2, caption2, image3, caption3, image4, caption4];
const stream = await substrate.stream(...nodes);
const capitalize = s => s.replace(/^\w/, c => c.toUpperCase());
return new Response(
new ReadableStream({
async start(controller) {
const pairs = [
{ image: null, caption: null, title: null },
{ image: null, caption: null, title: null },
{ image: null, caption: null, title: null },
{ image: null, caption: null, title: null },
];
const outputPair = (pair, index) => {
if (pair.image && pair.caption) {
controller.enqueue(new TextEncoder().encode(
`<div style="display:flex;justify-content:center;align-items:center;margin-bottom:20px;">
<div style="margin:0 10px;">${pair.image}</div>