Download render.py from Norod78/theanswer: direct link, hf CLI and curl.
- Browser
- Download file 6.77 kB
-
https://huggingface.co/spaces/Norod78/theanswer/resolve/main/render.py
- Command line
-
hf download hf://spaces/Norod78/theanswer/render.py
-
curl -L -o render.py https://huggingface.co/spaces/Norod78/theanswer/resolve/main/render.py
6.77 kB
| """Turn untrusted API JSON (via view_model) into RTL HTML. Escape first; only our tags are added. | |
| Layout follows the 7881 debug playground: status, answer, claims table (with a verified | |
| column), episode triage table, warnings. Styling follows the 2026-09-28 Space redesign. | |
| """ | |
| from __future__ import annotations | |
| import html | |
| import re | |
| from urllib.parse import urlsplit | |
| from textproc import DisplayOpts, highlight_terms, strip_fffd, trim_at_word_boundary | |
| from view_model import EpisodeView, ViewData | |
| _BULLET = re.compile(r"^\s*[-*\u2022]\s+(.*)$") | |
| _NUMBERED = re.compile(r"^\s*\d+\.\s+(.*)$") | |
| _BOLD = re.compile(r"\*\*(.+?)\*\*|__(.+?)__") | |
| _ITALIC = re.compile( | |
| r"(?<!\*)\*(?!\s|\*)(.+?)(?<!\s|\*)\*(?!\*)" | |
| r"|(?<![\w\u0590-\u05FF])_(?!_)(.+?)(?<!_)_(?![\w\u0590-\u05FF])" | |
| ) | |
| def _e(text: object) -> str: | |
| return html.escape(str(text or ""), quote=True) | |
| def render_notice(message: str, css_class: str = "notice") -> str: | |
| return f'<div class="{css_class}" dir="rtl" role="status">{_e(message)}</div>' | |
| def _inline(escaped_line: str) -> str: | |
| def bold(match: re.Match[str]) -> str: | |
| return f"<strong>{match.group(1) if match.group(1) is not None else match.group(2)}</strong>" | |
| def italic(match: re.Match[str]) -> str: | |
| return f"<em>{match.group(1) if match.group(1) is not None else match.group(2)}</em>" | |
| return _ITALIC.sub(italic, _BOLD.sub(bold, escaped_line)) | |
| def markdown_to_safe_html(text: str) -> str: | |
| """Escape HTML, then a small Markdown subset. Never emits links or raw tags.""" | |
| lines = html.escape(strip_fffd(text).replace("\r\n", "\n").replace("\r", "\n"), quote=True).split("\n") | |
| blocks: list[str] = [] | |
| i = 0 | |
| while i < len(lines): | |
| if not lines[i].strip(): | |
| i += 1 | |
| continue | |
| for pattern, tag in ((_BULLET, "ul"), (_NUMBERED, "ol")): | |
| if pattern.match(lines[i]): | |
| items = [] | |
| while i < len(lines) and pattern.match(lines[i]): | |
| items.append(f"<li>{_inline(pattern.match(lines[i]).group(1))}</li>") # type: ignore[union-attr] | |
| i += 1 | |
| blocks.append(f"<{tag}>{''.join(items)}</{tag}>") | |
| break | |
| else: | |
| para = [] | |
| while i < len(lines) and lines[i].strip() and not (_BULLET.match(lines[i]) or _NUMBERED.match(lines[i])): | |
| para.append(_inline(lines[i])) | |
| i += 1 | |
| blocks.append("<p>" + "<br>".join(para) + "</p>") | |
| return "".join(blocks) | |
| def is_http_url(url: str) -> bool: | |
| candidate = (url or "").strip() | |
| if not candidate or any(ch.isspace() or ord(ch) < 32 for ch in candidate): | |
| return False | |
| try: | |
| parts = urlsplit(candidate) | |
| except ValueError: | |
| return False | |
| return parts.scheme in ("http", "https") and bool(parts.netloc) | |
| def episode_link(ep: EpisodeView, view: dict) -> str: | |
| title = strip_fffd(ep.title).strip() | |
| if not title or is_http_url(title): | |
| title = str(view["missing_title"]) | |
| inner = _e(title) | |
| if is_http_url(ep.url): | |
| return (f'<a class="episode-link" href="{_e(ep.url.strip())}" target="_blank" ' | |
| f'rel="noopener noreferrer">{inner}</a>') | |
| return f'<span class="episode-name">{inner}</span>' | |
| def _date(ep: EpisodeView) -> str: | |
| date = strip_fffd(ep.date).strip() | |
| return "" if is_http_url(date) else f'<span class="src-date" dir="ltr">{_e(date)}</span>' | |
| def _cell(label: str, content: str, css: str = "") -> str: | |
| cls = f' class="{css}"' if css else "" | |
| return f'<td data-label="{_e(label)}"{cls}>{content}</td>' | |
| def _table(css: str, heading: str, headers: list[str], rows: list[str]) -> str: | |
| head = "".join(f"<th>{_e(h)}</th>" for h in headers) | |
| return (f'<section class="{css}"><h2>{_e(heading)}</h2><div class="table-wrap"><table>' | |
| f'<thead><tr>{head}</tr></thead><tbody>{"".join(rows)}</tbody></table></div></section>') | |
| def render_result(data: ViewData, question: str, view: dict, opts: DisplayOpts) -> str: | |
| status_text = view["status_labels"].get(data.status, data.status) | |
| parts = ['<div class="result" dir="rtl">', | |
| f'<div class="status status-{_e(data.status)}" role="status">' | |
| f'<span class="status-label">{_e(view["label_status"])}</span> {_e(status_text)}</div>'] | |
| answer_html = markdown_to_safe_html(data.answer_markdown or "") or f"<p>{_e(view['msg_refusal'])}</p>" | |
| parts.append(f'<article class="answer-card"><h2>{_e(view["label_answer"])}</h2>' | |
| f'<div class="answer-body">{answer_html}</div></article>') | |
| if data.claims: | |
| h = view["claims_headers"] | |
| rows = [] | |
| for c in data.claims: | |
| quote = trim_at_word_boundary(strip_fffd(c.quote), opts.max_quote_chars, opts.ellipsis) | |
| quote_html = f'<q class="quote-text">{highlight_terms(quote, question, opts)}</q>' | |
| if c.verified: | |
| check = f'<span class="badge ok" title="{_e(view["verified_title"])}">✓ {_e(view["verified_badge"])}</span>' | |
| else: | |
| check = f'<span class="badge unverified" title="{_e(view["unverified_title"])}">{_e(view["unverified_badge"])}</span>' | |
| rows.append("<tr" + ("" if c.verified else ' class="row-unverified"') + ">" | |
| + _cell(h[0], _e(c.text), "claim-text") | |
| + _cell(h[1], quote_html, "claim-quote") | |
| + _cell(h[2], check, "claim-verified") | |
| + _cell(h[3], episode_link(c.episode, view), "col-episode") | |
| + _cell(h[4], _date(c.episode), "col-date") | |
| + _cell(h[5], f'<span dir="ltr">{_e(c.timestamp)}</span>', "col-time") | |
| + "</tr>") | |
| parts.append(_table("claims", view["label_claims"], h, rows)) | |
| if data.triage: | |
| h = view["triage_headers"] | |
| rows = [] | |
| for t in data.triage: | |
| label = view["triage_labels"].get(t.label, t.label) | |
| rows.append("<tr>" + _cell(h[0], episode_link(t.episode, view), "col-episode") + _cell(h[1], _date(t.episode), "col-date") | |
| + _cell(h[2], f'<span class="chip chip-{_e(t.label)}">{_e(label)}</span>', "col-label") | |
| + _cell(h[3], _e(t.reason), "triage-reason") + "</tr>") | |
| parts.append(_table("triage", view["label_triage"], h, rows)) | |
| if data.warnings: | |
| items = "".join(f'<li dir="auto">{_e(w)}</li>' for w in data.warnings) | |
| parts.append(f'<section class="warnings"><h2>{_e(view["label_warnings"])}</h2>' | |
| f'<p class="warn-note">{_e(view["warnings_note"])}</p><ul>{items}</ul></section>') | |
| parts.append("</div>") | |
| return "".join(parts) | |