LexoSynth / frontend.py
skygg's picture
Added copy button in output
d55def7
Raw
History Blame Contribute Delete
8.62 kB
# ============================================================
# LEXOSYNTH - FRONTEND : GRADIO UI
# File : frontend.py
#
# Provides a minimal Gradio interface that calls the Flask
# backend at localhost:5000/analyze.
#
# Layout :
# - Heading at top center
# - Text input box (rounded)
# - Dropdown "Choose Engine" on left
# - "Analyze" button on right
# - Output textbox with copy button below
# ============================================================
import gradio as gr
import requests
# Flask backend URL
FLASK_URL = "http://localhost:5000"
# ============================================================
# SECTION 1 : ENGINE OPTIONS
# ============================================================
ENGINES = [
"β€” Select from dropdown β€”",
"Supersonic (Fast)",
"Go Deep (Llama)",
"Hybimix (Llama + Supersonic)",
"Go Deep Max (Sarvam)",
"Hybimix Max (Sarvam + Supersonic)"
]
# Maps display name to backend engine key
ENGINE_MAP = {
"Supersonic (Fast)" : "supersonic",
"Go Deep (Llama)" : "go_deep",
"Hybimix (Llama + Supersonic)" : "hybimix",
"Go Deep Max (Sarvam)" : "go_deep_max",
"Hybimix Max (Sarvam + Supersonic)": "hybimix_max"
}
# ============================================================
# SECTION 2 : ANALYZE FUNCTION (CALLS FLASK API)
# ============================================================
def analyze(text, engine_choice):
"""
Called when the user clicks Analyze.
Sends text + engine to Flask /analyze and returns
the formatted output string for display.
Parameters:
-----------
text : User input text (one or more sentences)
engine_choice : Selected engine display name from dropdown
Returns:
-----------
str : Formatted result string shown in the output textbox
"""
# Input validation
if not text or not text.strip():
return "⚠ Please enter some text before clicking Analyze."
if not engine_choice or engine_choice == "β€” Select from dropdown β€”":
return "⚠ Please select an engine from the dropdown."
engine_key = ENGINE_MAP.get(engine_choice)
if not engine_key:
return "⚠ Invalid engine selection."
# Show which engine is running
engine_label = engine_choice
# AI engines can be very slow on CPU β€” notify user
is_ai = engine_key in ("go_deep", "hybimix", "go_deep_max", "hybimix_max")
try:
response = requests.post(
f"{FLASK_URL}/analyze",
json = {"text": text.strip(), "engine": engine_key},
timeout = 600 # 10 min timeout β€” AI inference on CPU is slow
)
if response.status_code == 200:
data = response.json()
count = data.get("sentence_count", 0)
output = data.get("formatted_output", "No output received.")
# Add a summary header
header = (
f"Engine : {engine_label}\n"
f"Sentences processed : {count}\n"
+ "═" * 52 + "\n\n"
)
return header + output
else:
error = response.json().get("error", "Unknown server error.")
return f"❌ Server error : {error}"
except requests.exceptions.ConnectionError:
return (
"❌ Could not connect to the Flask backend.\n"
" Please make sure test.py is running."
)
except requests.exceptions.Timeout:
return (
"❌ Request timed out.\n"
" AI engines on CPU can take several minutes.\n"
" Try again or use Supersonic (Fast) for quick results."
)
except Exception as e:
return f"❌ Unexpected error : {str(e)}"
# ============================================================
# SECTION 3 : CUSTOM CSS
# ============================================================
CUSTOM_CSS = """
/* Center the main heading */
.main-title {
text-align : center;
padding : 24px 0 8px 0;
}
/* Rounded text input */
.rounded-input textarea,
.rounded-input input {
border-radius : 12px !important;
}
/* Rounded output box */
.rounded-output textarea {
border-radius : 12px !important;
font-family : 'Courier New', monospace;
font-size : 0.88rem;
}
/* Analyze button */
.analyze-btn button {
min-height : 46px !important;
border-radius : 10px !important;
font-size : 1rem !important;
font-weight : 600 !important;
}
/* Dropdown rounded */
.engine-dropdown .wrap {
border-radius : 10px !important;
}
/* Subtle section spacing */
.section-gap {
margin-top : 8px;
}
"""
# ============================================================
# SECTION 4 : BUILD GRADIO UI
# ============================================================
with gr.Blocks(
title = "Tortured Phrase Detector and Corrector",
theme = gr.themes.Soft(
primary_hue = "slate",
secondary_hue = "blue",
neutral_hue = "gray"
),
css = CUSTOM_CSS
) as demo:
# ── Heading ──
gr.HTML("""
<div class="main-title">
<h1 style="
font-size : 2rem;
font-weight : 700;
color : #1e293b;
margin : 0;
letter-spacing : -0.5px;
">
Tortured Phrase Detector and Corrector
</h1>
<p style="
color : #64748b;
font-size : 0.95rem;
margin-top : 6px;
">
Detect and correct unnatural AIML paraphrases in scientific text
</p>
</div>
""")
# ── Input text box ──
with gr.Column(elem_classes=["section-gap"]):
input_text = gr.Textbox(
placeholder = "Paste your scientific text here. Each sentence will be analyzed individually...",
label = "",
lines = 6,
max_lines = 20,
elem_classes = ["rounded-input"],
show_label = False
)
# ── Dropdown (left) + Analyze button (right) ──
with gr.Row(equal_height=True):
engine_dropdown = gr.Dropdown(
choices = ENGINES,
value = "β€” Select from dropdown β€”",
label = "Choose Engine",
interactive = True,
scale = 3,
min_width = 240,
elem_classes = ["engine-dropdown"]
)
analyze_btn = gr.Button(
value = "Analyze β†’",
variant = "primary",
scale = 1,
elem_classes = ["analyze-btn"]
)
# ── Output textbox with built-in copy button ──
output_text = gr.Textbox(
label = "Output",
lines = 14,
max_lines = 30,
interactive = False,
show_copy_button = True, # Built-in copy button
show_label = True,
placeholder = "Results will appear here after analysis...",
elem_classes = ["rounded-output", "section-gap"]
)
# ── Engine description (collapses by default) ──
with gr.Accordion("Engine descriptions", open=False):
gr.Markdown("""
| Engine | Speed | Description |
|--------|-------|-------------|
| **Supersonic (Fast)** | ⚑ Instant | CSV phrase lookup β€” no model loading needed |
| **Go Deep (Llama)** | 🐒 Slow | LLaMA 1B fine-tuned adapter |
| **Hybimix (Llama + Supersonic)** | 🐒 Slow | Both engines merged with confidence scoring |
| **Go Deep Max (Sarvam)** | 🐒 Slow | Sarvam 2B fine-tuned adapter |
| **Hybimix Max (Sarvam + Supersonic)** | 🐒 Slow | Both engines merged with confidence scoring |
> ⚠ **Note :** AI engines (Go Deep / Hybimix) run on CPU and may take **several minutes** per request.
> Use **Supersonic (Fast)** for instant results.
""")
# ── Wire Analyze button to function ──
analyze_btn.click(
fn = analyze,
inputs = [input_text, engine_dropdown],
outputs = output_text,
show_progress = "minimal"
)
# ── Also trigger on Enter key in text box ──
input_text.submit(
fn = analyze,
inputs = [input_text, engine_dropdown],
outputs = output_text,
show_progress = "minimal"
)