from __future__ import annotations from pathlib import Path import pandas as pd import streamlit as st import torch from transformers import RobertaForSequenceClassification, RobertaTokenizerFast REMOTE_CHECKPOINT = "Pengchong1113/argument-role-classifier" LOCAL_CHECKPOINT = "models/best" LABELS = ["claim", "counter_claim", "premise", "unknown"] LABEL_DISPLAY = { "claim": "Claim", "counter_claim": "Counter-claim", "premise": "Premise", "unknown": "Unknown", } LABEL_HELP = { "claim": "A debatable position or main assertion.", "counter_claim": "A reply that challenges the parent comment.", "premise": "A reason, example, or evidence used to support an argument.", "unknown": "A question, acknowledgement, vague reply, or off-topic comment.", } EXAMPLES = { "AI in education": { "parent": "Universities should allow students to use generative AI tools in coursework.", "current": "AI tools should be banned from graded assignments because they make authorship impossible to verify.", }, "Remote work": { "parent": "Remote work should remain the default for knowledge workers.", "current": "That ignores how much junior employees learn from being around experienced coworkers in person.", }, "Public transport": { "parent": "Cities should make public transport free for residents.", "current": "Fare collection systems are expensive to maintain, so removing fares can reduce administrative costs.", }, "No parent": { "parent": "", "current": "Online anonymity is necessary for free expression.", }, } st.set_page_config( page_title="Argument Role Classifier", page_icon="", layout="wide", ) st.markdown( """ """, unsafe_allow_html=True, ) @st.cache_resource(show_spinner="Loading model...") def load_model(checkpoint: str): path = Path(checkpoint) model_source = str(path) if path.exists() else checkpoint if path.exists() and not (path / "model.safetensors").exists() and not ( path / "pytorch_model.bin" ).exists(): raise FileNotFoundError( f"No model weights found in {path}. Expected model.safetensors " "or pytorch_model.bin." ) device = "cuda" if torch.cuda.is_available() else "cpu" tokenizer = RobertaTokenizerFast.from_pretrained(model_source) model = RobertaForSequenceClassification.from_pretrained(model_source) model.to(device) model.eval() return tokenizer, model, device def predict_with_scores( parent_text: str, current_text: str, checkpoint: str, ) -> tuple[str, float, dict[str, float]]: tokenizer, model, device = load_model(checkpoint) if parent_text.strip(): encoded = tokenizer( parent_text, current_text, return_tensors="pt", truncation=True, max_length=256, padding="max_length", ) else: encoded = tokenizer( current_text, return_tensors="pt", truncation=True, max_length=256, padding="max_length", ) encoded = {key: value.to(device) for key, value in encoded.items()} with torch.no_grad(): logits = model(**encoded).logits.squeeze(0) probabilities = torch.softmax(logits, dim=-1).detach().cpu().tolist() scores = dict(zip(LABELS, probabilities)) label = max(scores, key=scores.get) return label, scores[label], scores def render_label_reference() -> None: cols = st.columns(4) for col, label in zip(cols, LABELS): with col: st.markdown( f"""