Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
## 2024-05-19 - Caching YAML Load for Framework Registry
**Learning:** `yaml.safe_load` on `frameworks.yml` within `load_framework_registry()` was taking ~2-3 ms per call and it was repeatedly called for every framework entry via `get_framework_config()`. This was a micro-bottleneck, especially when dealing with lists or multiple frameworks.
**Action:** Applied the `@lru_cache` and `deepcopy` pattern successfully again to `load_framework_registry()` and `get_framework_config()` to avoid caching a mutable dictionary directly and avoid repeated YAML I/O parsing.

## 2024-05-19 - Caching YAML Load for FAQs
**Learning:** `yaml.safe_load` on `faqs.yml` within `build_faqs()` takes ~5 ms per call. This causes unnecessary overhead each time the UI components are built. This pattern confirms that any static `.yml` reading throughout the app during request cycles is a micro-bottleneck that should be avoided.
**Action:** Applied the same `@cache` and `copy.deepcopy` pattern used for `models.yml` and `frameworks.yml` to `load_faq_data()` to eliminate repetitive I/O and parsing time during UI rendering.
33 changes: 25 additions & 8 deletions ml_peg/app/utils/build_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

import copy
from functools import cache
from importlib import metadata
from pathlib import Path
import time
Expand Down Expand Up @@ -468,6 +470,24 @@ def build_plot_download_controls(graph_id: str) -> Div:
)


@cache
def load_faq_data() -> list[dict[str, str]]:
"""
Load FAQ configuration from ``faqs.yml``.

Returns
-------
list[dict[str, str]]
List of FAQ entries from the YAML configuration.
"""
faqs_path = Path(__file__).parent / "faqs.yml"
try:
with open(faqs_path, encoding="utf8") as f:
return yaml.safe_load(f) or []
except FileNotFoundError:
return []


def build_faqs() -> Div:
"""
Build FAQ section with collapsible dropdowns from YAML file.
Expand All @@ -477,23 +497,20 @@ def build_faqs() -> Div:
Div
Styled FAQ section with questions as dropdown titles and answers inside.
"""
# Load FAQs from YAML file
faqs_path = Path(__file__).parent / "faqs.yml"
# Load FAQs from cached YAML data
faqs_data = copy.deepcopy(load_faq_data())

try:
with open(faqs_path, encoding="utf8") as f:
faqs_data = yaml.safe_load(f)
except FileNotFoundError:
if not faqs_data:
return Div(
"FAQs file not found",
"FAQs file not found or empty",
style={
"color": "#dc3545",
"padding": "10px",
"fontStyle": "italic",
},
)

if not faqs_data or not isinstance(faqs_data, list):
if not isinstance(faqs_data, list):
return Div("No FAQs available")

# Build FAQ dropdowns
Expand Down
Loading