smsberthandleSmsMessage.ts7 matches
2import querystring from "node:querystring";
3import Anthropic from "npm:@anthropic-ai/sdk@0.24.3";
4import { RestClient } from "npm:@signalwire/compatibility-api";
5import chunk from "npm:chunk-text";
6import { backstory } from "../backstory.ts";
8687/**
88* Format chat history for Anthropic API
89*/
90function formatChatHistoryForAI(history) {
325};
326try {
327// Get Anthropic API key from environment
328const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
329if (!apiKey) {
330console.error("Anthropic API key is not configured.");
331await reply(
332"I apologize, but I'm not properly configured at the moment. Please inform the household administrator.",
336337// Initialize Anthropic client
338const anthropic = new Anthropic({ apiKey });
339340// Get message text and user info
267268try {
269// Include sequence in API call URL
270const apiUrl = \`\${window.location.pathname}?query=\${encodeURIComponent(query)}&sequence=\${encodeURIComponent(sequence)}&format=json\`;
271const response = await fetch(apiUrl, {
272method: 'GET',
273headers: { 'Accept': 'application/json' }
337const { OpenAI } = await import("https://esm.town/v/std/openai");
338339// --- OpenAI API Call Helper (Reused) ---
340async function callOpenAI(
341systemPrompt: string,
356357if (!response.choices?.[0]?.message?.content) {
358console.error("OpenAI API returned unexpected structure:", JSON.stringify(response));
359throw new Error("Received invalid or empty response from AI model.");
360}
361return { role: "assistant", content: response.choices[0].message.content };
362} catch (error) {
363console.error(`OpenAI API call failed for model ${model}. Error:`, error.message, error.response?.data);
364let errorMessage = `Error with AI model (${model}).`;
365let statusCode = error.status || error.response?.status;
512const sourceUrl = `https://val.town/v/${Deno.env.get("val_owner")}.${Deno.env.get("val_slug")}`;
513514// API Request (format=json)
515if (format === "json") {
516if (!userQuery || userQuery.trim().length === 0) {
belle-energie-checkerTODO.md1 match
31---------------------
3233<a href="mailto:serviceclient@labellenergie.fr?subject=LBE437298%20-%20Demande%20d'application%20des%20nouvelles%20conditions%20tarifaires&body=Bonjour%2C%0A%0APuis-je%20b%C3%A9n%C3%A9ficier%20des%20nouvelles%20conditions%20tarifaires%20de%20%7Bdate%7D%20pour%20mes%202%20contrats%20(LBE437298%20et%20LBE435565)%2C%20svp%20%3F%0A%0AMon%20n%C2%B0%20de%20client%20est%20le%20LBE437298.%0A%0ABien%20cordialement%2C%0APierre-Olivier%20Mauguet">
34Envoyer la demande à La Belle Énergie
35</a>
81<ul>
82<li>
83<a href="mailto:serviceclient@labellenergie.fr?subject=${numClient}%20-%20Demande%20d'application%20des%20nouvelles%20conditions%20tarifaires&body=Bonjour%2C%0A%0APuis-je%20b%C3%A9n%C3%A9ficier%20des%20nouvelles%20conditions%20tarifaires%20${date}pour%20${wordingContrat}%2C%20svp%20%3F%0A%0AMon%20n%C2%B0%20de%20client%20est%20le%20${numClient}.%0A%0ABien%20cordialement%2C%0APierre-Olivier%20Mauguet">
84Envoyer la demande à La Belle Énergie
85</a>
262263try {
264const apiUrl = \`\${window.location.pathname}?query=\${encodeURIComponent(query)}&format=json\`;
265const response = await fetch(apiUrl, {
266method: 'GET', // Keep using GET for simplicity here
267headers: { 'Accept': 'application/json' }
324const { OpenAI } = await import("https://esm.town/v/std/openai");
325326// --- Helper Function: Call OpenAI API ---
327// (Mostly unchanged, but updated the JSON mode check)
328async function callOpenAI(
332): Promise<{ role: "assistant" | "system"; content: string }> {
333try {
334// Ensure OPENAI_API_KEY is set in Val Town secrets (environment variable)
335const openai = new OpenAI();
336347348if (!response.choices?.[0]?.message?.content) {
349console.error("OpenAI API returned an unexpected or empty response structure:", JSON.stringify(response));
350throw new Error("Received invalid or empty response from AI model.");
351}
357} catch (error) {
358console.error(
359`OpenAI API call failed for model ${model}. System Prompt: ${systemPrompt.substring(0, 80)}... Error:`,
360error,
361);
372}
373if (statusCode === 401)
374errorMessage = "OpenAI API Error (401): Authentication failed. Verify API key secret ('openai').";
375else if (statusCode === 429) errorMessage = "OpenAI API Error (429): Rate limit or quota exceeded.";
376else if (statusCode === 400) errorMessage = `OpenAI API Error (400): Bad Request. ${error.message || ""}`;
377else if (statusCode >= 500) errorMessage = `OpenAI Server Error (${statusCode}): Issue on OpenAI's side.`;
378else if (error.code === "ENOTFOUND" || error.code === "ECONNREFUSED")
379errorMessage = `Network Error (${error.code}): Cannot connect to OpenAI API.`;
380381// Return error: JSON for Routing agent, plain text for others
632const sourceUrl = import.meta.url.replace("esm.town", "val.town"); // Link to Val Town editor
633634// --- API Request Branch (format=json) ---
635if (format === "json") {
636if (!userQuery || userQuery.trim().length === 0) {
stevensDemosendDailyBrief.ts8 matches
9798export async function sendDailyBriefing(chatId?: string, today?: DateTime) {
99// Get API keys from environment
100const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
101const telegramToken = Deno.env.get("TELEGRAM_TOKEN");
102106}
107108if (!apiKey) {
109console.error("Anthropic API key is not configured.");
110return;
111}
122123// Initialize Anthropic client
124const anthropic = new Anthropic({ apiKey });
125126// Initialize Telegram bot
162163// disabled title for now, it seemes unnecessary...
164// await bot.api.sendMessage(chatId, `*${title}*`, { parse_mode: "Markdown" });
165166// Then send the main content
169170if (content.length <= MAX_LENGTH) {
171await bot.api.sendMessage(chatId, content, { parse_mode: "Markdown" });
172// Store the briefing in chat history
173await storeChatMessage(
198// Send each chunk as a separate message and store in chat history
199for (const chunk of chunks) {
200await bot.api.sendMessage(chatId, chunk, { parse_mode: "Markdown" });
201// Store each chunk in chat history
202await storeChatMessage(
stevensDemoREADME.md1 match
53You'll need to set up some environment variables to make it run.
5455- `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.
stevensDemoREADME.md5 matches
8## Hono
910This 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.
1112## Serving assets to the frontend
20### `index.html`
2122The 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 /`.
2324We *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.
2526## 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
3132Hono 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.
stevensDemoNotebookView.tsx5 matches
8import { type Memory } from "../../shared/types.ts";
910const API_BASE = "/api/memories";
11const MEMORIES_PER_PAGE = 20;
1271setError(null);
72try {
73const response = await fetch(API_BASE);
74if (!response.ok) {
75throw new Error(`HTTP error! status: ${response.status}`);
100101try {
102const response = await fetch(API_BASE, {
103method: "POST",
104headers: { "Content-Type": "application/json" },
123124try {
125const response = await fetch(`${API_BASE}/${id}`, {
126method: "DELETE",
127});
155156try {
157const response = await fetch(`${API_BASE}/${editingMemory.id}`, {
158method: "PUT",
159headers: { "Content-Type": "application/json" },
stevensDemoindex.ts11 matches
26});
2728// --- API Routes for Memories ---
2930// GET /api/memories - Retrieve all memories
31app.get("/api/memories", async (c) => {
32const memories = await getAllMemories();
33return c.json(memories);
34});
3536// POST /api/memories - Create a new memory
37app.post("/api/memories", async (c) => {
38const body = await c.req.json<Omit<Memory, "id">>();
39if (!body.text) {
44});
4546// PUT /api/memories/:id - Update an existing memory
47app.put("/api/memories/:id", async (c) => {
48const id = c.req.param("id");
49const body = await c.req.json<Partial<Omit<Memory, "id">>>();
66});
6768// DELETE /api/memories/:id - Delete a memory
69app.delete("/api/memories/:id", async (c) => {
70const id = c.req.param("id");
71try {
83// --- Blob Image Serving Routes ---
8485// GET /api/images/:filename - Serve images from blob storage
86app.get("/api/images/:filename", async (c) => {
87const filename = c.req.param("filename");
88