from __future__ import annotations import html import json from pathlib import Path from typing import Any import joblib def export_artifacts( run_id: str, state: dict[str, Any], run_directory: Path, ) -> dict[str, str]: run_directory.mkdir(parents=True, exist_ok=True) bundle = state["model_bundle"] summary = state["summary_payload"] pipeline_path = run_directory / "model_pipeline.joblib" joblib.dump(bundle.pipeline, pipeline_path) metrics_path = run_directory / "metrics.json" metrics_path.write_text(json.dumps(summary, indent=2, default=str), encoding="utf-8") model_card_path = run_directory / "MODEL_CARD.md" model_card_path.write_text(_model_card(summary), encoding="utf-8") report_path = run_directory / "analysis_report.html" report_path.write_text(_html_report(summary), encoding="utf-8") requirements_path = run_directory / "reproduction.json" requirements_path.write_text( json.dumps( { "run_id": run_id, "random_state": state["settings"].random_state, "test_size": state["settings"].test_size, "target": summary["profile"]["target"], "task_type": summary["profile"]["task_type"], "best_model": summary["best_model"], }, indent=2, ), encoding="utf-8", ) return { "pipeline": str(pipeline_path), "metrics": str(metrics_path), "model_card": str(model_card_path), "report": str(report_path), "reproduction": str(requirements_path), } def _model_card(run: dict[str, Any]) -> str: best = run["model_results"][0] profile = run["profile"] issues = ( "\n".join(f"- {item['message']}" for item in run["quality_issues"]) or "- None detected" ) return f"""# Model Card — {run["dataset_name"]} ## Model details - Run ID: `{run["run_id"]}` - Task: {profile["task_type"]} - Target: `{profile["target"]}` - Selected model: **{run["best_model"]}** - Training-CV selection metric: `{best["primary_metric"]} = {best["selection_score"]:.4f}` - One-time untouched test metric: `{best["primary_metric"]} = {best["final_test_score"]:.4f}` - Training rows before split: {profile["rows"]:,} ## Intended use Exploratory decision support and portfolio demonstration. Validate with domain-specific, out-of-time data before any consequential or production use. ## Evaluation ```json {json.dumps(best["final_test_metrics"], indent=2)} ``` ## Data-quality observations {issues} ## Explainability Method: **{run["explainability"]["method"]}**. Importance values are predictive associations, not evidence of causation. ## Limitations - Results depend on the uploaded dataset and chosen target. - Automated task inference can be wrong; a domain owner should confirm the objective. - Fairness, privacy, and legal review are outside the automatic approval gate. """ def _html_report(run: dict[str, Any]) -> str: best = run["model_results"][0] summary_items = "".join(f"
  • {html.escape(item)}
  • " for item in run["executive_summary"]) recommendations = "".join(f"
  • {html.escape(item)}
  • " for item in run["recommendations"]) issues = ( "".join( f"{html.escape(item['severity'])}{html.escape(item['code'])}" f"{html.escape(item['message'])}" for item in run["quality_issues"] ) or "No material flags" ) metrics = "".join( f"{html.escape(name)}{value:.4f}" for name, value in best["final_test_metrics"].items() ) return f""" DataPilot AI report

    DataPilot AI Analysis Report

    {html.escape(run["dataset_name"])} · Run {html.escape(run["run_id"])}

    Selected model

    {html.escape(run["best_model"])}

    Test {html.escape(best["primary_metric"])}

    {best["final_test_score"]:.3f}

    Rows analyzed

    {run["profile"]["rows"]:,}

    Executive findings

    Evaluation

    {metrics}
    MetricValue

    Data quality

    {issues}
    SeverityCodeObservation

    Recommendations

      {recommendations}

    Generated from computed evidence. Predictive findings do not establish causality.

    """