110 return new Response(ppmData, {
111 headers: {
112 "Content-Type": "image/x-portable-pixmap",
113 "Content-Disposition": `attachment; filename="${key}.ppm"`
114 }
2import React from "https://esm.sh/react";
3import { renderToString } from "https://esm.sh/react-dom/server";
4import generateImageFromHtml from "https://esm.town/v/michaelwschultz/generateImageFromHtml";
5
6export default async function(req: Request) {
7 const url = new URL(req.url);
8 const isImageRequest = url.searchParams.get("generate") === "image";
9 const isListRequest = url.searchParams.get("generate") === "list";
10 const frameId = url.searchParams.get("frame");
45 }
46
47 // get ?&generate=image&frame=S0mth1ingKrAzy
48 if (frameId && !frame_list.includes(frameId)) {
49 const html = renderToString(
60 }
61
62 // get ?&generate=image&frame=weather
63 if (isImageRequest) {
64 const generateUrl = frames[frameId as keyof typeof frames];
65 const width = 800;
66 const height = 480;
67
68 const imageResponse = await generateImageFromHtml(generateUrl, width, height);
69 return new Response(imageResponse.body, {
70 status: imageResponse.status,
71 headers: {
72 "Content-Type": "image/png",
73 "Cache-Control": "no-store, max-age=0",
74 },
8 service_version: string;
9 title: string;
10 url: string; // image to display
11};
12
10 href="/public/favicon.svg"
11 sizes="any"
12 type="image/svg+xml"
13 >
14 </head>
1/** @jsxImportSource https://esm.sh/react@18.2.0?dev */
2import React, { useEffect, useRef, useState } from "https://esm.sh/react@18.2.0?dev";
3import { ImageUpload, processFiles } from "./ImageUpload.tsx";
4
5interface ChatInputProps {
8 handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
9 running: boolean;
10 images: (string | null)[];
11 setImages: React.Dispatch<React.SetStateAction<(string | null)[]>>;
12 isDragging: boolean;
13}
18 handleSubmit,
19 running,
20 images,
21 setImages,
22 isDragging,
23}: ChatInputProps) {
43 const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
44 e.preventDefault();
45 const validImages = images.filter((img): img is string => typeof img === "string");
46 console.log("Submitting with images:", validImages);
47 if (input.trim() || validImages.length > 0) {
48 handleSubmit(e);
49 setImages([]);
50 }
51 };
52
53 const handleProcessFiles = (files: File[]) => {
54 processFiles(files, images, setImages);
55 };
56
61 disabled={running}
62 >
63 {images.length > 0 && (
64 <ImageUpload
65 images={images}
66 setImages={setImages}
67 processFiles={handleProcessFiles}
68 />
82 if (e.key === "Enter" && !e.shiftKey && !isMobile) {
83 e.preventDefault();
84 if (input.trim() || images.filter(Boolean).length > 0) {
85 handleFormSubmit(e as any);
86 }
103 }
104 }}
105 accept="image/*"
106 multiple
107 className="hidden"
139 </div>
140
141 {/* Attach images button below textarea */}
142 {!running && (
143 <div className="flex justify-start mt-1 mb-2">
150 }
151 }}
152 title="Attach images"
153 >
154 <span>📎</span> Attach images
155 </button>
156 </div>
162 <div className="bg-white p-6 rounded-lg shadow-lg text-center">
163 <div className="text-2xl mb-2">📁</div>
164 <div className="text-xl font-semibold">Drop images here</div>
165 </div>
166 </div>
9 bearerToken: string;
10 selectedFiles: string[];
11 images: (string | null)[];
12 soundEnabled: boolean;
13}
19 bearerToken,
20 selectedFiles,
21 images,
22 soundEnabled,
23}: UseChatLogicProps) {
41 anthropicApiKey,
42 selectedFiles,
43 images: images
44 .filter((img): img is string => {
45 const isValid = typeof img === "string" && img.startsWith("data:");
46 if (!isValid && img !== null) {
47 console.warn("Invalid image format:", img?.substring(0, 50) + "...");
48 }
49 return isValid;
14 - [x] File write as a code embed
15 - [x] str_replace as a diff view
16- [x] make image drop area invisible and bigger
17- [x] Give it all the code (except maybe .txt files) as initial context (like cursor sonnet max)
18- [x] I seem to have lost the delete file tool and instructions, try to find them back in history or re-create?
12- If a section of code that you're working on is getting too complex, consider refactoring it into subcomponents
13
14## Image Handling
15
16- When users upload images, carefully analyze them to understand their content
17- Reference specific details from the images in your responses
18- If multiple images are uploaded, consider their relationship to each other
19- For code-related images (screenshots, diagrams), extract relevant information and incorporate it into your solutions
20- For UI mockups or design images, use them as reference for layout and design, use the colors from the image
21- When images contain text or code, transcribe relevant portions as needed
22- If image content is unclear, ask clarifying questions about what the user wants you to focus on
23
24## Technical Requirements
95## Val Town Platform Specifics
96- **Redirects:** Use `return new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }})` instead of `Response.redirect` which is broken
97- **Images:** Avoid external images or base64 images. Use emojis, unicode symbols, or icon fonts/libraries instead
98- For AI-generated images, use: `https://maxm-imggenurl.web.val.run/the-description-of-your-image`
99- **Storage:** DO NOT use the Deno KV module for storage
100- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
2import { type Message } from "https://esm.sh/@ai-sdk/react?dev&deps=react@18.2.0&react-dom@18.2.0";
3import ReactMarkdown from "https://esm.sh/react-markdown?dev&deps=react@18.2.0&react-dom@18.2.0";
4import { ImagePreview } from "./ImageUpload.tsx";
5
6// Helper function to detect language from file path
235 );
236 }
237 if (part.type === "image") {
238 // Handle both formats: {image: {url: string}} and {image: string}
239 const imageUrl = typeof part.image === 'string'
240 ? part.image
241 : part.image.url || (part.image as any).source?.url;
242
243 return (
244 <div className="mt-2">
245 <img
246 src={imageUrl}
247 alt="Uploaded image"
248 className="max-h-64 max-w-full object-contain rounded"
249 />
251 );
252 }
253 // Handle multiple images in a single part
254 if (part.type === "images") {
255 return <ImagePreview images={part.images.map(img => img.url)} />;
256 }
257}
51 }
52
53 const { messages, project, branchId, anthropicApiKey, selectedFiles, images } = await c.req.json();
54 console.log("Original messages:", JSON.stringify(messages, null, 2));
55 console.log("Images received:", JSON.stringify(images, null, 2));
56
57 // Check if API key is available
79 let coreMessages = convertToCoreMessages(messages);
80
81 // If there are images, we need to add them to the last user message
82 if (images && Array.isArray(images) && images.length > 0) {
83 // Find the last user message
84 const lastUserMessageIndex = coreMessages.findIndex(
103 });
104
105 // Add each image to the content array using the correct ImagePart format
106 for (const image of images) {
107 if (image && image.url) {
108 // Extract mime type from data URL if available
109 let mimeType = undefined;
110 if (image.url.startsWith("data:")) {
111 const matches = image.url.match(/^data:([^;]+);/);
112 if (matches && matches.length > 1) {
113 mimeType = matches[1];
116
117 newUserMessage.content.push({
118 type: "image",
119 image: image.url,
120 mimeType,
121 });