Open Source Framework for Explainable Time Series Analysis
Project description
WhyTrend
Open Source Framework for Explainable Time Series Analysis
WhyTrend detects anomalies, change points, and trend shifts in time series — then automatically explains why they happened using external context and LLMs.
If this project is useful to you, consider giving it a star on GitHub — it helps others discover the project. Forks and pull requests are welcome.
Features
- Fluent
PipelineAPI for source → detection → collection → ranking → explanation - Pluggable sources, detectors, collectors, rankers, and LLM providers
- Structured
Reportoutput (JSON and Markdown) - Async collectors and LLM calls
- Works offline with
MockLLMProviderand local models viaOllamaExplainer
Installation
git clone https://github.com/AlexProvatorov/WhyTrend.git
cd WhyTrend
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Optional extras
pip install -e ".[openai]" # OpenAI API
pip install -e ".[trends]" # Google Trends
pip install -e ".[prophet]" # Prophet detector
pip install -e ".[ranking]" # Embedding ranker
pip install -e ".[all]" # everything
Quickstart (CSV, no API keys)
from whytrend import (
BM25Ranker,
CSVSource,
LLMExplainer,
MockLLMProvider,
Pipeline,
ZScoreDetector,
)
pipeline = (
Pipeline(window_days=3)
.add_source(CSVSource("tests/fixtures/python_interest.csv", keyword="Python"))
.add_detector(ZScoreDetector(threshold=1.0))
.add_ranker(BM25Ranker(top_k=5))
.add_explainer(LLMExplainer(MockLLMProvider()))
)
report = pipeline.run()
print(report.executive_summary)
print(report.to_markdown())
Run the full demo:
pip install -e ".[dev]"
python examples/mvp_demo.py
Production-style example
from whytrend import (
GoogleTrends,
OpenAIExplainer,
Pipeline,
ProphetDetector,
)
from whytrend.collectors import (
GitHubReleasesCollector,
GoogleNewsCollector,
HackerNewsCollector,
RSSFeedCollector,
RedditCollector,
StackOverflowCollector,
WikipediaCollector,
)
from whytrend.rankers import BM25Ranker
pipeline = (
Pipeline()
.add_source(GoogleTrends("Python"))
.add_detector(ProphetDetector())
.add_collector(GoogleNewsCollector())
.add_collector(HackerNewsCollector())
.add_collector(RedditCollector()) # REDDIT_CLIENT_ID + REDDIT_CLIENT_SECRET
.add_collector(GitHubReleasesCollector()) # optional GITHUB_TOKEN
.add_collector(StackOverflowCollector()) # optional STACKEXCHANGE_KEY
.add_collector(
RSSFeedCollector(
[
"https://blog.python.org/feeds/posts/default",
"https://pyfound.blogspot.com/feeds/posts/default",
]
)
)
.add_collector(WikipediaCollector())
.add_ranker(BM25Ranker())
.add_explainer(OpenAIExplainer()) # OPENAI_API_KEY env var or api_key="..."
)
report = pipeline.run()
print(report.executive_summary)
Use OllamaExplainer(model="llama3.2") for a local LLM instead of OpenAI.
Reddit credentials (create at https://www.reddit.com/prefs/apps):
export REDDIT_CLIENT_ID="..."
export REDDIT_CLIENT_SECRET="..."
Or pass them explicitly:
RedditCollector(client_id="...", client_secret="...", subreddits=["Python", "MachineLearning"])
GitHub Releases works without a token for light use. For higher rate limits:
export GITHUB_TOKEN="ghp_..."
GitHubReleasesCollector(token="ghp_...", repos=["python/cpython"])
Stack Overflow works without a key for light use. For a higher daily quota (register at https://stackapps.com/):
export STACKEXCHANGE_KEY="..."
StackOverflowCollector(api_key="...", site="stackoverflow")
Custom RSS/Atom feeds (keyword + time-window filtered):
RSSFeedCollector(
[
"https://blog.python.org/feeds/posts/default",
"https://hnrss.org/frontpage",
]
)
Architecture
Source → Detector → Event Builder → Collectors → Ranker → Explainer → Report
Roadmap
Core MVP is in place. Next focus: integrations and ecosystem.
v0.2 — More collectors
- Google News
- GitHub Releases
- RSS / Stack Overflow
v0.3 — More detectors
- Ruptures (change-point)
- River / streaming detectors
v0.4 — More LLM providers
- Anthropic, Gemini, DeepSeek
- Azure OpenAI, OpenRouter
v0.5 — Reports and DX
- HTML / PDF reports
- CLI (
whytrend analyze ...) - Plugin registry (entry points)
Track progress in GitHub Issues.
Development
make install # install with detected tool (uv / poetry / pip)
make check # ruff + format check + mypy + pytest
Supports the three common workflows:
| Tool | Install | Run checks |
|---|---|---|
| uv (default if installed) | make install |
make check |
| poetry | make install TOOL=poetry |
make check TOOL=poetry |
| pip / venv | make install TOOL=pip |
make check TOOL=pip |
Auto-detect order: uv → poetry → pip. Override anytime with TOOL=....
Useful targets:
make lint # ruff check
make format # ruff format + autofix
make format-check # ruff format --check
make typecheck # mypy
make test # pytest
make help # list all targets
Author
Alexander Provatorov — GitHub @AlexProvatorov
License
Licensed under the Apache License, Version 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file whytrend-0.2.0.tar.gz.
File metadata
- Download URL: whytrend-0.2.0.tar.gz
- Upload date:
- Size: 43.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
723bbcb502b4cf5412a851e4b0f63a92e4010a2eb3f3044cdea1f7771534dcf1
|
|
| MD5 |
e3d82603a62b3e10d2de626ba3b7e785
|
|
| BLAKE2b-256 |
30620d5dbe69e0c70cb67d68799c8cf4a32ddc4ffb1f66fbe31742bc9df013c7
|
Provenance
The following attestation bundles were made for whytrend-0.2.0.tar.gz:
Publisher:
publish.yml on AlexProvatorov/WhyTrend
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whytrend-0.2.0.tar.gz -
Subject digest:
723bbcb502b4cf5412a851e4b0f63a92e4010a2eb3f3044cdea1f7771534dcf1 - Sigstore transparency entry: 2218362529
- Sigstore integration time:
-
Permalink:
AlexProvatorov/WhyTrend@01cb1c8451421884bad1a3fefc59ba3b1872dad7 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/AlexProvatorov
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@01cb1c8451421884bad1a3fefc59ba3b1872dad7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file whytrend-0.2.0-py3-none-any.whl.
File metadata
- Download URL: whytrend-0.2.0-py3-none-any.whl
- Upload date:
- Size: 53.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e961065cfbfa75bb866a947c21bd00f998599fdf38b64a3dc60f906313aafe0b
|
|
| MD5 |
0c737e053d920b0bb466cde9e798ddd2
|
|
| BLAKE2b-256 |
26c8fc94b253390540cfea7c838c6d09fe424529f1716d2837652d2984a3a361
|
Provenance
The following attestation bundles were made for whytrend-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on AlexProvatorov/WhyTrend
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whytrend-0.2.0-py3-none-any.whl -
Subject digest:
e961065cfbfa75bb866a947c21bd00f998599fdf38b64a3dc60f906313aafe0b - Sigstore transparency entry: 2218362762
- Sigstore integration time:
-
Permalink:
AlexProvatorov/WhyTrend@01cb1c8451421884bad1a3fefc59ba3b1872dad7 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/AlexProvatorov
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@01cb1c8451421884bad1a3fefc59ba3b1872dad7 -
Trigger Event:
release
-
Statement type: