AI_Humanizer / app.py
AJAY KASU
Phase 12: Structural Breakout (Staccato Rhythm, Symmetry Breaker, App Fix)
5ba84c5
#!/usr/bin/env python3
"""
app.py -- Gradio web UI for HF Spaces
--------------------------------------
Provides a browser-based interface to the 3-agent humanizer
pipeline. Designed for deployment on huggingface.co/spaces.
"""
import os
import sys
import logging
import json
import gradio as gr
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from main import process_text # updated function name
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("app")
# -- the gradio callback --------------------------------------------------
def humanize_text(input_text):
"""Called when user clicks 'Humanize'. Returns 4 outputs."""
intensity = 1.0 # Force maximum intensity for Pattern Erasure
if not input_text or not input_text.strip():
return (
"Please paste some text first!",
"N/A",
0.0,
)
try:
# process_text returns (plan_str, draft, humanized_text, ver_str)
plan_str, draft, final, ver_str = process_text(
input_text.strip(),
intensity=intensity
)
# Parse plan_str back to dict for gr.JSON
try:
plan_json = json.loads(plan_str)
except:
plan_json = {"error": "Failed to parse plan", "raw": plan_str}
# Verification string parsing (simple)
# e.g. "Label: Real\nConfidence: 2.1%"
try:
label = ver_str.split("\n")[0].split(":")[1].strip()
conf = float(ver_str.split("\n")[1].split(":")[1].strip().replace("%", ""))
except:
label = "Unknown"
conf = 0.0
return (
final,
label,
conf,
)
except Exception as exc:
logger.exception("pipeline error")
return (
f"Error: {exc}",
"Error",
0.0,
)
# -- build the UI ----------------------------------------------------------
CUSTOM_CSS = """
.gradio-container {
max-width: 1000px !important;
margin: auto !important;
}
.header-text {
text-align: center;
margin-bottom: 0.5rem;
}
"""
with gr.Blocks(css=CUSTOM_CSS, title="AI Text Humanizer") as demo:
gr.Markdown(
"""
# AI Text Humanizer (Re-Authoring Mode)
### Defeat Detection via fresh content generation
This pipeline doesn't just paraphrase; it **re-authors**.
1. **Planner** extracts core ideas into a wording-free JSON outline.
2. **Writer** builds a fresh draft based *only* on the outline (is blind to original wording).
3. **Humanizer** applies stylometric refinement and iterative evasion checks.
""",
elem_classes="header-text",
)
with gr.Row():
with gr.Column(scale=1):
input_box = gr.Textbox(
label="Paste AI-Generated Text",
placeholder="Paste the robotic AI text here...",
lines=10,
)
run_btn = gr.Button("Humanize", variant="primary", size="lg")
with gr.Column(scale=1):
output_box = gr.Textbox(
label="Humanized Output",
lines=10,
interactive=False,
)
with gr.Row():
label_out = gr.Textbox(label="Detection Result", interactive=False)
conf_out = gr.Number(label="AI Confidence (%)", interactive=False)
# wire it up
run_btn.click(
fn=humanize_text,
inputs=[input_box],
outputs=[output_box, label_out, conf_out],
)
gr.Markdown(
"""
---
**Why Re-Authoring?**
Standard 'humanizers' often trigger 'Paraphrased AI' flags because they keep the original n-gram structure.
By stripping everything down to a JSON idea-map first, we break the detectable surface patterns entirely.
"""
)
# -- launch ----------------------------------------------------------------
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)