3We hosted a party in the Val Town office and I texted a link to this site to all guests:
4
5
6
7You can see a demo here: https://x.com/stevekrouse/status/1819018859099132128
1# ☔️ Umbrella reminder if there's rain today
2
3
4
5## Setup
2
3
4
5
6Inspired from a RedwoodJS demo I mde last year, this adds generative art powered by Fal to the bedtime story maker.
21for a "fantastical story about a green whale who rides the bus" or the "spooky story about the tomato fox who explores a cave".
22
23Then using the summary, OpenAI geenrates another prompt to describe the instructions to geneate a childrens story book image.
24
25That's sent to Fal to generate an image.
26
27Stories get saved to `bedtime_stories` in SQLite for viewing, searching and maybe sharing.
7
8const TMDB_API_BASE = "https://api.themoviedb.org/3"
9const TMDB_IMAGE_BASE = "https://image.tmdb.org/t/p/w200"
10
11const headers = {
65 movies.map((movie, index) => `
66 <div class="movie-container">
67 <img src="${TMDB_IMAGE_BASE}${movie.poster_path}" alt="${movie.title}" style="width: 100px;">
68 <div class="movie-info">
69 <h3>${movie.title}</h3>
130 return `
131 <div class="movie-result ${resultClass}">
132 <img src="${TMDB_IMAGE_BASE}${movie.poster_path}" alt="${movie.title}" style="width: 100px;">
133 <div class="movie-info">
134 <h3>${movie.title}</h3>
2 title: string;
3 description: string;
4 image: string;
5 url: string;
6 type?: string;
8
9export function generateOpenGraphTags(data: OpenGraphData): string {
10 const { title, description, image, url, type = "website" } = data;
11
12 return `
13 <meta property="og:title" content="${escapeHtml(title)}" />
14 <meta property="og:description" content="${escapeHtml(description)}" />
15 <meta property="og:image" content="${escapeHtml(image)}" />
16 <meta property="og:type" content="${escapeHtml(type)}" />
17 <meta property="og:url" content="${escapeHtml(url)}" />
34// description:
35// "In a 24-hour detention, five misfit teens join forces to sneak a runaway truckload of breakfast burritos past a relentless sheriff who has them in his sights. As they navigate their differences and forge unlikely friendships, they discover that freedom comes in many forms—especially when there's a thirst for adventure and a belly full of burritos. Get ready for a wild ride, because together, they're breaking out… with breakfast!",
36// image: "https://fal.media/files/zebra/6tOPoTCgnrC83g6MK9Wbo.jpeg",
37// url: "[Your URL here]",
38// };
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.
4
5
6
7## Install
4
5<img width="300px"
6 src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/3618d5f1-fe2c-4b44-bdef-3c679f390700/public"/>
7
8
1import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
2import { ComputeJSON, ComputeText, GenerateImage, sb, StableVideoDiffusion, Substrate } from "npm:substrate";
3import { z } from "npm:zod";
4import { zodToJsonSchema } from "npm:zod-to-json-schema";
13const sentencesSchema = z.object({
14 sentences: z.array(z.string()).length(5).describe("5 short sentences condensing the story"),
15 imageDescriptions: z
16 .array(z.string())
17 .length(5)
18 .describe(
19 "5 descriptions of images to accompany each sentence. Describe simple images that depict the setting of each scene. Do not include characters, just the background. Return just the description, no prefix or explanation.",
20 ),
21});
22const sentences = new ComputeJSON({
23 prompt: sb
24 .interpolate`We're making a storyboard. Generate 5 short sentences condensing the story about ${topic}, along with descriptions of images to accompany each sentence.`,
25 json_schema: zodToJsonSchema(sentencesSchema),
26});
28let videoNodes = [];
29for (let i = 0; i < 5; i++) {
30 const image = new GenerateImage({
31 prompt: sentences.future.json_object.get("imageDescriptions").at(i),
32 store: "hosted",
33 });
34 image.cache_age = 60 * 60 * 24 * 7;
35 const video = new StableVideoDiffusion({
36 image_uri: image.future.image_uri,
37 store: "hosted",
38 motion_bucket_id: 20,
80 "The roar of the falls subsides as the traveler rounds a bend in the path.",
81 ],
82 "imageDescriptions": [
83 "A dense jungle with towering trees and vines",
84 "A misty forest with ferns and moss-covered tree trunks",
7* Type text prompts, select it, press "Q". Select a previous generation with a new text prompt to keep iterating. Selecting shapes doesn't work yet. Have fun!
8
9<a href="https://x.com/JanPaul123/status/1815502582015754657"><img width=500 src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/5893dfbf-c2de-4be0-049e-d8fdd1970a00/public"/></a>
10
7* Type text prompts, select it, press "Q". Select a previous generation with a new text prompt to keep iterating. Selecting shapes doesn't work yet. Have fun!
8
9<a href="https://x.com/JanPaul123/status/1815502582015754657"><img width=500 src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/5893dfbf-c2de-4be0-049e-d8fdd1970a00/public"/></a>
10