fomext commited on
Commit
e72d1aa
Β·
verified Β·
1 Parent(s): dc4dc6c

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -0
app.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Minimal Gradio smoke-test for Qwen3-30B-A3B on ZeroGPU.
3
+ No FastAPI, no custom routes β€” just enough to confirm the Space runs.
4
+ """
5
+
6
+ # ── Patch HfFolder before importing gradio ────────────────────────────────────
7
+ import huggingface_hub as _hf_hub
8
+
9
+ if not hasattr(_hf_hub, "HfFolder"):
10
+ class _HfFolder:
11
+ _token = None
12
+ @classmethod
13
+ def get_token(cls):
14
+ try:
15
+ from huggingface_hub.utils import get_token
16
+ return get_token()
17
+ except Exception:
18
+ return cls._token
19
+ @classmethod
20
+ def save_token(cls, token): cls._token = token
21
+ @classmethod
22
+ def delete_token(cls): cls._token = None
23
+
24
+ _hf_hub.HfFolder = _HfFolder # type: ignore[attr-defined]
25
+
26
+ # ── Imports ───────────────────────────────────────────────────────────────────
27
+ import gradio as gr
28
+ import spaces
29
+ import torch
30
+ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
31
+ from threading import Thread
32
+
33
+ MODEL_ID = "Qwen/Qwen3-30B-A3B"
34
+
35
+ _tok = None
36
+ _model = None
37
+
38
+ def get_model():
39
+ global _tok, _model
40
+ if _model is None:
41
+ print("Loading model…")
42
+ _tok = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
43
+ _model = AutoModelForCausalLM.from_pretrained(
44
+ MODEL_ID, torch_dtype=torch.bfloat16,
45
+ device_map="auto", trust_remote_code=True,
46
+ )
47
+ _model.eval()
48
+ print("Model ready βœ“")
49
+ return _tok, _model
50
+
51
+
52
+ @spaces.GPU(duration=120)
53
+ def respond(message, history):
54
+ tok, model = get_model()
55
+
56
+ msgs = [{"role": h["role"], "content": h["content"]} for h in history]
57
+ msgs.append({"role": "user", "content": message})
58
+
59
+ text = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True)
60
+ inputs = tok(text, return_tensors="pt").to(model.device)
61
+
62
+ streamer = TextIteratorStreamer(tok, skip_prompt=True, skip_special_tokens=True)
63
+ t = Thread(
64
+ target=model.generate,
65
+ kwargs=dict(**inputs, max_new_tokens=2048, do_sample=True,
66
+ temperature=0.7, top_p=0.9,
67
+ pad_token_id=tok.eos_token_id, streamer=streamer),
68
+ daemon=True,
69
+ )
70
+ t.start()
71
+
72
+ output = ""
73
+ for chunk in streamer:
74
+ output += chunk
75
+ yield output
76
+ t.join()
77
+
78
+
79
+ with gr.Blocks() as demo:
80
+ # Sign-in is required so ZeroGPU can recognize *your* Pro account from
81
+ # inside the embedded iframe and apply your 40-min daily quota instead
82
+ # of the anonymous-visitor quota (~3 min).
83
+ gr.LoginButton()
84
+
85
+ gr.ChatInterface(
86
+ fn=respond,
87
+ type="messages",
88
+ title="Qwen3-30B-A3B",
89
+ description="ZeroGPU-backed Qwen3-30B-A3B chat",
90
+ )
91
+
92
+ if __name__ == "__main__":
93
+ demo.launch()