Jeppcode commited on
Commit
f74183e
·
verified ·
1 Parent(s): 3ef2b47

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +339 -131
app.py CHANGED
@@ -2,211 +2,419 @@ import gradio as gr
2
  import subprocess
3
  from huggingface_hub import hf_hub_download
4
 
5
- # --- 1. Setup & Install ---
 
 
6
  subprocess.run("pip install -q 'llama_cpp_python==0.3.15'", shell=True, check=False)
7
  from llama_cpp import Llama
8
 
9
- # --- 2. Load Model (GGUF) ---
 
10
  MODEL_REPO = "Jeppcode/ScalableLab2"
11
- GGUF_FILENAME = "model-q4_k_m.gguf"
12
 
13
  print(f"Downloading GGUF model {MODEL_REPO}/{GGUF_FILENAME} ...")
14
- try:
15
- model_path = hf_hub_download(
16
- repo_id=MODEL_REPO,
17
- filename=GGUF_FILENAME,
18
- )
19
- except Exception as e:
20
- print(f"Error: {e}")
21
- model_path = ""
22
-
23
- llm = None
24
- if model_path:
25
- print("Initializing llama.cpp LLM ...")
26
- llm = Llama(
27
- model_path=model_path,
28
- n_ctx=2048,
29
- n_threads=2,
30
- n_batch=64,
31
- use_mmap=True,
32
- use_mlock=False,
33
- )
34
 
35
- # --- 3. Chat Logic ---
 
36
  STYLE_SYSTEM_PROMPTS = {
37
  "Default": "You are a helpful, polite assistant.",
38
- "Short answer": "Answer as concisely as possible, usually in 1–3 sentences.",
39
- "Detailed explanation": "Give clear, structured and detailed explanations.",
 
 
 
 
 
 
 
 
 
40
  }
41
 
42
- def _extract_text(content):
 
 
 
 
 
 
 
 
43
  if isinstance(content, list):
44
- return "\n".join(b.get("text", "") for b in content if isinstance(b, dict) and b.get("type") == "text")
45
- return str(content)
 
 
 
 
 
 
 
 
46
 
47
- def chat_fn(message, history, max_new_tokens, style):
48
- if not llm: return "Error: Model not loaded."
49
-
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  system_prompt = STYLE_SYSTEM_PROMPTS.get(style, STYLE_SYSTEM_PROMPTS["Default"])
51
- prompt = f"System: {system_prompt}\nConversation:\n"
 
 
 
 
 
52
  for msg in history or []:
53
  role = msg.get("role")
54
- txt = _extract_text(msg.get("content", ""))
55
- if txt:
56
- if role == "user": prompt += f"User: {txt}\n"
57
- elif role == "assistant": prompt += f"Assistant: {txt}\n"
58
- prompt += f"User: {message}\nAssistant:"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  output = llm(
61
  prompt,
62
  max_tokens=int(max_new_tokens),
63
- temperature=0.7,
64
- top_p=0.9,
65
- stop=["User:", "Assistant:", "System:"],
 
66
  )
67
- return output["choices"][0]["text"].strip()
68
 
