166bot.on("message", async (ctx) => {
167 try {
168 const OPENAI_KEY = Deno.env.get("OPENAI_API_KEY");
169 if (!OPENAI_KEY) {
170 console.error("OPENAI_API_KEY is not configured.");
171 await ctx.reply("I apologize, but I am not properly configured at present.");
172 return;
173 }
174
175 const openai = new OpenAI({ apiKey: OPENAI_KEY });
176
177 const messageText = ctx.message.text ?? "";
263export default async function(req: Request): Promise<Response> {
264 if (!isEndpointSet) {
265 await bot.api.setWebhook(req.url, { secret_token: SECRET_TOKEN });
266 isEndpointSet = true;
267 }
66// -----------------------------------------------------------------------------
67async function generateFunFacts(previousFacts: { date: string; text: string }[]) {
68 const apiKey = Deno.env.get("OPENAI_API_KEY");
69 if (!apiKey) {
70 console.error("OPENAI_API_KEY is not configured.");
71 return [];
72 }
73
74 const openai = new OpenAI({ apiKey });
75
76 // Build auxiliary strings for the prompt
26 */
27async function generateConciseWeatherSummary(weatherDay: ReturnType<typeof summarizeWeather>[number]) {
28 const apiKey = Deno.env.get("OPENAI_API_KEY");
29 if (!apiKey) {
30 console.error("OPENAI_API_KEY is not configured.");
31 return null;
32 }
33
34 const openai = new OpenAI({ apiKey });
35
36 const systemPrompt = `You are a weather forecaster. Create a very concise summary of a day's forecast.`;
96 today?: DateTime,
97) {
98 // Get API keys from environment
99 const apiKey = Deno.env.get("OPENAI_API_KEY");
100 const telegramToken = Deno.env.get("TELEGRAM_TOKEN");
101
105 }
106
107 if (!apiKey) {
108 console.error("OPENAI_API_KEY is not configured.");
109 return;
110 }
121
122 // Initialize OpenAI client
123 const openai = new OpenAI({ apiKey });
124
125 // Initialize Telegram bot
152
153 const sendChunk = async (chunk: string) => {
154 await bot.api.sendMessage(chatId!, chunk, { parse_mode: "Markdown" });
155 await storeChatMessage(chatId!, BOT_SENDER_ID, BOT_SENDER_NAME, chunk, true);
156 };
53You'll need to set up some environment variables to make it run.
54
55- `ANTHROPIC_API_KEY` for LLM calls
56- You'll need to follow [these instructions](https://docs.val.town/integrations/telegram/) to make a telegram bot, and set `TELEGRAM_TOKEN`. You'll also need to get a `TELEGRAM_CHAT_ID` in order to have the bot remember chat contents.
57- For the Google Calendar integration you'll need `GOOGLE_CALENDAR_ACCOUNT_ID` and `GOOGLE_CALENDAR_CALENDAR_ID`. See [these instuctions](https://www.val.town/v/stevekrouse/pipedream) for details.
8## Hono
9
10This app uses [Hono](https://hono.dev/) as the API framework. You can think of Hono as a replacement for [ExpressJS](https://expressjs.com/) that works in serverless environments like Val Town or Cloudflare Workers. If you come from Python or Ruby, Hono is also a lot like [Flask](https://github.com/pallets/flask) or [Sinatra](https://github.com/sinatra/sinatra), respectively.
11
12## Serving assets to the frontend
20### `index.html`
21
22The most complicated part of this backend API is serving index.html. In this app (like most apps) we serve it at the root, ie `GET /`.
23
24We *bootstrap* `index.html` with some initial data from the server, so that it gets dynamically injected JSON data without having to make another round-trip request to the server to get that data on the frontend. This is a common pattern for client-side rendered apps.
25
26## CRUD API Routes
27
28This app has two CRUD API routes: for reading and inserting into the messages table. They both speak JSON, which is standard. They import their functions from `/backend/database/queries.ts`. These routes are called from the React app to refresh and update data.
29
30## Errors
31
32Hono and other API frameworks have a habit of swallowing up Errors. We turn off this default behavior by re-throwing errors, because we think most of the time you'll want to see the full stack trace instead of merely "Internal Server Error". You can customize how you want errors to appear.
8import { type Memory } from "../../shared/types.ts";
9
10const API_BASE = "/api/memories";
11const MEMORIES_PER_PAGE = 20;
12
71 setError(null);
72 try {
73 const response = await fetch(API_BASE);
74 if (!response.ok) {
75 throw new Error(`HTTP error! status: ${response.status}`);
100
101 try {
102 const response = await fetch(API_BASE, {
103 method: "POST",
104 headers: { "Content-Type": "application/json" },
123
124 try {
125 const response = await fetch(`${API_BASE}/${id}`, {
126 method: "DELETE",
127 });
155
156 try {
157 const response = await fetch(`${API_BASE}/${editingMemory.id}`, {
158 method: "PUT",
159 headers: { "Content-Type": "application/json" },
18});
19
20// --- API Routes for Memories ---
21
22// GET /api/memories - Retrieve all memories
23app.get("/api/memories", async (c) => {
24 const memories = await getAllMemories();
25 return c.json(memories);
26});
27
28// POST /api/memories - Create a new memory
29app.post("/api/memories", async (c) => {
30 const body = await c.req.json<Omit<Memory, "id">>();
31 if (!body.text) {
36});
37
38// PUT /api/memories/:id - Update an existing memory
39app.put("/api/memories/:id", async (c) => {
40 const id = c.req.param("id");
41 const body = await c.req.json<Partial<Omit<Memory, "id">>>();
58});
59
60// DELETE /api/memories/:id - Delete a memory
61app.delete("/api/memories/:id", async (c) => {
62 const id = c.req.param("id");
63 try {
75// --- Blob Image Serving Routes ---
76
77// GET /api/images/:filename - Serve images from blob storage
78app.get("/api/images/:filename", async (c) => {
79 const filename = c.req.param("filename");
80
12 type="image/svg+xml"
13 />
14 <link rel="preconnect" href="https://fonts.googleapis.com" />
15 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
16 <link
17 href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap"
18 rel="stylesheet"
19 />
85 console.log(e.text);
86
87 // Get Anthropic API key from environment
88 const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
89 if (!apiKey) {
90 console.error("Anthropic API key is not configured for this val.");
91 return;
92 }
93
94 // Initialize Anthropic client
95 const anthropic = new Anthropic({ apiKey });
96
97 // Process each image attachment serially