19 finish_reason?: string;
20 num_images?: number;
21 our_api_token: boolean;
22}
23
44 finish_reason TEXT,
45 num_images INTEGER,
46 our_api_token INTEGER NOT NULL,
47 finish_timestamp INTEGER
48 )
17 finish_reason: string | null;
18 num_images: number | null;
19 our_api_token: number;
20}
21
57
58 // Fetch the inference calls data
59 fetch('/api/inference-calls?usage_id=' + usageId)
60 .then(response => response.json())
61 .then(data => {
192 <th>Finish</th>
193 <th>Images</th>
194 <th>Our API</th>
195 </tr>
196 </thead>
216 <td>${row.finish_reason || '-'}</td>
217 <td>${formatNumber(row.num_images)}</td>
218 <td>${formatBoolean(row.our_api_token)}</td>
219 </tr>
220 `).join("")}
9- **File Browser**: Select specific files to include in the context window for more focused AI assistance
10- **Branch Management**: View, select, and create branches without leaving the app
11- **Cost Tracking**: See estimated API usage costs for each interaction
12- **Sound Notifications**: Get alerted when Claude finishes responding
13- **Mobile-Friendly**: Works on both desktop and mobile devices
14- **Usage Dashboard**: Monitor API usage and inference calls with detailed analytics
15
16## How It Works
17
181. **Login**: Authenticate with your Val Town API token and Anthropic API key
192. **Select a Project**: Choose which Val Town project you want to work on
203. **Select Files**: Browse your project files and select which ones to include in the context window
26### Prerequisites
27
28- A Val Town account with API access
29- An Anthropic API key (Claude 3.7 Sonnet)
30
31### Setup
32
331. Visit the OpenTownie app
342. Enter your Val Town API token (with `projects:write` and `users:read` permissions)
353. Enter your Anthropic API key
364. Click "Login" to access your projects
37
49- React frontend with TypeScript
50- React Router
51- Hono API server backend
52- Web Audio API for sound notifications
53- AI SDK for Claude integration
54
55The application proxies requests to the Anthropic API and Val Town API, allowing Claude to view and edit your project files directly.
56
57## Privacy & Security
58
59- Your Val Town API token and Anthropic API key are stored locally in your browser
60- No data is stored on our servers
61- All communication with the APIs is done directly from your browser
62
1# Usage Dashboard
2
3A dashboard for monitoring API usage and inference calls.
4
5## Features
20 index.ts # Main entry point and routing
21 auth.ts # Authentication logic
22 /api/
23 index.ts # API request handler
24 requests.ts # API endpoints for requests data
25 inference-calls.ts # API endpoints for inference calls
26 user-summary.ts # API endpoints for user summary data
27 /views/
28 layout.ts # Common layout template
54 - Links back to the associated request
55
56### API Endpoints
57
58- `/api/requests` - Get paginated requests
59- `/api/requests?usage_id=123` - Get a specific request
60- `/api/inference-calls` - Get paginated inference calls
61- `/api/inference-calls?usage_id=123` - Get inference calls for a specific request
62- `/api/user-summary` - Get user summary data
63
64## Debugging
24 user_id = ?
25 AND timestamp > ?
26 AND our_api_token = 1
27 `,
28 [userId, new Date().getTime() - 24 * 60 * 60 * 1000],
108 branch_id,
109 model,
110 our_api_token,
111 num_images,
112}: {
115 branch_id: string;
116 model: string;
117 our_api_token: boolean;
118 num_images: number;
119}) {
127 branch_id,
128 model,
129 our_api_token,
130 num_images
131 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
138 branch_id,
139 model,
140 our_api_token ? 1 : 0,
141 num_images,
142 ],
90 value={customPath}
91 onChange={handlePathChange}
92 placeholder="Path (e.g., /api/data)"
93 />
94 </div>
11app.get("*", async (c, next) => {
12 const path = c.req.path;
13 if (path.startsWith("/api/") || c.req.header("Accept")?.includes("application/json")) {
14 return next();
15 }
21});
22
23app.route("/api", backend);
24app.get("/frontend/*", c => {
25 return serveFile(c.req.path, import.meta.url);
1import { basicAuthMiddleware } from "./auth.ts";
2import { handleApiRequest } from "./api/index.ts";
3import { getRequests } from "./api/requests.ts";
4import { getUserSummary } from "./api/user-summary.ts";
5import { getInferenceCalls } from "./api/inference-calls.ts";
6import { renderDashboard } from "./views/dashboard.ts";
7import { renderRequests } from "./views/requests.ts";
22 const path = url.pathname;
23
24 // Handle API requests
25 if (path.startsWith("/api/")) {
26 return handleApiRequest(req);
27 }
28
4
5/**
6 * Handle API requests
7 */
8export async function handleApiRequest(req: Request): Promise<Response> {
9 const url = new URL(req.url);
10 const path = url.pathname.replace("/api/", "");
11
12 try {
13 // Route to the appropriate API handler
14 if (path === "requests") {
15 const usageId = url.searchParams.get("usage_id");
59 }
60 } catch (error) {
61 console.error("API error:", error);
62 return new Response(JSON.stringify({ error: error.message }), {
63 status: 500,
42 </h2>
43 <ol>
44 <li>Login with your Val Town API token (with projects:read, projects:write, user:read permissions)</li>
45 <li>Select a project to work on</li>
46 <li>Chat with Claude about your code</li>
79 </div>
80 <h3>Cost Tracking</h3>
81 <p>See estimated API usage costs for each interaction</p>
82 </div>
83 </section>
92 <ul>
93 <li>React frontend with TypeScript</li>
94 <li>Hono API server backend</li>
95 <li>Web Audio API for sound notifications</li>
96 <li>AI SDK for Claude integration</li>
97 </ul>
98 <p>
99 The application proxies requests to the Anthropic API and Val Town API, allowing Claude to view and edit your
100 project files directly.
101 </p>