mirror of
https://github.com/shawnkim1997/All-in-one-Financial-Analysis.git
synced 2026-08-21 14:48:05 +00:00
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>
69 lines
1.8 KiB
Python
69 lines
1.8 KiB
Python
"""User settings persistence backed by SQLite.
|
|
|
|
Provides a simple key-value store for application settings such as API keys
|
|
and user preferences, using the ``settings`` table.
|
|
"""
|
|
|
|
from typing import Dict, Optional
|
|
|
|
import aiosqlite
|
|
|
|
from server.db.database import get_db
|
|
|
|
|
|
async def get_setting(key: str) -> Optional[str]:
|
|
"""Retrieve a single setting by key.
|
|
|
|
Args:
|
|
key: The setting key to look up.
|
|
|
|
Returns:
|
|
The setting value, or ``None`` if the key does not exist.
|
|
"""
|
|
db: aiosqlite.Connection = await get_db()
|
|
cursor = await db.execute(
|
|
"SELECT value FROM settings WHERE key = ?", (key,)
|
|
)
|
|
row = await cursor.fetchone()
|
|
return row[0] if row else None
|
|
|
|
|
|
async def set_setting(key: str, value: str) -> None:
|
|
"""Create or update a setting.
|
|
|
|
Uses ``INSERT OR REPLACE`` so the call is idempotent.
|
|
|
|
Args:
|
|
key: The setting key.
|
|
value: The setting value.
|
|
"""
|
|
db: aiosqlite.Connection = await get_db()
|
|
await db.execute(
|
|
"INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)",
|
|
(key, value),
|
|
)
|
|
await db.commit()
|
|
|
|
|
|
async def get_all_settings() -> Dict[str, str]:
|
|
"""Return every setting as a ``{key: value}`` dict.
|
|
|
|
Returns:
|
|
A dict mapping all stored keys to their values.
|
|
"""
|
|
db: aiosqlite.Connection = await get_db()
|
|
cursor = await db.execute("SELECT key, value FROM settings ORDER BY key")
|
|
rows = await cursor.fetchall()
|
|
return {row[0]: row[1] for row in rows}
|
|
|
|
|
|
async def delete_setting(key: str) -> None:
|
|
"""Remove a setting by key (no-op if the key does not exist).
|
|
|
|
Args:
|
|
key: The setting key to delete.
|
|
"""
|
|
db: aiosqlite.Connection = await get_db()
|
|
await db.execute("DELETE FROM settings WHERE key = ?", (key,))
|
|
await db.commit()
|