1@import url("https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=JetBrains+Mono:wght@400;500&display=swap");
23:root {
groqAudioChatmain.tsx47 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}
283839// If the file doesn't have a proper name or type, add one
40// This ensures the file has the right extension for the API
41if (!audioFile.name || !audioFile.type.startsWith("audio/")) {
42const newFile = new File(
50}
5152// Prepare the form data for Groq API
53const groqFormData = new FormData();
5465groqFormData.append("timestamp_granularities[]", "word");
6667// Call Groq API
68console.log("๐ค Sending request to Groq Whisper API");
69const start = Date.now();
70const response = await fetch("https://api.groq.com/openai/v1/audio/transcriptions", {
71method: "POST",
72headers: {
73"Authorization": `Bearer ${apiKey}`,
74},
75body: groqFormData,
76});
77const elapsed = Date.now() - start;
78console.log(`๐ค Groq Whisper API response received in ${elapsed}ms, status: ${response.status}`);
7980// Get response content type
99errorMessage = `Server error: ${response.status} ${response.statusText}`;
100// Log the full response for debugging
101console.error("โ Transcription API error response:", {
102status: response.status,
103statusText: response.statusText,
108}
109} catch (parseError) {
110console.error("โ Error parsing Groq API response:", parseError);
111errorMessage = "Failed to parse error response from server";
112}
113114return c.json({
115error: `Groq API error: ${errorMessage}`,
116status: response.status,
117}, response.status);
150console.log(`๐ต Last user message: "${messages.find(m => m.role === "user")?.content?.substring(0, 50)}..."`);
151152const GROQ_API_KEY = Deno.env.get("GROQ_API_KEY");
153if (!GROQ_API_KEY) {
154console.error("โ Missing GROQ_API_KEY environment variable");
155return c.json({ error: "GROQ_API_KEY environment variable is not set" }, 500);
156}
157158console.log("๐ต Sending request to Groq API");
159const start = Date.now();
160const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
161method: "POST",
162headers: {
163"Content-Type": "application/json",
164"Authorization": `Bearer ${GROQ_API_KEY}`,
165},
166body: JSON.stringify({
171});
172const elapsed = Date.now() - start;
173console.log(`๐ต Groq API response received in ${elapsed}ms, status: ${response.status}`);
174175if (!response.ok) {
176const errorData = await response.json();
177console.error("โ Chat API error:", errorData);
178return c.json({ error: "Failed to get chat completion", details: errorData }, response.status);
179}
206}
207208// Get API key from environment variable
209const apiKey = Deno.env.get("GROQ_API_KEY");
210if (!apiKey) {
211console.error("โ TTS error: Missing API key");
212return c.json({ error: "API key not configured" }, 500);
213}
214215// Call Groq Speech API
216console.log("๐ Sending request to Groq Speech API");
217const start = Date.now();
218const response = await fetch("https://api.groq.com/openai/v1/audio/speech", {
219method: "POST",
220headers: {
221"Content-Type": "application/json",
222"Authorization": `Bearer ${apiKey}`,
223},
224body: JSON.stringify({
230});
231const elapsed = Date.now() - start;
232console.log(`๐ Groq Speech API response received in ${elapsed}ms, status: ${response.status}`);
233234if (!response.ok) {
237const errorData = await response.json();
238errorMessage = errorData.error?.message || JSON.stringify(errorData);
239console.error("โ TTS API error:", errorData);
240} catch (e) {
241// If response is not JSON
242errorMessage = `Server error: ${response.status} ${response.statusText}`;
243console.error("โ TTS API non-JSON error:", errorMessage);
244}
245603// Now immediately send this message to get AI response
604try {
605// Prepare messages for the API
606const apiMessages = this.messages.map(({ role, content }) => ({ role, content }));
607
608// Ensure first message is always the correct system message for current mode
609if (apiMessages.length > 0 && apiMessages[0].role === 'system') {
610const systemMessage = this.chatMode === 'concise'
611? '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.'
612: 'You are a helpful assistant powered by the Llama-3.3-70b-versatile model. Respond conversationally and accurately to the user.';
613
614apiMessages[0].content = systemMessage;
615}
616
618method: 'POST',
619headers: { 'Content-Type': 'application/json' },
620body: JSON.stringify({ messages: apiMessages })
621});
622
681this.statusMessage = 'Thinking...';
682
683// Prepare messages for the API (excluding UI-only properties)
684const apiMessages = this.messages.map(({ role, content }) => ({ role, content }));
685
686// Ensure first message is always the correct system message for current mode
687if (apiMessages.length > 0 && apiMessages[0].role === 'system') {
688const systemMessage = this.chatMode === 'concise'
689? '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.'
690: 'You are a helpful assistant powered by the Llama-3.3-70b-versatile model. Respond conversationally and accurately to the user.';
691
692apiMessages[0].content = systemMessage;
693}
694
697method: 'POST',
698headers: { 'Content-Type': 'application/json' },
699body: JSON.stringify({ messages: apiMessages })
700});
701
val_to_project_converterindex.ts10 matches
3import { Hono } from "npm:hono";
4import { createProjectFromVals } from "./services/projectService.ts";
5import redirectHandler from "./api/redirect.ts";
67const app = new Hono();
1920// List user's projects
21app.get("/api/projects", async (c) => {
22const authHeader = c.req.header("Authorization");
23const apiKey = authHeader?.split("Bearer ")?.[1];
2425if (!apiKey) {
26return c.json({ error: "API key is required" }, 401);
27}
2829try {
30const projectsResponse = await fetch("https://api.val.town/v1/me/projects?limit=100", {
31headers: {
32"Authorization": `Bearer ${apiKey}`,
33},
34});
36if (!projectsResponse.ok) {
37const errorText = await projectsResponse.text();
38console.error("Val Town API Error:", errorText);
39throw new Error(`Failed to fetch projects: ${projectsResponse.statusText}`);
40}
58app.post("/convert", async (c) => {
59try {
60const { apiKey, vals, projectName, existingProjectId } = await c.req.json();
6162const result = await createProjectFromVals(apiKey, vals, projectName, existingProjectId);
6364return c.json(result);
val_to_project_converterApp.tsx20 matches
67export function App() {
8const [apiKey, setApiKey] = useState<string>("");
9const [valUrlsInput, setValUrlsInput] = useState<string>("");
10const [projectName, setProjectName] = useState<string>("");
19const [isLoadingProjects, setIsLoadingProjects] = useState<boolean>(false);
20const [projectsError, setProjectsError] = useState<string | null>(null);
21const [apiKeyHighlightError, setApiKeyHighlightError] = useState<boolean>(false);
2223useEffect(() => {
24if (apiKey) {
25const fetchProjects = async () => {
26setIsLoadingProjects(true);
29setSelectedProjectId("");
30try {
31const response = await fetch("/api/projects", {
32headers: {
33"Authorization": `Bearer ${apiKey}`,
34},
35});
45} catch (err: any) {
46console.error("Project fetch error:", err);
47setProjectsError(err.message || "Could not load projects. Ensure your API key is valid.");
48setCreationMode("new");
49} finally {
61}
62}
63}, [apiKey]);
6465const parseValUrls = (input: string): ValInfo[] => {
92setResults(null);
93setRedirectToRedirectPage(false);
94setApiKeyHighlightError(false);
9596const valsToConvert = parseValUrls(valUrlsInput);
103104let requestBody: any = {
105apiKey,
106vals: valsToConvert,
107};
146setIsLoading(false);
147}
148}, [apiKey, valUrlsInput, projectName, creationMode, selectedProjectId]);
149150const handleRedirectConfirm = async () => {
160headers: { "Content-Type": "application/json" },
161body: JSON.stringify({
162apiKey,
163originalVals: originalVals,
164projectName: results.projectName,
186187const handleExistingProjectLabelClick = () => {
188if (!apiKey) {
189setApiKeyHighlightError(true);
190setTimeout(() => setApiKeyHighlightError(false), 1500);
191}
192};
193194const handleApiKeyChange = (value: string) => {
195setApiKey(value);
196setResults(null);
197setError(null);
200setProjectsError(null);
201setSelectedProjectId("");
202setApiKeyHighlightError(false);
203};
204226{!results ? (
227<ConversionForm
228apiKey={apiKey}
229valUrls={valUrlsInput}
230projectName={projectName}
231isLoading={isLoading || isLoadingProjects}
232onApiKeyChange={handleApiKeyChange}
233onValUrlsChange={setValUrlsInput}
234onProjectNameChange={setProjectName}
241isLoadingProjects={isLoadingProjects}
242projectsError={projectsError}
243apiKeyHighlightError={apiKeyHighlightError}
244onExistingProjectLabelClick={handleExistingProjectLabelClick}
245/>
val_to_project_converterindex.html2 matches
8content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
9>
10<link rel="preconnect" href="https://fonts.googleapis.com">
11<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12<link
13href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=JetBrains+Mono:wght@400;500&display=swap"
14rel="stylesheet"
15>
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