77async function generateFunFacts(previousFacts) {
78 try {
79 // Get API key from environment
80 const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
81 if (!apiKey) {
82 console.error("Anthropic API key is not configured.");
83 return null;
84 }
85
86 // Initialize Anthropic client
87 const anthropic = new Anthropic({ apiKey });
88
89 // Format previous facts for the prompt
1export default async function (req: Request): Promise<Response> {
2 return Response.json({ ok: true })
3}
1const baseUrl = "https://api.neynar.com/v2/farcaster/";
2
3export async function fetchNeynarGet(path: string) {
7 "Content-Type": "application/json",
8 "x-neynar-experimental": "true",
9 "x-api-key": "NEYNAR_API_DOCS",
10 },
11 });
706 } catch (error) {
707 const errorDetails = { msg: error.message, name: error.name, status: error.status, type: error.type };
708 log("ERROR", "callOpenAI", `OpenAI API call failed for task ${taskId}`, { error: errorDetails }, mandateId, taskId);
709 throw new Error(`OpenAI API error: ${error.message}`);
710 }
711}
12app.get("/frontend/**/*", c => serveFile(c.req.path, import.meta.url));
13
14// Add your API routes here
15// app.get("/api/data", c => c.json({ hello: "world" }));
16
17// Unwrap and rethrow Hono errors as the original error
399 lg("DEBUG", "callOpenAI", `Initiating OpenAI call tid=${tid}`, { spLen: sysPrompt.length, upLen: userPrompt.length }, mid, tid);
400 try {
401 if (!process.env.OPENAI_API_KEY) {
402 lg("ERROR", "callOpenAI", "OpenAI API key missing.", undefined, mid, tid);
403 throw new Error("OpenAI API key not configured.");
404 }
405 const openai = new OpenAI();
419 } catch (err: any) {
420 const errDtls = { msg: err.message, name: err.name, status: err.status, type: err.type, code: err.code };
421 lg("ERROR", "callOpenAI", `OpenAI API call failed tid=${tid}`, { error: errDtls }, mid, tid);
422 throw new Error(`OpenAI API failed: ${err.message}` + (err.code ? ` (Code: ${err.code})` : ''));
423 }
424}
5date: "2025-04-26"
6url: "https://dcm31--2909c212671748f58fd383de8d4ca700.web.val.run"
7imageUrl: "https://chatgpt.com/backend-api/public_content/enc/eyJpZCI6Im1fNjgwZDE1N2JkZTQ0ODE5MThhZGE3NTNkZDI4NTI4NGQ6ZmlsZV8wMDAwMDAwMDVkZDQ2MWY2ODNjZGE4Y2Q1YzBlMDc3NSIsInRzIjoiNDg0OTEzIiwicCI6InB5aSIsInNpZyI6IjBhMGVlMjJiZGNmNDFjMTZiZThiNTNkOGMxY2Y1NWEyNTYwMDYyMjY0YzQ0MjM3Y2NlNmNkNjNjYzRiNzgyNGIiLCJ2IjoiMCIsImdpem1vX2lkIjpudWxsfQ=="
8tags: ["val-town", "showcase", "grid", "template"]
9---
97
98export async function sendDailyBriefing(chatId?: string, today?: DateTime) {
99 // Get API keys from environment
100 const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
101 const telegramToken = Deno.env.get("TELEGRAM_TOKEN");
102
106 }
107
108 if (!apiKey) {
109 console.error("Anthropic API key is not configured.");
110 return;
111 }
122
123 // Initialize Anthropic client
124 const anthropic = new Anthropic({ apiKey });
125
126 // Initialize Telegram bot
162
163 // disabled title for now, it seemes unnecessary...
164 // await bot.api.sendMessage(chatId, `*${title}*`, { parse_mode: "Markdown" });
165
166 // Then send the main content
169
170 if (content.length <= MAX_LENGTH) {
171 await bot.api.sendMessage(chatId, content, { parse_mode: "Markdown" });
172 // Store the briefing in chat history
173 await storeChatMessage(
198 // Send each chunk as a separate message and store in chat history
199 for (const chunk of chunks) {
200 await bot.api.sendMessage(chatId, chunk, { parse_mode: "Markdown" });
201 // Store each chunk in chat history
202 await storeChatMessage(
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.