triflix/gemini-functioncall
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8" />5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />6 <title>Upload Images for Generative AI</title>7 <script src="https://cdn.tailwindcss.com"></script>8 <!-- Marked library to render markdown results -->9 <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>10</head>11<body class="bg-gray-100">12 <div class="container mx-auto p-4">13 <h1 class="text-3xl font-bold text-center mb-6">Upload Images</h1>14 <div class="flex flex-col items-center">15 <!-- Upload/Paste Area -->16 <div id="upload-area" class="border-2 border-dashed border-gray-400 p-8 rounded w-full sm:w-11/12 md:w-3/4 lg:w-1/2 bg-white">17 <p class="mb-4 text-center">18 Paste images with <strong>Ctrl + V</strong> or click "Add Image".19 </p>20 <input type="file" id="fileInput" name="files" accept="image/*" multiple class="hidden" />21 <button id="addImageBtn" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mb-4">22 Add Image23 </button>24 <!-- Thumbnails container -->25 <div id="thumbnails" class="flex flex-wrap gap-4"></div>26 </div>27 28 <!-- Send Button -->29 <div class="mt-6">30 <button id="sendBtn" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">31 Send32 </button>33 </div>34 35 <!-- Result Display -->36 <div id="resultArea" class="mt-6 w-full sm:w-11/12 md:w-3/4 lg:w-1/2 overflow-x-auto"></div>37 </div>38 </div>39 40 <!-- Popup Card for First Time -->41 <div id="popupCard" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">42 <div class="bg-white rounded-lg p-6 w-11/12 sm:max-w-md mx-auto shadow-2xl transform transition-all duration-300">43 <div class="mb-4">44 <h2 class="text-2xl font-bold">๐ Hey, I'm Aditya Devarshi</h2>45 <p class="mt-2 text-gray-700">I'm an AI Engineer ๐ค, here to help with your assignments ๐, support multiple images ๐ท, and provide keyboard shortcuts โจ๏ธ.</p>46 <p class="mt-2 text-gray-700">Connect with me:</p>47 <ul class="list-disc list-inside mt-2 text-blue-600">48 <li><a href="https://www.adityadevarshi.online/" target="_blank">๐ Website</a></li>49 <li><a href="https://www.linkedin.com/in/aditya-devarshi/" target="_blank">๐ LinkedIn</a></li>50 <li><a href="https://github.com/devarshiadi" target="_blank">๐ GitHub</a></li>51 <li><a href="https://medium.com/@devarshia5" target="_blank">โ๏ธ Medium</a></li>52 </ul>53 </div>54 <div class="text-right">55 <button id="closePopup" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">56 Close57 </button>58 </div>59 </div>60 </div>61 62 <script>63 const fileInput = document.getElementById('fileInput');64 const addImageBtn = document.getElementById('addImageBtn');65 const thumbnails = document.getElementById('thumbnails');66 const sendBtn = document.getElementById('sendBtn');67 const resultArea = document.getElementById('resultArea');68 69 // Array to hold selected image files.70 let selectedFiles = [];71 72 // Trigger file input when Add Image button is clicked.73 addImageBtn.addEventListener('click', () => {74 fileInput.click();75 });76 77 // Handle file selection.78 fileInput.addEventListener('change', () => {79 for (let file of fileInput.files) {80 selectedFiles.push(file);81 addThumbnail(file);82 }83 fileInput.value = ""; // reset input84 });85 86 // Function to add image thumbnail.87 function addThumbnail(file) {88 const reader = new FileReader();89 reader.onload = function(e) {90 const thumbContainer = document.createElement('div');91 thumbContainer.classList.add('relative');92 thumbContainer.innerHTML = `93 <img src="${e.target.result}" alt="${file.name}" class="w-24 h-24 object-cover rounded border" />94 <button class="removeBtn absolute -top-2 -right-2 bg-red-500 text-white rounded-full px-1 text-xs">x</button>95 `;96 thumbnails.appendChild(thumbContainer);97 98 // Remove image on click.99 thumbContainer.querySelector('.removeBtn').addEventListener('click', () => {100 selectedFiles = selectedFiles.filter(f => f !== file);101 thumbContainer.remove();102 });103 }104 reader.readAsDataURL(file);105 }106 107 // Listen for paste events (Ctrl+V) to add images.108 window.addEventListener('paste', (event) => {109 const items = event.clipboardData.items;110 for (let item of items) {111 if (item.type.indexOf("image") !== -1) {112 const file = item.getAsFile();113 selectedFiles.push(file);114 addThumbnail(file);115 }116 }117 });118 119 // Handle Send button click.120 sendBtn.addEventListener('click', async () => {121 if (selectedFiles.length === 0) {122 alert("Please add at least one image.");123 return;124 }125 const formData = new FormData();126 selectedFiles.forEach(file => {127 formData.append('files', file);128 });129 resultArea.innerHTML = `<p class="text-gray-500">Processing...</p>`;130 try {131 const response = await fetch('/upload', {132 method: 'POST',133 body: formData134 });135 const data = await response.json();136 if (response.ok && data.result) {137 // Convert markdown result to HTML using marked.parse138 resultArea.innerHTML = `<div class="bg-gray-200 p-4 rounded whitespace-pre-wrap">${marked.parse(data.result)}</div>`;139 // Reset the UI.140 selectedFiles = [];141 thumbnails.innerHTML = "";142 } else {143 resultArea.innerHTML = `<p class="text-red-500">${data.detail || 'No result received.'}</p>`;144 }145 } catch (error) {146 resultArea.innerHTML = `<p class="text-red-500">Error processing the images: ${error.message}</p>`;147 }148 });149 150 // Show popup only if it hasn't been shown before151 if (!localStorage.getItem('popupShown')) {152 document.getElementById('popupCard').style.display = 'flex';153 } else {154 document.getElementById('popupCard').style.display = 'none';155 }156 document.getElementById('closePopup').addEventListener('click', function() {157 document.getElementById('popupCard').style.display = 'none';158 localStorage.setItem('popupShown', 'true');159 });160 </script>161</body>162</html>163 