JustScriptzz commited on
Commit
760f39f
·
verified ·
1 Parent(s): 2aaef5a

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. README.md +9 -7
  2. app.py +62 -0
  3. index.html +210 -18
  4. requirements.txt +7 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Nexus Plus V2 Chat
3
- emoji: 🏃
4
- colorFrom: yellow
5
- colorTo: yellow
6
- sdk: static
 
 
7
  pinned: false
 
 
8
  ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Nexus Plus v2
3
+ emoji: ⚡
4
+ colorFrom: purple
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 5.43.1
8
+ app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
+ hardware: zero-a10g
12
  ---
 
 
app.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
4
+ from huggingface_hub import hf_hub_download
5
+
6
+ REPO = "JustScriptzz/nexus-plus-v2"
7
+
8
+ def load_model():
9
+ tokenizer = AutoTokenizer.from_pretrained(REPO, trust_remote_code=True)
10
+ bnb_config = BitsAndBytesConfig(
11
+ load_in_4bit=True,
12
+ bnb_4bit_quant_type="nf4",
13
+ bnb_4bit_compute_dtype=torch.float16,
14
+ bnb_4bit_use_double_quant=True,
15
+ )
16
+ model = AutoModelForCausalLM.from_pretrained(
17
+ REPO,
18
+ quantization_config=bnb_config,
19
+ device_map="auto",
20
+ trust_remote_code=True,
21
+ )
22
+ return model, tokenizer
23
+
24
+ model, tokenizer = load_model()
25
+
26
+ @torch.inference_mode()
27
+ def chat(message, history):
28
+ messages = [{"role": "user", "content": message}]
29
+ text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
30
+ inputs = tokenizer(text, return_tensors="pt").to(model.device)
31
+ outputs = model.generate(
32
+ **inputs,
33
+ max_new_tokens=512,
34
+ temperature=0.7,
35
+ top_p=0.8,
36
+ do_sample=True,
37
+ )
38
+ reply = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
39
+ return reply or "..."
40
+
41
+ demo = gr.ChatInterface(
42
+ fn=chat,
43
+ title="Nexus Plus v2",
44
+ description="Qwen3-4B fine-tuned with QLoRA — smarter, deeper reasoning",
45
+ theme=gr.themes.Base(
46
+ primary_hue="purple",
47
+ neutral_hue="slate",
48
+ font=gr.themes.GoogleFont("Inter"),
49
+ ).set(
50
+ body_background_fill="#0a0a0f",
51
+ body_text_color="#e1e1e6",
52
+ block_background_fill="#111118",
53
+ block_border_color="#1e1e2e",
54
+ block_label_text_color="#888",
55
+ input_background_fill="#111118",
56
+ input_background_fill_focus="#111118",
57
+ button_primary_background_fill="#7c3aed",
58
+ button_primary_background_fill_hover="#6d28d9",
59
+ ),
60
+ )
61
+
62
+ demo.launch()
index.html CHANGED
@@ -1,19 +1,211 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Nexus Plus v2</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
9
+ * { font-family: 'Inter', sans-serif; box-sizing: border-box; }
10
+ body { background: #0a0a0f; color: #e1e1e6; margin: 0; min-height: 100vh; display: flex; flex-direction: column; align-items: center; }
11
+ .container { max-width: 680px; width: 100%; padding: 16px; display: flex; flex-direction: column; height: 100vh; }
12
+ .header { text-align: center; padding: 16px 0 12px; flex-shrink: 0; }
13
+ .header h1 { font-size: 28px; font-weight: 700; margin: 0; }
14
+ .header h1 span { color: #a78bfa; }
15
+ .header p { color: #666; font-size: 13px; margin-top: 4px; }
16
+ .status { display: flex; align-items: center; gap: 8px; padding: 6px 14px; background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06); border-radius: 20px; font-size: 12px; color: #888; width: fit-content; margin: 0 auto 12px; }
17
+ .dot { width: 6px; height: 6px; border-radius: 50%; background: #22c55e; flex-shrink: 0; }
18
+ .dot.loading { background: #eab308; animation: pulse 1s infinite; }
19
+ .dot.error { background: #ef4444; }
20
+ @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.3} }
21
+ .chat-box { flex: 1; overflow-y: auto; padding: 8px 0; }
22
+ .msg { padding: 12px 16px; margin: 8px 0; border-radius: 16px; max-width: 85%; line-height: 1.6; font-size: 15px; white-space: pre-wrap; word-wrap: break-word; }
23
+ .msg-user { background: linear-gradient(135deg, #7c3aed22, #6d28d922); border: 1px solid #7c3aed33; margin-left: auto; }
24
+ .msg-bot { background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06); }
25
+ .typing { display: inline-flex; gap: 4px; padding: 8px 14px; background: rgba(255,255,255,0.04); border-radius: 12px; margin: 8px 0; }
26
+ .typing i { width: 7px; height: 7px; background: #7c3aed; border-radius: 50%; animation: bounce 1.4s infinite; display: inline-block; }
27
+ .typing i:nth-child(2) { animation-delay: 0.16s; }
28
+ .typing i:nth-child(3) { animation-delay: 0.32s; }
29
+ @keyframes bounce { 0%,60%,100%{transform:translateY(0);opacity:0.4} 30%{transform:translateY(-6px);opacity:1} }
30
+ .input-row { display: flex; gap: 8px; padding: 12px 0; flex-shrink: 0; }
31
+ .input-row input { flex: 1; background: #111118; border: 1px solid rgba(255,255,255,0.1); color: #fff; border-radius: 16px; padding: 12px 16px; font-size: 15px; outline: none; }
32
+ .input-row input:focus { box-shadow: 0 0 0 2px #7c3aed44; }
33
+ .input-row button { background: #7c3aed; color: #fff; border: none; border-radius: 16px; padding: 12px 24px; font-weight: 600; cursor: pointer; flex-shrink: 0; }
34
+ .input-row button:hover { background: #6d28d9; }
35
+ .input-row button:disabled { opacity: 0.5; cursor: not-allowed; }
36
+ .welcome { background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06); border-radius: 16px; padding: 16px; margin: 8px 0; text-align: center; color: #888; font-size: 14px; }
37
+ .links { text-align: center; padding: 8px 0; flex-shrink: 0; }
38
+ .links a { color: #555; font-size: 12px; text-decoration: none; }
39
+ .links a:hover { color: #888; }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <div class="container">
44
+ <div class="header">
45
+ <h1>Nexus <span>Plus</span> <span style="color:#555;font-size:18px;font-weight:400">v2</span></h1>
46
+ <p>Qwen3-4B fine-tuned with QLoRA</p>
47
+ </div>
48
+ <div id="tokenBar" style="display:flex;gap:8px;margin-bottom:8px;flex-shrink:0;">
49
+ <input type="password" id="tokenInput" placeholder="HF token (hf_...)" style="flex:1;background:#111118;border:1px solid rgba(255,255,255,0.1);color:#fff;border-radius:16px;padding:10px 16px;font-size:13px;outline:none;">
50
+ <button onclick="saveToken()" style="background:#7c3aed;color:#fff;border:none;border-radius:16px;padding:10px 16px;font-size:13px;cursor:pointer;">Save</button>
51
+ </div>
52
+ <div class="status"><div class="dot" id="statusDot"></div><span id="statusText">Ready</span></div>
53
+ <div class="chat-box" id="chatBox">
54
+ <div class="welcome">
55
+ <strong>Hello!</strong> I'm Nexus Plus v2 — powered by Qwen3-4B fine-tuned with QLoRA.<br>Ask me anything.
56
+ </div>
57
+ </div>
58
+ <div class="input-row">
59
+ <input type="text" id="userInput" placeholder="Type a message..." autofocus>
60
+ <button id="sendBtn" onclick="sendMessage()">Send</button>
61
+ </div>
62
+ <div class="links">
63
+ <a href="https://huggingface.co/JustScriptzz/nexus-plus-v2">Model</a> ·
64
+ <a href="https://github.com/JustScriptzz/nexus-smAll-web">GitHub</a> ·
65
+ <a href="https://justscriptzz-nexus-smAll-v1-chat.hf.space">SmAll v1</a>
66
+ </div>
67
+ </div>
68
+
69
+ <script>
70
+ const chatBox = document.getElementById('chatBox');
71
+ const userInput = document.getElementById('userInput');
72
+ const sendBtn = document.getElementById('sendBtn');
73
+ const statusDot = document.getElementById('statusDot');
74
+ const statusText = document.getElementById('statusText');
75
+ const HISTORY = [];
76
+ let generating = false;
77
+ let HF_TOKEN = localStorage.getItem('hf_token') || '';
78
+
79
+ if (HF_TOKEN) {
80
+ document.getElementById('tokenInput').value = HF_TOKEN;
81
+ document.getElementById('tokenBar').style.display = 'none';
82
+ }
83
+
84
+ function saveToken() {
85
+ HF_TOKEN = document.getElementById('tokenInput').value.trim();
86
+ if (HF_TOKEN) {
87
+ localStorage.setItem('hf_token', HF_TOKEN);
88
+ document.getElementById('tokenBar').style.display = 'none';
89
+ }
90
+ }
91
+
92
+ function setStatus(state, text) {
93
+ statusDot.className = 'dot' + (state === 'loading' ? ' loading' : state === 'error' ? ' error' : '');
94
+ statusText.textContent = text;
95
+ }
96
+
97
+ function addMsg(role, text) {
98
+ const div = document.createElement('div');
99
+ div.className = 'msg ' + (role === 'user' ? 'msg-user' : 'msg-bot');
100
+ div.textContent = text;
101
+ chatBox.appendChild(div);
102
+ chatBox.scrollTop = chatBox.scrollHeight;
103
+ return div;
104
+ }
105
+
106
+ function addTyping() {
107
+ const div = document.createElement('div');
108
+ div.className = 'typing';
109
+ div.id = 'typing';
110
+ div.innerHTML = '<i></i><i></i><i></i>';
111
+ chatBox.appendChild(div);
112
+ chatBox.scrollTop = chatBox.scrollHeight;
113
+ }
114
+
115
+ function removeTyping() {
116
+ const t = document.getElementById('typing');
117
+ if (t) t.remove();
118
+ }
119
+
120
+ async function sendMessage() {
121
+ const msg = userInput.value.trim();
122
+ if (!msg || generating) return;
123
+ if (!HF_TOKEN) {
124
+ document.getElementById('tokenBar').style.display = 'flex';
125
+ document.getElementById('tokenInput').focus();
126
+ return;
127
+ }
128
+ generating = true;
129
+ sendBtn.disabled = true;
130
+ userInput.value = '';
131
+
132
+ // Remove welcome
133
+ const w = chatBox.querySelector('.welcome');
134
+ if (w) w.remove();
135
+
136
+ addMsg('user', msg);
137
+ HISTORY.push({ role: 'user', content: msg });
138
+ addTyping();
139
+ setStatus('loading', 'Generating...');
140
+
141
+ try {
142
+ const resp = await fetch('https://router.huggingface.co/hf-inference/models/JustScriptzz/nexus-plus-v2/v1/chat/completions', {
143
+ method: 'POST',
144
+ headers: {
145
+ 'Content-Type': 'application/json',
146
+ 'Authorization': 'Bearer ' + HF_TOKEN
147
+ },
148
+ body: JSON.stringify({
149
+ model: 'JustScriptzz/nexus-plus-v2',
150
+ messages: HISTORY,
151
+ max_tokens: 512,
152
+ temperature: 0.7,
153
+ top_p: 0.8,
154
+ stream: true
155
+ })
156
+ });
157
+
158
+ if (!resp.ok) {
159
+ const err = await resp.text();
160
+ throw new Error(`API error ${resp.status}: ${err}`);
161
+ }
162
+
163
+ removeTyping();
164
+ const botDiv = addMsg('bot', '');
165
+ const reader = resp.body.getReader();
166
+ const decoder = new TextDecoder();
167
+ let full = '';
168
+ let buffer = '';
169
+
170
+ while (true) {
171
+ const { done, value } = await reader.read();
172
+ if (done) break;
173
+ buffer += decoder.decode(value, { stream: true });
174
+ const lines = buffer.split('\n');
175
+ buffer = lines.pop();
176
+ for (const line of lines) {
177
+ if (line.startsWith('data: ')) {
178
+ const data = line.slice(6);
179
+ if (data === '[DONE]') continue;
180
+ try {
181
+ const j = JSON.parse(data);
182
+ const delta = j.choices?.[0]?.delta?.content;
183
+ if (delta) {
184
+ full += delta;
185
+ botDiv.textContent = full;
186
+ chatBox.scrollTop = chatBox.scrollHeight;
187
+ }
188
+ } catch(e) {}
189
+ }
190
+ }
191
+ }
192
+
193
+ HISTORY.push({ role: 'assistant', content: full });
194
+ setStatus('ready', 'Ready');
195
+ } catch (e) {
196
+ removeTyping();
197
+ addMsg('bot', 'Error: ' + e.message);
198
+ setStatus('error', 'Error — try again');
199
+ }
200
+
201
+ generating = false;
202
+ sendBtn.disabled = false;
203
+ userInput.focus();
204
+ }
205
+
206
+ userInput.addEventListener('keydown', e => {
207
+ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); }
208
+ });
209
+ </script>
210
+ </body>
211
  </html>
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ transformers
4
+ bitsandbytes
5
+ accelerate
6
+ huggingface_hub
7
+ peft