"""ScamShield NLP — Hugging Face Space entry point. A pure-inference Gradio app exposing the trained calibrated Linear SVM. Two ways to use it: 1. Web UI — type/paste a message and click "Analyze". 2. HTTP API — the same function is exposed through the Gradio API. """ import gradio as gr import spaces from predictor import ScamPredictor # --------------------------------------------------------- # Model # --------------------------------------------------------- predictor = ScamPredictor() # --------------------------------------------------------- # Configuration # --------------------------------------------------------- MAX_MESSAGE_LENGTH = 20000 TITLE = "ScamShield NLP" DESCRIPTION = ( "Classifies a text message as **SCAM** or **LEGITIMATE** using a " "**calibrated Linear SVM** trained on the ScamShield corpus " "(TF-IDF features, n-grams 1–2). Returns a calibrated scam probability " "(confidence) and a risk level." ) # --------------------------------------------------------- # Example messages # --------------------------------------------------------- EXAMPLES = [ ["Congratulations! You have won a prize. Click this link now."], [ "Dear customer, your account will be locked. " "Verify now: http://bit.ly/fake" ], [ "URGENT: Your parcel could not be delivered. " "Pay $2 to reschedule: https://short.link/x" ], ["Hi, the meeting is moved to 4pm tomorrow. See you then."], [ "Your OTP for verification is 482913. " "Do not share it with anyone." ], [ "Reminder: your subscription renews on the 28th. " "Manage settings here." ], ] # --------------------------------------------------------- # Analyze function # --------------------------------------------------------- @spaces.GPU def analyze(message: str) -> dict: """Validate input, then run inference with detailed error logging.""" import traceback try: # --------------------------------------------- # Validate input # --------------------------------------------- if message is None or not str(message).strip(): raise gr.Error("Message cannot be empty.") message = str(message) if len(message) > MAX_MESSAGE_LENGTH: raise gr.Error( f"Message too long (max {MAX_MESSAGE_LENGTH} characters)." ) # --------------------------------------------- # Run model prediction # --------------------------------------------- print("=" * 60) print("ANALYZE REQUEST") print(f"Message: {message}") print("=" * 60) result = predictor.predict(message) # --------------------------------------------- # Success logging # --------------------------------------------- print("=" * 60) print(f"SUCCESS: {result}") print("=" * 60) return result except gr.Error: # Keep Gradio validation errors readable. raise except Exception as e: # --------------------------------------------- # Detailed diagnostic logging # --------------------------------------------- error_msg = ( f"{type(e).__name__}: {e}\n" f"{traceback.format_exc()}" ) print("=" * 60) print("ERROR DURING ANALYSIS") print(error_msg) print("=" * 60) # Show a shorter message to the UI while keeping # the complete traceback in Hugging Face logs. raise gr.Error( f"Analysis failed: {type(e).__name__}: {e}" ) # --------------------------------------------------------- # Gradio UI # --------------------------------------------------------- with gr.Blocks( title=TITLE, theme=gr.themes.Soft() ) as demo: # --------------------------------------------- # Header # --------------------------------------------- gr.Markdown(f"# {TITLE}") gr.Markdown(DESCRIPTION) # --------------------------------------------- # Main layout # --------------------------------------------- with gr.Row(): # ----------------------------------------- # Input # ----------------------------------------- with gr.Column(scale=3): message_input = gr.Textbox( label="Message", lines=5, placeholder=( "Paste the SMS, email or chat message " "to classify…" ), ) analyze_button = gr.Button( "Analyze", variant="primary" ) # ----------------------------------------- # Output # ----------------------------------------- with gr.Column(scale=2): result_output = gr.JSON( label="Result" ) # --------------------------------------------- # Analyze button # --------------------------------------------- analyze_button.click( analyze, inputs=message_input, outputs=result_output, api_name="predict", ) # --------------------------------------------- # Enter / Submit # --------------------------------------------- message_input.submit( analyze, inputs=message_input, outputs=result_output, ) # --------------------------------------------- # Examples + Model information # --------------------------------------------- gr.Markdown( """ ### Example messages Click an example to load it, then press **Analyze**. ### Model `CalibratedClassifierCV(LinearSVC)` over `TfidfVectorizer` (10,000 features, n-gram 1–2) **Held-out test set:** - Accuracy: **96.91%** - Precision: **96.64%** - Recall: **94.99%** - F1: **95.81%** """ ) # --------------------------------------------- # Example messages # --------------------------------------------- gr.Examples( examples=EXAMPLES, inputs=message_input, outputs=result_output, ) # --------------------------------------------------------- # Launch # --------------------------------------------------------- if __name__ == "__main__": demo.launch()