Your IP : 216.73.216.79


Current Path : /var/www/pythonian/qwen/static/
Upload File :
Current File : /var/www/pythonian/qwen/static/image-generator.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Image Generator</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        .switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 24px;
        }

        .switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }

        .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: 0.4s;
            border-radius: 24px;
        }

        .slider:before {
            position: absolute;
            content: "";
            height: 18px;
            width: 18px;
            left: 3px;
            bottom: 3px;
            background-color: white;
            transition: 0.4s;
            border-radius: 50%;
        }

        input:checked + .slider {
            background-color: #3b82f6;
        }

        input:checked + .slider:before {
            transform: translateX(26px);
        }

        .spinner {
            border: 6px solid #f3f3f3;
            border-top: 6px solid #3b82f6;
            border-radius: 50%;
            width: 60px;
            height: 60px;
            animation: spin 1s linear infinite;
            margin: 0 auto 1rem;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen">
    <div x-data="imageGenerator()" class="max-w-6xl mx-auto p-4 sm:p-6 lg:p-8">
        <!-- Header -->
        <div class="text-center mb-8">
            <h1 class="text-4xl font-bold text-gray-800 mb-2">
                <i class="fas fa-palette mr-3 text-blue-500"></i>
                AI Image Generator
            </h1>
            <p class="text-gray-600 text-lg">Create stunning images with AI-powered generation</p>
        </div>

        <!-- Generator Form -->
        <div class="bg-white rounded-xl shadow-lg p-6 mb-8">
            <!-- Prompt Input -->
            <div class="mb-6">
                <label for="prompt" class="block text-sm font-semibold text-gray-700 mb-2">
                    <i class="fas fa-pen mr-2 text-blue-500"></i>
                    Prompt <span class="text-red-500">*</span>
                </label>
                <textarea
                    id="prompt"
                    x-model="prompt"
                    placeholder="Describe the image you want to create..."
                    rows="4"
                    class="w-full px-4 py-3 border-2 border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
                ></textarea>
                <p class="mt-1 text-xs text-gray-500">Be specific and descriptive for better results</p>
            </div>

            <!-- Negative Prompt -->
            <div class="mb-6">
                <label for="negativePrompt" class="block text-sm font-semibold text-gray-700 mb-2">
                    <i class="fas fa-ban mr-2 text-red-500"></i>
                    Negative Prompt
                </label>
                <textarea
                    id="negativePrompt"
                    x-model="negativePrompt"
                    placeholder="Elements to avoid in the image..."
                    rows="2"
                    class="w-full px-4 py-3 border-2 border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
                ></textarea>
            </div>

            <!-- Options Grid -->
            <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
                <!-- Model Selection -->
                <div>
                    <label for="model" class="block text-sm font-semibold text-gray-700 mb-2">
                        <i class="fas fa-brain mr-2 text-purple-500"></i>
                        Model
                    </label>
                    <select
                        id="model"
                        x-model="model"
                        class="w-full px-4 py-3 border-2 border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
                    >
                        <option value="qwen-image-plus">Qwen Image Plus (Default)</option>
                        <option value="qwen-image">Qwen Image</option>
                        <option value="qwen-image-max">Qwen Image Max</option>
                    </select>
                </div>

                <!-- Number of Images -->
                <div>
                    <label for="n" class="block text-sm font-semibold text-gray-700 mb-2">
                        <i class="fas fa-images mr-2 text-green-500"></i>
                        Number of Images
                    </label>
                    <input
                        type="number"
                        id="n"
                        x-model.number="n"
                        min="1"
                        max="4"
                        class="w-full px-4 py-3 border-2 border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
                    />
                </div>

                <!-- Size Selection -->
                <div>
                    <label for="size" class="block text-sm font-semibold text-gray-700 mb-2">
                        <i class="fas fa-expand mr-2 text-orange-500"></i>
                        Size
                    </label>
                    <select
                        id="size"
                        x-model="size"
                        class="w-full px-4 py-3 border-2 border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
                    >
                        <option value="1664*928">1664×928 (Default)</option>
                        <option value="1024*1024">1024×1024 (Square)</option>
                        <option value="1280*720">1280×720 (HD)</option>
                        <option value="1920*1080">1920×1080 (Full HD)</option>
                    </select>
                </div>
            </div>

            <!-- Toggle Options -->
            <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6 p-4 bg-gray-50 rounded-lg">
                <div class="flex items-center">
                    <label class="switch mr-3">
                        <input type="checkbox" x-model="promptExtend" />
                        <span class="slider"></span>
                    </label>
                    <div>
                        <span class="font-semibold text-gray-700">Prompt Extend</span>
                        <p class="text-xs text-gray-500">Automatically enhance your prompt</p>
                    </div>
                </div>

                <div class="flex items-center">
                    <label class="switch mr-3">
                        <input type="checkbox" x-model="watermark" />
                        <span class="slider"></span>
                    </label>
                    <div>
                        <span class="font-semibold text-gray-700">Add Watermark</span>
                        <p class="text-xs text-gray-500">Add watermark to generated images</p>
                    </div>
                </div>
            </div>

            <!-- Action Buttons -->
            <div class="flex flex-col sm:flex-row gap-4 justify-center">
                <button
                    @click="generateImage"
                    :disabled="isGenerating || !prompt"
                    class="px-8 py-4 bg-gradient-to-r from-blue-500 to-purple-600 text-white font-bold rounded-lg hover:from-blue-600 hover:to-purple-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition transform hover:-translate-y-1"
                >
                    <template x-if="isGenerating">
                        <span class="flex items-center justify-center">
                            <i class="fas fa-spinner fa-spin mr-2"></i>
                            Generating...
                        </span>
                    </template>
                    <template x-if="!isGenerating">
                        <span class="flex items-center justify-center">
                            <i class="fas fa-magic mr-2"></i>
                            Generate Image
                        </span>
                    </template>
                </button>

                <button
                    @click="resetForm"
                    class="px-8 py-4 bg-red-500 text-white font-bold rounded-lg hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition transform hover:-translate-y-1"
                >
                    <i class="fas fa-redo mr-2"></i>
                    Reset
                </button>
            </div>
        </div>

        <!-- Error Message -->
        <template x-if="errorMessage">
            <div class="bg-red-50 border-l-4 border-red-500 p-4 mb-6 rounded">
                <div class="flex items-center">
                    <i class="fas fa-exclamation-triangle text-red-500 mr-3 text-xl"></i>
                    <p class="text-red-700 font-medium" x-text="errorMessage"></p>
                </div>
            </div>
        </template>

        <!-- Loading Overlay -->
        <template x-if="isGenerating">
            <div class="fixed inset-0 bg-white bg-opacity-95 z-50 flex items-center justify-center">
                <div class="text-center">
                    <div class="spinner"></div>
                    <p class="text-2xl font-bold text-gray-800">Creating your masterpiece...</p>
                    <p class="text-gray-600 mt-2">This may take a moment</p>
                </div>
            </div>
        </template>

        <!-- Results Section -->
        <template x-if="generatedImages.length > 0">
            <div class="mt-8">
                <h2 class="text-2xl font-bold text-gray-800 mb-6 text-center">
                    <i class="fas fa-images mr-2 text-blue-500"></i>
                    Generated Images
                </h2>

                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
                    <template x-for="(image, index) in generatedImages" :key="index">
                        <div class="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition">
                            <img
                                :src="image.url"
                                :alt="`Generated image ${index + 1}`"
                                class="w-full h-auto"
                                @error="handleImageError"
                            />
                            <div class="p-4 bg-gray-50">
                                <div class="flex gap-2 justify-center">
                                    <button
                                        @click="downloadImage(image.url)"
                                        class="flex-1 px-4 py-2 bg-green-500 text-white font-semibold rounded-lg hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition"
                                    >
                                        <i class="fas fa-download mr-2"></i>
                                        Download
                                    </button>
                                    <button
                                        @click="copyImageUrl(image.url)"
                                        class="flex-1 px-4 py-2 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition"
                                    >
                                        <i class="fas fa-copy mr-2"></i>
                                        Copy URL
                                    </button>
                                </div>
                            </div>
                        </div>
                    </template>
                </div>
            </div>
        </template>
    </div>

    <script>
        document.addEventListener('alpine:init', () => {
            Alpine.data('imageGenerator', () => ({
                // Form data
                prompt: '',
                negativePrompt: '',
                n: 1,
                size: '1664*928',
                promptExtend: true,
                watermark: false,
                model: 'qwen-image-plus',

                // State
                isGenerating: false,
                errorMessage: '',
                generatedImages: [],
                requestId: '',

                // Generate image
                async generateImage() {
                    if (!this.prompt.trim()) {
                        this.errorMessage = 'Please enter a prompt to generate an image.';
                        return;
                    }

                    this.isGenerating = true;
                    this.errorMessage = '';
                    this.generatedImages = [];

                    try {
                        const response = await fetch('/generate-image', {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({
                                prompt: this.prompt,
                                negative_prompt: this.negativePrompt,
                                n: this.n,
                                size: this.size,
                                prompt_extend: this.promptExtend,
                                watermark: this.watermark,
                                model: this.model
                            })
                        });

                        const data = await response.json();

                        if (response.ok) {
                            this.generatedImages = data.image_urls.map(url => ({
                                url: url,
                                prompt: data.prompt
                            }));
                            this.requestId = data.request_id;
                            this.errorMessage = '';
                        } else {
                            this.errorMessage = data.error || 'Image generation failed';
                        }
                    } catch (error) {
                        this.errorMessage = `Error: ${error.message}`;
                        console.error('Generation error:', error);
                    } finally {
                        this.isGenerating = false;
                    }
                },

                // Reset form
                resetForm() {
                    this.prompt = '';
                    this.negativePrompt = '';
                    this.n = 1;
                    this.size = '1664*928';
                    this.promptExtend = true;
                    this.watermark = false;
                    this.model = 'qwen-image-plus';
                    this.generatedImages = [];
                    this.errorMessage = '';
                },

                // Download image
                async downloadImage(url) {
                    try {
                        const response = await fetch(url);
                        const blob = await response.blob();
                        const downloadUrl = window.URL.createObjectURL(blob);
                        const link = document.createElement('a');
                        link.href = downloadUrl;
                        link.download = `generated-image-${Date.now()}.png`;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                        window.URL.revokeObjectURL(downloadUrl);
                    } catch (error) {
                        console.error('Download error:', error);
                        alert('Failed to download image');
                    }
                },

                // Copy image URL
                copyImageUrl(url) {
                    const fullUrl = window.location.origin + url;
                    navigator.clipboard.writeText(fullUrl)
                        .then(() => {
                            alert('Image URL copied to clipboard!');
                        })
                        .catch(() => {
                            alert('Failed to copy URL');
                        });
                },

                // Handle image load error
                handleImageError(event) {
                    event.target.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgZmlsbD0iI2YwZjBmMCIvPjx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBmb250LWZhbWlseT0iQXJpYWwiIGZvbnQtc2l6ZT0iMjQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM5OTk5OTkiPkltYWdlIExvYWRlZCBGYWlsZWQ8L3RleHQ+PC9zdmc+';
                }
            }));
        });
    </script>
</body>
</html>