blogTesting001-makingVtCli.md4 matches
46
4748Unfortunately `vtfs` no longer works anymore and because of breaking API
49changes, and, while there was work in progress on `vtfs` to add support for val
50town projects, development has paused on the project in favor of `vt`.
175beginning, my plan for this was to implement "git" behavior first (pushing and
176pulling), and then just doing file system watching to add live syncing using
177[Deno.watchFs](https://docs.deno.com/api/deno/~/Deno.watchFs) to handle file
178system events.
179295296For `vtfs` I was using
297[Openapi Generator](https://github.com/OpenAPITools/openapi-generator), and it
298turned out that Val Town's OpenAPI specification didn't accept file sizes on the
299order of my tests -- where the response would include the file size, it was an
300integer, not a `format: int64` (long).
wondrousMaroonPeafowlmain.tsx38 matches
6import "jsr:@std/dotenv/load"; // needed for deno run; not req for smallweb or valtown
78// Function to handle audio transcription using Groq's Whisper API
9export const audioTranscriptionHandler = async (c) => {
10console.log("๐ค Audio transcription request received");
20}
2122// Get API key from environment variable
23const apiKey = Deno.env.get("GROQ_API_KEY");
24if (!apiKey) {
25console.error("โ Transcription error: Missing API key");
26return c.json({ error: "API key not configured" }, 500);
27}
2849}
5051// Prepare the form data for Groq API
52const groqFormData = new FormData();
5364groqFormData.append("timestamp_granularities[]", "word");
6566// Call Groq API
67console.log("๐ค Sending request to Groq Whisper API");
68const start = Date.now();
69const response = await fetch("https://api.groq.com/openai/v1/audio/transcriptions", {
70method: "POST",
71headers: {
72"Authorization": `Bearer ${apiKey}`,
73},
74body: groqFormData,
75});
76const elapsed = Date.now() - start;
77console.log(`๐ค Groq Whisper API response received in ${elapsed}ms, status: ${response.status}`);
7879// Get response content type
96} else {
97errorMessage = `Server error: ${response.status} ${response.statusText}`;
98console.error("โ Transcription API error response:", {
99status: response.status,
100statusText: response.statusText,
105}
106} catch (parseError) {
107console.error("โ Error parsing Groq API response:", parseError);
108errorMessage = "Failed to parse error response from server";
109}
110111return c.json({
112error: `Groq API error: ${errorMessage}`,
113status: response.status,
114}, response.status);
147console.log(`๐ต Last user message: "${messages.find(m => m.role === "user")?.content?.substring(0, 50)}..."`);
148149const GROQ_API_KEY = Deno.env.get("GROQ_API_KEY");
150if (!GROQ_API_KEY) {
151console.error("โ Missing GROQ_API_KEY environment variable");
152return c.json({ error: "GROQ_API_KEY environment variable is not set" }, 500);
153}
154155console.log("๐ต Sending request to Groq API");
156const start = Date.now();
157const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
158method: "POST",
159headers: {
160"Content-Type": "application/json",
161"Authorization": `Bearer ${GROQ_API_KEY}`,
162},
163body: JSON.stringify({
168});
169const elapsed = Date.now() - start;
170console.log(`๐ต Groq API response received in ${elapsed}ms, status: ${response.status}`);
171172if (!response.ok) {
173const errorData = await response.json();
174console.error("โ Chat API error:", errorData);
175return c.json({ error: "Failed to get chat completion", details: errorData }, response.status);
176}
203}
204205const apiKey = Deno.env.get("GROQ_API_KEY");
206if (!apiKey) {
207console.error("โ TTS error: Missing API key");
208return c.json({ error: "API key not configured" }, 500);
209}
210211console.log("๐ Sending request to Groq Speech API");
212const start = Date.now();
213const response = await fetch("https://api.groq.com/openai/v1/audio/speech", {
214method: "POST",
215headers: {
216"Content-Type": "application/json",
217"Authorization": `Bearer ${apiKey}`,
218},
219body: JSON.stringify({
225});
226const elapsed = Date.now() - start;
227console.log(`๐ Groq Speech API response received in ${elapsed}ms, status: ${response.status}`);
228229if (!response.ok) {
232const errorData = await response.json();
233errorMessage = errorData.error?.message || JSON.stringify(errorData);
234console.error("โ TTS API error:", errorData);
235} catch {
236errorMessage = `Server error: ${response.status} ${response.statusText}`;
237console.error("โ TTS API non-JSON error:", errorMessage);
238}
239return c.json({ error: errorMessage }, response.status);
460async sendAIRequest() {
461try {
462const apiMessages = this.messages.map(({ role, content }) => ({ role, content }));
463if (apiMessages[0].role === 'system') {
464apiMessages[0].content = this.chatMode === 'concise'
465? 'You are a helpful assistant powered by the Llama-3.3-70b-versatile model. Keep your responses short, concise and conversational. Aim for 1-3 sentences when possible.'
466: 'You are a helpful assistant powered by the Llama-3.3-70b-versatile model. Respond conversationally and accurately to the user.';
469method: 'POST',
470headers: { 'Content-Type': 'application/json' },
471body: JSON.stringify({ messages: apiMessages })
472});
473if (chatResponse.ok) {
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
stevensDemoindex.html2 matches
12type="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
17href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap"
18rel="stylesheet"
19/>
stevensDemohandleUSPSEmail.ts5 matches
85console.log(e.text);
8687// Get Anthropic API key from environment
88const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
89if (!apiKey) {
90console.error("Anthropic API key is not configured for this val.");
91return;
92}
9394// Initialize Anthropic client
95const anthropic = new Anthropic({ apiKey });
9697// Process each image attachment serially
stevensDemohandleTelegramMessage.ts7 matches
9293/**
94* Format chat history for Anthropic API
95*/
96function formatChatHistoryForAI(history) {
321bot.on("message", async (ctx) => {
322try {
323// Get Anthropic API key from environment
324const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
325if (!apiKey) {
326console.error("Anthropic API key is not configured.");
327ctx.reply(
328"I apologize, but I'm not properly configured at the moment. Please inform the household administrator."
332333// Initialize Anthropic client
334const anthropic = new Anthropic({ apiKey });
335336// Get message text and user info
502// Set webhook if it is not set yet
503if (!isEndpointSet) {
504await bot.api.setWebhook(req.url, {
505secret_token: SECRET_TOKEN,
506});