|
4 | 4 | - `app.py` is the Streamlit shell: it hydrates cached data via `initialize_app_data()`, gates the UI through `simple_auth_wrapper`, and delegates all heavy work to `src/core.py` and `src/ai_service.py`. |
5 | 5 | - `src/core.py` owns DuckDB execution and orchestrates data prep. `scan_parquet_files()` will run `scripts/sync_data.py` if `data/processed/*.parquet` are missing, so keep a local Parquet copy handy during tests to avoid network pulls. |
6 | 6 | - `src/ai_service.py` routes natural-language prompts into adapter implementations in `src/ai_engines/`. The prompt embeds the mortgage risk heuristics baked into `src/data_dictionary.py`; reuse `AIService._build_sql_prompt()` instead of crafting ad-hoc prompts. |
| 7 | +- `src/visualization.py` handles Altair chart generation with support for Bar, Line, Scatter, Histogram, and Heatmap charts. Use `make_chart()` for consistent visualization output. |
| 8 | +- `src/ui/` contains modular UI components: `tabs.py` for main interface tabs, `components.py` for reusable widgets, `sidebar.py` for navigation, and `style.py` for theming. |
| 9 | +- `src/services/` contains service layer abstractions: `ai_service.py` and `data_service.py` for business logic separation. |
7 | 10 |
|
8 | 11 | ## Data + ontology expectations |
9 | 12 | - Loan metadata lives in `data/processed/data.parquet`; schema text comes from `generate_enhanced_schema_context()` which stitches DuckDB types with ontology metadata from `src/data_dictionary.py` and `docs/DATA_DICTIONARY.md`. |
10 | 13 | - When adding derived features, update both the Parquet schema and the ontology entry so AI output and the Ontology Explorer tab stay in sync. |
11 | 14 | - The Streamlit Ontology tab imports `LOAN_ONTOLOGY` and `PORTFOLIO_CONTEXT`; breaking their shape (dict → FieldMetadata) will crash the UI. |
12 | 15 |
|
| 16 | +## Visualization layer |
| 17 | +- `src/visualization.py` provides chart generation using Altair with automatic type detection and error handling. |
| 18 | +- Supported chart types: Bar, Line, Scatter, Histogram, Heatmap (defined in `ALLOWED_CHART_TYPES`). |
| 19 | +- Charts auto-resolve data sources in priority order: explicit DataFrame → manual query results → AI query results. |
| 20 | +- Use `_validate_chart_params()` for parameter validation before calling `make_chart()`. |
| 21 | +- The visualization system handles type coercion, sorting, and provides fallbacks for missing data. |
| 22 | + |
13 | 23 | ## AI engine adapters |
14 | 24 | - Adapters must subclass `AIEngineAdapter` in `src/ai_engines/base.py`, expose `provider_id`, `name`, `is_available()`, and `generate_sql()`, then be exported via `src/ai_engines/__init__.py` and registered inside `AIService.adapters`. |
15 | 25 | - Use `clean_sql_response()` to strip markdown fences, and return `(sql, "")` on success; downstream callers treat any non-empty error string as failure. |
16 | 26 | - Keep `AI_PROVIDER` fallbacks working—tests rely on `AIService` surviving with zero credentials, so default to "unavailable" rather than raising. |
| 27 | +- Rate limiting is handled automatically via the base adapter class with configurable `AI_MAX_REQUESTS_PER_MINUTE`. |
17 | 28 |
|
18 | 29 | ## Developer workflows |
19 | 30 | - Install deps with `pip install -r requirements.txt`; prefer `make setup` for a clean environment (installs + cleanup). |
20 | 31 | - Fast test cycle: `make test-unit` skips integration markers; `make test` mirrors CI (pytest + coverage). Integration adapters are ignored by default via `pytest.ini`; remove the `--ignore` flags there if you really need live API coverage. |
21 | | -- Lint/format stack is Black 120 cols + isort + flake8 + mypy. `make ci` runs the whole suite and matches the GitHub Actions workflow. |
| 32 | +- Lint/format stack is Black 120 cols + isort + flake8 + mypy. `make ci` runs the whole suite and matches the GitHub Actions workflow. |
| 33 | +- Local environment: Use `conda activate gcp-pipeline`. Run `make format`, `make ci`, and `make dev` for local testing. |
22 | 34 |
|
23 | 35 | ## Environment & secrets |
24 | | -- Copy `.env.example` to `.env`, then set one provider block (`CLAUDE_API_KEY`, `AWS_*`, or `GEMINI_API_KEY`). Without credentials the UI drops to “AI unavailable” but manual SQL still works. |
| 36 | +- Copy `.env.example` to `.env`, then set one provider block (`CLAUDE_API_KEY`, `AWS_*`, or `GEMINI_API_KEY`). Without credentials the UI drops to "AI unavailable" but manual SQL still works. |
25 | 37 | - Data sync needs Cloudflare R2 keys (`R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_ENDPOINT_URL`). In offline dev, set `FORCE_DATA_REFRESH=false` and place Parquet files under `data/processed/`. |
26 | 38 | - Authentication defaults to Google OAuth (`ENABLE_AUTH=true`); set it to `false` for local hacking or provide `GOOGLE_CLIENT_ID/SECRET` plus HTTPS when deploying. |
27 | 39 |
|
28 | 40 | ## Practical tips |
29 | 41 | - Clear Streamlit caches with `streamlit cache clear` if schema or ontology changes; otherwise stale `@st.cache_data` results linger. |
30 | 42 | - When writing new ingest code, mirror the type-casting helpers in `notebooks/pipeline_csv_to_parquet*.ipynb` so DuckDB types stay compatible. |
31 | 43 | - Logging to Cloudflare D1 is optional—`src/d1_logger.py` silently no-ops without `CLOUDFLARE_*` secrets, so you can call it safely even in tests. |
| 44 | +- For visualization work, test with different data types and edge cases—the chart system includes extensive error handling and type coercion. |
| 45 | + |
| 46 | +## Linting & code quality |
| 47 | +- Follow PEP 8: always add spaces after commas in function calls, lists, and tuples |
| 48 | +- Remove unused imports to avoid F401 errors; use `isort` and check with `make format` |
| 49 | +- For type hints, ensure all arguments match expected types; cast with `str()` or provide defaults when needed |
| 50 | +- Module-level imports must be at the top of files before any other code to avoid E402 errors |
| 51 | +- Use `make lint` frequently during development to catch issues early |
| 52 | +- Target Python 3.11+ features: use built-in types (`list[T]`) instead of `typing.List[T]` |
| 53 | +- Altair charts should handle large datasets—`alt.data_transformers.disable_max_rows()` is called in visualization module |
0 commit comments