SPB Git

Repository Public MIT

Commit

Initial public release — VibeQuant v2.1.0

AI-powered financial intelligence platform: Claude AI agent (213 tools),
265+ FMP financial data endpoints, quantitative Python engine (Monte Carlo,
GARCH, VaR, Black-Scholes, portfolio optimization), multi-source web
research, SSE streaming chat, PDF/slides export, Electron desktop app.

Live demo: https://www.vquant.ai

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed · Aug 5, 2026
129 changed files +20,001 −0 Browse files
129 changed files
added .editorconfig +29 −0
@@ -0,0 +1,29 @@
1 +# =============================================================================
2 +# VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
3 +# -----------------------------------------------------------------------------
4 +# File: .editorconfig
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Website: https://www.spboucher.ai
9 +# Demo: https://www.vquant.ai
10 +# License: MIT (see LICENSE)
11 +#
12 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
13 +# =============================================================================
14 +
15 +root = true
16 +
17 +[*]
18 +indent_style = space
19 +indent_size = 2
20 +end_of_line = lf
21 +charset = utf-8
22 +trim_trailing_whitespace = true
23 +insert_final_newline = true
24 +
25 +[*.md]
26 +trim_trailing_whitespace = false
27 +
28 +[*.py]
29 +indent_size = 4
added .env.example +35 −0
@@ -0,0 +1,35 @@
1 +# =============================================================================
2 +# VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
3 +# -----------------------------------------------------------------------------
4 +# File: .env.example
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Website: https://www.spboucher.ai
9 +# Demo: https://www.vquant.ai
10 +# License: MIT (see LICENSE)
11 +#
12 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
13 +# =============================================================================
14 +
15 +# ─── Required ──────────────────────────────────────────
16 +ANTHROPIC_API_KEY=sk-ant-api03-your-key-here
17 +FMP_API_KEY=your-fmp-key-here
18 +
19 +# ─── Recommended ───────────────────────────────────────
20 +FIRECRAWL_API_KEY=fc-your-key-here
21 +TAVILY_API_KEY=tvly-your-key-here
22 +
23 +# ─── Optional ──────────────────────────────────────────
24 +EXA_API_KEY=your-exa-key-here
25 +SERPAPI_API_KEY=your-serpapi-key-here
26 +ELEVENLABS_API_KEY=your-elevenlabs-key-here
27 +
28 +# ─── Server Config ─────────────────────────────────────
29 +DATABASE_URL=sqlite://local.db
30 +SESSION_SECRET=generate-a-strong-random-secret-here
31 +PORT=5000
32 +NODE_ENV=development
33 +
34 +# ─── Python (optional, auto-detected) ─────────────────
35 +# PYTHON_PATH=/path/to/.venv/bin/python
added .github/workflows/ci.yml +59 −0
@@ -0,0 +1,59 @@
1 +# =============================================================================
2 +# VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
3 +# -----------------------------------------------------------------------------
4 +# File: .github/workflows/ci.yml
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Website: https://www.spboucher.ai
9 +# Demo: https://www.vquant.ai
10 +# License: MIT (see LICENSE)
11 +#
12 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
13 +# =============================================================================
14 +
15 +name: CI
16 +
17 +on:
18 + push:
19 + branches: [main]
20 + pull_request:
21 + branches: [main]
22 +
23 +jobs:
24 + ci:
25 + name: Lint, Typecheck, Test & Build
26 + runs-on: ubuntu-latest
27 +
28 + strategy:
29 + matrix:
30 + node-version: [20, 22]
31 +
32 + steps:
33 + - name: Checkout
34 + uses: actions/checkout@v4
35 +
36 + - name: Setup Node.js ${{ matrix.node-version }}
37 + uses: actions/setup-node@v4
38 + with:
39 + node-version: ${{ matrix.node-version }}
40 + cache: npm
41 +
42 + - name: Install dependencies
43 + run: npm ci --legacy-peer-deps
44 +
45 + - name: Lint
46 + run: npm run lint
47 + continue-on-error: true # 572 pre-existing warnings, fixing incrementally
48 +
49 + - name: Typecheck
50 + run: npm run typecheck
51 + continue-on-error: true # 15 pre-existing errors, fixing incrementally
52 +
53 + - name: Test
54 + run: npm test
55 +
56 + - name: Build
57 + run: npm run build
58 + env:
59 + NODE_ENV: production
added .gitignore +64 −0
@@ -0,0 +1,64 @@
1 +# =============================================================================
2 +# VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
3 +# -----------------------------------------------------------------------------
4 +# File: .gitignore
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Website: https://www.spboucher.ai
9 +# Demo: https://www.vquant.ai
10 +# License: MIT (see LICENSE)
11 +#
12 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
13 +# =============================================================================
14 +
15 +# Dependencies
16 +node_modules/
17 +.venv/
18 +
19 +# Build output
20 +dist/
21 +
22 +# Environment variables
23 +.env
24 +.env.local
25 +.env.*.local
26 +
27 +# Database
28 +local.db
29 +local.db-shm
30 +local.db-wal
31 +
32 +# Logs
33 +logs/
34 +
35 +# Temp & caches
36 +temp/
37 +__pycache__/
38 +*.pyc
39 +
40 +# Backups
41 +backups/
42 +
43 +# Generated images
44 +/*.png
45 +public/plots/
46 +public/figures/
47 +
48 +# OS files
49 +.DS_Store
50 +Thumbs.db
51 +
52 +# IDE
53 +.vscode/
54 +.idea/
55 +*.swp
56 +*.swo
57 +*~
58 +
59 +# Lock files (keep package-lock.json, ignore uv.lock)
60 +uv.lock
61 +
62 +# Misc artifacts
63 +downloads/
64 +attached_assets/
added .prettierignore +20 −0
@@ -0,0 +1,20 @@
1 +# =============================================================================
2 +# VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
3 +# -----------------------------------------------------------------------------
4 +# File: .prettierignore
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Website: https://www.spboucher.ai
9 +# Demo: https://www.vquant.ai
10 +# License: MIT (see LICENSE)
11 +#
12 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
13 +# =============================================================================
14 +
15 +node_modules/
16 +dist/
17 +.venv/
18 +package-lock.json
19 +*.py
20 +*.md
added .prettierrc +9 −0
@@ -0,0 +1,9 @@
1 +{
2 + "semi": true,
3 + "singleQuote": false,
4 + "trailingComma": "all",
5 + "printWidth": 100,
6 + "tabWidth": 2,
7 + "arrowParens": "always",
8 + "endOfLine": "lf"
9 +}
added LICENSE +21 −0
@@ -0,0 +1,21 @@
1 +MIT License
2 +
3 +Copyright (c) 2026 Simon-Pierre Boucher
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
added README.md +689 −0
@@ -0,0 +1,689 @@
1 +<!--
2 + =============================================================================
3 + VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + -----------------------------------------------------------------------------
5 + File: README.md
6 +
7 + Author: Simon-Pierre Boucher
8 + Contact: contact@spboucher.ai
9 + Website: https://www.spboucher.ai
10 + Demo: https://www.vquant.ai
11 + License: MIT (see LICENSE)
12 +
13 + Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + =============================================================================
15 +-->
16 +
17 +<div align="center">
18 +
19 +# VibeQuant
20 +
21 +### AI-Powered Institutional-Grade Financial Intelligence Platform
22 +
23 +<br/>
24 +
25 +**🌐 Live Demo: [www.vquant.ai](https://www.vquant.ai)**
26 +
27 +[![Live](https://img.shields.io/badge/Live_Demo-www.vquant.ai-00c853?style=for-the-badge&logo=googlechrome&logoColor=white)](https://www.vquant.ai)
28 +[![License](https://img.shields.io/badge/License-MIT-22c55e?style=for-the-badge)](./LICENSE)
29 +[![Version](https://img.shields.io/badge/Version-2.1.0-7c3aed?style=for-the-badge)](./)
30 +
31 +<br/>
32 +
33 +**Stack**
34 +
35 +[![TypeScript](https://img.shields.io/badge/TypeScript-5.6-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
36 +[![React](https://img.shields.io/badge/React-18.3-61dafb?style=flat-square&logo=react&logoColor=black)](https://react.dev/)
37 +[![Vite](https://img.shields.io/badge/Vite-5-646cff?style=flat-square&logo=vite&logoColor=white)](https://vitejs.dev/)
38 +[![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white)](https://expressjs.com/)
39 +[![Node.js](https://img.shields.io/badge/Node.js-18+-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/)
40 +[![TailwindCSS](https://img.shields.io/badge/Tailwind_CSS-3.4-06b6d4?style=flat-square&logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
41 +
42 +**AI & Data**
43 +
44 +[![Claude AI](https://img.shields.io/badge/Claude-Fable_5_(1M_ctx)-d97706?style=flat-square&logo=anthropic&logoColor=white)](https://anthropic.com/)
45 +[![Python](https://img.shields.io/badge/Python-3.11+-3776ab?style=flat-square&logo=python&logoColor=white)](https://python.org/)
46 +[![NumPy](https://img.shields.io/badge/NumPy-013243?style=flat-square&logo=numpy&logoColor=white)](https://numpy.org/)
47 +[![Pandas](https://img.shields.io/badge/Pandas-150458?style=flat-square&logo=pandas&logoColor=white)](https://pandas.pydata.org/)
48 +[![SciPy](https://img.shields.io/badge/SciPy-8caae6?style=flat-square&logo=scipy&logoColor=white)](https://scipy.org/)
49 +[![scikit--learn](https://img.shields.io/badge/scikit--learn-f7931e?style=flat-square&logo=scikitlearn&logoColor=white)](https://scikit-learn.org/)
50 +
51 +**Database & ORM**
52 +
53 +[![SQLite](https://img.shields.io/badge/SQLite-003b57?style=flat-square&logo=sqlite&logoColor=white)](https://sqlite.org/)
54 +[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169e1?style=flat-square&logo=postgresql&logoColor=white)](https://postgresql.org/)
55 +[![Drizzle](https://img.shields.io/badge/Drizzle_ORM-c5f74f?style=flat-square&logo=drizzle&logoColor=black)](https://orm.drizzle.team/)
56 +[![Zod](https://img.shields.io/badge/Zod-3e67b1?style=flat-square&logo=zod&logoColor=white)](https://zod.dev/)
57 +
58 +**Quality & Testing**
59 +
60 +[![ESLint](https://img.shields.io/badge/ESLint-4b32c3?style=flat-square&logo=eslint&logoColor=white)](https://eslint.org/)
61 +[![Prettier](https://img.shields.io/badge/Prettier-f7b93e?style=flat-square&logo=prettier&logoColor=black)](https://prettier.io/)
62 +[![Vitest](https://img.shields.io/badge/Vitest-6e9f18?style=flat-square&logo=vitest&logoColor=white)](https://vitest.dev/)
63 +[![Testing Library](https://img.shields.io/badge/Testing_Library-e33332?style=flat-square&logo=testinglibrary&logoColor=white)](https://testing-library.com/)
64 +
65 +**Metrics**
66 +
67 +[![Lines of Code](https://img.shields.io/badge/Lines_of_Code-36,000+-0969da?style=flat-square)](./)
68 +[![Source Files](https://img.shields.io/badge/Source_Files-150+-0969da?style=flat-square)](./)
69 +[![API Endpoints](https://img.shields.io/badge/API_Endpoints-265+-8b5cf6?style=flat-square)](./)
70 +[![Claude Tools](https://img.shields.io/badge/Claude_Tools-213-d97706?style=flat-square)](./)
71 +[![Python Libs](https://img.shields.io/badge/Python_Libs-17-3776ab?style=flat-square)](./)
72 +[![Tests](https://img.shields.io/badge/Tests-41_passing-22c55e?style=flat-square)](./)
73 +[![Test Suites](https://img.shields.io/badge/Test_Suites-6-22c55e?style=flat-square)](./)
74 +[![Components](https://img.shields.io/badge/React_Components-57-61dafb?style=flat-square)](./)
75 +[![Hooks](https://img.shields.io/badge/Custom_Hooks-5-61dafb?style=flat-square)](./)
76 +[![Route Modules](https://img.shields.io/badge/Route_Modules-6-000000?style=flat-square)](./)
77 +
78 +---
79 +
80 +[**Getting Started**](#-getting-started) &nbsp;&bull;&nbsp; [**Features**](#-features) &nbsp;&bull;&nbsp; [**Architecture**](#-architecture) &nbsp;&bull;&nbsp; [**API Reference**](#-api-reference) &nbsp;&bull;&nbsp; [**Contributing**](#-contributing)
81 +
82 +</div>
83 +
84 +---
85 +
86 +## Overview
87 +
88 +VibeQuant is a production-grade full-stack financial analysis platform that combines **Claude AI (Fable 5 default, 6 selectable models, up to 1M token context)** with **265+ financial data endpoints**, **quantitative Python analysis** (Monte Carlo, GARCH, VaR, Black-Scholes, portfolio optimization), and **multi-source web research** (Tavily, Firecrawl, Exa, SerpAPI) to deliver institutional-grade insights through a real-time streaming conversational interface.
89 +
90 +Built with a modern TypeScript stack (React 18 + Vite + Express + Drizzle ORM), validated with Zod schemas, tested with Vitest, and linted with ESLint + Prettier.
91 +
92 +---
93 +
94 +## Features
95 +
96 +### Financial Data Engine
97 +
98 +[![FMP API](https://img.shields.io/badge/FMP_API-230_endpoints-8b5cf6?style=flat-square)](https://financialmodelingprep.com/)
99 +
100 +| Category | Endpoints | Details |
101 +|----------|-----------|---------|
102 +| **Company Fundamentals** | 40+ | Profiles, income statements, balance sheets, cash flows, key metrics, financial ratios, growth rates |
103 +| **Market Data** | 30+ | Real-time quotes, historical prices, intraday data, batch quotes, market hours, gainers/losers/actives |
104 +| **Technical Analysis** | 15+ | RSI, MACD, EMA, SMA, ADX, Williams %R, CCI, Stochastic, WMA, DEMA, TEMA, Bollinger Bands |
105 +| **Analyst & Ratings** | 20+ | Estimates, price targets, upgrades/downgrades, consensus, historical grades, ratings snapshots |
106 +| **Insider & Institutional** | 15+ | Insider trading, institutional holders, 13F filings, Senate/House trading, beneficial ownership |
107 +| **Economic & Macro** | 15+ | Economic calendar, Treasury rates, economic indicators, market risk premium, COT reports |
108 +| **SEC & Compliance** | 25+ | SEC filings (8-K, 10-K, 10-Q), EDGAR search, company notes, earnings transcripts |
109 +| **Alternative Data** | 20+ | ESG scores, social sentiment, Congressional trading, crowdfunding, equity offerings |
110 +| **ETFs & Indices** | 15+ | ETF holdings, sector weightings, S&P 500/NASDAQ/Dow Jones constituents |
111 +| **Valuation** | 10+ | DCF, levered DCF, custom DCF, enterprise values, owner earnings, financial scores |
112 +| **Forex & Crypto** | 15+ | Forex pairs, crypto quotes, commodity prices, historical forex data |
113 +| **Events** | 10+ | Earnings calendar, IPO calendar, dividend history, stock splits, mergers & acquisitions |
114 +
115 +### Quantitative Analysis Engine
116 +
117 +[![Python](https://img.shields.io/badge/Python-17_scientific_libraries-3776ab?style=flat-square&logo=python&logoColor=white)](https://python.org/)
118 +
119 +| Model | Description | Libraries |
120 +|-------|-------------|-----------|
121 +| **Monte Carlo Simulation** | Price path simulation with customizable parameters (10k+ paths, configurable horizon) | `numpy`, `scipy` |
122 +| **Options Pricing** | Black-Scholes model with full Greeks (delta, gamma, theta, vega, rho) | `scipy.stats` |
123 +| **GARCH Volatility** | Volatility modeling and forecasting with GARCH(1,1) | `arch`, `statsmodels` |
124 +| **Value at Risk (VaR)** | Historical, parametric, and Monte Carlo VaR at multiple confidence levels | `numpy`, `scipy` |
125 +| **Portfolio Optimization** | Mean-variance optimization (Modern Portfolio Theory), efficient frontier | `cvxpy`, `scipy.optimize` |
126 +| **Risk Metrics** | Sharpe, Sortino, Calmar, max drawdown, beta, alpha, information ratio | `numpy`, `pandas` |
127 +| **Custom Python** | Arbitrary Python code execution with access to 17 libraries and FMP data | All libraries |
128 +
129 +<details>
130 +<summary><b>Full Python library list (17 packages)</b></summary>
131 +
132 +| Library | Version | Purpose |
133 +|---------|---------|---------|
134 +| `numpy` | latest | Numerical computing |
135 +| `pandas` | latest | Data manipulation |
136 +| `scipy` | latest | Scientific computing |
137 +| `scikit-learn` | latest | Machine learning |
138 +| `statsmodels` | latest | Statistical models |
139 +| `matplotlib` | latest | Plotting & charts |
140 +| `seaborn` | latest | Statistical visualization |
141 +| `plotly` | latest | Interactive charts |
142 +| `arch` | latest | GARCH models |
143 +| `cvxpy` | latest | Convex optimization |
144 +| `yfinance` | latest | Market data |
145 +| `ta` | latest | Technical analysis |
146 +| `quantstats` | latest | Portfolio analytics |
147 +| `beautifulsoup4` | latest | Web scraping |
148 +| `requests` | latest | HTTP client |
149 +| `lxml` | latest | XML/HTML parsing |
150 +| `Pillow` | latest | Image processing |
151 +
152 +</details>
153 +
154 +### Web Research Engine
155 +
156 +| Source | Capabilities | Badge |
157 +|--------|-------------|-------|
158 +| **Tavily** | AI-powered search with generated answers, time filters, domain filtering | [![Tavily](https://img.shields.io/badge/Tavily-AI_Search-4f46e5?style=flat-square)](https://tavily.com/) |
159 +| **Firecrawl** | Web scraping, PDF extraction (up to 750 pages), intelligent crawling, structured extraction, autonomous agents | [![Firecrawl](https://img.shields.io/badge/Firecrawl-Web_Extraction-f97316?style=flat-square)](https://firecrawl.dev/) |
160 +| **Exa** | Semantic neural search, content retrieval, similar page discovery | [![Exa](https://img.shields.io/badge/Exa-Semantic_Search-6366f1?style=flat-square)](https://exa.ai/) |
161 +| **SerpAPI** | Google Search, Images, Shopping, Finance, Trends, Scholar, Videos, Flights, Hotels | [![SerpAPI](https://img.shields.io/badge/SerpAPI-Google_Search-34a853?style=flat-square)](https://serpapi.com/) |
162 +
163 +### AI Agent
164 +
165 +[![Claude](https://img.shields.io/badge/Claude_Fable_5-6_models-d97706?style=flat-square&logo=anthropic&logoColor=white)](https://anthropic.com/)
166 +
167 +| Feature | Details |
168 +|---------|---------|
169 +| **Models** | 6 selectable Claude models — **Fable 5** (default), **Opus 4.8 / 4.7 / 4.6**, **Sonnet 4.6**, **Haiku 4.5** — up to 1M token context |
170 +| **Model Selector** | Switchable from the input bar and the welcome screen (per-model icons); selection persisted in `localStorage` |
171 +| **Reasoning** | Adaptive extended thinking shown in a collapsible "Raisonnement" widget that auto-expands while the model thinks (Fable 5 / Opus / Sonnet; Haiku has no adaptive thinking) |
172 +| **Tools** | 213 specialized financial tools |
173 +| **Batching** | Intelligent tool batching (5 tools per batch with 500ms pauses) |
174 +| **Streaming** | Real-time Server-Sent Events (SSE) for instant response display |
175 +| **History** | Persistent conversation sessions with token tracking |
176 +| **Vision** | Image analysis support (charts, screenshots, documents) |
177 +| **Cost Tracking** | Per-session input/output token counting and cost estimation |
178 +
179 +### Interface & Design
180 +
181 +| Aspect | Details |
182 +|--------|---------|
183 +| **Theme** | Modern light/dark themes with an indigo-violet accent; toggle persisted in `localStorage` |
184 +| **Design** | Rounded soft-cornered components, subtle background gradient, thin rounded scrollbars |
185 +| **Welcome screen** | Categorized example prompts + dedicated model selector with per-model icons |
186 +| **Stack** | Tailwind CSS 3.4 + Radix UI primitives |
187 +
188 +### Export & Reports
189 +
190 +| Format | Description | Badge |
191 +|--------|-------------|-------|
192 +| **PDF** | Professional reports generated with Puppeteer, markdown rendering | [![PDF](https://img.shields.io/badge/PDF-Puppeteer-ea4335?style=flat-square&logo=googlechrome&logoColor=white)](./) |
193 +| **DOCX** | Word documents via Pandoc conversion | [![DOCX](https://img.shields.io/badge/DOCX-Pandoc-2b579a?style=flat-square&logo=microsoftword&logoColor=white)](./) |
194 +| **LaTeX Slides** | Beamer presentations with professional theming | [![LaTeX](https://img.shields.io/badge/LaTeX-Beamer_Slides-008080?style=flat-square&logo=latex&logoColor=white)](./) |
195 +| **Data Files** | CSV, XLSX, JSON, TXT downloads of analysis data | [![Data](https://img.shields.io/badge/Data-CSV_XLSX_JSON-217346?style=flat-square&logo=microsoftexcel&logoColor=white)](./) |
196 +| **Share Links** | Shareable report URLs with unique IDs | [![Share](https://img.shields.io/badge/Share-Unique_Links-0ea5e9?style=flat-square)](./) |
197 +
198 +---
199 +
200 +## Getting Started
201 +
202 +### Prerequisites
203 +
204 +[![Node.js](https://img.shields.io/badge/Node.js-18+-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/)
205 +[![Python](https://img.shields.io/badge/Python-3.11+-3776ab?style=flat-square&logo=python&logoColor=white)](https://python.org/)
206 +[![npm](https://img.shields.io/badge/npm-9+-cb3837?style=flat-square&logo=npm&logoColor=white)](https://npmjs.com/)
207 +
208 +### Installation
209 +
210 +```bash
211 +# Clone the repository
212 +git clone https://github.com/spboucher-ai/vquant.git
213 +cd vquant
214 +
215 +# Install Node.js dependencies
216 +npm install
217 +
218 +# Set up Python virtual environment
219 +python3 -m venv .venv
220 +source .venv/bin/activate # macOS/Linux
221 +# .venv\Scripts\activate # Windows
222 +pip install -r requirements-safe.txt
223 +
224 +# Configure environment variables
225 +cp .env.example .env
226 +# Edit .env with your API keys
227 +
228 +# Start development server
229 +npm run dev
230 +```
231 +
232 +The app will be available at `http://localhost:5000`.
233 +
234 +### API Keys
235 +
236 +All services offer generous free tiers:
237 +
238 +| Service | Sign Up | Free Tier | Required |
239 +|---------|---------|-----------|----------|
240 +| [![Anthropic](https://img.shields.io/badge/Anthropic-d97706?style=flat-square&logo=anthropic&logoColor=white)](https://console.anthropic.com) | [console.anthropic.com](https://console.anthropic.com) | $5 credit | **Yes** |
241 +| [![FMP](https://img.shields.io/badge/FMP-0969da?style=flat-square)](https://financialmodelingprep.com) | [financialmodelingprep.com](https://financialmodelingprep.com) | 250 calls/day | **Yes** |
242 +| [![Firecrawl](https://img.shields.io/badge/Firecrawl-f97316?style=flat-square)](https://firecrawl.dev) | [firecrawl.dev](https://firecrawl.dev) | 500 credits | Recommended |
243 +| [![Tavily](https://img.shields.io/badge/Tavily-4f46e5?style=flat-square)](https://app.tavily.com) | [app.tavily.com](https://app.tavily.com) | 1000 calls/month | Recommended |
244 +| [![Exa](https://img.shields.io/badge/Exa-6366f1?style=flat-square)](https://exa.ai) | [exa.ai](https://exa.ai) | 1000 searches/month | Optional |
245 +| [![SerpAPI](https://img.shields.io/badge/SerpAPI-34a853?style=flat-square)](https://serpapi.com) | [serpapi.com](https://serpapi.com) | 100 searches/month | Optional |
246 +
247 +---
248 +
249 +## Scripts
250 +
251 +| Command | Description |
252 +|---------|-------------|
253 +| `npm run dev` | Start development server (Vite HMR + Express) |
254 +| `npm run build` | Build for production (client + server) |
255 +| `npm start` | Start production server |
256 +| `npm run typecheck` | TypeScript type checking (`tsc --noEmit`) |
257 +| `npm run lint` | ESLint check |
258 +| `npm run lint:fix` | ESLint auto-fix |
259 +| `npm run format` | Prettier format all files |
260 +| `npm run format:check` | Prettier check (CI-friendly) |
261 +| `npm test` | Run all tests (Vitest) |
262 +| `npm run test:watch` | Run tests in watch mode |
263 +| `npm run test:coverage` | Run tests with coverage report |
264 +| `npm run db:push` | Push database schema changes (Drizzle Kit) |
265 +
266 +---
267 +
268 +## Architecture
269 +
270 +```
271 +vquant/
272 +├── client/src/ # Frontend (React + TypeScript)
273 +│ ├── App.tsx # Router + providers + ErrorBoundary
274 +│ ├── main.tsx # Entry point
275 +│ ├── config.ts # App config, endpoints, feature flags
276 +│ ├── components/
277 +│ │ ├── chat/ # 13 chat-specific components
278 +│ │ │ ├── search-bar.tsx # Query input with image support
279 +│ │ │ ├── streaming-answer.tsx # Real-time markdown rendering
280 +│ │ │ ├── agent-steps.tsx # Tool execution progress
281 +│ │ │ ├── tool-results.tsx # Financial data display
282 +│ │ │ ├── monte-carlo-results.tsx # Simulation visualizations
283 +│ │ │ ├── share-button.tsx # Report sharing
284 +│ │ │ ├── download-buttons.tsx # PDF/DOCX export
285 +│ │ │ └── ... # + 6 more components
286 +│ │ ├── explore/ # 7 stock explorer components
287 +│ │ ├── financial/ # Price charts, options pricing
288 +│ │ ├── ui/ # 35 shadcn/ui primitives
289 +│ │ └── error-boundary.tsx # Global error handler
290 +│ ├── hooks/
291 +│ │ ├── useChatSession.ts # All chat state & business logic
292 +│ │ ├── useChatMutation.ts # SSE streaming client
293 +│ │ ├── useAnalytics.ts # Heartbeat tracking
294 +│ │ ├── use-toast.ts # Toast notifications
295 +│ │ └── use-mobile.tsx # Responsive detection
296 +│ ├── pages/ # 9 route pages
297 +│ │ ├── home.tsx # Main chat interface (255 lines)
298 +│ │ ├── explore.tsx # Stock explorer
299 +│ │ ├── admin.tsx # Admin dashboard
300 +│ │ ├── auth.tsx # Login/register
301 +│ │ ├── showcase.tsx # Community reports
302 +│ │ ├── shared-report.tsx # Shared report viewer
303 +│ │ ├── documentation.tsx # API documentation
304 +│ │ └── ... # + privacy, terms, slides, 404
305 +│ ├── lib/
306 +│ │ ├── queryClient.ts # TanStack Query config
307 +│ │ └── utils.ts # cn() + helpers
308 +│ └── utils/
309 +│ ├── chartCapture.ts # Chart-to-image conversion
310 +│ └── pdfGenerator.ts # Client-side PDF generation
311 +│
312 +├── server/ # Backend (Express + TypeScript)
313 +│ ├── index.ts # Server bootstrap, CORS, sessions
314 +│ ├── routes.ts # /api/chat (SSE streaming) + speech-to-text
315 +│ ├── routes/
316 +│ │ ├── auth.ts # /api/auth/* (register, login, logout, me)
317 +│ │ ├── admin.ts # /api/admin/* (database, CRUD) + requireAdmin
318 +│ │ ├── analytics.ts # /api/analytics/* (heartbeat, active users, metrics)
319 +│ │ ├── fmp.ts # /api/fmp/* (23 financial data endpoints)
320 +│ │ ├── reports.ts # /api/share/*, sessions, PDF/DOCX/slides, download
321 +│ │ └── validation.ts # Zod request schemas
322 +│ ├── services/
323 +│ │ ├── claude/
324 +│ │ │ ├── toolDefinitions.ts # 213 tool definitions (4,480 lines)
325 +│ │ │ └── tokenManagement.ts # Context window management
326 +│ │ ├── claudeService.ts # Claude API integration
327 +│ │ ├── fmpService.ts # 230 FMP API wrapper functions
328 +│ │ ├── python/
329 +│ │ │ ├── monteCarlo.ts # Monte Carlo simulation
330 +│ │ │ ├── optionsPricing.ts # Black-Scholes pricing
331 +│ │ │ ├── garch.ts # GARCH volatility model
332 +│ │ │ ├── var.ts # VaR + portfolio + risk metrics
333 +│ │ │ └── shared.ts # Python executor config
334 +│ │ ├── *.py # 11 Python scientific services
335 +│ │ ├── firecrawlService.ts # Web extraction
336 +│ │ ├── tavilyService.ts # AI search
337 +│ │ ├── exaService.ts # Semantic search
338 +│ │ └── serpapiService.ts # Google search
339 +│ ├── db.ts # Drizzle ORM (SQLite + PostgreSQL)
340 +│ ├── storage.ts # Typed data access layer
341 +│ ├── types/
342 +│ │ └── modules.d.ts # Module declarations
343 +│ └── utils/
344 +│ └── logger.ts # Structured logging
345 +│
346 +├── shared/ # Shared between client & server
347 +│ ├── schema.ts # PostgreSQL schema (Drizzle)
348 +│ ├── schema-sqlite.ts # SQLite schema (Drizzle)
349 +│ └── types.ts # API interfaces (SearchResult, etc.)
350 +│
351 +├── vitest.config.ts # Test configuration
352 +├── eslint.config.js # ESLint flat config
353 +├── vite.config.ts # Vite build config
354 +├── tsconfig.json # TypeScript config
355 +├── tailwind.config.ts # Tailwind CSS config
356 +├── .prettierrc # Prettier config
357 +├── .editorconfig # Editor config
358 +├── .env.example # Environment template
359 +└── .gitignore # Git ignore rules
360 +```
361 +
362 +### System Architecture
363 +
364 +```
365 +┌──────────────────────────────────────────────────────────────────┐
366 +│ CLIENT (React 18) │
367 +│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌───────────┐ │
368 +│ │ Chat UI │ │ Explore Page │ │ Admin Panel│ │ Auth/Docs │ │
369 +│ │ (SSE) │ │ (FMP data) │ │ (Analytics)│ │ (Sessions)│ │
370 +│ └────┬─────┘ └──────┬───────┘ └─────┬──────┘ └─────┬─────┘ │
371 +│ │ │ │ │ │
372 +│ ┌────┴───────────────┴────────────────┴───────────────┴─────┐ │
373 +│ │ TanStack Query + useChatSession │ │
374 +│ └───────────────────────────┬───────────────────────────────┘ │
375 +└──────────────────────────────┼──────────────────────────────────┘
376 + │ HTTP / SSE
377 +┌──────────────────────────────┼──────────────────────────────────┐
378 +│ SERVER (Express 4) │
379 +│ ┌───────────────────────────┴───────────────────────────────┐ │
380 +│ │ Route Modules (6) │ │
381 +│ │ auth │ admin │ analytics │ fmp │ reports │ chat (SSE) │ │
382 +│ └───┬───────┬──────────┬──────────┬──────────┬──────────────┘ │
383 +│ │ │ │ │ │ │
384 +│ ┌───┴───┐ ┌─┴──────┐ ┌┴────────┐ │ ┌─────┴──────────────┐ │
385 +│ │Storage│ │Analytics│ │Zod Valid│ │ │ Claude Opus 4.8 │ │
386 +│ │(Drizzle)│ │Metrics │ │Schemas │ │ │ 213 tools │ │
387 +│ └───┬───┘ └────────┘ └────────┘ │ │ 5-tool batching │ │
388 +│ │ │ └──────────┬──────────┘ │
389 +│ ┌───┴──────┐ ┌─────┴──────┐ ┌─────┴──────────┐ │
390 +│ │SQLite/PG │ │ FMP Service│ │ Python Engine │ │
391 +│ │(Drizzle) │ │ 230 funcs │ │ 17 libraries │ │
392 +│ └──────────┘ └────────────┘ └────────────────┘ │
393 +│ │
394 +│ ┌────────────────────────────────────────────────────────────┐ │
395 +│ │ External APIs │ │
396 +│ │ Tavily │ Firecrawl │ Exa │ SerpAPI │ ElevenLabs │ │
397 +│ └────────────────────────────────────────────────────────────┘ │
398 +└─────────────────────────────────────────────────────────────────┘
399 +```
400 +
401 +---
402 +
403 +## API Reference
404 +
405 +### Chat (SSE Streaming)
406 +
407 +| Method | Endpoint | Description |
408 +|--------|----------|-------------|
409 +| `POST` | `/api/chat` | Main AI chat with streaming (Server-Sent Events) |
410 +| `POST` | `/api/speech-to-text` | Audio transcription (ElevenLabs Scribe) |
411 +
412 +### Authentication
413 +
414 +| Method | Endpoint | Description |
415 +|--------|----------|-------------|
416 +| `POST` | `/api/auth/register` | Create account (generates unique token) |
417 +| `POST` | `/api/auth/login` | Authenticate with token |
418 +| `POST` | `/api/auth/logout` | End session |
419 +| `GET` | `/api/auth/me` | Get current user |
420 +
421 +### Shared Reports & Sessions
422 +
423 +| Method | Endpoint | Description |
424 +|--------|----------|-------------|
425 +| `GET` | `/api/shared-reports` | List all shared reports |
426 +| `POST` | `/api/share` | Create shareable report |
427 +| `GET` | `/api/share/:shareId` | Get shared report |
428 +| `GET` | `/api/sessions` | List user sessions |
429 +| `GET` | `/api/sessions/:id` | Get session with messages |
430 +
431 +### Document Generation
432 +
433 +| Method | Endpoint | Description |
434 +|--------|----------|-------------|
435 +| `POST` | `/api/generate-pdf` | Markdown to PDF (Puppeteer) |
436 +| `POST` | `/api/generate-docx` | Markdown to DOCX (Pandoc) |
437 +| `POST` | `/api/convert-to-slides` | Markdown to Beamer LaTeX PDF |
438 +| `GET` | `/api/download/:filename` | Download data file |
439 +
440 +### Financial Data (FMP)
441 +
442 +| Method | Endpoint | Description |
443 +|--------|----------|-------------|
444 +| `GET` | `/api/fmp/quote/:symbol` | Real-time stock quote |
445 +| `GET` | `/api/fmp/company-profile/:symbol` | Company profile |
446 +| `GET` | `/api/fmp/historical-price/:symbol` | Historical prices |
447 +| `GET` | `/api/fmp/intraday/:symbol` | Intraday price data |
448 +| `GET` | `/api/fmp/income-statement/:symbol` | Income statement |
449 +| `GET` | `/api/fmp/balance-sheet/:symbol` | Balance sheet |
450 +| `GET` | `/api/fmp/cash-flow/:symbol` | Cash flow statement |
451 +| `GET` | `/api/fmp/key-metrics/:symbol` | Key financial metrics |
452 +| `GET` | `/api/fmp/financial-ratios/:symbol` | Financial ratios |
453 +| `GET` | `/api/fmp/analyst-estimates/:symbol` | Analyst estimates |
454 +| `GET` | `/api/fmp/price-target/:symbol` | Price targets |
455 +| `GET` | `/api/fmp/insider-trading/:symbol` | Insider trades |
456 +| `GET` | `/api/fmp/institutional-holders/:symbol` | Institutional holders |
457 +| `GET` | `/api/fmp/earnings-surprises/:symbol` | Earnings surprises |
458 +| `GET` | `/api/fmp/dividend-history/:symbol` | Dividend history |
459 +| `GET` | `/api/fmp/esg-score/:symbol` | ESG score |
460 +| `GET` | `/api/fmp/financial-news/:symbol` | Financial news |
461 +| `GET` | `/api/fmp/upgrades-downgrades/:symbol` | Analyst upgrades/downgrades |
462 +| `GET` | `/api/fmp/gainers` | Top market gainers |
463 +| `GET` | `/api/fmp/losers` | Top market losers |
464 +| `GET` | `/api/fmp/actives` | Most active stocks |
465 +| `GET` | `/api/fmp/market-hours` | Market hours |
466 +| `GET` | `/api/fmp/chart/light/:symbol` | Lightweight chart data |
467 +
468 +### Analytics & Admin
469 +
470 +| Method | Endpoint | Description |
471 +|--------|----------|-------------|
472 +| `POST` | `/api/analytics/heartbeat` | Update user activity |
473 +| `GET` | `/api/analytics/active-users` | Active users (admin) |
474 +| `GET` | `/api/analytics/real-time-stats` | Real-time stats |
475 +| `GET` | `/api/analytics/metrics` | Historical metrics (admin) |
476 +| `POST` | `/api/admin/login` | Admin login |
477 +| `GET` | `/api/admin/database` | Full database view (admin) |
478 +| `DELETE` | `/api/admin/users/:id` | Delete user (admin) |
479 +| `DELETE` | `/api/admin/sessions/:id` | Delete session (admin) |
480 +| `DELETE` | `/api/admin/reports/:id` | Delete report (admin) |
481 +
482 +---
483 +
484 +## Usage Examples
485 +
486 +### Financial Analysis
487 +```
488 +"Full analysis of NVDA: profile, financials, insider trades, analyst ratings, sector performance"
489 +
490 +"Compare AAPL, MSFT, GOOGL on: market cap, P/E, revenue growth, ESG scores, analyst consensus"
491 +
492 +"Due diligence on TSLA: DCF valuation, institutional holders, insider trading patterns, earnings surprises"
493 +
494 +"Show me the top gainers today with their financial ratios and analyst ratings"
495 +```
496 +
497 +### Quantitative Analysis
498 +```
499 +"Run a Monte Carlo simulation on AAPL with 10,000 paths over 252 trading days"
500 +
501 +"Calculate the correlation matrix of FAANG stocks and display a heatmap"
502 +
503 +"Backtest an RSI strategy on SPY and show the equity curve with Sharpe ratio"
504 +
505 +"Optimize a portfolio of AAPL, MSFT, GOOGL, AMZN for maximum Sharpe ratio"
506 +
507 +"Calculate Value at Risk for a $100,000 NVDA position at 95% and 99% confidence"
508 +
509 +"Estimate GARCH volatility for TSLA and forecast 30-day ahead volatility"
510 +
511 +"Price a call option on AAPL with strike $200, 30 days to expiry, and show all Greeks"
512 +```
513 +
514 +### Web Research
515 +```
516 +"Search latest AI industry news this week and summarize key developments"
517 +
518 +"Extract the last NVIDIA earnings call transcript and highlight guidance changes"
519 +
520 +"Research the impact of Fed rate decisions on tech stocks in 2024-2025"
521 +
522 +"Crawl investor.nvidia.com and extract all Q4 financial press releases"
523 +```
524 +
525 +---
526 +
527 +## Documentation
528 +
529 +Exhaustive documentation is available in the [`docs/`](./docs) directory:
530 +
531 +| Document | Description |
532 +|----------|-------------|
533 +| **[Getting Started](./docs/GETTING_STARTED.md)** | Prerequisites, installation, Python setup, env vars, first run, troubleshooting |
534 +| **[Architecture](./docs/ARCHITECTURE.md)** | System diagram, directory structure, data flow, design decisions |
535 +| **[API Reference](./docs/API_REFERENCE.md)** | All 44 endpoints with request/response schemas, SSE event types, query params |
536 +| **[Python Analysis](./docs/PYTHON_ANALYSIS.md)** | 8 built-in models (Monte Carlo, Black-Scholes, GARCH, VaR, portfolio, risk, plots, custom), all 17 libraries |
537 +| **[Database Schema](./docs/DATABASE.md)** | All 9 tables with columns, types, constraints, relationships |
538 +| **[Deployment](./docs/DEPLOYMENT.md)** | Production build, env vars, Docker example, CORS, security checklist |
539 +| **[Contributing](./docs/CONTRIBUTING.md)** | Dev setup, code conventions, commit format, how to add endpoints/tools |
540 +| **[`.env.example`](./.env.example)** | All environment variables with categories |
541 +
542 +---
543 +
544 +## Testing
545 +
546 +[![Tests](https://img.shields.io/badge/Tests-41_passing-22c55e?style=flat-square&logo=vitest&logoColor=white)](./)
547 +[![Vitest](https://img.shields.io/badge/Framework-Vitest_4-6e9f18?style=flat-square)](./)
548 +[![Duration](https://img.shields.io/badge/Duration-<1s-22c55e?style=flat-square)](./)
549 +
550 +| Suite | Tests | What it covers |
551 +|-------|-------|---------------|
552 +| `App.test.tsx` | 3 | Smoke test: renders, shows home page, search bar present |
553 +| `config.test.ts` | 5 | App config: name, domain, endpoints, limits, feature flags |
554 +| `utils.test.ts` | 5 | `cn()`: class merging, conditionals, dedup, edge cases |
555 +| `queryClient.test.ts` | 6 | Query defaults: staleTime, gcTime, retry, refetch policy |
556 +| `useChatSession.test.tsx` | 6 | Hook: initial state, reset, history toggle, mutation shape, handlers |
557 +| `validation.test.ts` | 16 | All Zod schemas: valid/invalid inputs, missing fields, max lengths |
558 +
559 +```bash
560 +npm test # Run once
561 +npm run test:watch # Watch mode
562 +npm run test:coverage # With coverage
563 +```
564 +
565 +---
566 +
567 +## Deployment
568 +
569 +### Production Build
570 +
571 +```bash
572 +npm run build # Builds client (Vite) + server (esbuild)
573 +npm start # Starts production server
574 +```
575 +
576 +### Environment Variables
577 +
578 +```bash
579 +# Required
580 +NODE_ENV=production
581 +PORT=5000
582 +SESSION_SECRET=<generate-a-strong-random-secret>
583 +ANTHROPIC_API_KEY=sk-ant-...
584 +FINANCIAL_MODELING_PREP_API_KEY=...
585 +
586 +# Database (default: SQLite)
587 +DATABASE_URL=sqlite://local.db
588 +# DATABASE_URL=postgresql://user:pass@host:5432/db
589 +
590 +# Optional APIs
591 +FIRECRAWL_API_KEY=fc-...
592 +TAVILY_API_KEY=tvly-...
593 +EXA_API_KEY=...
594 +SERPAPI_API_KEY=...
595 +```
596 +
597 +---
598 +
599 +## Contributing
600 +
601 +1. Fork the repository
602 +2. Create a feature branch (`git checkout -b feature/my-feature`)
603 +3. Run checks before committing:
604 + ```bash
605 + npm run typecheck && npm run lint && npm test
606 + ```
607 +4. Commit with a descriptive message
608 +5. Open a Pull Request
609 +
610 +### Code Conventions
611 +
612 +| Rule | Enforced By |
613 +|------|------------|
614 +| TypeScript `strict` mode | `tsconfig.json` |
615 +| ESLint (typescript-eslint + react-hooks) | `eslint.config.js` |
616 +| Prettier formatting | `.prettierrc` |
617 +| Zod validation on all API inputs | `server/routes/validation.ts` |
618 +| `logger` instead of `console.log` | ESLint `no-console` rule |
619 +| `@/` path alias (client), `@shared/` (shared) | `tsconfig.json` + `vite.config.ts` |
620 +| Components grouped by domain | `components/chat/`, `components/explore/`, etc. |
621 +| One hook per concern | `useChatSession`, `useChatMutation`, etc. |
622 +
623 +---
624 +
625 +## Authors
626 +
627 +<table>
628 + <tr>
629 + <td align="center" width="50%">
630 + <b>Simon-Pierre Boucher</b><br/>
631 + <i>Creator & Lead Developer</i><br/><br/>
632 + <a href="mailto:contact@spboucher.ai"><img src="https://img.shields.io/badge/Email-contact%40spboucher.ai-8b5cf6?style=flat-square&logo=maildotru&logoColor=white"/></a><br/>
633 + <a href="https://www.spboucher.ai"><img src="https://img.shields.io/badge/Website-spboucher.ai-3b82f6?style=flat-square&logo=safari&logoColor=white"/></a><br/>
634 + <a href="https://github.com/spboucher-ai"><img src="https://img.shields.io/badge/GitHub-spboucher--ai-181717?style=flat-square&logo=github&logoColor=white"/></a>
635 + </td>
636 + <td align="center" width="50%">
637 + <b>Claude Opus 4.8</b><br/>
638 + <i>AI Pair Programmer</i><br/><br/>
639 + <a href="https://claude.ai/claude-code"><img src="https://img.shields.io/badge/Claude_Code-Anthropic-d97706?style=flat-square&logo=anthropic&logoColor=white"/></a><br/>
640 + <a href="https://anthropic.com"><img src="https://img.shields.io/badge/Model-Opus_4.8_(1M_ctx)-d97706?style=flat-square"/></a><br/>
641 + <img src="https://img.shields.io/badge/Contribution-9_commits,_4000+_lines-22c55e?style=flat-square"/>
642 + </td>
643 + </tr>
644 +</table>
645 +
646 +> Full codebase audit, architecture restructuring, TypeScript typing, route modularization, hook extraction, ESLint/Prettier/Vitest setup, ErrorBoundary, Zod validation, and README authored via [Claude Code](https://claude.ai/claude-code).
647 +
648 +---
649 +
650 +## Acknowledgments
651 +
652 +[![Anthropic](https://img.shields.io/badge/Anthropic-Claude_AI-d97706?style=flat-square&logo=anthropic&logoColor=white)](https://anthropic.com/)
653 +[![FMP](https://img.shields.io/badge/Financial_Modeling_Prep-Financial_Data-0969da?style=flat-square)](https://financialmodelingprep.com/)
654 +[![Firecrawl](https://img.shields.io/badge/Firecrawl-Web_Extraction-f97316?style=flat-square)](https://firecrawl.dev/)
655 +[![Tavily](https://img.shields.io/badge/Tavily-AI_Search-4f46e5?style=flat-square)](https://tavily.com/)
656 +[![Exa](https://img.shields.io/badge/Exa-Semantic_Search-6366f1?style=flat-square)](https://exa.ai/)
657 +[![Radix UI](https://img.shields.io/badge/Radix_UI-Components-161618?style=flat-square)](https://radix-ui.com/)
658 +[![shadcn/ui](https://img.shields.io/badge/shadcn/ui-Design_System-000000?style=flat-square)](https://ui.shadcn.com/)
659 +[![Recharts](https://img.shields.io/badge/Recharts-Charts-22b5bf?style=flat-square)](https://recharts.org/)
660 +
661 +---
662 +
663 +## License
664 +
665 +[![MIT License](https://img.shields.io/badge/License-MIT-22c55e?style=for-the-badge)](./LICENSE)
666 +
667 +---
668 +
669 +<div align="center">
670 +
671 +<br/>
672 +
673 +[![Website](https://img.shields.io/badge/www.vquant.ai-Visit_Live_Platform-00c853?style=for-the-badge&logo=googlechrome&logoColor=white)](https://www.vquant.ai)
674 +
675 +<br/>
676 +
677 +*Where AI Meets Institutional-Grade Financial Analysis*
678 +
679 +<br/>
680 +
681 +**Built with** &nbsp;
682 +[![TypeScript](https://img.shields.io/badge/-TypeScript-3178c6?style=flat-square&logo=typescript&logoColor=white)](./)
683 +[![React](https://img.shields.io/badge/-React-61dafb?style=flat-square&logo=react&logoColor=black)](./)
684 +[![Claude](https://img.shields.io/badge/-Claude_AI-d97706?style=flat-square&logo=anthropic&logoColor=white)](./)
685 +[![Python](https://img.shields.io/badge/-Python-3776ab?style=flat-square&logo=python&logoColor=white)](./)
686 +[![Vite](https://img.shields.io/badge/-Vite-646cff?style=flat-square&logo=vite&logoColor=white)](./)
687 +[![Tailwind](https://img.shields.io/badge/-Tailwind-06b6d4?style=flat-square&logo=tailwindcss&logoColor=white)](./)
688 +
689 +</div>
added client/index.html +66 −0
@@ -0,0 +1,66 @@
1 +<!DOCTYPE html>
2 +<!--
3 + =============================================================================
4 + VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
5 + -----------------------------------------------------------------------------
6 + File: client/index.html
7 +
8 + Author: Simon-Pierre Boucher
9 + Contact: contact@spboucher.ai
10 + Website: https://www.spboucher.ai
11 + Demo: https://www.vquant.ai
12 + License: MIT (see LICENSE)
13 +
14 + Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
15 + =============================================================================
16 +-->
17 +
18 +<html lang="fr">
19 + <head>
20 + <meta charset="UTF-8" />
21 + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1" />
22 +
23 + <!-- Primary Meta Tags -->
24 + <title>VQuant | AI-Powered Financial Intelligence Platform</title>
25 + <meta name="title" content="VQuant | AI-Powered Financial Intelligence Platform" />
26 + <meta name="description" content="Plateforme d'analyse financière de niveau institutionnel propulsée par Claude AI. 265+ sources de données, analyses quantitatives avancées, extraction de PDFs, et recherche multi-sources." />
27 + <meta name="keywords" content="analyse financière, IA, Claude AI, FMP, analyse quantitative, trading, investissement, bourse, actions, ETF, Monte Carlo, portfolio optimization" />
28 + <meta name="author" content="VQuant" />
29 +
30 + <!-- Canonical URL -->
31 + <link rel="canonical" href="https://www.vquant.ai" />
32 +
33 + <!-- Open Graph / Facebook -->
34 + <meta property="og:type" content="website" />
35 + <meta property="og:url" content="https://www.vquant.ai" />
36 + <meta property="og:title" content="VQuant | AI-Powered Financial Intelligence" />
37 + <meta property="og:description" content="Plateforme d'analyse financière propulsée par IA avec 265+ sources de données et analyses quantitatives avancées" />
38 + <meta property="og:site_name" content="VQuant" />
39 +
40 + <!-- Twitter -->
41 + <meta property="twitter:card" content="summary_large_image" />
42 + <meta property="twitter:url" content="https://www.vquant.ai" />
43 + <meta property="twitter:title" content="VQuant | AI-Powered Financial Intelligence" />
44 + <meta property="twitter:description" content="Plateforme d'analyse financière propulsée par IA avec 265+ sources de données" />
45 +
46 + <!-- Fonts -->
47 + <link rel="preconnect" href="https://fonts.googleapis.com">
48 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
49 + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
50 +
51 + <!-- Favicon -->
52 + <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
53 +
54 + <!-- Desktop app (Electron) title bar adaptation -->
55 + <style>
56 + @media all {
57 + .electron-drag { -webkit-app-region: drag; }
58 + .electron-no-drag { -webkit-app-region: no-drag; }
59 + }
60 + </style>
61 + </head>
62 + <body>
63 + <div id="root"></div>
64 + <script type="module" src="/src/main.tsx"></script>
65 + </body>
66 +</html>
\ No newline at end of file
added client/src/App.test.tsx +39 −0
@@ -0,0 +1,39 @@
1 +/*
2 + * =============================================================================
3 + * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + * -----------------------------------------------------------------------------
5 + * File: client/src/App.test.tsx
6 + *
7 + * Author: Simon-Pierre Boucher
8 + * Contact: contact@spboucher.ai
9 + * Website: https://www.spboucher.ai
10 + * Demo: https://www.vquant.ai
11 + * License: MIT (see LICENSE)
12 + *
13 + * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + * =============================================================================
15 + */
16 +
17 +import { describe, it, expect } from "vitest";
18 +import { render, screen } from "@testing-library/react";
19 +import App from "./App";
20 +
21 +describe("App", () => {
22 + it("renders without crashing", () => {
23 + const { container } = render(<App />);
24 + expect(container).toBeTruthy();
25 + });
26 +
27 + it("renders the home page by default", () => {
28 + render(<App />);
29 + // The home page has a data-testid="page-home"
30 + expect(screen.getByTestId("page-home")).toBeInTheDocument();
31 + });
32 +
33 + it("renders the search bar", () => {
34 + render(<App />);
35 + expect(
36 + screen.getByPlaceholderText(/question.*march/i),
37 + ).toBeInTheDocument();
38 + });
39 +});
added client/src/App.tsx +67 −0
@@ -0,0 +1,67 @@
1 +/*
2 + * =============================================================================
3 + * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + * -----------------------------------------------------------------------------
5 + * File: client/src/App.tsx
6 + *
7 + * Author: Simon-Pierre Boucher
8 + * Contact: contact@spboucher.ai
9 + * Website: https://www.spboucher.ai
10 + * Demo: https://www.vquant.ai
11 + * License: MIT (see LICENSE)
12 + *
13 + * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + * =============================================================================
15 + */
16 +
17 +import { Switch, Route } from "wouter";
18 +import { queryClient } from "./lib/queryClient";
19 +import { QueryClientProvider } from "@tanstack/react-query";
20 +import { Toaster } from "@/components/ui/toaster";
21 +import { TooltipProvider } from "@/components/ui/tooltip";
22 +import { ThemeProvider } from "@/components/theme-provider";
23 +import { ErrorBoundary } from "@/components/error-boundary";
24 +import Home from "@/pages/home";
25 +import Showcase from "@/pages/showcase";
26 +import Admin from "@/pages/admin";
27 +import SharedReport from "@/pages/shared-report";
28 +import Documentation from "@/pages/documentation";
29 +import Privacy from "@/pages/privacy";
30 +import Terms from "@/pages/terms";
31 +import SlidesGenerator from "@/pages/slides-generator";
32 +import Auth from "@/pages/auth";
33 +import NotFound from "@/pages/not-found";
34 +
35 +function Router() {
36 + return (
37 + <Switch>
38 + <Route path="/" component={Home} />
39 + <Route path="/auth" component={Auth} />
40 + <Route path="/showcase" component={Showcase} />
41 + <Route path="/admin" component={Admin} />
42 + <Route path="/share/:shareId" component={SharedReport} />
43 + <Route path="/docs" component={Documentation} />
44 + <Route path="/privacy" component={Privacy} />
45 + <Route path="/terms" component={Terms} />
46 + <Route path="/slides-generator" component={SlidesGenerator} />
47 + <Route component={NotFound} />
48 + </Switch>
49 + );
50 +}
51 +
52 +function App() {
53 + return (
54 + <ErrorBoundary>
55 + <QueryClientProvider client={queryClient}>
56 + <ThemeProvider defaultTheme="light" storageKey="vquant-theme-v2">
57 + <TooltipProvider>
58 + <Toaster />
59 + <Router />
60 + </TooltipProvider>
61 + </ThemeProvider>
62 + </QueryClientProvider>
63 + </ErrorBoundary>
64 + );
65 +}
66 +
67 +export default App;
added client/src/components/chat/agent-steps.tsx +57 −0
@@ -0,0 +1,57 @@
1 +/*
2 + * =============================================================================
3 + * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + * -----------------------------------------------------------------------------
5 + * File: client/src/components/chat/agent-steps.tsx
6 + *
7 + * Author: Simon-Pierre Boucher
8 + * Contact: contact@spboucher.ai
9 + * Website: https://www.spboucher.ai
10 + * Demo: https://www.vquant.ai
11 + * License: MIT (see LICENSE)
12 + *
13 + * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + * =============================================================================
15 + */
16 +
17 +import { Check } from "lucide-react";
18 +
19 +export interface AgentStep {
20 + tool: string;
21 + status: 'pending' | 'running' | 'completed' | 'error';
22 + input?: any;
23 + error?: string;
24 + duration?: number;
25 +}
26 +
27 +interface AgentStepsProps {
28 + steps: AgentStep[];
29 + currentStep?: number;
30 +}
31 +
32 +export function AgentSteps({ steps, currentStep }: AgentStepsProps) {
33 + if (steps.length === 0) return null;
34 +
35 + // Only show completed steps with simple green circle and checkmark
36 + const completedSteps = steps.filter(s => s.status === 'completed');
37 +
38 + if (completedSteps.length === 0) return null;
39 +
40 + return (
41 + <div className="flex flex-wrap gap-2 mb-4">
42 + {completedSteps.map((step, index) => (
43 + <div
44 + key={`${step.tool}-${index}`}
45 + className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-green-500/10 border border-green-500/20"
46 + >
47 + <div className="w-4 h-4 rounded-full bg-green-500/20 flex items-center justify-center flex-shrink-0">
48 + <Check className="w-3 h-3 text-green-500" />
49 + </div>
50 + <span className="text-xs text-muted-foreground">
51 + {step.tool.replace(/_/g, ' ')}
52 + </span>
53 + </div>
54 + ))}
55 + </div>
56 + );
57 +}
added client/src/components/chat/conversation-history.tsx +89 −0
@@ -0,0 +1,89 @@
1 +/*
2 + * =============================================================================
3 + * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + * -----------------------------------------------------------------------------
5 + * File: client/src/components/chat/conversation-history.tsx
6 + *
7 + * Author: Simon-Pierre Boucher
8 + * Contact: contact@spboucher.ai
9 + * Website: https://www.spboucher.ai
10 + * Demo: https://www.vquant.ai
11 + * License: MIT (see LICENSE)
12 + *
13 + * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + * =============================================================================
15 + */
16 +
17 +import {
18 + Accordion,
19 + AccordionContent,
20 + AccordionItem,
21 + AccordionTrigger,
22 +} from "@/components/ui/accordion";
23 +import { StreamingAnswer } from "@/components/streaming-answer";
24 +
25 +interface ConversationMessage {
26 + question: string;
27 + answer: string;
28 +}
29 +
30 +interface ConversationHistoryProps {
31 + history: ConversationMessage[];
32 +}
33 +
34 +export function ConversationHistory({ history }: ConversationHistoryProps) {
35 + if (history.length === 0) {
36 + return null;
37 + }
38 +
39 + return (
40 + <div className="w-full max-w-4xl mx-auto mb-8 space-y-3">
41 + {history.map((message, index) => (
42 + <Accordion
43 + key={index}
44 + type="single"
45 + collapsible
46 + className="w-full"
47 + data-testid={`accordion-conversation-${index}`}
48 + >
49 + <AccordionItem value={`item-${index}`} className="border rounded-lg">
50 + <AccordionTrigger
51 + className="px-4 py-3 hover-elevate no-underline text-left"
52 + data-testid={`trigger-conversation-${index}`}
53 + >
54 + <div className="flex items-start gap-3 w-full pr-4">
55 + <div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-sm font-medium text-primary">
56 + {index + 1}
57 + </div>
58 + <div className="flex-1 min-w-0">
59 + <p className="text-sm font-medium truncate">
60 + {message.question}
61 + </p>
62 + </div>
63 + </div>
64 + </AccordionTrigger>
65 + <AccordionContent className="px-4 pb-4">
66 + <div className="pl-11">
67 + <div className="mb-3 text-sm font-medium text-muted-foreground">
68 + Question:
69 + </div>
70 + <div className="mb-4 p-3 rounded-md bg-muted/50">
71 + <p className="text-sm">{message.question}</p>
72 + </div>
73 + <div className="mb-3 text-sm font-medium text-muted-foreground">
74 + Answer:
75 + </div>
76 + <div className="prose prose-sm dark:prose-invert max-w-none">
77 + <StreamingAnswer
78 + content={message.answer}
79 + isStreaming={false}
80 + />
81 + </div>
82 + </div>
83 + </AccordionContent>
84 + </AccordionItem>
85 + </Accordion>
86 + ))}
87 + </div>
88 + );
89 +}
added client/src/components/chat/custom-python-figure.tsx +220 −0
@@ -0,0 +1,220 @@
1 +/*
2 + * =============================================================================
3 + * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + * -----------------------------------------------------------------------------
5 + * File: client/src/components/chat/custom-python-figure.tsx
6 + *
7 + * Author: Simon-Pierre Boucher
8 + * Contact: contact@spboucher.ai
9 + * Website: https://www.spboucher.ai
10 + * Demo: https://www.vquant.ai
11 + * License: MIT (see LICENSE)
12 + *
13 + * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + * =============================================================================
15 + */
16 +
17 +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
18 +import { Badge } from "@/components/ui/badge";
19 +import { useState, useEffect } from "react";
20 +import { ChevronDown, ChevronUp, Download } from "lucide-react";
21 +import { Button } from "@/components/ui/button";
22 +
23 +interface FigureBatch {
24 + id: string;
25 + figures: string[]; // URLs (/figures/xxx.png) or base64 encoded images
26 + output?: string; // Text output from Python
27 + description?: string;
28 +}
29 +
30 +function figureSrc(figure: string): string {
31 + // If it starts with / or http, it's a URL — use directly
32 + if (figure.startsWith('/') || figure.startsWith('http')) return figure;
33 + // Otherwise treat as base64
34 + return `data:image/png;base64,${figure}`;
35 +}
36 +
37 +interface CustomPythonFigureGalleryProps {
38 + figureBatches: FigureBatch[]; // Array of figure batches
39 +}
40 +
41 +export function CustomPythonFigure({ figureBatches }: CustomPythonFigureGalleryProps) {
42 + // Initialize with all batches expanded
43 + const [expandedBatches, setExpandedBatches] = useState<Set<string>>(
44 + new Set(figureBatches.map(b => b.id))
45 + );
46 +
47 + // When new batches are added, expand them automatically
48 + useEffect(() => {
49 + const allIds = new Set(figureBatches.map(b => b.id));
50 + setExpandedBatches(allIds);
51 + }, [figureBatches.length]); // Update when number of batches changes
52 +
53 + if (!figureBatches || figureBatches.length === 0) {
54 + return null;
55 + }
56 +
57 + const totalFigures = figureBatches.reduce((sum, batch) => sum + batch.figures.length, 0);
58 +
59 + const toggleBatch = (batchId: string) => {
60 + setExpandedBatches(prev => {
61 + const newSet = new Set(prev);
62 + if (newSet.has(batchId)) {
63 + newSet.delete(batchId);
64 + } else {
65 + newSet.add(batchId);
66 + }
67 + return newSet;
68 + });
69 + };
70 +
71 + return (
72 + <Card className="w-full">
73 + <CardHeader>
74 + <CardTitle className="flex items-center gap-2">
75 + <span className="text-2xl">🐍</span>
76 + Galerie d'Analyses Python
77 + <Badge variant="secondary" className="ml-auto">
78 + {totalFigures} figure{totalFigures > 1 ? 's' : ''}
79 + </Badge>
80 + </CardTitle>
81 + <CardDescription>
82 + {figureBatches.length} analyse{figureBatches.length > 1 ? 's' : ''} Python générée{figureBatches.length > 1 ? 's' : ''}
83 + </CardDescription>
84 + </CardHeader>
85 + <CardContent className="space-y-4">
86 + {figureBatches.map((batch, batchIndex) => {
87 + const isExpanded = expandedBatches.has(batch.id);
88 + const batchNumber = batchIndex + 1;
89 +
90 + return (
91 + <div key={batch.id} className="border rounded-lg overflow-hidden">
92 + {/* Batch Header - Collapsible */}
93 + <div
94 + className="flex items-center justify-between p-4 bg-muted/30 cursor-pointer hover:bg-muted/50 transition-colors"
95 + onClick={() => toggleBatch(batch.id)}
96 + >
97 + <div className="flex items-center gap-3">
98 + <Badge variant="outline">#{batchNumber}</Badge>
99 + <div>
100 + <div className="font-semibold text-sm">
101 + {batch.description || `Analyse Python #${batchNumber}`}
102 + </div>
103 + <div className="text-xs text-muted-foreground">
104 + {batch.figures.length} figure{batch.figures.length > 1 ? 's' : ''}
105 + {batch.output && ` • ${batch.output.split('\n').length} lignes de résultats`}
106 + </div>
107 + </div>
108 + </div>
109 + <Button variant="ghost" size="sm">
110 + {isExpanded ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
111 + </Button>
112 + </div>
113 +
114 + {/* Batch Content - Expandable */}
115 + {isExpanded && (
116 + <div className="p-4 space-y-4">
117 + {/* Text output if available */}
118 + {batch.output && batch.output.trim() && (
119 + <div className="bg-muted/50 p-4 rounded-lg">
120 + <h4 className="font-semibold mb-2 text-sm">📊 Résultats</h4>
121 + <pre className="text-sm font-mono whitespace-pre-wrap overflow-x-auto">
122 + {batch.output}
123 + </pre>
124 + </div>
125 + )}
126 +
127 + {/* Figures Grid */}
128 + <div className="space-y-3">
129 + <div className="flex items-center justify-between">
130 + <h4 className="font-semibold text-sm">
131 + 📈 Graphique{batch.figures.length > 1 ? 's' : ''}
132 + </h4>
133 + {batch.figures.length > 1 && (
134 + <Button
135 + variant="outline"
136 + size="sm"
137 + onClick={(e) => {
138 + e.stopPropagation();
139 + // Download all figures as zip would be nice, but for now just show button
140 + }}
141 + className="text-xs"
142 + >
143 + <Download className="w-3 h-3 mr-1" />
144 + Tout télécharger
145 + </Button>
146 + )}
147 + </div>
148 +
149 + <div className={`grid gap-4 ${batch.figures.length > 1 ? 'grid-cols-1 lg:grid-cols-2' : 'grid-cols-1'}`}>
150 + {batch.figures.map((figure, figIndex) => {
151 + const figureId = `${batch.id}-${figIndex}`;
152 +
153 + return (
154 + <div key={figIndex} className="border rounded-lg overflow-hidden bg-card group relative">
155 + {/* Figure ID badge for reference */}
156 + <div className="absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity">
157 + <Badge variant="secondary" className="text-xs font-mono">
158 + {figureId}
159 + </Badge>
160 + </div>
161 +
162 + <img
163 + src={figureSrc(figure)}
164 + alt={`Figure ${batchNumber}.${figIndex + 1}`}
165 + className="w-full h-auto cursor-pointer"
166 + style={{ maxHeight: '600px', objectFit: 'contain' }}
167 + onError={(e) => {
168 + const img = e.currentTarget;
169 + if (!img.dataset.retried) {
170 + img.dataset.retried = 'true';
171 + // Retry with cache-busted URL
172 + const src = figureSrc(figure);
173 + img.src = src.includes('?') ? `${src}&t=${Date.now()}` : `${src}?t=${Date.now()}`;
174 + } else {
175 + img.style.display = 'none';
176 + const fallback = img.parentElement?.querySelector('.figure-fallback');
177 + if (fallback) (fallback as HTMLElement).style.display = 'flex';
178 + }
179 + }}
180 + onClick={() => {
181 + const win = window.open();
182 + if (win) {
183 + win.document.write(`<img src="${figureSrc(figure)}" style="max-width: 100%; height: auto;" />`);
184 + win.document.title = `Figure ${batchNumber}.${figIndex + 1}`;
185 + }
186 + }}
187 + />
188 + <div className="figure-fallback items-center justify-center p-8 bg-muted/30" style={{ display: 'none' }}>
189 + <p className="text-sm text-muted-foreground">Figure non disponible</p>
190 + </div>
191 +
192 + {/* Figure info footer */}
193 + <div className="p-2 bg-muted/30 border-t flex items-center justify-between">
194 + <div className="text-xs text-muted-foreground">
195 + Figure {batchNumber}.{figIndex + 1}
196 + </div>
197 + <a
198 + href={figureSrc(figure)}
199 + download={`vibequant-figure-${figureId}.png`}
200 + className="text-xs text-primary hover:underline flex items-center gap-1"
201 + onClick={(e) => e.stopPropagation()}
202 + >
203 + <Download className="w-3 h-3" />
204 + Télécharger
205 + </a>
206 + </div>
207 + </div>
208 + );
209 + })}
210 + </div>
211 + </div>
212 + </div>
213 + )}
214 + </div>
215 + );
216 + })}
217 + </CardContent>
218 + </Card>
219 + );
220 +}
added client/src/components/chat/download-buttons.tsx +217 −0
@@ -0,0 +1,217 @@
1 +/*
2 + * =============================================================================
3 + * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform
4 + * -----------------------------------------------------------------------------
5 + * File: client/src/components/chat/download-buttons.tsx
6 + *
7 + * Author: Simon-Pierre Boucher
8 + * Contact: contact@spboucher.ai
9 + * Website: https://www.spboucher.ai
10 + * Demo: https://www.vquant.ai
11 + * License: MIT (see LICENSE)
12 + *
13 + * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
14 + * =============================================================================
15 + */
16 +
17 +import { FileText, FileDown, FileType, Loader2, Presentation } from "lucide-react";
18 +import { Button } from "@/components/ui/button";
19 +import { useState } from "react";
20 +import { useToast } from "@/hooks/use-toast";
21 +import { useLocation } from "wouter";
22 +
23 +interface DownloadButtonsProps {
24 + question: string;
25 + answer: string;
26 + contentRef?: React.RefObject<HTMLElement>;
27 + figureUrls?: string[];
28 +}
29 +
30 +export function DownloadButtons({ question, answer, contentRef, figureUrls = [] }: DownloadButtonsProps) {
31 + const [isGeneratingPDF, setIsGeneratingPDF] = useState(false);
32 + const [isGeneratingDOCX, setIsGeneratingDOCX] = useState(false);
33 + const { toast } = useToast();
34 + const [, setLocation] = useLocation();
35 +
36 + const handleDownloadMarkdown = () => {
37 + const content = answer;
38 + const blob = new Blob([content], { type: 'text/markdown' });
39 + const url = URL.createObjectURL(blob);
40 + const a = document.createElement('a');
41 + a.href = url;
42 + a.download = `vibequant-${Date.now()}.md`;
43 + document.body.appendChild(a);
44 + a.click();
45 + document.body.removeChild(a);
46 + URL.revokeObjectURL(url);
47 +
48 + toast({
49 + title: "Téléchargement réussi",
50 + description: "Le fichier Markdown a été téléchargé avec succès.",
51 + });
52 + };
53 +
54 + const handleDownloadPDF = async () => {
55 + setIsGeneratingPDF(true);
56 +
57 + try {
58 + const response = await fetch('/api/generate-pdf', {
59 + method: 'POST',
60 + headers: {
61 + 'Content-Type': 'application/json',
62 + },
63 + body: JSON.stringify({
64 + question,
65 + answer
66 + }),
67 + });
68 +
69 + if (!response.ok) {
70 + throw new Error('Failed to generate PDF');
71 + }
72 +
73 + const blob = await response.blob();
74 + const url = URL.createObjectURL(blob);
75 + const a = document.createElement('a');
76 + a.href = url;
77 + a.download = `vibequant-${Date.now()}.pdf`;
78 + document.body.appendChild(a);
79 + a.click();
80 + document.body.removeChild(a);
81 + URL.revokeObjectURL(url);
82 +
83 + toast({
84 + title: "PDF généré avec succès",
85 + description: "Le rapport PDF a été téléchargé.",
86 + });
87 + } catch (error) {
88 + console.error('Error generating PDF:', error);
89 + toast({
90 + title: "Erreur de génération",
91 + description: "Une erreur s'est produite lors de la génération du PDF. Veuillez réessayer.",
92 + variant: "destructive",
93 + });
94 + } finally {
95 + setIsGeneratingPDF(false);
96 + }
97 + };
98 +
99 + const handleDownloadDOCX = async () => {
100 + setIsGeneratingDOCX(true);
101 +
102 + try {
103 + const response = await fetch('/api/generate-docx', {
104 + method: 'POST',
105 + headers: {
106 + 'Content-Type': 'application/json',
107 + },
108 + body: JSON.stringify({
109 + question,
110 + answer
111 + }),
112 + });
113 +
114 + if (!response.ok) {
115 + throw new Error('Failed to generate Word document');
116 + }
117 +
118 + const blob = await response.blob();
119 + const url = URL.createObjectURL(blob);
120 + const a = document.createElement('a');
121 + a.href = url;
122 + a.download = `vibequant-${Date.now()}.docx`;
123 + document.body.appendChild(a);
124 + a.click();
125 + document.body.removeChild(a);
126 + URL.revokeObjectURL(url);
127 +
128 + toast({
129 + title: "Word généré avec succès",
130 + description: "Le document Word a été téléchargé.",
131 + });
132 + } catch (error) {
133 + console.error('Error generating DOCX:', error);
134 + toast({
135 + title: "Erreur de génération",
136 + description: "Une erreur s'est produite lors de la génération du Word. Veuillez réessayer.",
137 + variant: "destructive",
138 + });
139 + } finally {
140 + setIsGeneratingDOCX(false);
141 + }
142 + };
143 +
144 + const handleConvertToSlides = () => {
145 + // Store content in sessionStorage to pass to slides generator page
146 + sessionStorage.setItem('slidesContent', JSON.stringify({ question, answer, figureUrls }));
147 + setLocation('/slides-generator');
148 +
149 + toast({
150 + title: "Redirection...",
151 + description: "Ouverture du générateur de slides",
152 + });
153 + };
154 +
155 + return (
156 + <>
157 + <Button
158 + variant="outline"
159 + size="sm"
160 + onClick={handleDownloadMarkdown}
161 + className="gap-2 hover:bg-muted transition-colors"
162 + disabled={isGeneratingPDF}
163 + >
164 + <FileText className="w-4 h-4" />
165 + <span className="hidden sm:inline">Télécharger MD</span>
166 + </Button>
167 + <Button
168 + variant="outline"
169 + size="sm"
170 + onClick={handleDownloadPDF}
171 + className="gap-2 hover:bg-muted transition-colors"
172 + disabled={isGeneratingPDF}
173 + >
174 + {isGeneratingPDF ? (
175 + <>
176 + <Loader2 className="w-4 h-4 animate-spin" />
177 + <span className="hidden sm:inline">Génération...</span>
178 + </>
179 + ) : (
180 + <>
181 + <FileDown className="w-4 h-4" />
182 + <span className="hidden sm:inline">Télécharger PDF</span>
183 + </>
184 + )}
185 + </Button>
186 + <Button
187 + variant="outline"
188 + size="sm"
189 + onClick={handleDownloadDOCX}
190 + className="gap-2 hover:bg-muted transition-colors"
191 + disabled={isGeneratingDOCX}
192 + >
193 + {isGeneratingDOCX ? (
194 + <>
195 + <Loader2 className="w-4 h-4 animate-spin" />
196 + <span className="hidden sm:inline">Génération...</span>
197 + </>
198 + ) : (
199 + <>
200 + <FileType className="w-4 h-4" />
201 + <span className="hidden sm:inline">Télécharger Word</span>
202 + </>
203 + )}
204 + </Button>
205 + <Button
206 + variant="outline"
207 + size="sm"
208 + onClick={handleConvertToSlides}
209 + className="gap-2 hover:bg-muted transition-colors"
210 + disabled={isGeneratingPDF || isGeneratingDOCX || !question || !answer}
211 + >
212 + <Presentation className="w-4 h-4" />
213 + <span className="hidden sm:inline">Convertir en Slides</span>
214 + </Button>
215 + </>
216 + );
217 +}
added client/src/components/chat/empty-state.tsx +422 −0
Large diff (422 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/error-state.tsx +56 −0
Large diff (56 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/monte-carlo-results.tsx +226 −0
Large diff (226 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/result-card.tsx +73 −0
Large diff (73 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/search-bar.tsx +85 −0
Large diff (85 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/searching-widget.tsx +106 −0
Large diff (106 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/session-history.tsx +89 −0
Large diff (89 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/share-button.tsx +198 −0
Large diff (198 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/thinking-widget.tsx +64 −0
Large diff (64 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/chat/tool-results.tsx +30 −0
Large diff (30 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/error-boundary.tsx +83 −0
Large diff (83 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/analyst-view.tsx +324 −0
Large diff (324 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/financial-statements-view.tsx +289 −0
Large diff (289 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/market-overview.tsx +361 −0
Large diff (361 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/metrics-view.tsx +324 −0
Large diff (324 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/news-view.tsx +157 −0
Large diff (157 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/ownership-view.tsx +207 −0
Large diff (207 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/explore/stock-header.tsx +293 −0
Large diff (293 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/financial/advanced-price-chart.tsx +535 −0
Large diff (535 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/financial/options-pricing-card.tsx +246 −0
Large diff (246 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/market-ticker.tsx +131 −0
Large diff (131 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/streaming-answer.tsx +410 −0
Large diff (410 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/theme-color-picker.tsx +80 −0
Large diff (80 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/theme-provider.tsx +149 −0
Large diff (149 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/theme-toggle.tsx +40 −0
Large diff (40 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/accordion.tsx +72 −0
Large diff (72 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/alert-dialog.tsx +155 −0
Large diff (155 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/alert.tsx +75 −0
Large diff (75 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/aspect-ratio.tsx +21 −0
Large diff (21 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/avatar.tsx +67 −0
Large diff (67 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/badge.tsx +56 −0
Large diff (56 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/breadcrumb.tsx +131 −0
Large diff (131 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/button.tsx +78 −0
Large diff (78 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/calendar.tsx +84 −0
Large diff (84 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/card.tsx +101 −0
Large diff (101 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/carousel.tsx +276 −0
Large diff (276 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/chart.tsx +381 −0
Large diff (381 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/checkbox.tsx +44 −0
Large diff (44 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/collapsible.tsx +27 −0
Large diff (27 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/command.tsx +167 −0
Large diff (167 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/context-menu.tsx +214 −0
Large diff (214 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/dialog.tsx +138 −0
Large diff (138 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/drawer.tsx +134 −0
Large diff (134 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/dropdown-menu.tsx +214 −0
Large diff (214 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/form.tsx +194 −0
Large diff (194 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/hover-card.tsx +45 −0
Large diff (45 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/input-otp.tsx +85 −0
Large diff (85 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/input.tsx +39 −0
Large diff (39 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/label.tsx +40 −0
Large diff (40 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/menubar.tsx +272 −0
Large diff (272 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/navigation-menu.tsx +144 −0
Large diff (144 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/pagination.tsx +133 −0
Large diff (133 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/popover.tsx +45 −0
Large diff (45 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/progress.tsx +44 −0
Large diff (44 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/radio-group.tsx +58 −0
Large diff (58 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/resizable.tsx +61 −0
Large diff (61 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/scroll-area.tsx +62 −0
Large diff (62 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/select.tsx +176 −0
Large diff (176 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/separator.tsx +45 −0
Large diff (45 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/sheet.tsx +156 −0
Large diff (156 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/sidebar.tsx +743 −0
Large diff (743 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/skeleton.tsx +31 −0
Large diff (31 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/slider.tsx +42 −0
Large diff (42 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/switch.tsx +43 −0
Large diff (43 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/table.tsx +133 −0
Large diff (133 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/tabs.tsx +69 −0
Large diff (69 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/textarea.tsx +38 −0
Large diff (38 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/toast.tsx +143 −0
Large diff (143 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/toaster.tsx +49 −0
Large diff (49 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/toggle-group.tsx +77 −0
Large diff (77 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/toggle.tsx +59 −0
Large diff (59 lines) is not loaded by default to keep the page fast.Load diff
added client/src/components/ui/tooltip.tsx +46 −0
Large diff (46 lines) is not loaded by default to keep the page fast.Load diff
added client/src/config.test.ts +48 −0
Large diff (48 lines) is not loaded by default to keep the page fast.Load diff
added client/src/config.ts +67 −0
Large diff (67 lines) is not loaded by default to keep the page fast.Load diff
added client/src/hooks/use-mobile.tsx +35 −0
Large diff (35 lines) is not loaded by default to keep the page fast.Load diff
added client/src/hooks/use-toast.ts +207 −0
Large diff (207 lines) is not loaded by default to keep the page fast.Load diff
added client/src/hooks/useAnalytics.ts +110 −0
Large diff (110 lines) is not loaded by default to keep the page fast.Load diff
added client/src/hooks/useChatMutation.ts +114 −0
Large diff (114 lines) is not loaded by default to keep the page fast.Load diff
added client/src/hooks/useChatSession.test.tsx +127 −0
Large diff (127 lines) is not loaded by default to keep the page fast.Load diff
added client/src/hooks/useChatSession.ts +356 −0
Large diff (356 lines) is not loaded by default to keep the page fast.Load diff
added client/src/index.css +541 −0
Large diff (541 lines) is not loaded by default to keep the page fast.Load diff
added client/src/lib/queryClient.test.ts +49 −0
Large diff (49 lines) is not loaded by default to keep the page fast.Load diff
added client/src/lib/queryClient.ts +74 −0
Large diff (74 lines) is not loaded by default to keep the page fast.Load diff
added client/src/lib/utils.test.ts +41 −0
Large diff (41 lines) is not loaded by default to keep the page fast.Load diff
added client/src/lib/utils.ts +22 −0
Large diff (22 lines) is not loaded by default to keep the page fast.Load diff
added client/src/main.tsx +21 −0
Large diff (21 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/admin.tsx +791 −0
Large diff (791 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/auth.tsx +331 −0
Large diff (331 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/documentation.tsx +730 −0
Large diff (730 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/explore.tsx +492 −0
Large diff (492 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/home.tsx +263 −0
Large diff (263 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/not-found.tsx +37 −0
Large diff (37 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/privacy.tsx +143 −0
Large diff (143 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/shared-report.tsx +222 −0
Large diff (222 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/showcase.tsx +373 −0
Large diff (373 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/slides-generator.tsx +320 −0
Large diff (320 lines) is not loaded by default to keep the page fast.Load diff
added client/src/pages/terms.tsx +197 −0
Large diff (197 lines) is not loaded by default to keep the page fast.Load diff
added client/src/test/setup.ts +17 −0
Large diff (17 lines) is not loaded by default to keep the page fast.Load diff
added client/src/utils/chartCapture.ts +93 −0
Large diff (93 lines) is not loaded by default to keep the page fast.Load diff
added client/src/utils/pdfGenerator.ts +655 −0
Large diff (655 lines) is not loaded by default to keep the page fast.Load diff
added desktop/create-icon.sh +95 −0
Large diff (95 lines) is not loaded by default to keep the page fast.Load diff
added desktop/icons/VQuant.iconset/icon_128x128.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_128x128@2x.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_16x16.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_16x16@2x.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_256x256.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_256x256@2x.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_32x32.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_32x32@2x.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_512x512.png +0 −0

Binary file not shown.

added desktop/icons/VQuant.iconset/icon_512x512@2x.png +0 −0

Binary file not shown.

added desktop/icons/icon.icns +0 −0

Binary file not shown.

added desktop/main.js +652 −0
Large diff (652 lines) is not loaded by default to keep the page fast.Load diff
added desktop/package-lock.json +612 −0
Large diff (612 lines) is not loaded by default to keep the page fast.Load diff

Diff truncated — file too large.

Menu

Theme