HumanizerV2 / app.py
taha092's picture
Update app.py
31d085e verified
import gradio as gr
import torch
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
from transformers.pipelines import pipeline
from sentence_transformers import SentenceTransformer, util
import numpy as np
import gradio.themes as grthemes
import random
import re
# ----------------------
# Paraphrasing Model Setup (Pegasus + T5)
# ----------------------
PEGASUS_MODEL_NAME = "tuner007/pegasus_paraphrase"
T5_MODEL_NAME = "Vamsi/T5_Paraphrase_Paws"
pegasus_tokenizer = AutoTokenizer.from_pretrained(PEGASUS_MODEL_NAME)
pegasus_model = AutoModelForSeq2SeqLM.from_pretrained(PEGASUS_MODEL_NAME)
t5_tokenizer = AutoTokenizer.from_pretrained(T5_MODEL_NAME)
t5_model = AutoModelForSeq2SeqLM.from_pretrained(T5_MODEL_NAME)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
pegasus_model = pegasus_model.to(device)
t5_model = t5_model.to(device)
# ----------------------
# Semantic Similarity Model
# ----------------------
similarity_model = SentenceTransformer('all-MiniLM-L6-v2')
# ----------------------
# Local AI Detector (roberta-base-openai-detector)
# ----------------------
AI_DETECTOR_MODEL = "roberta-base-openai-detector"
ai_detector = pipeline("text-classification", model=AI_DETECTOR_MODEL, device=0 if torch.cuda.is_available() else -1)
# ----------------------
# Prompt Variations for Humanization
# ----------------------
PEGASUS_PROMPTS = [
"Paraphrase this naturally:",
"Rewrite as if explaining to a friend:",
"Make this sound like a real conversation:",
"Express this in a casual, human way:",
"Reword this with natural flow:",
"Make this sound less robotic:",
"Rewrite in a friendly, informal tone:",
"Paraphrase in a way a student would say it:",
]
T5_PROMPTS = [
"Paraphrase the following text in a formal, academic tone:",
"Paraphrase the following text in a casual, conversational tone:",
"Paraphrase the following text in a friendly, approachable tone:",
"Paraphrase the following text to bypass AI detectors and sound as human as possible:",
]
# ----------------------
# Sentence Splitter
# ----------------------
def split_sentences(text):
sentences = re.split(r'(?<=[.!?])\s+', text.strip())
return [s for s in sentences if s]
# ----------------------
# Aggressive Post-Processing
# ----------------------
def postprocess_text(text):
contractions = {
"do not": "don't", "cannot": "can't", "will not": "won't", "I am": "I'm",
"is not": "isn't", "are not": "aren't", "did not": "didn't", "it is": "it's",
"does not": "doesn't", "have not": "haven't", "has not": "hasn't"
}
for k, v in contractions.items():
text = re.sub(rf'\b{k}\b', v, text, flags=re.IGNORECASE)
idioms = [
"at the end of the day", "to be honest", "as a matter of fact", "for what it's worth",
"in a nutshell", "the bottom line is", "all things considered"
]
transitions = [
"Interestingly,", "In fact,", "To be clear,", "As a result,", "For example,", "On the other hand,", "In other words,"
]
if random.random() < 0.3:
text += " " + random.choice(idioms) + "."
if random.random() < 0.3:
text = random.choice(transitions) + " " + text
# Randomly lower-case a word to mimic human error
if random.random() < 0.2:
words = text.split()
if len(words) > 3:
idx = random.randint(1, len(words)-2)
words[idx] = words[idx].lower()
text = ' '.join(words)
return text
# ----------------------
# Multi-Model, Multi-Pass Paraphrasing
# ----------------------
def pegasus_paraphrase(sentence):
prompt = random.choice(PEGASUS_PROMPTS)
full_prompt = f"{prompt} {sentence}"
batch = pegasus_tokenizer([full_prompt], truncation=True, padding='longest', max_length=60, return_tensors="pt").to(device)
outputs = pegasus_model.generate(
**batch,
max_length=60,
num_beams=5,
num_return_sequences=1,
temperature=1.0
)
tgt_text = pegasus_tokenizer.batch_decode(outputs, skip_special_tokens=True)
return tgt_text[0] if tgt_text else sentence
def t5_paraphrase(sentence):
prompt = random.choice(T5_PROMPTS) + " " + sentence
input_ids = t5_tokenizer.encode(prompt, return_tensors="pt", max_length=256, truncation=True).to(device)
outputs = t5_model.generate(
input_ids,
do_sample=True,
top_k=120,
top_p=0.95,
temperature=0.7,
repetition_penalty=1.2,
max_length=256,
num_return_sequences=1
)
paraphrased = t5_tokenizer.decode(outputs[0], skip_special_tokens=True)
return paraphrased
# ----------------------
# Feedback Loop with AI Detector
# ----------------------
def check_ai_score(text):
try:
result = ai_detector(text)
for r in result:
if r['label'] in ['LABEL_1', 'Fake']:
return r['score'], None
elif r['label'] in ['LABEL_0', 'Real']:
return 1.0 - r['score'], None
return 0.5, None
except Exception as e:
return None, f"AI detection error: {str(e)}"
# ----------------------
# Main Humanizer Pipeline
# ----------------------
def humanize_pipeline(text, tone, max_feedback_loops=2):
sentences = split_sentences(text)
paraphrased = []
for sent in sentences:
# First pass: Pegasus
peg = pegasus_paraphrase(sent)
# Second pass: T5
t5 = t5_paraphrase(peg)
paraphrased.append(t5)
joined = ' '.join(paraphrased)
processed = postprocess_text(joined)
# Feedback loop: if still flagged as AI, re-paraphrase flagged sentences
for _ in range(max_feedback_loops):
ai_prob, _ = check_ai_score(processed)
if ai_prob is not None and ai_prob < 0.5:
break # Considered human
# Re-paraphrase all sentences again
sentences = split_sentences(processed)
paraphrased = []
for sent in sentences:
peg = pegasus_paraphrase(sent)
t5 = t5_paraphrase(peg)
paraphrased.append(t5)
joined = ' '.join(paraphrased)
processed = postprocess_text(joined)
return processed
# ----------------------
# Semantic Similarity Function
# ----------------------
def semantic_similarity(text1, text2):
emb1 = similarity_model.encode(text1, convert_to_tensor=True)
emb2 = similarity_model.encode(text2, convert_to_tensor=True)
sim = util.pytorch_cos_sim(emb1, emb2).item()
return sim
# ----------------------
# Humanization Score & Rating
# ----------------------
def humanization_score(sim, ai_prob):
score = (1.0 - sim) * 0.5 + (1.0 - ai_prob) * 0.5
return score
def humanization_rating(score):
if score < 0.7:
return f"⚠️ Still AI-like ({score:.2f})"
elif score < 0.85:
return f"👍 Acceptable ({score:.2f})"
else:
return f"✅ Highly Humanized ({score:.2f})"
# ----------------------
# Main Processing Function
# ----------------------
def process(text, tone):
if not text.strip():
return "", "", 0.0, "", 0.0, ""
pre_ai_prob, pre_err = check_ai_score(text)
if pre_ai_prob is None:
return "", f"AI Detection Error: {pre_err}", 0.0, "", 0.0, ""
try:
# Generate 3 versions for user choice
outputs = [humanize_pipeline(text, tone) for _ in range(3)]
except Exception as e:
return f"[Paraphrasing error: {str(e)}]", "", 0.0, "", 0.0, ""
# Pick the most human-like version (lowest ai_prob)
best = None
best_score = -1
best_ai_prob = 1.0
for out in outputs:
post_ai_prob, _ = check_ai_score(out)
sim = semantic_similarity(text, out)
score = humanization_score(sim, post_ai_prob if post_ai_prob is not None else 1.0)
if post_ai_prob is not None and post_ai_prob < best_ai_prob:
best = out
best_score = score
best_ai_prob = post_ai_prob
if best is None:
best = outputs[0]
best_score = 0.0
best_ai_prob = 1.0
sim = semantic_similarity(text, best)
rating = humanization_rating(best_score)
ai_score_str = f"Pre: {100*(1-pre_ai_prob):.1f}% human | Post: {100*(1-best_ai_prob):.1f}% human"
return (
best,
ai_score_str,
sim,
rating,
best_score * 100,
""
)
# ----------------------
# Gradio UI
# ----------------------
custom_theme = grthemes.Base(
primary_hue="blue",
secondary_hue="blue",
neutral_hue="slate"
)
with gr.Blocks(theme=custom_theme, title="AI Humanizer - Made by Taha") as demo:
gr.Markdown("""
# 🧠 AI Humanizer
<div style='display:flex;justify-content:space-between;align-items:center;'>
<span style='font-size:1.2em;color:#7bb1ff;'>Rewrite AI text to sound 100% human</span>
<span style='font-weight:bold;color:#7bb1ff;'>Made by Taha</span>
</div>
""", elem_id="header")
with gr.Row():
with gr.Column():
text_in = gr.Textbox(label="Paste AI-generated text here", lines=8, placeholder="Paste your text...", elem_id="input-box")
tone = gr.Dropdown(["Academic", "Casual", "Friendly", "Stealth"], value="Stealth", label="Tone Selector")
btn = gr.Button("Humanize", elem_id="humanize-btn")
with gr.Column():
text_out = gr.Textbox(label="Humanized Output", lines=8, interactive=False, elem_id="output-box")
ai_scores = gr.Markdown("", elem_id="ai-scores")
sim_score = gr.Number(label="Similarity (0=very different, 1=very similar)", interactive=False)
rating = gr.Markdown("", elem_id="rating")
human_score = gr.Number(label="Humanization Score (%)", interactive=False)
btn.click(
process,
inputs=[text_in, tone],
outputs=[text_out, ai_scores, sim_score, rating, human_score, gr.Textbox(visible=False)],
api_name="humanize"
)
gr.Markdown("""
<div style='text-align:center;color:#7bb1ff;margin-top:2em;'>
<b>Made by Taha</b> | Free for unlimited use | Optimized for students and creators
</div>
""", elem_id="footer")
demo.launch()