File size: 4,753 Bytes
306debd
58a1d31
306debd
903166e
58a1d31
 
306debd
5d6a8dd
58a1d31
eb3d588
dab1096
 
 
 
 
58a1d31
 
 
 
 
7e20c5d
5d6a8dd
 
 
 
 
 
 
 
b8795e6
58a1d31
 
 
dab1096
a67f3c8
58a1d31
 
7e20c5d
e460a69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99133af
e460a69
 
 
 
 
 
5aa6b15
6aa6439
e7834dd
7e20c5d
 
 
58a1d31
7e20c5d
 
58a1d31
 
7e20c5d
b8795e6
7e20c5d
58a1d31
7e20c5d
58a1d31
 
 
 
 
 
 
f1c2303
 
6756da9
1b0b128
58a1d31
7e20c5d
58a1d31
 
7e20c5d
 
58a1d31
7e20c5d
 
 
 
 
 
 
 
 
 
 
58a1d31
5aa6b15
 
 
7e20c5d
 
5aa6b15
 
 
7e20c5d
 
 
 
 
 
 
 
58a1d31
 
0449664
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import gradio as gr
import torch
import spaces
import sys
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
from threading import Thread
import transformers.modeling_rope_utils as rope_utils
from huggingface_hub import hf_hub_download

# 1. Monkey-patch dynamic_rope_update if missing
if not hasattr(rope_utils, 'dynamic_rope_update'):
    def dynamic_rope_update(rope_forward):
        return rope_forward
    rope_utils.dynamic_rope_update = dynamic_rope_update

model_id = "deepgrove/maple-preview"

print("πŸ”„ Loading tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)

# Explicitly load chat template
try:
    template_path = hf_hub_download(repo_id=model_id, filename="chat_template.jinja")
    with open(template_path, "r", encoding="utf-8") as f:
        tokenizer.chat_template = f.read()
    print("βœ… Chat template loaded successfully.")
except Exception as e:
    print(f"⚠️ Warning: Could not load chat template: {e}")

print("πŸ”„ Loading Maple-Preview...")
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto",
    torch_dtype=torch.bfloat16,
    trust_remote_code=True,
)

# 2. Aggressively replace the buggy fa3 wrapper in EVERY loaded module namespace
def custom_flash_attention_forward(
    query_states, key_states, value_states, attention_mask=None, query_length=None,
    is_causal=True, dropout=0.0, position_ids=None, softmax_scale=None, **kwargs
):
    from flash_attn import flash_attn_func, flash_attn_varlen_func
    
    if query_states.dim() == 3:
        cu_seq_lens_q = torch.tensor([0, query_states.shape[0]], dtype=torch.int32, device=query_states.device)
        cu_seq_lens_k = torch.tensor([0, key_states.shape[0]], dtype=torch.int32, device=key_states.device)
        return flash_attn_varlen_func(
            query_states, key_states, value_states,
            cu_seqlens_q=cu_seq_lens_q, cu_seqlens_k=cu_seq_lens_k,
            max_seqlen_q=query_states.shape[0], max_seqlen_k=key_states.shape[0],
            dropout_p=dropout, softmax_scale=softmax_scale, causal=is_causal
        )
    
    return flash_attn_func(
        query_states, key_states, value_states,
        dropout_p=dropout, softmax_scale=softmax_scale, causal=is_causal
    )

patched_count = 0
for name, module in list(sys.modules.items()):
    if 'maple' in name and hasattr(module, '_flash_attention_forward'):
        setattr(module, '_flash_attention_forward', custom_flash_attention_forward)
        patched_count += 1
        
print(f"βœ… Replaced _flash_attention_forward in {patched_count} modules.")

@spaces.GPU
def predict(message, history):
    messages = history + [{"role": "user", "content": message}]
    
    prompt = tokenizer.apply_chat_template(
        messages, 
        tokenize=False, 
        add_generation_prompt=True
    )
    
    inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
    
    streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
    
    generation_kwargs = dict(
        **inputs,
        streamer=streamer,
        max_new_tokens=2048,
        do_sample=True,
        temperature=0.7,
        top_p=0.9,
        repetition_penalty=1.15,
        no_repeat_ngram_size=3,
        pad_token_id=tokenizer.pad_token_id,
        eos_token_id=tokenizer.eos_token_id,
    )
    
    thread = Thread(target=model.generate, kwargs=generation_kwargs)
    thread.start()
    
    generated_text = ""
    for new_text in streamer:
        generated_text += new_text
        
        # Format thinking tags into a collapsible HTML dropdown element
        formatted_text = generated_text
        if "<think>" in formatted_text:
            if "</think>" in formatted_text:
                formatted_text = formatted_text.replace("<think>", "<details><summary>🧠 Thought Process</summary>\n\n").replace("</think>", "\n\n</details>\n\n---")
            else:
                formatted_text = formatted_text.replace("<think>", "<details><summary>🧠 Thought Process (Thinking...)</summary>\n\n") + "\n\n</details>"
                
        yield formatted_text

# 3. Custom Chatbot component with Copy & Copy All features enabled
chatbot_ui = gr.Chatbot(
    type="messages",
    show_copy_button=True,        # Adds a copy button to individual messages
    show_copy_all_button=True,    # Adds a button to copy the entire conversation history
    allow_file_downloads=True,
)

demo = gr.ChatInterface(
    fn=predict,
    type="messages",
    chatbot=chatbot_ui,
    title="🍁 Maple-Preview",
    description="A 20B-A1B ternary-weight reasoning LLM by DeepGrove. Powered by ZeroGPU.",
    theme="soft",
)

if __name__ == "__main__":
    demo.queue().launch()