import os from threading import Thread import gradio as gr import torch from transformers import ( AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer, ) # Support spaces.GPU if available on ZeroGPU try: import spaces has_spaces = True except ImportError: has_spaces = False def gpu_decorator(fn): if has_spaces: return spaces.GPU(duration=120)(fn) return fn MODEL_ID = "Hatsunama/Qwen3-4B-OBLITERATED-repaired" device = "cuda" if torch.cuda.is_available() else "cpu" print(f"Loading tokenizer from {MODEL_ID}...") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True) if tokenizer.pad_token_id is None: tokenizer.pad_token_id = tokenizer.eos_token_id or 151643 print(f"Loading model {MODEL_ID} on {device}...") model = AutoModelForCausalLM.from_pretrained( MODEL_ID, torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32, trust_remote_code=True ).to(device) if hasattr(model, "generation_config") and model.generation_config is not None: model.generation_config.max_length = None def strip_thought(text): """Strip reasoning/thought block from historical turns for cleaner multi-turn context.""" if "" in text: return text.split("")[-1].strip() return text def format_display_text(raw_text): """Format ... block into a collapsible thought accordion for Gradio chat.""" if "" in raw_text: parts = raw_text.split("") if len(parts) > 1: thought = parts[0].replace("", "").strip() answer = parts[1].strip() return f"
💭 Thought Process\n\n{thought}\n\n
\n\n{answer}" else: thought = parts[0].replace("", "").strip() return f"
💭 Thinking...\n\n{thought}\n\n
" return raw_text @gpu_decorator def predict(message, history): # Format messages conversation = [ {"role": "system", "content": "You are a helpful, respectful, and honest assistant."} ] if history: for item in history: if isinstance(item, dict): if item.get("role") == "system": continue role = item.get("role", "user") content = item.get("content", "") if role == "assistant": content = strip_thought(content) conversation.append({"role": role, "content": content}) elif isinstance(item, (list, tuple)) and len(item) == 2: conversation.append({"role": "user", "content": str(item[0])}) conversation.append({"role": "assistant", "content": strip_thought(str(item[1]))}) conversation.append({"role": "user", "content": str(message)}) text = tokenizer.apply_chat_template( conversation, tokenize=False, add_generation_prompt=True ) model_inputs = tokenizer([text], return_tensors="pt").to(device) streamer = TextIteratorStreamer( tokenizer, timeout=120.0, skip_prompt=True, skip_special_tokens=True ) pad_id = tokenizer.pad_token_id or 151643 eos_tokens = [151645, 151643] if tokenizer.eos_token_id is not None and tokenizer.eos_token_id not in eos_tokens: eos_tokens.append(tokenizer.eos_token_id) generate_kwargs = dict( model_inputs, streamer=streamer, max_new_tokens=2048, do_sample=True, top_p=0.95, top_k=20, temperature=0.6, repetition_penalty=1.15, pad_token_id=pad_id, eos_token_id=eos_tokens, ) errors = [] def worker(): try: model.generate(**generate_kwargs) except Exception as e: errors.append(e) streamer.end() thread = Thread(target=worker) thread.daemon = True thread.start() try: partial_text = "" for new_text in streamer: partial_text += new_text yield format_display_text(partial_text) except Exception as e: if errors: yield f"⚠️ Generation error: {errors[0]}" else: yield f"⚠️ Stream error: {e}" demo = gr.ChatInterface( fn=predict, title="🧠 Qwen3-4B-OBLITERATED Chat", description="Live un-censored / abliterated Qwen 4B model running on Hugging Face ZeroGPU. Supports dynamic reasoning (`/think` and `/no_think`)." ) if __name__ == "__main__": demo.launch()