20// -------------------- SQLITE HELPERS -------------------- //
2122export async function storeChatMessage(
23chatId: number | string,
24senderId: string,
49}
5051export async function getChatHistory(chatId: number | string, limit = 50) {
52try {
53const { sqlite } = await import("https://esm.town/v/stevekrouse/sqlite");
63}
6465function formatChatHistoryForAI(history: any[]) {
66const messages = [] as { role: "user" | "assistant"; content: string }[];
67for (const msg of history) {
77// -------------------- LLM ANALYSIS -------------------- //
7879async function analyzeMessageContent(
80openai: OpenAI,
81username: string,
261// -------------------- WEBHOOK HANDLER -------------------- //
262263export default async function(req: Request): Promise<Response> {
264if (!isEndpointSet) {
265await bot.api.setWebhook(req.url, { secret_token: SECRET_TOKEN });
stevens-openaigenerateFunFacts.ts7 matches
10// Helper: fetch previous fun facts so we avoid duplicates
11// -----------------------------------------------------------------------------
12async function getPreviousFunFacts() {
13try {
14const result = await sqlite.execute(
30// Helper: delete and insert DB rows
31// -----------------------------------------------------------------------------
32async function deleteExistingFunFacts(dates: string[]) {
33try {
34for (const date of dates) {
43}
4445async function insertFunFact(date: string, factText: string) {
46try {
47await sqlite.execute(
65// LLM: generate seven new fun‑facts (OpenAI)
66// -----------------------------------------------------------------------------
67async function generateFunFacts(previousFacts: { date: string; text: string }[]) {
68const apiKey = Deno.env.get("OPENAI_API_KEY");
69if (!apiKey) {
153// Fallback regex parser (unchanged except for generic references)
154// -----------------------------------------------------------------------------
155function parseFallbackFacts(responseText: string, expectedDates: string[]) {
156const factPattern = /(\d{4}-\d{2}-\d{2})["']?[,:]?\s*["']?(.*?)["']?[,}]/gs;
157const facts: { date: string; text: string }[] = [];
179// Pipeline: generate & store fun facts weekly
180// -----------------------------------------------------------------------------
181export async function generateAndStoreFunFacts() {
182const previousFacts = await getPreviousFunFacts();
183const newFacts = await generateFunFacts(previousFacts);
205// Default export: cron entry point (weekly)
206// -----------------------------------------------------------------------------
207export default async function () {
208console.log("Running fun facts generation cron job…");
209return await generateAndStoreFunFacts();
stevens-openaigetWeather.ts5 matches
5const TABLE_NAME = `memories`;
67function summarizeWeather(weather: WeatherResponse) {
8const summarizeDay = (day: WeatherResponse["weather"][number]) => ({
9date: day.date,
25* into a <25‑word sentence.
26*/
27async function generateConciseWeatherSummary(weatherDay: ReturnType<typeof summarizeWeather>[number]) {
28const apiKey = Deno.env.get("OPENAI_API_KEY");
29if (!apiKey) {
63}
6465async function deleteExistingForecast(date: string) {
66await sqlite.execute(
67`DELETE FROM ${TABLE_NAME} WHERE date = ? AND text LIKE 'weather forecast:%'`,
70}
7172async function insertForecast(date: string, forecast: string) {
73const { nanoid } = await import("https://esm.sh/nanoid@5.0.5");
74await sqlite.execute(
89* Main entry. Fetches the forecast, generates concise summaries, and stores them.
90*/
91export default async function getWeatherForecast(interval: number) {
92const weather = await getWeather("Washington, DC");
93const summary = summarizeWeather(weather);
stevens-openaisendDailyBrief.ts5 matches
11* Generate the daily briefing using OpenAI Chat Completions
12*/
13async function generateBriefingContent(
14openai: OpenAI,
15memories: Awaited<ReturnType<typeof getRelevantMemories>>,
92// -------------------------- MAIN EXPORT --------------------------- //
9394export async function sendDailyBriefing(
95chatId?: string,
96today?: DateTime,
131}
132133// Fetch relevant memories using the utility function
134const memories = await getRelevantMemories();
135console.log(memories);
178* Generate helper text listing today + six subsequent days in readable form.
179*/
180function generateWeekDays(today: DateTime) {
181const output: string[] = [];
182198199// Default export for cron compatibility
200export default async function(overrideToday?: DateTime) {
201return await sendDailyBriefing(undefined, overrideToday);
202}
4import { DateTime } from "https://esm.sh/luxon@3.4.4";
56export async function testDailyBrief() {
7try {
8const testChatId = Deno.env.get("TEST_TELEGRAM_CHAT_ID");
2// Run this script manually to create the database table
34export default async function setupTelegramChatDb() {
5try {
6// Import SQLite module
stevens-openaiREADME.md2 matches
16In a normal server environment, you would likely use a middleware [like this one](https://hono.dev/docs/getting-started/nodejs#serve-static-files) to serve static files. Some frameworks or deployment platforms automatically make any content inside a `public/` folder public.
1718However in Val Town you need to handle this yourself, and it can be suprisingly difficult to read and serve files in a Val Town Project. This template uses helper functions from [stevekrouse/utils/serve-public](https://www.val.town/x/stevekrouse/utils/branch/main/code/serve-public/README.md), which handle reading project files in a way that will work across branches and forks, automatically transpiles typescript to javascript, and assigns content-types based on the file's extension.
1920### `index.html`
26## CRUD API Routes
2728This 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.
2930## Errors
stevens-openaiREADME.md2 matches
45* `migrations.ts` - code to set up the database tables the app needs
6* `queries.ts` - functions to run queries against those tables, which are imported and used in the main Hono server in `/backend/index.ts`
78## Migrations
18The queries file is where running the migrations happen in this app. It'd also be reasonable for that to happen in index.ts, or as is said above, for that line to be commented out, and only run when actual changes are made to your database schema.
1920The queries file exports functions to get and write data. It relies on shared types and data imported from the `/shared` directory.
stevens-openaiqueries.ts4 matches
6const tableName = "memories_demo";
78export async function getAllMemories(): Promise<Memory[]> {
9const result = await sqlite.execute(
10`SELECT id, date, text, createdBy, createdDate, tags FROM ${tableName}
23}
2425export async function createMemory(
26memory: Omit<Memory, "id">
27): Promise<Memory> {
51}
5253export async function updateMemory(
54id: string,
55memory: Partial<Omit<Memory, "id">>
70}
7172export async function deleteMemory(id: string): Promise<void> {
73await sqlite.execute(`DELETE FROM ${tableName} WHERE id = ?`, [id]);
74}
4import { nanoid } from "https://esm.sh/nanoid@5.0.5";
56export default async function populateMemoryIds() {
7try {
8// Import SQLite module