mahiindex.html28 matches
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6<title>AI Image Recognition</title>
7<!-- TailwindCSS -->
8<script src="https://cdn.twind.style" crossorigin></script>
29<div class="container mx-auto px-4 py-8 max-w-4xl">
30<header class="text-center mb-8">
31<h1 class="text-3xl font-bold text-blue-600 mb-2">AI Image Recognition</h1>
32<p class="text-gray-600">Enter an image URL to get an AI-powered description</p>
33</header>
34
35<main class="bg-white rounded-lg shadow-md p-6">
36<div class="mb-6">
37<label for="imageUrl" class="block text-sm font-medium text-gray-700 mb-2">Image URL</label>
38<div class="flex">
39<input
40type="text"
41id="imageUrl"
42placeholder="https://example.com/image.jpg"
43class="flex-1 rounded-l-md border border-gray-300 px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
44>
50</button>
51</div>
52<p class="mt-1 text-sm text-gray-500">Paste a direct link to an image (JPG, PNG, etc.)</p>
53</div>
54
55<div id="previewContainer" class="mb-6 hidden">
56<h2 class="text-lg font-medium text-gray-800 mb-2">Image Preview</h2>
57<div class="flex justify-center bg-gray-100 rounded-md p-2">
58<img id="imagePreview" src="" alt="Preview" class="max-h-64 rounded">
59</div>
60</div>
62<div id="loadingContainer" class="mb-6 hidden text-center py-4">
63<div class="loading-spinner mr-2"></div>
64<span class="text-gray-600">Analyzing image...</span>
65</div>
66
87<script>
88// DOM elements
89const imageUrlInput = document.getElementById('imageUrl');
90const analyzeBtn = document.getElementById('analyzeBtn');
91const previewContainer = document.getElementById('previewContainer');
92const imagePreview = document.getElementById('imagePreview');
93const loadingContainer = document.getElementById('loadingContainer');
94const resultContainer = document.getElementById('resultContainer');
98
99// Event listeners
100imageUrlInput.addEventListener('input', updatePreview);
101analyzeBtn.addEventListener('click', analyzeImage);
102
103// Handle Enter key in the input field
104imageUrlInput.addEventListener('keydown', (e) => {
105if (e.key === 'Enter') {
106analyzeImage();
107}
108});
109
110// Update image preview when URL changes
111function updatePreview() {
112const imageUrl = imageUrlInput.value.trim();
113
114if (imageUrl) {
115imagePreview.src = imageUrl;
116previewContainer.classList.remove('hidden');
117
118// Handle image load errors
119imagePreview.onerror = () => {
120previewContainer.classList.add('hidden');
121};
125}
126
127// Analyze the image using the API
128async function analyzeImage() {
129const imageUrl = imageUrlInput.value.trim();
130
131if (!imageUrl) {
132showError('Please enter an image URL');
133return;
134}
146'Content-Type': 'application/json',
147},
148body: JSON.stringify({ imageUrl }),
149});
150
1# AI Image Recognition App
23This Val Town app uses OpenAI's Vision API to analyze images and provide descriptions of their content.
45## Features
67- Submit image URLs for AI analysis
8- Get detailed descriptions of image content
9- Simple, user-friendly interface
1017181. Visit the app URL
192. Enter an image URL in the input field
203. Click "Analyze Image"
214. View the AI-generated description of the image
2223## Technologies Used
Townieuser-summary.ts2 matches
18SUM(cache_write_tokens) as total_cache_write_tokens,
19SUM(price) as total_price,
20SUM(num_images) as total_images
21FROM ${USAGE_TABLE}
22WHERE our_api_token = 1
101total_cache_write_tokens: userData.cache_write_tokens,
102total_price: userData.price,
103total_images: 0,
104used_inference_data: true
105});
TownieuseChatLogic.ts4 matches
7branchId: string | undefined;
8selectedFiles: string[];
9images: (string | null)[];
10soundEnabled: boolean;
11}
17// bearerToken,
18selectedFiles,
19images,
20soundEnabled,
21}: UseChatLogicProps) {
40branchId,
41selectedFiles,
42images: images
43.filter((img): img is string => {
44const isValid = typeof img === "string" && img.startsWith("data:");
45if (!isValid && img !== null) {
46console.warn(
47"Invalid image format:",
48img?.substring(0, 50) + "..."
49);
29- [x] File write as a code embed
30- [x] str_replace as a diff view
31- [x] make image drop area invisible and bigger
32- [x] Give it all the code (except maybe .txt files) as initial context (like cursor sonnet max)
33- [x] I seem to have lost the delete file tool and instructions, try to find them back in history or re-create?
55- [x] Create branch
56- [x] URL input + pathname
57- [x] Image upload controls
58- [x] Preview refresh button
59- [x] Audio controls
Towniesystem_prompt.txt2 matches
172173- **Redirects:** Use `return new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }})` instead of `Response.redirect` which is broken
174- **Images:** Avoid external images or base64 images. Use emojis, unicode symbols, or icon fonts/libraries instead
175- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
176- **Storage:** DO NOT use the Deno KV module for storage
177- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
Towniestyles.css11 matches
782background-color: var(--highlight);
783}
784.card-image {
785display: flex;
786align-items: center;
809}
810811.image-placeholder,
812.image-thumbnail {
813flex-shrink: 0;
814width: 40px;
817object-fit: cover;
818}
819.image-placeholder {
820background-color: var(--muted);
821}
828}
829830.image-row {
831display: flex;
832gap: var(--space-1);
833}
834.input-image {
835position: relative;
836border: 1px solid var(--muted);
837border-radius: 6px;
838}
839.remove-image-button {
840position: absolute;
841top: 0;
850opacity: 0;
851}
852.input-image:hover .remove-image-button {
853opacity: 1;
854}
855856.image-drop-overlay {
857position: fixed;
858top: 0;
867justify-content: center;
868}
869.image-drop-inner {
870padding: var(--space-2);
871background-color: var(--background);
872}
873874.transition, .input-box, .icon-button, .button, .remove-image-button {
875transition-property: color, background-color, border-color, opacity;
876transition-duration: 200ms;
Towniesend-message.ts11 matches
33}
3435const { messages, project, branchId, anthropicApiKey, selectedFiles, images } = await c.req.json();
3637// do we want to allow user-provided tokens still
63branch_id: branchId,
64val_id: project.id,
65num_images: images?.length || 0,
66model: "claude-3-7-sonnet-20250219",
67});
73let coreMessages = convertToCoreMessages(messages);
7475// If there are images, we need to add them to the last user message
76if (images && Array.isArray(images) && images.length > 0) {
77// Find the last user message
78const lastUserMessageIndex = coreMessages.findIndex(
96};
9798// Add each image to the content array using the correct ImagePart format
99for (const image of images) {
100if (image && image.url) {
101// Extract mime type from data URL if available
102let mimeType = undefined;
103if (image.url.startsWith("data:")) {
104const matches = image.url.match(/^data:([^;]+);/);
105if (matches && matches.length > 1) {
106mimeType = matches[1];
109110newUserMessage.content.push({
111type: "image",
112image: image.url,
113mimeType,
114});
Townieschema.tsx2 matches
18price?: number;
19finish_reason?: string;
20num_images?: number;
21our_api_token: boolean;
22}
43price REAL,
44finish_reason TEXT,
45num_images INTEGER,
46our_api_token INTEGER NOT NULL,
47finish_timestamp INTEGER
Townierequests.ts3 matches
16price: number | null;
17finish_reason: string | null;
18num_images: number | null;
19our_api_token: number;
20}
191<th>Price</th>
192<th>Finish</th>
193<th>Images</th>
194<th>Our API</th>
195</tr>
215<td class="price">${formatPrice(row.price)}</td>
216<td>${row.finish_reason || '-'}</td>
217<td>${formatNumber(row.num_images)}</td>
218<td>${formatBoolean(row.our_api_token)}</td>
219</tr>