Skip to content

Feat/explainer story i18n - #803

Open
Creylay wants to merge 5 commits into
developfrom
feat/explainer-story-i18n
Open

Feat/explainer story i18n#803
Creylay wants to merge 5 commits into
developfrom
feat/explainer-story-i18n

Conversation

@Creylay

@Creylay Creylay commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a story() narrative hook to every explainer (13/13), so global and local explanations come with a deterministic, human-readable summary in addition to their plots. Stories are generated in all 5 supported languages (en, es, pt, de, zh) at once and returned alongside the plot response, so the frontend can switch languages instantly (via the existing i18n selector) without refetching. Also removes redundant hardcoded English text that a subset of explainers previously baked into their plots, now superseded by the multilingual story() output.


Type of Change

  • Backend change
  • Backend change
  • Frontend change
  • CI / Workflow change
  • Build / Packaging change
  • Bug fix
  • Documentation

Changes (by file)

Core story infrastructure

  • DashAI/back/explainability/story.py: new format_story()/concat_stories() helpers that build a MultilingualString from per-language templates, reused by every explainer instead of duplicating 5-language boilerplate.
  • DashAI/back/explainability/global_explainer.py, local_explainer.py: added an optional story(explanation, explainer_output) hook to BaseGlobalExplainer/BaseLocalExplainer (default None), mirroring the existing plot() contract.

DashAI/back/explainability/explainers/ (Explainers)

  • permutation_feature_importance.py, regression_permutation_feature_importance.py: new story() ranking features by importance; only claims the model "relies on" features with measurable (>0) importance, calling out separately when the rest showed none instead of lumping them together.
  • partial_dependence.py, regression_partial_dependence.py: new story() classifying each curve as increasing/decreasing/flat/non-monotonic from its actual values; added a dedicated "flat" case for curves with no real change (previously misreported as "increases").
  • kernel_shap.py: new story(); removed the old English-only Plotly annotation baked into the chart (predicted class/probability), now covered — with more detail — by story().
  • contrastive_shap.py, dice_counterfactual.py, nearest_counterfactual.py, regression_kernel_shap.py, token_ablation.py, grad_cam.py, occlusion_saliency.py, lime_text.py: migrated each explainer's existing hardcoded English TextArtifact summary into a multilingual story() with equivalent wording, and removed the now-redundant TextArtifact from plot().

** DashAI/back/api/api_v1/endpoints/explainers.py (API)**

  • GET /global/plot/{id} and GET /local/plot/{id} now also load explanation_path (previously only plot_path/plots_path) and attach a "story" key ({"en": ..., "es": ..., ...} or null) to each artifact/group in the response.
  • Added _resolve_story_explainer() to reconstruct the explainer from its registered class + stored parameters (no trained model needed — story() never touches it) and _attach_stories()/_attach_one_story() to compute and attach stories per artifact, never raising: any failure (unbuildable explainer, mismatched shape) just leaves "story": null.
  • Added _as_group_target()/_as_artifact_target() to reconstruct a real (unvalidated) ArtifactGroup/Artifact from the wire-format dict that explainer_job.py actually persists (it normalizes plot()'s output before pickling), so story()'s isinstance checks work against real data, not just hand-built test objects.

DashAI/front/src/components/explainers/ (Frontend)

  • StoryBox.jsx: new component that reads the active i18next language from story and renders it as a plain "text" artifact through the existing ArtifactViewer — same box, same download button, nothing new to maintain visually.
  • ExplainersPlot.jsx: renders StoryBox under each grouped and ungrouped artifact.
  • utils/i18n/locales/{en,es,pt,de,zh}/explainers.json: added the storyTitle label.

Tests

  • tests/back/api/test_explainer_story_attach.py (new): covers _attach_stories against the real dict-shaped output explainer_job.py persists (not hand-built Pydantic objects), including the no-explainer no-op case.
  • tests/back/explainers/test_image_explainers.py, test_lib_explainers.py, test_new_explainers.py, test_task_explainers.py: updated assertions that expected the now-removed TextArtifact in plot()'s output; assert story()'s content directly instead.

Testing

  • Manually verified against real generated explanations (not just synthetic test data) for both global and local explainers, in multiple languages, including the flat-curve and zero-importance edge cases.
  • Reviewers should spot-check the wording of the non-English translations (es/pt/de/zh) in at least one explainer of each kind (global ranking, local per-instance, counterfactual). They were hand-translated, not machine-translated.

Creylay added 5 commits August 7, 2026 11:17
- Added story generation methods to RegressionKernelShap, RegressionPartialDependence, RegressionPermutationFeatureImportance, and TokenAblation explainers to provide narrative summaries of predictions and feature contributions.
- Updated plot methods to remove text artifacts and focus solely on visual representations.
- Introduced StoryBox component in the frontend to display narrative summaries alongside artifacts.
- Modified existing tests to validate the new story functionality and ensure compatibility with the updated plot outputs.
- Updated localization files to include new keys for narrative summaries in multiple languages.
…and regression explainers with multilingual support
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant