Skip to content
Open
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
7 changes: 7 additions & 0 deletions expert_backend/recommenders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@
register,
unregister,
)
from expert_backend.recommenders.toop import ToOpRecommender

# Register the default (expert) and canonical random examples.
# This module is imported by the FastAPI startup path so every server
# process has the three built-in models available immediately.
register(ExpertRecommender)
register(RandomRecommender)
register(RandomOverflowRecommender)
# ToOp is an OPTIONAL install (Python 3.11 + heavy GPU deps). The
# class itself only lazy-imports toop_engine_topology_optimizer inside
# `recommend()`, so registering it here costs nothing when ToOp isn't
# installed — the model just produces an empty recommendation with a
# clear log line.
register(ToOpRecommender)

# Side-effect: patches RecommenderService to consume the registry
# (state + getters + update_config wrap + reset wrap + model-aware
Expand Down
29 changes: 29 additions & 0 deletions expert_backend/recommenders/_service_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,35 @@ def _run_analysis_step2_with_model(
action_scores = self._compute_mw_start_for_scores(
results.get("action_scores", {})
)

# ToOp: each candidate topology is a single prioritized action
# (one merged grid2op action object) that the assessment phase
# already REALLY simulated, so ``enriched_actions[topology_id]``
# carries the true combined max_rho. Leave the entries in the
# main Suggested-Actions feed and decorate them in place with
# N-way metadata so the frontend ActionCard can render the
# constituent moves. Also inject the synthesised contents into
# ``_dict_action`` so the card stays re-simulatable /
# session-saveable.
topo_groups = getattr(recommender, "_last_topology_groups", None)
if topo_groups:
topo_entries = getattr(recommender, "_last_topology_dict_entries", {}) or {}
if self._dict_action is None:
self._dict_action = {}
self._dict_action.update(topo_entries)
for grp in topo_groups:
tid = grp["topology_id"]
entry = enriched_actions.get(tid)
if entry is None:
continue
constituents = grp.get("constituents", []) or []
entry["is_toop_topology"] = True
entry["constituent_ids"] = constituents
entry["constituent_count"] = len(constituents)
entry["rank"] = grp.get("rank")
if not entry.get("description_unitaire"):
entry["description_unitaire"] = "ToOp: " + ", ".join(constituents)

enrichment_time = time.time() - _t_enrich

logger.info(
Expand Down
Loading