├── .devcontainer
├── devcontainer.json
└── on-create.sh
├── .dockerignore
├── .dvc
├── .gitignore
└── config
├── .dvcignore
├── .gitbook.yaml
├── .github
├── scripts
│ ├── jupyter-to-html.sh
│ └── transform-jupyter-python.mjs
├── share-actions
│ ├── get-bikes-dataset-cached
│ │ └── action.yml
│ ├── ui-node-pnpm-install
│ │ └── action.yml
│ └── ui-types-from-backend
│ │ └── action.yml
└── workflows
│ ├── docker.yml
│ ├── examples.yml
│ ├── main.yml
│ ├── release.yml
│ └── ui.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── biome.jsonc
├── config.json
├── config.yaml
├── docker
├── Dockerfile.service
├── Dockerfile.service.dev
└── Makefile
├── example_test.py
├── examples
├── cookbook
│ ├── descriptors.ipynb
│ └── metrics.ipynb
├── future_examples
│ ├── cloud_sdk.ipynb
│ ├── future_dashboads.ipynb
│ ├── future_reviews.py
│ ├── list_metrics.ipynb
│ ├── metric_workbench.ipynb
│ ├── prompt_registry.ipynb
│ └── upload_snapshots.ipynb
├── readme.md
└── service
│ ├── .gitignore
│ ├── README.md
│ ├── remote_demo_project.py
│ ├── run_service.sh
│ └── workspace_tutorial.ipynb
├── images
└── gh_header.png
├── requirements.dev.txt
├── requirements.min.txt
├── ruff.toml
├── setup.cfg
├── setup.py
├── setupbase.py
├── src
└── evidently
│ ├── __init__.py
│ ├── _pydantic_compat.py
│ ├── _registry.py
│ ├── _version.py
│ ├── cli
│ ├── __init__.py
│ ├── __main__.py
│ ├── demo_project.py
│ ├── legacy_ui.py
│ ├── main.py
│ └── ui.py
│ ├── core
│ ├── __init__.py
│ ├── _utils.py
│ ├── base_types.py
│ ├── compare.py
│ ├── container.py
│ ├── datasets.py
│ ├── metric_types.py
│ ├── preset_types.py
│ ├── registries
│ │ ├── __init__.py
│ │ ├── bound_tests.py
│ │ ├── column_conditions.py
│ │ ├── descriptors.py
│ │ ├── metric_results.py
│ │ ├── metric_tests.py
│ │ ├── metrics.py
│ │ └── presets.py
│ ├── report.py
│ ├── serialization.py
│ └── tests.py
│ ├── descriptors
│ ├── __init__.py
│ ├── _context_relevance.py
│ ├── _custom_descriptors.py
│ ├── _generate_descriptors.py
│ ├── _text_length.py
│ ├── generated_descriptors.py
│ └── llm_judges.py
│ ├── errors.py
│ ├── future
│ ├── __init__.py
│ ├── datasets.py
│ ├── descriptors
│ │ └── __init__.py
│ ├── generators
│ │ └── __init__.py
│ ├── metric_types.py
│ ├── metrics
│ │ └── __init__.py
│ ├── presets
│ │ └── __init__.py
│ ├── report.py
│ └── tests
│ │ └── __init__.py
│ ├── generators
│ ├── __init__.py
│ └── column.py
│ ├── legacy
│ ├── __init__.py
│ ├── __main__.py
│ ├── _config.py
│ ├── _registry.py
│ ├── base_metric.py
│ ├── calculation_engine
│ │ ├── __init__.py
│ │ ├── engine.py
│ │ ├── metric_implementation.py
│ │ └── python_engine.py
│ ├── calculations
│ │ ├── __init__.py
│ │ ├── classification_performance.py
│ │ ├── data_drift.py
│ │ ├── data_integration.py
│ │ ├── data_quality.py
│ │ ├── recommender_systems.py
│ │ ├── regression_performance.py
│ │ ├── stattests
│ │ │ ├── __init__.py
│ │ │ ├── anderson_darling_stattest.py
│ │ │ ├── chisquare_stattest.py
│ │ │ ├── cramer_von_mises_stattest.py
│ │ │ ├── energy_distance.py
│ │ │ ├── epps_singleton_stattest.py
│ │ │ ├── fisher_exact_stattest.py
│ │ │ ├── g_stattest.py
│ │ │ ├── hellinger_distance.py
│ │ │ ├── jensenshannon.py
│ │ │ ├── kl_div.py
│ │ │ ├── ks_stattest.py
│ │ │ ├── mann_whitney_urank_stattest.py
│ │ │ ├── mmd_stattest.py
│ │ │ ├── psi.py
│ │ │ ├── registry.py
│ │ │ ├── t_test.py
│ │ │ ├── text_content_drift.py
│ │ │ ├── text_content_drift_abs.py
│ │ │ ├── tvd_stattest.py
│ │ │ ├── utils.py
│ │ │ ├── wasserstein_distance_norm.py
│ │ │ └── z_stattest.py
│ │ └── utils.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── collector.py
│ │ ├── main.py
│ │ └── ui.py
│ ├── collector
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── client.py
│ │ ├── config.py
│ │ └── storage.py
│ ├── core.py
│ ├── dashboard
│ │ └── tabs
│ │ │ └── quality_metrics_options_example.ipynb
│ ├── descriptors
│ │ ├── BERTScore_descriptor.py
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── contains_link_descriptor.py
│ │ ├── custom_descriptor.py
│ │ ├── exact_match_descriptor.py
│ │ ├── hf_descriptor.py
│ │ ├── is_valid_json_descriptor.py
│ │ ├── is_valid_python_descriptor.py
│ │ ├── is_valid_sql_descriptor.py
│ │ ├── json_match_descriptor.py
│ │ ├── json_schema_match_descriptor.py
│ │ ├── llm_judges.py
│ │ ├── non_letter_character_percentage_descriptor.py
│ │ ├── oov_words_percentage_descriptor.py
│ │ ├── openai_descriptor.py
│ │ ├── regexp_descriptor.py
│ │ ├── semantic_similarity.py
│ │ ├── sentence_count_descriptor.py
│ │ ├── sentiment_descriptor.py
│ │ ├── text_contains_descriptor.py
│ │ ├── text_length_descriptor.py
│ │ ├── text_part_descriptor.py
│ │ ├── trigger_words_presence_descriptor.py
│ │ ├── word_count_descriptor.py
│ │ └── words_descriptor.py
│ ├── experimental
│ │ ├── __init__.py
│ │ └── report_set.py
│ ├── features
│ │ ├── BERTScore_feature.py
│ │ ├── OOV_words_percentage_feature.py
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── contains_link_feature.py
│ │ ├── custom_feature.py
│ │ ├── exact_match_feature.py
│ │ ├── feature_generator.py
│ │ ├── generated_features.py
│ │ ├── hf_feature.py
│ │ ├── is_valid_json_feature.py
│ │ ├── is_valid_python_feature.py
│ │ ├── is_valid_sql_feature.py
│ │ ├── json_match_feature.py
│ │ ├── json_schema_match_feature.py
│ │ ├── llm_judge.py
│ │ ├── non_letter_character_percentage_feature.py
│ │ ├── openai_feature.py
│ │ ├── regexp_feature.py
│ │ ├── semantic_similarity_feature.py
│ │ ├── sentence_count_feature.py
│ │ ├── sentiment_feature.py
│ │ ├── text_contains_feature.py
│ │ ├── text_length_feature.py
│ │ ├── text_part_feature.py
│ │ ├── trigger_words_presence_feature.py
│ │ ├── word_count_feature.py
│ │ └── words_feature.py
│ ├── metric_preset
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── classification_performance.py
│ │ ├── data_drift.py
│ │ ├── data_quality.py
│ │ ├── metric_preset.py
│ │ ├── recsys.py
│ │ ├── regression_performance.py
│ │ ├── target_drift.py
│ │ └── text_evals.py
│ ├── metric_results.py
│ ├── metrics
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── base_metric.py
│ │ ├── classification_performance
│ │ │ ├── __init__.py
│ │ │ ├── base_classification_metric.py
│ │ │ ├── class_balance_metric.py
│ │ │ ├── class_separation_metric.py
│ │ │ ├── classification_dummy_metric.py
│ │ │ ├── classification_quality_metric.py
│ │ │ ├── confusion_matrix_metric.py
│ │ │ ├── lift_curve_metric.py
│ │ │ ├── lift_table_metric.py
│ │ │ ├── objects.py
│ │ │ ├── pr_curve_metric.py
│ │ │ ├── pr_table_metric.py
│ │ │ ├── probability_distribution_metric.py
│ │ │ ├── quality_by_class_metric.py
│ │ │ ├── quality_by_feature_table.py
│ │ │ └── roc_curve_metric.py
│ │ ├── custom_metric.py
│ │ ├── data_drift
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── column_drift_metric.py
│ │ │ ├── column_interaction_plot.py
│ │ │ ├── column_value_plot.py
│ │ │ ├── data_drift_table.py
│ │ │ ├── dataset_drift_metric.py
│ │ │ ├── embedding_drift_methods.py
│ │ │ ├── embeddings_drift.py
│ │ │ ├── feature_importance.py
│ │ │ ├── target_by_features_table.py
│ │ │ ├── text_descriptors_drift_metric.py
│ │ │ ├── text_domain_classifier_drift_metric.py
│ │ │ └── text_metric.py
│ │ ├── data_integrity
│ │ │ ├── __init__.py
│ │ │ ├── column_missing_values_metric.py
│ │ │ ├── column_regexp_metric.py
│ │ │ ├── column_summary_metric.py
│ │ │ ├── dataset_missing_values_metric.py
│ │ │ └── dataset_summary_metric.py
│ │ ├── data_quality
│ │ │ ├── __init__.py
│ │ │ ├── column_category_metric.py
│ │ │ ├── column_correlations_metric.py
│ │ │ ├── column_distribution_metric.py
│ │ │ ├── column_quantile_metric.py
│ │ │ ├── column_value_list_metric.py
│ │ │ ├── column_value_range_metric.py
│ │ │ ├── conflict_prediction_metric.py
│ │ │ ├── conflict_target_metric.py
│ │ │ ├── dataset_correlations_metric.py
│ │ │ ├── stability_metric.py
│ │ │ ├── text_descriptors_correlation_metric.py
│ │ │ └── text_descriptors_distribution.py
│ │ ├── recsys
│ │ │ ├── __init__.py
│ │ │ ├── base_top_k.py
│ │ │ ├── diversity.py
│ │ │ ├── f_beta_top_k.py
│ │ │ ├── hit_rate_k.py
│ │ │ ├── item_bias.py
│ │ │ ├── map_k.py
│ │ │ ├── mar_k.py
│ │ │ ├── mrr.py
│ │ │ ├── ndcg_k.py
│ │ │ ├── novelty.py
│ │ │ ├── pairwise_distance.py
│ │ │ ├── personalisation.py
│ │ │ ├── popularity_bias.py
│ │ │ ├── precision_recall_k.py
│ │ │ ├── precision_top_k.py
│ │ │ ├── rec_examples.py
│ │ │ ├── recall_top_k.py
│ │ │ ├── scores_distribution.py
│ │ │ ├── serendipity.py
│ │ │ ├── train_stats.py
│ │ │ └── user_bias.py
│ │ ├── regression_performance
│ │ │ ├── __init__.py
│ │ │ ├── abs_perc_error_in_time.py
│ │ │ ├── error_bias_table.py
│ │ │ ├── error_distribution.py
│ │ │ ├── error_in_time.py
│ │ │ ├── error_normality.py
│ │ │ ├── objects.py
│ │ │ ├── predicted_and_actual_in_time.py
│ │ │ ├── predicted_vs_actual.py
│ │ │ ├── regression_dummy_metric.py
│ │ │ ├── regression_performance_metrics.py
│ │ │ ├── regression_quality.py
│ │ │ ├── top_error.py
│ │ │ ├── utils.py
│ │ │ └── visualization.py
│ │ └── utils.py
│ ├── model
│ │ ├── __init__.py
│ │ ├── dashboard.py
│ │ └── widget.py
│ ├── options
│ │ ├── __init__.py
│ │ ├── agg_data.py
│ │ ├── base.py
│ │ ├── color_scheme.py
│ │ ├── data_drift.py
│ │ ├── option.py
│ │ └── quality_metrics.py
│ ├── pipeline
│ │ ├── __init__.py
│ │ └── column_mapping.py
│ ├── renderers
│ │ ├── __init__.py
│ │ ├── base_renderer.py
│ │ ├── html_widgets.py
│ │ └── render_utils.py
│ ├── report
│ │ ├── __init__.py
│ │ └── report.py
│ ├── runner
│ │ ├── __init__.py
│ │ ├── loader.py
│ │ └── runner.py
│ ├── spark
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── calculations
│ │ │ ├── __init__.py
│ │ │ ├── data_drift.py
│ │ │ ├── histogram.py
│ │ │ └── stattests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── chisquare.py
│ │ │ │ ├── jensenshannon.py
│ │ │ │ ├── psi.py
│ │ │ │ ├── utils.py
│ │ │ │ └── wasserstein.py
│ │ ├── engine.py
│ │ ├── metrics
│ │ │ ├── __init__.py
│ │ │ ├── data_drift.py
│ │ │ └── feature_importance.py
│ │ ├── utils.py
│ │ └── visualizations.py
│ ├── suite
│ │ ├── __init__.py
│ │ └── base_suite.py
│ ├── test_preset
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── classification_binary.py
│ │ ├── classification_binary_topk.py
│ │ ├── classification_multiclass.py
│ │ ├── data_drift.py
│ │ ├── data_quality.py
│ │ ├── data_stability.py
│ │ ├── no_target_performance.py
│ │ ├── recsys.py
│ │ ├── regression.py
│ │ └── test_preset.py
│ ├── test_suite
│ │ ├── __init__.py
│ │ └── test_suite.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── base_test.py
│ │ ├── classification_performance_tests.py
│ │ ├── custom_test.py
│ │ ├── data_drift_tests.py
│ │ ├── data_integrity_tests.py
│ │ ├── data_quality_tests.py
│ │ ├── recsys_tests.py
│ │ ├── regression_performance_tests.py
│ │ └── utils.py
│ ├── ui
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── projects.py
│ │ │ ├── service.py
│ │ │ └── static.py
│ │ ├── app.py
│ │ ├── assets
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ ├── manifest.json
│ │ │ ├── robots.txt
│ │ │ └── static
│ │ │ │ ├── css
│ │ │ │ └── index-CJbKDbyR.css
│ │ │ │ └── js
│ │ │ │ ├── WidgetsContent-CSRajGBd.js
│ │ │ │ ├── dashboard-main-BGHDi9oT.js
│ │ │ │ ├── index-Nx_mkSx_.js
│ │ │ │ └── snapshot-view-main-Z97zaUJO.js
│ │ ├── base.py
│ │ ├── components
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── local_storage.py
│ │ │ ├── security.py
│ │ │ ├── storage.py
│ │ │ └── telemetry.py
│ │ ├── config.py
│ │ ├── dashboards
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── reports.py
│ │ │ ├── test_suites.py
│ │ │ └── utils.py
│ │ ├── datasets.py
│ │ ├── demo_projects
│ │ │ ├── __init__.py
│ │ │ ├── adult.py
│ │ │ ├── base.py
│ │ │ ├── bikes.py
│ │ │ ├── bikes_v2.py
│ │ │ ├── reviews.py
│ │ │ ├── reviews_v2.py
│ │ │ └── simple.py
│ │ ├── errors.py
│ │ ├── example.ipynb
│ │ ├── local_service.py
│ │ ├── managers
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── base.py
│ │ │ └── projects.py
│ │ ├── remote.py
│ │ ├── security
│ │ │ ├── __init__.py
│ │ │ ├── no_security.py
│ │ │ ├── service.py
│ │ │ └── token.py
│ │ ├── storage
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── config.py
│ │ │ ├── local
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── watcher.py
│ │ │ └── utils.py
│ │ ├── type_aliases.py
│ │ ├── utils.py
│ │ └── workspace
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── cloud.py
│ │ │ ├── remote.py
│ │ │ └── view.py
│ └── utils
│ │ ├── __init__.py
│ │ ├── dashboard.py
│ │ ├── data_drift_utils.py
│ │ ├── data_operations.py
│ │ ├── data_preprocessing.py
│ │ ├── generators.py
│ │ ├── llm
│ │ ├── __init__.py
│ │ ├── _registry.py
│ │ ├── base.py
│ │ ├── errors.py
│ │ ├── prompts.py
│ │ └── wrapper.py
│ │ ├── numpy_encoder.py
│ │ ├── sync.py
│ │ ├── types.py
│ │ └── visualizations.py
│ ├── llm
│ ├── __init__.py
│ ├── options.py
│ └── templates.py
│ ├── metrics
│ ├── __init__.py
│ ├── _legacy.py
│ ├── classification.py
│ ├── column_statistics.py
│ ├── dataset_statistics.py
│ ├── group_by.py
│ ├── recsys.py
│ └── regression.py
│ ├── nbextension
│ ├── __init__.py
│ └── static
│ │ ├── extension.js
│ │ ├── index.js
│ │ ├── index.js.LICENSE.txt
│ │ └── material-ui-icons.woff2
│ ├── presets
│ ├── __init__.py
│ ├── classification.py
│ ├── dataset_stats.py
│ ├── drift.py
│ └── regression.py
│ ├── pydantic_utils.py
│ ├── sdk
│ ├── __init__.py
│ ├── models.py
│ ├── panels.py
│ └── prompts.py
│ ├── telemetry.py
│ ├── tests
│ ├── __init__.py
│ ├── aliases.py
│ ├── categorical_tests.py
│ ├── descriptors.py
│ ├── numerical_tests.py
│ └── reference.py
│ ├── ui
│ ├── __init__.py
│ ├── backport.py
│ ├── service
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── projects.py
│ │ │ ├── service.py
│ │ │ └── static.py
│ │ ├── app.py
│ │ ├── assets
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ ├── manifest.json
│ │ │ ├── robots.txt
│ │ │ └── static
│ │ │ │ ├── css
│ │ │ │ └── index-CJbKDbyR.css
│ │ │ │ └── js
│ │ │ │ ├── dashboard-main-CItiR2E4.js
│ │ │ │ ├── defaultLocale-B_SPPAJR.js
│ │ │ │ ├── index-AnvlphjY.js
│ │ │ │ └── snapshot-view-main-C7vBwLih.js
│ │ ├── base.py
│ │ ├── components
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── dashboard.py
│ │ │ ├── local_storage.py
│ │ │ ├── security.py
│ │ │ ├── storage.py
│ │ │ └── telemetry.py
│ │ ├── config.py
│ │ ├── datasets.py
│ │ ├── demo_projects
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ └── bikes.py
│ │ ├── errors.py
│ │ ├── local_service.py
│ │ ├── managers
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── base.py
│ │ │ └── projects.py
│ │ ├── security
│ │ │ ├── __init__.py
│ │ │ ├── no_security.py
│ │ │ ├── service.py
│ │ │ └── token.py
│ │ ├── services
│ │ │ ├── __init__.py
│ │ │ └── dashbord
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── file.py
│ │ ├── storage
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── config.py
│ │ │ ├── fslocation.py
│ │ │ ├── local
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── watcher.py
│ │ │ └── utils.py
│ │ ├── type_aliases.py
│ │ ├── utils.py
│ │ └── workspace
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ └── view.py
│ ├── storage
│ │ ├── __init__.py
│ │ └── local
│ │ │ ├── __init__.py
│ │ │ └── base.py
│ ├── utils.py
│ └── workspace.py
│ └── utils
│ ├── __init__.py
│ └── llm
│ ├── __init__.py
│ └── wrapper.py
├── test_data
├── adults.CITATION
├── adults.parquet
└── reviews.parquet
├── tests
├── __init__.py
├── calculation_engine
│ ├── __init__.py
│ └── test_python_engine.py
├── calculations
│ ├── __init__.py
│ ├── stattests
│ │ ├── __init__.py
│ │ ├── test_get_stattest.py
│ │ └── test_utils.py
│ ├── test_classification_performance.py
│ ├── test_data_clean.py
│ ├── test_data_drift.py
│ ├── test_data_integration.py
│ ├── test_data_quality.py
│ └── test_recommender_systems.py
├── cli
│ ├── __init__.py
│ └── test_ui.py
├── collector
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_app.py
│ ├── test_client.py
│ └── test_config.py
├── conftest.py
├── dataset_generator
│ └── __init__.py
├── features
│ ├── __init__.py
│ ├── test_OOV_words_percentage_feature.py
│ ├── test_bertscore_feature.py
│ ├── test_contains_link_feature.py
│ ├── test_custom_feature.py
│ ├── test_exact_feature.py
│ ├── test_is_valid_json_feature.py
│ ├── test_is_valid_python_feature.py
│ ├── test_is_valid_sql_feature.py
│ ├── test_json_match.py
│ ├── test_json_schema_match_feature.py
│ ├── test_llm_judge.py
│ ├── test_multicolumn.py
│ ├── test_non_letter_character_percentage_feature.py
│ ├── test_text_contains_feature.py
│ ├── test_text_length_feature.py
│ ├── test_text_part_feature.py
│ ├── test_trigger_words_present_feature.py
│ └── test_words_feature.py
├── future
│ ├── __init__.py
│ ├── descriptors
│ │ ├── __init__.py
│ │ ├── test_conditions.py
│ │ ├── test_descriptors.py
│ │ └── test_feature_descriptors.py
│ ├── generators
│ │ ├── __init__.py
│ │ └── test_generator.py
│ ├── metrics
│ │ ├── __init__.py
│ │ ├── all_metrics_tests.py
│ │ ├── category_count.py
│ │ ├── test_in_range_metric.py
│ │ ├── test_list_metrics.py
│ │ ├── test_min_metric.py
│ │ ├── test_missing_count.py
│ │ ├── test_out_range_metric.py
│ │ └── test_test_fields.py
│ ├── presets
│ │ ├── __init__.py
│ │ ├── dataset_stats.py
│ │ ├── regression.py
│ │ ├── test_serialization.py
│ │ └── test_test_fields.py
│ ├── report
│ │ ├── __init__.py
│ │ └── test_report.py
│ ├── test_data_definition.py
│ └── test_ui
│ │ ├── __init__.py
│ │ └── test_workspace
│ │ ├── __init__.py
│ │ └── test_local.py
├── metric_preset
│ ├── __init__.py
│ ├── test_all_metrics_presets.py
│ ├── test_data_quality.py
│ └── test_target_drift.py
├── metrics
│ ├── __init__.py
│ ├── data_drift
│ │ ├── __init__.py
│ │ ├── test_column_drift_metric.py
│ │ ├── test_column_value_plot.py
│ │ ├── test_data_drift_table.py
│ │ ├── test_dataset_drift_metric.py
│ │ └── test_target_by_features_table.py
│ ├── data_interity
│ │ ├── __init__.py
│ │ ├── test_column_missing_values_metric.py
│ │ ├── test_column_regexp_metric.py
│ │ ├── test_column_summary_metric.py
│ │ ├── test_dataset_missing_values_metric.py
│ │ └── test_dataset_summary_metric.py
│ ├── data_quality
│ │ ├── __init__.py
│ │ ├── test_column_correlations_metric.py
│ │ ├── test_column_distribution_metric.py
│ │ ├── test_column_quantile_metric.py
│ │ ├── test_column_value_list_metric.py
│ │ ├── test_column_value_range_metric.py
│ │ ├── test_dataset_correlations_metric.py
│ │ └── test_stability_metric.py
│ ├── recsys
│ │ ├── __init__.py
│ │ ├── test_diversity.py
│ │ ├── test_f_beta_top_k.py
│ │ ├── test_hit_rate_k.py
│ │ ├── test_map_k.py
│ │ ├── test_mar_k.py
│ │ ├── test_mrr.py
│ │ ├── test_ndcg_k.py
│ │ ├── test_novelty.py
│ │ ├── test_pairwise_distances.py
│ │ ├── test_personalisation.py
│ │ ├── test_popularity_bias.py
│ │ ├── test_precision_top_k.py
│ │ ├── test_recall_top_k.py
│ │ ├── test_scores_distribution.py
│ │ └── test_serendipity.py
│ ├── regression_performance
│ │ ├── __init__.py
│ │ ├── test_error_bias_table.py
│ │ └── test_regression_performance_metrics.py
│ ├── test_base_metric.py
│ └── test_metrics_json_representation.py
├── multitest
│ ├── __init__.py
│ ├── conftest.py
│ ├── datasets.py
│ └── metrics
│ │ ├── __init__.py
│ │ ├── classification.py
│ │ ├── conftest.py
│ │ ├── custom.py
│ │ ├── data_drift.py
│ │ ├── data_integrity.py
│ │ ├── data_quality.py
│ │ ├── recsys.py
│ │ ├── regression.py
│ │ └── test_all.py
├── options
│ ├── __init__.py
│ ├── test_base.py
│ └── test_data_drift.py
├── report
│ ├── __init__.py
│ ├── test_report.py
│ └── test_report_profile.py
├── spark
│ ├── __init__.py
│ └── metrics
│ │ ├── __init__.py
│ │ └── test_data_drift.py
├── stattests
│ ├── __init__.py
│ ├── test_registry.py
│ └── test_stattests.py
├── test_core.py
├── test_metric_results.py
├── test_preset
│ ├── __init__.py
│ ├── test_classification_multiclass.py
│ ├── test_data_drift.py
│ ├── test_data_drift_preset.py
│ ├── test_data_quality.py
│ ├── test_data_stability.py
│ ├── test_no_target_performance.py
│ └── test_no_target_performance_preset.py
├── test_pydantic_aliases.py
├── test_pydantic_compat.py
├── test_setup.py
├── test_suite
│ ├── __init__.py
│ ├── test_test_suite.py
│ └── test_test_suite_loading.py
├── test_torch_numpy.py
├── test_utils.py
├── tests
│ ├── __init__.py
│ ├── test_base_tests.py
│ ├── test_classification_performance_tests.py
│ ├── test_custom_test.py
│ ├── test_data_drift_tests.py
│ ├── test_data_integrity_tests.py
│ ├── test_data_quality_tests.py
│ ├── test_regression_performance_tests.py
│ └── test_utils.py
├── ui
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_app.py
│ ├── test_dashboards.py
│ ├── test_demo_project.py
│ └── test_ui_basic.py
└── utils
│ ├── __init__.py
│ ├── test_data_preprocessing.py
│ ├── test_numpy_encoder.py
│ └── test_pydantic_utils.py
└── ui
├── .gitignore
├── README.md
├── html-visual-testing
├── .gitignore
├── README.md
├── package.json
├── playwright.config.ts
└── tests
│ ├── .gitignore
│ ├── helpers.ts
│ ├── visual.spec.ts
│ └── visual.spec.ts-snapshots.dvc
├── package.json
├── packages
└── evidently-ui-lib
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── src
│ ├── api
│ │ ├── JsonParser.ts
│ │ ├── client-heplers.ts
│ │ ├── index.tsx
│ │ ├── types
│ │ │ ├── index.ts
│ │ │ ├── utils.ts
│ │ │ └── v2.ts
│ │ └── utils.ts
│ ├── components
│ │ ├── AlertThemed.tsx
│ │ ├── AutoTabs.tsx
│ │ ├── BaseTabs.tsx
│ │ ├── DashboardDateFilter.tsx
│ │ ├── DashboardWidgets.tsx
│ │ ├── DiscordSvg.tsx
│ │ ├── DownloadButton.tsx
│ │ ├── HidedTags.tsx
│ │ ├── JsonView.tsx
│ │ ├── LoadableVIew.tsx
│ │ ├── LogoSvg.tsx
│ │ ├── OnClickedPoint.tsx
│ │ ├── Plot.tsx
│ │ ├── ProjectCard.tsx
│ │ ├── ProjectLayout.tsx
│ │ ├── ServiceHeader.tsx
│ │ ├── TextWithCopyIcon.tsx
│ │ ├── ThemeToggle.tsx
│ │ ├── WidgetGroup.tsx
│ │ ├── WidgetsContent.tsx
│ │ └── v2
│ │ │ └── Dashboard
│ │ │ ├── HelperComponents
│ │ │ ├── DrawDashboardPanels.tsx
│ │ │ └── RenderPanelByDataFetchGeneralComponent.tsx
│ │ │ ├── Panels
│ │ │ ├── DashboardPanel.tsx
│ │ │ ├── Skeleton.tsx
│ │ │ ├── implementations
│ │ │ │ ├── Counter.tsx
│ │ │ │ ├── Pie.tsx
│ │ │ │ ├── Plot.tsx
│ │ │ │ ├── Text.tsx
│ │ │ │ └── helpers
│ │ │ │ │ ├── general.tsx
│ │ │ │ │ ├── mui.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ └── types.tsx
│ │ │ └── utils.tsx
│ ├── contexts
│ │ ├── DashboardContext.tsx
│ │ ├── DashboardViewParams.tsx
│ │ ├── DashboardViewParamsV2.tsx
│ │ └── WidgetWrapper.tsx
│ ├── hooks
│ │ ├── index.tsx
│ │ ├── theme.ts
│ │ └── useUpdateQueryStringValueWithoutNavigation.tsx
│ ├── router-utils
│ │ ├── components
│ │ │ ├── breadcrumbs.tsx
│ │ │ ├── error.tsx
│ │ │ ├── navigation-progress.tsx
│ │ │ └── navigations.tsx
│ │ ├── fetchers.tsx
│ │ ├── hooks.tsx
│ │ ├── router-builder.tsx
│ │ ├── types.ts
│ │ └── utils.tsx
│ ├── routes-components
│ │ ├── dashboard
│ │ │ └── index.tsx
│ │ ├── snapshotId
│ │ │ └── index.tsx
│ │ └── snapshots
│ │ │ └── index.tsx
│ ├── shared-dependencies
│ │ ├── mui-icons-material.tsx
│ │ ├── mui-material.tsx
│ │ ├── openapi-fetch.tsx
│ │ ├── react-hook-form.tsx
│ │ ├── react-router-dom.tsx
│ │ └── zod.tsx
│ ├── standalone
│ │ └── app.tsx
│ ├── theme
│ │ └── index.tsx
│ ├── utils
│ │ └── index.tsx
│ └── widgets
│ │ ├── AlertBlock.tsx
│ │ ├── AlertStatBlock.tsx
│ │ ├── BigGraphWidgetContent.tsx
│ │ ├── BigTableWidget
│ │ ├── BigTableDetails.tsx
│ │ ├── BigTableWidgetContent.tsx
│ │ ├── GraphDetails.tsx
│ │ ├── HistogramGraphColumn.tsx
│ │ ├── LineGraphColumn.tsx
│ │ └── ScatterGraphColumn.tsx
│ │ ├── CounterWidgetContent.tsx
│ │ ├── InsightBlock.tsx
│ │ ├── NotImplementedWidgetContent.tsx
│ │ ├── ProgressWidgetContent.tsx
│ │ ├── RichDataWidget.tsx
│ │ ├── TabbedGraphWidgetContent.tsx
│ │ ├── TabbedWidgetContent.tsx
│ │ ├── TableWidgetContent.tsx
│ │ ├── TestSuiteWidget
│ │ ├── TestData.tsx
│ │ └── TestSuiteWidgetContent.tsx
│ │ ├── TextWidgetContent.tsx
│ │ ├── Widget.tsx
│ │ ├── WidgetList.tsx
│ │ ├── WidgetPanel.tsx
│ │ └── WidgetRenderer.tsx
│ └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── service
├── .gitignore
├── README.md
├── index.html
├── package.json
├── playwright.config.ts
├── public
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── api
│ │ └── index.ts
│ ├── index.css
│ ├── main.tsx
│ ├── routes
│ │ ├── components.tsx
│ │ ├── hooks.tsx
│ │ ├── router.tsx
│ │ ├── src
│ │ │ ├── dashboard
│ │ │ │ ├── dashboard-main.tsx
│ │ │ │ └── import.tsx
│ │ │ ├── home
│ │ │ │ ├── components.tsx
│ │ │ │ ├── home-main.tsx
│ │ │ │ └── import.tsx
│ │ │ ├── index.tsx
│ │ │ ├── project
│ │ │ │ ├── import.tsx
│ │ │ │ └── project-main.tsx
│ │ │ ├── projects-layout
│ │ │ │ ├── import.tsx
│ │ │ │ └── projects-layout-main.tsx
│ │ │ ├── projects-list
│ │ │ │ ├── components.tsx
│ │ │ │ ├── import.tsx
│ │ │ │ └── projects-list-main.tsx
│ │ │ ├── reports-layout
│ │ │ │ ├── import.tsx
│ │ │ │ └── reports-layout-main.tsx
│ │ │ ├── reports-list
│ │ │ │ ├── import.tsx
│ │ │ │ └── reports-list-main.tsx
│ │ │ ├── snapshot-view
│ │ │ │ ├── import.tsx
│ │ │ │ └── snapshot-view-main.tsx
│ │ │ ├── test-suites-layout
│ │ │ │ ├── import.tsx
│ │ │ │ └── test-suites-layout-main.tsx
│ │ │ └── test-suites-list
│ │ │ │ ├── import.tsx
│ │ │ │ └── test-suites-list-main.tsx
│ │ └── types.tsx
│ └── vite-env.d.ts
├── tests
│ ├── .gitignore
│ ├── smoke.spec.ts
│ ├── visual.spec.ts
│ └── visual.spec.ts-snapshots.dvc
├── tsconfig.json
└── vite.config.ts
├── service_v2
├── .gitignore
├── README.md
├── index.html
├── package.json
├── playwright.config.ts
├── public
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── Components
│ │ ├── DashboardPanel.tsx
│ │ └── GoToSnapshotButton.tsx
│ ├── api
│ │ └── index.ts
│ ├── contexts
│ │ └── project.tsx
│ ├── index.css
│ ├── main.tsx
│ ├── routes
│ │ ├── components.tsx
│ │ ├── hooks.tsx
│ │ ├── router.tsx
│ │ ├── src
│ │ │ ├── dashboard
│ │ │ │ ├── dashboard-main.tsx
│ │ │ │ └── import.tsx
│ │ │ ├── home
│ │ │ │ ├── components.tsx
│ │ │ │ ├── home-main.tsx
│ │ │ │ └── import.tsx
│ │ │ ├── index.tsx
│ │ │ ├── load-panel-points
│ │ │ │ ├── import.tsx
│ │ │ │ └── load-panel-points-main.tsx
│ │ │ ├── project
│ │ │ │ ├── import.tsx
│ │ │ │ └── project-main.tsx
│ │ │ ├── projects-layout
│ │ │ │ ├── import.tsx
│ │ │ │ └── projects-layout-main.tsx
│ │ │ ├── projects-list
│ │ │ │ ├── components.tsx
│ │ │ │ ├── import.tsx
│ │ │ │ └── projects-list-main.tsx
│ │ │ ├── reports-layout
│ │ │ │ ├── import.tsx
│ │ │ │ └── reports-layout-main.tsx
│ │ │ ├── reports-list
│ │ │ │ ├── import.tsx
│ │ │ │ └── reports-list-main.tsx
│ │ │ └── snapshot-view
│ │ │ │ ├── import.tsx
│ │ │ │ └── snapshot-view-main.tsx
│ │ └── types.tsx
│ └── vite-env.d.ts
├── tests
│ ├── .gitignore
│ ├── smoke.spec.ts
│ ├── visual.spec.ts
│ └── visual.spec.ts-snapshots.dvc
├── tsconfig.json
└── vite.config.ts
├── standalone
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── main.tsx
│ └── vite-env.d.ts
├── tsconfig.json
└── vite.config.ts
└── tsconfig.base.ui.json
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Default Linux Universal",
3 | "image": "mcr.microsoft.com/devcontainers/universal:2",
4 | "onCreateCommand": "./.devcontainer/on-create.sh",
5 | "postAttachCommand": {
6 | "ui": "source ./venv/bin/activate && evidently ui --port 8000 --demo-projects all --workspace test-workspace"
7 | },
8 | "forwardPorts": [8000],
9 | "portsAttributes": {
10 | "8000": {
11 | "label": "evidently UI",
12 | "onAutoForward": "openBrowser"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.devcontainer/on-create.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | virtualenv venv
5 | source ./venv/bin/activate
6 | pip install -e ".[dev]"
7 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | ui
2 |
--------------------------------------------------------------------------------
/.dvc/.gitignore:
--------------------------------------------------------------------------------
1 | /config.local
2 | /tmp
3 | /cache
4 |
--------------------------------------------------------------------------------
/.dvc/config:
--------------------------------------------------------------------------------
1 | [core]
2 | remote = gs
3 | ['remote "gs"']
4 | url = gs://evidently-service-visual-testing
5 |
--------------------------------------------------------------------------------
/.dvcignore:
--------------------------------------------------------------------------------
1 | # Add patterns of files dvc should ignore, which could improve
2 | # the performance. Learn more at
3 | # https://dvc.org/doc/user-guide/dvcignore
4 |
--------------------------------------------------------------------------------
/.gitbook.yaml:
--------------------------------------------------------------------------------
1 | root: ./docs/book/
2 |
3 | structure:
4 | readme: README.md
5 | summary: SUMMARY.md
6 |
--------------------------------------------------------------------------------
/.github/scripts/transform-jupyter-python.mjs:
--------------------------------------------------------------------------------
1 | import { readFileSync, writeFileSync, lstatSync } from 'node:fs'
2 |
3 | const filePath = process.argv[2]
4 |
5 | if (!lstatSync(filePath).isFile()) {
6 | throw `${filePath} is not a file`
7 | }
8 |
9 | const pythonFile = readFileSync(filePath, { encoding: 'utf-8' })
10 |
11 | const pythonFileTransformed = pythonFile
12 | .replace(/^(.+) = (.+.run\(.+)\n^\1/gm, '$1 = $2\n$1.save_html("$1.html")')
13 |
14 | writeFileSync(filePath, pythonFileTransformed)
15 |
--------------------------------------------------------------------------------
/.github/share-actions/get-bikes-dataset-cached/action.yml:
--------------------------------------------------------------------------------
1 | name: Get bikes dataset cached
2 | runs:
3 | using: "composite"
4 | steps:
5 | - uses: actions/cache@v4
6 | id: cache-bikes-dataset
7 | env:
8 | cache-name: cache-bikes-dataset
9 | with:
10 | path: Bike-Sharing-Dataset.zip
11 | key: cache-bikes-dataset
12 | enableCrossOsArchive: true
13 |
14 | - name: Download test data
15 | if: ${{ steps.cache-bikes-dataset.outputs.cache-hit != 'true' }}
16 | run: curl -k https://archive.ics.uci.edu/static/public/275/bike+sharing+dataset.zip -o Bike-Sharing-Dataset.zip
17 | shell: bash
18 |
--------------------------------------------------------------------------------
/.github/share-actions/ui-node-pnpm-install/action.yml:
--------------------------------------------------------------------------------
1 | name: UI install
2 | inputs:
3 | args:
4 | type: string
5 | description: ""
6 | required: false
7 | default: ""
8 | runs:
9 | using: "composite"
10 | steps:
11 | - uses: pnpm/action-setup@v3
12 | with:
13 | version: 9
14 |
15 | - name: Use Node.js 20
16 | uses: actions/setup-node@v4
17 | with:
18 | node-version: 20
19 | cache: "pnpm"
20 | cache-dependency-path: ui/pnpm-lock.yaml
21 |
22 | - name: 📥 Install node dependencies
23 | working-directory: ui
24 | run: pnpm i --frozen-lockfile --ignore-scripts ${{ inputs.args }}
25 | shell: bash
26 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------
1 | name: Publish on Docker Hub
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | latest:
7 | type: boolean
8 | default: false
9 | description: "Add latest tag"
10 |
11 | jobs:
12 | build_and_pub_docker:
13 | runs-on: [ ubuntu-22.04 ]
14 | steps:
15 | - name: Login to docker.io
16 | run: echo ${{ secrets.DOCKER_PWD }} | docker login -u ${{ secrets.DOCKER_LOGIN }} --password-stdin
17 | - uses: actions/checkout@master
18 | - name: setup builder
19 | run: docker buildx create --name mybuilder --bootstrap --use
20 | - name: Build and release latest image
21 | if: ${{ inputs.latest }}
22 | run: cd docker && make release
23 | - name: Build and push image
24 | if: ${{ ! inputs.latest }}
25 | run: cd docker && make buildx
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.egg-info
2 | venv
3 | .venv*
4 | .vscode
5 | .DS_Store
6 | examples/.DS_Store
7 | example_scripts
8 | .ipynb_checkpoints
9 | .idea
10 | .mypy_cache
11 | .pytest_cache
12 | dist
13 | build
14 | MANIFEST
15 |
16 | profile.json
17 |
18 | __pycache__
19 |
20 | evidently-openapi-schema.yml
21 | evidently-v2-openapi-schema
22 |
23 | # see .devcontainer/devcontainer.json
24 | test-workspace
25 | workspace-for-visual-testing
26 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: "v4.6.0"
4 | hooks:
5 | - id: check-case-conflict
6 | - id: check-merge-conflict
7 | - id: check-toml
8 | - id: check-yaml
9 | exclude: '(docs|examples)/.*'
10 | - id: end-of-file-fixer
11 | exclude: '(docs|examples)/.*'
12 | - id: trailing-whitespace
13 | exclude: '(docs|examples)/.*'
14 |
15 | - repo: https://github.com/astral-sh/ruff-pre-commit
16 | rev: "v0.3.7"
17 | hooks:
18 | - id: ruff
19 | args: [--exit-non-zero-on-fix, --fix]
20 | - id: ruff-format
21 |
22 | - repo: https://github.com/biomejs/pre-commit
23 | rev: "v0.4.0"
24 | hooks:
25 | - id: biome-check
26 | additional_dependencies: ["@biomejs/biome@1.8.3"]
27 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include setupbase.py
2 | include README.md
3 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "data_format": {
3 | "separator": ",",
4 | "header": true,
5 | "date_column": "dteday"
6 | },
7 | "column_mapping" : {},
8 | "dashboard_tabs": {
9 | "data_drift": {
10 | },
11 | "cat_target_drift":{
12 | "verbose_level": 0
13 | }
14 | },
15 | "options": {
16 | "data_drift": {
17 | "confidence": 0.95,
18 | "drift_share": 0.5,
19 | "nbinsx": null,
20 | "xbins": null
21 | }
22 | },
23 | "pretty_print": true,
24 | "sampling": {
25 | "reference": {
26 | "type": "none",
27 | "n": 1,
28 | "ratio": 0.1
29 | },
30 | "current": {
31 | "type": "nth",
32 | "n": 2,
33 | "ratio": 0.1
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/config.yaml:
--------------------------------------------------------------------------------
1 | data_format:
2 | separator: ","
3 | header: true
4 | date_column: "dteday"
5 | column_mapping: {}
6 | profile_sections:
7 | - data_drift:
8 | xbins:
9 | nbinsx:
10 | drift_share: 0.5
11 | pretty_print: true
12 | sampling:
13 | reference:
14 | type: "simple" # could be "none", "simple", "random"
15 | n: 5 # used with simple sampling, number of rows to skip
16 | ratio: 0.1 # used with random sampling, part of data to take from chunk
17 | random_seed: 4 # used with random sampling, used as seed for random generator
18 | current:
19 | type: "nth" # could be "none", "simple", "random"
20 | n: 5 # used with simple sampling, number of rows to skip
21 | ratio: 0.1 # used with random sampling, part of data to take from chunk
22 |
--------------------------------------------------------------------------------
/docker/Dockerfile.service:
--------------------------------------------------------------------------------
1 | FROM python:3.10-slim
2 | ARG BUILD_DATE
3 | ARG VCS_REF
4 | ARG VERSION
5 | LABEL org.label-schema.build-date=$BUILD_DATE \
6 | org.label-schema.name="Evidently AI Service" \
7 | org.label-schema.url="https://github.com/evidentlyai/evidently" \
8 | org.label-schema.vcs-ref=$VCS_REF \
9 | org.label-schema.vcs-url="https://github.com/evidentlyai/evidently" \
10 | org.label-schema.version=$VERSION \
11 | org.label-schema.schema-version="1.0"
12 | LABEL maintainer="mike0sv@evidentlyai.com"
13 |
14 |
15 |
16 | WORKDIR /src
17 | COPY setup.py .
18 | COPY setupbase.py .
19 | COPY README.md .
20 | COPY src ./src
21 | RUN apt-get update && \
22 | apt-get install -y \
23 | build-essential \
24 | make \
25 | gcc \
26 | && pip install . \
27 | && apt-get remove -y --purge make gcc build-essential \
28 | && apt-get autoremove -y \
29 | && rm -rf /var/lib/apt/lists/* \
30 | && rm -rf /src
31 |
32 | WORKDIR /app
33 | ENTRYPOINT ["evidently", "ui", "--host", "0.0.0.0"]
34 |
--------------------------------------------------------------------------------
/docker/Dockerfile.service.dev:
--------------------------------------------------------------------------------
1 | FROM python:3.10-slim
2 | ARG BUILD_DATE
3 | ARG VCS_REF
4 | ARG VERSION
5 | LABEL org.label-schema.build-date=$BUILD_DATE \
6 | org.label-schema.name="Evidently AI Service" \
7 | org.label-schema.url="https://github.com/evidentlyai/evidently" \
8 | org.label-schema.vcs-ref=$VCS_REF \
9 | org.label-schema.vcs-url="https://github.com/evidentlyai/evidently" \
10 | org.label-schema.version=$VERSION \
11 | org.label-schema.schema-version="1.0"
12 | LABEL maintainer="mike0sv@evidentlyai.com"
13 |
14 |
15 | RUN apt-get update && \
16 | apt-get install -y \
17 | build-essential \
18 | make \
19 | gcc
20 |
21 | WORKDIR /src
22 | COPY setup.py .
23 | COPY setupbase.py .
24 | COPY README.md .
25 | COPY src ./src
26 |
27 | RUN pip install . \
28 | && rm -rf /src
29 |
30 | WORKDIR /app
31 | CMD ["evidently", "ui", "--host", "0.0.0.0"]
32 |
--------------------------------------------------------------------------------
/examples/service/.gitignore:
--------------------------------------------------------------------------------
1 | workspace
--------------------------------------------------------------------------------
/examples/service/remote_demo_project.py:
--------------------------------------------------------------------------------
1 | from evidently.ui.workspace import RemoteWorkspace
2 | from evidently.ui.service.demo_projects import DEMO_PROJECTS
3 | DEMO_PROJECT_NAME = "bikes"
4 |
5 | def main():
6 | workspace = "http://localhost:8000"
7 | ws = RemoteWorkspace(workspace)
8 | demo_project = DEMO_PROJECTS[DEMO_PROJECT_NAME]
9 | has_demo_project = any(p.name == demo_project.name for p in ws.list_projects())
10 | if not has_demo_project:
11 | print("Generating demo project...")
12 | demo_project.create(ws)
13 |
14 | demo_project = ws.search_project(demo_project.name)[0]
15 | print(demo_project.id)
16 |
17 |
18 | if __name__ == '__main__':
19 | main()
--------------------------------------------------------------------------------
/examples/service/run_service.sh:
--------------------------------------------------------------------------------
1 | docker run -p 8000:8000 \
2 | -v $(pwd)/workspace:/app/workspace \
3 | --name evidently-service \
4 | --detach \
5 | evidently/evidently-service:latest
--------------------------------------------------------------------------------
/images/gh_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/images/gh_header.png
--------------------------------------------------------------------------------
/requirements.dev.txt:
--------------------------------------------------------------------------------
1 | # keep in sync with setup.py extra_require block.
2 | wheel==0.38.1
3 | setuptools==65.5.1; python_version < '3.12'
4 | setuptools==68.2.2; python_version >= '3.12'
5 | jupyter==1.0.0
6 | mypy==1.1.1
7 | pandas-stubs
8 | pytest==7.4.4
9 | pytest-asyncio==0.23.7
10 | pytest-mock==3.14.0
11 | types-PyYAML==6.0.1
12 | types-requests==2.26.0
13 | types-dataclasses==0.6
14 | types-python-dateutil==2.8.19
15 | types-ujson==5.4.0
16 | pillow==10.3.0
17 | pip-audit
18 | pyspark
19 | ruff==0.3.7
20 | pre-commit==3.5.0
21 |
22 | # service dependencies
23 | litestar>=2.7.1
24 | dynaconf
25 | uvicorn
26 | pyarrow
27 | httpx
28 |
--------------------------------------------------------------------------------
/requirements.min.txt:
--------------------------------------------------------------------------------
1 | # keep in sync with setup.py install_require block (but there should be set as lower bound).
2 | plotly==5.10.0
3 | statsmodels==0.12.2
4 | scikit-learn==1.0.1
5 | pandas[parquet]==1.3.5
6 | numpy==1.22.0
7 | nltk==3.6.7
8 | scipy==1.10.0
9 | requests==2.32.0
10 | PyYAML==5.4
11 | pydantic==1.10.16
12 | litestar==2.8.3
13 | typing-inspect==0.9.0
14 | uvicorn==0.22.0
15 | watchdog==3.0.0
16 | typer==0.3
17 | rich==13
18 | iterative-telemetry==0.0.5
19 | dynaconf==3.2.4
20 | pyarrow==14.0.1
21 | pyspark==3.4.0
22 | fsspec==2024.6.1
23 | certifi==2024.7.4
24 | urllib3==1.26.19
25 | ujson==5.4.0
26 | deprecation==2.1.0
27 | uuid6==2024.7.10
28 | cryptography==43.0.1
29 |
30 | openai==1.16.2
31 | evaluate==0.4.1
32 | transformers[torch]==4.39.3
33 | sentence-transformers==2.7.0
34 | sqlvalidator==0.0.20
35 |
--------------------------------------------------------------------------------
/src/evidently/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | from evidently.core.compare import compare
4 | from evidently.core.datasets import BinaryClassification
5 | from evidently.core.datasets import DataDefinition
6 | from evidently.core.datasets import Dataset
7 | from evidently.core.datasets import MulticlassClassification
8 | from evidently.core.datasets import Recsys
9 | from evidently.core.datasets import Regression
10 | from evidently.core.report import Report
11 | from evidently.legacy.core import ColumnType
12 |
13 | from . import _registry
14 | from ._version import __version__
15 | from ._version import version_info
16 | from .nbextension import _jupyter_nbextension_paths
17 |
18 | __all__ = [
19 | "__version__",
20 | "version_info",
21 | "_jupyter_nbextension_paths",
22 | "_registry",
23 | "Report",
24 | "Dataset",
25 | "DataDefinition",
26 | "BinaryClassification",
27 | "MulticlassClassification",
28 | "Regression",
29 | "Recsys",
30 | "compare",
31 | "ColumnType", # legacy support
32 | ]
33 |
--------------------------------------------------------------------------------
/src/evidently/_registry.py:
--------------------------------------------------------------------------------
1 | from .core import registries as future_registry
2 | from .legacy import _registry as legacy_registry
3 |
4 | __all__ = ["future_registry", "legacy_registry"]
5 |
--------------------------------------------------------------------------------
/src/evidently/_version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | version_info = (0, 7, 6)
5 | __version__ = ".".join(map(str, version_info))
6 |
7 |
8 | if __name__ == "__main__":
9 | print(__version__)
10 |
--------------------------------------------------------------------------------
/src/evidently/cli/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.cli.demo_project import generate_demo_project
2 | from evidently.cli.legacy_ui import legacy_ui
3 | from evidently.cli.main import app
4 | from evidently.cli.ui import ui
5 |
6 | __all__ = ["app", "ui", "legacy_ui", "generate_demo_project"]
7 |
8 | if __name__ == "__main__":
9 | app()
10 |
--------------------------------------------------------------------------------
/src/evidently/cli/__main__.py:
--------------------------------------------------------------------------------
1 | from evidently.cli import app
2 | from evidently.cli.ui import ui
3 |
4 | __all__ = ["app", "ui"]
5 |
6 | app()
7 |
--------------------------------------------------------------------------------
/src/evidently/cli/demo_project.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from typer import Option
4 | from typer import echo
5 |
6 | from evidently.cli.main import app
7 | from evidently.ui.service.demo_projects import DEMO_PROJECTS
8 |
9 |
10 | @app.command("demo_project")
11 | def generate_demo_project(
12 | project: str = Option("all", help="Project to generate"),
13 | path: str = Option("workspace", help="Workspace path"),
14 | ):
15 | _project = DEMO_PROJECTS.get(project)
16 | if _project is None:
17 | echo(f"Demo project {project} not found.")
18 | sys.exit(1)
19 | _project.create(path)
20 |
--------------------------------------------------------------------------------
/src/evidently/cli/main.py:
--------------------------------------------------------------------------------
1 | from typer import Typer
2 |
3 | app = Typer(
4 | context_settings={"help_option_names": ["-h", "--help"]},
5 | )
6 |
7 |
8 | @app.callback(no_args_is_help=True, invoke_without_command=True)
9 | def evidently_callback():
10 | """\b
11 | Evidently is tool to help you evaluate, test and monitor your data and ML models.
12 | Documentation: https://docs.evidentlyai.com
13 | """
14 |
--------------------------------------------------------------------------------
/src/evidently/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/core/__init__.py
--------------------------------------------------------------------------------
/src/evidently/core/_utils.py:
--------------------------------------------------------------------------------
1 | import inspect
2 | from typing import Iterable
3 | from typing import List
4 | from typing import Tuple
5 |
6 |
7 | def not_implemented(self_obj: object):
8 | currentframe = inspect.currentframe()
9 | name = "(unknown)"
10 | if currentframe is not None and currentframe.f_back:
11 | name = currentframe.f_back.f_code.co_name
12 | return NotImplementedError(f"Metric Type: {type(self_obj)} should implement {name}()")
13 |
14 |
15 | def _flatten(obj: object, paths: List[str] = None) -> Iterable[Tuple[str, float]]:
16 | paths = paths or []
17 | if isinstance(obj, float):
18 | yield ".".join(paths), obj
19 | return
20 | if isinstance(obj, dict):
21 | for k, v in obj.items():
22 | yield from _flatten(v, paths + [str(k)])
23 | return
24 | if isinstance(obj, list):
25 | for i, v in enumerate(obj):
26 | yield from _flatten(v, paths + [str(i)])
27 | return
28 | raise NotImplementedError("Not implemented for {}".format(type(obj)))
29 |
--------------------------------------------------------------------------------
/src/evidently/core/base_types.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 |
3 | from evidently._pydantic_compat import StrictBool
4 |
5 | Label = Union[StrictBool, int, str, None]
6 |
--------------------------------------------------------------------------------
/src/evidently/core/preset_types.py:
--------------------------------------------------------------------------------
1 | import dataclasses
2 | from typing import List
3 |
4 | from evidently.core.metric_types import render_widgets
5 | from evidently.legacy.model.widget import BaseWidgetInfo
6 |
7 |
8 | @dataclasses.dataclass
9 | class PresetResult:
10 | widget: List[BaseWidgetInfo]
11 |
12 | def _repr_html_(self):
13 | return render_widgets(self.widget, as_iframe=True)
14 |
--------------------------------------------------------------------------------
/src/evidently/core/registries/__init__.py:
--------------------------------------------------------------------------------
1 | from . import bound_tests
2 | from . import column_conditions
3 | from . import descriptors
4 | from . import metric_results
5 | from . import metric_tests
6 | from . import metrics
7 | from . import presets
8 |
9 | __all__ = ["descriptors", "presets", "metrics", "metric_tests", "metric_results", "bound_tests", "column_conditions"]
10 |
--------------------------------------------------------------------------------
/src/evidently/core/registries/bound_tests.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E501
2 | # fmt: off
3 | from evidently.core.metric_types import BoundTest
4 | from evidently.pydantic_utils import register_type_alias
5 |
6 | register_type_alias(BoundTest, "evidently.core.metric_types.ByLabelBoundTest", "evidently:bound_test:ByLabelBoundTest")
7 | register_type_alias(BoundTest, "evidently.core.metric_types.ByLabelCountBoundTest", "evidently:bound_test:ByLabelCountBoundTest")
8 | register_type_alias(BoundTest, "evidently.core.metric_types.CountBoundTest", "evidently:bound_test:CountBoundTest")
9 | register_type_alias(BoundTest, "evidently.core.metric_types.MeanStdBoundTest", "evidently:bound_test:MeanStdBoundTest")
10 | register_type_alias(BoundTest, "evidently.core.metric_types.SingleValueBoundTest", "evidently:bound_test:SingleValueBoundTest")
11 | register_type_alias(BoundTest, "evidently.metrics.column_statistics.ValueDriftBoundTest", "evidently:bound_test:ValueDriftBoundTest")
12 |
--------------------------------------------------------------------------------
/src/evidently/core/registries/descriptors.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E501
2 | # fmt: off
3 | from evidently.core.datasets import Descriptor
4 | from evidently.pydantic_utils import register_type_alias
5 |
6 | register_type_alias(Descriptor, "evidently.core.datasets.FeatureDescriptor", "evidently:descriptor_v2:FeatureDescriptor")
7 | register_type_alias(Descriptor, "evidently.descriptors._context_relevance.ContextRelevance", "evidently:descriptor_v2:ContextRelevance")
8 | register_type_alias(Descriptor, "evidently.descriptors._custom_descriptors.CustomColumnDescriptor", "evidently:descriptor_v2:CustomColumnDescriptor")
9 | register_type_alias(Descriptor, "evidently.descriptors._custom_descriptors.CustomDescriptor", "evidently:descriptor_v2:CustomDescriptor")
10 | register_type_alias(Descriptor, "evidently.descriptors._text_length.TextLength", "evidently:descriptor_v2:TextLength")
11 |
12 | register_type_alias(Descriptor, "evidently.core.datasets.ColumnTest", "evidently:descriptor_v2:ColumnTest")
13 | register_type_alias(Descriptor, "evidently.core.datasets.SingleInputDescriptor", "evidently:descriptor_v2:SingleInputDescriptor")
14 | register_type_alias(Descriptor, "evidently.core.datasets.TestSummary", "evidently:descriptor_v2:TestSummary")
15 |
--------------------------------------------------------------------------------
/src/evidently/core/registries/metric_results.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E501
2 | # fmt: off
3 | from evidently.core.metric_types import MetricResult
4 | from evidently.pydantic_utils import register_type_alias
5 |
6 | register_type_alias(MetricResult, "evidently.core.metric_types.ByLabelCountValue", "evidently:metric_result_v2:ByLabelCountValue")
7 | register_type_alias(MetricResult, "evidently.core.metric_types.ByLabelValue", "evidently:metric_result_v2:ByLabelValue")
8 | register_type_alias(MetricResult, "evidently.core.metric_types.CountValue", "evidently:metric_result_v2:CountValue")
9 | register_type_alias(MetricResult, "evidently.core.metric_types.MeanStdValue", "evidently:metric_result_v2:MeanStdValue")
10 | register_type_alias(MetricResult, "evidently.core.metric_types.SingleValue", "evidently:metric_result_v2:SingleValue")
11 |
--------------------------------------------------------------------------------
/src/evidently/core/serialization.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import Dict
3 | from typing import List
4 | from typing import Union
5 |
6 | from evidently._pydantic_compat import BaseModel
7 | from evidently.core.metric_types import MetricId
8 | from evidently.core.metric_types import MetricResult
9 | from evidently.legacy.model.widget import BaseWidgetInfo
10 | from evidently.legacy.suite.base_suite import MetadataValueType
11 |
12 |
13 | class MetricReportItem(BaseModel):
14 | metric_id: MetricId
15 | params: dict
16 |
17 |
18 | class PresetReportItem(BaseModel):
19 | pass # TODO: support presets
20 |
21 |
22 | class ReportModel(BaseModel):
23 | items: List[Union[MetricReportItem, PresetReportItem]]
24 |
25 |
26 | class SnapshotModel(BaseModel):
27 | report: ReportModel
28 | timestamp: datetime
29 | metadata: Dict[str, MetadataValueType]
30 | tags: List[str]
31 | metric_results: Dict[MetricId, MetricResult]
32 | top_level_metrics: List[MetricId]
33 | widgets: List[BaseWidgetInfo]
34 | tests_widgets: List[BaseWidgetInfo]
35 |
--------------------------------------------------------------------------------
/src/evidently/descriptors/llm_judges.py:
--------------------------------------------------------------------------------
1 | from evidently.llm.templates import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/errors.py:
--------------------------------------------------------------------------------
1 | class EvidentlyError(Exception):
2 | def get_message(self):
3 | return f"{self.__class__.__name__}: {self}"
4 |
--------------------------------------------------------------------------------
/src/evidently/future/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/future/__init__.py
--------------------------------------------------------------------------------
/src/evidently/future/datasets.py:
--------------------------------------------------------------------------------
1 | from evidently.core.datasets import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/descriptors/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.descriptors import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/generators/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.generators import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/metric_types.py:
--------------------------------------------------------------------------------
1 | from evidently.core.metric_types import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/metrics/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.metrics import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/presets/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.presets import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/report.py:
--------------------------------------------------------------------------------
1 | from evidently.core.report import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/future/tests/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.tests import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/src/evidently/generators/__init__.py:
--------------------------------------------------------------------------------
1 | from .column import ColumnMetricGenerator
2 |
3 | __all__ = ["ColumnMetricGenerator"]
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/_config.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | TELEMETRY_ADDRESS = "https://telemetry-321112.ew.r.appspot.com/post_data"
4 | TELEMETRY_ENABLED = not os.getenv("EVIDENTLY_DISABLE_TELEMETRY", "0") == "1"
5 |
--------------------------------------------------------------------------------
/src/evidently/legacy/_registry.py:
--------------------------------------------------------------------------------
1 | from .descriptors import _registry as descriptors_registry
2 | from .features import _registry as features_registry
3 | from .metric_preset import _registry as metric_preset_registry
4 | from .metrics import _registry as metrics_registry
5 | from .test_preset import _registry as test_preset_registry
6 | from .tests import _registry as tests_registry
7 | from .utils.llm import _registry as llm_registry
8 |
9 | __all__ = [
10 | "tests_registry",
11 | "metrics_registry",
12 | "descriptors_registry",
13 | "features_registry",
14 | "llm_registry",
15 | "metric_preset_registry",
16 | "test_preset_registry",
17 | ]
18 |
--------------------------------------------------------------------------------
/src/evidently/legacy/calculation_engine/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/calculation_engine/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/calculation_engine/metric_implementation.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | class MetricImplementation:
5 | @abc.abstractmethod
6 | def calculate(self, context, data):
7 | raise NotImplementedError()
8 |
9 | @classmethod
10 | @abc.abstractmethod
11 | def supported_engines(cls):
12 | raise NotImplementedError()
13 |
--------------------------------------------------------------------------------
/src/evidently/legacy/calculations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/calculations/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/calculations/stattests/text_content_drift.py:
--------------------------------------------------------------------------------
1 | from typing import Tuple
2 |
3 | import pandas as pd
4 |
5 | from evidently.legacy.calculations.stattests.registry import StatTest
6 | from evidently.legacy.calculations.stattests.registry import register_stattest
7 | from evidently.legacy.core import ColumnType
8 | from evidently.legacy.utils.data_drift_utils import calculate_text_drift_score
9 |
10 |
11 | def _perc_text_content_drift(
12 | reference_data: pd.Series, current_data: pd.Series, feature_type: ColumnType, threshold: float
13 | ) -> Tuple[float, bool]:
14 | return calculate_text_drift_score(reference_data, current_data, bootstrap=True, p_value=1 - threshold)
15 |
16 |
17 | perc_text_content_drift_stat_test = StatTest(
18 | name="perc_text_content_drift",
19 | display_name="Percentile text content drift",
20 | allowed_feature_types=[ColumnType.Text],
21 | default_threshold=0.95,
22 | )
23 |
24 | register_stattest(perc_text_content_drift_stat_test, _perc_text_content_drift)
25 |
--------------------------------------------------------------------------------
/src/evidently/legacy/calculations/stattests/text_content_drift_abs.py:
--------------------------------------------------------------------------------
1 | from typing import Tuple
2 |
3 | import pandas as pd
4 |
5 | from evidently.legacy.calculations.stattests.registry import StatTest
6 | from evidently.legacy.calculations.stattests.registry import register_stattest
7 | from evidently.legacy.core import ColumnType
8 | from evidently.legacy.utils.data_drift_utils import calculate_text_drift_score
9 |
10 |
11 | def _abs_text_content_drift(
12 | reference_data: pd.Series, current_data: pd.Series, feature_type: ColumnType, threshold: float
13 | ) -> Tuple[float, bool]:
14 | return calculate_text_drift_score(reference_data, current_data, bootstrap=False, threshold=threshold)
15 |
16 |
17 | abs_text_content_drift_stat_test = StatTest(
18 | name="abs_text_content_drift",
19 | display_name="Absolute text content drift",
20 | allowed_feature_types=[ColumnType.Text],
21 | default_threshold=0.55,
22 | )
23 |
24 | register_stattest(abs_text_content_drift_stat_test, _abs_text_content_drift)
25 |
--------------------------------------------------------------------------------
/src/evidently/legacy/cli/__init__.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.cli.collector import collector
2 | from evidently.legacy.cli.main import app
3 | from evidently.legacy.cli.ui import ui
4 |
5 | __all__ = ["app", "ui", "collector"]
6 |
7 |
8 | def main():
9 | app()
10 |
11 |
12 | if __name__ == "__main__":
13 | main()
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/cli/collector.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from typer import Option
4 |
5 | from evidently.legacy.cli.main import app
6 |
7 |
8 | @app.command("collector")
9 | def collector(
10 | host: str = Option("127.0.0.1", help="Collector host"),
11 | port: int = Option(8001, help="Collector port"),
12 | config_path: str = Option(None, help="Path to config file"),
13 | secret: Optional[str] = Option(None, help="Secret for writing operations"),
14 | ):
15 | """Start Evidently collector service"""
16 | from evidently.legacy.collector.app import run
17 | from evidently.legacy.collector.config import CONFIG_PATH
18 |
19 | run(host, port, config_path or CONFIG_PATH, secret)
20 |
--------------------------------------------------------------------------------
/src/evidently/legacy/cli/main.py:
--------------------------------------------------------------------------------
1 | from typer import Typer
2 |
3 | app = Typer(
4 | context_settings={"help_option_names": ["-h", "--help"]},
5 | )
6 |
7 |
8 | @app.callback(no_args_is_help=True, invoke_without_command=True)
9 | def evidently_callback():
10 | """\b
11 | Evidently is tool to help you evaluate, test and monitor your data and ML models.
12 | Documentation: https://docs.evidentlyai.com
13 | """
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/collector/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/collector/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/collector/client.py:
--------------------------------------------------------------------------------
1 | from typing import Any
2 | from typing import Dict
3 |
4 | import pandas as pd
5 |
6 | from evidently.legacy.collector.config import CollectorConfig
7 | from evidently.legacy.ui.utils import RemoteClientBase
8 |
9 |
10 | class CollectorClient(RemoteClientBase):
11 | def create_collector(self, id: str, collector: CollectorConfig) -> Dict[str, Any]:
12 | return self._request(f"/{id}", "POST", body=collector.dict()).json()
13 |
14 | def send_data(self, id: str, data: pd.DataFrame) -> Dict[str, Any]:
15 | return self._request(f"/{id}/data", "POST", body=data.to_dict()).json()
16 |
17 | def set_reference(self, id: str, reference: pd.DataFrame) -> Dict[str, Any]:
18 | return self._request(f"/{id}/reference", "POST", body=reference.to_dict()).json()
19 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/BERTScore_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features.BERTScore_feature import BERTScoreFeature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeatures
4 |
5 |
6 | class BERTScore(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:BERTScore"
9 |
10 | with_column: str
11 |
12 | def feature(self, column_name: str) -> GeneratedFeatures:
13 | return BERTScoreFeature(columns=[column_name, self.with_column], display_name=self.display_name)
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/contains_link_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import contains_link_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class ContainsLink(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:ContainsLink"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return contains_link_feature.ContainsLink(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/exact_match_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features.exact_match_feature import ExactMatchFeature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeatures
4 |
5 |
6 | class ExactMatch(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:ExactMatch"
9 |
10 | with_column: str
11 |
12 | def feature(self, column_name: str) -> GeneratedFeatures:
13 | return ExactMatchFeature(columns=[column_name, self.with_column], display_name=self.display_name)
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/is_valid_json_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import is_valid_json_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class IsValidJSON(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:IsValidJSON"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return is_valid_json_feature.IsValidJSON(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/is_valid_python_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import is_valid_python_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class IsValidPython(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:IsValidPython"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return is_valid_python_feature.IsValidPython(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/is_valid_sql_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import is_valid_sql_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class IsValidSQL(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:IsValidSQL"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return is_valid_sql_feature.IsValidSQL(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/json_match_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import json_match_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class JSONMatch(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:JSONMatch"
9 |
10 | with_column: str
11 |
12 | def feature(self, column_name: str) -> GeneratedFeature:
13 | return json_match_feature.JSONMatch(first_column=column_name, second_column=self.with_column)
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/json_schema_match_descriptor.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from evidently.legacy.features import json_schema_match_feature
4 | from evidently.legacy.features.generated_features import FeatureDescriptor
5 | from evidently.legacy.features.generated_features import GeneratedFeature
6 |
7 |
8 | class JSONSchemaMatch(FeatureDescriptor):
9 | class Config:
10 | type_alias = "evidently:descriptor:JSONSchemaMatch"
11 |
12 | expected_schema: Dict[str, type]
13 | validate_types: bool = False
14 | exact_match: bool = False
15 |
16 | def feature(self, column_name: str) -> GeneratedFeature:
17 | return json_schema_match_feature.JSONSchemaMatch(
18 | column_name=column_name,
19 | expected_schema=self.expected_schema,
20 | validate_types=self.validate_types,
21 | exact_match=self.exact_match,
22 | display_name=self.display_name,
23 | )
24 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/non_letter_character_percentage_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import non_letter_character_percentage_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class NonLetterCharacterPercentage(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:NonLetterCharacterPercentage"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return non_letter_character_percentage_feature.NonLetterCharacterPercentage(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/oov_words_percentage_descriptor.py:
--------------------------------------------------------------------------------
1 | from typing import Tuple
2 |
3 | from evidently.legacy.features.generated_features import FeatureDescriptor
4 | from evidently.legacy.features.generated_features import GeneratedFeature
5 | from evidently.legacy.features.OOV_words_percentage_feature import OOVWordsPercentage
6 |
7 |
8 | class OOV(FeatureDescriptor):
9 | class Config:
10 | type_alias = "evidently:descriptor:OOV"
11 |
12 | ignore_words: Tuple = ()
13 |
14 | def feature(self, column_name: str) -> GeneratedFeature:
15 | return OOVWordsPercentage(column_name, self.ignore_words, self.display_name)
16 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/regexp_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import regexp_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class RegExp(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:RegExp"
9 |
10 | reg_exp: str
11 |
12 | def feature(self, column_name: str) -> GeneratedFeature:
13 | return regexp_feature.RegExp(column_name, self.reg_exp, self.display_name)
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/semantic_similarity.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features.generated_features import FeatureDescriptor
2 | from evidently.legacy.features.generated_features import GeneratedFeatures
3 | from evidently.legacy.features.semantic_similarity_feature import SemanticSimilarityFeature
4 |
5 |
6 | class SemanticSimilarity(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:SemanticSimilarity"
9 |
10 | with_column: str
11 |
12 | def feature(self, column_name: str) -> GeneratedFeatures:
13 | return SemanticSimilarityFeature(columns=[column_name, self.with_column], display_name=self.display_name)
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/sentence_count_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import sentence_count_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class SentenceCount(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:SentenceCount"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return sentence_count_feature.SentenceCount(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/sentiment_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import sentiment_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class Sentiment(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:Sentiment"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return sentiment_feature.Sentiment(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/text_length_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import text_length_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class TextLength(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:TextLength"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return text_length_feature.TextLength(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/text_part_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import text_part_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class BeginsWith(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:BeginsWith"
9 |
10 | prefix: str
11 | case_sensitive: bool = True
12 |
13 | def feature(self, column_name: str) -> GeneratedFeature:
14 | return text_part_feature.BeginsWith(
15 | column_name,
16 | self.prefix,
17 | self.case_sensitive,
18 | self.display_name,
19 | )
20 |
21 |
22 | class EndsWith(FeatureDescriptor):
23 | class Config:
24 | type_alias = "evidently:descriptor:EndsWith"
25 |
26 | suffix: str
27 | case_sensitive: bool = True
28 |
29 | def feature(self, column_name: str) -> GeneratedFeature:
30 | return text_part_feature.EndsWith(
31 | column_name,
32 | self.suffix,
33 | self.case_sensitive,
34 | self.display_name,
35 | )
36 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/trigger_words_presence_descriptor.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from evidently.legacy.features import trigger_words_presence_feature
4 | from evidently.legacy.features.generated_features import FeatureDescriptor
5 | from evidently.legacy.features.generated_features import GeneratedFeature
6 |
7 |
8 | class TriggerWordsPresence(FeatureDescriptor):
9 | class Config:
10 | type_alias = "evidently:descriptor:TriggerWordsPresence"
11 |
12 | words_list: List[str]
13 | lemmatize: bool = True
14 |
15 | def feature(self, column_name: str) -> GeneratedFeature:
16 | return trigger_words_presence_feature.TriggerWordsPresent(
17 | column_name,
18 | self.words_list,
19 | self.lemmatize,
20 | self.display_name,
21 | )
22 |
--------------------------------------------------------------------------------
/src/evidently/legacy/descriptors/word_count_descriptor.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.features import word_count_feature
2 | from evidently.legacy.features.generated_features import FeatureDescriptor
3 | from evidently.legacy.features.generated_features import GeneratedFeature
4 |
5 |
6 | class WordCount(FeatureDescriptor):
7 | class Config:
8 | type_alias = "evidently:descriptor:WordCount"
9 |
10 | def feature(self, column_name: str) -> GeneratedFeature:
11 | return word_count_feature.WordCount(column_name, self.display_name)
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/experimental/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/experimental/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/experimental/report_set.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import os
3 | from typing import Dict
4 | from typing import Optional
5 |
6 | from evidently._pydantic_compat import ValidationError
7 | from evidently.legacy.suite.base_suite import Snapshot
8 | from evidently.legacy.ui.type_aliases import SnapshotID
9 |
10 |
11 | def load_snapshots(
12 | path: str,
13 | date_from: Optional[datetime.datetime] = None,
14 | date_to: Optional[datetime.datetime] = None,
15 | skip_errors: bool = False,
16 | ) -> Dict[SnapshotID, Snapshot]:
17 | result = {}
18 | for file in os.listdir(path):
19 | filepath = os.path.join(path, file)
20 | try:
21 | suite = Snapshot.load(filepath)
22 | except ValidationError:
23 | if skip_errors:
24 | continue
25 | raise
26 | if date_from is not None and suite.timestamp < date_from:
27 | continue
28 | if date_to is not None and suite.timestamp > date_to:
29 | continue
30 | result[suite.id] = suite
31 | return result
32 |
--------------------------------------------------------------------------------
/src/evidently/legacy/features/__init__.py:
--------------------------------------------------------------------------------
1 | from . import _registry
2 |
3 | __all__ = ["_registry"]
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/features/exact_match_feature.py:
--------------------------------------------------------------------------------
1 | from typing import ClassVar
2 | from typing import List
3 |
4 | import pandas as pd
5 |
6 | from evidently.legacy.base_metric import ColumnName
7 | from evidently.legacy.core import ColumnType
8 | from evidently.legacy.features.generated_features import GeneratedFeature
9 | from evidently.legacy.utils.data_preprocessing import DataDefinition
10 |
11 |
12 | class ExactMatchFeature(GeneratedFeature):
13 | class Config:
14 | type_alias = "evidently:feature:ExactMatchFeature"
15 |
16 | __feature_type__: ClassVar = ColumnType.Categorical
17 | columns: List[str]
18 |
19 | def generate_feature(self, data: pd.DataFrame, data_definition: DataDefinition) -> pd.DataFrame:
20 | return pd.DataFrame({self._feature_name(): data[self.columns[0]] == data[self.columns[1]]})
21 |
22 | def _feature_name(self):
23 | return "|".join(self.columns)
24 |
25 | def _as_column(self) -> "ColumnName":
26 | return self._create_column(
27 | self._feature_name(),
28 | default_display_name=f"Exact Match for {' '.join(self.columns)}.",
29 | )
30 |
--------------------------------------------------------------------------------
/src/evidently/legacy/features/is_valid_json_feature.py:
--------------------------------------------------------------------------------
1 | import json
2 | from typing import Any
3 | from typing import ClassVar
4 | from typing import Optional
5 |
6 | from evidently.legacy.core import ColumnType
7 | from evidently.legacy.features.generated_features import ApplyColumnGeneratedFeature
8 |
9 |
10 | class IsValidJSON(ApplyColumnGeneratedFeature):
11 | class Config:
12 | type_alias = "evidently:feature:IsValidJSON"
13 |
14 | __feature_type__: ClassVar = ColumnType.Categorical
15 | display_name_template: ClassVar = "JSON valid for {column_name}"
16 |
17 | def __init__(self, column_name: str, display_name: Optional[str] = None):
18 | self.display_name = display_name
19 | super().__init__(column_name=column_name)
20 |
21 | def apply(self, value: Any):
22 | try:
23 | json.loads(value)
24 | except ValueError:
25 | return False
26 | return True
27 |
--------------------------------------------------------------------------------
/src/evidently/legacy/features/is_valid_python_feature.py:
--------------------------------------------------------------------------------
1 | import ast
2 | from typing import Any
3 | from typing import ClassVar
4 | from typing import Optional
5 |
6 | from evidently.legacy.core import ColumnType
7 | from evidently.legacy.features.generated_features import ApplyColumnGeneratedFeature
8 |
9 |
10 | class IsValidPython(ApplyColumnGeneratedFeature):
11 | class Config:
12 | type_alias = "evidently:feature:IsValidPython"
13 |
14 | __feature_type__: ClassVar = ColumnType.Categorical
15 | display_name_template: ClassVar = "Valid Python for {column_name}"
16 |
17 | def __init__(self, column_name: str, display_name: Optional[str] = None):
18 | self.display_name = display_name
19 | super().__init__(column_name=column_name)
20 |
21 | def apply(self, value: Any) -> bool:
22 | try:
23 | ast.parse(value)
24 | return True
25 | except (SyntaxError, TypeError):
26 | return False
27 |
--------------------------------------------------------------------------------
/src/evidently/legacy/features/sentence_count_feature.py:
--------------------------------------------------------------------------------
1 | import re
2 | from typing import Any
3 | from typing import ClassVar
4 | from typing import Optional
5 |
6 | import numpy as np
7 |
8 | from evidently.legacy.core import ColumnType
9 | from evidently.legacy.features.generated_features import ApplyColumnGeneratedFeature
10 |
11 |
12 | class SentenceCount(ApplyColumnGeneratedFeature):
13 | class Config:
14 | type_alias = "evidently:feature:SentenceCount"
15 |
16 | __feature_type__: ClassVar = ColumnType.Numerical
17 | _reg: ClassVar[re.Pattern] = re.compile(r"(? List[AnyMetric]:
26 | raise NotImplementedError()
27 |
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/base_metric.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 | from typing import Optional
3 | from typing import Type
4 | from typing import Union
5 |
6 | from evidently.legacy.base_metric import Metric
7 | from evidently.legacy.utils.generators import BaseGenerator
8 | from evidently.legacy.utils.generators import make_generator_by_columns
9 |
10 |
11 | def generate_column_metrics(
12 | metric_class: Type[Metric],
13 | columns: Optional[Union[str, list]] = None,
14 | parameters: Optional[Dict] = None,
15 | skip_id_column: bool = False,
16 | ) -> BaseGenerator[Metric]:
17 | """Function for generating metrics for columns"""
18 | return make_generator_by_columns(
19 | base_class=metric_class,
20 | columns=columns,
21 | parameters=parameters,
22 | skip_id_column=skip_id_column,
23 | )
24 |
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/classification_performance/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/metrics/classification_performance/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/data_drift/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/metrics/data_drift/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/data_integrity/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/metrics/data_integrity/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/data_quality/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/metrics/data_quality/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/recsys/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/metrics/recsys/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/recsys/map_k.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetric
2 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetricRenderer
3 | from evidently.legacy.renderers.base_renderer import default_renderer
4 |
5 |
6 | class MAPKMetric(TopKMetric):
7 | class Config:
8 | type_alias = "evidently:metric:MAPKMetric"
9 |
10 | def key(self):
11 | return "map"
12 |
13 |
14 | @default_renderer(wrap_type=MAPKMetric)
15 | class MAPKMetricRenderer(TopKMetricRenderer):
16 | yaxis_name = "map@k"
17 | header = "MAP"
18 |
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/recsys/mar_k.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetric
2 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetricRenderer
3 | from evidently.legacy.renderers.base_renderer import default_renderer
4 |
5 |
6 | class MARKMetric(TopKMetric):
7 | class Config:
8 | type_alias = "evidently:metric:MARKMetric"
9 |
10 | def key(self):
11 | return "mar"
12 |
13 |
14 | @default_renderer(wrap_type=MARKMetric)
15 | class MARKMetricRenderer(TopKMetricRenderer):
16 | yaxis_name = "mar@k"
17 | header = "MAR"
18 |
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/recsys/precision_top_k.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetric
2 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetricRenderer
3 | from evidently.legacy.renderers.base_renderer import default_renderer
4 |
5 |
6 | class PrecisionTopKMetric(TopKMetric):
7 | class Config:
8 | type_alias = "evidently:metric:PrecisionTopKMetric"
9 |
10 | def key(self):
11 | return "precision"
12 |
13 |
14 | @default_renderer(wrap_type=PrecisionTopKMetric)
15 | class PrecisionTopKMetricRenderer(TopKMetricRenderer):
16 | yaxis_name = "precision@k"
17 | header = "Precision"
18 |
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/recsys/recall_top_k.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetric
2 | from evidently.legacy.metrics.recsys.base_top_k import TopKMetricRenderer
3 | from evidently.legacy.renderers.base_renderer import default_renderer
4 |
5 |
6 | class RecallTopKMetric(TopKMetric):
7 | class Config:
8 | type_alias = "evidently:metric:RecallTopKMetric"
9 |
10 | def key(self):
11 | return "recall"
12 |
13 |
14 | @default_renderer(wrap_type=RecallTopKMetric)
15 | class RecallTopKMetricRenderer(TopKMetricRenderer):
16 | yaxis_name = "recall@k"
17 | header = "Recall"
18 |
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/regression_performance/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/metrics/regression_performance/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/metrics/regression_performance/utils.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.metrics.regression_performance.objects import IntervalSeries
2 | from evidently.legacy.metrics.regression_performance.objects import RegressionMetricScatter
3 |
4 |
5 | def apply_func_to_binned_data(
6 | df_for_bins, func, target_column, preds_column, is_ref_data=False
7 | ) -> RegressionMetricScatter:
8 | def _apply(x):
9 | if x.shape[0] == 0:
10 | return None
11 | return func(x[target_column], x[preds_column])
12 |
13 | reference = None
14 | if is_ref_data:
15 | reference = IntervalSeries.from_data(
16 | df_for_bins[df_for_bins.data == "ref"].groupby("target_binned", observed=False).apply(_apply)
17 | )
18 |
19 | result = RegressionMetricScatter(
20 | current=IntervalSeries.from_data(
21 | df_for_bins[df_for_bins.data == "curr"].groupby("target_binned", observed=False).apply(_apply)
22 | ),
23 | reference=reference,
24 | )
25 |
26 | return result
27 |
--------------------------------------------------------------------------------
/src/evidently/legacy/model/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/model/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/model/dashboard.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | from typing import List
5 |
6 | from evidently._pydantic_compat import BaseModel
7 | from evidently.legacy.model.widget import BaseWidgetInfo
8 |
9 |
10 | class DashboardInfo(BaseModel):
11 | name: str
12 | widgets: List[BaseWidgetInfo]
13 |
--------------------------------------------------------------------------------
/src/evidently/legacy/options/__init__.py:
--------------------------------------------------------------------------------
1 | from .color_scheme import BERLIN_AUTUMN_COLOR_OPTIONS
2 | from .color_scheme import KARACHI_SUNRISE_COLOR_OPTIONS
3 | from .color_scheme import NIGHTOWL_COLOR_OPTIONS
4 | from .color_scheme import SOLARIZED_COLOR_OPTIONS
5 | from .color_scheme import ColorOptions
6 |
7 | __all__ = [
8 | "BERLIN_AUTUMN_COLOR_OPTIONS",
9 | "KARACHI_SUNRISE_COLOR_OPTIONS",
10 | "NIGHTOWL_COLOR_OPTIONS",
11 | "SOLARIZED_COLOR_OPTIONS",
12 | "ColorOptions",
13 | ]
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/options/agg_data.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from evidently.legacy.options.option import Option
4 |
5 |
6 | class RenderOptions(Option):
7 | raw_data: bool = False
8 |
9 |
10 | class DataDefinitionOptions(Option):
11 | categorical_features_cardinality: Optional[int] = None
12 |
--------------------------------------------------------------------------------
/src/evidently/legacy/options/option.py:
--------------------------------------------------------------------------------
1 | from evidently.pydantic_utils import FrozenBaseModel
2 |
3 |
4 | class Option(FrozenBaseModel):
5 | pass
6 |
--------------------------------------------------------------------------------
/src/evidently/legacy/pipeline/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/pipeline/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/renderers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/renderers/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/report/__init__.py:
--------------------------------------------------------------------------------
1 | from .report import Report
2 |
3 | __all__ = ["Report"]
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/runner/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/runner/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/spark/__init__.py:
--------------------------------------------------------------------------------
1 | from .engine import SparkEngine
2 | from .metrics import data_drift
3 | from .metrics import feature_importance
4 |
5 | __all__ = ["SparkEngine", "data_drift", "feature_importance"]
6 |
--------------------------------------------------------------------------------
/src/evidently/legacy/spark/calculations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/spark/calculations/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/spark/calculations/stattests/__init__.py:
--------------------------------------------------------------------------------
1 | from . import chisquare
2 | from . import jensenshannon
3 | from . import psi
4 | from . import wasserstein
5 |
6 | __all__ = ["chisquare", "wasserstein", "psi", "jensenshannon"]
7 |
--------------------------------------------------------------------------------
/src/evidently/legacy/spark/calculations/stattests/jensenshannon.py:
--------------------------------------------------------------------------------
1 | from scipy.spatial import distance
2 |
3 | from evidently.legacy.calculations.stattests import jensenshannon_stat_test
4 | from evidently.legacy.calculations.stattests.registry import StatTestFuncReturns
5 | from evidently.legacy.core import ColumnType
6 |
7 | from .base import SparkStatTestImpl
8 | from .base import SpartStatTestData
9 | from .utils import get_binned_data
10 |
11 |
12 | class SparkJensenShannon(SparkStatTestImpl):
13 | base_stat_test = jensenshannon_stat_test
14 |
15 | def __call__(self, data: SpartStatTestData, feature_type: ColumnType, threshold: float) -> StatTestFuncReturns:
16 | cur = data.current_data
17 | ref = data.reference_data
18 | column_name = data.column_name
19 | reference_percents, current_percents = get_binned_data(ref, cur, column_name, feature_type, False)
20 | jensenshannon_value = distance.jensenshannon(reference_percents, current_percents, base=None)
21 | return jensenshannon_value, jensenshannon_value >= threshold
22 |
--------------------------------------------------------------------------------
/src/evidently/legacy/spark/calculations/stattests/psi.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | from evidently.legacy.calculations.stattests import psi_stat_test
4 | from evidently.legacy.calculations.stattests.registry import StatTestFuncReturns
5 | from evidently.legacy.core import ColumnType
6 |
7 | from .base import SparkStatTestImpl
8 | from .base import SpartStatTestData
9 | from .utils import get_binned_data
10 |
11 |
12 | class SparkPSI(SparkStatTestImpl):
13 | base_stat_test = psi_stat_test
14 |
15 | def __call__(self, data: SpartStatTestData, feature_type: ColumnType, threshold: float) -> StatTestFuncReturns:
16 | cur = data.current_data
17 | ref = data.reference_data
18 | column_name = data.column_name
19 | reference_percents, current_percents = get_binned_data(ref, cur, column_name, feature_type)
20 |
21 | psi_values = (reference_percents - current_percents) * np.log(reference_percents / current_percents)
22 | psi_value = np.sum(psi_values)
23 |
24 | return psi_value, psi_value >= threshold
25 |
--------------------------------------------------------------------------------
/src/evidently/legacy/spark/metrics/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/spark/metrics/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/suite/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/suite/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/test_preset/__init__.py:
--------------------------------------------------------------------------------
1 | """Predefined Test Presets for Test Suite"""
2 |
3 | from . import _registry
4 | from .classification_binary import BinaryClassificationTestPreset
5 | from .classification_binary_topk import BinaryClassificationTopKTestPreset
6 | from .classification_multiclass import MulticlassClassificationTestPreset
7 | from .data_drift import DataDriftTestPreset
8 | from .data_quality import DataQualityTestPreset
9 | from .data_stability import DataStabilityTestPreset
10 | from .no_target_performance import NoTargetPerformanceTestPreset
11 | from .recsys import RecsysTestPreset
12 | from .regression import RegressionTestPreset
13 |
14 | __all__ = [
15 | "BinaryClassificationTestPreset",
16 | "BinaryClassificationTopKTestPreset",
17 | "MulticlassClassificationTestPreset",
18 | "DataDriftTestPreset",
19 | "DataQualityTestPreset",
20 | "DataStabilityTestPreset",
21 | "NoTargetPerformanceTestPreset",
22 | "RegressionTestPreset",
23 | "RecsysTestPreset",
24 | "_registry",
25 | ]
26 |
--------------------------------------------------------------------------------
/src/evidently/legacy/test_preset/test_preset.py:
--------------------------------------------------------------------------------
1 | import abc
2 | from typing import Any
3 | from typing import Dict
4 | from typing import List
5 | from typing import Optional
6 | from typing import Union
7 |
8 | from evidently.legacy.base_metric import BasePreset
9 | from evidently.legacy.tests.base_test import Test
10 | from evidently.legacy.utils.data_preprocessing import DataDefinition
11 | from evidently.legacy.utils.generators import BaseGenerator
12 |
13 | AnyTest = Union[Test, BaseGenerator[Test]]
14 |
15 |
16 | class TestPreset(BasePreset):
17 | class Config:
18 | is_base_type = True
19 |
20 | @abc.abstractmethod
21 | def generate_tests(
22 | self, data_definition: DataDefinition, additional_data: Optional[Dict[str, Any]]
23 | ) -> List[AnyTest]:
24 | raise NotImplementedError
25 |
--------------------------------------------------------------------------------
/src/evidently/legacy/test_suite/__init__.py:
--------------------------------------------------------------------------------
1 | from .test_suite import TestSuite
2 |
3 | __all__ = ["TestSuite"]
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/.gitignore
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/api/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/api/service.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import Optional
3 |
4 | from litestar import Router
5 | from litestar import get
6 |
7 | import evidently
8 | from evidently.legacy.ui.api.models import Version
9 |
10 | EVIDENTLY_APPLICATION_NAME = "Evidently UI"
11 |
12 |
13 | @get("/version")
14 | async def version() -> Version:
15 | return Version(
16 | application=EVIDENTLY_APPLICATION_NAME,
17 | version=evidently.__version__,
18 | commit=get_git_revision_short_hash(os.path.dirname(evidently.__file__)) or "-",
19 | )
20 |
21 |
22 | def get_git_revision_short_hash(path: str) -> Optional[str]:
23 | from_env = os.environ.get("GIT_COMMIT")
24 | if from_env is not None:
25 | return from_env
26 | import subprocess
27 |
28 | try:
29 | return subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], cwd=path).decode("ascii").strip()
30 | except Exception:
31 | return None
32 |
33 |
34 | def service_api():
35 | return Router("", route_handlers=[version])
36 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/api/static.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pathlib
3 |
4 | import litestar
5 | from litestar import MediaType
6 | from litestar import Response
7 | from litestar.response import File
8 | from litestar.router import Router
9 | from litestar.static_files import create_static_files_router
10 |
11 | BASE_PATH = str(pathlib.Path(__file__).parent.parent.resolve() / "assets")
12 |
13 |
14 | def assets_router(base_path: str = BASE_PATH):
15 | @litestar.get(
16 | ["/", "/projects/{path:path}"],
17 | include_in_schema=False,
18 | )
19 | async def index() -> Response:
20 | return File(
21 | path=os.path.join(base_path, "index.html"),
22 | filename="index.html",
23 | media_type=MediaType.HTML,
24 | content_disposition_type="inline",
25 | )
26 |
27 | return Router(
28 | path="",
29 | route_handlers=[
30 | index,
31 | create_static_files_router("/", directories=[base_path]),
32 | ],
33 | )
34 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/assets/favicon-16x16.png
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/assets/favicon-32x32.png
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/assets/favicon.ico
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 | Evidently - ML Monitoring Demo
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Evidently.AI",
3 | "name": "Evidently.AI Dashboards",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "favicon-96x96.png",
12 | "type": "image/png",
13 | "sizes": "96x96"
14 | }
15 | ],
16 | "start_url": ".",
17 | "display": "standalone",
18 | "theme_color": "#000000",
19 | "background_color": "#ffffff"
20 | }
21 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/static/css/index-CJbKDbyR.css:
--------------------------------------------------------------------------------
1 | body{margin:0;padding:0}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
2 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/assets/static/js/snapshot-view-main-Z97zaUJO.js:
--------------------------------------------------------------------------------
1 | import{j as t,B as h,c as r,r as p,u as i}from"./index-Nx_mkSx_.js";import{D as c,C as j,S as m,J as n}from"./WidgetsContent-CSRajGBd.js";const _=({data:a,dashboardContextState:s})=>t.jsx(t.Fragment,{children:t.jsx(c.Provider,{value:j(s),children:t.jsx(h,{py:2,children:t.jsx(m,{widgets:a.widgets})})})}),C="/projects/:projectId/reports/:snapshotId",x={param:"snapshotId"},I={crumb:x},l=({params:a})=>{const{projectId:s,snapshotId:e}=a;return r.GET("/api/projects/{project_id}/{snapshot_id}/data",{params:{path:{project_id:s,snapshot_id:e}},parseAs:"text"}).then(p()).then(n)},D=()=>{const{loaderData:a,params:s}=i(),{projectId:e,snapshotId:d}=s;return t.jsx(_,{data:a,dashboardContextState:{getAdditionGraphData:o=>r.GET("/api/projects/{project_id}/{snapshot_id}/graphs_data/{graph_id}",{params:{path:{project_id:e,snapshot_id:d,graph_id:encodeURIComponent(o)}},parseAs:"text"}).then(p()).then(n),getAdditionWidgetData:o=>r.GET("/api/projects/{project_id}/{snapshot_id}/graphs_data/{graph_id}",{params:{path:{project_id:e,snapshot_id:d,graph_id:encodeURIComponent(o)}},parseAs:"text"}).then(p()).then(n)}})};export{D as Component,C as currentRoutePath,I as handle,l as loadData};
2 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/components/__init__.py:
--------------------------------------------------------------------------------
1 | from .local_storage import DataStorageComponent
2 | from .local_storage import InMemoryDataStorage
3 | from .local_storage import MetadataStorageComponent
4 |
5 | __all__ = ["InMemoryDataStorage", "DataStorageComponent", "MetadataStorageComponent"]
6 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/dashboards/__init__.py:
--------------------------------------------------------------------------------
1 | from .base import DashboardConfig
2 | from .base import PanelValue
3 | from .base import ReportFilter
4 | from .reports import CounterAgg
5 | from .reports import DashboardPanelCounter
6 | from .reports import DashboardPanelDistribution
7 | from .reports import DashboardPanelHistogram
8 | from .reports import DashboardPanelPlot
9 | from .reports import HistBarMode
10 | from .reports import PlotType
11 | from .test_suites import DashboardPanelTestSuite
12 | from .test_suites import DashboardPanelTestSuiteCounter
13 | from .test_suites import TestFilter
14 | from .test_suites import TestSuitePanelType
15 |
16 | __all__ = [
17 | "DashboardPanelPlot",
18 | "DashboardConfig",
19 | "DashboardPanelTestSuite",
20 | "DashboardPanelTestSuiteCounter",
21 | "TestSuitePanelType",
22 | "TestFilter",
23 | "ReportFilter",
24 | "DashboardPanelCounter",
25 | "PanelValue",
26 | "CounterAgg",
27 | "PlotType",
28 | "HistBarMode",
29 | "DashboardPanelTestSuiteCounter",
30 | "DashboardPanelDistribution",
31 | "DashboardPanelHistogram",
32 | ]
33 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/demo_projects/__init__.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from .adult import adult_demo_project
4 | from .base import DemoProject
5 | from .bikes import bikes_demo_project
6 | from .reviews import reviews_demo_project
7 | from .simple import simple_demo_project
8 |
9 | # from .bikes_v2 import bikes_v2_demo_project
10 | # from .reviews_v2 import reviews_v2_demo_project
11 |
12 | DEMO_PROJECTS: Dict[str, DemoProject] = {
13 | "bikes": bikes_demo_project,
14 | "reviews": reviews_demo_project,
15 | "adult": adult_demo_project,
16 | }
17 |
18 | DEMO_PROJECTS_NAMES = list(DEMO_PROJECTS.keys())
19 |
20 | __all__ = [
21 | "DemoProject",
22 | "DEMO_PROJECTS",
23 | "simple_demo_project",
24 | "reviews_demo_project",
25 | "bikes_demo_project",
26 | "adult_demo_project",
27 | ]
28 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/managers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/managers/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/remote.py:
--------------------------------------------------------------------------------
1 | """For backward compatibility with evidently <= 4.9"""
2 |
3 | import warnings
4 |
5 | from evidently.legacy.ui.workspace import RemoteWorkspace
6 |
7 | __all__ = ["RemoteWorkspace"]
8 |
9 | warnings.warn(
10 | "Importing RemoteWorkspace from evidently.legacy.ui.remote is deprecated. Please import from evidently.legacy.ui.workspace",
11 | DeprecationWarning,
12 | )
13 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/security/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/security/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/security/no_security.py:
--------------------------------------------------------------------------------
1 | from litestar import Request
2 |
3 | from ..base import User
4 | from ..components.security import NoSecurityComponent
5 | from .service import SecurityService
6 |
7 |
8 | class NoSecurityService(SecurityService):
9 | def __init__(self, security_config: NoSecurityComponent):
10 | self.security_config = security_config
11 |
12 | def authenticate(self, request: Request) -> User:
13 | return User(id=self.security_config.dummy_user_id, name="")
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/security/service.py:
--------------------------------------------------------------------------------
1 | import abc
2 | from typing import Optional
3 |
4 | from litestar import Request
5 |
6 | from evidently.legacy.ui.base import User
7 |
8 |
9 | class SecurityService:
10 | @abc.abstractmethod
11 | def authenticate(self, request: Request) -> Optional[User]:
12 | raise NotImplementedError()
13 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/security/token.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from litestar import Request
4 |
5 | from evidently.legacy.ui.components.security import TokenSecurityComponent
6 | from evidently.legacy.ui.security.service import SecurityService
7 | from evidently.legacy.ui.security.service import User
8 | from evidently.legacy.ui.type_aliases import ZERO_UUID
9 |
10 | SECRET_HEADER_NAME = "evidently-secret"
11 |
12 |
13 | default_user = User(id=ZERO_UUID, name="")
14 |
15 |
16 | class TokenSecurity(SecurityService):
17 | def __init__(self, config: TokenSecurityComponent):
18 | self.config = config
19 |
20 | def authenticate(self, request: Request) -> Optional[User]:
21 | if request.headers.get(SECRET_HEADER_NAME) == self.config.token.get_secret_value():
22 | return default_user
23 | return None
24 |
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/storage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/storage/__init__.py
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/storage/config.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/legacy/ui/storage/config.py
--------------------------------------------------------------------------------
/src/evidently/legacy/ui/workspace/__init__.py:
--------------------------------------------------------------------------------
1 | from .base import WorkspaceBase
2 | from .cloud import CloudWorkspace
3 | from .remote import RemoteWorkspace
4 | from .view import Workspace
5 |
6 | __all__ = ["WorkspaceBase", "Workspace", "RemoteWorkspace", "CloudWorkspace"]
7 |
--------------------------------------------------------------------------------
/src/evidently/legacy/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .numpy_encoder import NumpyEncoder
2 |
3 | __all__ = ["NumpyEncoder"]
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/utils/llm/__init__.py:
--------------------------------------------------------------------------------
1 | from . import _registry
2 |
3 | __all__ = ["_registry"]
4 |
--------------------------------------------------------------------------------
/src/evidently/legacy/utils/llm/_registry.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E501
2 | # fmt: off
3 | from evidently.legacy.utils.llm.prompts import PromptBlock
4 | from evidently.legacy.utils.llm.prompts import PromptTemplate
5 | from evidently.pydantic_utils import register_type_alias
6 |
7 | register_type_alias(PromptBlock, "evidently.legacy.utils.llm.prompts.Anchor", "evidently:prompt_block:Anchor")
8 | register_type_alias(PromptBlock, "evidently.legacy.utils.llm.prompts.JsonOutputFormatBlock", "evidently:prompt_block:JsonOutputFormatBlock")
9 | register_type_alias(PromptBlock, "evidently.legacy.utils.llm.prompts.NoopOutputFormat", "evidently:prompt_block:NoopOutputFormat")
10 | register_type_alias(PromptBlock, "evidently.legacy.utils.llm.prompts.SimpleBlock", "evidently:prompt_block:SimpleBlock")
11 | register_type_alias(PromptBlock, "evidently.legacy.utils.llm.prompts.StringFormatBlock", "evidently:prompt_block:StringFormatBlock")
12 | register_type_alias(PromptBlock, "evidently.legacy.utils.llm.prompts.StringListFormatBlock", "evidently:prompt_block:StringListFormatBlock")
13 | register_type_alias(PromptTemplate, "evidently.legacy.utils.llm.prompts.BlockPromptTemplate", "evidently:prompt_template:BlockPromptTemplate")
14 |
--------------------------------------------------------------------------------
/src/evidently/legacy/utils/llm/base.py:
--------------------------------------------------------------------------------
1 | import dataclasses
2 | from typing import Any
3 | from typing import Dict
4 |
5 |
6 | @dataclasses.dataclass(unsafe_hash=True, frozen=True)
7 | class LLMMessage:
8 | role: str
9 | content: str
10 |
11 | @classmethod
12 | def user(cls, message: str):
13 | return LLMMessage("user", message)
14 |
15 | @classmethod
16 | def system(cls, message: str):
17 | return LLMMessage("system", message)
18 |
19 |
20 | LLMResponse = Dict[str, Any]
21 |
--------------------------------------------------------------------------------
/src/evidently/legacy/utils/llm/errors.py:
--------------------------------------------------------------------------------
1 | from evidently.errors import EvidentlyError
2 |
3 |
4 | class EvidentlyLLMError(EvidentlyError):
5 | pass
6 |
7 |
8 | class LLMResponseParseError(EvidentlyLLMError):
9 | def __init__(self, message: str, response):
10 | self.message = message
11 | self.response = response
12 |
13 | def get_message(self):
14 | return f"{self.__class__.__name__}: {self.message}"
15 |
16 |
17 | class LLMRequestError(EvidentlyLLMError):
18 | def __init__(self, message: str, original_error: Exception = None):
19 | super().__init__(message)
20 | self.original_error = original_error
21 |
22 |
23 | class LLMRateLimitError(LLMRequestError):
24 | pass
25 |
--------------------------------------------------------------------------------
/src/evidently/legacy/utils/sync.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import threading
3 | from functools import wraps
4 | from typing import Awaitable
5 | from typing import Callable
6 | from typing import TypeVar
7 |
8 | _loop = asyncio.new_event_loop()
9 |
10 | _thr = threading.Thread(target=_loop.run_forever, name="Async Runner", daemon=True)
11 |
12 | TA = TypeVar("TA")
13 |
14 |
15 | def async_to_sync(awaitable: Awaitable[TA]) -> TA:
16 | try:
17 | asyncio.get_running_loop()
18 | # we are in sync context but inside a running loop
19 | if not _thr.is_alive():
20 | _thr.start()
21 | future = asyncio.run_coroutine_threadsafe(awaitable, _loop)
22 | return future.result()
23 | except RuntimeError:
24 | pass
25 | new_loop = asyncio.new_event_loop()
26 | asyncio.set_event_loop(new_loop)
27 | try:
28 | return new_loop.run_until_complete(awaitable)
29 | finally:
30 | new_loop.close()
31 |
32 |
33 | def sync_api(f: Callable[..., Awaitable[TA]]) -> Callable[..., TA]:
34 | @wraps(f)
35 | def sync_call(*args, **kwargs):
36 | return async_to_sync(f(*args, **kwargs))
37 |
38 | return sync_call
39 |
--------------------------------------------------------------------------------
/src/evidently/llm/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/llm/__init__.py
--------------------------------------------------------------------------------
/src/evidently/llm/options.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.utils.llm.wrapper import AnthropicOptions
2 | from evidently.legacy.utils.llm.wrapper import DeepSeekOptions
3 | from evidently.legacy.utils.llm.wrapper import GeminiOptions
4 | from evidently.legacy.utils.llm.wrapper import LLMOptions
5 | from evidently.legacy.utils.llm.wrapper import MistralOptions
6 | from evidently.legacy.utils.llm.wrapper import OllamaOptions
7 | from evidently.legacy.utils.llm.wrapper import OpenAIOptions
8 | from evidently.legacy.utils.llm.wrapper import VertexAIOptions
9 |
10 | __all__ = [
11 | "AnthropicOptions",
12 | "LLMOptions",
13 | "OpenAIOptions",
14 | "GeminiOptions",
15 | "DeepSeekOptions",
16 | "VertexAIOptions",
17 | "MistralOptions",
18 | "OllamaOptions",
19 | ]
20 |
--------------------------------------------------------------------------------
/src/evidently/llm/templates.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.descriptors.llm_judges import BinaryClassificationPromptTemplate
2 | from evidently.legacy.descriptors.llm_judges import MulticlassClassificationPromptTemplate
3 |
4 | __all__ = ["BinaryClassificationPromptTemplate", "MulticlassClassificationPromptTemplate"]
5 |
--------------------------------------------------------------------------------
/src/evidently/nbextension/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 |
5 | def _jupyter_nbextension_paths():
6 | return [{"section": "notebook", "src": "nbextension/static", "dest": "evidently", "require": "evidently/extension"}]
7 |
--------------------------------------------------------------------------------
/src/evidently/nbextension/static/extension.js:
--------------------------------------------------------------------------------
1 | // Entry point for the notebook bundle containing custom model definitions.
2 | //
3 | define(function() {
4 | "use strict";
5 |
6 | window['requirejs'].config({
7 | map: {
8 | '*': {
9 | 'evidently': 'nbextensions/evidently/index',
10 | },
11 | }
12 | });
13 | // Export the required load_ipython_extension function
14 | return {
15 | load_ipython_extension : function() {}
16 | };
17 | });
18 |
--------------------------------------------------------------------------------
/src/evidently/nbextension/static/material-ui-icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/nbextension/static/material-ui-icons.woff2
--------------------------------------------------------------------------------
/src/evidently/presets/__init__.py:
--------------------------------------------------------------------------------
1 | from .classification import ClassificationDummyQuality
2 | from .classification import ClassificationPreset
3 | from .classification import ClassificationQuality
4 | from .classification import ClassificationQualityByLabel
5 | from .dataset_stats import DatasetStats
6 | from .dataset_stats import DataSummaryPreset
7 | from .dataset_stats import TextEvals
8 | from .dataset_stats import ValueStats
9 | from .drift import DataDriftPreset
10 | from .regression import RegressionDummyQuality
11 | from .regression import RegressionPreset
12 | from .regression import RegressionQuality
13 |
14 | __all__ = [
15 | "ClassificationDummyQuality",
16 | "ClassificationPreset",
17 | "ClassificationQuality",
18 | "ClassificationQualityByLabel",
19 | "ValueStats",
20 | "TextEvals",
21 | "DatasetStats",
22 | "DataSummaryPreset",
23 | "RegressionDummyQuality",
24 | "RegressionQuality",
25 | "RegressionPreset",
26 | "DataDriftPreset",
27 | ]
28 |
--------------------------------------------------------------------------------
/src/evidently/sdk/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/sdk/__init__.py
--------------------------------------------------------------------------------
/src/evidently/tests/__init__.py:
--------------------------------------------------------------------------------
1 | from .aliases import eq
2 | from .aliases import gt
3 | from .aliases import gte
4 | from .aliases import is_in
5 | from .aliases import lt
6 | from .aliases import lte
7 | from .aliases import not_eq
8 | from .aliases import not_in
9 | from .reference import Reference
10 |
11 | __all__ = [
12 | "eq",
13 | "not_eq",
14 | "gt",
15 | "gte",
16 | "is_in",
17 | "not_in",
18 | "lt",
19 | "lte",
20 | "Reference",
21 | ]
22 |
--------------------------------------------------------------------------------
/src/evidently/tests/reference.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from evidently._pydantic_compat import BaseModel
4 |
5 |
6 | class Reference(BaseModel):
7 | relative: Optional[float] = None
8 | absolute: Optional[float] = None
9 |
10 | def __hash__(self) -> int:
11 | return hash(self.relative) + hash(self.absolute)
12 |
--------------------------------------------------------------------------------
/src/evidently/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/.gitignore
--------------------------------------------------------------------------------
/src/evidently/ui/service/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/api/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/api/service.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import Optional
3 |
4 | from litestar import Router
5 | from litestar import get
6 |
7 | import evidently
8 | from evidently.legacy.ui.api.models import Version
9 |
10 | EVIDENTLY_APPLICATION_NAME = "Evidently UI"
11 |
12 |
13 | @get("/version")
14 | async def version() -> Version:
15 | return Version(
16 | application=EVIDENTLY_APPLICATION_NAME,
17 | version=evidently.__version__,
18 | commit=get_git_revision_short_hash(os.path.dirname(evidently.__file__)) or "-",
19 | )
20 |
21 |
22 | def get_git_revision_short_hash(path: str) -> Optional[str]:
23 | from_env = os.environ.get("GIT_COMMIT")
24 | if from_env is not None:
25 | return from_env
26 | import subprocess
27 |
28 | try:
29 | return subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], cwd=path).decode("ascii").strip()
30 | except Exception:
31 | return None
32 |
33 |
34 | def service_api():
35 | return Router("", route_handlers=[version])
36 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/api/static.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pathlib
3 |
4 | import litestar
5 | from litestar import MediaType
6 | from litestar import Response
7 | from litestar.response import File
8 | from litestar.router import Router
9 | from litestar.static_files import create_static_files_router
10 |
11 | BASE_PATH = str(pathlib.Path(__file__).parent.parent.resolve() / "assets")
12 |
13 |
14 | def assets_router(base_path: str = BASE_PATH):
15 | @litestar.get(
16 | ["/", "/projects/{path:path}"],
17 | include_in_schema=False,
18 | )
19 | async def index() -> Response:
20 | return File(
21 | path=os.path.join(base_path, "index.html"),
22 | filename="index.html",
23 | media_type=MediaType.HTML,
24 | content_disposition_type="inline",
25 | )
26 |
27 | return Router(
28 | path="",
29 | route_handlers=[
30 | index,
31 | create_static_files_router("/", directories=[base_path]),
32 | ],
33 | )
34 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/assets/favicon-16x16.png
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/assets/favicon-32x32.png
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/assets/favicon.ico
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 | Evidently - ML Monitoring Demo
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Evidently.AI",
3 | "name": "Evidently.AI Dashboards",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "favicon-96x96.png",
12 | "type": "image/png",
13 | "sizes": "96x96"
14 | }
15 | ],
16 | "start_url": ".",
17 | "display": "standalone",
18 | "theme_color": "#000000",
19 | "background_color": "#ffffff"
20 | }
21 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/assets/static/css/index-CJbKDbyR.css:
--------------------------------------------------------------------------------
1 | body{margin:0;padding:0}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
2 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/components/__init__.py:
--------------------------------------------------------------------------------
1 | from .local_storage import DataStorageComponent
2 | from .local_storage import InMemoryDataStorage
3 | from .local_storage import MetadataStorageComponent
4 |
5 | __all__ = ["InMemoryDataStorage", "DataStorageComponent", "MetadataStorageComponent"]
6 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/components/dashboard.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from litestar.di import Provide
4 |
5 | from evidently.ui.service.components.base import Component
6 | from evidently.ui.service.components.base import ComponentContext
7 | from evidently.ui.service.services.dashbord.file import JsonFileDashboardManager
8 |
9 |
10 | class DashboardComponent(Component):
11 | __service_name__ = "dashboards"
12 | storage_type = "file"
13 | path: str = "workspace"
14 |
15 | def provider(self):
16 | if self.storage_type == "file":
17 |
18 | async def factory():
19 | return JsonFileDashboardManager(self.path)
20 |
21 | return factory
22 | raise ValueError("Unknown storage type {}".format(self.storage_type))
23 |
24 | def get_dependencies(self, ctx: ComponentContext) -> Dict[str, Provide]:
25 | return {
26 | "dashboard_manager": Provide(self.provider()),
27 | }
28 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/demo_projects/__init__.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from .base import DemoProject
4 | from .bikes import bikes_demo_project
5 |
6 | DEMO_PROJECTS: Dict[str, DemoProject] = {
7 | "bikes": bikes_demo_project,
8 | }
9 |
10 | DEMO_PROJECTS_NAMES = list(DEMO_PROJECTS.keys())
11 |
12 | __all__ = [
13 | "DemoProject",
14 | "DEMO_PROJECTS",
15 | "bikes_demo_project",
16 | ]
17 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/managers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/managers/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/security/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/security/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/security/no_security.py:
--------------------------------------------------------------------------------
1 | from litestar import Request
2 |
3 | from ..base import User
4 | from ..components.security import NoSecurityComponent
5 | from .service import SecurityService
6 |
7 |
8 | class NoSecurityService(SecurityService):
9 | def __init__(self, security_config: NoSecurityComponent):
10 | self.security_config = security_config
11 |
12 | def authenticate(self, request: Request) -> User:
13 | return User(id=self.security_config.dummy_user_id, name="")
14 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/security/service.py:
--------------------------------------------------------------------------------
1 | import abc
2 | from typing import Optional
3 |
4 | from litestar import Request
5 |
6 | from evidently.ui.service.base import User
7 |
8 |
9 | class SecurityService:
10 | @abc.abstractmethod
11 | def authenticate(self, request: Request) -> Optional[User]:
12 | raise NotImplementedError()
13 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/security/token.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from litestar import Request
4 |
5 | from evidently.ui.service.components.security import TokenSecurityComponent
6 | from evidently.ui.service.security.service import SecurityService
7 | from evidently.ui.service.security.service import User
8 | from evidently.ui.service.type_aliases import ZERO_UUID
9 |
10 | SECRET_HEADER_NAME = "evidently-secret"
11 |
12 |
13 | default_user = User(id=ZERO_UUID, name="")
14 |
15 |
16 | class TokenSecurity(SecurityService):
17 | def __init__(self, config: TokenSecurityComponent):
18 | self.config = config
19 |
20 | def authenticate(self, request: Request) -> Optional[User]:
21 | if request.headers.get(SECRET_HEADER_NAME) == self.config.token.get_secret_value():
22 | return default_user
23 | return None
24 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/services/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/services/dashbord/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/services/dashbord/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/services/dashbord/base.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 | from evidently.sdk.models import DashboardModel
4 | from evidently.ui.service.type_aliases import ProjectID
5 |
6 |
7 | class DashboardManager:
8 | @abc.abstractmethod
9 | async def get_dashboard(self, project_id: ProjectID) -> DashboardModel:
10 | raise NotImplementedError
11 |
12 | @abc.abstractmethod
13 | async def save_dashboard(self, project_id: ProjectID, dashboard: DashboardModel) -> None:
14 | raise NotImplementedError
15 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/services/dashbord/file.py:
--------------------------------------------------------------------------------
1 | import typing
2 | from typing import Optional
3 |
4 | from evidently.sdk.models import DashboardModel
5 | from evidently.ui.service.services.dashbord.base import DashboardManager
6 | from evidently.ui.service.type_aliases import ProjectID
7 |
8 | if typing.TYPE_CHECKING:
9 | from evidently.ui.service.storage.local import LocalState
10 |
11 |
12 | class JsonFileDashboardManager(DashboardManager):
13 | def __init__(self, path: str, local_state: Optional["LocalState"] = None):
14 | from evidently.ui.service.storage.local import LocalState
15 |
16 | self._path = path
17 | self._state = local_state or LocalState(path, None)
18 |
19 | async def get_dashboard(self, project_id: ProjectID) -> DashboardModel:
20 | return self._state.read_dashboard(project_id)
21 |
22 | async def save_dashboard(self, project_id: ProjectID, dashboard: DashboardModel) -> None:
23 | return self._state.write_dashboard(project_id, dashboard)
24 |
--------------------------------------------------------------------------------
/src/evidently/ui/service/storage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/storage/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/storage/config.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/service/storage/config.py
--------------------------------------------------------------------------------
/src/evidently/ui/service/workspace/__init__.py:
--------------------------------------------------------------------------------
1 | from .base import WorkspaceBase
2 | from .view import Workspace
3 |
4 | __all__ = ["WorkspaceBase", "Workspace"]
5 |
--------------------------------------------------------------------------------
/src/evidently/ui/storage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/storage/__init__.py
--------------------------------------------------------------------------------
/src/evidently/ui/storage/local/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/ui/storage/local/__init__.py
--------------------------------------------------------------------------------
/src/evidently/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/utils/__init__.py
--------------------------------------------------------------------------------
/src/evidently/utils/llm/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/src/evidently/utils/llm/__init__.py
--------------------------------------------------------------------------------
/src/evidently/utils/llm/wrapper.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.utils.llm.wrapper import * # noqa: F403
2 |
--------------------------------------------------------------------------------
/test_data/adults.CITATION:
--------------------------------------------------------------------------------
1 | Title: Adult
2 | Description: Predict whether annual income of an individual exceeds $50K/yr based on census data. Also known as "Census Income" dataset.
3 | Dataset source: https://archive.ics.uci.edu/dataset/2/adult
4 | Creators: Barry Becker, Ronny Kohavi
5 | Licence: CC BY 4.0
6 |
--------------------------------------------------------------------------------
/test_data/adults.parquet:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/test_data/adults.parquet
--------------------------------------------------------------------------------
/test_data/reviews.parquet:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/test_data/reviews.parquet
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/__init__.py
--------------------------------------------------------------------------------
/tests/calculation_engine/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/calculation_engine/__init__.py
--------------------------------------------------------------------------------
/tests/calculations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/calculations/__init__.py
--------------------------------------------------------------------------------
/tests/calculations/stattests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/calculations/stattests/__init__.py
--------------------------------------------------------------------------------
/tests/calculations/test_recommender_systems.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/calculations/test_recommender_systems.py
--------------------------------------------------------------------------------
/tests/cli/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/cli/__init__.py
--------------------------------------------------------------------------------
/tests/cli/test_ui.py:
--------------------------------------------------------------------------------
1 | import inspect
2 |
3 | import pytest
4 |
5 | from evidently.cli import app
6 | from evidently.ui.service.demo_projects import DEMO_PROJECTS_NAMES
7 |
8 |
9 | @pytest.fixture()
10 | def ui_command():
11 | command = [c for c in app.registered_commands if c.name == "ui"][0]
12 | argspec = inspect.getfullargspec(command.callback)
13 | return dict(zip(argspec.annotations.keys(), argspec.defaults))
14 |
15 |
16 | @pytest.mark.parametrize("demo_project", DEMO_PROJECTS_NAMES)
17 | def test_all_demo_projects_in_help(demo_project, ui_command):
18 | assert demo_project in ui_command["demo_projects"].help
19 |
--------------------------------------------------------------------------------
/tests/collector/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/collector/__init__.py
--------------------------------------------------------------------------------
/tests/dataset_generator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/dataset_generator/__init__.py
--------------------------------------------------------------------------------
/tests/features/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/features/__init__.py
--------------------------------------------------------------------------------
/tests/features/test_OOV_words_percentage_feature.py:
--------------------------------------------------------------------------------
1 | import nltk
2 | import pandas as pd
3 |
4 | from evidently.legacy.features.OOV_words_percentage_feature import OOVWordsPercentage
5 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
6 | from evidently.legacy.utils.data_preprocessing import create_data_definition
7 |
8 | nltk.download("words")
9 | nltk.download("wordnet")
10 | nltk.download("omw-1.4")
11 |
12 |
13 | def test_oov_words_percentage():
14 | feature_generator = OOVWordsPercentage("column_1", ignore_words=("foobar",))
15 | data = pd.DataFrame(dict(column_1=["Who ate apples? Go iaehb!", "Who ate apples? Go foobar! ", "the"]))
16 | result = feature_generator.generate_feature(
17 | data=data,
18 | data_definition=create_data_definition(None, data, ColumnMapping()),
19 | )
20 | assert result.equals(pd.DataFrame(dict(column_1=[20.0, 0, 0])))
21 |
--------------------------------------------------------------------------------
/tests/features/test_custom_feature.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.features.custom_feature import CustomSingleColumnFeature
4 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
5 | from evidently.legacy.utils.data_preprocessing import create_data_definition
6 |
7 |
8 | def test_custom_feature():
9 | def add_two(data: pd.Series) -> pd.Series:
10 | return data + 2
11 |
12 | feature_generator = CustomSingleColumnFeature(column_name="column_1", display_name="cl", func=add_two, name="cf")
13 | data = pd.DataFrame(dict(column_1=[1, 2, 3]))
14 | result = feature_generator.generate_feature(
15 | data=data,
16 | data_definition=create_data_definition(None, data, ColumnMapping()),
17 | )
18 |
19 | pd.testing.assert_frame_equal(result, pd.DataFrame(dict(cf=[3, 4, 5])))
20 | assert feature_generator.as_column().display_name == "cl"
21 |
--------------------------------------------------------------------------------
/tests/features/test_exact_feature.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | import pytest
3 |
4 | from evidently.legacy.features.exact_match_feature import ExactMatchFeature
5 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
6 | from evidently.legacy.utils.data_preprocessing import create_data_definition
7 |
8 |
9 | @pytest.mark.parametrize(
10 | ("value1", "value2", "expected"),
11 | [
12 | ("this is same", "this is same", True),
13 | ("this is same", "this is different", False),
14 | ],
15 | )
16 | def test_exact_match_feature(value1: str, value2: str, expected: bool):
17 | feature_generator = ExactMatchFeature(columns=["column_1", "column_2"])
18 | data = pd.DataFrame(dict(column_1=[value1], column_2=[value2]))
19 | result = feature_generator.generate_feature(
20 | data=data, data_definition=create_data_definition(None, data, ColumnMapping())
21 | )
22 | expected_df = pd.DataFrame([[expected]], columns=["column_1|column_2"])
23 | pd.testing.assert_frame_equal(result, expected_df)
24 |
--------------------------------------------------------------------------------
/tests/features/test_is_valid_json_feature.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | import pytest
3 |
4 | from evidently.legacy.features.is_valid_json_feature import IsValidJSON
5 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
6 | from evidently.legacy.utils.data_preprocessing import create_data_definition
7 |
8 |
9 | @pytest.mark.parametrize(
10 | ("item", "expected"),
11 | [
12 | ('{"test": "abc"}', True),
13 | ("not json", False),
14 | ],
15 | )
16 | def test_is_valid_json_feature(item: str, expected: bool):
17 | feature_generator = IsValidJSON("column_1")
18 | data = pd.DataFrame(dict(column_1=[item]))
19 | result = feature_generator.generate_feature(
20 | data=data,
21 | data_definition=create_data_definition(None, data, ColumnMapping()),
22 | )
23 | assert result.equals(pd.DataFrame(dict(column_1=[expected])))
24 |
--------------------------------------------------------------------------------
/tests/features/test_non_letter_character_percentage_feature.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.features.non_letter_character_percentage_feature import NonLetterCharacterPercentage
4 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
5 | from evidently.legacy.utils.data_preprocessing import create_data_definition
6 |
7 |
8 | def test_non_letter_character_percentage():
9 | feature_generator = NonLetterCharacterPercentage(column_name="column_1", display_name="cl")
10 | data = pd.DataFrame(dict(column_1=["2Ad <4", "abc ", "144&&?1"]))
11 | result = feature_generator.generate_feature(
12 | data=data,
13 | data_definition=create_data_definition(None, data, ColumnMapping()),
14 | )
15 |
16 | assert result.equals(pd.DataFrame(dict(column_1=[100 * 3 / 6, 0, 100])))
17 | assert feature_generator.as_column().display_name == "cl"
18 |
--------------------------------------------------------------------------------
/tests/features/test_text_length_feature.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.features.text_length_feature import TextLength
4 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
5 | from evidently.legacy.utils.data_preprocessing import create_data_definition
6 |
7 |
8 | def test_text_length_feature():
9 | feature_generator = TextLength("column_1")
10 | data = pd.DataFrame(dict(column_1=["abcdefg", "abc", "a"]))
11 | result = feature_generator.generate_feature(
12 | data=data,
13 | data_definition=create_data_definition(None, data, ColumnMapping()),
14 | )
15 | assert result.equals(pd.DataFrame(dict(column_1=[7, 3, 1])))
16 |
--------------------------------------------------------------------------------
/tests/features/test_trigger_words_present_feature.py:
--------------------------------------------------------------------------------
1 | import nltk
2 | import pandas as pd
3 |
4 | from evidently.legacy.features.trigger_words_presence_feature import TriggerWordsPresent
5 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
6 | from evidently.legacy.utils.data_preprocessing import create_data_definition
7 |
8 | nltk.download("words")
9 | nltk.download("wordnet")
10 | nltk.download("omw-1.4")
11 |
12 |
13 | def test_trigger_words_present_feature():
14 | feature_generator = TriggerWordsPresent("column_1", words_list=("apple",))
15 | data = pd.DataFrame(dict(column_1=["Who are you and where are my apples?", "abc ", "a"]))
16 | result = feature_generator.generate_feature(
17 | data=data,
18 | data_definition=create_data_definition(None, data, ColumnMapping()),
19 | )
20 | assert result.equals(pd.DataFrame(dict(column_1_apple_True=[1, 0, 0])))
21 |
--------------------------------------------------------------------------------
/tests/future/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/__init__.py
--------------------------------------------------------------------------------
/tests/future/descriptors/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/descriptors/__init__.py
--------------------------------------------------------------------------------
/tests/future/generators/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/generators/__init__.py
--------------------------------------------------------------------------------
/tests/future/generators/test_generator.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.core.report import Report
4 | from evidently.generators import ColumnMetricGenerator
5 | from evidently.presets import ValueStats
6 |
7 |
8 | def test_generator_renders():
9 | generator = ColumnMetricGenerator(ValueStats, columns=["a", "b"])
10 | report = Report([generator])
11 | snapshot = report.run(pd.DataFrame(data={"a": [1, 2, 3, 4], "b": [1, 2, 3, 4]}))
12 | assert len(snapshot._widgets) == 2
13 |
--------------------------------------------------------------------------------
/tests/future/metrics/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/metrics/__init__.py
--------------------------------------------------------------------------------
/tests/future/metrics/category_count.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | import pytest
3 |
4 | from evidently.core.datasets import Dataset
5 | from evidently.core.metric_types import CountValue
6 | from evidently.core.report import Report
7 | from evidently.metrics import CategoryCount
8 |
9 |
10 | @pytest.mark.parametrize(
11 | "data,category,expected_count",
12 | [
13 | (["a", "a", "a"], "a", 3),
14 | (["a", "a", "a"], "b", 0),
15 | ([True, True, True], True, 3),
16 | ([True, True, True], False, 0),
17 | ([True, True, None], True, 2),
18 | ([True, True, None], False, 0),
19 | ([False, False, None], False, 2),
20 | ],
21 | )
22 | def test_category_count_metric(data, category, expected_count):
23 | dataset = Dataset.from_pandas(pd.DataFrame(data=dict(column=data)))
24 | metric = CategoryCount("column", category=category)
25 | report = Report([metric])
26 | snapshot = report.run(dataset, None)
27 | metric_result = snapshot._context.get_metric_result(metric.metric_id)
28 | assert isinstance(metric_result, CountValue)
29 | assert metric_result.count == expected_count
30 |
--------------------------------------------------------------------------------
/tests/future/metrics/test_in_range_metric.py:
--------------------------------------------------------------------------------
1 | from evidently.metrics import InRangeValueCount
2 |
3 |
4 | def test_in_range_metric():
5 | metric = InRangeValueCount(column="a", left=0.5, right=1)
6 | assert metric.left == 0.5
7 | assert metric.right == 1
8 |
--------------------------------------------------------------------------------
/tests/future/metrics/test_min_metric.py:
--------------------------------------------------------------------------------
1 | def test_min_metric():
2 | assert True
3 |
--------------------------------------------------------------------------------
/tests/future/metrics/test_missing_count.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | import pytest
4 |
5 | from evidently.core.datasets import Dataset
6 | from evidently.core.metric_types import CountValue
7 | from evidently.core.report import Report
8 | from evidently.metrics import DatasetMissingValueCount
9 |
10 |
11 | @pytest.mark.parametrize(
12 | "data,metric,result",
13 | [(pd.DataFrame({"a": [1, 2, np.nan, np.nan]}), DatasetMissingValueCount(), {"count": 2, "share": 0.5})],
14 | )
15 | def test_missing_count(data, metric, result):
16 | dataset = Dataset.from_pandas(data)
17 | report = Report([metric])
18 | run = report.run(dataset, None)
19 | res = run._context.get_metric_result(metric)
20 | assert isinstance(res, CountValue)
21 | assert res.count.value == result["count"]
22 | assert res.share.value == result["share"]
23 |
--------------------------------------------------------------------------------
/tests/future/metrics/test_out_range_metric.py:
--------------------------------------------------------------------------------
1 | from evidently.metrics import OutRangeValueCount
2 |
3 |
4 | def test_out_range_metric():
5 | metric = OutRangeValueCount(column="a", left=0.5, right=1)
6 | assert metric.left == 0.5
7 | assert metric.right == 1
8 |
--------------------------------------------------------------------------------
/tests/future/presets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/presets/__init__.py
--------------------------------------------------------------------------------
/tests/future/report/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/report/__init__.py
--------------------------------------------------------------------------------
/tests/future/test_ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/test_ui/__init__.py
--------------------------------------------------------------------------------
/tests/future/test_ui/test_workspace/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/future/test_ui/test_workspace/__init__.py
--------------------------------------------------------------------------------
/tests/metric_preset/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metric_preset/__init__.py
--------------------------------------------------------------------------------
/tests/metrics/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metrics/__init__.py
--------------------------------------------------------------------------------
/tests/metrics/data_drift/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metrics/data_drift/__init__.py
--------------------------------------------------------------------------------
/tests/metrics/data_interity/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metrics/data_interity/__init__.py
--------------------------------------------------------------------------------
/tests/metrics/data_quality/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metrics/data_quality/__init__.py
--------------------------------------------------------------------------------
/tests/metrics/recsys/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metrics/recsys/__init__.py
--------------------------------------------------------------------------------
/tests/metrics/recsys/test_scores_distribution.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 |
4 | from evidently.legacy.metrics import ScoreDistribution
5 | from evidently.legacy.pipeline.column_mapping import ColumnMapping
6 | from evidently.legacy.report import Report
7 |
8 |
9 | def test_score_distribution():
10 | current = pd.DataFrame(
11 | data=dict(
12 | user_id=["a", "a", "a", "b", "b", "b", "c", "c", "c"],
13 | prediction=[1.25, 1.0, 0.3, 0.9, 0.8, 0.7, 1.0, 0.5, 0.3],
14 | target=[1, 0, 0, 0, 0, 0, 0, 0, 1],
15 | ),
16 | )
17 |
18 | metric = ScoreDistribution(k=3)
19 | report = Report(metrics=[metric])
20 | column_mapping = ColumnMapping()
21 | report.run(reference_data=None, current_data=current, column_mapping=column_mapping)
22 |
23 | results = metric.get_result()
24 | assert np.isclose(results.current_entropy, 2.15148438)
25 |
--------------------------------------------------------------------------------
/tests/metrics/regression_performance/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/metrics/regression_performance/__init__.py
--------------------------------------------------------------------------------
/tests/multitest/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/multitest/__init__.py
--------------------------------------------------------------------------------
/tests/multitest/metrics/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/multitest/metrics/__init__.py
--------------------------------------------------------------------------------
/tests/multitest/metrics/custom.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.base_metric import InputData
4 | from evidently.legacy.metrics.custom_metric import CustomValueMetric
5 | from tests.multitest.conftest import AssertResultFields
6 | from tests.multitest.datasets import TestDataset
7 | from tests.multitest.metrics.conftest import TestMetric
8 | from tests.multitest.metrics.conftest import metric
9 |
10 |
11 | def custom_func(data: InputData) -> float:
12 | return 0.3
13 |
14 |
15 | @metric
16 | def custom_callable_metric():
17 | reference_data = current_data = pd.DataFrame({"text": [1, 2, 3]})
18 |
19 | return TestMetric(
20 | name="custom_callable_metric",
21 | metric=CustomValueMetric(func=custom_func, title="aaa"),
22 | fingerprint="bf2e25a384e9d1ad621d73862c661a95",
23 | outcomes=AssertResultFields({"value": 0.3}),
24 | datasets=[
25 | TestDataset("custom_callable_metric_data", current=current_data, reference=reference_data, tags=[]),
26 | ],
27 | )
28 |
--------------------------------------------------------------------------------
/tests/options/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/options/__init__.py
--------------------------------------------------------------------------------
/tests/options/test_base.py:
--------------------------------------------------------------------------------
1 | from evidently.legacy.options import ColorOptions
2 | from evidently.legacy.options.base import Options
3 | from evidently.legacy.options.color_scheme import GREY
4 | from evidently.legacy.options.option import Option
5 |
6 |
7 | def test_options_creation():
8 | opt = ColorOptions(primary_color=GREY)
9 |
10 | obj = Options.from_any_options([opt])
11 | assert obj.color_options == opt
12 |
13 | obj = Options.from_any_options({"color": opt})
14 | assert obj.color_options == opt
15 |
16 |
17 | class CustomOption(Option):
18 | field: int = 10
19 |
20 |
21 | def test_custom_option():
22 | option = CustomOption(field=10)
23 |
24 | obj = Options.from_any_options([option])
25 | assert obj.get(CustomOption) == option
26 |
27 | obj = Options.from_any_options({"custom": {CustomOption: option}})
28 | assert obj.get(CustomOption) == option
29 |
--------------------------------------------------------------------------------
/tests/report/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/report/__init__.py
--------------------------------------------------------------------------------
/tests/spark/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/spark/__init__.py
--------------------------------------------------------------------------------
/tests/spark/metrics/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/spark/metrics/__init__.py
--------------------------------------------------------------------------------
/tests/stattests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/stattests/__init__.py
--------------------------------------------------------------------------------
/tests/test_preset/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/test_preset/__init__.py
--------------------------------------------------------------------------------
/tests/test_preset/test_classification_multiclass.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.test_preset import MulticlassClassificationTestPreset
4 | from evidently.legacy.test_suite import TestSuite
5 |
6 |
7 | def test_no_target_performance_preset():
8 | test_current_dataset = pd.DataFrame(
9 | {
10 | "category_feature": ["y", "y", "n", "p"],
11 | "numerical_feature": [0.4, -12, 0, 234],
12 | "target": [1, 1, 0, 1],
13 | "prediction": [0, 0, 1, 0],
14 | }
15 | )
16 | test_reference_dataset = pd.DataFrame(
17 | {
18 | "category_feature": ["y", "n", "n", "y"],
19 | "numerical_feature": [0, 1, 2, 5],
20 | "target": [0, 0, 0, 1],
21 | "prediction": [0, 0, 0, 1],
22 | }
23 | )
24 | data_quality_suite = TestSuite(
25 | tests=[
26 | MulticlassClassificationTestPreset(stattest="psi"),
27 | ]
28 | )
29 |
30 | data_quality_suite.run(current_data=test_current_dataset, reference_data=test_reference_dataset)
31 | assert not data_quality_suite
32 | assert len(data_quality_suite.as_dict()["tests"]) == 8
33 |
--------------------------------------------------------------------------------
/tests/test_preset/test_data_quality.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.test_preset import DataQualityTestPreset
4 | from evidently.legacy.test_suite import TestSuite
5 |
6 |
7 | def test_data_quality_preset():
8 | test_current_dataset = pd.DataFrame(
9 | {
10 | "category_feature": ["n", "y", "n", "p"],
11 | "numerical_feature": [0.4, -12, None, 234],
12 | "target": [1, 1, None, 1],
13 | "prediction": [0, 0, None, 0],
14 | }
15 | )
16 | test_reference_dataset = pd.DataFrame(
17 | {
18 | "category_feature": ["y", "n", "n", "y"],
19 | "numerical_feature": [0, 1, 2, 5],
20 | "target": [0, 0, 0, 1],
21 | "prediction": [0, 0, 0, 1],
22 | }
23 | )
24 | data_quality_suite = TestSuite(
25 | tests=[
26 | DataQualityTestPreset(),
27 | ]
28 | )
29 |
30 | data_quality_suite.run(current_data=test_current_dataset, reference_data=test_reference_dataset)
31 | assert not data_quality_suite
32 | assert len(data_quality_suite.as_dict()["tests"]) == 11
33 |
--------------------------------------------------------------------------------
/tests/test_preset/test_data_stability.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.test_preset import DataStabilityTestPreset
4 | from evidently.legacy.test_suite import TestSuite
5 |
6 |
7 | def test_data_stability_preset():
8 | test_current_dataset = pd.DataFrame(
9 | {
10 | "category_feature": ["t", "e", "", ""],
11 | "numerical_feature": [0.4, -12, None, 234],
12 | "target": [1, 1, None, 1],
13 | "prediction": [0, 0, None, 0],
14 | }
15 | )
16 | test_reference_dataset = pd.DataFrame(
17 | {
18 | "category_feature": ["y", "n", "n", "y"],
19 | "numerical_feature": [0, 1, 2, 5],
20 | "target": [0, 0, 0, 1],
21 | "prediction": [0, 0, 0, 1],
22 | }
23 | )
24 | data_quality_suite = TestSuite(
25 | tests=[
26 | DataStabilityTestPreset(),
27 | ]
28 | )
29 |
30 | data_quality_suite.run(current_data=test_current_dataset, reference_data=test_reference_dataset)
31 | assert not data_quality_suite
32 | assert len(data_quality_suite.as_dict()["tests"]) == 10
33 |
--------------------------------------------------------------------------------
/tests/test_preset/test_no_target_performance.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from evidently.legacy.test_preset import NoTargetPerformanceTestPreset
4 | from evidently.legacy.test_suite import TestSuite
5 |
6 |
7 | def test_no_target_performance_preset():
8 | test_current_dataset = pd.DataFrame(
9 | {
10 | "category_feature": ["y", "y", "n", "p"],
11 | "numerical_feature": [0.4, -12, 0, 234],
12 | "target": [1, 1, 0, 1],
13 | "prediction": [0, 0, 1, 0],
14 | }
15 | )
16 | test_reference_dataset = pd.DataFrame(
17 | {
18 | "category_feature": ["y", "n", "n", "y"],
19 | "numerical_feature": [0, 1, 2, 5],
20 | "target": [0, 0, 0, 1],
21 | "prediction": [0, 0, 0, 1],
22 | }
23 | )
24 | data_quality_suite = TestSuite(
25 | tests=[
26 | NoTargetPerformanceTestPreset(),
27 | ]
28 | )
29 |
30 | data_quality_suite.run(current_data=test_current_dataset, reference_data=test_reference_dataset)
31 | assert not data_quality_suite
32 | assert len(data_quality_suite.as_dict()["tests"]) == 10
33 |
--------------------------------------------------------------------------------
/tests/test_setup.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from setup import setup_args
4 |
5 |
6 | def test_minimal_requirements():
7 | path = Path(__file__).parent.parent
8 | with open(path / "requirements.min.txt") as f:
9 | lines = {line.strip().split("#")[0] for line in f.readlines()}
10 | min_reqs = {
11 | k.split("[")[0]: _get_min_version(v)
12 | for line in lines
13 | if line.strip()
14 | for k, v in (line.strip().split("=="),)
15 | }
16 |
17 | install_reqs = {
18 | k.split("[")[0]: _get_min_version(v) for r in setup_args["install_requires"] for k, v in (r.split(">="),)
19 | }
20 | extra = []
21 | wrong_version = []
22 | for m, v in install_reqs.items():
23 | if m not in min_reqs:
24 | extra.append(f"{m}>={v}")
25 | continue
26 | if v != min_reqs[m]:
27 | wrong_version.append(f"{m}>={v}")
28 | continue
29 |
30 | assert (
31 | len(extra) == 0 and len(wrong_version) == 0
32 | ), f"install_requires has extra reqs {extra} and wrong versions of {wrong_version}"
33 |
34 |
35 | def _get_min_version(value):
36 | return value.split(",")[0]
37 |
--------------------------------------------------------------------------------
/tests/test_suite/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/test_suite/__init__.py
--------------------------------------------------------------------------------
/tests/test_torch_numpy.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import torch
3 |
4 |
5 | def test_torch_to_numpy():
6 | array = torch.tensor([1, 2, 3]).numpy()
7 | assert np.array_equal(array, np.array([1, 2, 3]))
8 |
--------------------------------------------------------------------------------
/tests/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/tests/__init__.py
--------------------------------------------------------------------------------
/tests/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/ui/__init__.py
--------------------------------------------------------------------------------
/tests/ui/test_demo_project.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from evidently.legacy.ui.demo_projects import DEMO_PROJECTS
4 | from evidently.legacy.ui.demo_projects import DEMO_PROJECTS_NAMES
5 | from evidently.legacy.ui.workspace import Workspace
6 | from tests.conftest import slow
7 |
8 |
9 | @slow
10 | @pytest.mark.parametrize("demo_project", DEMO_PROJECTS_NAMES)
11 | def test_create_demo_project(demo_project, tmp_path):
12 | dp = DEMO_PROJECTS[demo_project]
13 | dp.count = 2
14 | dp.create(str(tmp_path))
15 |
16 | ws = Workspace(path=str(tmp_path))
17 | assert len(ws.search_project(dp.name)) > 0
18 |
--------------------------------------------------------------------------------
/tests/ui/test_ui_basic.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from litestar.testing import TestClient
3 |
4 | from evidently.legacy.ui.app import create_app
5 | from evidently.legacy.ui.demo_projects import DEMO_PROJECTS
6 | from evidently.legacy.ui.local_service import LocalConfig
7 | from tests.conftest import slow
8 |
9 |
10 | @pytest.fixture
11 | def test_client_with_demo(tmp_path):
12 | dp = DEMO_PROJECTS["bikes"]
13 | dp.create(str(tmp_path))
14 | config = LocalConfig()
15 | config.storage.path = str(tmp_path)
16 |
17 | return TestClient(create_app(config=config))
18 |
19 |
20 | @slow
21 | def test_root_route(test_client):
22 | response = test_client.get("/")
23 | assert response.status_code == 200
24 |
--------------------------------------------------------------------------------
/tests/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/tests/utils/__init__.py
--------------------------------------------------------------------------------
/ui/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .tsc-dts
3 | playwright-report
4 | test-results
5 | vite-bundle-report
6 | tsconfig.tsbuildinfo
7 |
--------------------------------------------------------------------------------
/ui/html-visual-testing/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | config.json
4 |
--------------------------------------------------------------------------------
/ui/html-visual-testing/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/html-visual-testing/README.md
--------------------------------------------------------------------------------
/ui/html-visual-testing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "html-visual-testing",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "test": "playwright test"
7 | },
8 | "dependencies": {
9 | },
10 | "devDependencies": {
11 | "wait-on": "^7.1.0",
12 | "@playwright/test": "^1.43.0"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ui/html-visual-testing/tests/.gitignore:
--------------------------------------------------------------------------------
1 | /visual.spec.ts-snapshots
2 |
--------------------------------------------------------------------------------
/ui/html-visual-testing/tests/helpers.ts:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs'
2 | import path from 'node:path'
3 | import { fileURLToPath } from 'node:url'
4 |
5 | export const HELPERS = {
6 | getDirname: () => {
7 | const __filename = fileURLToPath(import.meta.url)
8 | const __dirname = path.dirname(__filename)
9 | return { __dirname }
10 | },
11 | getConfigPath: () => path.join(HELPERS.getDirname().__dirname, '..', './config.json'),
12 | readConfig: () => JSON.parse(fs.readFileSync(HELPERS.getConfigPath())) as Record
13 | }
14 |
--------------------------------------------------------------------------------
/ui/html-visual-testing/tests/visual.spec.ts:
--------------------------------------------------------------------------------
1 | import { type Page, expect, test } from '@playwright/test'
2 | import { HELPERS } from './helpers'
3 |
4 | const config = HELPERS.readConfig()
5 |
6 | test.describe.configure({ mode: 'parallel' })
7 |
8 | const testByName = async ({ name, page, folder }: { folder: string; name: string; page: Page }) => {
9 | await page.goto('/')
10 |
11 | await page.getByRole('link', { name: folder }).click()
12 | await page.getByRole('link', { name, exact: true }).click()
13 |
14 | await expect(page.getByRole('button').first()).toBeVisible()
15 |
16 | await expect(page).toHaveScreenshot({ fullPage: true, maxDiffPixels: 0 })
17 | }
18 |
19 | for (const [folder, files] of Object.entries(config)) {
20 | test.describe(folder, () => {
21 | for (const name of files) {
22 | for (const colorScheme of ['light', 'dark'] as const) {
23 | test.describe(name, () => {
24 | test.use({ colorScheme })
25 |
26 | test(`(${colorScheme})`, ({ page }) => testByName({ page, name, folder }))
27 | })
28 | }
29 | }
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/ui/html-visual-testing/tests/visual.spec.ts-snapshots.dvc:
--------------------------------------------------------------------------------
1 | outs:
2 | - md5: 27092ecec5fc12bf94107b38b7f8df11.dir
3 | size: 5481840
4 | nfiles: 28
5 | hash: md5
6 | path: visual.spec.ts-snapshots
7 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/.gitignore:
--------------------------------------------------------------------------------
1 | src/api/types/endpoints.d.ts
2 | src/api/types/endpoints_v2.d.ts
3 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/README.md:
--------------------------------------------------------------------------------
1 | # Evidently UI
2 |
3 | Package common to `service` and `standalone`
4 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/api/types/index.ts:
--------------------------------------------------------------------------------
1 | // This file was auto-generated by openapi-typescript.
2 | // TODO: add docs
3 | import type { components, paths } from '~/api/types/endpoints'
4 |
5 | // TODO: fix this `WidgetInfo` import
6 | // use Schemas['BaseWidgetInfo'] instead
7 | import type { WidgetInfo } from '~/api'
8 |
9 | export type BackendPaths = paths
10 | ///////////////////////////////
11 | /// TYPES
12 | ///////////////////////////////
13 | type Schemas = components['schemas']
14 |
15 | type OmitNever = { [K in keyof T as T[K] extends never ? never : K]: T[K] }
16 |
17 | export type GetSearchParamsAPIs = OmitNever<{
18 | [P in keyof paths]: paths[P] extends Record ? Z : never
19 | }>
20 |
21 | export type ProjectModel = Schemas['Project']
22 | export type ReportModel = Schemas['ReportModel']
23 | export type TestSuiteModel = Schemas['TestSuiteModel']
24 |
25 | // TODO: fix this `WidgetInfo`
26 | export type DashboardInfoModel = Omit & {
27 | widgets: WidgetInfo[]
28 | }
29 |
30 | export type MetadataModel = ReportModel['metadata']
31 |
32 | export type DownloadSnapshotURL = keyof BackendPaths
33 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/api/types/utils.ts:
--------------------------------------------------------------------------------
1 | export type ID = { id: string }
2 | export type OptionalID = { id?: string | null | undefined }
3 | export type StrictID = Omit & ID
4 |
5 | // This version supports for NaN, -Infinity and Infinity.
6 | export type JSONStrExtended = string
7 |
8 | export type ErrorResponse = { status_code: number | false; detail: string }
9 |
10 | export type ErrorData = { error: ErrorResponse }
11 |
12 | ///////////////////////////////
13 | // TYPES TEST
14 | // see details here:
15 | // https://frontendmasters.com/blog/testing-types-in-typescript/
16 | ///////////////////////////////
17 |
18 | export type Expect = T
19 | type ShapesMatch = [T] extends [U] ? true : false
20 |
21 | export type TYPE_SATISFIED = ShapesMatch extends true
22 | ? ShapesMatch extends true
23 | ? true
24 | : false
25 | : false
26 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/api/types/v2.ts:
--------------------------------------------------------------------------------
1 | ///////////////////////////////
2 | /// V2 TYPES
3 | ///////////////////////////////
4 | import type { components, paths } from '~/api/types/endpoints_v2'
5 |
6 | export type BackendPaths = paths
7 |
8 | type Schemas = components['schemas']
9 |
10 | type OmitNever = { [K in keyof T as T[K] extends never ? never : K]: T[K] }
11 |
12 | export type GetSearchParamsAPIs = OmitNever<{
13 | [P in keyof paths]: paths[P] extends Record ? Z : never
14 | }>
15 |
16 | export type SeriesModel = Schemas['SeriesResponse']
17 | export type BatchMetricDataModel = Schemas['BatchMetricData']
18 | export type DashboardModel = Schemas['DashboardModel']
19 | export type DashboardPanelPlotModel = Schemas['DashboardModel']['panels'][number]
20 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/api/utils.ts:
--------------------------------------------------------------------------------
1 | import type { ErrorData, OptionalID, StrictID } from '~/api/types/utils'
2 |
3 | export const ensureID: (e: Entity) => StrictID = (e) => {
4 | if (e.id) {
5 | return { ...e, id: e.id }
6 | }
7 |
8 | throw `"id" is missing in object: ${JSON.stringify(e)}`
9 | }
10 |
11 | export const ensureIDInArray: (e: Entity[]) => StrictID[] = (
12 | e
13 | ) => {
14 | return e.map(ensureID)
15 | }
16 |
17 | export const expectJsonRequest = (request: Request) => {
18 | if (request.headers.get('Content-type') !== 'application/json') {
19 | throw new Response('Unsupported Media Type', { status: 415 })
20 | }
21 | }
22 |
23 | export const isSuccessData = (e: T): e is Exclude =>
24 | !e || typeof e !== 'object' || !('error' in e)
25 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/AlertThemed.tsx:
--------------------------------------------------------------------------------
1 | import { Alert, type AlertProps } from '@mui/material'
2 | import { useThemeMode } from '~/hooks/theme'
3 |
4 | export const AlertThemed: React.FC & { forseFilled?: boolean }> = ({
5 | forseFilled,
6 | sx,
7 | ...props
8 | }) => {
9 | const mode = useThemeMode()
10 |
11 | return (
12 | theme.applyStyles('light', { border: 'none' }),
15 | ...(Array.isArray(sx) ? sx : [sx])
16 | ]}
17 | variant={mode === 'dark' ? (forseFilled ? 'filled' : 'outlined') : undefined}
18 | {...props}
19 | />
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/AutoTabs.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import BaseTabs, { type TabInfo } from './BaseTabs'
3 |
4 | /***
5 | * Provides interactive tabs without needs to control it behavior (ie track active tabs),
6 | * but all tabs loads from start, so it could be negative on performance
7 | */
8 |
9 | interface AutoTabsProps {
10 | tabs: TabInfo[]
11 | }
12 |
13 | interface AutoTabsState {
14 | activeTab: number
15 | }
16 |
17 | const AutoTabs: React.FunctionComponent = (props) => {
18 | const [state, setState] = useState({ activeTab: 0 })
19 | return (
20 |
21 | setState((s) => ({ ...s, activeTab: newTabIdx }))}
24 | tabs={props.tabs}
25 | />
26 |
27 | )
28 | }
29 |
30 | export default AutoTabs
31 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/DashboardWidgets.tsx:
--------------------------------------------------------------------------------
1 | import { Typography } from '@mui/material'
2 | import type { WidgetInfo } from '~/api'
3 | import { DrawWidgets } from '~/components/WidgetsContent'
4 |
5 | export const DashboardWidgets = ({ widgets }: { widgets: WidgetInfo[] }) => {
6 | if (widgets.length === 0) {
7 | return (
8 |
9 | This dashboard is currently empty. Please add a monitoring panel to start.
10 |
11 | )
12 | }
13 |
14 | return
15 | }
16 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/JsonView.tsx:
--------------------------------------------------------------------------------
1 | import { useTheme } from '@mui/material'
2 | import JsonView, { type JsonViewProps } from '@uiw/react-json-view'
3 | import { githubDarkTheme } from '@uiw/react-json-view/githubDark'
4 | import { githubLightTheme } from '@uiw/react-json-view/githubLight'
5 | import { useMemo } from 'react'
6 | import { useThemeMode } from '~/hooks/theme'
7 |
8 | export const JsonViewThemed: React.FC<
9 | React.PropsWithRef<
10 | Omit, 'style' | 'displayObjectSize' | 'displayDataTypes'>
11 | >
12 | > = ({ ...props }) => {
13 | const mode = useThemeMode()
14 |
15 | const {
16 | palette: {
17 | primary: { main }
18 | }
19 | } = useTheme()
20 |
21 | const theme = useMemo(
22 | () => ({
23 | ...(mode === 'light' ? githubLightTheme : githubDarkTheme),
24 | '--w-rjv-background-color': 'transparent',
25 | '--w-rjv-ellipsis-color': main
26 | }),
27 | [mode, main]
28 | )
29 |
30 | return
31 | }
32 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/TextWithCopyIcon.tsx:
--------------------------------------------------------------------------------
1 | import ContentCopyIcon from '@mui/icons-material/ContentCopy'
2 | import { IconButton } from '@mui/material'
3 | import { Box } from '@mui/material'
4 |
5 | export const TextWithCopyIcon = ({
6 | showText,
7 | copyText
8 | }: {
9 | showText: string
10 | copyText: string
11 | }) => {
12 | return (
13 |
14 | {showText}
15 | navigator.clipboard.writeText(copyText)}
19 | >
20 |
21 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/WidgetGroup.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import { Box, Divider, Grid, Typography } from '@mui/material'
4 |
5 | interface WidgetGroupProps {
6 | title: string
7 | children: React.ReactNode
8 | }
9 |
10 | const WidgetGroup: React.FunctionComponent = (props) => (
11 |
12 | {props.title}
13 |
14 | {props.children}
15 |
16 |
17 |
18 | )
19 |
20 | export default WidgetGroup
21 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/v2/Dashboard/Panels/DashboardPanel.tsx:
--------------------------------------------------------------------------------
1 | import { assertNever } from '~/utils'
2 | import { CounterDashboardPanel, type CounterPanelProps } from './implementations/Counter'
3 | import { PieDashboardPanel, type PiePanelProps } from './implementations/Pie'
4 | import { PlotDashboardPanel, type PlotPanelProps } from './implementations/Plot'
5 | import { TextDashboardPanel, type TextPanelProps } from './implementations/Text'
6 |
7 | export type DashboardPanelProps =
8 | | PlotPanelProps
9 | | CounterPanelProps
10 | | TextPanelProps
11 | | PiePanelProps
12 |
13 | export const DashboardPanel = (props: DashboardPanelProps) => {
14 | if (props.type === 'bar' || props.type === 'line') {
15 | return
16 | }
17 |
18 | if (props.type === 'pie') {
19 | return
20 | }
21 |
22 | if (props.type === 'counter') {
23 | return
24 | }
25 |
26 | if (props.type === 'text') {
27 | return
28 | }
29 |
30 | assertNever(props.type)
31 | }
32 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/v2/Dashboard/Panels/implementations/Text.tsx:
--------------------------------------------------------------------------------
1 | import type { MakePanel } from '~/components/v2/Dashboard/Panels/types'
2 | import { PanelCardGeneral } from './helpers/general'
3 |
4 | export type TextPanelProps = MakePanel<{
5 | type: 'text'
6 | size: 'full' | 'half'
7 | title?: string
8 | description?: string
9 | }>
10 |
11 | export const TextDashboardPanel = ({ title, description }: TextPanelProps) => {
12 | return (
13 | <>
14 |
20 | >
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/components/v2/Dashboard/Panels/types.tsx:
--------------------------------------------------------------------------------
1 | type IPanelProps = { type: string; size: 'full' | 'half' }
2 |
3 | export type MakePanel = T
4 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/contexts/DashboardViewParams.tsx:
--------------------------------------------------------------------------------
1 | import type { PlotMouseEvent } from 'plotly.js'
2 | import React, { useContext } from 'react'
3 |
4 | export type DashboardViewParams = {
5 | isXaxisAsCategorical: boolean
6 | OnClickedPointComponent?: ({ event }: { event: PlotMouseEvent }) => JSX.Element
7 | OnHoveredPlotComponent?: () => JSX.Element
8 | } | null
9 |
10 | export const DashboardViewParamsContext = React.createContext(null)
11 |
12 | export const useDashboardViewParams = () => useContext(DashboardViewParamsContext)
13 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/contexts/DashboardViewParamsV2.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 |
3 | export type DashboardViewParams = {
4 | OnClickedPointComponent?: (data: { snapshotId: string }) => JSX.Element
5 | } | null
6 |
7 | export const DashboardViewParamsContext = React.createContext(null)
8 |
9 | export const useDashboardViewParams = () => useContext(DashboardViewParamsContext)
10 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/contexts/WidgetWrapper.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 |
3 | export type WidgetWrapper = {
4 | WidgetWrapper: ({ id, children }: { id: string; children: React.ReactNode }) => JSX.Element
5 | }
6 |
7 | const EmptyWidgetWrapper: WidgetWrapper['WidgetWrapper'] = ({ children }) => <>{children}>
8 |
9 | export const widgetWrapperContext = React.createContext({
10 | WidgetWrapper: EmptyWidgetWrapper
11 | })
12 |
13 | export const useWidgetWrapper = () => useContext(widgetWrapperContext)
14 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/hooks/index.tsx:
--------------------------------------------------------------------------------
1 | export * from '@uidotdev/usehooks'
2 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/hooks/theme.ts:
--------------------------------------------------------------------------------
1 | import { useColorScheme, useMediaQuery } from '@mui/material'
2 | import { useMemo } from 'react'
3 |
4 | export const useThemeMode = () => {
5 | const { mode } = useColorScheme()
6 | const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')
7 |
8 | return !mode || mode === 'system' ? (prefersDarkMode ? 'dark' : 'light') : mode
9 | }
10 |
11 | export const useNivoTheme = () => {
12 | const mode = useThemeMode()
13 |
14 | const theme = useMemo(
15 | () =>
16 | mode === 'dark'
17 | ? {
18 | tooltip: {
19 | container: {
20 | background: '#000',
21 | color: '#fff'
22 | }
23 | }
24 | }
25 | : undefined,
26 | [mode]
27 | )
28 |
29 | return theme
30 | }
31 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/hooks/useUpdateQueryStringValueWithoutNavigation.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 |
3 | export function useUpdateQueryStringValueWithoutNavigation(queryKey: string, queryValue: string) {
4 | useEffect(() => {
5 | const currentSearchParams = new URLSearchParams(window.location.search)
6 | const oldQuery = currentSearchParams.get(queryKey) ?? ''
7 | if (queryValue === oldQuery) return
8 |
9 | if (queryValue) {
10 | currentSearchParams.set(queryKey, queryValue)
11 | } else {
12 | currentSearchParams.delete(queryKey)
13 | }
14 | const newUrl = [window.location.pathname, currentSearchParams.toString()]
15 | .filter(Boolean)
16 | .join('?')
17 |
18 | window.history.replaceState(null, '', newUrl)
19 | }, [queryKey, queryValue])
20 | }
21 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/router-utils/components/breadcrumbs.tsx:
--------------------------------------------------------------------------------
1 | import { Box, Breadcrumbs as BreadcrumbsMaterial, Link } from '@mui/material'
2 | import { Link as RouterLink } from 'react-router-dom'
3 |
4 | interface Crumb {
5 | to: string
6 | linkText: string
7 | }
8 |
9 | export const BreadCrumbs = ({ crumbs }: { crumbs: Crumb[] }) => {
10 | return (
11 |
12 |
13 | {crumbs.map((crumb) => (
14 |
15 | {crumb.linkText}
16 |
17 | ))}
18 |
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/router-utils/utils.tsx:
--------------------------------------------------------------------------------
1 | import { redirect } from 'react-router-dom'
2 | import { makeRouteUrl } from '~/router-utils/router-builder'
3 | import type { GetLinkParamsByPathOnly } from '~/router-utils/types'
4 |
5 | export const createRedirect = () => {
6 | const _redirect = ({ to, paramsToReplace = {} }: GetLinkParamsByPathOnly) =>
7 | redirect(makeRouteUrl({ paramsToReplace, path: to })) as never
8 |
9 | return _redirect
10 | }
11 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/routes-components/snapshotId/index.tsx:
--------------------------------------------------------------------------------
1 | import { Box } from '@mui/material'
2 | import type { DashboardInfoModel } from '~/api/types'
3 | import { SnapshotWidgets } from '~/components/WidgetsContent'
4 | import DashboardContext, {
5 | CreateDashboardContextState,
6 | type DashboardContextState
7 | } from '~/contexts/DashboardContext'
8 |
9 | export const SnapshotTemplateComponent = ({
10 | data,
11 | dashboardContextState
12 | }: {
13 | dashboardContextState: DashboardContextState
14 | data: DashboardInfoModel
15 | }) => {
16 | return (
17 | <>
18 |
19 |
20 |
21 |
22 |
23 | >
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/shared-dependencies/mui-icons-material.tsx:
--------------------------------------------------------------------------------
1 | export * from '@mui/icons-material'
2 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/shared-dependencies/mui-material.tsx:
--------------------------------------------------------------------------------
1 | export * from '@mui/material'
2 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/shared-dependencies/openapi-fetch.tsx:
--------------------------------------------------------------------------------
1 | import createClientFunction from 'openapi-fetch'
2 | export const createClient = createClientFunction
3 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/shared-dependencies/react-hook-form.tsx:
--------------------------------------------------------------------------------
1 | export * from 'react-hook-form'
2 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/shared-dependencies/react-router-dom.tsx:
--------------------------------------------------------------------------------
1 | export * from 'react-router-dom'
2 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/shared-dependencies/zod.tsx:
--------------------------------------------------------------------------------
1 | export { zodResolver } from '@hookform/resolvers/zod'
2 | export * from 'zod'
3 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/utils/index.tsx:
--------------------------------------------------------------------------------
1 | // https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html
2 | export function assertNever(x: never): never {
3 | throw `Unexpected object: ${x}`
4 | }
5 |
6 | export function assertNeverActionVariant(x: never): never {
7 | throw `Unexpected action variant: ${x}`
8 | }
9 |
10 | export const REST_PARAMS_FOR_FETCHER_SUBMIT = {
11 | method: 'post',
12 | encType: 'application/json'
13 | } as const
14 |
15 | export const clamp = ({ value, min, max }: Record<'value' | 'min' | 'max', number>) =>
16 | Math.min(Math.max(value, min), max)
17 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/AlertStatBlock.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import { Typography } from '@mui/material'
4 | import type { AlertStats } from '~/api'
5 | import AlertBlock from './AlertBlock'
6 |
7 | interface AlertStatBlockProps {
8 | alertStats: AlertStats
9 | }
10 |
11 | const AlertStatBlock: React.FunctionComponent = (props) => {
12 | const { alertStats } = props
13 | return (
14 |
23 |
24 | - {alertStats.triggered.period} alerts triggered in the period
25 | - {alertStats.triggered.last_24h} alerts triggered in 24 hours
26 | - {alertStats.active} total active alerts
27 |
28 |
29 | }
30 | />
31 | )
32 | }
33 |
34 | export default AlertStatBlock
35 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/BigTableWidget/GraphDetails.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import type { WidgetSize } from '~/api'
4 | import LoadableView from '~/components/LoadableVIew'
5 | import DashboardContext from '~/contexts/DashboardContext'
6 | import BigGraphWidgetContent from '~/widgets/BigGraphWidgetContent'
7 |
8 | interface RowDetailsProps {
9 | graphId: string
10 | widgetSize: WidgetSize
11 | }
12 |
13 | export const GraphDetails: React.FunctionComponent = (props) => {
14 | return (
15 |
16 | {(dashboardContext) => (
17 | dashboardContext.getAdditionGraphData(props.graphId)}>
18 | {(params) => }
19 |
20 | )}
21 |
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/InsightBlock.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import { AlertTitle } from '@mui/material'
4 |
5 | import type { InsightsParams } from '~/api'
6 | import { AlertThemed } from '~/components/AlertThemed'
7 |
8 | interface InsightBlockProps {
9 | data: InsightsParams
10 | }
11 |
12 | const InsightBlock: React.FunctionComponent = (props) => {
13 | return (
14 |
15 | {props.data.title}
16 | {props.data.text}
17 |
18 | )
19 | }
20 |
21 | export default InsightBlock
22 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/NotImplementedWidgetContent.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | const NotImplementedWidgetContent: React.FunctionComponent = () => Not implemented
4 |
5 | export default NotImplementedWidgetContent
6 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/ProgressWidgetContent.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import { Box, LinearProgress, Typography } from '@mui/material'
4 |
5 | import type { PercentWidgetParams } from '~/api'
6 |
7 | const ProgressWidgetContent: React.FunctionComponent = (props) => (
8 |
9 |
10 |
11 |
12 |
13 |
14 | {`${Math.round(
15 | (props.value / props.maxValue) * 100
16 | )}%`}
17 |
18 |
19 |
20 |
21 | {props.details ?? ''}
22 |
23 |
24 |
25 | )
26 |
27 | export default ProgressWidgetContent
28 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/TabbedGraphWidgetContent.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import type { MultiTabGraphWidgetParams } from '~/api'
4 |
5 | import AutoTabs from '~/components/AutoTabs'
6 | import BigGraphWidgetContent from './BigGraphWidgetContent'
7 |
8 | const TabbedGraphWidgetContent: React.FunctionComponent<
9 | MultiTabGraphWidgetParams & { widgetSize: number }
10 | > = (props) => (
11 | ({
13 | title: g.title,
14 | tab: (
15 |
20 | )
21 | }))}
22 | />
23 | )
24 |
25 | export default TabbedGraphWidgetContent
26 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/TabbedWidgetContent.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 |
3 | import type { MultiTabWidgetParams } from '~/api'
4 |
5 | import AutoTabs from '~/components/AutoTabs'
6 | import { WidgetRenderer } from './WidgetRenderer'
7 |
8 | const TabbedWidgetContent: React.FunctionComponent<
9 | MultiTabWidgetParams & { id: string; widgetSize: number }
10 | > = (props) => {
11 | return (
12 | ({
14 | title: g.title,
15 | tab:
16 | }))}
17 | />
18 | )
19 | }
20 |
21 | export default TabbedWidgetContent
22 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/TextWidgetContent.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react'
2 | import ReactMarkdown from 'react-markdown'
3 |
4 | import type { TextWidgetParams } from '~/api'
5 |
6 | const TextWidgetContent: React.FunctionComponent = (props) => {
7 | return (
8 | <>
9 | {props.text}
10 | >
11 | )
12 | }
13 |
14 | export default TextWidgetContent
15 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/src/widgets/WidgetPanel.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Grid } from '@mui/material'
4 |
5 | interface WidgetPanelProps {
6 | children: React.ReactNode
7 | }
8 |
9 | class WidgetPanel extends React.Component {
10 | render() {
11 | return (
12 |
13 | {this.props.children}
14 |
15 | )
16 | }
17 | }
18 |
19 | export default WidgetPanel
20 |
--------------------------------------------------------------------------------
/ui/packages/evidently-ui-lib/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.ui",
3 | "compilerOptions": {
4 | "composite": true,
5 | "outDir": ".tsc-dts",
6 | "noEmit": false,
7 | "emitDeclarationOnly": true,
8 | "declaration": true,
9 | "baseUrl": "./src",
10 | "paths": {
11 | "~/*": ["*"]
12 | }
13 | },
14 | "include": ["src"]
15 | }
16 |
--------------------------------------------------------------------------------
/ui/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | # all packages in direct subdirs of packages/
3 | - 'packages/*'
4 | - 'service'
5 | - 'service_v2'
6 | - 'standalone'
7 | - 'html-visual-testing'
8 |
--------------------------------------------------------------------------------
/ui/service/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/ui/service/README.md:
--------------------------------------------------------------------------------
1 | # Evidently UI service
2 |
--------------------------------------------------------------------------------
/ui/service/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 | Evidently - ML Monitoring Demo
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ui/service/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "service",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "type-check": "tsc --build",
8 | "build": "vite build",
9 | "code-check": "biome check",
10 | "preview": "vite preview",
11 | "test": "playwright test"
12 | },
13 | "dependencies": {
14 | "evidently-ui-lib": "workspace:*",
15 | "react": "^18.2.0",
16 | "react-dom": "^18.2.0"
17 | },
18 | "devDependencies": {
19 | "wait-on": "^7.1.0",
20 | "@playwright/test": "^1.43.0",
21 | "@types/react": "^18.2.0",
22 | "@types/react-dom": "^18.2.0",
23 | "vite": "^5.2.12",
24 | "@vitejs/plugin-react-swc": "^3.7.0",
25 | "vite-tsconfig-paths": "^4.2.1",
26 | "typescript": "^5.7.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ui/service/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/service/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ui/service/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/service/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ui/service/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/service/public/favicon.ico
--------------------------------------------------------------------------------
/ui/service/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Evidently.AI",
3 | "name": "Evidently.AI Dashboards",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "favicon-96x96.png",
12 | "type": "image/png",
13 | "sizes": "96x96"
14 | }
15 | ],
16 | "start_url": ".",
17 | "display": "standalone",
18 | "theme_color": "#000000",
19 | "background_color": "#ffffff"
20 | }
21 |
--------------------------------------------------------------------------------
/ui/service/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/ui/service/src/api/index.ts:
--------------------------------------------------------------------------------
1 | import type { BackendPaths } from 'evidently-ui-lib/api/types'
2 | import { createClient } from 'evidently-ui-lib/shared-dependencies/openapi-fetch'
3 |
4 | export const clientAPI = createClient({ baseUrl: '/' })
5 |
--------------------------------------------------------------------------------
/ui/service/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | body {
7 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira
8 | Sans, Droid Sans, Helvetica Neue, sans-serif;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | }
12 |
--------------------------------------------------------------------------------
/ui/service/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 |
4 | import { CssBaseline, ThemeProvider } from 'evidently-ui-lib/shared-dependencies/mui-material'
5 | import { RouterProvider } from 'evidently-ui-lib/shared-dependencies/react-router-dom'
6 | import { theme } from 'evidently-ui-lib/theme/index'
7 | import { router } from './routes/router'
8 |
9 | import './index.css'
10 |
11 | const rootElement = document.getElementById('root')
12 |
13 | if (rootElement) {
14 | ReactDOM.createRoot(rootElement).render(
15 |
16 |
21 |
22 |
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/ui/service/src/routes/components.tsx:
--------------------------------------------------------------------------------
1 | import { CreateRouterLinkComponent } from 'evidently-ui-lib/router-utils/components/navigations'
2 | import type { Routes } from 'routes/types'
3 |
4 | export const RouterLink = CreateRouterLinkComponent()
5 |
--------------------------------------------------------------------------------
/ui/service/src/routes/hooks.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | createUseLoaderGeneral,
3 | createUseSubmitFetcherGeneral
4 | } from 'evidently-ui-lib/router-utils/fetchers'
5 | import { createUseMatchRouter } from 'evidently-ui-lib/router-utils/hooks'
6 | import type { Routes } from 'routes/types'
7 |
8 | export const useSubmitFetcher = createUseSubmitFetcherGeneral()
9 | export const useLoader = createUseLoaderGeneral()
10 | export const useMatchRouter = createUseMatchRouter()
11 |
--------------------------------------------------------------------------------
/ui/service/src/routes/router.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | decorateAllRoutes,
3 | decorateTopLevelRoutes
4 | } from 'evidently-ui-lib/router-utils/router-builder'
5 | import { createBrowserRouter } from 'evidently-ui-lib/shared-dependencies/react-router-dom'
6 | import { routes } from '~/routes/src'
7 |
8 | const finalRoutes = routes.map((r) => decorateTopLevelRoutes(r)).map((r) => decorateAllRoutes(r))
9 |
10 | export const router = createBrowserRouter(finalRoutes)
11 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/dashboard/import.tsx:
--------------------------------------------------------------------------------
1 | // export * as Dashboard from './dashboard-main'
2 |
3 | // we export it lazy because of ~2.6 MB chunk size :) plotly.js is too big :3
4 | const lazy = () => import('./dashboard-main')
5 | export const DashboardLazy = { lazy } as const
6 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/home/components.tsx:
--------------------------------------------------------------------------------
1 | import { EvidentlyLogoSvg } from 'evidently-ui-lib/components/LogoSvg'
2 | import { RouterLink } from '~/routes/components'
3 |
4 | export const HomeLink = () => (
5 | ,
10 | sx: (theme) => ({
11 | color: '#4d4d4d',
12 | ...theme.applyStyles('dark', {
13 | color: theme.palette.text.primary
14 | }),
15 | '&:hover': {
16 | borderRadius: '5px',
17 | color: theme.palette.text.disabled,
18 | ...theme.applyStyles('dark', {
19 | color: theme.palette.text.secondary
20 | })
21 | }
22 | })
23 | }}
24 | />
25 | )
26 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/home/import.tsx:
--------------------------------------------------------------------------------
1 | export * as Home from './home-main'
2 |
3 | // const lazy = () => import('./home-main')
4 | // export const Home = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/project/import.tsx:
--------------------------------------------------------------------------------
1 | export * as Project from './project-main'
2 |
3 | // const lazy = () => import('./project-main')
4 | // export const Project = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/projects-layout/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ProjectsLayout from './projects-layout-main'
2 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/projects-layout/projects-layout-main.tsx:
--------------------------------------------------------------------------------
1 | ///////////////////
2 | // ROUTE
3 | ///////////////////
4 |
5 | export const currentRoutePath = '/projects'
6 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/projects-list/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ProjectsList from './projects-list-main'
2 |
3 | // const lazy = () => import('./projects-list-main')
4 | // export const ProjectsList = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/reports-layout/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ReportsLayout from './reports-layout-main'
2 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/reports-layout/reports-layout-main.tsx:
--------------------------------------------------------------------------------
1 | import type { CrumbDefinition } from 'evidently-ui-lib/router-utils/router-builder'
2 |
3 | ///////////////////
4 | // ROUTE
5 | ///////////////////
6 |
7 | export const currentRoutePath = '/projects/:projectId/reports'
8 |
9 | const crumb: CrumbDefinition = { title: 'Reports' }
10 |
11 | export const handle = { crumb }
12 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/reports-list/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ReportsList from './reports-list-main'
2 |
3 | // const lazy = () => import('./reports-list-main')
4 | // export const Reports = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/snapshot-view/import.tsx:
--------------------------------------------------------------------------------
1 | // export * as SnapshotId from '~/routes/src/snapshot-view/snapshot-view-main'
2 |
3 | // we export it lazy because of ~2.6 MB chunk size :) plotly.js is too big :3
4 | const lazy = () => import('./snapshot-view-main')
5 | export const SnapshotIdLazy = { lazy } as const
6 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/test-suites-layout/import.tsx:
--------------------------------------------------------------------------------
1 | export * as TestSuitesLayout from './test-suites-layout-main'
2 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/test-suites-layout/test-suites-layout-main.tsx:
--------------------------------------------------------------------------------
1 | import type { CrumbDefinition } from 'evidently-ui-lib/router-utils/router-builder'
2 |
3 | ///////////////////
4 | // ROUTE
5 | ///////////////////
6 |
7 | export const currentRoutePath = '/projects/:projectId/test-suites'
8 |
9 | const crumb: CrumbDefinition = { title: 'Test Suites' }
10 |
11 | export const handle = { crumb }
12 |
--------------------------------------------------------------------------------
/ui/service/src/routes/src/test-suites-list/import.tsx:
--------------------------------------------------------------------------------
1 | export * as TestSuitesList from './test-suites-list-main'
2 |
3 | // const lazy = () => import('./projects-list-main')
4 | // export const Reports = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service/src/routes/types.tsx:
--------------------------------------------------------------------------------
1 | import type { Expect } from 'evidently-ui-lib/api/types/utils'
2 |
3 | import type {
4 | ExpectEqActuall,
5 | GetMatches,
6 | GetRouteStructure
7 | } from 'evidently-ui-lib/router-utils/types'
8 |
9 | import type { routes } from '~/routes/src'
10 |
11 | export type Routes = GetMatches
12 |
13 | export type Paths = Routes['path']
14 |
15 | export type GetRouteByPath = Extract
16 |
17 | export type __TESTS_ROUTE_STRUCTURE = Expect>>
18 |
--------------------------------------------------------------------------------
/ui/service/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ui/service/tests/.gitignore:
--------------------------------------------------------------------------------
1 | /visual.spec.ts-snapshots
2 |
--------------------------------------------------------------------------------
/ui/service/tests/visual.spec.ts-snapshots.dvc:
--------------------------------------------------------------------------------
1 | outs:
2 | - md5: cfa0fff0fbbc55830bbe5db6416ad390.dir
3 | size: 4019193
4 | nfiles: 8
5 | hash: md5
6 | path: visual.spec.ts-snapshots
7 |
--------------------------------------------------------------------------------
/ui/service/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.ui",
3 | "compilerOptions": {
4 | "baseUrl": "./src",
5 | "paths": {
6 | "~/*": ["*"]
7 | }
8 | },
9 | "include": ["src"],
10 | "references": [{ "path": "../packages/evidently-ui-lib/" }]
11 | }
12 |
--------------------------------------------------------------------------------
/ui/service/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import tsconfigPaths from 'vite-tsconfig-paths'
3 | import react from '@vitejs/plugin-react-swc'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react(), tsconfigPaths()],
8 | server: {
9 | port: 3000,
10 | proxy: {
11 | '/api': 'http://127.0.0.1:8000'
12 | }
13 | },
14 | build: {
15 | rollupOptions: {
16 | output: {
17 | assetFileNames: (assetInfo) => {
18 | let [extType] = assetInfo.name.split('.').reverse()
19 | if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
20 | // don't hash images
21 | return `static/img/[name][extname]`
22 | }
23 | // hash everything else (like css)
24 | return `static/${extType}/[name]-[hash][extname]`
25 | },
26 | chunkFileNames: 'static/js/[name]-[hash].js',
27 | entryFileNames: 'static/js/[name]-[hash].js'
28 | }
29 | }
30 | }
31 | })
32 |
--------------------------------------------------------------------------------
/ui/service_v2/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/ui/service_v2/README.md:
--------------------------------------------------------------------------------
1 | # Evidently UI service
2 |
--------------------------------------------------------------------------------
/ui/service_v2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 | Evidently - ML Monitoring Demo
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ui/service_v2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "service_v2",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "type-check": "tsc --build",
8 | "build": "vite build",
9 | "code-check": "biome check",
10 | "preview": "vite preview",
11 | "test": "playwright test"
12 | },
13 | "dependencies": {
14 | "evidently-ui-lib": "workspace:*",
15 | "dayjs": "^1.11.13",
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0",
18 | "tiny-invariant": "^1.3.3"
19 | },
20 | "devDependencies": {
21 | "wait-on": "^7.1.0",
22 | "@playwright/test": "^1.43.0",
23 | "@types/react": "^18.2.0",
24 | "@types/react-dom": "^18.2.0",
25 | "vite": "^5.2.12",
26 | "@vitejs/plugin-react-swc": "^3.7.0",
27 | "vite-tsconfig-paths": "^4.2.1",
28 | "typescript": "^5.7.2"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ui/service_v2/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/service_v2/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ui/service_v2/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/service_v2/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ui/service_v2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evidentlyai/evidently/5938939af1cf99bbe55ad4c37cee347c2e592015/ui/service_v2/public/favicon.ico
--------------------------------------------------------------------------------
/ui/service_v2/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Evidently.AI",
3 | "name": "Evidently.AI Dashboards",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "favicon-96x96.png",
12 | "type": "image/png",
13 | "sizes": "96x96"
14 | }
15 | ],
16 | "start_url": ".",
17 | "display": "standalone",
18 | "theme_color": "#000000",
19 | "background_color": "#ffffff"
20 | }
21 |
--------------------------------------------------------------------------------
/ui/service_v2/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/ui/service_v2/src/Components/GoToSnapshotButton.tsx:
--------------------------------------------------------------------------------
1 | import { useIsAnyLoaderOrActionRunning } from 'evidently-ui-lib/router-utils/hooks'
2 | import invariant from 'tiny-invariant'
3 | import { useProjectInfo } from '~/contexts/project'
4 | import { RouterLink } from '~/routes/components'
5 |
6 | const GoToSnapshotByPoint = ({ snapshotId }: { snapshotId: string }) => {
7 | const { project } = useProjectInfo()
8 | invariant(project)
9 |
10 | const isLoading = useIsAnyLoaderOrActionRunning()
11 |
12 | return (
13 |
21 | )
22 | }
23 |
24 | export const OnClickedPointComponent = GoToSnapshotByPoint
25 |
--------------------------------------------------------------------------------
/ui/service_v2/src/api/index.ts:
--------------------------------------------------------------------------------
1 | import type { BackendPaths } from 'evidently-ui-lib/api/types/v2'
2 | import { createClient } from 'evidently-ui-lib/shared-dependencies/openapi-fetch'
3 |
4 | export const clientAPI = createClient({ baseUrl: '/' })
5 |
--------------------------------------------------------------------------------
/ui/service_v2/src/contexts/project.tsx:
--------------------------------------------------------------------------------
1 | import type { ProjectModel } from 'evidently-ui-lib/api/types'
2 | import type { StrictID } from 'evidently-ui-lib/api/types/utils'
3 | import React from 'react'
4 |
5 | export const ProjectContext = React.createContext<{ project: StrictID | null }>({
6 | project: null
7 | })
8 |
9 | export const useProjectInfo = () => React.useContext(ProjectContext)
10 |
--------------------------------------------------------------------------------
/ui/service_v2/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | body {
7 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira
8 | Sans, Droid Sans, Helvetica Neue, sans-serif;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | }
12 |
--------------------------------------------------------------------------------
/ui/service_v2/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 |
4 | import { CssBaseline, ThemeProvider } from 'evidently-ui-lib/shared-dependencies/mui-material'
5 | import { RouterProvider } from 'evidently-ui-lib/shared-dependencies/react-router-dom'
6 | import { theme } from 'evidently-ui-lib/theme/index'
7 | import { router } from './routes/router'
8 |
9 | import './index.css'
10 |
11 | const rootElement = document.getElementById('root')
12 |
13 | if (rootElement) {
14 | ReactDOM.createRoot(rootElement).render(
15 |
16 |
21 |
22 |
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/components.tsx:
--------------------------------------------------------------------------------
1 | import { CreateRouterLinkComponent } from 'evidently-ui-lib/router-utils/components/navigations'
2 | import type { Routes } from 'routes/types'
3 |
4 | export const RouterLink = CreateRouterLinkComponent()
5 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/hooks.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | createUseLoaderGeneral,
3 | createUseSubmitFetcherGeneral
4 | } from 'evidently-ui-lib/router-utils/fetchers'
5 | import { createUseMatchRouter } from 'evidently-ui-lib/router-utils/hooks'
6 | import type { Routes } from 'routes/types'
7 |
8 | export const useSubmitFetcher = createUseSubmitFetcherGeneral()
9 | export const useLoader = createUseLoaderGeneral()
10 | export const useMatchRouter = createUseMatchRouter()
11 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/router.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | decorateAllRoutes,
3 | decorateTopLevelRoutes
4 | } from 'evidently-ui-lib/router-utils/router-builder'
5 | import { createBrowserRouter } from 'evidently-ui-lib/shared-dependencies/react-router-dom'
6 | import { routes } from '~/routes/src'
7 |
8 | const finalRoutes = routes.map((r) => decorateTopLevelRoutes(r)).map((r) => decorateAllRoutes(r))
9 |
10 | export const router = createBrowserRouter(finalRoutes)
11 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/dashboard/import.tsx:
--------------------------------------------------------------------------------
1 | // export * as Dashboard from './dashboard-main'
2 |
3 | // we export it lazy because of ~2.6 MB chunk size :) plotly.js is too big :3
4 | const lazy = () => import('./dashboard-main')
5 | export const DashboardLazy = { lazy } as const
6 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/home/components.tsx:
--------------------------------------------------------------------------------
1 | import { EvidentlyLogoSvg } from 'evidently-ui-lib/components/LogoSvg'
2 | import { RouterLink } from '~/routes/components'
3 |
4 | export const HomeLink = () => (
5 | ,
10 | sx: (theme) => ({
11 | color: '#4d4d4d',
12 | ...theme.applyStyles('dark', {
13 | color: theme.palette.text.primary
14 | }),
15 | '&:hover': {
16 | borderRadius: '5px',
17 | color: theme.palette.text.disabled,
18 | ...theme.applyStyles('dark', {
19 | color: theme.palette.text.secondary
20 | })
21 | }
22 | })
23 | }}
24 | />
25 | )
26 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/home/import.tsx:
--------------------------------------------------------------------------------
1 | export * as Home from './home-main'
2 |
3 | // const lazy = () => import('./home-main')
4 | // export const Home = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/load-panel-points/import.tsx:
--------------------------------------------------------------------------------
1 | export * as LoadPanelPointsAPIV2 from './load-panel-points-main'
2 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/project/import.tsx:
--------------------------------------------------------------------------------
1 | export * as Project from './project-main'
2 |
3 | // const lazy = () => import('./project-main')
4 | // export const Project = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/projects-layout/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ProjectsLayout from './projects-layout-main'
2 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/projects-layout/projects-layout-main.tsx:
--------------------------------------------------------------------------------
1 | ///////////////////
2 | // ROUTE
3 | ///////////////////
4 |
5 | export const currentRoutePath = '/projects'
6 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/projects-list/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ProjectsList from './projects-list-main'
2 |
3 | // const lazy = () => import('./projects-list-main')
4 | // export const ProjectsList = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/reports-layout/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ReportsLayout from './reports-layout-main'
2 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/reports-layout/reports-layout-main.tsx:
--------------------------------------------------------------------------------
1 | import type { CrumbDefinition } from 'evidently-ui-lib/router-utils/router-builder'
2 |
3 | ///////////////////
4 | // ROUTE
5 | ///////////////////
6 |
7 | export const currentRoutePath = '/projects/:projectId/reports'
8 |
9 | const crumb: CrumbDefinition = { title: 'Reports' }
10 |
11 | export const handle = { crumb }
12 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/reports-list/import.tsx:
--------------------------------------------------------------------------------
1 | export * as ReportsList from './reports-list-main'
2 |
3 | // const lazy = () => import('./reports-list-main')
4 | // export const Reports = { lazy } as const
5 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/src/snapshot-view/import.tsx:
--------------------------------------------------------------------------------
1 | // export * as SnapshotId from '~/routes/src/snapshot-view/snapshot-view-main'
2 |
3 | // we export it lazy because of ~2.6 MB chunk size :) plotly.js is too big :3
4 | const lazy = () => import('./snapshot-view-main')
5 | export const SnapshotIdLazy = { lazy } as const
6 |
--------------------------------------------------------------------------------
/ui/service_v2/src/routes/types.tsx:
--------------------------------------------------------------------------------
1 | import type { Expect } from 'evidently-ui-lib/api/types/utils'
2 |
3 | import type {
4 | ExpectEqActuall,
5 | GetMatches,
6 | GetRouteStructure
7 | } from 'evidently-ui-lib/router-utils/types'
8 |
9 | import type { routes } from 'routes/src'
10 |
11 | export type Routes = GetMatches
12 |
13 | export type Paths = Routes['path']
14 |
15 | export type GetRouteByPath = Extract
16 |
17 | export type __TESTS_ROUTE_STRUCTURE = Expect>>
18 |
--------------------------------------------------------------------------------
/ui/service_v2/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ui/service_v2/tests/.gitignore:
--------------------------------------------------------------------------------
1 | /visual.spec.ts-snapshots
2 |
--------------------------------------------------------------------------------
/ui/service_v2/tests/visual.spec.ts-snapshots.dvc:
--------------------------------------------------------------------------------
1 | outs:
2 | - md5: a766691a583eca68217d1d55514d7ed5.dir
3 | size: 1662020
4 | nfiles: 4
5 | hash: md5
6 | path: visual.spec.ts-snapshots
7 |
--------------------------------------------------------------------------------
/ui/service_v2/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.ui",
3 | "compilerOptions": {
4 | "baseUrl": "./src",
5 | "paths": {
6 | "~/*": ["*"]
7 | }
8 | },
9 | "include": ["src"],
10 | "references": [{ "path": "../packages/evidently-ui-lib/" }]
11 | }
12 |
--------------------------------------------------------------------------------
/ui/service_v2/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import tsconfigPaths from 'vite-tsconfig-paths'
3 | import react from '@vitejs/plugin-react-swc'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react(), tsconfigPaths()],
8 | server: {
9 | port: 3000,
10 | proxy: {
11 | '/api': 'http://127.0.0.1:8000'
12 | }
13 | },
14 | build: {
15 | rollupOptions: {
16 | output: {
17 | assetFileNames: (assetInfo) => {
18 | let [extType] = assetInfo.name.split('.').reverse()
19 | if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
20 | // don't hash images
21 | return `static/img/[name][extname]`
22 | }
23 | // hash everything else (like css)
24 | return `static/${extType}/[name]-[hash][extname]`
25 | },
26 | chunkFileNames: 'static/js/[name]-[hash].js',
27 | entryFileNames: 'static/js/[name]-[hash].js'
28 | }
29 | }
30 | }
31 | })
32 |
--------------------------------------------------------------------------------
/ui/standalone/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/ui/standalone/README.md:
--------------------------------------------------------------------------------
1 | # Evidently standalone
2 |
--------------------------------------------------------------------------------
/ui/standalone/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Evidently UI standalone
7 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ui/standalone/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "standalone",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "type-check": "tsc --build",
8 | "build": "vite build",
9 | "code-check": "biome check",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "evidently-ui-lib": "workspace:*",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.0",
19 | "@types/react-dom": "^18.2.0",
20 | "@vitejs/plugin-react-swc": "^3.7.0",
21 | "typescript": "^5.7.2",
22 | "vite": "^5.2.12",
23 | "vite-tsconfig-paths": "^4.2.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ui/standalone/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ui/standalone/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.ui",
3 | "compilerOptions": {
4 | "baseUrl": "./src"
5 | },
6 | "include": ["src"],
7 | "references": [{ "path": "../packages/evidently-ui-lib/" }]
8 | }
9 |
--------------------------------------------------------------------------------
/ui/standalone/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import tsconfigPaths from 'vite-tsconfig-paths'
3 | import react from '@vitejs/plugin-react-swc'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react(), tsconfigPaths()],
8 | build: {
9 | rollupOptions: {
10 | output: {
11 | entryFileNames: 'index.js'
12 | }
13 | }
14 | }
15 | })
16 |
--------------------------------------------------------------------------------
/ui/tsconfig.base.ui.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["ESNext", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true,
22 |
23 | "verbatimModuleSyntax": true,
24 | }
25 | }
26 |
--------------------------------------------------------------------------------