CoolFace
Apppublic

suryaarajan/earnings-lens-project

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
App README

πŸ“ˆ EarningsLens

AI-powered, explainable analysis of earnings-call language.

EarningsLens takes a pasted earnings-call paragraph, management-commentary snippet, or transcript excerpt and returns a structured, beginner-readable analysis: financial sentiment, operational and financial themes, an explainable operational-risk score, management outlook, likely financial impacts, supporting evidence, and a concise executive summary.

It sits at the intersection of business analytics, supply-chain and operations management, finance and investment analysis, and natural-language processing β€” implemented with Hugging Face transformers and a small, transparent Python application.

⚠️ Educational decision-support tool β€” not financial advice. EarningsLens analyzes language. It does not predict stock returns and is not an investment-recommendation system.

1. Project overview

EarningsLens is a portfolio-quality MVP that demonstrates how pretrained NLP models plus transparent, hand-written heuristics can turn dense earnings-call prose into structured, explainable signals a business student can read and reason about.

2. Business problem

Earnings calls are long and full of hedged, qualitative language. Analysts, students, and operators want a fast way to gauge tone, surface operational and financial themes (freight, inventory, demand, margins, capacity, and so on), and frame likely business effects β€” without over-claiming precision. EarningsLens provides that first-pass lens while being explicit about its limits.

3. Main features

  • β€”Financial sentiment (positive / negative / neutral) with a signed score.
  • β€”Operational & financial themes via configurable zero-shot classification.
  • β€”Explainable operational-risk score (0–100) with a documented formula.
  • β€”Management outlook (Optimistic / Balanced / Cautious).
  • β€”Likely financial impacts from a transparent themeβ†’effect mapping.
  • β€”Evidence excerpts drawn directly from your input.
  • β€”Deterministic executive summary in hedged, decision-support language.
  • β€”Sentence-aware chunking so long passages are handled without truncation.
  • β€”Runs fully local on CPU β€” no API keys, database, or external data feeds.

4. Architecture

app.py                      Gradio Blocks UI (module-level `demo` for HF Spaces)
src/earnings_lens/
β”œβ”€β”€ config.py               Model names, thresholds, theme lists, label maps
β”œβ”€β”€ schemas.py              Typed dataclasses for internal results
β”œβ”€β”€ chunking.py             Sentence splitting + token-bounded chunking
β”œβ”€β”€ models.py               Lazy, lru_cache-d Hugging Face pipelines
β”œβ”€β”€ scoring.py              Aggregation + explainable heuristics
β”œβ”€β”€ analyzer.py             Orchestration + input validation (DI-friendly)
└── formatting.py           Executive summary + display tables

The analysis logic is decoupled from the models: analyzer.analyze() accepts injectable sentiment_fn, zeroshot_fn, and tokenizer callables, so the whole pipeline is testable with fakes and no downloads.

5. Models used

PurposeModelHow it is used
Financial sentiment`ProsusAI/finbert`All three class probabilities per chunk, labels normalized to lowercase
Theme classification`cross-encoder/nli-deberta-v3-small`Zero-shot, multi_label=True, hypothesis template "This earnings-call passage discusses {}."

Both run on CPU by default (device=-1); CUDA is never assumed. Pipelines are lazily built and cached with functools.lru_cache, so models load only on the first analysis β€” importing a module (or a test) never downloads them.

6. How the pipeline works

  1. 1.Input & validation β€” text is stripped and checked for length (about 40–15,000 characters). The upper limit keeps the free CPU demo responsive; input is never silently truncated.
  2. 2.Sentence-aware chunking β€” text is split into sentences with a lightweight regex (no extra NLP model) and greedily packed into ~380-token chunks using the FinBERT tokenizer, leaving room for special tokens. A single oversized sentence is split safely on tokens and decoded back to text. Order is preserved and each chunk records its token count.
  3. 3.Sentiment β€” FinBERT scores every chunk; positive/negative/neutral are combined with token-count weights. The signed score is positive βˆ’ negative.
  4. 4.Themes β€” the zero-shot model scores every chunk against the theme vocabulary; strengths are token-weighted across chunks and the top themes are displayed. Zero-shot values are reported as model confidence / theme strength, not calibrated probabilities.
  5. 5.Heuristics β€” risk score, outlook, impacts, evidence, and the executive summary are computed with deterministic, documented Python.

7. Explainable risk-score formula

