| <!DOCTYPE html> |
| <html lang="fa" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>مولد تصویر آلفا - Flux Pro</title> |
| <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;600;800&display=swap" rel="stylesheet"> |
| <style> |
| :root { |
| --igadlm-alpha-color-primary: #5A67D8; |
| --igadlm-alpha-color-primary-darker: #4C51BF; |
| --igadlm-alpha-color-secondary: #805AD5; |
| --igadlm-alpha-color-secondary-darker: #6B46C1; |
| --igadlm-alpha-color-text: #1A202C; |
| --igadlm-alpha-color-text-light: #4A5568; |
| --igadlm-alpha-color-text-muted: #718096; |
| --igadlm-alpha-color-bg-card: #FFFFFF; |
| --igadlm-alpha-color-border: #CBD5E0; |
| --igadlm-alpha-color-input-bg: #EDF2F7; |
| --igadlm-alpha-color-white: #FFFFFF; |
| --igadlm-alpha-color-success: #38A169; |
| --igadlm-alpha-color-error: #E53E3E; |
| --igadlm-alpha-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.07), 0 1px 2px 0 rgba(0, 0, 0, 0.04); |
| --igadlm-alpha-shadow-md: 0 4px 8px -2px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.05); |
| --igadlm-alpha-shadow-lg: 0 10px 20px -5px rgba(0, 0, 0, 0.1), 0 6px 10px -5px rgba(0, 0, 0, 0.05); |
| --igadlm-alpha-shadow-focus: 0 0 0 3px rgba(90, 103, 216, 0.35); |
| --igadlm-alpha-border-radius-md: 8px; |
| --igadlm-alpha-border-radius-lg: 12px; |
| --igadlm-alpha-transition-speed: 0.25s; |
| --igadlm-alpha-transition-easing: cubic-bezier(0.4, 0, 0.2, 1); |
| } |
| |
| body.standalone-igadlm-alpha-app { background-color: #f0f2f5; margin:0; padding:20px; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh;} |
| #imageGeneratorAppAlphaV2 *, #imageGeneratorAppAlphaV2 *::before, #imageGeneratorAppAlphaV2 *::after { box-sizing: border-box; margin: 0; padding: 0; border-width: 0; border-style: solid; } |
| #imageGeneratorAppAlphaV2 { all: unset; display: block; font-family: 'Vazirmatn', 'Tahoma', sans-serif; color: var(--igadlm-alpha-color-text); line-height: 1.6; direction: rtl; width: 100%; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overflow-x: hidden; background-color: transparent; } |
| #imageGeneratorAppAlphaV2 div, #imageGeneratorAppAlphaV2 p, #imageGeneratorAppAlphaV2 h1, #imageGeneratorAppAlphaV2 h2, #imageGeneratorAppAlphaV2 h3, #imageGeneratorAppAlphaV2 label, #imageGeneratorAppAlphaV2 input, #imageGeneratorAppAlphaV2 textarea, #imageGeneratorAppAlphaV2 button, #imageGeneratorAppAlphaV2 img, #imageGeneratorAppAlphaV2 a { all: revert; box-sizing: border-box; font-family: inherit; } |
| #imageGeneratorAppAlphaV2 .app-content-wrapper { display: flex; justify-content: center; width: 100%; overflow-x: hidden; } |
| #imageGeneratorAppAlphaV2 .app-content { width: 100%; max-width: 550px; padding: 0 15px; } |
| #imageGeneratorAppAlphaV2 .app-header { text-align: center; margin-bottom: 30px; } |
| #imageGeneratorAppAlphaV2 .app-header h1 { font-size: clamp(1.8em, 5.5vw, 2.3em); font-weight: 700; color: var(--igadlm-alpha-color-primary); margin-bottom: 8px; } |
| #imageGeneratorAppAlphaV2 .app-header p { font-size: 0.95em; color: var(--igadlm-alpha-color-text-light); } |
| #imageGeneratorAppAlphaV2 .form-section-card { background-color: var(--igadlm-alpha-color-bg-card); padding: 30px; border-radius: var(--igadlm-alpha-border-radius-lg); box-shadow: var(--igadlm-alpha-shadow-lg); border: 1px solid var(--igadlm-alpha-color-border); transition: opacity 0.3s ease-in-out; } |
| #imageGeneratorAppAlphaV2 .form-group { margin-bottom: 20px; } |
| #imageGeneratorAppAlphaV2 .form-group label { display: block; font-size: 0.85rem; color: var(--igadlm-alpha-color-text-light); margin-bottom: 6px; font-weight: 600; } |
| #imageGeneratorAppAlphaV2 #imagePromptAlpha { width: 100%; padding: 10px 14px; border: 1px solid var(--igadlm-alpha-color-border); border-radius: var(--igadlm-alpha-border-radius-md); font-size: 0.9rem; background-color: var(--igadlm-alpha-color-input-bg); color: var(--igadlm-alpha-color-text); min-height: 60px; resize: vertical; } |
| #imageGeneratorAppAlphaV2 #imagePromptAlpha:focus { outline: none; border-color: var(--igadlm-alpha-color-primary); box-shadow: var(--igadlm-alpha-shadow-focus); background-color: var(--igadlm-alpha-color-white); } |
| #imageGeneratorAppAlphaV2 .dimension-buttons-simple { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; } |
| #imageGeneratorAppAlphaV2 .dimension-button-simple { padding: 10px 8px; font-size: 0.9rem; font-weight: 500; border: 1px solid var(--igadlm-alpha-color-border); border-radius: var(--igadlm-alpha-border-radius-md); background-color: var(--igadlm-alpha-color-input-bg); color: var(--igadlm-alpha-color-text-muted); cursor: pointer; text-align: center; transition: all var(--igadlm-alpha-transition-speed); box-shadow: var(--igadlm-alpha-shadow-sm); } |
| #imageGeneratorAppAlphaV2 .dimension-button-simple.selected { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary) 0%, var(--igadlm-alpha-color-secondary) 100%); color: var(--igadlm-alpha-color-white); border-color: transparent; font-weight: 600; transform: translateY(-2px); box-shadow: var(--igadlm-alpha-shadow-md); } |
| #imageGeneratorAppAlphaV2 .dimension-button-simple:hover:not(.selected) { border-color: var(--igadlm-alpha-color-primary-darker); color: var(--igadlm-alpha-color-primary-darker); background-color: var(--igadlm-alpha-color-white); transform: translateY(-1px); } |
| @media (min-width: 400px) { #imageGeneratorAppAlphaV2 .dimension-buttons-simple { grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); }} |
| #imageGeneratorAppAlphaV2 #generateBtnAlpha { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 11px 16px; border-radius: var(--igadlm-alpha-border-radius-md); font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: all var(--igadlm-alpha-transition-speed); box-shadow: var(--igadlm-alpha-shadow-md); background: linear-gradient(60deg, var(--igadlm-alpha-color-primary) 0%, var(--igadlm-alpha-color-secondary) 100%); color: var(--igadlm-alpha-color-white); border-style: none; margin-top: 12px; } |
| #imageGeneratorAppAlphaV2 #generateBtnAlpha:hover:not(:disabled) { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary-darker) 0%, var(--igadlm-alpha-color-secondary-darker) 100%); transform: translateY(-2px); box-shadow: var(--igadlm-alpha-shadow-lg); } |
| #imageGeneratorAppAlphaV2 #generateBtnAlpha:disabled { background: #cbd5e0 !important; color: #718096 !important; cursor: not-allowed; box-shadow: none !important; transform: none !important; } |
| #imageGeneratorAppAlphaV2 #aiLoaderAlpha { display: none; flex-direction: column; align-items: center; margin: 20px auto 10px auto; } |
| #imageGeneratorAppAlphaV2 .ai-loader-bar-container-inline { display: flex; justify-content: center; align-items: flex-end; height: 25px; } |
| #imageGeneratorAppAlphaV2 .ai-loader-bar-inline { width: 5px; height: 5px; background-color: var(--igadlm-alpha-color-primary); border-radius: 2.5px; margin: 0 2.5px; animation: igadlmAlphaV2LoaderAnim 1.2s infinite ease-in-out; } |
| #imageGeneratorAppAlphaV2 .ai-loader-bar-inline:nth-child(2) { animation-delay: 0.2s; background-color: var(--igadlm-alpha-color-secondary); } |
| #imageGeneratorAppAlphaV2 .ai-loader-bar-inline:nth-child(3) { animation-delay: 0.4s; } |
| #imageGeneratorAppAlphaV2 #statusAlphaText { text-align: center; font-size: 0.85em; color: var(--igadlm-alpha-color-text-muted); font-weight: 500; margin-top: 10px; min-height: 1.4em; } |
| #imageGeneratorAppAlphaV2 #imageResultContainerAlpha { margin-top: 15px; text-align: center; display: none; } |
| #imageGeneratorAppAlphaV2 #generatedImageAlpha { max-width: 100%; height: auto; min-height: 180px; border-radius: var(--igadlm-alpha-border-radius-md); box-shadow: var(--igadlm-alpha-shadow-md); display: none; border: 1px solid var(--igadlm-alpha-color-border); background-color: var(--igadlm-alpha-color-input-bg); object-fit: contain; margin: 0 auto; } |
| #imageGeneratorAppAlphaV2 #downloadImageBtnAlpha { display: none; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 11px 16px; border-radius: var(--igadlm-alpha-border-radius-md); font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: all var(--igadlm-alpha-transition-speed); margin-top: 10px; background-color: var(--igadlm-alpha-color-white); color: var(--igadlm-alpha-color-primary); border: 1px solid var(--igadlm-alpha-color-border); box-shadow: var(--igadlm-alpha-shadow-sm); text-decoration: none; } |
| #imageGeneratorAppAlphaV2 #downloadImageBtnAlpha:hover { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary) 0%, var(--igadlm-alpha-color-secondary) 100%); color: var(--igadlm-alpha-color-white); border-color: transparent; transform: translateY(-2px); box-shadow: var(--igadlm-alpha-shadow-lg); } |
| @keyframes igadlmAlphaV2LoaderAnim { 0%, 100% { transform: scaleY(0.5); opacity: 0.5; } 50% { transform: scaleY(1.5); opacity: 1; height: 15px; } } |
| </style> |
| </head> |
| <body class="standalone-igadlm-alpha-app"> |
|
|
| <div id="imageGeneratorAppAlphaV2"> |
| <div class="app-content-wrapper"> |
| <div class="app-content"> |
| <div class="app-header"> |
| <h1>🖼️ مولد تصویر آلفا</h1> |
| <p><span style="color: #339966; font-weight: bold;">Flux Pro</span></p> |
| <p>ایده خود را به یک تصویر خلاقانه تبدیل کنید</p> |
| </div> |
| |
| <div class="form-section-card" id="alphaFormSectionCard"> |
| <div class="form-group"> |
| <label for="imagePromptAlpha">ایده خود را بنویسید (به فارسی):</label> |
| <textarea id="imagePromptAlpha" rows="3" placeholder="مثال: یک قلعه باستانی بر فراز ابرها"></textarea> |
| </div> |
| |
| <div class="form-group"> |
| <label>اندازه تصویر (نسبت):</label> |
| <div class="dimension-buttons-simple" id="alphaDimensionButtons"></div> |
| </div> |
| |
| <button id="generateBtnAlpha">🎨 ساخت تصویر</button> |
| |
| <div class="ai-loader-inline" id="aiLoaderAlpha"> |
| <div class="ai-loader-bar-container-inline"> |
| <div class="ai-loader-bar-inline"></div> |
| <div class="ai-loader-bar-inline"></div> |
| <div class="ai-loader-bar-inline"></div> |
| </div> |
| </div> |
| |
| <div id="statusAlphaText">وضعیت: آماده برای تولید تصویر.</div> |
| |
| <div id="imageResultContainerAlpha"> |
| <img id="generatedImageAlpha" alt="تصویر ایجاد شده" /> |
| <a id="downloadImageBtnAlpha" href="#" download="flux_image.webp">📥 دانلود تصویر</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| (function() { |
| const PREDEFINED_DIMENSIONS_MAP = { |
| "1:1": { width: 1024, height: 1024, display: "۱:۱ (مربع)" }, |
| "16:9": { width: 1344, height: 768, display: "۱۶:۹ (افقی)" }, |
| "9:16": { width: 768, height: 1344, display: "۹:۱۶ (عمودی)" }, |
| "4:3": { width: 1152, height: 864, display: "۴:۳ (کلاسیک)" } |
| }; |
| |
| let selectedAspectRatioKey = Object.keys(PREDEFINED_DIMENSIONS_MAP)[0]; |
| |
| const btnContainer = document.getElementById('alphaDimensionButtons'); |
| const statusText = document.getElementById('statusAlphaText'); |
| const loader = document.getElementById('aiLoaderAlpha'); |
| const genBtn = document.getElementById('generateBtnAlpha'); |
| const resultContainer = document.getElementById('imageResultContainerAlpha'); |
| const imgEl = document.getElementById('generatedImageAlpha'); |
| const downloadBtn = document.getElementById('downloadImageBtnAlpha'); |
| const promptInput = document.getElementById('imagePromptAlpha'); |
| |
| let pollTimer; |
| |
| Object.keys(PREDEFINED_DIMENSIONS_MAP).forEach((key) => { |
| const dimInfo = PREDEFINED_DIMENSIONS_MAP[key]; |
| const button = document.createElement('button'); |
| button.className = 'dimension-button-simple'; |
| button.textContent = dimInfo.display; |
| button.dataset.ratioKey = key; |
| if (key === selectedAspectRatioKey) { button.classList.add('selected'); } |
| |
| button.addEventListener('click', () => { |
| btnContainer.querySelectorAll('.dimension-button-simple').forEach(btn => btn.classList.remove('selected')); |
| button.classList.add('selected'); |
| selectedAspectRatioKey = button.dataset.ratioKey; |
| }); |
| btnContainer.appendChild(button); |
| }); |
| |
| function updateStatus(text, type='info', showLoader=false) { |
| statusText.textContent = text; |
| statusText.style.color = type === 'error' ? 'var(--igadlm-alpha-color-error)' : |
| type === 'success' ? 'var(--igadlm-alpha-color-success)' : 'var(--igadlm-alpha-color-text-muted)'; |
| loader.style.display = showLoader ? 'flex' : 'none'; |
| } |
| |
| genBtn.onclick = async () => { |
| const prompt = promptInput.value.trim(); |
| if(!prompt) return updateStatus('لطفا ایده خود را بنویسید!', 'error'); |
| |
| genBtn.disabled = true; |
| resultContainer.style.display = 'none'; |
| imgEl.style.display = 'none'; |
| downloadBtn.style.display = 'none'; |
| |
| updateStatus('در حال ترجمه متن به انگلیسی... (مرحله ۱ از ۳)', 'info', true); |
| const dims = PREDEFINED_DIMENSIONS_MAP[selectedAspectRatioKey]; |
| |
| try { |
| const res = await fetch('/api/generate', { |
| method: 'POST', |
| headers: {'Content-Type': 'application/json'}, |
| body: JSON.stringify({ |
| prompt: prompt, |
| width: dims.width, |
| height: dims.height, |
| action_name: "generate-flux" |
| }) |
| }); |
| |
| const data = await res.json(); |
| |
| if (data.status === 'success') { |
| updateStatus(`متن ترجمه شد: "${data.translated_prompt.substring(0, 30)}..."\nدر حال ساخت تصویر... (مرحله ۲ از ۳)`, 'info', true); |
| pollTimer = setInterval(() => checkResult(data.run_id), 3000); |
| } else { |
| updateStatus('خطا در برقراری ارتباط با گیتهاب.', 'error'); |
| genBtn.disabled = false; |
| } |
| } catch (e) { |
| updateStatus('خطای ارتباط با سرور داکر.', 'error'); |
| genBtn.disabled = false; |
| } |
| }; |
| |
| async function checkResult(run_id) { |
| try { |
| const res = await fetch(`/api/status/${run_id}`); |
| const data = await res.json(); |
| |
| if (data.status === 'ready') { |
| clearInterval(pollTimer); |
| loader.style.display = 'none'; |
| updateStatus('تصویر با موفقیت ساخته شد! 🎉 (مرحله ۳ از ۳)', 'success', false); |
| |
| imgEl.src = data.url; |
| downloadBtn.href = data.url; |
| |
| imgEl.style.display = 'block'; |
| downloadBtn.style.display = 'inline-flex'; |
| resultContainer.style.display = 'block'; |
| |
| genBtn.disabled = false; |
| } |
| } catch(e) { |
| console.log('در حال دریافت اطلاعات...'); |
| } |
| } |
| })(); |
| </script> |
| </body> |
| </html> |