| """ |
| DIPPER Paraphrase API — HuggingFace Spaces deployment (GPU-enabled). |
| Uses google/t5-efficient-large-nl32 tokenizer with SamSJackson/paraphrase-dipper-no-ctx model. |
| """ |
| import gradio as gr |
| import torch |
| from transformers import AutoTokenizer, AutoModelForSeq2SeqLM |
| import time |
|
|
| device = "cuda" if torch.cuda.is_available() else "cpu" |
| print(f"[DIPPER] Device: {device}") |
|
|
| print("[DIPPER] Loading model...") |
| t0 = time.time() |
|
|
| |
| tokenizer = AutoTokenizer.from_pretrained("google/t5-efficient-large-nl32") |
| model = AutoModelForSeq2SeqLM.from_pretrained("SamSJackson/paraphrase-dipper-no-ctx") |
| model = model.to(device) |
| model.eval() |
| print(f"[DIPPER] Model loaded in {time.time()-t0:.1f}s on {device}") |
| print(f"[DIPPER] Tokenizer vocab: {tokenizer.vocab_size}, Model params: {sum(p.numel() for p in model.parameters())/1e6:.1f}M") |
|
|
| |
| test_input = "lexical = 40, order = 40 This is a test sentence about machine learning and artificial intelligence." |
| test_ids = tokenizer(test_input, return_tensors="pt", max_length=512, truncation=True) |
| test_ids = {k: v.to(device) for k, v in test_ids.items()} |
| with torch.no_grad(): |
| test_out = model.generate(**test_ids, max_new_tokens=128, top_p=0.75, do_sample=True) |
| test_result = tokenizer.decode(test_out[0], skip_special_tokens=True) |
| print(f"[DIPPER] Self-test result: '{test_result}'") |
|
|
| def paraphrase(text: str, lex: int = 40, order: int = 40) -> str: |
| """Paraphrase a single paragraph using DIPPER.""" |
| if not text or not text.strip(): |
| return "" |
| |
| text = text.strip() |
| prefix = f"lexical = {lex}, order = {order} " |
| input_text = prefix + text |
| |
| inputs = tokenizer(input_text, return_tensors="pt", max_length=1000, truncation=True) |
| inputs = {k: v.to(device) for k, v in inputs.items()} |
| |
| t0 = time.time() |
| with torch.no_grad(): |
| outputs = model.generate( |
| **inputs, |
| max_new_tokens=500, |
| top_p=0.75, |
| do_sample=True |
| ) |
| elapsed = time.time() - t0 |
| |
| result = tokenizer.decode(outputs[0], skip_special_tokens=True) |
| print(f"[DIPPER] {len(text)} -> {len(result)} chars in {elapsed:.1f}s") |
| return result |
|
|
| def batch_paraphrase(text: str, lex: int = 40, order: int = 40) -> str: |
| """Paraphrase multi-paragraph text by processing each paragraph separately.""" |
| if not text or not text.strip(): |
| return "" |
| |
| paragraphs = [p.strip() for p in text.split('\n\n') if p.strip()] |
| results = [] |
| |
| for i, para in enumerate(paragraphs): |
| print(f"[DIPPER] Paragraph {i+1}/{len(paragraphs)}") |
| result = paraphrase(para, lex=lex, order=order) |
| results.append(result) |
| |
| return '\n\n'.join(results) |
|
|
| |
| with gr.Blocks(title="DIPPER Paraphrase API") as demo: |
| gr.Markdown("# DIPPER Paraphrase API\nRewrite text to bypass AI detection. Use the API endpoint for programmatic access.") |
| gr.Markdown(f"**Device:** {device} | **Tokenizer:** google/t5-efficient-large-nl32 | **Model:** SamSJackson/paraphrase-dipper-no-ctx (972M)") |
| |
| with gr.Row(): |
| with gr.Column(): |
| input_text = gr.Textbox(label="Input Text", lines=10, placeholder="Paste text here...") |
| lex_slider = gr.Slider(0, 100, value=40, step=10, label="Lexical Control (40=optimal)") |
| ord_slider = gr.Slider(0, 100, value=40, step=10, label="Order Control (40=optimal)") |
| btn = gr.Button("Paraphrase", variant="primary") |
| with gr.Column(): |
| output_text = gr.Textbox(label="Paraphrased Text", lines=10) |
| |
| btn.click(fn=batch_paraphrase, inputs=[input_text, lex_slider, ord_slider], outputs=output_text) |
|
|
| demo.launch() |
|
|