69
- # --- 4. THEME CSS ---
70
- # Note: We use a reliable Unsplash URL for the background to avoid file path errors
71
- christmas_css = """
72
- /* Import a festive font */
73
- @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&family=Lato:wght@400;700&display=swap');
 
 
 
 
 
 
 
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  body {
76
- background: url('https://images.unsplash.com/photo-1543169176-78e7c10b27b6?q=80&w=2560&auto=format&fit=crop') no-repeat center center fixed !important;
77
- background-size: cover !important;
78
- color: #f0f0f0;
79
- font-family: "Lato", sans-serif;
80
  }
81
 
82
- h1, h2, h3 {
83
- font-family: "Cinzel", serif;
84
- color: #FFD700 !important; /* Gold */
85
- text-shadow: 0px 2px 4px rgba(0,0,0,0.8);
86
- text-transform: uppercase;
 
 
87
  }
88
 
89
- /* 1. HERO HEADER STYLES */
90
  .hero {
91
  position: relative;
92
- margin: 1rem auto;
93
  max-width: 900px;
94
- padding: 2rem;
95
  border-radius: 20px;
96
- /* Dark Holiday Red/Black Gradient */
97
- background: linear-gradient(135deg, rgba(60, 10, 10, 0.9), rgba(10, 20, 30, 0.95));
98
- border: 2px solid #D4AF37; /* Gold Border */
99
- box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), 0 0 10px rgba(212, 175, 55, 0.3);
 
 
 
 
 
100
  overflow: hidden;
 
 
 
 
 
101
  display: flex;
 
102
  align-items: center;
103
- gap: 20px;
104
  }
105
 
106
- .hero-image {
107
- width: 100px;
108
- height: 100px;
109
- border-radius: 50%;
110
- border: 3px solid #D4AF37;
111
- overflow: hidden;
112
  flex-shrink: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
 
115
- .hero-image img {
116
- width: 100%;
117
- height: 100%;
118
- object-fit: cover;
 
 
119
  }
120
 
121
- .hero-text h1 {
122
  margin: 0;
123
- font-size: 1.8rem;
124
- letter-spacing: 0.1em;
 
125
  }
126
 
127
- .hero-text p {
128
- margin-top: 0.5rem;
129
- font-size: 1rem;
130
- color: #E0E0E0;
 
 
 
 
 
 
131
  }
132
 
133
- /* 2. GRADIO CONTAINER TRANSPARENCY */
134
- .gradio-container {
135
- background: transparent !important;
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
 
138
- /* 3. COMPONENT STYLING */
139
- .group, .form, .bubble-wrap {
140
- background: rgba(15, 23, 42, 0.85) !important;
141
- border: 1px solid rgba(255, 255, 255, 0.3) !important;
142
- border-radius: 15px !important;
143
- backdrop-filter: blur(5px);
144
  }
145
 
146
- /* Messages */
147
- .user-message {
148
- background: linear-gradient(135deg, #8E0E00, #3E0000) !important; /* Holiday Red */
149
- border-left: 4px solid #D4AF37 !important;
150
- color: white !important;
 
 
151
  }
152
 
153
- .bot-message {
154
- background: linear-gradient(135deg, #0f2e18, #05140a) !important; /* Pine Green */
155
- border-left: 4px solid #71B280 !important;
156
- color: #E0E0E0 !important;
 
 
 
157
  }
158
 
159
- /* Inputs */
160
- textarea, input {
161
- background-color: rgba(0, 0, 0, 0.6) !important;
162
- border: 1px solid #D4AF37 !important;
163
- color: white !important;
 
164
  }
165
 
166
  /* Buttons */
167
- button {
168
- background: linear-gradient(to right, #D4AF37, #C5A028) !important;
169
- color: black !important;
170
- font-weight: bold !important;
171
  border: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
- footer {visibility: hidden}
174
  """
175
 
176
- # --- 5. BUILD THE UI ---
177
- # FIX: Removed 'css' from constructor to prevent TypeError
178
- with gr.Blocks(title="Christmas Lab 2") as demo:
179
-
180
- # HTML Header
181
  gr.HTML(
182
  """
183
  <div class="hero">
184
- <div class="hero-image">
185
- <img src="https://images.unsplash.com/photo-1482517967863-00e15c9b4499?q=80&w=400&auto=format&fit=crop" alt="Christmas AI">
186
- </div>
187
  <div class="hero-text">
188
- <h1>Holiday AI Workshop</h1>
189
  <p>
190
- Welcome to the Winter Lab. I am powered by fine-tuned Llama models
191
- and hot cocoa. Ask me anything!
 
192
  </p>
193
  </div>
 
 
194
  </div>
195
  """
196
  )
197
-
198
- max_new_tokens_slider = gr.Slider(minimum=16, maximum=256, value=64, step=8, label="Max Response Length")
199
- style_radio = gr.Radio(["Default", "Short answer", "Detailed explanation"], value="Detailed explanation", label="Style")
200
 
