Val Town Code SearchReturn to Val Town

API Access

You can access search results via JSON API by adding format=json to your query:

https://codesearch.val.run//%22script.js/%22?q=image&page=5&format=json

For typeahead suggestions, use the /typeahead endpoint:

https://codesearch.val.run/typeahead?q=image

Returns an array of strings in format "username" or "username/projectName"

Found 12681 results for "image"(962ms)

postherousimages.ts105 matches

@paulkinlanUpdated 1 day ago
1import { blob } from "https://esm.town/v/std/blob";
2import { createImage, generateUniqueImageFilename, getImageByFilename, deleteImage } from "../database/queries.ts";
3import { BlogImage, CreateImageData, EmailAttachment } from "../../shared/types.ts";
4
5// Supported image MIME types
6const SUPPORTED_IMAGE_TYPES = [
7 'image/jpeg',
8 'image/jpg',
9 'image/png',
10 'image/gif',
11 'image/webp',
12 'image/svg+xml'
13];
14
17
18/**
19 * Check if a MIME type is a supported image format
20 */
21export function isSupportedImageType(mimeType: string): boolean {
22 return SUPPORTED_IMAGE_TYPES.includes(mimeType.toLowerCase());
23}
24
25/**
26 * Validate image file
27 */
28export function validateImageFile(file: { size: number; type: string }): { valid: boolean; error?: string } {
29 if (file.size > MAX_FILE_SIZE) {
30 return { valid: false, error: `File size too large. Maximum size is ${MAX_FILE_SIZE / (1024 * 1024)}MB` };
31 }
32
33 if (!isSupportedImageType(file.type)) {
34 return { valid: false, error: `Unsupported file type. Supported types: ${SUPPORTED_IMAGE_TYPES.join(', ')}` };
35 }
36
39
40/**
41 * Store an image from a File object (for uploads)
42 */
43export async function storeImageFromFile(
44 file: File,
45 uploadedByEmail: string,
48 postSlug?: string;
49 } = {}
50): Promise<BlogImage> {
51 // Validate the file
52 const validation = validateImageFile(file);
53 if (!validation.valid) {
54 throw new Error(validation.error);
56
57 // Generate unique filename
58 const filename = await generateUniqueImageFilename(file.name);
59 const blobKey = `images/${filename}`;
60
61 // Read file as array buffer and store in blob
63 await blob.set(blobKey, new Uint8Array(arrayBuffer));
64
65 // Try to get image dimensions (basic approach)
66 let width: number | undefined;
67 let height: number | undefined;
68
69 // For now, we'll skip dimension detection as it requires additional libraries
70 // In a production environment, you might want to use a library like 'image-size'
71
72 // Create image record
73 const imageData: CreateImageData = {
74 filename,
75 original_filename: file.name,
84 };
85
86 return await createImage(imageData);
87}
88
89/**
90 * Store an image from base64 data (for email attachments)
91 */
92export async function storeImageFromBase64(
93 base64Data: string,
94 originalFilename: string,
99 postSlug?: string;
100 } = {}
101): Promise<BlogImage> {
102 // Convert base64 to Uint8Array
103 const binaryString = atob(base64Data);
110
111 // Validate the file
112 const validation = validateImageFile({ size: fileSize, type: mimeType });
113 if (!validation.valid) {
114 throw new Error(validation.error);
116
117 // Generate unique filename
118 const filename = await generateUniqueImageFilename(originalFilename);
119 const blobKey = `images/${filename}`;
120
121 // Store in blob
122 await blob.set(blobKey, bytes);
123
124 // Create image record
125 const imageData: CreateImageData = {
126 filename,
127 original_filename: originalFilename,
134 };
135
136 return await createImage(imageData);
137}
138
139/**
140 * Get image data from blob storage
141 */
142export async function getImageData(filename: string): Promise<{ data: Uint8Array; mimeType: string } | null> {
143 const imageRecord = await getImageByFilename(filename);
144 if (!imageRecord) {
145 return null;
146 }
147
148 const blobData = await blob.get(imageRecord.blob_key);
149 if (!blobData) {
150 return null;
169 return {
170 data,
171 mimeType: imageRecord.mime_type
172 };
173}
174
175/**
176 * Delete an image (both record and blob data)
177 */
178export async function deleteImageCompletely(filename: string): Promise<boolean> {
179 const imageRecord = await getImageByFilename(filename);
180 if (!imageRecord) {
181 return false;
182 }
183
184 // Delete from blob storage
185 await blob.delete(imageRecord.blob_key);
186
187 // Delete from database
188 return await deleteImage(filename);
189}
190
191/**
192 * Process email attachments and extract images
193 */
194export async function processEmailAttachments(
196 uploadedByEmail: string,
197 postSlug?: string
198): Promise<BlogImage[]> {
199 const images: BlogImage[] = [];
200
201 for (const attachment of attachments) {
202 if (isSupportedImageType(attachment.contentType)) {
203 try {
204 const image = await storeImageFromBase64(
205 attachment.content,
206 attachment.filename,
209 { postSlug }
210 );
211 images.push(image);
212 console.log(`✅ Processed email attachment image: ${attachment.filename} -> ${image.filename}`);
213 } catch (error) {
214 console.error(`❌ Failed to process email attachment ${attachment.filename}:`, error);
217 }
218
219 return images;
220}
221
222/**
223 * Generate image URL for serving
224 */
225export function getImageUrl(filename: string, baseUrl?: string): string {
226 const base = baseUrl || '';
227 return `${base}/images/${filename}`;
228}
229
230/**
231 * Replace image references in content with proper URLs and add unreferenced attachments
232 *
233 * This function handles two main scenarios:
234 * 1. Inline images: Replaces various email client image reference patterns (cid:, src=, etc.) with proper URLs
235 * 2. Attachment images: Adds images that were attached but not referenced in the email content
236 *
237 * @param content - The email content (HTML or text)
238 * @param images - Array of processed images from email attachments
239 * @param baseUrl - Base URL for generating image URLs
240 * @returns Updated content with proper image references and unreferenced attachments
241 */
242export function replaceImageReferencesInContent(content: string, images: BlogImage[], baseUrl?: string): string {
243 let updatedContent = content;
244 const referencedImages = new Set<string>();
245
246 // If no images, return content as-is
247 if (images.length === 0) {
248 return updatedContent;
249 }
250
251 for (const image of images) {
252 const imageUrl = getImageUrl(image.filename, baseUrl);
253 const originalFilename = image.original_filename;
254
255 // Escape special regex characters in filename
258 // Replace various possible references to the original filename
259 const patterns = [
260 // Content-ID references (most common for inline images)
261 new RegExp(`cid:${escapedFilename}`, 'gi'),
262 new RegExp(`cid:"${escapedFilename}"`, 'gi'),
277
278 // Email client specific patterns
279 new RegExp(`\\[image: ${escapedFilename}\\]`, 'gi'),
280 new RegExp(`\\[Inline image ${escapedFilename}\\]`, 'gi'),
281 new RegExp(`<${escapedFilename}>`, 'gi'),
282 ];
283
284 let imageWasReferenced = false;
285
286 for (const pattern of patterns) {
287 const matches = updatedContent.match(pattern);
288 if (matches && matches.length > 0) {
289 imageWasReferenced = true;
290 referencedImages.add(image.filename);
291
292 if (pattern.source.includes('src=')) {
293 // Replace src attributes
294 updatedContent = updatedContent.replace(pattern, `src="${imageUrl}"`);
295 } else if (pattern.source.includes('cid:')) {
296 // Replace Content-ID references
297 updatedContent = updatedContent.replace(pattern, imageUrl);
298 } else if (pattern.source.includes('alt=') || pattern.source.includes('title=')) {
299 // For alt/title attributes, just update the reference but keep the structure
300 updatedContent = updatedContent.replace(pattern, (match) => {
301 return match.replace(originalFilename, imageUrl);
302 });
303 } else {
304 // Replace other references with proper img tags
305 updatedContent = updatedContent.replace(pattern, `<img src="${imageUrl}" alt="${image.alt_text || image.original_filename}" style="max-width: 100%; height: auto;" />`);
306 }
307 }
313 if (brokenMatches) {
314 for (const match of brokenMatches) {
315 // Check if this img tag might be referencing our image
316 if (match.includes(originalFilename) ||
317 match.includes('src=""') ||
320 match.includes("src='cid:")) {
321
322 imageWasReferenced = true;
323 referencedImages.add(image.filename);
324
325 // Extract alt text if present
326 const altMatch = match.match(/alt=["']([^"']*)["']/i);
327 const altText = altMatch ? altMatch[1] : (image.alt_text || image.original_filename);
328
329 // Replace with working img tag
330 const newImgTag = `<img src="${imageUrl}" alt="${altText}" style="max-width: 100%; height: auto;" />`;
331 updatedContent = updatedContent.replace(match, newImgTag);
332 }
341 const cidMatches = [...updatedContent.matchAll(cidPattern)];
342
343 if (cidMatches.length > 0 && images.length > 0) {
344 console.log(`🔍 Found ${cidMatches.length} unmatched CID references, using first available image`);
345
346 // Use the first available image for unmatched CID references
347 const firstImage = images[0];
348 const firstImageUrl = getImageUrl(firstImage.filename, baseUrl);
349
350 for (const match of cidMatches) {
352 const cidId = match[1];
353
354 console.log(`🔄 Replacing unmatched CID: ${cidId} with ${firstImageUrl}`);
355 updatedContent = updatedContent.replace(fullMatch, `src="${firstImageUrl}"`);
356 referencedImages.add(firstImage.filename);
357 }
358 }
359
360 // Add unreferenced attachment images at the end of the content
361 const unreferencedImages = images.filter(image => !referencedImages.has(image.filename));
362
363 if (unreferencedImages.length > 0) {
364 console.log(`📎 Adding ${unreferencedImages.length} unreferenced attachment images to content`);
365
366 // Add a section for attachments
368 attachmentSection += '<h3 style="margin-bottom: 1rem; color: #374151;">Attachments:</h3>\n';
369
370 for (const image of unreferencedImages) {
371 const imageUrl = getImageUrl(image.filename, baseUrl);
372 attachmentSection += `<div style="margin-bottom: 1rem;">\n`;
373 attachmentSection += ` <img src="${imageUrl}" alt="${image.alt_text || image.original_filename}" style="max-width: 100%; height: auto; border-radius: 0.5rem; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);" />\n`;
374 if (image.alt_text || image.original_filename !== image.filename) {
375 attachmentSection += ` <p style="margin-top: 0.5rem; font-size: 0.875rem; color: #6b7280; font-style: italic;">${image.alt_text || image.original_filename}</p>\n`;
376 }
377 attachmentSection += `</div>\n`;

postherousindex.ts113 matches

@paulkinlanUpdated 1 day ago
5 deletePostsByAuthorEmail,
6 getActiveFollowers,
7 getAllImages,
8 getAllPosts,
9 getEmailVerificationByToken,
10 getFollowerCount,
11 getImagesByPostSlug,
12 getImagesByUser,
13 getPostActivityCounts,
14 getPostBySlug,
29import { isEmailAllowed } from "./services/email-security.ts";
30import {
31 deleteImageCompletely,
32 getImageData,
33 getImageUrl,
34 storeImageFromFile,
35 validateImageFile,
36} from "./services/images.ts";
37import { generateRSSFeed } from "./services/rss.ts";
38import { extractDomain, generateWebFingerResponse, isValidWebFingerResource } from "./services/webfinger.ts";
215
216 <!-- Twitter -->
217 <meta property="twitter:card" content="summary_large_image">
218 <meta property="twitter:url" content="${baseUrl}">
219 <meta property="twitter:title" content="${escapeHtml(config.blog_title)}">
225 <link rel="alternate" type="application/activity+json" href="${baseUrl}/actor" />
226 <!-- Favicon -->
227 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>${config.blog_icon}</text></svg>">
228
229 <!-- Styles -->
319
320 <!-- Twitter -->
321 <meta property="twitter:card" content="summary_large_image">
322 <meta property="twitter:url" content="${postUrl}">
323 <meta property="twitter:title" content="${escapeHtml(post.title)}">
329
330 <!-- Favicon -->
331 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>${config.blog_icon}</text></svg>">
332
333 <!-- Styles -->
1417 icon: follower.actor_icon_url
1418 ? {
1419 type: "Image",
1420 url: follower.actor_icon_url,
1421 }
1454 icon: follower.actor_icon_url
1455 ? {
1456 type: "Image",
1457 url: follower.actor_icon_url,
1458 }
1750});
1751
1752// ===== IMAGE ROUTES =====
1753
1754// Serve image upload page
1755app.get("/upload", async c => {
1756 try {
1769 <div class="max-w-md mx-auto bg-white rounded-lg shadow-md p-6 text-center">
1770 <h1 class="text-2xl font-bold text-gray-900 mb-4">Upload Disabled</h1>
1771 <p class="text-gray-600 mb-4">Image upload is currently disabled.</p>
1772 <p class="text-sm text-gray-500">Administrator: Set the UPLOAD_PASSWORD environment variable to enable uploads.</p>
1773 <a href="/" class="text-blue-600 hover:text-blue-800 text-sm">← Back to Blog</a>
1922});
1923
1924// Serve images
1925app.get("/images/:filename", async c => {
1926 try {
1927 await ensureDbInitialized();
1928 const filename = c.req.param("filename");
1929
1930 const imageData = await getImageData(filename);
1931 if (!imageData) {
1932 return c.text("Image not found", 404);
1933 }
1934
1935 // Return the image data as a proper Response
1936 return new Response(imageData.data, {
1937 headers: {
1938 "Content-Type": imageData.mimeType,
1939 "Cache-Control": "public, max-age=31536000", // Cache for 1 year
1940 },
1941 });
1942 } catch (error) {
1943 console.error("Error serving image:", error);
1944 return c.text("Error serving image", 500);
1945 }
1946});
1947
1948// Upload image endpoint
1949app.post("/api/images/upload", async c => {
1950 try {
1951 await ensureDbInitialized();
1953 // Get the uploaded file and form data
1954 const body = await c.req.formData();
1955 const file = body.get("image") as File;
1956 const password = body.get("password") as string;
1957 const uploaderEmail = body.get("email") as string;
1960
1961 if (!file) {
1962 return c.json({ error: "No image file provided" }, 400);
1963 }
1964
1979 console.log(`✅ Valid upload password from ${uploaderEmail}`);
1980
1981 // Store the image
1982 const image = await storeImageFromFile(file, uploaderEmail, {
1983 altText: altText || undefined,
1984 postSlug: postSlug || undefined,
1986
1987 const baseUrl = getBaseUrl(c);
1988 const imageUrl = getImageUrl(image.filename, baseUrl);
1989
1990 return c.json({
1991 success: true,
1992 image: {
1993 id: image.id,
1994 filename: image.filename,
1995 originalFilename: image.original_filename,
1996 url: imageUrl,
1997 mimeType: image.mime_type,
1998 fileSize: image.file_size,
1999 altText: image.alt_text,
2000 postSlug: image.post_slug,
2001 createdAt: image.created_at,
2002 },
2003 });
2004 } catch (error) {
2005 console.error("Error uploading image:", error);
2006 return c.json({ error: error.message || "Failed to upload image" }, 500);
2007 }
2008});
2009
2010// Get images for a specific post
2011app.get("/api/posts/:slug/images", async c => {
2012 try {
2013 await ensureDbInitialized();
2014 const slug = c.req.param("slug");
2015
2016 const images = await getImagesByPostSlug(slug);
2017 const baseUrl = getBaseUrl(c);
2018
2019 return c.json({
2020 images: images.map(image => ({
2021 id: image.id,
2022 filename: image.filename,
2023 originalFilename: image.original_filename,
2024 url: getImageUrl(image.filename, baseUrl),
2025 mimeType: image.mime_type,
2026 fileSize: image.file_size,
2027 altText: image.alt_text,
2028 createdAt: image.created_at,
2029 })),
2030 });
2031 } catch (error) {
2032 console.error("Error fetching post images:", error);
2033 return c.json({ error: "Failed to fetch images" }, 500);
2034 }
2035});
2036
2037// Get images uploaded by a user
2038app.get("/api/images/user/:email", async c => {
2039 try {
2040 await ensureDbInitialized();
2047 }
2048
2049 const images = await getImagesByUser(email);
2050 const baseUrl = getBaseUrl(c);
2051
2052 return c.json({
2053 images: images.map(image => ({
2054 id: image.id,
2055 filename: image.filename,
2056 originalFilename: image.original_filename,
2057 url: getImageUrl(image.filename, baseUrl),
2058 mimeType: image.mime_type,
2059 fileSize: image.file_size,
2060 altText: image.alt_text,
2061 postSlug: image.post_slug,
2062 createdAt: image.created_at,
2063 })),
2064 });
2065 } catch (error) {
2066 console.error("Error fetching user images:", error);
2067 return c.json({ error: "Failed to fetch images" }, 500);
2068 }
2069});
2070
2071// Delete an image
2072app.delete("/api/images/:filename", async c => {
2073 try {
2074 await ensureDbInitialized();
2080 }
2081
2082 const success = await deleteImageCompletely(filename);
2083
2084 if (!success) {
2085 return c.json({ error: "Image not found" }, 404);
2086 }
2087
2088 return c.json({ success: true, message: "Image deleted successfully" });
2089 } catch (error) {
2090 console.error("Error deleting image:", error);
2091 return c.json({ error: "Failed to delete image" }, 500);
2092 }
2093});
2094
2095// Get all images (admin endpoint)
2096app.get("/api/images", async c => {
2097 try {
2098 await ensureDbInitialized();
2106 const offset = parseInt(c.req.query("offset") || "0");
2107
2108 const images = await getAllImages(limit, offset);
2109 const baseUrl = getBaseUrl(c);
2110
2111 return c.json({
2112 images: images.map(image => ({
2113 id: image.id,
2114 filename: image.filename,
2115 originalFilename: image.original_filename,
2116 url: getImageUrl(image.filename, baseUrl),
2117 mimeType: image.mime_type,
2118 fileSize: image.file_size,
2119 altText: image.alt_text,
2120 postSlug: image.post_slug,
2121 uploadedByEmail: image.uploaded_by_email,
2122 createdAt: image.created_at,
2123 })),
2124 pagination: {
2125 limit,
2126 offset,
2127 hasMore: images.length === limit,
2128 },
2129 });
2130 } catch (error) {
2131 console.error("Error fetching all images:", error);
2132 return c.json({ error: "Failed to fetch images" }, 500);
2133 }
2134});
2135
2136// Serve images from blob storage
2137app.get("/images/:filename", async c => {
2138 try {
2139 const filename = c.req.param("filename");
2143 }
2144
2145 console.log(`📷 Serving image: ${filename}`);
2146
2147 const imageData = await getImageData(filename);
2148
2149 if (!imageData) {
2150 console.log(`❌ Image not found: ${filename}`);
2151 return c.text("Image not found", 404);
2152 }
2153
2154 console.log(`✅ Image found: ${filename}, size: ${imageData.data.length} bytes, type: ${imageData.mimeType}`);
2155
2156 // Set appropriate headers
2157 const headers = {
2158 "Content-Type": imageData.mimeType,
2159 "Content-Length": imageData.data.length.toString(),
2160 "Cache-Control": "public, max-age=31536000", // Cache for 1 year
2161 "ETag": `"${filename}"`,
2162 };
2163
2164 return new Response(imageData.data, { headers });
2165 } catch (error) {
2166 console.error("Error serving image:", error);
2167 return c.text("Error serving image", 500);
2168 }
2169});

iiif44tumain.tsx10 matches

@sammeltassenUpdated 1 day ago
13}
14
15function createManifest(images: any[], label: string, uuid: string) {
16 const builder = new IIIFBuilder();
17 const id = iiifBaseUrl + uuid;
31 profile: "https://djehuty.4tu.nl/#x1-490005",
32 }]);
33 if (images.length) {
34 for (const [index, item] of images.entries()) {
35 manifest.createCanvas(id + "/canvas/" + item.meta.uuid, (canvas) => {
36 canvas.height = item.height;
39 canvas.addRendering({
40 id: item.meta.download_url,
41 type: "Image",
42 label: { "en": ["Download original image"] },
43 format: "image/tiff",
44 });
45 canvas.createAnnotation(id + "/annotation/" + item.meta.uuid, {
49 body: {
50 id: item.id + "/full/max/0/default.jpg",
51 type: "Image",
52 format: "image/jpeg",
53 height: item.height,
54 width: item.width,
83 return Response.json({ error: "Please provide a valid identifier" });
84 }
85 const images = await Promise.all(
86 metadata.files.map((i: any) =>
87 fetchJson(iiifBaseUrl + i.uuid + "/info.json").then((resp) => {
96 );
97 const manifest = createManifest(
98 images.filter((img: any) => img),
99 metadata.title,
100 datasetUuid,

gesturemain.ts1 match

@knowUpdated 1 day ago
219 onFrame: async () => {
220 if (videoElement.readyState >= 3) {
221 await hands.send({ image: videoElement });
222 }
223 },

FFS_Frame_Custom_actionsmain.ts4 matches

@isakarimUpdated 1 day ago
137 ],
138 };
139 case "generate.image":
140 return {
141 title: "Generate Image",
142 description: "Firefly text-to-image.",
143 fields: [{
144 type: "textarea",
151 return {
152 title: "Remove Background",
153 description: "Remove the background of the selected image.",
154 fields: [{
155 type: "boolean",

Townie-Al2val-summary.ts3 matches

@prubeandoAlUpdated 2 days ago
16 SUM(cache_write_tokens) as total_cache_write_tokens,
17 SUM(price) as total_price,
18 SUM(num_images) as total_images
19 FROM ${USAGE_TABLE}
20 WHERE val_id = ? AND our_api_token = 1
54 total_cache_write_tokens: 0,
55 total_price: 0,
56 total_images: 0
57 };
58
85 // Always include inference price for comparison
86 inference_price: inferenceSummary.inference_price || 0,
87 total_images: usageSummary.total_images,
88 // Add flag to indicate inference data usage
89 used_inference_data: !!inferenceSummary.inference_price,

Townie-Al2val-detail.ts6 matches

@prubeandoAlUpdated 2 days ago
17 price?: number;
18 finish_reason?: string;
19 num_images?: number;
20 our_api_token: boolean;
21}
31 inference_price: number;
32 original_price?: number;
33 total_images: number;
34 used_inference_data?: boolean;
35 inference_price_primary?: boolean;
66 <th>Cache Write</th>
67 <th>Total Price</th>
68 <th>Images</th>
69 </tr>
70 </thead>
76 <td>${formatNumber(summary.total_cache_write_tokens)}</td>
77 <td class="price">${formatPrice(summary.total_price)}</td>
78 <td>${formatNumber(summary.total_images)}</td>
79 </tr>
80 </tbody>
97 <th>Price</th>
98 <th>Finish</th>
99 <th>Images</th>
100 </tr>
101 </thead>
114 <td class="price">${formatPrice(row.price)}</td>
115 <td>${row.finish_reason || '-'}</td>
116 <td>${formatNumber(row.num_images)}</td>
117 </tr>
118 `).join("")}

Townie-Al2user-summary.ts2 matches

@prubeandoAlUpdated 2 days ago
18 SUM(cache_write_tokens) as total_cache_write_tokens,
19 SUM(price) as total_price,
20 SUM(num_images) as total_images
21 FROM ${USAGE_TABLE}
22 WHERE our_api_token = 1
151 total_price: userData.price,
152 inference_price: inferencePriceByUser.get(userId) || 0,
153 total_images: 0,
154 used_inference_data: true
155 });

Townie-Al2user-detail.ts7 matches

@prubeandoAlUpdated 2 days ago
13 total_price: number;
14 inference_price: number;
15 total_images: number;
16 used_inference_data?: boolean;
17}
32 price?: number;
33 finish_reason?: string;
34 num_images?: number;
35 our_api_token: boolean;
36}
48 total_price: 0,
49 inference_price: 0,
50 total_images: 0
51 };
52
77 <th>Total Price</th>
78 <th>Inference Price</th>
79 <th>Images</th>
80 </tr>
81 </thead>
88 <td class="price">${formatPrice(userData.total_price)} ${userData.used_inference_data ? '<span class="badge badge-info" title="Using inference data">I</span>' : ''}</td>
89 <td class="price">${formatPrice(userData.inference_price || 0)}</td>
90 <td>${formatNumber(userData.total_images)}</td>
91 </tr>
92 </tbody>
135 <th>Price</th>
136 <th>Finish</th>
137 <th>Images</th>
138 </tr>
139 </thead>
152 <td class="price">${formatPrice(row.price)}</td>
153 <td>${row.finish_reason || '-'}</td>
154 <td>${formatNumber(row.num_images)}</td>
155 </tr>
156 `).join("")}

Townie-Al2useChatLogic.ts4 matches

@prubeandoAlUpdated 2 days ago
7 branchId: string | undefined;
8 selectedFiles: string[];
9 images: (string | null)[];
10 soundEnabled: boolean;
11}
20 // bearerToken,
21 selectedFiles,
22 images,
23 soundEnabled,
24}: UseChatLogicProps) {
44 branchId,
45 selectedFiles,
46 images: images
47 .filter((img): img is string => {
48 const isValid = typeof img === "string" && img.startsWith("data:");
49 if (!isValid && img !== null) {
50 console.warn(
51 "Invalid image format:",
52 img?.substring(0, 50) + "..."
53 );

ImageThing

@refactorizedUpdated 2 days ago

Gemini-Image-Banana-012 file matches

@aibotcommanderUpdated 3 days ago
Chrimage
Atiq
"Focal Lens with Atig Wazir" "Welcome to my photography journey! I'm Atiq Wazir, a passionate photographer capturing life's beauty one frame at a time. Explore my gallery for stunning images, behind-the-scenes stories, and tips & tricks to enhance your own