| 796 | |
| 797 | |
| 798 | def get_app( |
| 799 | store: "feast.FeatureStore", |
| 800 | project_id: str, |
| 801 | root_path: str = "", |
| 802 | ): |
| 803 | app = FastAPI() |
| 804 | |
| 805 | app.add_middleware( |
| 806 | CORSMiddleware, |
| 807 | allow_origins=["*"], |
| 808 | allow_credentials=True, |
| 809 | allow_methods=["*"], |
| 810 | allow_headers=["*"], |
| 811 | ) |
| 812 | |
| 813 | _setup_rest_mode(app, store) |
| 814 | |
| 815 | ui_dir_ref = importlib_resources.files(__spec__.parent) / "ui/build/" # type: ignore[name-defined, arg-type] |
| 816 | with importlib_resources.as_file(ui_dir_ref) as ui_dir: |
| 817 | projects_dict = _build_projects_list(store, project_id, root_path) |
| 818 | with ui_dir.joinpath("projects-list.json").open(mode="w") as f: |
| 819 | f.write(json.dumps(projects_dict)) |
| 820 | |
| 821 | @app.get("/api/mlflow-runs") |
| 822 | def get_mlflow_runs(max_results: int = 50): |
| 823 | """Return MLflow runs linked to this Feast project via auto-logging.""" |
| 824 | mlflow_cfg = getattr(store.config, "mlflow", None) |
| 825 | if not mlflow_cfg or not mlflow_cfg.enabled: |
| 826 | return {"runs": [], "mlflow_uri": None} |
| 827 | |
| 828 | try: |
| 829 | import mlflow |
| 830 | |
| 831 | tracking_uri = mlflow_cfg.get_tracking_uri() |
| 832 | mlflow_ui_base = tracking_uri or mlflow.get_tracking_uri() or "" |
| 833 | client = mlflow.MlflowClient(tracking_uri=tracking_uri) |
| 834 | |
| 835 | project_name = store.config.project |
| 836 | experiment = client.get_experiment_by_name(project_name) |
| 837 | if experiment is None: |
| 838 | return {"runs": [], "mlflow_uri": mlflow_ui_base or None} |
| 839 | experiment_ids = [experiment.experiment_id] |
| 840 | |
| 841 | safe_project = project_name.replace("\\", "\\\\").replace("'", "\\'") |
| 842 | filter_str = ( |
| 843 | f"tags.`feast.project` = '{safe_project}' " |
| 844 | f"AND tags.`feast.retrieval_type` != ''" |
| 845 | ) |
| 846 | |
| 847 | max_results = min(max(max_results, 1), 200) |
| 848 | runs = client.search_runs( |
| 849 | experiment_ids=experiment_ids, |
| 850 | filter_string=filter_str, |
| 851 | max_results=max_results, |
| 852 | order_by=["start_time DESC"], |
| 853 | ) |
| 854 | |
| 855 | run_id_to_models: Dict[str, List[dict]] = {} |