201
- # Chat Interface
202
- chat = gr.ChatInterface(
203
- fn=chat_fn,
204
- additional_inputs=[max_new_tokens_slider, style_radio],
205
- additional_inputs_accordion="Workshop Settings",
206
  )
207
 
208
- # FIX: Assign CSS manually after creation
209
- demo.css = christmas_css
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
  if __name__ == "__main__":
212
- demo.launch(allowed_paths=["."])
 
2
  import subprocess
3
  from huggingface_hub import hf_hub_download
4
 
5
+ # 1. Install llama-cpp-python in runtime (not via requirements.txt)
6
+ # Important: remove `llama-cpp-python` from requirements.txt
7
+ # or Spaces will try to build from source and get stuck.
8
  subprocess.run("pip install -q 'llama_cpp_python==0.3.15'", shell=True, check=False)
9
  from llama_cpp import Llama
10
 
11
+
12
+ # 2. Load your GGUF model from Hugging Face
13
  MODEL_REPO = "Jeppcode/ScalableLab2"
14
+ GGUF_FILENAME = "model-q4_k_m.gguf" # or "model-f16.gguf" if you prefer fp16
15
 
16
  print(f"Downloading GGUF model {MODEL_REPO}/{GGUF_FILENAME} ...")
17
+ model_path = hf_hub_download(
18
+ repo_id=MODEL_REPO,
19
+ filename=GGUF_FILENAME,
20
+ )
21
+
22
+ print("Initializing llama.cpp LLM ...")
23
+ llm = Llama(
24
+ model_path=model_path,
25
+ n_ctx=2048, # context length
26
+ n_threads=2, # threads (Spaces CPU is limited)
27
+ n_batch=64, # batch size for generation
28
+ use_mmap=True,
29
+ use_mlock=False,
30
+ )
 
 
 
 
 
 
31
 
32
+
33
+ # 3. Style presets (system prompts)
34
  STYLE_SYSTEM_PROMPTS = {
35
  "Default": "You are a helpful, polite assistant.",
36
+ "Short answer": (
37
+ "You are a helpful assistant. Answer as concisely as possible, usually in 1-3 sentences."
38
+ ),
39
+ "Detailed explanation": (
40
+ "You are a helpful teaching assistant. Give clear, structured and detailed explanations, "
41
+ "often with bullet points or numbered steps when useful."
42
+ ),
43
+ "Step-by-step reasoning": (
44
+ "You are a careful problem solver. Think step by step and explain your reasoning clearly "
45
+ "before giving the final answer."
46
+ ),
47
  }
48
 
49
+
50
+ def _extract_text_from_content(content):
51
+ """
52
+ In Gradio 6 ChatInterface, history uses the messages format.
53
+ content can be:
54
+ - a string
55
+ - a list of blocks: [{"type": "text", "text": "..."} , ...]
56
+ We convert it into a simple string.
57
+ """
58
  if isinstance(content, list):
59
+ texts = []
60
+ for block in content:
61
+ if isinstance(block, dict) and block.get("type") == "text":
62
+ texts.append(block.get("text", ""))
63
+ else:
64
+ texts.append(str(block))
65
+ return "\n".join(t for t in texts if t)
66
+ else:
67
+ return str(content)
68
+
69
 
70
+ def build_prompt(message, history, style):
71
+ """
72
+ Build a simple text prompt for llama.cpp based on:
73
+ - chosen style (system prompt)
74
+ - conversation history
75
+ - latest user message
76
+
77
+ Format:
78
+ System: ...
79
+ Conversation:
80
+ User: ...
81
+ Assistant: ...
82
+ ...
83
+ User: <current message>
84
+ Assistant:
85
+ """
86
  system_prompt = STYLE_SYSTEM_PROMPTS.get(style, STYLE_SYSTEM_PROMPTS["Default"])
