Spaces:
Running
Running
Download index.html from Hosdroid/KokabAI-Static: direct link, hf CLI and curl.
- Browser
- Download file 6.69 kB
-
https://huggingface.co/spaces/Hosdroid/KokabAI-Static/resolve/main/index.html
- Command line
-
hf download hf://spaces/Hosdroid/KokabAI-Static/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Hosdroid/KokabAI-Static/resolve/main/index.html
6.69 kB
| <html lang="fa-IR" dir="rtl" data-theme="dark"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>کوکب AI by کوکب تک</title> | |
| <style> | |
| :root { | |
| --bg:#161616;--surface:#282828;--text:#fff;--text-sec:rgba(255,255,255,.66);--accent:#75B6EB;--border:rgba(255,255,255,.12); | |
| } | |
| *{margin:0;padding:0;box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;} | |
| body{background:var(--bg);color:var(--text);height:100vh;display:flex;flex-direction:column;} | |
| .header{padding:16px;text-align:center;border-bottom:1px solid var(--border);} | |
| .header h1{font-size:20px;margin-bottom:4px;} | |
| .header p{color:var(--text-sec);font-size:13px;} | |
| .chat-container{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:16px;max-width:800px;margin:0 auto;width:100%;} | |
| .message{display:flex;gap:12px;max-width:80%;} | |
| .message.user{align-self:flex-end;flex-direction:row-reverse;} | |
| .avatar{width:32px;height:32px;border-radius:50%;background:var(--surface);flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;} | |
| .bubble{padding:12px 16px;border-radius:16px;line-height:1.6;font-size:15px;word-wrap:break-word;} | |
| .user .bubble{background:var(--accent);color:#000;border-radius:16px 16px 4px 16px;} | |
| .ai .bubble{background:var(--surface);color:var(--text);border-radius:16px 16px 16px 4px;} | |
| .input-area{padding:20px;border-top:1px solid var(--border);max-width:800px;margin:0 auto;width:100%;} | |
| .input-group{display:flex;gap:10px;background:var(--surface);padding:8px;border-radius:24px;border:1px solid var(--border);} | |
| input{flex:1;background:transparent;border:none;outline:none;color:var(--text);padding:8px 12px;font-size:15px;} | |
| button{background:var(--text);color:var(--bg);border:none;padding:10px 20px;border-radius:20px;cursor:pointer;font-weight:bold;transition:opacity .2s;} | |
| button:disabled{opacity:.5;cursor:default;} | |
| .error{color:#ff545a;background:rgba(255,84,90,.1);padding:10px;border-radius:8px;font-size:13px;} | |
| pre{background:rgba(0,0,0,.3);padding:10px;border-radius:8px;overflow-x:auto;} | |
| code{font-family:monospace;} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h1>کوکب AI</h1> | |
| <p>قدرت گرفته از Qwen3.8-Flash-pro</p> | |
| </div> | |
| <div class="chat-container" id="chat"></div> | |
| <div class="input-area"> | |
| <div class="input-group"> | |
| <input type="text" id="inp" placeholder="پیام خود را بنویسید..." autocomplete="off"> | |
| <button id="btn" disabled>ارسال</button> | |
| </div> | |
| </div> | |
| <script> | |
| // تنظیمات - توکن از طریق Secrets Space خوانده میشود | |
| const MODEL = "kokabtak/Qwen3.8-Flash-pro"; | |
| // در Static Space نمیتوان مستقیماً به environment variables دسترسی داشت | |
| // بنابراین کاربر باید توکن را در Settings > Variables وارد کند و ما از fetch با هدر استفاده میکنیم | |
| // اما چون Static Space است، بهترین راه این است که کاربر توکن خودش را در تنظیمات فضا وارد کند | |
| // و اینجا از یک متغیر سراسری که توسط HF تزریق میشود استفاده کنیم (اگر پشتیبانی شود) | |
| // یا اینکه از کاربر بخواهیم توکن را وارد کند. | |
| // برای سادگی، فرض میکنیم توکن در window.HF_TOKEN قرار دارد (توسط HF Inject میشود) | |
| // اگر کار نکرد، کاربر باید توکن را دستی وارد کند. | |
| let HF_TOKEN = ""; | |
| // تلاش برای دریافت توکن از متادیتای صفحه (روش استاندارد HF برای Static Spaces) | |
| fetch("/config.json") | |
| .then(r => r.json()) | |
| .then(cfg => { | |
| if(cfg.hf_token) HF_TOKEN = cfg.hf_token; | |
| }) | |
| .catch(() => {}); | |
| const chatDiv = document.getElementById('chat'); | |
| const inp = document.getElementById('inp'); | |
| const btn = document.getElementById('btn'); | |
| let messages = []; | |
| inp.addEventListener('input', () => btn.disabled = !inp.value.trim()); | |
| inp.addEventListener('keydown', e => { if(e.key==='Enter' && !e.shiftKey) send(); }); | |
| btn.addEventListener('click', send); | |
| function addMsg(role, text) { | |
| const div = document.createElement('div'); | |
| div.className = `message ${role}`; | |
| const av = document.createElement('div'); | |
| av.className = 'avatar'; | |
| av.textContent = role === 'user' ? '👤' : '🤖'; | |
| const bub = document.createElement('div'); | |
| bub.className = 'bubble'; | |
| let html = text.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); | |
| html = html.replace(/\*\*(.+?)\*\*/g, '<b>$1</b>'); | |
| html = html.replace(/`(.+?)`/g, '<code>$1</code>'); | |
| html = html.replace(/\n/g, '<br>'); | |
| bub.innerHTML = html; | |
| div.appendChild(av); | |
| div.appendChild(bub); | |
| chatDiv.appendChild(div); | |
| chatDiv.scrollTop = chatDiv.scrollHeight; | |
| } | |
| async function send() { | |
| const txt = inp.value.trim(); | |
| if(!txt) return; | |
| // اگر توکن نداریم، از کاربر بخواهیم وارد کند | |
| if(!HF_TOKEN) { | |
| HF_TOKEN = prompt("لطفاً توکن Hugging Face خود را وارد کنید:\n(میتوانید از Settings > Variables > YOUR_TOKEN_HERE را کپی کنید)"); | |
| if(!HF_TOKEN) { | |
| addMsg('ai', '❌ بدون توکن، امکان ارسال پیام نیست.'); | |
| return; | |
| } | |
| } | |
| inp.value = ''; | |
| btn.disabled = true; | |
| addMsg('user', txt); | |
| messages.push({role: 'user', content: txt}); | |
| const loadingDiv = document.createElement('div'); | |
| loadingDiv.className = 'message ai'; | |
| loadingDiv.innerHTML = '<div class="avatar">🤖</div><div class="bubble">در حال فکر کردن...</div>'; | |
| chatDiv.appendChild(loadingDiv); | |
| chatDiv.scrollTop = chatDiv.scrollHeight; | |
| try { | |
| const res = await fetch(`https://api-inference.huggingface.co/models/${MODEL}/v1/chat/completions`, { | |
| method: 'POST', | |
| headers: { | |
| 'Authorization': `Bearer ${HF_TOKEN}`, | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| model: MODEL, | |
| messages: messages, | |
| max_tokens: 1024 | |
| }) | |
| }); | |
| chatDiv.removeChild(loadingDiv); | |
| if(!res.ok) { | |
| const err = await res.text(); | |
| throw new Error(`${res.status}: ${err}`); | |
| } | |
| const data = await res.json(); | |
| const reply = data.choices[0].message.content; | |
| messages.push({role: 'assistant', content: reply}); | |
| addMsg('ai', reply); | |
| } catch(e) { | |
| chatDiv.removeChild(loadingDiv); | |
| addMsg('ai', `❌ خطا: ${e.message}`); | |
| console.error(e); | |
| } | |
| btn.disabled = false; | |
| inp.focus(); | |
| } | |
| </script> | |
| </body> | |
| </html> | |