6<title>React Hono Val Town Starter</title>
7<link rel="stylesheet" href="/frontend/style.css">
8<link rel="icon" href="/frontend/favicon.svg" type="image/svg+xml">
9</head>
10<body>
Towniesend-message.ts11 matches
26}
2728const { messages, project, branchId, anthropicApiKey, selectedFiles, images } = await c.req.json();
2930// do we want to allow user-provided tokens still
56branch_id: branchId,
57val_id: project.id,
58num_images: images?.length || 0,
59model,
60});
66let coreMessages = convertToCoreMessages(messages);
6768// If there are images, we need to add them to the last user message
69if (images && Array.isArray(images) && images.length > 0) {
70// Find the last user message
71const lastUserMessageIndex = coreMessages.findIndex(
89};
9091// Add each image to the content array using the correct ImagePart format
92for (const image of images) {
93if (image && image.url) {
94// Extract mime type from data URL if available
95let mimeType = undefined;
96if (image.url.startsWith("data:")) {
97const matches = image.url.match(/^data:([^;]+);/);
98if (matches && matches.length > 1) {
99mimeType = matches[1];
102103newUserMessage.content.push({
104type: "image",
105image: image.url,
106mimeType,
107});
73</div>
74
75<!-- Single Step: Camera/Image Capture + Question -->
76<div class="bg-white rounded-[32px] card-washed-shadow ">
77<div class="camera-container mb-4">
84:disabled="isProcessing"
85class="bg-gray-200 text-black px-4 py-2 rounded-xl hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-400">
86<span class="text-xs font-mono" x-show="!isProcessing">Analyze the Quiz Image!</span>
87<span class="text-xs font-mono" x-show="isProcessing">Processing...</span>
88</button>
107<div x-show="isProcessing" class="flex flex-col items-center justify-center py-8">
108<div class="loading-spinner mb-4"></div>
109<p class="text-gray-600 font-mono">Processing image and answering...</p>
110</div>
111
171canvas.height = videoElement.videoHeight;
172const context = canvas.getContext('2d');
173context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
174const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg'));
175const formData = new FormData();
176formData.append('image_input', blob);
177178const response = await fetch('/api/ask', {
188this.totalTime = data.totalTime;
189} catch (error) {
190alert('Error processing image and question. Please try again.');
191} finally {
192this.isProcessing = false;
216try {
217const formData = await c.req.formData();
218const imageFile = formData.get('image_input');
219220if (!imageFile || !(imageFile instanceof Blob)) {
221return c.json({ error: 'No image file provided' }, 400);
222}
223224// Convert blob to base64
225const arrayBuffer = await imageFile.arrayBuffer();
226const bytes = new Uint8Array(arrayBuffer);
227const base64Image = uint8ToBase64(bytes);
228229// Step 1: OCR
236{
237role: 'system',
238content: 'You are an expert OCR (Optical Character Recognition) assistant. Your task is to extract ALL text from the provided image. Return ONLY the extracted text without any commentary, introductions, or explanations - just the raw text content that you see in the image, preserving paragraph structure when possible.'
239},
240{
243{
244type: 'text',
245text: 'Extract all text from this image. Return only the extracted text without any additional commentary.'
246},
247{
248type: 'image_url',
249image_url: {
250url: `data:image/jpeg;base64,${base64Image}`
251}
252}
kworknew-file-6847.tsx18 matches
34// Функция для работы с API Gemini
5async function geminiImageAnalysis(base64Image: string | null, prompt: string) {
6const GEMINI_API_KEY = Deno.env.get("GEMINI_API_KEY");
720body: JSON.stringify({
21contents: [{
22parts: base64Image
23? [
24{ text: prompt },
25{
26inlineData: {
27mimeType: "image/jpeg",
28data: base64Image,
29},
30},
170Входящее сообщение: ${text}`;
171172const response = await geminiImageAnalysis(null, contextualPrompt);
173console.log("Ответ на текстовое сообщение:", response.slice(0, 200));
174181182// Обработка изображений
183async function processImageMessage(imageBuffer: ArrayBuffer): Promise<string[]> {
184try {
185if (!imageBuffer || imageBuffer.byteLength === 0) {
186return ["Изображение не было корректно загружено."];
187}
188189// Конвертация изображения в base64
190const uint8Array = new Uint8Array(imageBuffer);
191const chunks = [];
192const chunkSize = 8192;
196}
197198const base64Image = btoa(chunks.join(""));
199200const prompt = `Ты профессиональный репетитор.
218Важно: объясняй максимально просто и понятно для ученика 5-9 класса!`;
219220const solution = await geminiImageAnalysis(base64Image, prompt);
221return splitLongText(solution);
222} catch (error) {
2424. Если вопрос не задан, сделай общий обзор содержания`;
243244const response = await geminiImageAnalysis(base64Pdf, contextPrompt);
245return splitLongText(response);
246} catch (error) {
366if (photo && photo.length > 0) {
367const largestPhoto = photo[photo.length - 1];
368const imageBuffer = await downloadTelegramFile(largestPhoto.file_id);
369370if (imageBuffer) {
371const responseParts = await processImageMessage(imageBuffer);
372for (const part of responseParts) {
373await sendTelegramMessage(chatId, part);
377378// Обработка изображений в формате документа
379if (document && (document.mime_type === "image/jpeg" || document.mime_type === "image/png")) {
380const imageBuffer = await downloadTelegramFile(document.file_id);
381382if (imageBuffer) {
383const responseParts = await processImageMessage(imageBuffer);
384for (const part of responseParts) {
385await sendTelegramMessage(chatId, part);
reactHonoExampleREADME.md1 match
3It's common to have code and types that are needed on both the frontend and the backend. It's important that you write this code in a particularly defensive way because it's limited by what both environments support:
45
67For example, you *cannot* use the `Deno` keyword. For imports, you can't use `npm:` specifiers, so we reccomend `https://esm.sh` because it works on the server & client. You *can* use TypeScript because that is transpiled in `/backend/index.ts` for the frontend. Most code that works on the frontend tends to work in Deno, because Deno is designed to support "web-standards", but there are definitely edge cases to look out for.
reactHonoExampleREADME.md1 match
21## `favicon.svg`
2223As of this writing Val Town only supports text files, which is why the favicon is an SVG and not an .ico or any other binary image format. If you need binary file storage, check out [Blob Storage](https://docs.val.town/std/blob/).
2425## `components/`
reactHonoExampleindex.html1 match
6<title>React Hono Val Town Starter</title>
7<link rel="stylesheet" href="/public/style.css">
8<link rel="icon" href="/public/favicon.svg" sizes="any" type="image/svg+xml">
9</head>
10<body>
reactHonoStarterindex.html1 match
6<title>React Hono Val Town Starter</title>
7<link rel="stylesheet" href="/frontend/style.css">
8<link rel="icon" href="/frontend/favicon.svg" type="image/svg+xml">
9</head>
10<body>
myNewWebsiteindex.html1 match
6<title>React Hono Val Town Starter</title>
7<link rel="stylesheet" href="/frontend/style.css">
8<link rel="icon" href="/frontend/favicon.svg" type="image/svg+xml">
9</head>
10<body>
3_It's a tool that sends a daily email that shows everyone who you follow on Bluesky who has updated their profile in the last day. You can Remix it on Val Town (this website), tweak a few environnment variables, and it'll be yours!_ Here's what an email looks like with a person's description update:
45
67## Setup