87
+
88
+ prompt_parts = []
89
+ prompt_parts.append(f"System: {system_prompt}\n")
90
+ prompt_parts.append("Conversation:\n")
91
+
92
+ # history is a list of dicts: {"role": "...", "content": ...}
93
  for msg in history or []:
94
  role = msg.get("role")
95
+ content = _extract_text_from_content(msg.get("content", ""))
96
+
97
+ if not content:
98
+ continue
99
+
100
+ if role == "user":
101
+ prompt_parts.append(f"User: {content}\n")
102
+ elif role == "assistant":
103
+ prompt_parts.append(f"Assistant: {content}\n")
104
+ elif role == "system":
105
+ prompt_parts.append(f"System (previous): {content}\n")
106
+
107
+ # Current user message
108
+ prompt_parts.append(f"User: {message}\n")
109
+ prompt_parts.append("Assistant:")
110
+
111
+ full_prompt = "".join(prompt_parts)
112
+ return full_prompt
113
+
114
+
115
+ def chat_fn(message, history, max_new_tokens, temperature, top_p, repetition_penalty, style):
116
+ """
117
+ Main function called by Gradio ChatInterface.
118
+ - message: latest user input
119
+ - history: previous messages (messages format)
120
+ - other params: sliders / radio buttons
121
+ """
122
+ prompt = build_prompt(message, history, style)
123
+
124
+ # Handle deterministic mode when temperature == 0
125
+ temp = float(temperature)
126
+ top_p_val = float(top_p)
127
+ repeat_pen = float(repetition_penalty)
128
+
129
+ if temp <= 0.0:
130
+ temp = 0.0
131
+ top_p_val = 1.0 # less important when temp=0
132
 
133
  output = llm(
134
  prompt,
135
  max_tokens=int(max_new_tokens),
136
+ temperature=temp,
137
+ top_p=top_p_val,
138
+ repeat_penalty=repeat_pen,
139
+ stop=["User:", "Assistant:", "System:", "Conversation:"],
140
  )
 
141
 
142
+ reply = output["choices"][0]["text"].strip()
143
+ return reply
144
+
145
+
146
+ # 4. Sliders and controls (extra inputs to ChatInterface)
147
+ max_new_tokens_slider = gr.Slider(
148
+ minimum=16,
149
+ maximum=256,
150
+ value=64,
151
+ step=8,
152
+ label="Max new tokens (response length)",
153
+ )
154
 
