kirikir13 commited on
Commit
9fc1b0f
·
verified ·
1 Parent(s): b068e84

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -437
app.py CHANGED
@@ -1,459 +1,111 @@
1
- # =============================================================================
2
- # Qwen 3.6 27B CoderBot — Hugging Face ZeroGPU Space
3
- # Model: DavidAU/Qwen3.6-27B-Heretic-Uncensored-FINETUNE-NEO-CODE-Di-IMatrix-MAX-GGUF
4
- # Quant: Q4_K_M (~16GB, 94.5% of BF16) — fits ZeroGPU 48GB VRAM
5
- # =============================================================================
6
 
7
- import spaces
8
- import gradio as gr
9
- import os
10
- import json
11
- import tempfile
12
- import traceback
13
- from pathlib import Path
14
- from typing import List, Dict, Optional, Generator
15
-
16
- # ---------------------------------------------------------------------------
17
- # MODEL CONFIGURATION — change these env vars or edit directly
18
- # ---------------------------------------------------------------------------
19
-
20
- MODEL_REPO = os.environ.get(
21
- "MODEL_REPO",
22
- "DavidAU/Qwen3.6-27B-Heretic-Uncensored-FINETUNE-NEO-CODE-Di-IMatrix-MAX-GGUF",
23
- )
24
- MODEL_FILE = os.environ.get(
25
- "MODEL_FILE",
26
- "Qwen3.6-27B-NEO-CODE-HERE-2T-OT-Q4_K_M.gguf", # 16.1 GB, 94.5% of BF16
27
- )
28
- N_CTX = int(os.environ.get("N_CTX", "8192")) # context window
29
- N_GPU_LAYERS = int(os.environ.get("N_GPU_LAYERS", "-1")) # -1 = offload all layers to GPU
30
-
31
- # ---------------------------------------------------------------------------
32
- # SYSTEM PROMPT — tuned for coding / code review
33
- # ---------------------------------------------------------------------------
34
-
35
- SYSTEM_PROMPT = """You are Qwen CoderBot — an uncensored 27B coding assistant. You excel at:
36
 
37
- Writing production-quality code in Python, TypeScript, JavaScript, Rust, Go, C/C++, SQL, shell, and more
38
- • Debugging, refactoring, and reviewing complex code
39
- • Explaining algorithms, data structures, architecture patterns, and system design
40
- • Reading and understanding code files users share with you
41
-
42
- Rules:
43
- - Always put code in ```language ... ``` blocks with the correct language tag.
44
- - When the user shares files, read them carefully before answering. Refer back to specific lines or functions.
45
- - Be precise, concise, and thorough. Prefer working, runnable solutions.
46
- - If you're unsure, say so — never fabricate APIs or libraries.
47
- - For Qwen "thinking" mode, you may use ... blocks.
48
  """
49
 
