KokabAI-Static / index.html
Hosdroid's picture
Upload index.html with huggingface_hub
197c540 verified
Raw History Blame Contribute Delete
6.69 kB
<!DOCTYPE html>
<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,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
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>