155
+ temperature_slider = gr.Slider(
156
+ minimum=0.0,
157
+ maximum=1.5,
158
+ value=0.0,
159
+ step=0.1,
160
+ label="Temperature (0 = deterministic, higher = more random)",
161
+ )
162
+
163
+ top_p_slider = gr.Slider(
164
+ minimum=0.1,
165
+ maximum=1.0,
166
+ value=0.9,
167
+ step=0.05,
168
+ label="Top-p (nucleus sampling)",
169
+ )
170
+
171
+ repetition_penalty_slider = gr.Slider(
172
+ minimum=0.8,
173
+ maximum=1.3,
174
+ value=1.0,
175
+ step=0.05,
176
+ label="Repetition penalty",
177
+ )
178
+
179
+ style_radio = gr.Radio(
180
+ choices=[
181
+ "Default",
182
+ "Short answer",
183
+ "Detailed explanation",
184
+ "Step-by-step reasoning",
185
+ ],
186
+ value="Detailed explanation",
187
+ label="Answer style",
188
+ )
189
+
190
+ # 5. Christmas theme CSS
191
+ # Assumes the image "Cute-Christmas-Background-edit-online-1.jpg"
192
+ # is in the Space repository root, so we can reference it as file=...
193
+ christmas_css = """
194
  body {
195
+ background: radial-gradient(circle at top, #1b1c2b 0, #050611 55%, #000000 100%);
196
+ color: #fdf6e3;
197
+ font-family: "Georgia", "Times New Roman", serif;
 
198
  }
199
 
200
+ /* Use the repo image as a soft background */
201
+ .gradio-container {
202
+ background:
203
+ linear-gradient(rgba(0,0,0,0.55), rgba(0,0,0,0.85)),
204
+ url("file=Cute-Christmas-Background-edit-online-1.jpg");
205
+ background-size: cover;
206
+ background-position: center;
207
  }
208
 
209
+ /* Christmas hero card */
210
  .hero {
211
  position: relative;
212
+ margin: 0 auto 1.5rem auto;
213
  max-width: 900px;
214
+ padding: 1.6rem 1.6rem 1.4rem 1.6rem;
215
  border-radius: 20px;
216
+ border: 1px solid rgba(255, 255, 255, 0.14);
217
+ background:
218
+ radial-gradient(circle at top,
219
+ rgba(255, 255, 255, 0.15),
220
+ rgba(5, 5, 15, 0.98)
221
+ );
222
+ box-shadow:
223
+ 0 0 28px rgba(0, 0, 0, 0.9),
224
+ 0 0 70px rgba(180, 0, 40, 0.55);
225
  overflow: hidden;
226
+ }
227
+
228
+ .hero-inner {
229
+ position: relative;
230
+ z-index: 1;
231
  display: flex;
232
+ gap: 1.2rem;
233
  align-items: center;
 
234
  }
235
 
236
+ .hero-badge {
 
 
 
 
 
237
  flex-shrink: 0;
238
+ width: 92px;
239
+ height: 92px;
240
+ border-radius: 999px;
241
+ overflow: hidden;
242
+ border: 2px solid rgba(255, 255, 255, 0.8);
243
+ box-shadow:
244
+ 0 0 24px rgba(0, 0, 0, 0.9),
245
+ 0 0 30px rgba(0, 160, 90, 0.7);
246
+ background:
247
+ radial-gradient(circle at top,
248
+ rgba(255,255,255,0.3),
249
+ rgba(5,5,10,1)
250
+ ),
251
+ url("file=Cute-Christmas-Background-edit-online-1.jpg");
252
+ background-size: cover;
253
+ background-position: center;
254
  }
255
 
256
+ .hero-text h1 {
257
+ margin: 0 0 0.35rem 0;
258
+ font-size: 1.35rem;
259
+ letter-spacing: 0.08em;
260
+ text-transform: uppercase;
261
+ color: #ffefe0;
262
  }
263
 
264
+ .hero-text p {
265
  margin: 0;
266
+ font-size: 0.95rem;
267
+ color: #f8eadd;
268
+ line-height: 1.5;
269
  }
270
 
271
+ .hero-keyline {
272
+ margin-top: 1rem;
273
+ height: 1px;
274
+ background-image: linear-gradient(
275
+ 90deg,
276
+ rgba(255, 255, 255, 0),
277
+ rgba(255, 225, 150, 0.9),
278
+ rgba(255, 255, 255, 0)
279
+ );
280
+ opacity: 0.9;
281
  }
282
 
283
+ /* Chat card */
284
+ .gr-chat-interface {
285
+ position: relative !important;
286
+ border-radius: 18px !important;
287
+ border: 1px solid rgba(255, 255, 255, 0.16);
288
+ background:
289
+ linear-gradient(
290
+ 135deg,
291
+ rgba(5, 10, 20, 0.96),
292
+ rgba(10, 15, 30, 0.96)
293
+ );
294
+ box-shadow:
295
+ 0 0 24px rgba(0, 0, 0, 0.9),
296
+ 0 0 50px rgba(0, 180, 120, 0.45);
297
+ overflow: hidden;
298
  }
299
 
300
+ /* Chat messages as gift tags */
301
+ .gr-chat-message {
302
+ position: relative;
303
+ border-radius: 14px !important;
304
+ border: 1px solid rgba(255, 255, 255, 0.06) !important;
305
+ backdrop-filter: blur(4px);
306
  }
307
 
308
+ .gr-chat-message.user {
309
+ background:
310
+ radial-gradient(circle at top left,
311
+ rgba(0, 180, 120, 0.28),
312
+ rgba(10, 15, 25, 0.98)
313
+ ) !important;
314
+ border-left: 4px solid #00c278 !important;
315
  }
316
 
317
+ .gr-chat-message.bot {
318
+ background:
319
+ radial-gradient(circle at top left,
320
+ rgba(230, 30, 90, 0.32),
321
+ rgba(10, 10, 24, 0.98)
322
+ ) !important;
323
+ border-left: 4px solid #ff4060 !important;
324
  }
325
 
326
+ /* Input area */
327
+ textarea, .gr-text-input, .gr-textbox {
328
+ background: rgba(5, 10, 20, 0.98) !important;
329
+ border-radius: 999px !important;
330
+ border: 1px solid rgba(255, 255, 255, 0.4) !important;
331
+ color: #fffbf3 !important;
332
  }
333
 
334
  /* Buttons */
335
+ button, .gr-button {
336
+ background: linear-gradient(135deg, #ff4060, #00c278) !important;
337
+ border-radius: 999px !important;
 
338
  border: none !important;
339
+ color: #fffbf3 !important;
340
+ font-weight: 600 !important;
341
+ letter-spacing: 0.08em;
342
+ text-transform: uppercase;
343
+ box-shadow:
344
+ 0 0 16px rgba(0, 0, 0, 0.9),
345
+ 0 0 26px rgba(255, 204, 140, 0.6);
346
+ }
347
+
348
+ button:hover, .gr-button:hover {
349
+ filter: brightness(1.07);
350
+ box-shadow:
351
+ 0 0 18px rgba(255, 90, 120, 0.8),
352
+ 0 0 32px rgba(0, 200, 150, 0.7);
353
+ }
354
+
355
+ /* Sliders and controls */
356
+ input[type="range"] {
357
+ accent-color: #ff4060;
358
+ }
359
+
360
+ /* Scrollbar */
361
+ ::-webkit-scrollbar {
362
+ width: 8px;
363
+ }
364
+ ::-webkit-scrollbar-track {
365
+ background: transparent;
366
+ }
367
+ ::-webkit-scrollbar-thumb {
368
+ background: rgba(255, 255, 255, 0.5);
369
+ border-radius: 999px;
370
  }
 
371
  """
372
 
373
+
374
+ # 6. Build the UI with Blocks so we can add a hero section
375
+ with gr.Blocks(css=christmas_css) as demo:
 
 
376
  gr.HTML(
377
  """
378
  <div class="hero">
379
+ <div class="hero-inner">
380
+ <div class="hero-badge"></div>
 
381
  <div class="hero-text">
382
+ <h1>Scalable Lab 2 Christmas Chat</h1>
383
  <p>
384
+ Talk to our fine tuned Llama based model, wrapped as a compact GGUF
385
+ and running on CPU. Use the controls below to tune response length,
386
+ randomness and style like a Christmas DJ for language models.
387
  </p>
388
  </div>
389
+ </div>
390
+ <div class="hero-keyline"></div>
391
  </div>
392
  """
393
  )
 
 
 
394
 
395
+ gr.Markdown(
396
+ "🎄 **Tip:** Try switching between short answers and step by step reasoning, "
397
+ "and play with temperature and top p to see how the model behaves."
 
 
398
  )
399
 
400
+ gr.ChatInterface(
401
+ fn=chat_fn,
402
+ title="Lab 2 – Fine tuned GGUF model",
403
+ description=(
404
+ "Chat with our fine tuned Llama based model, converted to GGUF and "
405
+ "loaded via llama.cpp from `Jeppcode/ScalableLab2`.\n\n"
406
+ "Use the controls in the accordion below like a DJ board to tweak "
407
+ "response length, randomness and style."
408
+ ),
409
+ additional_inputs=[
410
+ max_new_tokens_slider,
411
+ temperature_slider,
412
+ top_p_slider,
413
+ repetition_penalty_slider,
414
+ style_radio,
415
+ ],
416
+ additional_inputs_accordion="Generation controls",
417
+ )
418
 
419
  if __name__ == "__main__":
420
+ demo.launch()