from html import escape import streamlit as st ARTICLE_CARD_STYLES = """ """ def inject_article_card_styles() -> None: st.markdown(ARTICLE_CARD_STYLES, unsafe_allow_html=True) def _safe_text(value: object, fallback: str = "") -> str: if value is None: return fallback text = str(value).strip() return text or fallback def _label_style(label: str) -> tuple[str, str]: if label.lower() == "biased": return "#c24138", "#fff4f2" return "#247857", "#effaf5" def smart_truncate(text, limit=80): if len(text) <= limit: return text return text[:limit].rsplit(" ", 1)[0] + "..." def render_article_card(article: dict, debug: bool = False) -> None: label = _safe_text(article.get("text_label"), "Unknown") confidence = float(article.get("confidence", 0) or 0) source = _safe_text(article.get("source"), "Unknown source") source_bias = _safe_text(article.get("source_bias"), "Unknown bias") source_bias_provenance = _safe_text(article.get("source_bias_provenance")) source_meta = f"{source} / {source_bias}" if source_bias_provenance and source_bias_provenance != "manual_demo": source_meta = f"{source_meta} / {source_bias_provenance}" url = _safe_text(article.get("url"), "#") description = _safe_text(article.get("description")) fallback_text = _safe_text(article.get("text"))[:280] excerpt = description or fallback_text or "No article excerpt was returned by the API." title = _safe_text(article.get("title")) or smart_truncate(excerpt, 80) accent, soft = _label_style(label) confidence_pct = max(0, min(confidence, 1)) * 100 st.markdown( f"""
{escape(excerpt)}