50
- # ===========================================================================
51
- # MODEL LOADER — lazy singleton, re-initialised inside @spaces.GPU when
52
- # the GPU becomes available. We download the GGUF at module level (CPU)
53
- # and stream it into GPU memory on first call.
54
- # ===========================================================================
55
-
56
- _llm = None
57
- _model_path: Optional[str] = None
58
-
59
-
60
- def _ensure_model_downloaded() -> str:
61
- """Download the GGUF once to the persistent HuggingFace cache."""
62
- global _model_path
63
- if _model_path is not None:
64
- return _model_path
65
- from huggingface_hub import hf_hub_download
66
- print(f"[CoderBot] Downloading {MODEL_FILE} from {MODEL_REPO} …")
67
- _model_path = hf_hub_download(
68
- repo_id=MODEL_REPO,
69
- filename=MODEL_FILE,
70
- )
71
- print(f"[CoderBot] Model cached at {_model_path}")
72
- return _model_path
73
-
74
-
75
- def _get_llm():
76
- """Return (or create) the llama-cpp Llama instance on GPU."""
77
- global _llm
78
- if _llm is not None:
79
- return _llm
80
- from llama_cpp import Llama
81
- model_path = _ensure_model_downloaded()
82
- print(f"[CoderBot] Loading model onto GPU (n_gpu_layers={N_GPU_LAYERS}) …")
83
- _llm = Llama(
84
- model_path=model_path,
85
- n_ctx=N_CTX,
86
- n_gpu_layers=N_GPU_LAYERS,
87
- chat_format="chatml",
88
- verbose=False,
89
- seed=-1,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  )
91
- print("[CoderBot] Model loaded ✓")
92
- return _llm
93
-
94
-
95
- # ===========================================================================
96
- # FILE PARSERS — extract text from every common dev / doc format
97
- # ===========================================================================
98
-
99
- def _read_text(path: str, encoding: str = "utf-8") -> str:
100
- """Safe text-file reader with encoding fallback."""
101
- encodings = [encoding, "utf-8-sig", "latin-1", "cp1252", "utf-16"]
102
- for enc in encodings:
103
- try:
104
- with open(path, "r", encoding=enc) as f:
105
- return f.read()
106
- except (UnicodeDecodeError, UnicodeError):
107
- continue
108
- # Last resort
109
- with open(path, "r", encoding="utf-8", errors="replace") as f:
110
- return f.read()
111
-
112
-
113
- def parse_file(file_path: str, file_name: str) -> str:
114
- """
115
- Parse a single file and return a markdown-formatted string with its
116
- contents, ready to be pasted into the model context.
117
- """
118
- suffix = Path(file_name).suffix.lower()
119
- name = Path(file_name).name
120
-
121
- # ---- Plain text / code files ----
122
- if suffix in (
123
- ".txt", ".md", ".py", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
124
- ".css", ".scss", ".less", ".html", ".htm", ".xml", ".svg",
125
- ".yaml", ".yml", ".toml", ".ini", ".cfg", ".conf",
126
- ".sh", ".bash", ".zsh", ".fish", ".ps1", ".bat",
127
- ".sql", ".graphql", ".prisma",
128
- ".c", ".cpp", ".cc", ".cxx", ".h", ".hpp", ".hh",
129
- ".java", ".kt", ".kts", ".scala", ".groovy",
130
- ".go", ".rs", ".rb", ".php", ".pl", ".pm",
131
- ".swift", ".r", ".lua", ".zig", ".nim", ".dart",
132
- ".dockerfile", ".makefile", ".cmake", ".gradle",
133
- ".env", ".gitignore", ".editorconfig",
134
- ".tf", ".tfvars", ".hcl",
135
- ".vue", ".svelte", ".astro",
136
- ".ipynb",
137
- ):
138
- content = _read_text(file_path)
139
- lang = suffix.lstrip(".")
140
- if suffix == ".md":
141
- lang = "markdown"
142
- elif suffix in (".yml",):
143
- lang = "yaml"
144
- elif suffix in (".tf", ".tfvars"):
145
- lang = "hcl"
146
- elif suffix in (".htm",):
147
- lang = "html"
148
- elif suffix in (".Dockerfile",):
149
- lang = "dockerfile"
150
- elif suffix == ".ipynb":
151
- # Parse Jupyter notebook to extract code + markdown cells
152
- try:
153
- nb = json.loads(content)
154
- lines = []
155
- for cell in nb.get("cells", []):
156
- cell_type = cell.get("cell_type", "code")
157
- source = "".join(cell.get("source", []))
158
- if cell_type == "code":
159
- lines.append(f"```python\n{source}\n```")
160
- else:
161
- lines.append(source)
162
- content = "\n\n".join(lines)
163
- return f"### 📓 {name}\n\n{content}\n\n---\n"
164
- except Exception:
165
- pass
166
- return f"### 📄 `{name}`\n```{lang}\n{content}\n```\n\n---\n"
167
-
168
- # ---- JSON ----
169
- if suffix == ".json":
170
- content = _read_text(file_path)
171
- try:
172
- parsed = json.loads(content)
173
- pretty = json.dumps(parsed, indent=2, ensure_ascii=False)
174
- return f"### 📄 `{name}`\n```json\n{pretty}\n```\n\n---\n"
175
- except Exception:
176
- return f"### 📄 `{name}`\n```json\n{content}\n```\n\n---\n"
177
 
