Files
All-in-one-Financial-Analysis/atlas-terminal/scripts/generate_readme.py
T
shawnkim1997andClaude Opus 4.6 b2acda81ee feat: add Atlas Terminal — Next.js 14 + FastAPI full-stack migration
Complete migration from Streamlit to Next.js 14 App Router + FastAPI backend.

Frontend (Next.js 14):
- 10 pages: Overview, Research, Valuation, Technical, Markets, Earnings, News, Portfolio, Filings, Settings
- Terminal Noir dark theme with custom Tailwind config
- TradingView Lightweight Charts for candlestick/volume
- Valuation: DCF, Sensitivity Matrix, Monte Carlo, Tornado, Reverse DCF
- Financial Statements table with YoY growth badges and margin rows
- SEC EDGAR inline filing viewer with section tabs
- News split-view with iframe article embedding
- Technical Analysis with RSI, MACD, Bollinger, Fibonacci, Moving Averages
- Earnings beat/miss visualization
- AI Copilot chat panel with Gemini integration

Backend (FastAPI):
- 13 routers: market_data, financials, valuation, technical, earnings, insider, edgar, news, portfolio, analysis, chat, estimates, fx
- Services: DCF engine, Monte Carlo simulation, sensitivity analysis, risk metrics, SEC parser, technical indicators
- yfinance + yahooquery data sources with fallback pattern
- SQLite caching layer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 02:10:10 +00:00

143 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Generate README.md for ATLAS Terminal from project metadata.
Scans the project structure and produces a fresh README with:
- Feature list derived from router files
- Tech stack from requirements.txt and package.json
- Changelog from recent git commits
Run manually or via the GitHub Actions workflow (.github/workflows/update-readme.yml).
"""
import json
import subprocess
import textwrap
from datetime import datetime
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _read_requirements() -> list[str]:
"""Return top-level package names from requirements.txt."""
req_path = PROJECT_ROOT / "requirements.txt"
if not req_path.exists():
return []
lines = req_path.read_text().splitlines()
packages = []
for line in lines:
line = line.strip()
if line and not line.startswith("#"):
name = line.split(">=")[0].split("==")[0].split("[")[0].strip()
packages.append(name)
return packages
def _read_package_json_deps() -> list[str]:
"""Return dependency names from apps/web/package.json."""
pkg_path = PROJECT_ROOT / "apps" / "web" / "package.json"
if not pkg_path.exists():
return []
try:
data = json.loads(pkg_path.read_text())
deps = list(data.get("dependencies", {}).keys())
deps += list(data.get("devDependencies", {}).keys())
return deps
except (json.JSONDecodeError, OSError):
return []
def _detect_routers() -> list[str]:
"""Return router module names from server/routers/."""
router_dir = PROJECT_ROOT / "server" / "routers"
if not router_dir.exists():
return []
return sorted(
f.stem
for f in router_dir.glob("*.py")
if f.stem != "__init__"
)
def _recent_commits(n: int = 10) -> list[str]:
"""Return the last *n* one-line commit messages."""
try:
result = subprocess.run(
["git", "log", f"-{n}", "--pretty=format:%s"],
capture_output=True, text=True, cwd=str(PROJECT_ROOT),
)
if result.returncode == 0:
return [line for line in result.stdout.splitlines() if line.strip()]
except FileNotFoundError:
pass
return []
# ---------------------------------------------------------------------------
# Template
# ---------------------------------------------------------------------------
def generate() -> str:
routers = _detect_routers()
py_deps = _read_requirements()
js_deps = _read_package_json_deps()
commits = _recent_commits(10)
feature_bullets = "\n".join(f"- **{r.replace('_', ' ').title()}**" for r in routers)
py_stack = ", ".join(py_deps[:8]) + (" ..." if len(py_deps) > 8 else "")
js_stack = ", ".join(js_deps[:8]) + (" ..." if len(js_deps) > 8 else "")
changelog = "\n".join(f"- {c}" for c in commits) if commits else "- (no commits yet)"
today = datetime.now().strftime("%Y-%m-%d")
readme = textwrap.dedent(f"""\
# ATLAS Terminal
> Personal Bloomberg-style financial terminal -- real-time market data,
> AI-powered analysis, DCF valuation, and portfolio management.
## Features
{feature_bullets}
## Tech Stack
**Backend (Python):** {py_stack}
**Frontend (Next.js):** {js_stack}
## Quick Start
```bash
# Backend
cd atlas-terminal
pip install -r requirements.txt
uvicorn server.main:app --reload --port 8000
# Frontend
cd apps/web
npm install && npm run dev
```
## Recent Changes
{changelog}
---
*Auto-generated on {today}*
""")
return readme
def main():
readme_path = PROJECT_ROOT / "README.md"
content = generate()
readme_path.write_text(content)
print(f"README.md written ({len(content)} bytes)")
if __name__ == "__main__":
main()