risk_score = 100 Γ— ( 0.45 Β· negative_probability
                   + 0.45 Β· risk_theme_strength
                   + 0.10 Β· caution_score )
  • β€”negative_probability β€” token-weighted FinBERT negative probability.
  • β€”risk_theme_strength β€” average of up to the top three aggregated risk-oriented theme scores (0 if none detected).
  • β€”caution_score β€” share of a transparent caution-word list present in the text, counted by distinct terms so repeated words cannot exceed 1.0.

The result is rounded and clamped to 0–100:

RangeLevel
0–34Low
35–64Moderate
65–100High

This is a transparent, project-specific heuristic decision-support score β€” not a prediction of stock performance or financial distress.

8. Local installation and run

bash
# 1) Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate            # Windows: .venv\Scripts\activate

# 2) Install runtime dependencies
pip install -r requirements.txt

# 3) (optional) install dev dependencies for tests
pip install -r requirements-dev.txt

# 4) Launch the app locally
python app.py                        # serves at http://127.0.0.1:7860

The first analysis downloads the two models (a few hundred MB) and can take a little longer; subsequent runs use the local cache. Public sharing is disabled by default.

9. Testing

bash
python -m pytest -q
python -m compileall app.py src tests

Tests run offline β€” they use fake model callables and a whitespace tokenizer, so no network access or model download is required.

10. Example inputs and outputs

Input (negative operational passage):

"Freight costs remained elevated during the quarter, and component shortages continued to affect production. We expect inventory levels to remain above historical averages through the end of the year…"

Illustrative output:

  • β€”Sentiment: Strongly negative (signed score β‰ˆ βˆ’0.93)
  • β€”Top themes: freight and logistics costs Β· labor and workforce costs Β· production capacity constraints
  • β€”Operational risk: ~61 / 100 (Moderate)
  • β€”Outlook: Cautious
  • β€”Likely impacts: gross-margin pressure; operating-expense pressure
  • β€”Summary: "The model identifies an overall financial sentiment that is strongly negative… The estimated operational risk level is moderate… the passage suggests a cautious management outlook…"

More examples ship in `examples/sample_passages.txt` and are clickable in the UI.

11. Project structure

EarningsLens/
β”œβ”€β”€ app.py
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ requirements-dev.txt
β”œβ”€β”€ README.md
β”œβ”€β”€ LICENSE
β”œβ”€β”€ .gitignore
β”œβ”€β”€ conftest.py
β”œβ”€β”€ src/earnings_lens/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ config.py
β”‚   β”œβ”€β”€ models.py
β”‚   β”œβ”€β”€ chunking.py
β”‚   β”œβ”€β”€ analyzer.py
β”‚   β”œβ”€β”€ scoring.py
β”‚   β”œβ”€β”€ formatting.py
β”‚   └── schemas.py
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ test_chunking.py
β”‚   β”œβ”€β”€ test_scoring.py
β”‚   β”œβ”€β”€ test_analyzer.py
β”‚   └── test_formatting.py
└── examples/
    └── sample_passages.txt

12. Limitations

  • β€”Pretrained models are used as-is (no fine-tuning yet); they can misread sarcasm, hedging, or unusual phrasing.
  • β€”Zero-shot "confidence" is a relative strength, not a calibrated probability.
  • β€”The operational-risk score is a heuristic for study and discussion β€” it does not predict stock returns or financial distress.
  • β€”The analysis reflects only the pasted text; it has no access to filings, guidance history, or market data.
  • β€”English-language earnings commentary works best.

13. Ethical and financial disclaimer

EarningsLens is an educational decision-support tool, not an investment-recommendation system. It does not provide personalized financial advice and does not predict stock performance. Always verify findings against primary sources and consult a licensed professional for investment decisions.

14. Potential future improvements

  • β€”Fine-tuned, calibrated theme and sentiment models on labeled earnings data.
  • β€”Confidence calibration and uncertainty display.
  • β€”Speaker/segment attribution (prepared remarks vs. Q&A).
  • β€”Multi-passage and full-transcript comparison over time.
  • β€”Exportable reports and optional retrieval over prior calls.

15. Model attribution and licensing

  • β€”FinBERT β€” Β© ProsusAI, distributed on the Hugging Face Hub under its own terms.
  • β€”cross-encoder/nli-deberta-v3-small β€” Β© its authors, under its own terms.

The MIT license in `LICENSE` covers the original EarningsLens application code only. It does not extend to third-party model weights, which are governed by their respective licenses. Verify each model's license and usage terms before any commercial use.


A note on the MVP

This MVP deliberately uses pretrained models rather than a newly trained model: FinBERT analyzes financial sentiment, and the zero-shot model identifies a configurable set of business themes. Model confidence scores are not guaranteed to be calibrated probabilities, and the risk score is a project-specific heuristic. The project does not predict stock returns.