178
- # ---- CSV ----
179
- if suffix == ".csv":
180
- import csv
181
- import io
182
- content = _read_text(file_path)
183
- reader = csv.reader(io.StringIO(content))
184
- rows = list(reader)
185
- if len(rows) > 51: # truncate very large CSVs
186
- truncated = rows[:50]
187
- truncated.append([f"… {len(rows) - 50} more rows truncated"])
188
- rows = truncated
189
- col_widths = [max(len(str(cell)) for cell in col) for col in zip(*rows)]
190
- table = "\n".join(
191
- "| " + " | ".join(str(cell).ljust(w) for cell, w in zip(row, col_widths)) + " |"
192
- for row in rows
193
- )
194
- header_sep = "|-" + "-|-".join("-" * w for w in col_widths) + "-|"
195
- table = table.split("\n", 1)
196
- table.insert(1, header_sep)
197
- return f"### 📊 `{name}`\n" + "\n".join(table) + "\n\n---\n"
198
 
199
- # ---- Word documents ----
200
- if suffix == ".docx":
201
- try:
202
- import docx
203
- doc = docx.Document(file_path)
204
- text = "\n\n".join(p.text for p in doc.paragraphs if p.text.strip())
205
- return f"### 📝 `{name}`\n{text}\n\n---\n"
206
- except ImportError:
207
- return f"### ⚠️ `{name}` (DOCX — install python-docx)\n\n---\n"
208
- except Exception as e:
209
- return f"### ⚠️ `{name}` (DOCX parse error: {e})\n\n---\n"
210
 
211
- # ---- PDF ----
212
- if suffix == ".pdf":
213
- try:
214
- import pdfplumber
215
- with pdfplumber.open(file_path) as pdf:
216
- text = "\n\n".join(
217
- page.extract_text() or "" for page in pdf.pages
218
- )
219
- return f"### 📑 `{name}`\n{text}\n\n---\n"
220
- except ImportError:
221
- return f"### ⚠️ `{name}` (PDF — install pdfplumber)\n\n---\n"
222
- except Exception as e:
223
- return f"### ⚠️ `{name}` (PDF parse error: {e})\n\n---\n"
224
 
225
- # ---- Fallback: try to read as text ----
226
- try:
227
- content = _read_text(file_path)
228
- return f"### 📄 `{name}`\n```\n{content[:10000]}\n```\n\n---\n"
229
- except Exception as e:
230
- return f"### ❌ `{name}` (could not read: {e})\n\n---\n"
231
 
232
 
233
- def parse_all_files(files) -> str:
234
- """Parse a list of Gradio file objects into a single context string."""
235
- if not files:
236
- return ""
237
- parts = []
238
- for f in files:
239
- # Gradio file objects may be dicts or have .name attribute
240
- if isinstance(f, dict):
241
- path = f.get("path") or f.get("name")
242
- name = f.get("orig_name") or f.get("name", "unknown")
243
- elif hasattr(f, "name"):
244
- path = f.name
245
- name = getattr(f, "orig_name", Path(path).name)
246
- else:
247
- path = str(f)
248
- name = Path(path).name
249
- try:
250
- parts.append(parse_file(path, name))
251
- except Exception as e:
252
- parts.append(f"### ❌ `{name}`\nParse error: {e}\n\n---\n")
253
- return "\n".join(parts)
254
 
 
 
255
 
256
- # ===========================================================================
257
- # MAIN GENERATION FUNCTION — wrapped with @spaces.GPU for ZeroGPU
258
- # ===========================================================================
259
 
