1import urlHeader from "https://esm.town/v/substrate/urlHeader";
2import { ComputeText, GenerateImage, sb, Substrate, UpscaleImage } from "npm:substrate";
34const substrate = new Substrate({ apiKey: Deno.env.get("SUBSTRATE_API_KEY") });
7const url = new URL(req.url);
8const searchParams = url.searchParams;
9const simImage = searchParams.get("image");
10if (simImage) {
11const prompt = new ComputeText({
12prompt: sb
13.interpolate`Describe an image named ${simImage}. Describe a single subject with background and style details.
14We'll use this description to generate an image so include creative details like style, vibe, mood, character.`,
15temperature: 0.8,
16});
17prompt.cache_age = 60 * 60;
18const image = new GenerateImage({
19prompt: prompt.future.text,
20});
21image.cache_age = 60 * 60 * 24;
22const res = await substrate.run(image);
23const imageUri = res.get(image).image_uri;
24const base64Data = imageUri.split(",")[1];
25const imageData = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));
26return new Response(imageData, {
27headers: {
28"Content-Type": "image/jpeg",
29},
30});
39}
4041const instructions = `all images should be in the form /?image=<image description including art style>.
42always use descriptive image names including the particular style (e.g. photograph, illustration).
43include plenty of local urls to other pages on the same domain.
44all urls must be in this format: /?url=<full url with a domain, descriptive path, and params>.
sqlite_adminREADME.md1 match
3This is a lightweight SQLite Admin interface to view and debug your SQLite data.
45
67It's currently super limited (no pagination, editing data, data-type specific viewers), and is just a couple dozens lines of code over a couple different vals. Forks encouraged! Just comment on the val if you add any features that you want to share.
sqliteExplorerAppREADME.md1 match
3View and interact with your Val Town SQLite data. It's based off Steve's excellent [SQLite Admin](https://www.val.town/v/stevekrouse/sqlite_admin?v=46) val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by [LibSQL Studio](https://github.com/invisal/libsql-studio) by [invisal](https://github.com/invisal). This is now more an SPA, with tables, queries and results showing up on the same page.
45
67## Install
45<div align="center">
6<img src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/67a1d35e-c37c-41a4-0e5a-03a9ba585d00/public" width="700px"/>
7</div>
1011<div align="center">
12<img src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/67a1d35e-c37c-41a4-0e5a-03a9ba585d00/public" width="500px"/>
13</div>
generateQRmain.tsx2 matches
13);
14}
15const base64Image = await qrcode(url.toString(), { type: "text/html" });
16return new Response(
17`<html>
20</head>
21<body>
22<img src=${base64Image} style="margin: 0 auto; max-width: 600px" width="100%" />
23<p style="font-size: 0.85rem">QR Code generated using <a href="https://val.town">val.town</a></p>
24<p style="font-size: 0.85rem">Built with 💗 by <a href="https://twitter.com/neverstew">Neverstew</a></p>
getValsContextWindowmain.tsx1 match
338---
339
340Val Town comes with blob storage built-in. It allows for storing any data: text, JSON, images. You can access it via [\`std/blob\`](https://www.val.town/v/std/blob).
341
342Blob storage is scoped globally to your account. If you set a blob in one val, you can retrieve it by the same key in another val. It's backed by Cloudflare R2.
1import promptHeader from "https://esm.town/v/substrate/promptHeader";
2import wrapper from "https://esm.town/v/substrate/substrateBadgeMiddleware";
3import { ComputeJSON, ComputeText, GenerateImage, sb, Substrate } from "npm:substrate";
45async function handler(req: Request): Promise<Response> {
substrateBadgemain.tsx1 match
45return new Response(badge, {
46headers: {
47"Content-Type": "image/svg+xml",
48},
49});
IllustratedPrimermain.tsx22 matches
1import wrapper from "https://esm.town/v/substrate/substrateBadgeMiddleware";
2import { ComputeJSON, ComputeText, GenerateImage, sb, Substrate } from "npm:substrate";
3import { z } from "npm:zod";
4import { zodToJsonSchema } from "npm:zod-to-json-schema";
23});
24const prompt1 = new ComputeText({
25prompt: sb.interpolate`generate a description of an image of ${
26c1.future.json_object.get("concepts").at(0)
27}. Be concise and terse. Include details on the background, angle & framing, and style.`,
28});
29const prompt2 = new ComputeText({
30prompt: sb.interpolate`generate a description of an image of ${
31c1.future.json_object.get("concepts").at(1)
32}. Be concise and terse. Include details on the background, angle & framing, and style.`,
43${caption1.future.text}`,
44}, { cache_age: 800 });
45const image1 = new GenerateImage({ prompt: prompt1.future.text });
46const image2 = new GenerateImage({ prompt: prompt2.future.text });
47const c2 = new ComputeJSON({
48prompt: sb.interpolate`List deeper concepts or ideas related to: ${c1.future.json_object.get("concepts").at(0)}
53});
54const prompt3 = new ComputeText({
55prompt: sb.interpolate`generate a description of an image of ${
56c2.future.json_object.get("concepts").at(0)
57}. Be creative depicting abstract topics with extra detail. Include details on the background, angle & framing, and style.`,
58});
59const prompt4 = new ComputeText({
60prompt: sb.interpolate`generate a description of an image of ${
61c2.future.json_object.get("concepts").at(1)
62}. Be creative depicting abstract topics with extra detail. Include details on the background, angle & framing, and style.`,
77${caption3.future.text}`,
78});
79const image3 = new GenerateImage({ prompt: prompt3.future.text });
80const image4 = new GenerateImage({ prompt: prompt4.future.text });
81const nodes = [image1, caption1, image2, caption2, image3, caption3, image4, caption4];
82const stream = await substrate.stream(...nodes);
8388async start(controller) {
89const pairs = [
90{ image: null, caption: null, title: null },
91{ image: null, caption: null, title: null },
92{ image: null, caption: null, title: null },
93{ image: null, caption: null, title: null },
94];
9596const outputPair = (pair, index) => {
97if (pair.image && pair.caption) {
98controller.enqueue(new TextEncoder().encode(
99`<div style="display:flex;justify-content:center;align-items:center;margin-bottom:20px;">
100<div style="margin:0 10px;">${pair.image}</div>
101<div style="margin:0 10px;font-size:1.2rem;">
102<a href="/?subject=${pair.title}"><b>${capitalize(pair.title)}</b></a><br/>${pair.caption}</div>
103</div>`,
104));
105pairs[index] = { image: null, caption: null, title: null }; // Reset after output
106}
107};
152if (index !== -1) {
153const pairIndex = Math.floor(index / 2);
154const isImage = index % 2 === 0;
155const content = event.data.image_uri
156? `<img src="${event.data.image_uri}" width=400/>`
157: `<div>${event.data.text}</div>`;
158159if (isImage) {
160pairs[pairIndex].image = content;
161} else {
162pairs[pairIndex].caption = content;