Spaces:
Running
Running
| <html lang="fa" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>🪐 ویـرایشگر تصویر هوش مصنوعی امـید (کد منبع)</title> | |
| <!-- Tailwind CSS for modern, mobile-first styling --> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| /* --- فونتها: استفاده از فونت بی رویـا (B Roya) برای ظاهر فارسی بهتر --- */ | |
| @font-face { | |
| font-family: 'B Roya'; | |
| src: url('https://cdn.fontcdn.ir/Font/Persian/Roya/BRoya.woff') format('woff'); | |
| font-weight: normal; | |
| font-style: normal; | |
| } | |
| @font-face { | |
| font-family: 'B Roya'; | |
| src: url('https://cdn.fontcdn.ir/Font/Persian/Roya/BRoyaBold.woff') format('woff'); | |
| font-weight: bold; | |
| font-style: normal; | |
| } | |
| /* --- متغیرهای جهتدهی بر اساس زبان انتخاب شده --- */ | |
| :root { | |
| --text-direction: ltr; | |
| --text-align: left; | |
| } | |
| [lang="fa"] { | |
| --text-direction: rtl; | |
| --text-align: right; | |
| } | |
| body { | |
| font-family: 'B Roya', Tahoma, 'Inter', 'sans-serif'; | |
| direction: var(--text-direction); | |
| background-color: #000000; /* حالت تیره مطلق برای پسزمینه */ | |
| color: #e5e7eb; | |
| } | |
| /* --- استایل اسکرولبار --- */ | |
| .chat-container::-webkit-scrollbar { width: 5px; } | |
| .chat-container::-webkit-scrollbar-track { background: #050505; } | |
| .chat-container::-webkit-scrollbar-thumb { border-radius: 10px; background-color: #334155; } | |
| /* --- انیمیشن بارگذاری --- */ | |
| .spinner { | |
| border: 2px solid rgba(255, 255, 255, 0.1); | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 50%; | |
| border-left-color: #3b82f6; | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } | |
| /* --- اشکال حبابهای چت برای راست به چپ (RTL) و چپ به راست (LTR) --- */ | |
| .user-bubble { | |
| border-bottom-left-radius: 0; | |
| border-bottom-right-radius: 0.75rem; | |
| } | |
| [dir="rtl"] .user-bubble { | |
| border-bottom-left-radius: 0.75rem; | |
| border-bottom-right-radius: 0; | |
| } | |
| .model-bubble { | |
| border-bottom-right-radius: 0; | |
| border-bottom-left-radius: 0.75rem; | |
| } | |
| [dir="rtl"] .model-bubble { | |
| border-bottom-right-radius: 0.75rem; | |
| border-bottom-left-radius: 0; | |
| } | |
| </style> | |
| <script> | |
| // پیکربندی Tailwind برای تم تیره سفارشی | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| 'primary-blue': '#3b82f6', | |
| 'gemini-green': '#00bfa5', | |
| 'dark-bg': '#020617', /* آبی/مشکی بسیار تیره */ | |
| 'dark-card': '#0f172a', /* Slate 900 */ | |
| 'darker-input': '#1e293b' /* Slate 800 */ | |
| }, | |
| fontSize: { | |
| 'xxs': '0.65rem', | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| </head> | |
| <body class="min-h-screen flex flex-col antialiased selection:bg-primary-blue selection:text-white overflow-hidden"> | |
| <div id="app" class="flex flex-col w-full max-w-7xl mx-auto h-screen border-x border-gray-900 relative bg-black"> | |
| <!-- هدر (شیک و مینیمال) --> | |
| <header class="px-4 py-3 bg-dark-card/90 backdrop-blur-md border-b border-gray-800 z-20 flex justify-between items-center"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-7 h-7 bg-gradient-to-br from-blue-700 to-indigo-800 rounded-lg flex items-center justify-center text-xs shadow-lg shadow-blue-900/30">🪐</div> | |
| <div> | |
| <h1 class="text-sm font-bold text-gray-200 tracking-wide opacity-90" data-en="Gemini AI Image Editor" data-fa="ویـرایشگر تصویر هوش مصنوعی امـید">ویـرایشگر تصویر هوش مصنوعی امـید</h1> | |
| </div> | |
| </div> | |
| <!-- انتخاب زبان --> | |
| <select id="language-selector" onchange="setLanguage(this.value)" | |
| class="px-2 py-1 text-[10px] rounded bg-gray-800 text-gray-400 border border-gray-700 focus:border-primary-blue outline-none transition hover:bg-gray-700 cursor-pointer"> | |
| <option value="fa">فارسی</option> | |
| <option value="en">English</option> | |
| </select> | |
| </header> | |
| <!-- نوار ابزار (دکمههای پرامپت آماده و هوش مصنوعی) --> | |
| <div id="tools-bar" class="px-3 py-2 bg-black flex flex-wrap gap-2 justify-center border-b border-gray-900 z-10"> | |
| <!-- دکمه پیشنهاد پرامپت با هوش مصنوعی --> | |
| <button id="suggest-prompt-btn" onclick="generateSuggestedPrompt()" | |
| class="flex items-center gap-1.5 px-3 py-1 text-[10px] font-medium rounded-full bg-gray-900 border border-gray-800 text-gray-400 hover:bg-gray-800 hover:text-white hover:border-gray-600 disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-200" | |
| disabled | |
| title="ابتدا باید تصویر پیوست کنید"> | |
| <svg class="w-3 h-3 text-gemini-green" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.41 | |
| 4-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg> | |
| <span data-en="Auto-Prompt" data-fa="هوش مصنوعی">هوش مصنوعی</span> | |
| </button> | |
| <!-- منوی انتخاب پرامپتهای آماده --> | |
| <div class="relative group"> | |
| <select id="ready-made-prompts" onchange="useReadyMadePrompt(this.value)" | |
| class="appearance-none pl-3 pr-6 py-1 text-[10px] font-medium rounded-full bg-gray-900 text-gray-400 border border-gray-800 hover:border-gray-600 focus:ring-1 focus:ring-primary-blue outline-none transition cursor-pointer w-48 truncate text-center"> | |
| <option value="" disabled selected data-en="📂 Select Style..." data-fa="📂 انتخاب سبک...">📂 انتخاب سبک...</option> | |
| <optgroup label="📸 عکاسی حرفهای" data-label-en="📸 Photography Pro" data-label-fa="📸 عکاسی حرفهای"> | |
| <option value="Hyper-realistic portrait, 85mm lens, f/1.2, bokeh, studio lighting, 8k" data-en="Portrait 85mm" data-fa="پرتره (85mm)">پرتره (85mm)</option> | |
| <option value="Wide angle landscape, 16mm, golden hour, dramatic clouds, sharp" data-en="Landscape 16mm" data-fa="منظره (16mm)">منظره (16mm)</option> | |
| <option value="Macro photography eye, extreme detail, reflections, sharp focus" data-en="Macro Eye" data-fa="ماکرو (چشم)">ماکرو (چشم)</option> | |
| </optgroup> | |
| <optgroup label="🎨 سبکهای هنری" data-label-en="🎨 Art Styles" data-label-fa="🎨 سبکهای هنری"> | |
| <option value="Oil painting, impasto style, thick brushstrokes, vibrant palette" data-en="Oil Painting" data-fa="رنگ روغن (غلیظ)">رنگ روغن (غلیظ)</option> | |
| <option value="Watercolor illustration, ink lines, pastel colors, minimalist" data-en="Watercolor" data-fa="آبرنگ و جوهر">آبرنگ و جوهر</option> | |
| <option value="Cyberpunk digital art, neon lights, glitch effect, futuristic" data-en="Cyberpunk" data-fa="سایبرپانک">سایبرپانک</option> | |
| <option value="Pencil sketch, charcoal shading, rough paper texture" data-en="Sketch" data-fa="طراحی مداد">طراحی مداد</option> | |
| </optgroup> | |
| <optgroup label="🛠️ ویرایش" data-label-en="🛠️ Edit" data-label-fa="🛠️ ویرایش"> | |
| <option value="Make it winter, snow, ice, cold blue lighting" data-en="Winter" data-fa="زمستان (برفی)">زمستان (برفی)</option> | |
| <option value="Change background to sunset beach, warm lighting" data-en="Sunset Beach" data-fa="ساحل غروب">ساحل غروب</option> | |
| <option value="Turn into marble statue, classical style" data-en="Statue" data-fa="مجسمه سنگی">مجسمه سنگی</option> | |
| </optgroup> | |
| </select> | |
| <div class="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none text-gray-600 rtl:right-auto rtl:left-0"> | |
| <svg class="w-2.5 h-2.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- محفظه چت (محل نمایش تعاملات) --> | |
| <main id="chat-container" class="flex-grow overflow-y-auto p-3 space-y-4 pb-28 bg-black relative"> | |
| <!-- پیام خوش آمدگویی (توسط جاوااسکریپت تزریق میشود) --> | |
| <div class="flex justify-start w-full"> | |
| <div id="welcome-message" class="bg-dark-card text-gray-400 p-3 rounded-2xl model-bubble max-w-sm border border-gray-800/50 shadow-md text-xs leading-5"> | |
| <!-- Content injected via JS --> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- ناحیه ورودی --> | |
| <div class="absolute bottom-0 left-0 right-0 p-2 bg-black/95 backdrop-blur-xl border-t border-gray-900 z-30"> | |
| <div class="max-w-4xl mx-auto w-full space-y-2"> | |
| <!-- ناحیه پیشنمایش تصویر پیوست شده --> | |
| <div id="image-preview-container" class="hidden px-3 py-2 bg-dark-card rounded-lg border border-gray-800 flex flex-wrap items-center gap-2 animate-fade-in"> | |
| <div class="flex items-center gap-1 text-primary-blue font-bold text-[10px] px-2 py-0.5 bg-blue-900/10 rounded"> | |
| <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg> | |
| <span id="attached-count">0</span> | |
| </div> | |
| <div id="preview-thumbnails" class="flex gap-2 overflow-x-auto"></div> | |
| <button onclick="clearAttachments()" class="ml-auto rtl:ml-0 rtl:mr-auto text-red-400 hover:text-red-300 text-[10px] p-1" data-en="Clear" data-fa="حذف">حذف</button> | |
| </div> | |
| <!-- نوار ورودی اصلی --> | |
| <div class="flex items-end gap-2"> | |
| <!-- دکمه پیوست فایل --> | |
| <label for="file-input" class="p-2 bg-dark-card text-gray-500 hover:text-gray-200 hover:bg-gray-800 rounded-xl cursor-pointer transition-all border border-gray-800 hover:border-gray-700 group" title="پیوست تصویر"> | |
| <svg class="w-4 h-4 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 | |
| 13"></path></svg> | |
| </label> | |
| <input type="file" id="file-input" accept="image/*" class="hidden" multiple onchange="handleFileUpload(event)"> | |
| <!-- جعبه متن پرامپت --> | |
| <div class="relative flex-grow"> | |
| <textarea id="prompt-input" rows="1" | |
| class="w-full bg-darker-input text-gray-200 text-xs rounded-xl px-3 py-2.5 border border-gray-800 focus:border-primary-blue/50 focus:ring-1 focus:ring-primary-blue/50 outline-none resize-none min-h-[40px] max-h-[100px] overflow-y-auto transition-all placeholder-gray-700" | |
| placeholder="ایده خود را بنویسید..." | |
| oninput="autoExpand(this); toggleSendButton();" | |
| onkeydown="handleEnter(event)"></textarea> | |
| </div> | |
| <!-- دکمه ارسال --> | |
| <button id="send-button" onclick="processRequest()" disabled | |
| class="p-2 bg-primary-blue text-white rounded-xl hover:bg-blue-600 disabled:opacity-30 disabled:cursor-not-allowed disabled:bg-gray-800 transition-all shadow-md active:scale-95"> | |
| <svg class="w-4 h-4 rtl:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path></svg> | |
| </button> | |
| </div> | |
| <!-- نمایشگر وضعیت بارگذاری --> | |
| <div id="loading-indicator" class="hidden flex items-center justify-center gap-2 text-[10px] font-medium text-gray-500 bg-dark-card/50 py-0.5 rounded-full w-fit mx-auto px-3 border border-gray-900"> | |
| <div class="spinner w-2.5 h-2.5 border-[1.5px]"></div> | |
| <span id="loading-text" class="animate-pulse">Processing...</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // ================================================================= | |
| // --- تنظیمات API --- | |
| // این متغیرها برای استفاده در محیط Canvas تعریف شدهاند و API Key را از محیط میگیرند. | |
| const apiKey = ""; | |
| // آدرس API برای تولید تصویر (تصاویر جدید) - مدل Imagen | |
| const IMAGEN_URL = "https://generativelanguage.googleapis.com/v1beta/models/imagine-pro:generateContent?key=" + apiKey; | |
| // آدرس API برای ویرایش تصویر (تغییر تصویر موجود) - مدل Gemini Pro Vision | |
| const GEMINI_VISION_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=" + apiKey; | |
| // ================================================================= | |
| // --- تنظیمات اولیه و متغیرهای عمومی --- | |
| let attachedFiles = []; // آرایهای برای نگهداری فایلهای پیوست شده | |
| let currentLanguage = 'fa'; // زبان پیشفرض | |
| // ================================================================= | |
| // --- توابع اصلی --- | |
| // تابع تغییر زبان | |
| function setLanguage(lang) { | |
| currentLanguage = lang; | |
| document.documentElement.lang = lang; | |
| document.documentElement.dir = lang === 'fa' ? 'rtl' : 'ltr'; | |
| // بهروزرسانی تمام المانهای قابل ترجمه | |
| document.querySelectorAll('[data-fa]').forEach(el => { | |
| el.textContent = lang === 'fa' ? el.getAttribute('data-fa') : el.getAttribute('data-en'); | |
| }); | |
| // بهروزرسانی optionهای select | |
| document.querySelectorAll('option[data-fa]').forEach(opt => { | |
| opt.textContent = lang === 'fa' ? opt.getAttribute('data-fa') : opt.getAttribute('data-en'); | |
| }); | |
| // بهروزرسانی labelهای optgroup | |
| document.querySelectorAll('optgroup[data-label-fa]').forEach(group => { | |
| group.label = lang === 'fa' ? group.getAttribute('data-label-fa') : group.getAttribute('data-label-en'); | |
| }); | |
| // بهروزرسانی placeholder | |
| const promptInput = document.getElementById('prompt-input'); | |
| promptInput.placeholder = lang === 'fa' ? 'ایده خود را بنویسید...' : 'Describe your idea...'; | |
| // بهروزرسانی پیام خوشآمدگویی | |
| showWelcomeMessage(); | |
| } | |
| // تابع نمایش پیام خوشآمدگویی | |
| function showWelcomeMessage() { | |
| const welcomeMessage = document.getElementById('welcome-message'); | |
| const messages = { | |
| fa: "سلام! 👋\n\nمن امـید هستم، ویرایشگر تصویر هوش مصنوعی شما.\n\nبرای شروع:\n۱. یک تصویر ضمیمه کنید\n۲. از پرامپتهای آماده استفاده کنید یا ایده خود را توصیف کنید\n۳. روی دکمه ارسال کلیک کنید تا تصویر شما ساخته شود!", | |
| en: "Hello! 👋\n\nI'm Omid, your AI image editor.\n\nTo get started:\n1. Attach an image\n2. Use ready-made prompts or describe your idea\n3. Click send to generate your image!" | |
| }; | |
| welcomeMessage.textContent = messages[currentLanguage]; | |
| } | |
| // تابع مدیریت آپلود فایل | |
| function handleFileUpload(event) { | |
| const files = Array.from(event.target.files); | |
| if (files.length === 0) return; | |
| // اضافه کردن فایلهای جدید به آرایه | |
| attachedFiles.push(...files); | |
| // بهروزرسانی پیشنمایش | |
| updateImagePreview(); | |
| // فعال کردن دکمه پیشنهاد پرامپت | |
| document.getElementById('suggest-prompt-btn').disabled = false; | |
| // پاک کردن input برای امکان آپلود مجدد همان فایل | |
| event.target.value = ''; | |
| } | |
| // تابع بهروزرسانی پیشنمایش تصاویر | |
| function updateImagePreview() { | |
| const container = document.getElementById('image-preview-container'); | |
| const countElement = document.getElementById('attached-count'); | |
| const thumbnailsContainer = document.getElementById('preview-thumbnails'); | |
| if (attachedFiles.length === 0) { | |
| container.classList.add('hidden'); | |
| return; | |
| } | |
| // نمایش تعداد فایلها | |
| countElement.textContent = attachedFiles.length; | |
| // پاک کردن پیشنمایشهای قبلی | |
| thumbnailsContainer.innerHTML = ''; | |
| // ایجاد پیشنمایش برای هر فایل | |
| attachedFiles.forEach((file, index) => { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| const thumb = document.createElement('div'); | |
| thumb.className = 'relative'; | |
| thumb.innerHTML = ` | |
| <img src="${e.target.result}" alt="Preview" class="w-10 h-10 object-cover rounded border border-gray-700"> | |
| <button onclick="removeAttachment(${index})" class="absolute -top-1 -left-1 bg-red-500 text-white rounded-full w-4 h-4 flex items-center justify-center text-[8px]">×</button> | |
| `; | |
| thumbnailsContainer.appendChild(thumb); | |
| }; | |
| reader.readAsDataURL(file); | |
| }); | |
| // نمایش کانتینر | |
| container.classList.remove('hidden'); | |
| } | |
| // تابع حذف یک فایل پیوست شده | |
| function removeAttachment(index) { | |
| attachedFiles.splice(index, 1); | |
| updateImagePreview(); | |
| // غیرفعال کردن دکمه پیشنهاد پرامپت اگر فایلی وجود نداشت | |
| if (attachedFiles.length === 0) { | |
| document.getElementById('suggest-prompt-btn').disabled = true; | |
| } | |
| } | |
| // تابع پاک کردن همه فایلهای پیوست شده | |
| function clearAttachments() { | |
| attachedFiles = []; | |
| updateImagePreview(); | |
| document.getElementById('suggest-prompt-btn').disabled = true; | |
| } | |
| // تابع گسترش خودکار textarea | |
| function autoExpand(textarea) { | |
| textarea.style.height = 'auto'; | |
| textarea.style.height = Math.min(textarea.scrollHeight, 100) + 'px'; | |
| } | |
| // تابع فعال/غیرفعال کردن دکمه ارسال | |
| function toggleSendButton() { | |
| const prompt = document.getElementById('prompt-input').value.trim(); | |
| const sendButton = document.getElementById('send-button'); | |
| sendButton.disabled = prompt.length === 0; | |
| } | |
| // تابع مدیریت Enter در textarea | |
| function handleEnter(event) { | |
| if (event.key === 'Enter' && !event.shiftKey) { | |
| event.preventDefault(); | |
| if (!document.getElementById('send-button').disabled) { | |
| processRequest(); | |
| } | |
| } | |
| } | |
| // تابع تولید پرامپت پیشنهادی با هوش مصنوعی | |
| function generateSuggestedPrompt() { | |
| if (attachedFiles.length === 0) return; | |
| const suggestions = { | |
| fa: [ | |
| "افزودن جرقههای نور به تصویر", | |
| "تبدیل به سبک نقاشی دیجیتال", | |
| "ایجاد افکت باران و مه", | |
| "اضافه کردن پرندههای پرندگان در آسمان", | |
| "تبدیل به سبک کارتونی شدید" | |
| ], | |
| en: [ | |
| "Add light sparks to the image", | |
| "Convert to digital painting style", | |
| "Create rain and fog effects", | |
| "Add flying birds in the sky", | |
| "Convert to strong cartoon style" | |
| ] | |
| }; | |
| const randomSuggestion = suggestions[currentLanguage][Math.floor(Math.random() * suggestions[currentLanguage].length)]; | |
| document.getElementById('prompt-input').value = randomSuggestion; | |
| autoExpand(document.getElementById('prompt-input')); | |
| toggleSendButton(); | |
| } | |
| // تابع استفاده از پرامپت آماده | |
| function useReadyMadePrompt(value) { | |
| if (value) { | |
| document.getElementById('prompt-input').value = value; | |
| autoExpand(document.getElementById('prompt-input')); | |
| toggleSendButton(); | |
| // ریست کردن select به حالت اولیه | |
| document.getElementById('ready-made-prompts').selectedIndex = 0; | |
| } | |
| } | |
| // تابع پردازش درخواست اصلی | |
| async function processRequest() { | |
| const prompt = document.getElementById('prompt-input').value.trim(); | |
| if (!prompt) return; | |
| // نمایش اندیکاتور بارگذاری | |
| document.getElementById('loading-indicator').classList.remove('hidden'); | |
| // ایجاد پیام کاربر | |
| addChatMessage(prompt, 'user'); | |
| // پاک کردن input | |
| document.getElementById('prompt-input').value = ''; | |
| autoExpand(document.getElementById('prompt-input')); | |
| toggleSendButton(); | |
| try { | |
| // شبیهسازی فرآیند تولید تصویر | |
| await new Promise(resolve => setTimeout(resolve, 2000)); | |
| // ایجاد پیام مدل با تصاویر نمونه | |
| const sampleImages = [ | |
| 'http://static.photos/abstract/320x240/1', | |
| 'http://static.photos/abstract/320x240/2' | |
| ]; | |
| addChatMessage(sampleImages, 'model'); | |
| } catch (error) { | |
| console.error('Error:', error); | |
| addChatMessage(currentLanguage === 'fa' ? 'خطا در پردازش درخواست' : 'Error processing request', 'error'); | |
| } finally { | |
| // پنهان کردن اندیکاتور بارگذاری | |
| document.getElementById('loading-indicator').classList.add('hidden'); | |
| } | |
| } | |
| // تابع افزودن پیام به چت | |
| function addChatMessage(content, type) { | |
| const chatContainer = document.getElementById('chat-container'); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `flex ${type === 'user' ? 'justify-end' : 'justify-start'} w-full`; | |
| if (type === 'user') { | |
| messageDiv.innerHTML = ` | |
| <div class="bg-primary-blue text-white p-3 rounded-2xl user-bubble max-w-xs sm:max-w-md border border-blue-500/30 shadow-md text-xs leading-5"> | |
| ${content} | |
| </div> | |
| `; | |
| } else if (type === 'model') { | |
| // محتوای تصاویر | |
| let imageContent = ''; | |
| if (Array.isArray(content)) { | |
| imageContent = ` | |
| <div class="grid grid-cols-2 gap-2 mt-2"> | |
| ${content.map(url => ` | |
| <div class="relative group"> | |
| <img src="${url}" alt="Generated" class="rounded-lg border border-gray-700 w-full h-24 object-cover"> | |
| <div class="absolute inset-0 bg-black/50 flex items-center justify-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity"> | |
| <button onclick="downloadImage('${url}')" class="p-1 bg-primary-blue rounded text-white"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg> | |
| </button> | |
| </div> | |
| </div> | |
| `).join('')} | |
| </div> | |
| `; | |
| } | |
| messageDiv.innerHTML = ` | |
| <div class="bg-dark-card text-gray-300 p-3 rounded-2xl model-bubble max-w-xs sm:max-w-md border border-gray-800/50 shadow-md text-xs leading-5"> | |
| ${currentLanguage === 'fa' ? 'اینجا تصاویر تولید شده شما هستند:' : 'Here are your generated images:'} | |
| ${imageContent} | |
| <div class="mt-2 pt-2 border-t border-gray-800/50 text-[10px] text-gray-500"> | |
| ${currentLanguage === 'fa' ? 'برای دانلود روی تصویر کلیک کنید' : 'Click on images to download'} | |
| </div> | |
| </div> | |
| `; | |
| } else { | |
| messageDiv.innerHTML = ` | |
| <div class="bg-red-900/30 text-red-300 p-3 rounded-2xl model-bubble max-w-xs sm:max-w-md border border-red-800/50 shadow-md text-xs leading-5"> | |
| ${content} | |
| </div> | |
| `; | |
| } | |
| chatContainer.appendChild(messageDiv); | |
| // اسکرول به آخر | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| } | |
| // تابع دانلود تصویر | |
| function downloadImage(url) { | |
| const link = document.createElement('a'); | |
| link.href = url; | |
| link.download = 'omid-image-' + Date.now() + '.jpg'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| } | |
| // ================================================================= | |
| // --- اجرای اولیه --- | |
| document.addEventListener('DOMContentLoaded', function() { | |
| showWelcomeMessage(); | |
| setLanguage('fa'); // تنظیم زبان اولیه | |
| // تنظیم اولیه دکمهها | |
| toggleSendButton(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |