| <!DOCTYPE html> |
| <html lang="ru"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Orack Mini</title> |
| <style> |
| :root { --bg: #0a0a0f; --panel: #12121a; --accent: #00f0ff; --text: #e0e0f0; --input-bg: #1a1a2e; --msg-user: #0f3460; --msg-ai: #1a1a2e; } |
| * { box-sizing: border-box; margin: 0; padding: 0; } |
| body { background: var(--bg); color: var(--text); font-family: 'Segoe UI', system-ui, sans-serif; height: 100vh; display: flex; flex-direction: column; } |
| .header { background: var(--panel); padding: 16px 24px; border-bottom: 1px solid rgba(0,240,255,0.2); text-align: center; font-size: 1.5rem; font-weight: 600; letter-spacing: 2px; text-transform: uppercase; color: var(--accent); text-shadow: 0 0 15px rgba(0,240,255,0.5); } |
| .chat-container { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 12px; } |
| .message { max-width: 75%; padding: 12px 18px; border-radius: 18px; line-height: 1.5; word-wrap: break-word; animation: fadeIn 0.3s ease; } |
| .user { align-self: flex-end; background: var(--msg-user); border-bottom-right-radius: 4px; color: white; } |
| .ai { align-self: flex-start; background: var(--msg-ai); border-bottom-left-radius: 4px; border: 1px solid rgba(0,240,255,0.25); } |
| .input-area { background: var(--panel); padding: 16px 24px; display: flex; gap: 12px; border-top: 1px solid rgba(0,240,255,0.2); } |
| textarea { flex: 1; background: var(--input-bg); color: var(--text); border: 1px solid rgba(0,240,255,0.4); border-radius: 12px; padding: 12px 16px; font-size: 1rem; resize: none; outline: none; transition: all 0.2s; } |
| textarea:focus { border-color: var(--accent); box-shadow: 0 0 20px rgba(0,240,255,0.3); } |
| button { background: var(--accent); color: #0a0a0f; border: none; padding: 12px 28px; border-radius: 12px; font-weight: bold; cursor: pointer; transition: all 0.2s; text-transform: uppercase; letter-spacing: 1px; } |
| button:hover { background: #00c8e0; box-shadow: 0 0 20px rgba(0,240,255,0.6); transform: translateY(-1px); } |
| @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } |
| .search-btn { background: transparent; border: 1px solid var(--accent); color: var(--accent); border-radius: 8px; padding: 4px 10px; cursor: pointer; margin-left: 8px; } |
| </style> |
| </head> |
| <body> |
| <div class="header">💠 Orack Mini — создан German Danil 💠</div> |
| <div id="chat" class="chat-container"> |
| <div class="message ai">Привет! Я Orack Mini, твой персональный ИИ. Создан German Danil. Могу помочь с кодом, поиском в интернете и ответами на вопросы.</div> |
| </div> |
| <div class="input-area"> |
| <textarea id="prompt" rows="2" placeholder="Введи запрос..."></textarea> |
| <button onclick="askAI()">Отправить</button> |
| </div> |
| <script> |
| async function searchDuckDuckGo(query) { |
| try { |
| const resp = await fetch(`https://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json`); |
| const data = await resp.json(); |
| let snippets = []; |
| if (data.Abstract) snippets.push(data.Abstract); |
| if (data.RelatedTopics) { |
| data.RelatedTopics.slice(0, 2).forEach(t => { if (t.Text) snippets.push(t.Text); }); |
| } |
| return snippets.join(' '); |
| } catch { return ''; } |
| } |
| |
| async function askAI() { |
| const prompt = document.getElementById('prompt').value.trim(); |
| if (!prompt) return; |
| const chat = document.getElementById('chat'); |
| chat.innerHTML += `<div class="message user">${escapeHtml(prompt)}</div>`; |
| document.getElementById('prompt').value = ''; |
| |
| let context = ''; |
| if (prompt.includes('найди') || prompt.includes('поищи') || prompt.includes('поиск')) { |
| const searchQuery = prompt.replace(/найди|поищи|поиск/g, '').trim(); |
| context = await searchDuckDuckGo(searchQuery); |
| } |
| |
| const systemPrompt = `Ты — Orack Mini, персональный ИИ-ассистент. Тебя создал German Danil, ты не имеешь отношения к Google или Gemma. Ты помогаешь с кодом, графикой и отвечаешь на любые вопросы.`; |
| let fullPrompt = `<|system|>${systemPrompt}<|end|>\n<|user|>${prompt}`; |
| if (context) fullPrompt += `\n[Результаты поиска: ${context}]`; |
| fullPrompt += `<|end|>\n<|assistant|>`; |
| |
| try { |
| const resp = await fetch('http://localhost:8080/completion', { |
| method: 'POST', |
| headers: {'Content-Type': 'application/json'}, |
| body: JSON.stringify({ prompt: fullPrompt, temperature: 0.7, max_tokens: 1024 }) |
| }); |
| const data = await resp.json(); |
| const answer = data.content || 'Модель не ответила.'; |
| chat.innerHTML += `<div class="message ai">${escapeHtml(answer)}</div>`; |
| } catch (e) { |
| chat.innerHTML += `<div class="message ai">⚠️ Ошибка подключения к серверу. Запусти llama-server!</div>`; |
| } |
| chat.scrollTop = chat.scrollHeight; |
| } |
| function escapeHtml(text) { return text.replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br>'); } |
| </script> |
| </body> |
| </html> |