1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource npm:hono@3/jsx */
import { unkey, type UnkeyContext } from "npm:@unkey/hono";
import { Hono } from "npm:hono";
import {
createBedtimeStory,
getBedtimeStoryById,
getRecentBedtimeStories,
} from "https://esm.town/v/dthyresson/bedtimeStoriesDb";
import type { BedtimeStory } from "https://esm.town/v/dthyresson/bedtimeStoriesDb";
import { getSortedActivities } from "https://esm.town/v/dthyresson/bedtimeStoryActivities";
import { getSortedAdjectives } from "https://esm.town/v/dthyresson/bedtimeStoryAdjectives";
import { getSortedAnimals } from "https://esm.town/v/dthyresson/bedtimeStoryAnimals";
import { getSortedColors } from "https://esm.town/v/dthyresson/bedtimeStoryColors";
import { generateOpenGraphTags, OpenGraphData } from "https://esm.town/v/dthyresson/generateOpenGraphTags";
import { ValTownLink } from "https://esm.town/v/dthyresson/viewOnValTownComponent";
import { chat } from "https://esm.town/v/stevekrouse/openai";
import * as fal from "npm:@fal-ai/serverless-client";
export const falConfig = () => {
fal.config({
// Can also be auto-configured using environment variables:
credentials: Deno.env.get("FAL_KEY"),
});
return fal;
};
const app = new Hono<{ Variables: { unkey: UnkeyContext } }>();
// app.use(
// "*",
// unkey({
// apiId: "rlns_2AMjVgwwMksmssLVb56LVmkpB56C",
// }),
// );
function parseStory(text) {
// Split the text into lines and remove empty lines
const lines = text.split("\n").filter(line => line.trim() !== "");
// Extract the title (first line), remove quotes, markdown and trim
const title = lines[0]
.replace(/^"|"$/g, "")
.replace(/\*\*|\*/g, "")
.replace(/\#\#|\#/g, "")
.trim();
// Extract the summary (second line) and trim
const summary = lines[1]
.replace(/^"|"$/g, "")
.replace(/\*\*|\*/g, "")
.replace(/\#\#|\#/g, "")
.trim();
// Join the rest of the lines as the story, replace '\n' with actual newlines
const story = lines.slice(2).join("\n").replace(/\\n/g, "\n").trim();
// Return the JSON object
return {
title,
summary,
story,
};
}
export const generateBedtimeStory = async (options: BedtimeStory | null): BedtimeStory => {
const { adjective = "funny", color = "pink", animal = "penguin", activity = "flies a kite" } = options;
const { content } = await chat(
[
{
role: "system",
content: `Write a ${adjective} bedtime story about a ${color} colored ${animal} that ${activity}.
The story should have a title, be suitable for young children, give the animal a friendly name and be no longer than 300 words.
Return the title on the first line, on the second line a one sentence summary of this story, and then the story.
If the story mentions other animals, include them in the summary.
`,
},
],
{ max_tokens: 1_000, model: "gpt-4o-mini" },
);
console.log(content);
const parsedContent = parseStory(content);
const story = { ...options, ...parsedContent };
const pictureUrl = await generateBedtimeStoryPictureUrl(story);
return { ...story, pictureUrl };
};
export const generateBedtimeStoryPictureUrl = async (bedtimeStory) => {
const fal = falConfig();
const { adjective, animal, color, summary } = bedtimeStory;