Spaces:
Running
Running
| <html lang="ru"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Установка GPT Platform</title> | |
| <!-- Подключение иконок FontAwesome --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary-color: #10a37f; /* OpenAI Green-ish */ | |
| --primary-hover: #0d8a6c; | |
| --bg-dark: #0f1115; | |
| --bg-card: #1e2128; | |
| --bg-input: #2d313a; | |
| --text-main: #ececf1; | |
| --text-muted: #9ca3af; | |
| --border-color: #353a45; | |
| --accent-glow: rgba(16, 163, 127, 0.2); | |
| --error-color: #ef4444; | |
| --font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; | |
| --font-mono: 'Courier New', Courier, monospace; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: var(--font-family); | |
| background-color: var(--bg-dark); | |
| color: var(--text-main); | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 100vh; | |
| background-image: radial-gradient(circle at 50% 0%, #1a2c26 0%, var(--bg-dark) 60%); | |
| } | |
| /* Header */ | |
| header { | |
| padding: 1.5rem 2rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| border-bottom: 1px solid var(--border-color); | |
| background: rgba(15, 17, 21, 0.8); | |
| backdrop-filter: blur(10px); | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| } | |
| .logo { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| color: var(--primary-color); | |
| } | |
| .logo i { | |
| font-size: 1.8rem; | |
| } | |
| .brand-link { | |
| color: var(--text-muted); | |
| text-decoration: none; | |
| font-size: 0.9rem; | |
| transition: color 0.3s; | |
| } | |
| .brand-link:hover { | |
| color: var(--primary-color); | |
| } | |
| /* Main Container */ | |
| main { | |
| flex: 1; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 2rem; | |
| } | |
| .installer-container { | |
| width: 100%; | |
| max-width: 900px; | |
| background: var(--bg-card); | |
| border-radius: 16px; | |
| box-shadow: 0 20px 50px rgba(0,0,0,0.5); | |
| border: 1px solid var(--border-color); | |
| overflow: hidden; | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 600px; | |
| position: relative; | |
| } | |
| /* Progress Steps (Top Bar) */ | |
| .steps-indicator { | |
| display: flex; | |
| justify-content: space-between; | |
| padding: 2rem 3rem; | |
| border-bottom: 1px solid var(--border-color); | |
| background: rgba(0,0,0,0.2); | |
| } | |
| .step-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| opacity: 0.5; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| } | |
| .step-item.active { | |
| opacity: 1; | |
| color: var(--primary-color); | |
| } | |
| .step-item.completed { | |
| opacity: 1; | |
| color: var(--primary-color); | |
| } | |
| .step-circle { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 50%; | |
| background: var(--bg-input); | |
| border: 2px solid var(--border-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-weight: bold; | |
| font-size: 0.9rem; | |
| transition: all 0.3s; | |
| } | |
| .step-item.active .step-circle { | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 15px var(--accent-glow); | |
| } | |
| .step-item.completed .step-circle { | |
| background: var(--primary-color); | |
| border-color: var(--primary-color); | |
| color: #fff; | |
| } | |
| .step-line { | |
| flex: 1; | |
| height: 2px; | |
| background: var(--border-color); | |
| margin: 0 10px; | |
| } | |
| .step-item.completed + .step-line { | |
| background: var(--primary-color); | |
| } | |
| /* Content Area */ | |
| .content-area { | |
| flex: 1; | |
| padding: 3rem; | |
| position: relative; | |
| } | |
| .step-content { | |
| display: none; | |
| animation: fadeIn 0.4s ease forwards; | |
| height: 100%; | |
| flex-direction: column; | |
| } | |
| .step-content.active { | |
| display: flex; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| h2 { | |
| font-size: 2rem; | |
| margin-bottom: 1rem; | |
| color: #fff; | |
| } | |
| p.description { | |
| color: var(--text-muted); | |
| margin-bottom: 2rem; | |
| line-height: 1.6; | |
| } | |
| /* Forms */ | |
| .form-group { | |
| margin-bottom: 1.5rem; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| color: var(--text-main); | |
| font-weight: 500; | |
| } | |
| input[type="text"], | |
| input[type="password"], | |
| select { | |
| width: 100%; | |
| padding: 12px 16px; | |
| background: var(--bg-input); | |
| border: 1px solid var(--border-color); | |
| border-radius: 8px; | |
| color: white; | |
| font-size: 1rem; | |
| transition: border-color 0.3s, box-shadow 0.3s; | |
| } | |
| input:focus, select:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px var(--accent-glow); | |
| } | |
| .grid-2 { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 1.5rem; | |
| } | |
| /* Range Slider */ | |
| .range-container { | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| } | |
| input[type="range"] { | |
| flex: 1; | |
| accent-color: var(--primary-color); | |
| cursor: pointer; | |
| } | |
| .range-value { | |
| font-family: var(--font-mono); | |
| background: var(--bg-input); | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| min-width: 40px; | |
| text-align: center; | |
| } | |
| /* Terminal / Installation View */ | |
| .terminal-window { | |
| background: #0d0e12; | |
| border-radius: 8px; | |
| border: 1px solid #333; | |
| font-family: var(--font-mono); | |
| padding: 1.5rem; | |
| flex: 1; | |
| overflow-y: auto; | |
| max-height: 400px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .terminal-line { | |
| color: #ccc; | |
| font-size: 0.9rem; | |
| } | |
| .terminal-line.success { color: var(--primary-color); } | |
| .terminal-line.warning { color: #fbbf24; } | |
| .terminal-line.error { color: var(--error-color); } | |
| .terminal-line.info { color: #60a5fa; } | |
| .progress-bar-container { | |
| height: 6px; | |
| background: var(--bg-input); | |
| border-radius: 3px; | |
| margin-top: 1rem; | |
| overflow: hidden; | |
| } | |
| .progress-bar-fill { | |
| height: 100%; | |
| background: var(--primary-color); | |
| width: 0%; | |
| transition: width 0.1s linear; | |
| } | |
| /* Success View */ | |
| .success-view { | |
| text-align: center; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| } | |
| .success-icon { | |
| font-size: 5rem; | |
| color: var(--primary-color); | |
| margin-bottom: 1.5rem; | |
| animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| } | |
| @keyframes popIn { | |
| 0% { transform: scale(0); opacity: 0; } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| /* Footer Navigation */ | |
| .footer-nav { | |
| padding: 1.5rem 3rem; | |
| border-top: 1px solid var(--border-color); | |
| display: flex; | |
| justify-content: space-between; | |
| } | |
| .btn { | |
| padding: 12px 24px; | |
| border-radius: 8px; | |
| border: none; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .btn-secondary { | |
| background: transparent; | |
| color: var(--text-muted); | |
| border: 1px solid var(--border-color); | |
| } | |
| .btn-secondary:hover { | |
| background: rgba(255,255,255,0.05); | |
| color: #fff; | |
| } | |
| .btn-primary { | |
| background: var(--primary-color); | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background: var(--primary-hover); | |
| transform: translateY(-1px); | |
| box-shadow: 0 4px 12px rgba(16, 163, 127, 0.3); | |
| } | |
| .btn:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| transform: none ; | |
| } | |
| /* Responsive */ | |
| @media (max-width: 768px) { | |
| .steps-indicator { | |
| padding: 1rem; | |
| } | |
| .step-text { | |
| display: none; | |
| } | |
| .content-area { | |
| padding: 1.5rem; | |
| } | |
| .grid-2 { | |
| grid-template-columns: 1fr; | |
| } | |
| .footer-nav { | |
| padding: 1rem; | |
| } | |
| .terminal-window { | |
| max-height: 250px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="logo"> | |
| <i class="fa-solid fa-brain"></i> | |
| <span>GPT Setup</span> | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="brand-link"> | |
| Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square" style="font-size: 0.7em;"></i> | |
| </a> | |
| </header> | |
| <main> | |
| <div class="installer-container"> | |
| <!-- Шаги --> | |
| <div class="steps-indicator"> | |
| <div class="step-item active" id="indicator-1"> | |
| <div class="step-circle">1</div> | |
| <span class="step-text">Приветствие</span> | |
| </div> | |
| <div class="step-line"></div> | |
| <div class="step-item" id="indicator-2"> | |
| <div class="step-circle">2</div> | |
| <span class="step-text">Конфигурация</span> | |
| </div> | |
| <div class="step-line"></div> | |
| <div class="step-item" id="indicator-3"> | |
| <div class="step-circle">3</div> | |
| <span class="step-text">Установка</span> | |
| </div> | |
| <div class="step-line"></div> | |
| <div class="step-item" id="indicator-4"> | |
| <div class="step-circle">4</div> | |
| <span class="step-text">Готово</span> | |
| </div> | |
| </div> | |
| <!-- Контент --> | |
| <div class="content-area"> | |
| <!-- Шаг 1: Приветствие --> | |
| <div class="step-content active" id="step-1"> | |
| <h2>Добро пожаловать в GPT Platform</h2> | |
| <p class="description"> | |
| Этот мастер поможет вам настроить локальную среду для работы с моделями GPT. | |
| Мы настроим параметры ядра, подключим API ключи и подготовим нейросеть к работе. | |
| </p> | |
| <div style="background: rgba(16, 163, 127, 0.1); border: 1px solid var(--primary-color); padding: 1.5rem; border-radius: 8px; margin-bottom: 1rem;"> | |
| <h3 style="color: var(--primary-color); font-size: 1.1rem; margin-bottom: 0.5rem;"><i class="fa-solid fa-check-circle"></i> Что будет установлено:</h3> | |
| <ul style="margin-left: 1.5rem; color: var(--text-muted);"> | |
| <li>GPT-4 Turbo Core Engine</li> | |
| <li>Модули обработки естественного языка (NLP)</li> | |
| <li>Локальный векторный базис данных</li> | |
| <li>Плагин безопасности</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <!-- Шаг 2: Конфигурация --> | |
| <div class="step-content" id="step-2"> | |
| <h2>Настройка параметров</h2> | |
| <p class="description">Введите данные для подключения к API или выберите локальный режим.</p> | |
| <div class="form-group"> | |
| <label>API OpenAI Key</label> | |
| <div style="position: relative;"> | |
| <input type="password" id="api-key" placeholder="sk-..." autocomplete="off"> | |
| <i class="fa-solid fa-eye" style="position: absolute; right: 15px; top: 14px; color: var(--text-muted); cursor: pointer;" onclick="togglePassword()"></i> | |
| </div> | |
| <p style="font-size: 0.8rem; color: var(--text-muted); margin-top: 5px;">Оставьте пустым для использования локальных моделей.</p> | |
| </div> | |
| <div class="grid-2"> | |
| <div class="form-group"> | |
| <label>Модель по умолчанию</label> | |
| <select id="model-select"> | |
| <option value="gpt-4">GPT-4 (Omni)</option> | |
| <option value="gpt-3.5">GPT-3.5 Turbo</option> | |
| <option value="local">Llama 3 (Local)</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label>Макс. токены</label> | |
| <input type="text" value="4096" id="max-tokens"> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label>Температура (Креативность): <span id="temp-val" class="range-value">0.7</span></label> | |
| <div class="range-container"> | |
| <span style="font-size: 0.8rem; color: var(--text-muted);">Точный</span> | |
| <input type="range" min="0" max="2" step="0.1" value="0.7" oninput="document.getElementById('temp-val').innerText = this.value"> | |
| <span style="font-size: 0.8rem; color: var(--text-muted);">Креативный</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Шаг 3: Установка --> | |
| <div class="step-content" id="step-3"> | |
| <h2>Установка системы</h2> | |
| <p class="description">Пожалуйста, подождите, пока компоненты системы загружаются и настраиваются.</p> | |
| <div class="terminal-window" id="terminal"> | |
| <div class="terminal-line info">> Инициализация мастера установки...</div> | |
| </div> | |
| <div class="progress-bar-container"> | |
| <div class="progress-bar-fill" id="progress-fill"></div> | |
| </div> | |
| <div style="text-align: right; margin-top: 5px; font-size: 0.8rem; color: var(--text-muted);"> | |
| <span id="progress-text">0%</span> | |
| </div> | |
| </div> | |
| <!-- Шаг 4: Готово --> | |
| <div class="step-content" id="step-4"> | |
| <div class="success-view"> | |
| <i class="fa-solid fa-circle-check success-icon"></i> | |
| <h2>Установка завершена!</h2> | |
| <p class="description"> | |
| Платформа GPT успешно установлена и настроена. | |
| Теперь вы можете начать создавать новые проекты. | |
| </p> | |
| <div style="display: flex; gap: 1rem;"> | |
| <button class="btn btn-secondary" onclick="location.reload()"> | |
| <i class="fa-solid fa-rotate-left"></i> Сбросить | |
| </button> | |
| <button class="btn btn-primary" onclick="launchDashboard()"> | |
| Перейти к панели <i class="fa-solid fa-arrow-right"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Навигация --> | |
| <div class="footer-nav" id="footer-nav"> | |
| <button class="btn btn-secondary" id="btn-back" onclick="changeStep(-1)" disabled> | |
| Назад | |
| </button> | |
| <button class="btn btn-primary" id="btn-next" onclick="changeStep(1)"> | |
| Далее <i class="fa-solid fa-chevron-right"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| let currentStep = 1; | |
| const totalSteps = 4; | |
| function changeStep(direction) { | |
| const nextStep = currentStep + direction; | |
| if (nextStep < 1 || nextStep > totalSteps) return; | |
| // Валидация перед переходом на шаг 3 (Установка) | |
| if (nextStep === 3) { | |
| if (!validateConfig()) return; | |
| startInstallation(); | |
| } | |
| // Обновляем UI | |
| updateUI(nextStep); | |
| currentStep = nextStep; | |
| } | |
| function updateUI(step) { | |
| // Скрываем все шаги | |
| document.querySelectorAll('.step-content').forEach(el => el.classList.remove('active')); | |
| // Показываем текущий | |
| document.getElementById(`step-${step}`).classList.add('active'); | |
| // Обновляем индикаторы сверху | |
| document.querySelectorAll('.step-item').forEach((el, index) => { | |
| const stepNum = index + 1; | |
| el.classList.remove('active', 'completed'); | |
| if (stepNum === step) { | |
| el.classList.add('active'); | |
| } else if (stepNum < step) { | |
| el.classList.add('completed'); | |
| // Меняем цифру на галочку для завершенных шагов | |
| el.querySelector('.step-circle').innerHTML = '<i class="fa-solid fa-check"></i>'; | |
| } else { | |
| el.querySelector('.step-circle').innerText = stepNum; | |
| } | |
| }); | |
| // Управление кнопками | |
| const btnBack = document.getElementById('btn-back'); | |
| const btnNext = document.getElementById('btn-next'); | |
| const footerNav = document.getElementById('footer-nav'); | |
| btnBack.disabled = step === 1 || step === 3; // Назад нельзя на 1 шаге и во время установки | |
| if (step === 4) { | |
| footerNav.style.display = 'none'; // Скрываем кнопки на финальном экране | |
| } else if (step === 3) { | |
| btnNext.disabled = true; | |
| btnNext.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Установка...'; | |
| } else { | |
| footerNav.style.display = 'flex'; | |
| btnNext.disabled = false; | |
| btnNext.innerHTML = step === 2 ? 'Начать установку <i class="fa-solid fa-download"></i>' : 'Далее <i class="fa-solid fa-chevron-right"></i>'; | |
| } | |
| } | |
| function togglePassword() { | |
| const input = document.getElementById('api-key'); | |
| const icon = document.querySelector('.fa-eye'); | |
| if (input.type === "password") { | |
| input.type = "text"; | |
| icon.classList.remove('fa-eye'); | |
| icon.classList.add('fa-eye-slash'); | |
| } else { | |
| input.type = "password"; | |
| icon.classList.remove('fa-eye-slash'); | |
| icon.classList.add('fa-eye'); | |
| } | |
| } | |
| function validateConfig() { | |
| const apiKey = document.getElementById('api-key').value; | |
| const model = document.getElementById('model-select').value; | |
| // Простая проверка: если выбран облачный режим, нужен ключ | |
| if (model !== 'local' && apiKey.length < 5) { | |
| // Визуальная индикация ошибки без alert() | |
| const input = document.getElementById('api-key'); | |
| input.style.borderColor = 'var(--error-color)'; | |
| input.focus(); | |
| // Добавляем сообщение об ошибке | |
| let msg = document.getElementById('error-msg'); | |
| if (!msg) { | |
| msg = document.createElement('p'); | |
| msg.id = 'error-msg'; | |
| msg.style.color = 'var(--error-color)'; | |
| msg.style.fontSize = '0.8rem'; | |
| msg.style.marginTop = '5px'; | |
| input.parentNode.after(msg); | |
| } | |
| msg.innerText = 'Пожалуйста, введите корректный API Key для облачной модели.'; | |
| setTimeout(() => { | |
| input.style.borderColor = 'var(--border-color)'; | |
| if(msg) msg.remove(); | |
| }, 3000); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // Имитация процесса установки | |
| function startInstallation() { | |
| const terminal = document.getElementById('terminal'); | |
| const progressFill = document.getElementById('progress-fill'); | |
| const progressText = document.getElementById('progress-text'); | |
| const logs = [ | |
| { msg: "Проверка системных требований...", type: "info", delay: 500 }, | |
| { msg: "ОК: CPU (8 cores), RAM (32GB) обнаружены.", type: "success", delay: 800 }, | |
| { msg: "Загрузка базовых зависимостей Python...", type: "info", delay: 1500 }, | |
| { msg: "Установка torch (CUDA 12.1)...", type: "warning", delay: 2500 }, | |
| { msg: "Установка transformers...", type: "info", delay: 3000 }, | |
| { msg: "Настройка модели: " + document.getElementById('model-select').value, type: "info", delay: 3500 }, | |
| { msg: "Инициализация токенизатора...", type: "info", delay: 4000 }, | |
| { msg: "Загрузка весов модели (это может занять время)...", type: "warning", delay: 5000 }, | |
| { msg: "Оптимизация графического процессора...", type: "info", delay: 7000 }, | |
| { msg: "Настройка векторной базы данных...", type: "info", delay: 8000 }, | |
| { msg: "Запуск сервисов...", type: "info", delay: 9000 }, | |
| { msg: "SUCCESS: Система готова к работе.", type: "success", delay: 10000 } | |
| ]; | |
| let startTime = Date.now(); | |
| let totalDuration = 10000; // 10 секунд общее время | |
| // Таймер для обновления прогресс-бара | |
| const progressInterval = setInterval(() => { | |
| let elapsed = Date.now() - startTime; | |
| let percent = Math.min(100, Math.floor((elapsed / totalDuration) * 100)); | |
| progressFill.style.width = percent + '%'; | |
| progressText.innerText = percent + '%'; | |
| if (elapsed >= totalDuration) { | |
| clearInterval(progressInterval); | |
| // Завершаем установку | |
| setTimeout(() => { | |
| changeStep(1); | |
| }, 1000); | |
| } | |
| }, 100); | |
| // Вывод логов | |
| logs.forEach(log => { | |
| setTimeout(() => { | |
| addLog(log.msg, log.type); | |
| }, log.delay); | |
| }); | |
| } | |
| function addLog(text, type) { | |
| const terminal = document.getElementById('terminal'); | |
| const div = document.createElement('div'); | |
| div.className = `terminal-line ${type}`; | |
| // Добавляем временную метку | |
| const time = new Date().toLocaleTimeString('ru-RU', { hour12: false }); | |
| div.innerText = `[${time}] ${text}`; | |
| terminal.appendChild(div); | |
| terminal.scrollTop = terminal.scrollHeight; // Автопрокрутка вниз | |
| } | |
| function launchDashboard() { | |
| // Имитация перехода | |
| const btn = event.currentTarget; | |
| btn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Загрузка...'; | |
| setTimeout(() => { | |
| // В реальном приложении здесь был бы редирект | |
| document.querySelector('.success-view h2').innerText = "Перенаправление..."; | |
| document.querySelector('.success-view p').innerText = "Добро пожаловать в панель управления GPT."; | |
| btn.style.display = 'none'; | |
| }, 1500); | |
| } | |
| </script> | |
| </body> | |
| </html> |