Spaces:
Sleeping
Sleeping
Download dashboard/note.py from Viney/readthrough: direct link, hf CLI and curl.
- Browser
- Download file 65.9 kB
-
https://huggingface.co/spaces/Viney/readthrough/resolve/main/dashboard/note.py
- Command line
-
hf download hf://spaces/Viney/readthrough/dashboard/note.py
-
curl -L -o note.py https://huggingface.co/spaces/Viney/readthrough/resolve/main/dashboard/note.py
65.9 kB
| # -*- coding: utf-8 -*- | |
| """The Brief, rendered as the published research note. | |
| One document, ten sections, a sticky contents bar, a sticky data rail and a | |
| sourced footer β the same structure, in the same order, with the same classes | |
| and the same palette as the artifact this design was taken from | |
| (https://claude.ai/code/artifact/a552e2bc-add9-48ea-b706-4b95f122d0e5). | |
| Two rules hold the whole file together. | |
| **Every section keeps its slot.** A section whose data the corpus does not | |
| hold still prints its eyebrow, its heading and a sentence saying so. Sections | |
| that disappear when empty would move every heading below them, and the layout | |
| is part of what is being reproduced. | |
| **Every fact keeps its tag.** Numbers reach the page through | |
| ``dashboard.note_data``, which knows whether a quarter was filed or derived, | |
| and each claim carries the source it was read from plus that source's | |
| reliability β the ``.src``/``.rel`` pair the note uses everywhere. Nothing is | |
| printed that cannot say where it came from. | |
| ``build`` is a pure function returning HTML, so the document can be asserted | |
| in tests without a Streamlit runtime. ``render`` is the Streamlit entry point. | |
| """ | |
| from __future__ import annotations | |
| from contextvars import ContextVar | |
| import re | |
| from decimal import ROUND_HALF_UP, Decimal | |
| from html import escape | |
| import streamlit as st | |
| from dashboard import note_data as nd | |
| from dashboard.i18n import STRINGS | |
| from dashboard.note_charts import bars_vs_guidance, line_series, paired_bars | |
| # ββ Locale details the note is written in ββββββββββββββββββββββββββββββββββββ | |
| _QUARTER_PREFIX = {"en": "Q", "fr": "T", "es": "T", "de": "Q"} | |
| _THOUSANDS = {"en": ",", "fr": "β―", "es": ".", "de": "."} | |
| _DECIMAL = {"en": ".", "fr": ",", "es": ",", "de": ","} | |
| # French and Spanish set a space before the percent sign; English and German do not. | |
| _PCT_SPACE = {"en": "", "fr": "β―", "es": "β―", "de": "β―"} | |
| _MONTHS_LONG = { | |
| "en": ("January", "February", "March", "April", "May", "June", "July", | |
| "August", "September", "October", "November", "December"), | |
| "fr": ("janvier", "fΓ©vrier", "mars", "avril", "mai", "juin", "juillet", | |
| "aoΓ»t", "septembre", "octobre", "novembre", "dΓ©cembre"), | |
| "es": ("enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", | |
| "agosto", "septiembre", "octubre", "noviembre", "diciembre"), | |
| "de": ("Januar", "Februar", "MΓ€rz", "April", "Mai", "Juni", "Juli", | |
| "August", "September", "Oktober", "November", "Dezember"), | |
| } | |
| _MONTHS_SHORT = { | |
| "en": ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"), | |
| "fr": ("janv.", "fΓ©vr.", "mars", "avr.", "mai", "juin", "juil.", "aoΓ»t", | |
| "sept.", "oct.", "nov.", "dΓ©c."), | |
| "es": ("ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", | |
| "sept.", "oct.", "nov.", "dic."), | |
| "de": ("Jan.", "Feb.", "MΓ€rz", "Apr.", "Mai", "Juni", "Juli", "Aug.", | |
| "Sept.", "Okt.", "Nov.", "Dez."), | |
| } | |
| # SourcedFact.source -> the tag text printed in the .src chip. | |
| _SOURCE_TAG = { | |
| "metrics": "note_tag_metrics", | |
| "transcript": "note_tag_transcript", | |
| "news": "note_tag_news", | |
| "analyst": "note_tag_analyst", | |
| } | |
| _REL_CLASS = {"HIGH": "hi", "MEDIUM": "med", "LOW": "low"} | |
| EM_DASH = "β" | |
| NO_VALUE = "β" | |
| # The language of the document being built. Numbers and words have to agree: | |
| # a note that prints "96,2" under a heading that says "Revenue" is two | |
| # documents. build() binds this once and every label resolves through it, so | |
| # the caller's `lang` governs the whole page rather than half of it. A | |
| # ContextVar rather than a module global because a hosted Space serves several | |
| # sessions from one process. | |
| _ACTIVE_LANG: ContextVar[str | None] = ContextVar("note_lang", default=None) | |
| def _lang() -> str: | |
| bound = _ACTIVE_LANG.get() | |
| if bound: | |
| return bound | |
| try: | |
| return st.session_state.get("ui_lang", "en") | |
| except Exception: | |
| return "en" | |
| def _t(key: str, lang: str | None = None) -> str: | |
| """``i18n.t`` bound to this document's language rather than the session's. | |
| *lang* overrides the bound language. It exists for the formatting helpers, | |
| which take a language argument: without it they would format the number in | |
| the language asked for and fetch its unit in the session's, printing | |
| "96,2 bn$". | |
| """ | |
| bucket = STRINGS.get(key, {}) | |
| return bucket.get(lang or _lang()) or bucket.get("en") or key | |
| # ββ Text βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _esc(text: object) -> str: | |
| """Escape for HTML and neutralise ``$``. | |
| st.markdown reads a pair of dollar signs as LaTeX, which is how dollar | |
| amounts in a brief used to render as broken maths. Every figure in this | |
| note is a dollar amount, so this is not optional. | |
| """ | |
| return escape(str(text if text is not None else "")).replace("$", "$") | |
| def _round(value: float, places: int) -> Decimal: | |
| """Round half up, the way a printed table does. | |
| Binary floating point rounds 13.25 down to 13.2; a reader comparing the | |
| note against the filing expects 13.3. Formatting a financial document is | |
| exactly where that difference is visible. | |
| """ | |
| quantum = Decimal(1).scaleb(-places) | |
| return Decimal(str(value)).quantize(quantum, rounding=ROUND_HALF_UP) | |
| def _num(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| """A number in the document's locale: grouped thousands, local decimal.""" | |
| if value is None: | |
| return NO_VALUE | |
| lang = lang or _lang() | |
| text = f"{_round(value, places):,.{places}f}" | |
| return ( | |
| text.replace(",", "\x00") | |
| .replace(".", _DECIMAL[lang]) | |
| .replace("\x00", _THOUSANDS[lang]) | |
| ) | |
| def _signed(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| if value is None: | |
| return NO_VALUE | |
| return ("+" if value >= 0 else "-") + _num(abs(value), places, lang=lang) | |
| def _pct(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| if value is None: | |
| return NO_VALUE | |
| lang = lang or _lang() | |
| return f"{_num(value, places, lang=lang)}{_PCT_SPACE[lang]}%" | |
| def _signed_pct(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| if value is None: | |
| return NO_VALUE | |
| lang = lang or _lang() | |
| return f"{_signed(value, places, lang=lang)}{_PCT_SPACE[lang]}%" | |
| def _bn(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| """A currency amount in billions, bare: no unit and no symbol. | |
| For table cells, whose column header states the unit once. | |
| """ | |
| return NO_VALUE if value is None else _num(value / 1e9, places, lang=lang) | |
| def _money(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| """A billions amount with its unit, in the document's own convention. | |
| French, Spanish and German put the amount first and the currency last | |
| ("96,2 Md$"); English puts the symbol first and the scale straight after | |
| the number ("$96.2bn"). Returns markup rather than text -- the dollar | |
| sign arrives already encoded -- so callers must not escape the result. | |
| """ | |
| lang = lang or _lang() | |
| amount = _bn(value, places, lang=lang) | |
| if amount == NO_VALUE: | |
| return NO_VALUE | |
| unit = escape(_t("note_unit_bn", lang)) | |
| return f"${amount}{unit}" if lang == "en" else f"{amount} {unit}$" | |
| def _unit(lang: str | None = None) -> str: | |
| """The billions-of-dollars unit alone, as markup. | |
| The note prints the tile value bare and puts the unit at the head of | |
| the subtitle ("96,2" over "Md$ Β· +106 % a/a"). That anatomy is kept in | |
| every language; only the unit's own spelling changes, because English | |
| writes the symbol first. | |
| """ | |
| lang = lang or _lang() | |
| unit = escape(_t("note_unit_bn", lang)) | |
| return f"${unit}" if lang == "en" else f"{unit}$" | |
| def _signed_money(value: float | None, places: int = 1, *, lang: str | None = None) -> str: | |
| """A signed billions amount with its unit, e.g. "+$5.2bn".""" | |
| lang = lang or _lang() | |
| if value is None: | |
| return NO_VALUE | |
| sign = "+" if value >= 0 else "-" | |
| return f"{sign}{_money(abs(value), places, lang=lang)}" | |
| def _per_share(value: float | None, *, lang: str | None = None) -> str: | |
| """A per-share amount, with the symbol where the language puts it.""" | |
| lang = lang or _lang() | |
| if value is None: | |
| return NO_VALUE | |
| amount = _num(value, 2, lang=lang) | |
| return f"${amount}" if lang == "en" else f"{amount} $" | |
| def _plain(label: str) -> str: | |
| """A row label stripped of its unit parenthetical, for use in a sentence. | |
| Table labels carry "(bn$)" because the column has to state the unit | |
| once. Inline, beside an amount that states its own unit, it reads twice. | |
| """ | |
| return re.sub(r"\s*\([^)]*\)\s*$", "", label) | |
| def _period_label(row: dict | None, *, lang: str | None = None, short: bool = True) -> str: | |
| """``Q2FY2027`` in the document's language: ``T2 FY27`` in French.""" | |
| if not row or not row.get("fq"): | |
| return NO_VALUE | |
| lang = lang or _lang() | |
| year = row["fy"] % 100 if short else row["fy"] | |
| return f"{_QUARTER_PREFIX[lang]}{row['fq']} FY{year:02d}" | |
| def _date(value: object, *, lang: str | None = None, long: bool = False) -> str: | |
| """``2026-08-26`` as ``26 aoΓ»t 2026`` (or ``26 sept. 2026`` when short).""" | |
| text = str(value or "")[:10] | |
| if len(text) != 10 or text[4] != "-": | |
| return text or NO_VALUE | |
| lang = lang or _lang() | |
| try: | |
| year, month, day = int(text[:4]), int(text[5:7]), int(text[8:10]) | |
| except ValueError: | |
| return text | |
| names = _MONTHS_LONG[lang] if long else _MONTHS_SHORT[lang] | |
| name = names[month - 1] | |
| if lang == "en": | |
| return f"{name} {day}, {year}" | |
| return f"{day} {name} {year}" | |
| # ββ Source chips βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _tag_text(source: object, latest: dict | None, *, lang: str | None = None) -> str: | |
| """The tag half of a source chip, period-qualified where that is knowable.""" | |
| key = str(source or "").strip() | |
| if key in ("10-K", "10-Q"): | |
| if key == "10-Q" and latest: | |
| return f"10-Q {_period_label(latest, lang=lang)}" | |
| if key == "10-K" and latest: | |
| return f"10-K FY{latest['fy'] % 100:02d}" | |
| return key | |
| if key == "transcript" and latest: | |
| return f"{_t('note_tag_transcript')} {_period_label(latest, lang=lang)}" | |
| return _t(_SOURCE_TAG.get(key, "note_tag_metrics")) if key else _t("note_tag_calc") | |
| def _src(source: object, reliability: object, latest: dict | None = None) -> str: | |
| """One ``.src`` chip: source tag welded to its reliability badge.""" | |
| rel = str(reliability or "MEDIUM").upper() | |
| cls = _REL_CLASS.get(rel, "med") | |
| return ( | |
| f'<span class="src"><span class="tag">{_esc(_tag_text(source, latest))}</span>' | |
| f'<span class="rel {cls}">{_esc(rel)}</span></span>' | |
| ) | |
| def _calc_src(reliability: str = "MEDIUM") -> str: | |
| """The chip for a number this note computed rather than read.""" | |
| cls = _REL_CLASS.get(reliability, "med") | |
| return ( | |
| f'<span class="src"><span class="tag">{_esc(_t("note_tag_calc"))}</span>' | |
| f'<span class="rel {cls}">{_esc(reliability)}</span></span>' | |
| ) | |
| def _fact_src(fact: dict, latest: dict | None) -> str: | |
| return _src(fact.get("source"), fact.get("reliability"), latest) | |
| def _dimension(key: object) -> str: | |
| """A schema enum as prose. Falls back to the key with its gaps opened up.""" | |
| raw = str(key or "").strip() | |
| if not raw: | |
| return "" | |
| label = _t(f"note_dim_{raw}") | |
| if label != f"note_dim_{raw}": | |
| return label | |
| return raw.replace("_", " ").capitalize() | |
| def _verdict(key: object) -> str: | |
| raw = str(key or "").strip().lower() | |
| if not raw: | |
| return "" | |
| label = _t(f"note_verdict_{raw}") | |
| return raw if label == f"note_verdict_{raw}" else label | |
| def _facts(brief: dict, key: str) -> list[dict]: | |
| """Verified-or-unmarked facts for *key*, failures dropped.""" | |
| out = [] | |
| for item in brief.get(key) or []: | |
| if isinstance(item, dict) and str(item.get("text") or "").strip(): | |
| if str(item.get("verification_status") or "").upper() != "FAILED": | |
| out.append(item) | |
| return out | |
| # ββ Small markup helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _section(anchor: str, eyebrow: str, heading: str, body: str) -> str: | |
| return ( | |
| f'<section id="{anchor}"><div class="eyebrow">{_esc(eyebrow)}</div>' | |
| f"<h2>{_esc(heading)}</h2>{body}</section>" | |
| ) | |
| def _empty(ticker: str) -> str: | |
| return f'<p>{_esc(_t("note_empty_section").format(ticker=ticker))}</p>' | |
| def _table(headers: list[str], rows: list[list[str]], *, classes: str = "fin compact") -> str: | |
| """A ``table.fin``. Cells are pre-escaped by their callers on purpose: | |
| several carry a source chip, which must reach the page as markup.""" | |
| if not rows: | |
| return "" | |
| head = "".join(f"<th>{h}</th>" for h in headers) | |
| body = "".join( | |
| "<tr>" + "".join(f"<td>{cell}</td>" for cell in row) + "</tr>" for row in rows | |
| ) | |
| return ( | |
| f'<div class="tblwrap"><table class="{classes}"><thead><tr>{head}</tr></thead>' | |
| f"<tbody>{body}</tbody></table></div>" | |
| ) | |
| def _dl(pairs: list[tuple[str, str]]) -> str: | |
| return "<dl>" + "".join(f"<dt>{k}</dt><dd>{v}</dd>" for k, v in pairs) + "</dl>" | |
| def _tile(key: str, value: str, sub: str, *, tone: str = "") -> str: | |
| """One tile. All three parts are markup, not text: they carry currency | |
| symbols already encoded by _money/_unit/_per_share, and escaping them | |
| again here would print the entity instead of the sign. Call sites | |
| escape whatever they take from the brief.""" | |
| cls = f"v {tone}".strip() | |
| return ( | |
| f'<div class="tile"><div class="k">{key}</div>' | |
| f'<div class="{cls}">{value}</div><div class="s">{sub}</div></div>' | |
| ) | |
| # ββ The masthead and the head ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _masthead(brief: dict, latest: dict | None, lang: str) -> str: | |
| generated = _date(brief.get("generated_at") or brief.get("data_as_of"), lang=lang, long=True) | |
| corpus = _date(brief.get("filing_date"), lang=lang, long=True) | |
| form = (latest or {}).get("form_type") or "10-Q" | |
| period = _period_label(latest, lang=lang) | |
| corpus_line = ( | |
| f'{_esc(_t("note_corpus_stop"))} <b>{_esc(corpus)}</b> ' | |
| f"({_esc(form)}{'' if period == NO_VALUE else ' ' + _esc(period)})" | |
| ) | |
| return ( | |
| '<header class="mast">' | |
| f'<div class="house">Readthrough<small>{_esc(_t("note_tagline"))}</small></div>' | |
| f'<div class="meta">{_esc(_t("note_kind"))} Β· <b>{_esc(generated)}</b><br>' | |
| f'{corpus_line}<br>{_esc(_t("note_no_reco"))}</div>' | |
| "</header>" | |
| ) | |
| def _headline(brief: dict) -> str: | |
| narrative = brief.get("narrative") or {} | |
| if isinstance(narrative, dict) and str(narrative.get("headline") or "").strip(): | |
| return str(narrative["headline"]).strip() | |
| standout = brief.get("standout_number") or {} | |
| if isinstance(standout, dict) and str(standout.get("text") or "").strip(): | |
| return str(standout["text"]).strip() | |
| return str(brief.get("what_matters_most") or "").strip() | |
| def _lede(brief: dict) -> str: | |
| narrative = brief.get("narrative") or {} | |
| if isinstance(narrative, dict) and str(narrative.get("dek") or "").strip(): | |
| return str(narrative["dek"]).strip() | |
| matters = str(brief.get("what_matters_most") or "").strip() | |
| if matters and matters != _headline(brief): | |
| return matters | |
| return str(brief.get("non_obvious_takeaway") or "").strip() | |
| def _head(brief: dict, series: list[dict], latest: dict | None, lang: str) -> str: | |
| ticker = str(brief.get("ticker") or "") | |
| company = str(brief.get("company_name") or ticker) | |
| chips = [f'<span class="tk">{_esc(ticker)}</span>'] | |
| if latest: | |
| ended = _date(latest.get("report_date"), lang=lang, long=True) | |
| label = _period_label(latest, lang=lang, short=False) | |
| chips.append( | |
| f'<span class="tk">{_esc(label)}' | |
| f'{"" if ended == NO_VALUE else " Β· " + _esc(_t("note_quarter_ended")) + " " + _esc(ended)}' | |
| "</span>" | |
| ) | |
| lede = _lede(brief) | |
| return ( | |
| '<div class="head">' | |
| f'<div class="ticker"><span class="co">{_esc(company)}</span>{"".join(chips)}</div>' | |
| f"<h1>{_esc(_headline(brief))}</h1>" | |
| + (f'<p class="lede">{_esc(lede)}</p>' if lede else "") | |
| + _in_brief(brief, latest) | |
| + _tiles(brief, series, latest, lang) | |
| + "</div>" | |
| ) | |
| def _in_brief(brief: dict, latest: dict | None) -> str: | |
| """``what_changed`` as the note's five-line summary, each line sourced.""" | |
| facts = _facts(brief, "what_changed")[:5] | |
| if not facts: | |
| return "" | |
| items = "".join( | |
| f"<li>{_esc(fact['text'])} {_fact_src(fact, latest)}</li>" for fact in facts | |
| ) | |
| return ( | |
| f'<div class="enbref"><h2>{_esc(_t("note_inbrief"))}</h2><ul>{items}</ul></div>' | |
| ) | |
| def _tiles(brief: dict, series: list[dict], latest: dict | None, lang: str) -> str: | |
| """Exactly six tiles. The grid is six columns wide; a missing measure | |
| prints an em dash rather than collapsing the row.""" | |
| unit = _t("note_unit_bn") | |
| prior = nd.prior_quarter(series, latest) if latest else None | |
| ago = nd.year_ago(series, latest) if latest else None | |
| if not latest: | |
| return ( | |
| '<div class="tiles">' | |
| + "".join(_tile(_esc(_t(k)), NO_VALUE, "") for k in ( | |
| "note_tile_revenue", "note_tile_guidance", "note_tile_gm", | |
| "note_tile_eps", "note_tile_fcf", "note_tile_debt")) | |
| + "</div>" | |
| ) | |
| # 1 β revenue, with both growth rates underneath | |
| yoy = nd.growth(latest, ago) | |
| qoq = nd.growth(latest, prior) | |
| sub_parts = [_unit(lang)] | |
| if yoy is not None: | |
| sub_parts.append(f'{_signed_pct(yoy, 0, lang=lang)} {_t("note_yoy")}') | |
| if qoq is not None: | |
| sub_parts.append(f'{_signed_pct(qoq, 0, lang=lang)} {_t("note_qoq")}') | |
| tiles = [_tile(_esc(_t("note_tile_revenue")), _bn(latest.get("revenue"), lang=lang), | |
| " Β· ".join(sub_parts))] | |
| # 2 β the gap to the guidance midpoint the company itself gave | |
| beat = nd.guidance_beat(latest) | |
| if beat: | |
| gap, gap_pct = beat | |
| key = (f'{_esc(_t("note_tile_guidance"))} ' | |
| f'{_money(latest["guidance_midpoint"], 0, lang=lang)}') | |
| sub = _signed_money(gap, lang=lang) | |
| consensus = _consensus_gap(brief, latest) | |
| if consensus is not None: | |
| sub += f' Β· {_t("note_vs_consensus")} {_signed_pct(consensus, lang=lang)}' | |
| tiles.append(_tile(key, _signed_pct(gap_pct, lang=lang), sub, | |
| tone="pos" if gap >= 0 else "warn")) | |
| else: | |
| tiles.append(_tile(_esc(_t("note_tile_guidance")), NO_VALUE, "")) | |
| # 3 β gross margin against the margin that was guided | |
| gm = latest.get("gross_margin") | |
| gm_sub = [] | |
| guided_gm = latest.get("guidance_gross_margin_low") | |
| if guided_gm is not None: | |
| gm_sub.append(f'{_t("note_guided")} {_pct(float(guided_gm) * 100, lang=lang)}') | |
| if latest.get("operating_margin") is not None: | |
| gm_sub.append(f'{_t("note_op_margin_ab")} {_pct(float(latest["operating_margin"]) * 100, lang=lang)}') | |
| tiles.append(_tile(_esc(_t("note_tile_gm")), | |
| _pct(float(gm) * 100, lang=lang) if gm is not None else NO_VALUE, | |
| " Β· ".join(gm_sub))) | |
| # 4 β EPS | |
| eps = latest.get("eps") | |
| eps_sub = [] | |
| if prior and prior.get("eps") is not None: | |
| eps_sub.append(f'{_period_label(prior, lang=lang)} {_per_share(prior["eps"], lang=lang)}') | |
| if ago and ago.get("eps") is not None: | |
| eps_sub.append(f'{_period_label(ago, lang=lang)} {_per_share(ago["eps"], lang=lang)}') | |
| tiles.append(_tile(_esc(_t("note_tile_eps")), _per_share(eps, lang=lang), | |
| " Β· ".join(eps_sub))) | |
| # 5 β cash conversion, the note's quality ratio | |
| conversion = nd.cash_conversion(latest) | |
| fcf = nd.free_cash_flow(latest) | |
| conv_sub = [] | |
| if fcf is not None: | |
| conv_sub.append(f"FCF {_money(fcf, lang=lang)}") | |
| if latest.get("net_income") is not None: | |
| conv_sub.append(f'{_t("note_net_income_ab")} {_money(latest["net_income"], lang=lang)}') | |
| tiles.append(_tile(_esc(_t("note_tile_fcf")), | |
| _pct(conversion * 100, 0, lang=lang) if conversion is not None else NO_VALUE, | |
| " Β· ".join(conv_sub), | |
| tone="warn" if conversion is not None and conversion < 0.6 else "")) | |
| # 6 β debt, flagged when it moved sharply in one quarter | |
| debt = latest.get("total_debt") | |
| debt_delta = nd.growth(latest, prior, "total_debt") | |
| debt_sub = [_unit(lang)] | |
| if prior and prior.get("total_debt") is not None and debt is not None: | |
| debt_sub.append(f'{_signed((float(debt) - float(prior["total_debt"])) / 1e9, lang=lang)} {_esc(_t("note_qoq"))}') | |
| tiles.append(_tile(_esc(_t("note_tile_debt")), _bn(debt, lang=lang), " Β· ".join(debt_sub), | |
| tone="warn" if debt_delta is not None and debt_delta > 25 else "")) | |
| return '<div class="tiles">' + "".join(tiles) + "</div>" | |
| def _consensus_gap(brief: dict, latest: dict) -> float | None: | |
| """Revenue against consensus, but only when the tool vouched for the match. | |
| ``comparison_allowed`` is the gate the pipeline sets after checking that | |
| the estimate covers the period actually reported. Without it a consensus | |
| number is a different quarter's expectation and comparing them invents a | |
| beat or a miss. | |
| """ | |
| me = brief.get("market_expectations") or {} | |
| if not isinstance(me, dict) or me.get("comparison_allowed") is not True: | |
| return None | |
| estimate = me.get("consensus_rev_est_bn") | |
| revenue = latest.get("revenue") | |
| if estimate in (None, 0) or revenue is None: | |
| return None | |
| try: | |
| return (float(revenue) / 1e9 - float(estimate)) / float(estimate) * 100.0 | |
| except (TypeError, ValueError, ZeroDivisionError): | |
| return None | |
| # ββ Contents βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _TOC = ( | |
| ("resume", "note_toc_resume"), | |
| ("print", "note_toc_print"), | |
| ("cash", "note_toc_cash"), | |
| ("bilan", "note_toc_balance"), | |
| ("segments", "note_toc_mix"), | |
| ("direction", "note_toc_mgmt"), | |
| ("capital", "note_toc_capital"), | |
| ("bullbear", "note_toc_debate"), | |
| ("watch", "note_toc_watch"), | |
| ("annexes", "note_toc_annex"), | |
| ) | |
| def _toc() -> str: | |
| links = "".join(f'<a href="#{anchor}">{_esc(_t(key))}</a>' for anchor, key in _TOC) | |
| return f'<nav class="toc">{links}</nav>' | |
| # ββ Figures ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _figure(svg: str, caption: str) -> str: | |
| """One ``<figure>``: the chart inline, then its caption. | |
| Inline rather than an <img> data URI so the chart keeps reading the page's | |
| CSS variables and its own ``.ct``/``.cv``/``.cb`` class rules, exactly as | |
| the published note's figures do. See note_charts._svg for the one | |
| attribute Streamlit requires that the published note does without. | |
| """ | |
| return f"<figure>{svg}<figcaption>{caption}</figcaption></figure>" if svg else "" | |
| # ββ Section 1 β what matters βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _readings(brief: dict, latest: dict | None) -> list[str]: | |
| """The numbered readings: the between-the-lines items first, then the | |
| earnings-quality signals, then the takeaway. Each keeps its source.""" | |
| out: list[str] = [] | |
| for item in brief.get("between_the_lines") or []: | |
| if not isinstance(item, dict): | |
| continue | |
| observation = str(item.get("observation") or "").strip() | |
| reading = str(item.get("reading") or "").strip() | |
| implication = str(item.get("implication") or "").strip() | |
| if not (observation or reading): | |
| continue | |
| evidence = item.get("evidence") if isinstance(item.get("evidence"), dict) else {} | |
| body = f"<b>{_esc(observation)}</b> {_esc(reading)}" | |
| if implication: | |
| body += f" {_esc(implication)}" | |
| out.append(body + _src(evidence.get("source"), evidence.get("reliability") or "MEDIUM", latest)) | |
| for signal in brief.get("earnings_quality_signals") or []: | |
| if not isinstance(signal, dict): | |
| continue | |
| dimension = _dimension(signal.get("dimension")) | |
| rationale = str(signal.get("rationale") or "").strip() | |
| assessment = _verdict(signal.get("assessment")) | |
| if not (dimension or rationale): | |
| continue | |
| evidence = signal.get("evidence") if isinstance(signal.get("evidence"), dict) else {} | |
| label = f"{dimension} {EM_DASH} {assessment}" if assessment else dimension | |
| out.append( | |
| f"<b>{_esc(label)}</b> {_esc(rationale)}" | |
| + _src(evidence.get("source"), evidence.get("reliability") or "MEDIUM", latest) | |
| ) | |
| takeaway = str(brief.get("non_obvious_takeaway") or "").strip() | |
| if takeaway and takeaway != _lede(brief): | |
| out.append(_esc(takeaway) + _calc_src("MEDIUM")) | |
| return out | |
| def _gap_flag(brief: dict) -> str: | |
| """The note's own statement of what it could not read. | |
| Printed even when there is nothing missing: a reader who has learnt to | |
| look here for the caveats should find an explicit all-clear, not silence | |
| that could equally mean the check was skipped. | |
| """ | |
| gaps: list[str] = [] | |
| coverage = brief.get("coverage") or {} | |
| if isinstance(coverage, dict): | |
| for gap in coverage.get("gaps") or []: | |
| text = str(gap or "").strip() | |
| if text: | |
| gaps.append(text) | |
| for name, block in coverage.items(): | |
| if not isinstance(block, dict): | |
| continue | |
| if str(block.get("status") or "").upper() in ("MISSING", "EMPTY", "FAILED"): | |
| gaps.append(f'{name}: {_t("note_aside_absent")}') | |
| for note in brief.get("evidence_notes") or []: | |
| text = str(note or "").strip() | |
| if text: | |
| gaps.append(text) | |
| if not gaps: | |
| body = _esc(_t("note_gap_none")) | |
| else: | |
| body = ( | |
| f'<b>{_esc(_t("note_gap_title"))}</b> ' | |
| + " ".join(_esc(g if g.endswith(".") else g + ".") for g in gaps[:4]) | |
| + " " | |
| + _esc(_t("note_gap_flagged")) | |
| ) | |
| return f'<div class="flag"><p>{body}</p></div>' | |
| def _section_resume(brief: dict, latest: dict | None, ticker: str) -> str: | |
| thesis = str(brief.get("what_matters_most") or "").strip() | |
| readings = _readings(brief, latest) | |
| body = "" | |
| if thesis: | |
| body += f'<div class="thesis"><p>{_esc(thesis)}</p></div>' | |
| if readings: | |
| body += "<ol>" + "".join(f"<li>{item}</li>" for item in readings) + "</ol>" | |
| if not body: | |
| body = _empty(ticker) | |
| return _section( | |
| "resume", _t("note_eb_resume"), | |
| _t("note_h2_resume").format(n=len(readings) or ""), | |
| body + _gap_flag(brief), | |
| ) | |
| # ββ Section 2 β the quarter against guidance, consensus and history ββββββββββ | |
| def _section_print(brief: dict, series: list[dict], latest: dict | None, ticker: str, lang: str) -> str: | |
| if not latest: | |
| return _section("print", _t("note_eb_print"), _t("note_h2_print"), _empty(ticker)) | |
| unit = _t("note_unit_bn") | |
| prior = nd.prior_quarter(series, latest) | |
| ago = nd.year_ago(series, latest) | |
| me = brief.get("market_expectations") or {} | |
| consensus_allowed = isinstance(me, dict) and me.get("comparison_allowed") is True | |
| def cell(row: dict | None, fn) -> str: | |
| return NO_VALUE if not row else fn(row) | |
| band = latest.get("guidance_band") | |
| guided_revenue = NO_VALUE | |
| if band: | |
| mid = (band[0] + band[1]) / 2 | |
| spread = (band[1] - band[0]) / 2 / mid * 100 if mid else None | |
| guided_revenue = _bn(mid, lang=lang) | |
| if spread: | |
| guided_revenue += f" Β± {_pct(spread, 0, lang=lang)}" | |
| gm_guided = latest.get("guidance_gross_margin_low") | |
| rows = [ | |
| [_esc(_t("note_row_revenue").format(u=unit)), | |
| _bn(latest.get("revenue"), lang=lang), guided_revenue, | |
| _num(me.get("consensus_rev_est_bn"), lang=lang) if consensus_allowed else NO_VALUE, | |
| cell(prior, lambda r: _bn(r.get("revenue"), lang=lang)), | |
| cell(ago, lambda r: _bn(r.get("revenue"), lang=lang))], | |
| [_esc(_t("note_row_gm")), | |
| _pct(float(latest["gross_margin"]) * 100, lang=lang) if latest.get("gross_margin") is not None else NO_VALUE, | |
| _pct(float(gm_guided) * 100, lang=lang) if gm_guided is not None else NO_VALUE, | |
| NO_VALUE, | |
| cell(prior, lambda r: _pct(float(r["gross_margin"]) * 100, lang=lang) if r.get("gross_margin") is not None else NO_VALUE), | |
| cell(ago, lambda r: _pct(float(r["gross_margin"]) * 100, lang=lang) if r.get("gross_margin") is not None else NO_VALUE)], | |
| [_esc(_t("note_row_opex").format(u=unit)), | |
| _bn(nd.opex(latest), 2, lang=lang), NO_VALUE, NO_VALUE, | |
| cell(prior, lambda r: _bn(nd.opex(r), 2, lang=lang)), | |
| cell(ago, lambda r: _bn(nd.opex(r), 2, lang=lang))], | |
| [_esc(_t("note_row_op_margin")), | |
| _pct(float(latest["operating_margin"]) * 100, lang=lang) if latest.get("operating_margin") is not None else NO_VALUE, | |
| NO_VALUE, NO_VALUE, | |
| cell(prior, lambda r: _pct(float(r["operating_margin"]) * 100, lang=lang) if r.get("operating_margin") is not None else NO_VALUE), | |
| cell(ago, lambda r: _pct(float(r["operating_margin"]) * 100, lang=lang) if r.get("operating_margin") is not None else NO_VALUE)], | |
| [_esc(_t("note_row_tax")), | |
| _pct(float(latest["effective_tax_rate"]) * 100, lang=lang) if latest.get("effective_tax_rate") is not None else NO_VALUE, | |
| NO_VALUE, NO_VALUE, | |
| cell(prior, lambda r: _pct(float(r["effective_tax_rate"]) * 100, lang=lang) if r.get("effective_tax_rate") is not None else NO_VALUE), | |
| cell(ago, lambda r: _pct(float(r["effective_tax_rate"]) * 100, lang=lang) if r.get("effective_tax_rate") is not None else NO_VALUE)], | |
| [_esc(_t("note_row_eps")), | |
| _num(latest.get("eps"), 2, lang=lang), NO_VALUE, | |
| _num(me.get("consensus_eps_est"), 2, lang=lang) if consensus_allowed else NO_VALUE, | |
| cell(prior, lambda r: _num(r.get("eps"), 2, lang=lang)), | |
| cell(ago, lambda r: _num(r.get("eps"), 2, lang=lang))], | |
| [_esc(_t("note_row_fcf").format(u=unit)), | |
| _bn(nd.free_cash_flow(latest), lang=lang), NO_VALUE, NO_VALUE, | |
| cell(prior, lambda r: _bn(nd.free_cash_flow(r), lang=lang)), | |
| cell(ago, lambda r: _bn(nd.free_cash_flow(r), lang=lang))], | |
| [_esc(_t("note_row_returns").format(u=unit)), | |
| _bn(nd.shareholder_returns(latest), lang=lang), NO_VALUE, NO_VALUE, | |
| cell(prior, lambda r: _bn(nd.shareholder_returns(r), lang=lang)), | |
| cell(ago, lambda r: _bn(nd.shareholder_returns(r), lang=lang))], | |
| ] | |
| headers = [ | |
| _esc(_period_label(latest, lang=lang)), | |
| _esc(_t("note_th_published")), | |
| _esc(_t("note_th_guidance")), | |
| _esc(_t("note_th_consensus")), | |
| _esc(_period_label(prior, lang=lang)), | |
| _esc(_period_label(ago, lang=lang)), | |
| ] | |
| body = _table(headers, rows) | |
| body += ( | |
| '<p style="font-size:12.5px;color:var(--ink-2)">' | |
| + _esc(_t("note_sources_line")) | |
| + _src("metrics", "HIGH", latest) + "</p>" | |
| ) | |
| body += _figure_revenue(series, latest, lang) | |
| quote = _latest_guidance_quote(brief) | |
| if quote: | |
| body += f'<h3>{_esc(_t("note_h3_guidance_frame"))}</h3>' | |
| body += ( | |
| f'<div class="quote"><p>{_esc(quote["text"])}</p></div>' | |
| + f'<p>{_src(quote.get("source"), quote.get("reliability"), latest)}</p>' | |
| ) | |
| return _section("print", _t("note_eb_print"), _t("note_h2_print"), body) | |
| def _latest_guidance_quote(brief: dict) -> dict | None: | |
| for item in brief.get("guidance_history") or []: | |
| if isinstance(item, dict) and str(item.get("text") or "").strip(): | |
| return item | |
| return None | |
| def _figure_revenue(series: list[dict], latest: dict | None, lang: str) -> str: | |
| points = [] | |
| for row in series: | |
| if row.get("revenue") is None: | |
| continue | |
| beat = nd.guidance_beat(row) | |
| points.append({ | |
| "label": _period_label(row, lang=lang), | |
| "value": float(row["revenue"]) / 1e9, | |
| "value_text": _num(float(row["revenue"]) / 1e9, 1, lang=lang), | |
| "guide": None if not row.get("guidance_midpoint") else float(row["guidance_midpoint"]) / 1e9, | |
| "delta": _signed_pct(beat[1], lang=lang) if beat else "", | |
| "derived": bool(row.get("derived")), | |
| }) | |
| if not points: | |
| return "" | |
| unit = _t("note_unit_bn") | |
| svg = bars_vs_guidance( | |
| points, | |
| label=_t("note_fig_revenue_caption"), | |
| footnote=f'{unit}$ Β· {_t("note_fig_revenue_legend")}', | |
| ) | |
| caption = ( | |
| _esc(_t("note_fig_revenue_caption")) + " " | |
| + _esc(_t("note_method_derived").format(mark="d")) | |
| + _src("metrics", "HIGH", latest) + _calc_src("MEDIUM") | |
| ) | |
| return _figure(svg, caption) | |
| # ββ Section 3 β earnings quality βββββββββββββββββββββββββββββββββββββββββββββ | |
| def _section_cash(brief: dict, series: list[dict], latest: dict | None, ticker: str, lang: str) -> str: | |
| if not latest: | |
| return _section("cash", _t("note_eb_cash"), _t("note_h2_cash"), _empty(ticker)) | |
| unit = _t("note_unit_bn") | |
| prior = nd.prior_quarter(series, latest) | |
| body = "" | |
| conversion = nd.cash_conversion(latest) | |
| fcf = nd.free_cash_flow(latest) | |
| if conversion is not None and fcf is not None: | |
| lead = ( | |
| f'{_esc(_t("note_tile_fcf"))} {_pct(conversion * 100, 0, lang=lang)}' | |
| f' ({_esc(_plain(_t("note_row_fcf").format(u=unit)))} {_money(fcf, lang=lang)}, ' | |
| f'{_esc(_t("note_row_net_income"))} {_money(latest.get("net_income"), lang=lang)}).' | |
| ) | |
| prior_conv = nd.cash_conversion(prior) if prior else None | |
| if prior_conv is not None: | |
| lead += ( | |
| f' {_esc(_period_label(prior, lang=lang))}: ' | |
| f'{_pct(prior_conv * 100, 0, lang=lang)}.' | |
| ) | |
| body += f"<p>{lead}{_calc_src('MEDIUM')}{_src('metrics', 'HIGH', latest)}</p>" | |
| # Net income against free cash flow, quarter by quarter. | |
| groups = [] | |
| for row in series[-9:]: | |
| net_income, quarter_fcf = row.get("net_income"), nd.free_cash_flow(row) | |
| if net_income is None or quarter_fcf is None: | |
| continue | |
| ratio = nd.cash_conversion(row) | |
| groups.append({ | |
| "label": _period_label(row, lang=lang), | |
| "left": float(net_income) / 1e9, | |
| "left_text": _num(float(net_income) / 1e9, 1, lang=lang), | |
| "right": quarter_fcf / 1e9, | |
| "right_text": _num(quarter_fcf / 1e9, 1, lang=lang), | |
| "ratio": _pct(ratio * 100, 0, lang=lang) if ratio is not None else "", | |
| "ratio_warn": ratio is not None and ratio < 0.6, | |
| }) | |
| if groups: | |
| svg = paired_bars( | |
| groups, | |
| label=_t("note_fig_cash_caption"), | |
| footnote=f'{unit}$ Β· {_t("note_fig_cash_legend")}', | |
| ) | |
| body += _figure( | |
| svg, | |
| _esc(_t("note_fig_cash_caption")) | |
| + _src("metrics", "HIGH", latest) + _calc_src("MEDIUM"), | |
| ) | |
| # Days sales outstanding β where a receivable-funded quarter shows up. | |
| points = [] | |
| for row in series[-9:]: | |
| days = nd.dso(row) | |
| if days is None: | |
| continue | |
| points.append({ | |
| "label": _period_label(row, lang=lang), | |
| "value": days, | |
| "value_text": _num(days, 0, lang=lang), | |
| "emphasis": row is latest, | |
| }) | |
| if points: | |
| svg = line_series( | |
| points, | |
| label=_t("note_fig_dso_caption"), | |
| footnote=f'{_t("note_row_dso")} Β· {_t("note_fig_dso_legend")}', | |
| ) | |
| body += _figure( | |
| svg, | |
| _esc(_t("note_fig_dso_caption")) + _calc_src("MEDIUM"), | |
| ) | |
| body += _bridge_table(series, latest, lang, unit) | |
| signals = [ | |
| s for s in brief.get("earnings_quality_signals") or [] | |
| if isinstance(s, dict) and str(s.get("rationale") or "").strip() | |
| ] | |
| if signals: | |
| for signal in signals[:3]: | |
| evidence = signal.get("evidence") if isinstance(signal.get("evidence"), dict) else {} | |
| snippet = str(evidence.get("evidence_snippet") or "").strip() | |
| if not snippet: | |
| continue | |
| body += ( | |
| f'<div class="quote"><p>{_esc(snippet)}</p>' | |
| f'<p class="gl">{_esc(signal.get("rationale"))}</p></div>' | |
| ) | |
| return _section("cash", _t("note_eb_cash"), _t("note_h2_cash"), body or _empty(ticker)) | |
| def _bridge_table(series: list[dict], latest: dict, lang: str, unit: str) -> str: | |
| """Net income to operating cash flow, with the unexplained gap named. | |
| The residual line is the point of the table. Everything the corpus tags | |
| is listed; whatever the tagged items do not account for is shown as a | |
| residual rather than folded silently into another line. | |
| """ | |
| ocf = latest.get("operating_cash_flow") | |
| net_income = latest.get("net_income") | |
| if ocf is None or net_income is None: | |
| return "" | |
| prior = nd.prior_quarter(series, latest) | |
| def delta(key: str) -> float | None: | |
| if not prior or latest.get(key) is None or prior.get(key) is None: | |
| return None | |
| return float(latest[key]) - float(prior[key]) | |
| rows: list[list[str]] = [[_esc(_t("note_row_net_income")), _bn(net_income, lang=lang)]] | |
| accounted = float(net_income) | |
| for key, label, sign in ( | |
| ("depreciation_amortization", "note_row_da", +1), | |
| ("sbc", "note_row_sbc", +1), | |
| ): | |
| value = latest.get(key) | |
| if value is None: | |
| continue | |
| accounted += sign * float(value) | |
| rows.append([_esc(_t(label)), _signed(sign * float(value) / 1e9, lang=lang)]) | |
| for key, label in ( | |
| ("receivables", "note_row_receivables"), | |
| ("inventory", "note_row_inventory"), | |
| ("deferred_revenue", "note_row_deferred"), | |
| ): | |
| change = delta(key) | |
| if change is None: | |
| continue | |
| # A receivable or an inventory build consumes cash; deferred revenue supplies it. | |
| effect = change if key == "deferred_revenue" else -change | |
| accounted += effect | |
| rows.append([_esc(_t(label)), _signed(effect / 1e9, lang=lang)]) | |
| residual = float(ocf) - accounted | |
| rows.append([_esc(_t("note_row_residual")), _signed(residual / 1e9, lang=lang)]) | |
| rows.append([_esc(_t("note_row_ocf")), _bn(ocf, lang=lang)]) | |
| table = _table([_esc(_t("note_th_line")), f"{_esc(unit)}$"], rows) | |
| return f'<h3>{_esc(_t("note_h3_ni_to_ocf"))}</h3>{table}' | |
| # ββ Section 4 β the balance sheet ββββββββββββββββββββββββββββββββββββββββββββ | |
| def _section_balance(brief: dict, series: list[dict], latest: dict | None, ticker: str, lang: str) -> str: | |
| if not latest: | |
| return _section("bilan", _t("note_eb_balance"), _t("note_h2_balance"), _empty(ticker)) | |
| unit = _t("note_unit_bn") | |
| prior = nd.prior_quarter(series, latest) | |
| lines: list[str] = [] | |
| rows: list[list[str]] = [] | |
| for key, label in ( | |
| ("receivables", "note_row_receivables"), | |
| ("inventory", "note_row_inventory"), | |
| ("deferred_revenue", "note_row_deferred"), | |
| ("total_debt", "note_row_debt"), | |
| ("cash_and_st_investments", "note_row_cash"), | |
| ("stockholders_equity", "note_row_equity"), | |
| ): | |
| now = latest.get(key) | |
| if now is None: | |
| continue | |
| then = (prior or {}).get(key) | |
| change = None if then is None else float(now) - float(then) | |
| rows.append([ | |
| _esc(_t(label)), | |
| _bn(now, lang=lang), | |
| NO_VALUE if then is None else _bn(then, lang=lang), | |
| NO_VALUE if change is None else _signed(change / 1e9, lang=lang), | |
| ]) | |
| # Risks the filing itself marks as new are the note's "what is new" line. | |
| for risk in brief.get("risks_categorized") or []: | |
| if not isinstance(risk, dict) or not risk.get("is_new_this_filing"): | |
| continue | |
| text = str(risk.get("text") or "").strip() | |
| if text: | |
| lines.append( | |
| f'<li><b>{_esc(risk.get("category") or "")}</b> {_esc(text)}' | |
| + _fact_src(risk, latest) + "</li>" | |
| ) | |
| body = "" | |
| if lines: | |
| body += f'<h3>{_esc(_t("note_h3_balance_delta"))}</h3><ul>{"".join(lines)}</ul>' | |
| if rows: | |
| headers = [ | |
| _esc(_t("note_th_metric")), | |
| _esc(_period_label(latest, lang=lang)), | |
| _esc(_period_label(prior, lang=lang)), | |
| _esc(_t("note_th_gap")), | |
| ] | |
| body += _table(headers, rows) | |
| body += ( | |
| f'<p style="font-size:12.5px;color:var(--ink-2)">{_esc(unit)}$ Β· ' | |
| f'{_esc(_t("note_method_verified"))}{_src("metrics", "HIGH", latest)}</p>' | |
| ) | |
| return _section("bilan", _t("note_eb_balance"), _t("note_h2_balance"), body or _empty(ticker)) | |
| # ββ Section 5 β revenue mix ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _section_mix(brief: dict, latest: dict | None, ticker: str, lang: str) -> str: | |
| rows: list[list[str]] = [] | |
| note = "" | |
| try: | |
| from storage import segments_db | |
| for axis in ("srt:ProductOrServiceAxis", "us-gaap:StatementBusinessSegmentsAxis"): | |
| period_end = segments_db.latest_period_end(ticker, axis) | |
| if not period_end: | |
| continue | |
| members = segments_db.read_segments(ticker, axis, period_end) | |
| total = sum(float(m["revenue"]) for m in members if m.get("revenue")) or 0.0 | |
| for member in members: | |
| revenue = member.get("revenue") | |
| if revenue is None: | |
| continue | |
| label = str(member.get("label") or member.get("member") or "").split(":")[-1] | |
| label = label.removesuffix("Member") | |
| rows.append([ | |
| _esc(label), | |
| _bn(revenue, lang=lang), | |
| _pct(float(revenue) / total * 100, lang=lang) if total else NO_VALUE, | |
| _esc(_date(period_end, lang=lang)), | |
| ]) | |
| if rows: | |
| # The mix can lag the income statement by a quarter: segment | |
| # tables are tagged on their own schedule. Say which period is | |
| # on screen rather than letting it read as the latest one. | |
| if latest and str(period_end) != str(latest.get("report_date")): | |
| note = ( | |
| f'<p>{_esc(_t("note_h2_mix"))} {EM_DASH} ' | |
| f'{_esc(_date(period_end, lang=lang))}.' | |
| f'{_src("10-Q", "HIGH", latest)}</p>' | |
| ) | |
| break | |
| except Exception: | |
| rows = [] | |
| body = note | |
| if rows: | |
| headers = [ | |
| _esc(_t("note_th_segment")), | |
| f'{_esc(_t("note_unit_bn"))}$', | |
| _esc(_t("note_th_share")), | |
| _esc(_t("note_th_quarter")), | |
| ] | |
| body += _table(headers, rows) | |
| for driver in (brief.get("mda_summary") or {}).get("drivers") or []: | |
| if isinstance(driver, dict) and str(driver.get("text") or "").strip(): | |
| body += f'<p>{_esc(driver["text"])}{_fact_src(driver, latest)}</p>' | |
| return _section("segments", _t("note_eb_mix"), _t("note_h2_mix"), body or _empty(ticker)) | |
| # ββ Section 6 β management on the record βββββββββββββββββββββββββββββββββββββ | |
| def _section_management(brief: dict, latest: dict | None, ticker: str) -> str: | |
| body = "" | |
| mda = brief.get("mda_summary") or {} | |
| key_quote = mda.get("key_quote") if isinstance(mda, dict) else None | |
| if isinstance(key_quote, dict) and str(key_quote.get("evidence_snippet") or "").strip(): | |
| body += ( | |
| f'<div class="quote"><p>{_esc(key_quote["evidence_snippet"])}</p>' | |
| f'<p class="gl">{_esc(key_quote.get("text") or "")}</p></div>' | |
| ) | |
| for topic in brief.get("management_commentary") or []: | |
| if not isinstance(topic, dict): | |
| continue | |
| summary = str(topic.get("summary") or "").strip() | |
| if not summary: | |
| continue | |
| heading = str(topic.get("topic") or "").strip() | |
| body += ( | |
| (f"<h3>{_esc(heading)}</h3>" if heading else "") | |
| + f"<p>{_esc(summary)}{_fact_src(topic, latest)}</p>" | |
| ) | |
| for headwind in (mda.get("headwinds") or []) if isinstance(mda, dict) else []: | |
| if isinstance(headwind, dict) and str(headwind.get("text") or "").strip(): | |
| body += ( | |
| f'<div class="flag"><p>{_esc(headwind["text"])}' | |
| f"{_fact_src(headwind, latest)}</p></div>" | |
| ) | |
| return _section("direction", _t("note_eb_mgmt"), _t("note_h2_mgmt"), body or _empty(ticker)) | |
| # ββ Section 7 β capital allocation βββββββββββββββββββββββββββββββββββββββββββ | |
| def _section_capital(series: list[dict], latest: dict | None, ticker: str, lang: str) -> str: | |
| if not latest: | |
| return _section("capital", _t("note_eb_capital"), _t("note_h2_capital"), _empty(ticker)) | |
| unit = _t("note_unit_bn") | |
| prior = nd.prior_quarter(series, latest) | |
| items: list[str] = [] | |
| for key, label in ( | |
| ("buybacks", "note_row_buybacks"), | |
| ("dividends_paid", "note_row_dividends"), | |
| ): | |
| value = latest.get(key) | |
| if value is None: | |
| continue | |
| line = f'<b>{_esc(_plain(_t(label)))}</b> {_money(value, lang=lang)}' | |
| then = (prior or {}).get(key) | |
| if then is not None: | |
| line += ( | |
| f' ({_esc(_period_label(prior, lang=lang))}: ' | |
| f'{_money(then, lang=lang)})' | |
| ) | |
| items.append(f'<li>{line}{_src("10-Q", "HIGH", latest)}</li>') | |
| returns, fcf = nd.shareholder_returns(latest), nd.free_cash_flow(latest) | |
| if returns is not None and fcf: | |
| items.append( | |
| f'<li><b>{_esc(_plain(_t("note_row_returns").format(u=unit)))}</b> ' | |
| f'{_money(returns, lang=lang)} Β· ' | |
| f'{_pct(returns / fcf * 100, 0, lang=lang)} ' | |
| f'{_esc(_plain(_t("note_row_fcf").format(u=unit)))}' | |
| f"{_calc_src('MEDIUM')}</li>" | |
| ) | |
| shares = latest.get("shares_diluted") | |
| if shares is not None: | |
| line = (f'<b>{_esc(_t("note_row_shares"))}</b> ' | |
| f'{_bn(shares, 2, lang=lang)} {_esc(_t("note_unit_bn"))}') | |
| change = nd.growth(latest, prior, "shares_diluted") | |
| if change is not None: | |
| line += f' Β· {_signed_pct(change, lang=lang)} {_esc(_t("note_qoq"))}' | |
| items.append(f'<li>{line}{_src("metrics", "HIGH", latest)}</li>') | |
| debt = latest.get("total_debt") | |
| if debt is not None: | |
| line = f'<b>{_esc(_t("note_row_debt"))}</b> {_money(debt, lang=lang)}' | |
| then = (prior or {}).get("total_debt") | |
| if then is not None: | |
| line += ( | |
| f' ({_esc(_period_label(prior, lang=lang))}: ' | |
| f'{_money(then, lang=lang)})' | |
| ) | |
| items.append(f'<li>{line}{_src("10-Q", "HIGH", latest)}</li>') | |
| body = f'<ul>{"".join(items)}</ul>' if items else _empty(ticker) | |
| return _section("capital", _t("note_eb_capital"), _t("note_h2_capital"), body) | |
| # ββ Section 8 β the two readings βββββββββββββββββββββββββββββββββββββββββββββ | |
| def _section_debate(brief: dict, latest: dict | None, ticker: str) -> str: | |
| bull = _facts(brief, "bull_points") | |
| bear = _facts(brief, "bear_points") | |
| if not bull and not bear: | |
| return _section("bullbear", _t("note_eb_debate"), _t("note_h2_debate"), _empty(ticker)) | |
| def column(heading: str, facts: list[dict]) -> str: | |
| if not facts: | |
| return f"<div><h3>{_esc(heading)}</h3>{_empty(ticker)}</div>" | |
| items = "".join( | |
| f"<li>{_esc(fact['text'])}{_fact_src(fact, latest)}</li>" for fact in facts | |
| ) | |
| return f"<div><h3>{_esc(heading)}</h3><ol>{items}</ol></div>" | |
| body = ( | |
| '<div class="bb">' | |
| + column(_t("note_h3_bull"), bull) | |
| + column(_t("note_h3_bear"), bear) | |
| + "</div>" | |
| ) | |
| return _section("bullbear", _t("note_eb_debate"), _t("note_h2_debate"), body) | |
| # ββ Section 9 β the calendar βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _section_watch(brief: dict, latest: dict | None, ticker: str) -> str: | |
| items = [] | |
| watch = brief.get("what_to_watch") or [] | |
| for entry in watch: | |
| if isinstance(entry, dict): | |
| text = str(entry.get("text") or entry.get("watch") or "").strip() | |
| when = str(entry.get("event_date") or entry.get("period") or "").strip() | |
| else: | |
| text = str(entry or "").strip() | |
| when = "" | |
| if not text: | |
| continue | |
| # No date in the data means no date on the page. The column still needs | |
| # a value, so it says what kind of horizon this is instead of guessing. | |
| when = when or ( | |
| _t("note_watch_next_read") | |
| if any(word in text.lower() for word in ("next quarter", "next filing", "10-q", "transcript", | |
| "prochain", "prΓ³ximo", "nΓ€chst")) | |
| else _t("note_watch_ongoing") | |
| ) | |
| items.append( | |
| f'<li><span class="d">{_esc(when)}</span>' | |
| f'<span>{_esc(text)}{_calc_src("MEDIUM")}</span></li>' | |
| ) | |
| body = f'<ul class="tl">{"".join(items)}</ul>' if items else _empty(ticker) | |
| return _section("watch", _t("note_eb_watch"), _t("note_h2_watch"), body) | |
| # ββ Section 10 β appendices ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _annexe(eyebrow: str, heading: str, body: str) -> str: | |
| return ( | |
| f'<div class="annexe"><div class="eyebrow">{_esc(eyebrow)}</div>' | |
| f"<h3>{_esc(heading)}</h3>{body}</div>" | |
| ) | |
| def _section_annexes(brief: dict, series: list[dict], latest: dict | None, | |
| market: dict | None, ticker: str, lang: str) -> str: | |
| unit = _t("note_unit_bn") | |
| body = "" | |
| # The guidance record: every quarter the company guided, against what it filed. | |
| track_rows = [] | |
| for row in series: | |
| beat = nd.guidance_beat(row) | |
| if not beat: | |
| continue | |
| gap, gap_pct = beat | |
| gm_guided = row.get("guidance_gross_margin_low") | |
| track_rows.append([ | |
| _esc(_period_label(row, lang=lang)) + ("<sup>d</sup>" if row.get("derived") else ""), | |
| _bn(row["guidance_midpoint"], lang=lang), | |
| _bn(row.get("revenue"), lang=lang), | |
| _signed_pct(gap_pct, lang=lang), | |
| _signed(gap / 1e9, lang=lang), | |
| _pct(float(gm_guided) * 100, lang=lang) if gm_guided is not None else NO_VALUE, | |
| _pct(float(row["gross_margin"]) * 100, lang=lang) if row.get("gross_margin") is not None else NO_VALUE, | |
| ]) | |
| if track_rows: | |
| headers = [ | |
| _esc(_t("note_th_quarter")), | |
| f'{_esc(_t("note_th_guidance"))} ({_esc(_t("note_th_midpoint"))})', | |
| _esc(_t("note_th_actual")), | |
| _esc(_t("note_th_gap")), | |
| f'{_esc(_t("note_th_gap"))} ({_esc(unit)}$)', | |
| f'{_esc(_t("note_tile_gm"))} {_esc(_t("note_guided"))}', | |
| _esc(_t("note_th_actual")), | |
| ] | |
| footnote = ( | |
| '<p style="font-size:12.5px;color:var(--ink-2)"><sup>d</sup> ' | |
| + _esc(_t("note_method_derived").format(mark="d")) | |
| + "</p>" | |
| ) | |
| body += _annexe( | |
| _t("note_annex_eb_history"), _t("note_h3_track"), | |
| _table(headers, track_rows) + footnote, | |
| ) | |
| # Multiples, printed as market context and nothing more. | |
| if market: | |
| rows = [] | |
| for key, label in ( | |
| ("price", "note_aside_price"), | |
| ("trailing_pe", None), | |
| ("forward_pe", None), | |
| ("ev_to_sales", None), | |
| ("ev_to_ebitda", None), | |
| ("dividend_yield_pct", None), | |
| ): | |
| value = market.get(key) | |
| if value is None: | |
| continue | |
| name = _t(label) if label else key.replace("_", " ").upper() | |
| text = ( | |
| _pct(float(value), 2, lang=lang) if key == "dividend_yield_pct" | |
| else _num(float(value), 2, lang=lang) | |
| ) | |
| rows.append([_esc(name), text]) | |
| if rows: | |
| body += _annexe( | |
| _t("note_annex_eb_market"), _t("note_h3_multiples"), | |
| _table([_esc(_t("note_th_metric")), _esc(_t("note_th_value"))], rows) | |
| + f'<p style="font-size:12.5px;color:var(--ink-2)">' | |
| f'{_esc(_t("note_aside_market_note"))}{_src("analyst", "MEDIUM", latest)}</p>', | |
| ) | |
| # The series the whole note is built on, printed so it can be checked. | |
| if series: | |
| quarters = series[-9:] | |
| headers = [""] + [ | |
| _esc(_period_label(row, lang=lang)) + ("<sup>d</sup>" if row.get("derived") else "") | |
| for row in quarters | |
| ] | |
| def line(label: str, fn) -> list[str]: | |
| return [_esc(label)] + [fn(row) for row in quarters] | |
| rows = [ | |
| line(_t("note_row_revenue").format(u=unit), lambda r: _bn(r.get("revenue"), lang=lang)), | |
| line(_t("note_row_gm"), lambda r: _pct(float(r["gross_margin"]) * 100, lang=lang) if r.get("gross_margin") is not None else NO_VALUE), | |
| line(_t("note_row_net_income"), lambda r: _bn(r.get("net_income"), lang=lang)), | |
| line(_t("note_row_ocf"), lambda r: _bn(r.get("operating_cash_flow"), lang=lang)), | |
| line(_t("note_row_capex"), lambda r: _bn(r.get("capex"), lang=lang)), | |
| line(_t("note_row_fcf").format(u=unit), lambda r: _bn(nd.free_cash_flow(r), lang=lang)), | |
| line(_t("note_row_receivables"), lambda r: _bn(r.get("receivables"), lang=lang)), | |
| line(_t("note_row_dso"), lambda r: _num(nd.dso(r), 0, lang=lang)), | |
| line(_t("note_row_debt"), lambda r: _bn(r.get("total_debt"), lang=lang)), | |
| line(_t("note_row_rd"), lambda r: _bn(r.get("research_development"), lang=lang)), | |
| line(_t("note_row_sga"), lambda r: _bn(r.get("sga"), lang=lang)), | |
| ] | |
| body += _annexe( | |
| _t("note_annex_eb_data"), _t("note_h3_quarters").format(n=len(quarters)), | |
| _table(headers, rows, classes="fin"), | |
| ) | |
| return _section("annexes", _t("note_eb_annex"), _t("note_h2_annex"), body or _empty(ticker)) | |
| # ββ The data rail ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _aside(brief: dict, series: list[dict], latest: dict | None, | |
| market: dict | None, lang: str) -> str: | |
| unit = _t("note_unit_bn") | |
| boxes = [] | |
| if latest: | |
| pairs = [ | |
| (_esc(_t("note_quarter_ended")), _esc(_date(latest.get("report_date"), lang=lang))), | |
| (f'{_esc(latest.get("form_type") or "10-Q")} {_esc(_t("note_aside_filed"))}', | |
| _esc(_date(latest.get("filing_date"), lang=lang))), | |
| ] | |
| if latest.get("accession"): | |
| pairs.append((_esc(_t("note_aside_accession")), _esc(latest["accession"]))) | |
| for key, label in ( | |
| ("revenue", "note_tile_revenue"), | |
| ("net_income", "note_row_net_income"), | |
| ("operating_cash_flow", "note_row_ocf"), | |
| ("capex", "note_row_capex"), | |
| ("research_development", "note_row_rd"), | |
| ("sga", "note_row_sga"), | |
| ("sbc", "note_row_sbc"), | |
| ): | |
| if latest.get(key) is not None: | |
| pairs.append((_esc(_plain(_t(label))), _money(latest[key], lang=lang))) | |
| fcf = nd.free_cash_flow(latest) | |
| if fcf is not None: | |
| pairs.append((_esc(_plain(_t("note_row_fcf").format(u=unit))), | |
| _money(fcf, lang=lang))) | |
| if latest.get("eps") is not None: | |
| pairs.append((_esc(_t("note_tile_eps")), _per_share(latest["eps"], lang=lang))) | |
| boxes.append( | |
| f'<div class="box"><h4>{_esc(_t("note_aside_key"))} Β· ' | |
| f'{_esc(_period_label(latest, lang=lang))}</h4>{_dl(pairs)}</div>' | |
| ) | |
| if market: | |
| pairs = [] | |
| if market.get("price") is not None: | |
| pairs.append((_esc(_t("note_aside_price")), _per_share(market["price"], lang=lang))) | |
| if market.get("market_cap"): | |
| pairs.append((_esc(_t("note_aside_mcap")), | |
| _money(market["market_cap"], 0, lang=lang))) | |
| if market.get("week52_low") and market.get("week52_high"): | |
| pairs.append(( | |
| _esc(_t("note_aside_52w")), | |
| f'{_per_share(market["week52_low"], lang=lang)}{EM_DASH}' | |
| f'{_per_share(market["week52_high"], lang=lang)}', | |
| )) | |
| if pairs: | |
| boxes.append( | |
| f'<div class="box"><h4>{_esc(_t("note_aside_market"))}</h4>{_dl(pairs)}' | |
| f'<p class="note">{_esc(_t("note_aside_market_note"))}</p></div>' | |
| ) | |
| coverage = brief.get("coverage") or {} | |
| pairs = [(_esc(_t("note_aside_quarters")), _esc(str(len(series))))] | |
| if isinstance(coverage, dict): | |
| for name, label in ( | |
| ("filings", "note_aside_filings"), | |
| ("transcripts", "note_aside_transcripts"), | |
| ("news", "note_aside_news"), | |
| ): | |
| block = coverage.get(name) | |
| if isinstance(block, dict): | |
| count = block.get("evidence_count") | |
| pairs.append(( | |
| _esc(_t(label)), | |
| _esc(str(count) if count is not None else (block.get("status") or NO_VALUE)), | |
| )) | |
| report = brief.get("evidence_coverage") or brief.get("verification_report") or {} | |
| if isinstance(report, dict) and report.get("verified") is not None: | |
| total = report.get("total") or ( | |
| (report.get("verified") or 0) + (report.get("unverified") or 0) + (report.get("failed") or 0) | |
| ) | |
| pairs.append((_esc(_t("note_aside_verified")), _esc(f'{report["verified"]} / {total}'))) | |
| boxes.append(f'<div class="box"><h4>{_esc(_t("note_aside_coverage"))}</h4>{_dl(pairs)}</div>') | |
| boxes.append( | |
| f'<div class="box"><h4>{_esc(_t("note_aside_rel"))}</h4>' | |
| f'<div class="legend"><span class="rel hi">HIGH</span><span>{_esc(_t("note_rel_hi"))}</span></div>' | |
| f'<div class="legend"><span class="rel med">MEDIUM</span><span>{_esc(_t("note_rel_med"))}</span></div>' | |
| f'<div class="legend"><span class="rel low">LOW</span><span>{_esc(_t("note_rel_low"))}</span></div>' | |
| "</div>" | |
| ) | |
| return "<aside>" + "".join(boxes) + "</aside>" | |
| # ββ The footer βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _footer(brief: dict, series: list[dict], latest: dict | None, lang: str) -> str: | |
| sources = [] | |
| seen: set[str] = set() | |
| for row in reversed(series): | |
| accession = str(row.get("accession") or "") | |
| if not accession or accession in seen or row.get("derived"): | |
| continue | |
| seen.add(accession) | |
| form = row.get("form_type") or "10-Q" | |
| label = ( | |
| f'{form} {_period_label(row, lang=lang, short=False)}, {_t("note_aside_accession")} ' | |
| f'{accession}, {_t("note_aside_filed")} {_date(row.get("filing_date"), lang=lang)}' | |
| ) | |
| url = row.get("source_url") | |
| item = _esc(label) | |
| if url: | |
| item += f' {EM_DASH} <a href="{escape(str(url))}">sec.gov</a>' | |
| sources.append(f"<li>{item}</li>") | |
| if len(sources) >= 6: | |
| break | |
| method = "".join( | |
| f"<li>{_esc(text)}</li>" | |
| for text in ( | |
| _t("note_method_corpus"), | |
| _t("note_method_derived").format(mark="d"), | |
| _t("note_method_fcf"), | |
| _t("note_method_verified"), | |
| ) | |
| ) | |
| return ( | |
| '<footer class="foot">' | |
| + (f'<h4>{_esc(_t("note_foot_sources"))}</h4><ul>{"".join(sources)}</ul>' if sources else "") | |
| + f'<h4>{_esc(_t("note_foot_method"))}</h4><ul>{method}</ul>' | |
| + f'<h4>{_esc(_t("note_foot_warning"))}</h4>' | |
| + f'<p style="max-width:none">{_esc(_t("disclaimer"))}</p>' | |
| + "</footer>" | |
| ) | |
| # ββ Assembly βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def build(brief: dict, *, series: list[dict] | None = None, | |
| market: dict | None = None, lang: str | None = None) -> str: | |
| """Return the note as one HTML string. No Streamlit, no network.""" | |
| token = _ACTIVE_LANG.set(lang or _lang()) | |
| try: | |
| return _build(brief, series=series, market=market) | |
| finally: | |
| _ACTIVE_LANG.reset(token) | |
| def _build(brief: dict, *, series: list[dict] | None, market: dict | None) -> str: | |
| lang = _lang() | |
| ticker = str((brief or {}).get("ticker") or "") | |
| series = series if series is not None else nd.quarter_series(ticker) | |
| latest = series[-1] if series else None | |
| main = ( | |
| "<main>" | |
| + _section_resume(brief, latest, ticker) | |
| + _section_print(brief, series, latest, ticker, lang) | |
| + _section_cash(brief, series, latest, ticker, lang) | |
| + _section_balance(brief, series, latest, ticker, lang) | |
| + _section_mix(brief, latest, ticker, lang) | |
| + _section_management(brief, latest, ticker) | |
| + _section_capital(series, latest, ticker, lang) | |
| + _section_debate(brief, latest, ticker) | |
| + _section_watch(brief, latest, ticker) | |
| + _section_annexes(brief, series, latest, market, ticker, lang) | |
| + "</main>" | |
| ) | |
| return ( | |
| '<div class="rt-note"><div class="wrap">' | |
| + _masthead(brief, latest, lang) | |
| + _head(brief, series, latest, lang) | |
| + _toc() | |
| + '<div class="grid">' | |
| + main | |
| + _aside(brief, series, latest, market, lang) | |
| + "</div>" | |
| + _footer(brief, series, latest, lang) | |
| + "</div></div>" | |
| ) | |
| def _market(ticker: str) -> dict | None: | |
| """Cached quote and multiples, or None. Never raises, never blocks a render.""" | |
| try: | |
| from analytics.valuation import fetch_multiples | |
| data, _error = fetch_multiples(ticker) | |
| return data or None | |
| except Exception: | |
| return None | |
| def render(brief: dict) -> None: | |
| """The Brief, as the note. Streamlit entry point. | |
| The stylesheet is not injected here: ``theme.inject_global_css`` ships it | |
| once per page load, pinned to the light tokens. Re-injecting the | |
| dark-capable ``TOKENS`` from inside a rerun would let the document flip | |
| palette while the plotly charts on the other routes could not follow. | |
| ``st.markdown`` rather than ``st.html``: st.html's sanitiser strips | |
| ``<svg>`` outright, which empties every figure. Markdown keeps it, at the | |
| price of reading paired dollar signs as LaTeX β which is why every ``$`` | |
| in this module and in note_charts is emitted as ``$``. | |
| """ | |
| ticker = str((brief or {}).get("ticker") or "") | |
| st.markdown(build(brief, market=_market(ticker)), unsafe_allow_html=True) | |