import gradio as gr import spaces from transformers import pipeline # Available models shown in the dropdown. MODEL_OPTIONS = { "XLM-RoBERTa X-Stance": "MatteoFasulo/xlm-roberta-xstance", "mDeBERTa-v3 X-Stance": "MatteoFasulo/mdeberta-v3-xstance", } # Cache one classifier for each model so it is not reloaded on every request. classifiers = {} def get_classifier(model_name): if model_name not in classifiers: classifiers[model_name] = pipeline( task="text-classification", model=model_name, device=0, ) return classifiers[model_name] @spaces.GPU def predict_stance(selected_model, question, comment): if not question.strip() or not comment.strip(): return "⚠️ Please provide both a question and a comment.", None try: model_name = MODEL_OPTIONS[selected_model] model = get_classifier(model_name) result = model( { "text": question, "text_pair": comment, } ) if isinstance(result, list) and len(result) > 0: prediction = result[0] label = prediction["label"] score = prediction["score"] elif isinstance(result, dict): label = result.get("label", "Unknown") score = result.get("score", 0.0) else: return "⚠️ Unexpected model output format.", None normalized_label = label.upper() if "FAVOR" in normalized_label: emoji = "✅" color = "green" explanation = "The comment **supports** the political question." elif "AGAINST" in normalized_label: emoji = "❌" color = "red" explanation = "The comment **opposes** the political question." else: emoji = "❓" color = "orange" explanation = "The model returned an unrecognized stance label." output = f""" ### {emoji} Prediction: **{label}**
{explanation}
**Confidence:** {score:.2%} **Model:** `{model_name}` --- *💡 Tip: Try questions in German or French!* """ if "FAVOR" in normalized_label: confidence_dist = { "FAVOR": score, "AGAINST": 1 - score, } elif "AGAINST" in normalized_label: confidence_dist = { "AGAINST": score, "FAVOR": 1 - score, } else: confidence_dist = {label: score} return output, confidence_dist except Exception as e: error_msg = f"❌ Error during prediction: {str(e)}" return error_msg, None with gr.Blocks( title="Multilingual Stance Detection", theme=gr.themes.Soft(), ) as demo: gr.Markdown(""" # 🌍 Multilingual Political Stance Detection Select a model and predict whether a comment **supports (FAVOR)** or **opposes (AGAINST)** a political question. The models support multilingual stance detection, including 🇩🇪 German and 🇫🇷 French. """) with gr.Row(): with gr.Column(): model_dropdown = gr.Dropdown( choices=list(MODEL_OPTIONS.keys()), value="XLM-RoBERTa X-Stance", label="🤖 Model", info="Choose the model used for stance classification.", interactive=True, ) question_input = gr.Textbox( label="🗳️ Political Question", lines=3, placeholder=( "e.g. Sollte die Schweiz die Kernenergie verbieten?" ), ) comment_input = gr.Textbox( label="💬 Comment", lines=5, placeholder=( "e.g. Erneuerbare Energien sollten Kernenergie " "ersetzen, weil sie sicherer und nachhaltiger sind." ), ) submit_btn = gr.Button( "🔍 Analyze Stance", variant="primary", ) with gr.Column(): output_text = gr.Markdown( label="Analysis Results", ) confidence_plot = gr.Label( label="Confidence Distribution", num_top_classes=2, ) gr.Examples( examples=[ [ "Sollte die Schweiz erneuerbare Energien stärker fördern?", ( "Investitionen in erneuerbare Energien reduzieren " "Emissionen und verbessern die Energieunabhängigkeit." ), ], [ "Sollte die Schweiz der Europäischen Union beitreten?", ( "Die Schweiz muss ihre Unabhängigkeit und Neutralität " "um jeden Preis bewahren." ), ], [ "Sollte die Schweiz die Kernenergie schrittweise abschaffen?", ( "Kernenergie ist gefährlich und sollte durch sicherere " "Alternativen ersetzt werden." ), ], [ "Sollte die Schweiz die Einwanderung begrenzen?", ( "Eine Begrenzung der Einwanderung schadet der Wirtschaft " "und dem kulturellen Austausch." ), ], [ ( "Sollte die Schweiz ein bedingungsloses " "Grundeinkommen einführen?" ), ( "Ein bedingungsloses Grundeinkommen würde die soziale " "Sicherheit stärken und Armut reduzieren." ), ], [ ( "La Suisse devrait-elle promouvoir davantage " "les énergies renouvelables?" ), ( "Les investissements dans les énergies renouvelables " "réduisent les émissions et améliorent " "l'indépendance énergétique." ), ], [ "La Suisse devrait-elle adhérer à l'Union européenne?", ( "La Suisse doit préserver son indépendance et sa " "neutralité à tout prix." ), ], [ ( "La Suisse devrait-elle éliminer progressivement " "l'énergie nucléaire?" ), ( "L'énergie nucléaire est dangereuse et devrait être " "remplacée par des alternatives plus sûres." ), ], [ "La Suisse devrait-elle limiter l'immigration?", ( "La limitation de l'immigration nuit à l'économie " "et aux échanges culturels." ), ], [ ( "La Suisse devrait-elle introduire un revenu " "de base inconditionnel?" ), ( "Un revenu de base inconditionnel renforcerait la " "sécurité sociale et réduirait la pauvreté." ), ], ], inputs=[question_input, comment_input], label="📝 Try these examples", ) prediction_inputs = [ model_dropdown, question_input, comment_input, ] prediction_outputs = [ output_text, confidence_plot, ] submit_btn.click( fn=predict_stance, inputs=prediction_inputs, outputs=prediction_outputs, ) comment_input.submit( fn=predict_stance, inputs=prediction_inputs, outputs=prediction_outputs, ) if __name__ == "__main__": demo.launch()