260
- @spaces.GPU
261
- def chatbot_respond(
262
- message: str,
263
- history: List,
264
- uploaded_files,
265
- ) -> Generator[List, None, None]:
266
- """
267
- Called on every user message. history is in Gradio 6 "messages" format:
268
- list of {"role": "user"|"assistant", "content": "..."} dicts.
269
- uploaded_files is the current file list from gr.File.
270
 
271
- Yields the updated history list after each token chunk for streaming.
272
- """
273
- # ---- 1. Parse any newly uploaded files ----
274
- file_context = parse_all_files(uploaded_files)
275
-
276
- # ---- 2. Build the message list for llama-cpp-python (ChatML format) ----
277
- messages = [{"role": "system", "content": SYSTEM_PROMPT}]
278
-
279
- # If files were uploaded, inject their content
280
- if file_context:
281
- messages.append({
282
- "role": "user",
283
- "content": (
284
- "[The user has uploaded the following files. "
285
- "Read them carefully and refer to them in your answers.]\n\n"
286
- + file_context
287
- ),
288
- })
289
- messages.append({
290
- "role": "assistant",
291
- "content": (
292
- "Got it! I've read through all the uploaded files. "
293
- "Ask me anything about them."
294
- ),
295
- })
296
-
297
- # Append the real conversation history (Gradio 6 "messages" format)
298
- for entry in history:
299
- role = entry.get("role", "user")
300
- content = entry.get("content", "")
301
- if content:
302
- messages.append({"role": role, "content": content})
303
-
304
- # Append the current user message
305
- messages.append({"role": "user", "content": message})
306
-
307
- # ---- 3. Stream the completion ----
308
- llm = _get_llm()
309
- stream = llm.create_chat_completion(
310
- messages=messages,
311
- temperature=0.6,
312
- top_p=0.8,
313
- top_k=20,
314
- max_tokens=4096,
315
- stream=True,
316
- stop=["<|im_end|>", "<|endoftext|>"],
317
  )
318
 
