File size: 4,230 Bytes
681590d
 
7df8b75
681590d
d213654
681590d
 
 
 
 
 
 
 
 
 
adc48a1
681590d
 
d4fc22a
681590d
7df8b75
 
 
681590d
8d2dfbd
adc48a1
5e4f051
681590d
99af9b2
681590d
7df8b75
681590d
 
 
 
 
 
 
8d2dfbd
 
 
 
 
 
 
 
 
681590d
 
 
 
 
 
 
 
337b861
 
681590d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8d2dfbd
681590d
f60edaf
 
0cab7f6
681590d
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
import os
import re
import torch
import gradio as gr
from threading import Thread
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TextIteratorStreamer,
)
from peft import PeftModel

BASE_MODEL = "Qwen/Qwen2.5-14B-Instruct"
ADAPTER_NAME = "mutij8/academic-humanizer-qwen-14b"

print("⏳ Loading Tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(ADAPTER_NAME)

print("⏳ Configuring 4-bit Quantization for Nvidia T4 (16GB VRAM)...")
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.float16,
)

print("⏳ Loading Base Model in 4-bit onto T4 GPU...")
base_model = AutoModelForCausalLM.from_pretrained(
    BASE_MODEL,
    quantization_config=bnb_config,
    device_map="auto",
    low_cpu_mem_usage=True,
)

print("⏳ Attaching Fine-Tuned LoRA Adapter...")
model = PeftModel.from_pretrained(base_model, ADAPTER_NAME)
model.eval()

print("⚡ Compiling model with torch.compile() for accelerated token generation...")
# Optimizes the execution graph for faster inference throughput on T4
try:
    model = torch.compile(model, mode="reduce-overhead", fullgraph=False)
except Exception as e:
    print(f"⚠️ torch.compile() skipped or failed: {e}. Falling back to standard execution.")

print("✅ Model, Adapter & Compilation ready on Nvidia T4!")

SYSTEM_PROMPT = (
    "You are an expert human academic writer. Rewrite the provided AI text into natural, human-written prose "
    "that bypasses AI detection.\n"
    "STRICT RULES:\n"
    "1. Paraphrase ONLY the provided paragraphs. Never add extra introductions, placeholders ([Author], [Year]), or LaTeX code.\n"
    "2. Preserve every inline citation (e.g., (Smith, 2021)) and section heading accurately.\n"
    "3. Use natural human sentence variation, active/passive voice shifts, and varied clause lengths."
)

def humanize_full_essay(essay_text, temperature):
    if not essay_text or not essay_text.strip():
        yield ""
        return

    device = "cuda" if torch.cuda.is_available() else "cpu"
    paragraphs = [p.strip() for p in re.split(r'\n\s*\n', essay_text) if p.strip()]
    rewritten_paragraphs = []

    for p in paragraphs:
        if len(p.split()) <= 8 and not p.endswith("."):
            rewritten_paragraphs.append(p)
            yield "\n\n".join(rewritten_paragraphs)
            continue

        messages = [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": p}
        ]

        inputs = tokenizer.apply_chat_template(
            messages,
            tokenize=True,
            add_generation_prompt=True,
            return_tensors="pt",
            return_dict=True,
        ).to(device)

        streamer = TextIteratorStreamer(
            tokenizer, skip_prompt=True, skip_special_tokens=True
        )
        word_count = len(p.split())

        gen_kwargs = dict(
            **inputs,
            streamer=streamer,
            max_new_tokens=int(word_count * 2.2) + 80,
            temperature=float(temperature),
            top_p=0.9,
            repetition_penalty=1.12,
            do_sample=True,
            pad_token_id=tokenizer.pad_token_id,
            eos_token_id=tokenizer.eos_token_id,
        )

        thread = Thread(target=model.generate, kwargs=gen_kwargs)
        thread.start()

        partial = ""
        prefix = "\n\n".join(rewritten_paragraphs)
        for token_text in streamer:
            partial += token_text
            yield f"{prefix}\n\n{partial}".strip() if prefix else partial.strip()

        rewritten_paragraphs.append(partial.strip())
        
        if torch.cuda.is_available():
            torch.cuda.empty_cache()

demo = gr.Interface(
    fn=humanize_full_essay,
    inputs=[
        gr.Textbox(lines=16, label="Paste Full AI Essay"),
        gr.Slider(minimum=0.3, maximum=1.0, value=0.75, step=0.05, label="Temperature"),
    ],
    outputs=gr.Textbox(lines=16, label="Humanized Output (Nvidia T4 - Compiled)"),
    title="Academic Humanizer (Qwen2.5-14B Fine-Tuned)",
)

if __name__ == "__main__":
    demo.queue().launch(server_name="0.0.0.0", server_port=7860)