///
import {
Cell,
generateObject,
handler,
ifElse,
lift,
NAME,
recipe,
str,
toSchema,
UI,
} from "commontools";
interface InputState {
number: Cell;
}
interface NumberStory {
number: number;
story: string;
title: string;
storyOrigin: string;
seeAlso: number[];
imagePrompt: string;
}
interface SetNumberEvent {
number: Cell;
n: number;
}
// Handler to increment the number
const adder = handler((_, state) => {
state.number.set(state.number.get() + 1);
});
// Handler to set a specific number
const setNumber = handler((_, state: { number: Cell; n: number }) => {
state.number.set(state.n);
});
// Generate the prompt for the LLM
const generatePrompt = lift(({ number }: { number: number }) => {
return {
prompt:
`You are the parent of a young child who loves to learn about numbers. Luckily for your child, you are a historian of numbers and when the child says a number you make up an interesting story about it, including the history of the number. The child is currently at ${number}. Also return a recommendation for other numbers that might be interesting to the child to learn about next.`,
schema: outputSchema,
};
});
// Generate an image URL from the prompt
const generateImageUrl = lift(({ imagePrompt }: { imagePrompt: string }) => {
return `/api/ai/img?prompt=${encodeURIComponent(imagePrompt)}`;
});
const inputSchema = toSchema({
default: { number: 0 },
});
const outputSchema = toSchema();
export default recipe(inputSchema, outputSchema, (cell) => {
// Use generateObject to get structured data from the LLM
const { result: object, pending } = generateObject(
generatePrompt({ number: cell.number }),
);
const imageUrl = generateImageUrl({
imagePrompt: object?.imagePrompt || "robot thinking",
});
return {
[NAME]: str`Number Story: ${object?.title || "Loading..."}`,
[UI]: (
Current number: {cell.number} (click to increment)
{ifElse(
pending,