319
- partial = ""
320
- for chunk in stream:
321
- choices = chunk.get("choices", [])
322
- if choices:
323
- delta = choices[0].get("delta", {})
324
- content = delta.get("content", "")
325
- if content:
326
- partial += content
327
- # YIELD in Gradio 6 "messages" format
328
- yield history + [{"role": "user", "content": message},
329
- {"role": "assistant", "content": partial}]
330
-
331
- # Final yield
332
- yield history + [{"role": "user", "content": message},
333
- {"role": "assistant", "content": partial}]
334
-
335
-
336
- # ===========================================================================
337
- # GRADIO UI — clean two‑column layout: chat on the left, file drop on right
338
- # ===========================================================================
339
-
340
- def create_demo() -> gr.Blocks:
341
- with gr.Blocks(
342
- title="Qwen 3.6 27B CoderBot",
343
- ) as demo:
344
-
345
- gr.Markdown(
346
- """
347
- # 🧠 Qwen 3.6 27B CoderBot
348
- **Uncensored · Code-optimized · ZeroGPU-powered**
349
- Drop code files, docs, JSON, CSVs — chat about them with a 27B coding LLM.
350
- """,
351
- )
352
-
353
- with gr.Row(equal_height=True):
354
- # ---- LEFT: Chat ----
355
- with gr.Column(scale=3):
356
- chatbot = gr.Chatbot(
357
- label="Chat",
358
- height=580,
359
- avatar_images=(
360
- None,
361
- "https://huggingface.co/front/assets/huggingface_logo-noborder.svg",
362
- ),
363
- )
364
- with gr.Row():
365
- msg = gr.Textbox(
366
- placeholder="Ask about your code, or just start chatting …",
367
- scale=8,
368
- show_label=False,
369
- container=False,
370
- )
371
- send = gr.Button("▶", scale=1, variant="primary", min_width=48)
372
- with gr.Row():
373
- clear_btn = gr.Button("🗑 Clear chat", size="sm", scale=1)
374
-
375
- # ---- RIGHT: File upload + info ----
376
- with gr.Column(scale=1, elem_classes="file-upload-col"):
377
- gr.Markdown("### 📎 Drop Files")
378
- files = gr.File(
379
- file_count="multiple",
380
- label="Upload code, docs, data …",
381
- file_types=[
382
- ".py", ".ts", ".tsx", ".js", ".jsx", ".mjs",
383
- ".json", ".yaml", ".yml", ".toml",
384
- ".md", ".txt", ".csv",
385
- ".html", ".css", ".scss", ".xml", ".svg",
386
- ".c", ".cpp", ".h", ".hpp", ".java", ".kt",
387
- ".go", ".rs", ".rb", ".php", ".swift",
388
- ".sql", ".sh", ".bash", ".ps1",
389
- ".docx", ".pdf",
390
- ".env", ".gitignore", ".cfg", ".ini", ".conf",
391
- ".vue", ".svelte", ".dockerfile",
392
- ],
393
- )
394
- gr.Markdown(
395
- """
396
- **Supported:** `.py` `.ts` `.js` `.json` `.md` `.docx` `.pdf` `.csv`
397
- `.yaml` `.toml` `.html` `.css` `.sql` `.go` `.rs` `.java` + more
398
-
399
- Files are parsed and sent as context — the model reads them
400
- before answering.
401
- """
402
- )
403
- uploaded_info = gr.Markdown("_No files uploaded yet._")
404
- file_content_state = gr.State("")
405
-
406
- # ---- Event wiring ----
407
-
408
- def update_file_info(uploaded):
409
- if not uploaded:
410
- return "_No files uploaded._", ""
411
- names = []
412
- for f in uploaded:
413
- if isinstance(f, dict):
414
- names.append(f.get("orig_name", "?"))
415
- else:
416
- names.append(getattr(f, "orig_name", Path(str(f)).name))
417
- label = "**Uploaded:**\n" + "\n".join(f"• `{n}`" for n in names)
418
- return label, parse_all_files(uploaded)
419
-
420
- def respond(message, history, current_files):
421
- """Generator wrapper that streams into the chatbot."""
422
- for updated_history in chatbot_respond(message, history, current_files):
423
- yield updated_history
424
-
425
- # Trigger response on text submit or send button
426
- msg.submit(
427
- respond,
428
- inputs=[msg, chatbot, files],
429
- outputs=[chatbot],
430
- ).then(lambda: "", None, [msg])
431
-
432
- send.click(
433
- respond,
434
- inputs=[msg, chatbot, files],
435
- outputs=[chatbot],
436
- ).then(lambda: "", None, [msg])
437
-
438
- # Clear chat — return empty list (Gradio 6 "messages" format)
439
- clear_btn.click(lambda: [], None, chatbot, queue=False)
440
-
441
- # File upload feedback
442
- files.change(update_file_info, files, [uploaded_info, file_content_state])
443
-
444
- return demo
445
-
446
 
447
- # ===========================================================================
448
- # LAUNCH
449
- # ===========================================================================
 
 
450
 
451
  if __name__ == "__main__":
452
- demo = create_demo()
453
- demo.queue(default_concurrency_limit=1, max_size=4)
454
  demo.launch(
455
- css="""
456
- .file-upload-col { background: var(--background-fill-secondary); border-radius: 12px; padding: 16px; }
457
- footer { display: none !important; }
458
- """,
459
  )
 
 
 
 
 
 
1
 
2
+ """Mr. Smith-Davinci v3.0 — v1 GPU Space entry point.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
+ v1 (GPU Space): DEFAULT_BACKEND=hf_local_gguf runs DavidAU GGUF on GPU
 
 
 
 
 
 
 
 
 
 
5
  """
6
 
7
+ import os
8
+ import sys
9
+ import traceback
10
+ import subprocess
11
+
12
+ # ── Runtime install: llama-cpp-python (avoids build timeout on v1) ──
13
+ try:
14
+ import llama_cpp
15
+ except ImportError:
16
+ print("[RUNTIME] Installing llama-cpp-python from pre-built wheel...", flush=True)
17
+ subprocess.check_call([
18
+ sys.executable, "-m", "pip", "install", "--no-cache-dir",
19
+ "--extra-index-url", "https://abetlen.github.io/llama-cpp-python/whl/cu121",
20
+ "llama-cpp-python"
21
+ ])
22
+ import llama_cpp
23
+ print("[RUNTIME] llama-cpp-python installed successfully", flush=True)
24
+
25
+ # ── Monkey-patch: fix gradio_client 1.4.0 boolean-schema crash ──
26
+ try:
27
+ from gradio_client import utils as gc_utils
28
+ _original_get_type = gc_utils.get_type
29
+
30
+ def _patched_get_type(schema):
31
+ if isinstance(schema, bool):
32
+ return "boolean" if schema else "null"
33
+ return _original_get_type(schema)
34
+
35
+ gc_utils.get_type = _patched_get_type
36
+ except Exception:
37
+ pass
38
+
39
+ # ── Monkey-patch: restore HfFolder for gradio 5.0.0 + hfh 1.x compat ──
40
+ try:
41
+ import huggingface_hub
42
+ if not hasattr(huggingface_hub, "HfFolder"):
43
+ class _HfFolder:
44
+ path = None
45
+ @staticmethod
46
+ def get_token(): return None
47
+ @staticmethod
48
+ def save_token(t): pass
49
+ @staticmethod
50
+ def delete_token(): pass
51
+ huggingface_hub.HfFolder = _HfFolder
52
+ except Exception:
53
+ pass
54
+
55
+
56
+ def _is_on_hf_spaces() -> bool:
57
+ return bool(
58
+ os.environ.get("SPACE_ID")
59
+ or os.environ.get("HUGGINGFACE_SPACE_ID")
60
+ or os.environ.get("HF_SPACE")
61
+ or os.path.exists("/.hf_spaces")
62
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ def _get_default_backend() -> str:
66
+ return "hf_local_gguf"
 
 
 
 
 
 
 
 
 
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ def _get_chairman_space_id() -> str:
70
+ return os.environ.get("CHAIRMAN_SPACE_ID", "kirikir13/mr-SmithDavinci_Full-Harness_v1")
 
 
 
 
71
 
72
 
73
+ try:
74
+ print("Importing smith_davinci...", file=sys.stderr)
75
+ from smith_davinci.engine import SmithEngine
76
+ from ui.app import create_ui
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
+ print("Creating engine...", file=sys.stderr)
79
+ engine = SmithEngine()
80
 
81
+ from smith_davinci.backends.hf_local_gguf import HFLocalGGUFBackend
82
+ engine.registry._backends["hf_local_gguf"] = HFLocalGGUFBackend
83
+ print("[REGISTRY] Force-registered hf_local_gguf backend", file=sys.stderr)
84
 
85
+ engine.default_backend = _get_default_backend()
86
+ engine.chairman_space_id = _get_chairman_space_id()
87
+ engine.is_hf_spaces = _is_on_hf_spaces()
 
 
 
 
 
 
 
88
 
89
+ print(
90
+ f"[ENV] Backend: {engine.default_backend} | "
91
+ f"Chairman Space: {engine.chairman_space_id} | "
92
+ f"On HF: {engine.is_hf_spaces}",
93
+ file=sys.stderr,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  )
95
 
96
+ print("Creating UI...", file=sys.stderr)
97
+ demo = create_ui(engine)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ print("DEMO CREATED — handing off to runtime", file=sys.stderr)
100
+ except Exception as e:
101
+ print("FATAL STARTUP ERROR:", repr(e), file=sys.stderr)
102
+ traceback.print_exc(file=sys.stderr)
103
+ raise
104
 
105
  if __name__ == "__main__":
 
 
106
  demo.launch(
107
+ debug=True,
108
+ share=False,
109
+ server_name="0.0.0.0",
110
+ server_port=7860,
111
  )