A 10-Q is 40 pages long and only a few sentences in it matter. This turns one into a single page, with a sentiment score, a one-line headline and what management actually said, in under 30 seconds.
Apple's 10-Q reads confidently, but market risk exposure is the caveat.
Sentiment climbed from +0.20 in Feb 2026 to +0.78 today, across 4 filings. Apple reported Q3 2026 net sales of $109.4 billion, up 16% year over year.
01 - The problem
Retail investors skim the filing, miss the change in tone, or go by the headlines. Analysts pay thousands a month for Bloomberg terminals that pre-digest it for them. I wanted to see how close a weekend project could get.
The question: can a language model pull out what a first-year analyst would, like beats, misses, guidance changes, new risks and shifts in tone, for a fraction of a cent per ticker and fast enough to feel like a search?
02 - How it works
Everything runs on the server. The page streams progress while the pipeline works, then shows the brief when it's done. Every step is cached, so running the same ticker twice is instant and free.
One submission. A cached ticker comes back from Turso in milliseconds. A fresh one goes through SEC EDGAR, an earnings call transcript if there is one, and Groq's gpt-oss-120b, then comes back as a brief.
The cache key is (content_hash, prompt_version, model). A second run of the same ticker is instant and uses no AI calls. When I change the prompt, I bump the version and old results expire on their own, with no migration.
03 - The redesign
Version one worked, but it showed its results as a grid of metric cards, gauges and line charts. It looked like every fintech tutorial, and nobody would forward it to a friend.
Version one
Metric cards, gauges and Chart.js line charts. Everything had equal weight, so nothing stood out.
Version two
Reads like a Bloomberg opinion column, with the data inside the sentences.
Type: Manrope for headlines, Cormorant Garamond italic for labels and numbers, Inter for body text. Colors: cobalt on warm cream, based on Bicentra Biotech's brand.
04 - How sentiment is calculated
The score isn't a count of positive and negative words, and it isn't tuned against stock returns. Groq's gpt-oss-120b reads the filing (up to about 18,000 characters) and returns a label and a score in one call, as JSON.
Two settings matter. response_format is set to json_object, so the model can't answer in prose. reasoning_effort is set to low, because this is extraction, not a math proof, and longer reasoning would cost more without a better read.
Only the latest filing goes through the model. The three older points on the sparkline come from how the stock moved after each one (section 07). Same −1 to 1 scale, no extra AI calls.
Scores are repeatable. The same filing text always returns the same number until I change the prompt and bump its version, say v3 to v4. Then every ticker gets re-scored.
No positive words minus negative words. VADER and FinBERT do that. This doesn't.
+0.78 doesn't mean the stock goes up 78%. It means the model read the writing as confidently positive.
A company that always sounds cautious might score −0.2 in a good quarter. The change over time matters more than the number.
If real money is on the line, read the 10-Q. The brief tells you which filings are worth reading. That's why the Signal section leads with the trend, not the score alone.
05 - Diff mode
A filing only means something next to the last one. Diff mode compares any two runs and shows what moved.
The change in score between two runs, and whether the label flipped.
A new theme like "AI acceleration" showing up three quarters in a row is a real signal.
When a company goes from missing estimates to beating them, the diff says so directly.
Questions analysts asked on this call that they didn't ask last quarter. Needs a transcript.
06 - Earnings call context
When AlphaVantage has the transcript, part of it goes into the prompt with the filing. The model can compare the polished filing with how executives actually talked, and with what analysts pushed back on.
That adds a management tone field, quotes with speaker names, and an analyst pushback section. With no transcript, that section just doesn't show up. No error, the brief runs on the filing alone.
07 - The three-minute timeout
The demo started dying at exactly three minutes, the app's own time limit. It was making four Groq calls in a row, one full analysis and three quick scores for the history chart, and on a slow day for Groq that took longer than three minutes.
The logs were silent while it happened, because Gunicorn holds Python's output until later. One setting, PYTHONUNBUFFERED=1, fixed that.
The history chart answers one question: how did each past filing land? The stock price already answers that. So the three older filings are scored by how the stock moved in the 30 trading days after each one.
The newest point stays the model's read, since a filing that just came out doesn't have 30 days of price history yet.
Render's free tier puts the app to sleep after 15 minutes with no traffic, and it takes about a minute to wake up. That's a bad first impression if a recruiter is the one clicking.
About $3 to $4 a month for one always-on machine, but there's no spending cap, so you have to watch the bill.
Plenty of hardware, but Docker apps now need a paid plan.
$7 a month, fixed, no cold starts. The right move once this is a real product.
cron-job.org hits the health check every 10 minutes, so the app never sleeps. Render's 750 free hours a month cover one app running nonstop, since even a 31-day month is 744 hours.
08 - The information gap
Insider trades come from SEC Form 4. When a CEO, CFO or 10% owner buys or sells their own stock, they have two business days to report it. Congressional trades come from the House Clerk. Under the 2012 STOCK Act, representatives have 45 days.
Both are delayed and self-reported. What's interesting isn't whether either group traded. It's whether they agree.
Four possible states. Agreement backs up the filing. Disagreement, especially executives selling while Congress buys, is worth reading closely. The two are never merged into one score, since that would be false precision. They sit side by side in the Evidence section, sorted by date, so you can see whose money moved first.
09 - Decisions
01
The app is small and mostly reads. Turso keeps the main copy in the cloud with a local copy on the server, so reads are fast and writes sync in the background. Postgres would have been heavier for no benefit.
02
Cached results are keyed by (content_hash, prompt_version, model). Change the version and old results stop matching, so new runs re-analyze automatically.
03
A run takes 8 to 25 seconds, long enough to need a progress bar. Server-Sent Events send one stream of updates and work with plain Gunicorn. WebSockets would have been overkill.
04
The Groq and AlphaVantage keys live in Render's settings and never reach the browser. The demo only allows five tickers, and anything else gets a polite error.
05
Most finance tools default to a grid of cards. This one is a single page you read. The signal isn't a card that says "Sentiment: +0.78." It's a sentence with the trend inside it.
06
Render's free tier plus Turso's free storage. A free ping every 10 minutes keeps the app awake, so the first click doesn't wait a minute.
Try it
The live demo runs on AAPL, NVDA, TSLA, MSFT and JPM. Clone the repo for anything else.