genesis-flow 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- genesis_flow-1.0.0.dist-info/METADATA +822 -0
- genesis_flow-1.0.0.dist-info/RECORD +645 -0
- genesis_flow-1.0.0.dist-info/WHEEL +5 -0
- genesis_flow-1.0.0.dist-info/entry_points.txt +19 -0
- genesis_flow-1.0.0.dist-info/licenses/LICENSE.txt +202 -0
- genesis_flow-1.0.0.dist-info/top_level.txt +1 -0
- mlflow/__init__.py +367 -0
- mlflow/__main__.py +3 -0
- mlflow/ag2/__init__.py +56 -0
- mlflow/ag2/ag2_logger.py +294 -0
- mlflow/anthropic/__init__.py +40 -0
- mlflow/anthropic/autolog.py +129 -0
- mlflow/anthropic/chat.py +144 -0
- mlflow/artifacts/__init__.py +268 -0
- mlflow/autogen/__init__.py +144 -0
- mlflow/autogen/chat.py +142 -0
- mlflow/azure/__init__.py +26 -0
- mlflow/azure/auth_handler.py +257 -0
- mlflow/azure/client.py +319 -0
- mlflow/azure/config.py +120 -0
- mlflow/azure/connection_factory.py +340 -0
- mlflow/azure/exceptions.py +27 -0
- mlflow/azure/stores.py +327 -0
- mlflow/azure/utils.py +183 -0
- mlflow/bedrock/__init__.py +45 -0
- mlflow/bedrock/_autolog.py +202 -0
- mlflow/bedrock/chat.py +122 -0
- mlflow/bedrock/stream.py +160 -0
- mlflow/bedrock/utils.py +43 -0
- mlflow/cli.py +707 -0
- mlflow/client.py +12 -0
- mlflow/config/__init__.py +56 -0
- mlflow/crewai/__init__.py +79 -0
- mlflow/crewai/autolog.py +253 -0
- mlflow/crewai/chat.py +29 -0
- mlflow/data/__init__.py +75 -0
- mlflow/data/artifact_dataset_sources.py +170 -0
- mlflow/data/code_dataset_source.py +40 -0
- mlflow/data/dataset.py +123 -0
- mlflow/data/dataset_registry.py +168 -0
- mlflow/data/dataset_source.py +110 -0
- mlflow/data/dataset_source_registry.py +219 -0
- mlflow/data/delta_dataset_source.py +167 -0
- mlflow/data/digest_utils.py +108 -0
- mlflow/data/evaluation_dataset.py +562 -0
- mlflow/data/filesystem_dataset_source.py +81 -0
- mlflow/data/http_dataset_source.py +145 -0
- mlflow/data/huggingface_dataset.py +258 -0
- mlflow/data/huggingface_dataset_source.py +118 -0
- mlflow/data/meta_dataset.py +104 -0
- mlflow/data/numpy_dataset.py +223 -0
- mlflow/data/pandas_dataset.py +231 -0
- mlflow/data/polars_dataset.py +352 -0
- mlflow/data/pyfunc_dataset_mixin.py +31 -0
- mlflow/data/schema.py +76 -0
- mlflow/data/sources.py +1 -0
- mlflow/data/spark_dataset.py +406 -0
- mlflow/data/spark_dataset_source.py +74 -0
- mlflow/data/spark_delta_utils.py +118 -0
- mlflow/data/tensorflow_dataset.py +350 -0
- mlflow/data/uc_volume_dataset_source.py +81 -0
- mlflow/db.py +27 -0
- mlflow/dspy/__init__.py +17 -0
- mlflow/dspy/autolog.py +197 -0
- mlflow/dspy/callback.py +398 -0
- mlflow/dspy/constant.py +1 -0
- mlflow/dspy/load.py +93 -0
- mlflow/dspy/save.py +393 -0
- mlflow/dspy/util.py +109 -0
- mlflow/dspy/wrapper.py +226 -0
- mlflow/entities/__init__.py +104 -0
- mlflow/entities/_mlflow_object.py +52 -0
- mlflow/entities/assessment.py +545 -0
- mlflow/entities/assessment_error.py +80 -0
- mlflow/entities/assessment_source.py +141 -0
- mlflow/entities/dataset.py +92 -0
- mlflow/entities/dataset_input.py +51 -0
- mlflow/entities/dataset_summary.py +62 -0
- mlflow/entities/document.py +48 -0
- mlflow/entities/experiment.py +109 -0
- mlflow/entities/experiment_tag.py +35 -0
- mlflow/entities/file_info.py +45 -0
- mlflow/entities/input_tag.py +35 -0
- mlflow/entities/lifecycle_stage.py +35 -0
- mlflow/entities/logged_model.py +228 -0
- mlflow/entities/logged_model_input.py +26 -0
- mlflow/entities/logged_model_output.py +32 -0
- mlflow/entities/logged_model_parameter.py +46 -0
- mlflow/entities/logged_model_status.py +74 -0
- mlflow/entities/logged_model_tag.py +33 -0
- mlflow/entities/metric.py +200 -0
- mlflow/entities/model_registry/__init__.py +29 -0
- mlflow/entities/model_registry/_model_registry_entity.py +13 -0
- mlflow/entities/model_registry/model_version.py +243 -0
- mlflow/entities/model_registry/model_version_deployment_job_run_state.py +44 -0
- mlflow/entities/model_registry/model_version_deployment_job_state.py +70 -0
- mlflow/entities/model_registry/model_version_search.py +25 -0
- mlflow/entities/model_registry/model_version_stages.py +25 -0
- mlflow/entities/model_registry/model_version_status.py +35 -0
- mlflow/entities/model_registry/model_version_tag.py +35 -0
- mlflow/entities/model_registry/prompt.py +73 -0
- mlflow/entities/model_registry/prompt_version.py +244 -0
- mlflow/entities/model_registry/registered_model.py +175 -0
- mlflow/entities/model_registry/registered_model_alias.py +35 -0
- mlflow/entities/model_registry/registered_model_deployment_job_state.py +39 -0
- mlflow/entities/model_registry/registered_model_search.py +25 -0
- mlflow/entities/model_registry/registered_model_tag.py +35 -0
- mlflow/entities/multipart_upload.py +74 -0
- mlflow/entities/param.py +49 -0
- mlflow/entities/run.py +97 -0
- mlflow/entities/run_data.py +84 -0
- mlflow/entities/run_info.py +188 -0
- mlflow/entities/run_inputs.py +59 -0
- mlflow/entities/run_outputs.py +43 -0
- mlflow/entities/run_status.py +41 -0
- mlflow/entities/run_tag.py +36 -0
- mlflow/entities/source_type.py +31 -0
- mlflow/entities/span.py +774 -0
- mlflow/entities/span_event.py +96 -0
- mlflow/entities/span_status.py +102 -0
- mlflow/entities/trace.py +317 -0
- mlflow/entities/trace_data.py +71 -0
- mlflow/entities/trace_info.py +220 -0
- mlflow/entities/trace_info_v2.py +162 -0
- mlflow/entities/trace_location.py +173 -0
- mlflow/entities/trace_state.py +39 -0
- mlflow/entities/trace_status.py +68 -0
- mlflow/entities/view_type.py +51 -0
- mlflow/environment_variables.py +866 -0
- mlflow/evaluation/__init__.py +16 -0
- mlflow/evaluation/assessment.py +369 -0
- mlflow/evaluation/evaluation.py +411 -0
- mlflow/evaluation/evaluation_tag.py +61 -0
- mlflow/evaluation/fluent.py +48 -0
- mlflow/evaluation/utils.py +201 -0
- mlflow/exceptions.py +213 -0
- mlflow/experiments.py +140 -0
- mlflow/gemini/__init__.py +81 -0
- mlflow/gemini/autolog.py +186 -0
- mlflow/gemini/chat.py +261 -0
- mlflow/genai/__init__.py +71 -0
- mlflow/genai/datasets/__init__.py +67 -0
- mlflow/genai/datasets/evaluation_dataset.py +131 -0
- mlflow/genai/evaluation/__init__.py +3 -0
- mlflow/genai/evaluation/base.py +411 -0
- mlflow/genai/evaluation/constant.py +23 -0
- mlflow/genai/evaluation/utils.py +244 -0
- mlflow/genai/judges/__init__.py +21 -0
- mlflow/genai/judges/databricks.py +404 -0
- mlflow/genai/label_schemas/__init__.py +153 -0
- mlflow/genai/label_schemas/label_schemas.py +209 -0
- mlflow/genai/labeling/__init__.py +159 -0
- mlflow/genai/labeling/labeling.py +250 -0
- mlflow/genai/optimize/__init__.py +13 -0
- mlflow/genai/optimize/base.py +198 -0
- mlflow/genai/optimize/optimizers/__init__.py +4 -0
- mlflow/genai/optimize/optimizers/base_optimizer.py +38 -0
- mlflow/genai/optimize/optimizers/dspy_mipro_optimizer.py +221 -0
- mlflow/genai/optimize/optimizers/dspy_optimizer.py +91 -0
- mlflow/genai/optimize/optimizers/utils/dspy_mipro_callback.py +76 -0
- mlflow/genai/optimize/optimizers/utils/dspy_mipro_utils.py +18 -0
- mlflow/genai/optimize/types.py +75 -0
- mlflow/genai/optimize/util.py +30 -0
- mlflow/genai/prompts/__init__.py +206 -0
- mlflow/genai/scheduled_scorers.py +431 -0
- mlflow/genai/scorers/__init__.py +26 -0
- mlflow/genai/scorers/base.py +492 -0
- mlflow/genai/scorers/builtin_scorers.py +765 -0
- mlflow/genai/scorers/scorer_utils.py +138 -0
- mlflow/genai/scorers/validation.py +165 -0
- mlflow/genai/utils/data_validation.py +146 -0
- mlflow/genai/utils/enum_utils.py +23 -0
- mlflow/genai/utils/trace_utils.py +211 -0
- mlflow/groq/__init__.py +42 -0
- mlflow/groq/_groq_autolog.py +74 -0
- mlflow/johnsnowlabs/__init__.py +888 -0
- mlflow/langchain/__init__.py +24 -0
- mlflow/langchain/api_request_parallel_processor.py +330 -0
- mlflow/langchain/autolog.py +147 -0
- mlflow/langchain/chat_agent_langgraph.py +340 -0
- mlflow/langchain/constant.py +1 -0
- mlflow/langchain/constants.py +1 -0
- mlflow/langchain/databricks_dependencies.py +444 -0
- mlflow/langchain/langchain_tracer.py +597 -0
- mlflow/langchain/model.py +919 -0
- mlflow/langchain/output_parsers.py +142 -0
- mlflow/langchain/retriever_chain.py +153 -0
- mlflow/langchain/runnables.py +527 -0
- mlflow/langchain/utils/chat.py +402 -0
- mlflow/langchain/utils/logging.py +671 -0
- mlflow/langchain/utils/serialization.py +36 -0
- mlflow/legacy_databricks_cli/__init__.py +0 -0
- mlflow/legacy_databricks_cli/configure/__init__.py +0 -0
- mlflow/legacy_databricks_cli/configure/provider.py +482 -0
- mlflow/litellm/__init__.py +175 -0
- mlflow/llama_index/__init__.py +22 -0
- mlflow/llama_index/autolog.py +55 -0
- mlflow/llama_index/chat.py +43 -0
- mlflow/llama_index/constant.py +1 -0
- mlflow/llama_index/model.py +577 -0
- mlflow/llama_index/pyfunc_wrapper.py +332 -0
- mlflow/llama_index/serialize_objects.py +188 -0
- mlflow/llama_index/tracer.py +561 -0
- mlflow/metrics/__init__.py +479 -0
- mlflow/metrics/base.py +39 -0
- mlflow/metrics/genai/__init__.py +25 -0
- mlflow/metrics/genai/base.py +101 -0
- mlflow/metrics/genai/genai_metric.py +771 -0
- mlflow/metrics/genai/metric_definitions.py +450 -0
- mlflow/metrics/genai/model_utils.py +371 -0
- mlflow/metrics/genai/prompt_template.py +68 -0
- mlflow/metrics/genai/prompts/__init__.py +0 -0
- mlflow/metrics/genai/prompts/v1.py +422 -0
- mlflow/metrics/genai/utils.py +6 -0
- mlflow/metrics/metric_definitions.py +619 -0
- mlflow/mismatch.py +34 -0
- mlflow/mistral/__init__.py +34 -0
- mlflow/mistral/autolog.py +71 -0
- mlflow/mistral/chat.py +135 -0
- mlflow/ml_package_versions.py +452 -0
- mlflow/models/__init__.py +97 -0
- mlflow/models/auth_policy.py +83 -0
- mlflow/models/cli.py +354 -0
- mlflow/models/container/__init__.py +294 -0
- mlflow/models/container/scoring_server/__init__.py +0 -0
- mlflow/models/container/scoring_server/nginx.conf +39 -0
- mlflow/models/dependencies_schemas.py +287 -0
- mlflow/models/display_utils.py +158 -0
- mlflow/models/docker_utils.py +211 -0
- mlflow/models/evaluation/__init__.py +23 -0
- mlflow/models/evaluation/_shap_patch.py +64 -0
- mlflow/models/evaluation/artifacts.py +194 -0
- mlflow/models/evaluation/base.py +1811 -0
- mlflow/models/evaluation/calibration_curve.py +109 -0
- mlflow/models/evaluation/default_evaluator.py +996 -0
- mlflow/models/evaluation/deprecated.py +23 -0
- mlflow/models/evaluation/evaluator_registry.py +80 -0
- mlflow/models/evaluation/evaluators/classifier.py +704 -0
- mlflow/models/evaluation/evaluators/default.py +233 -0
- mlflow/models/evaluation/evaluators/regressor.py +96 -0
- mlflow/models/evaluation/evaluators/shap.py +296 -0
- mlflow/models/evaluation/lift_curve.py +178 -0
- mlflow/models/evaluation/utils/metric.py +123 -0
- mlflow/models/evaluation/utils/trace.py +179 -0
- mlflow/models/evaluation/validation.py +434 -0
- mlflow/models/flavor_backend.py +93 -0
- mlflow/models/flavor_backend_registry.py +53 -0
- mlflow/models/model.py +1639 -0
- mlflow/models/model_config.py +150 -0
- mlflow/models/notebook_resources/agent_evaluation_template.html +235 -0
- mlflow/models/notebook_resources/eval_with_dataset_example.py +22 -0
- mlflow/models/notebook_resources/eval_with_synthetic_example.py +22 -0
- mlflow/models/python_api.py +369 -0
- mlflow/models/rag_signatures.py +128 -0
- mlflow/models/resources.py +321 -0
- mlflow/models/signature.py +662 -0
- mlflow/models/utils.py +2054 -0
- mlflow/models/wheeled_model.py +280 -0
- mlflow/openai/__init__.py +57 -0
- mlflow/openai/_agent_tracer.py +364 -0
- mlflow/openai/api_request_parallel_processor.py +131 -0
- mlflow/openai/autolog.py +509 -0
- mlflow/openai/constant.py +1 -0
- mlflow/openai/model.py +824 -0
- mlflow/openai/utils/chat_schema.py +367 -0
- mlflow/optuna/__init__.py +3 -0
- mlflow/optuna/storage.py +646 -0
- mlflow/plugins/__init__.py +72 -0
- mlflow/plugins/base.py +358 -0
- mlflow/plugins/builtin/__init__.py +24 -0
- mlflow/plugins/builtin/pytorch_plugin.py +150 -0
- mlflow/plugins/builtin/sklearn_plugin.py +158 -0
- mlflow/plugins/builtin/transformers_plugin.py +187 -0
- mlflow/plugins/cli.py +321 -0
- mlflow/plugins/discovery.py +340 -0
- mlflow/plugins/manager.py +465 -0
- mlflow/plugins/registry.py +316 -0
- mlflow/plugins/templates/framework_plugin_template.py +329 -0
- mlflow/prompt/constants.py +20 -0
- mlflow/prompt/promptlab_model.py +197 -0
- mlflow/prompt/registry_utils.py +248 -0
- mlflow/promptflow/__init__.py +495 -0
- mlflow/protos/__init__.py +0 -0
- mlflow/protos/assessments_pb2.py +174 -0
- mlflow/protos/databricks_artifacts_pb2.py +489 -0
- mlflow/protos/databricks_filesystem_service_pb2.py +196 -0
- mlflow/protos/databricks_managed_catalog_messages_pb2.py +95 -0
- mlflow/protos/databricks_managed_catalog_service_pb2.py +86 -0
- mlflow/protos/databricks_pb2.py +267 -0
- mlflow/protos/databricks_trace_server_pb2.py +374 -0
- mlflow/protos/databricks_uc_registry_messages_pb2.py +1249 -0
- mlflow/protos/databricks_uc_registry_service_pb2.py +170 -0
- mlflow/protos/facet_feature_statistics_pb2.py +296 -0
- mlflow/protos/internal_pb2.py +77 -0
- mlflow/protos/mlflow_artifacts_pb2.py +336 -0
- mlflow/protos/model_registry_pb2.py +1073 -0
- mlflow/protos/scalapb/__init__.py +0 -0
- mlflow/protos/scalapb/scalapb_pb2.py +104 -0
- mlflow/protos/service_pb2.py +2600 -0
- mlflow/protos/unity_catalog_oss_messages_pb2.py +457 -0
- mlflow/protos/unity_catalog_oss_service_pb2.py +130 -0
- mlflow/protos/unity_catalog_prompt_messages_pb2.py +447 -0
- mlflow/protos/unity_catalog_prompt_messages_pb2_grpc.py +24 -0
- mlflow/protos/unity_catalog_prompt_service_pb2.py +164 -0
- mlflow/protos/unity_catalog_prompt_service_pb2_grpc.py +785 -0
- mlflow/py.typed +0 -0
- mlflow/pydantic_ai/__init__.py +57 -0
- mlflow/pydantic_ai/autolog.py +173 -0
- mlflow/pyfunc/__init__.py +3844 -0
- mlflow/pyfunc/_mlflow_pyfunc_backend_predict.py +61 -0
- mlflow/pyfunc/backend.py +523 -0
- mlflow/pyfunc/context.py +78 -0
- mlflow/pyfunc/dbconnect_artifact_cache.py +144 -0
- mlflow/pyfunc/loaders/__init__.py +7 -0
- mlflow/pyfunc/loaders/chat_agent.py +117 -0
- mlflow/pyfunc/loaders/chat_model.py +125 -0
- mlflow/pyfunc/loaders/code_model.py +31 -0
- mlflow/pyfunc/loaders/responses_agent.py +112 -0
- mlflow/pyfunc/mlserver.py +46 -0
- mlflow/pyfunc/model.py +1473 -0
- mlflow/pyfunc/scoring_server/__init__.py +604 -0
- mlflow/pyfunc/scoring_server/app.py +7 -0
- mlflow/pyfunc/scoring_server/client.py +146 -0
- mlflow/pyfunc/spark_model_cache.py +48 -0
- mlflow/pyfunc/stdin_server.py +44 -0
- mlflow/pyfunc/utils/__init__.py +3 -0
- mlflow/pyfunc/utils/data_validation.py +224 -0
- mlflow/pyfunc/utils/environment.py +22 -0
- mlflow/pyfunc/utils/input_converter.py +47 -0
- mlflow/pyfunc/utils/serving_data_parser.py +11 -0
- mlflow/pytorch/__init__.py +1171 -0
- mlflow/pytorch/_lightning_autolog.py +580 -0
- mlflow/pytorch/_pytorch_autolog.py +50 -0
- mlflow/pytorch/pickle_module.py +35 -0
- mlflow/rfunc/__init__.py +42 -0
- mlflow/rfunc/backend.py +134 -0
- mlflow/runs.py +89 -0
- mlflow/server/__init__.py +302 -0
- mlflow/server/auth/__init__.py +1224 -0
- mlflow/server/auth/__main__.py +4 -0
- mlflow/server/auth/basic_auth.ini +6 -0
- mlflow/server/auth/cli.py +11 -0
- mlflow/server/auth/client.py +537 -0
- mlflow/server/auth/config.py +34 -0
- mlflow/server/auth/db/__init__.py +0 -0
- mlflow/server/auth/db/cli.py +18 -0
- mlflow/server/auth/db/migrations/__init__.py +0 -0
- mlflow/server/auth/db/migrations/alembic.ini +110 -0
- mlflow/server/auth/db/migrations/env.py +76 -0
- mlflow/server/auth/db/migrations/versions/8606fa83a998_initial_migration.py +51 -0
- mlflow/server/auth/db/migrations/versions/__init__.py +0 -0
- mlflow/server/auth/db/models.py +67 -0
- mlflow/server/auth/db/utils.py +37 -0
- mlflow/server/auth/entities.py +165 -0
- mlflow/server/auth/logo.py +14 -0
- mlflow/server/auth/permissions.py +65 -0
- mlflow/server/auth/routes.py +18 -0
- mlflow/server/auth/sqlalchemy_store.py +263 -0
- mlflow/server/graphql/__init__.py +0 -0
- mlflow/server/graphql/autogenerated_graphql_schema.py +353 -0
- mlflow/server/graphql/graphql_custom_scalars.py +24 -0
- mlflow/server/graphql/graphql_errors.py +15 -0
- mlflow/server/graphql/graphql_no_batching.py +89 -0
- mlflow/server/graphql/graphql_schema_extensions.py +74 -0
- mlflow/server/handlers.py +3217 -0
- mlflow/server/prometheus_exporter.py +17 -0
- mlflow/server/validation.py +30 -0
- mlflow/shap/__init__.py +691 -0
- mlflow/sklearn/__init__.py +1994 -0
- mlflow/sklearn/utils.py +1041 -0
- mlflow/smolagents/__init__.py +66 -0
- mlflow/smolagents/autolog.py +139 -0
- mlflow/smolagents/chat.py +29 -0
- mlflow/store/__init__.py +10 -0
- mlflow/store/_unity_catalog/__init__.py +1 -0
- mlflow/store/_unity_catalog/lineage/__init__.py +1 -0
- mlflow/store/_unity_catalog/lineage/constants.py +2 -0
- mlflow/store/_unity_catalog/registry/__init__.py +6 -0
- mlflow/store/_unity_catalog/registry/prompt_info.py +75 -0
- mlflow/store/_unity_catalog/registry/rest_store.py +1740 -0
- mlflow/store/_unity_catalog/registry/uc_oss_rest_store.py +507 -0
- mlflow/store/_unity_catalog/registry/utils.py +121 -0
- mlflow/store/artifact/__init__.py +0 -0
- mlflow/store/artifact/artifact_repo.py +472 -0
- mlflow/store/artifact/artifact_repository_registry.py +154 -0
- mlflow/store/artifact/azure_blob_artifact_repo.py +275 -0
- mlflow/store/artifact/azure_data_lake_artifact_repo.py +295 -0
- mlflow/store/artifact/cli.py +141 -0
- mlflow/store/artifact/cloud_artifact_repo.py +332 -0
- mlflow/store/artifact/databricks_artifact_repo.py +729 -0
- mlflow/store/artifact/databricks_artifact_repo_resources.py +301 -0
- mlflow/store/artifact/databricks_logged_model_artifact_repo.py +93 -0
- mlflow/store/artifact/databricks_models_artifact_repo.py +216 -0
- mlflow/store/artifact/databricks_sdk_artifact_repo.py +134 -0
- mlflow/store/artifact/databricks_sdk_models_artifact_repo.py +97 -0
- mlflow/store/artifact/dbfs_artifact_repo.py +240 -0
- mlflow/store/artifact/ftp_artifact_repo.py +132 -0
- mlflow/store/artifact/gcs_artifact_repo.py +296 -0
- mlflow/store/artifact/hdfs_artifact_repo.py +209 -0
- mlflow/store/artifact/http_artifact_repo.py +218 -0
- mlflow/store/artifact/local_artifact_repo.py +142 -0
- mlflow/store/artifact/mlflow_artifacts_repo.py +94 -0
- mlflow/store/artifact/models_artifact_repo.py +259 -0
- mlflow/store/artifact/optimized_s3_artifact_repo.py +356 -0
- mlflow/store/artifact/presigned_url_artifact_repo.py +173 -0
- mlflow/store/artifact/r2_artifact_repo.py +70 -0
- mlflow/store/artifact/runs_artifact_repo.py +265 -0
- mlflow/store/artifact/s3_artifact_repo.py +330 -0
- mlflow/store/artifact/sftp_artifact_repo.py +141 -0
- mlflow/store/artifact/uc_volume_artifact_repo.py +76 -0
- mlflow/store/artifact/unity_catalog_models_artifact_repo.py +168 -0
- mlflow/store/artifact/unity_catalog_oss_models_artifact_repo.py +168 -0
- mlflow/store/artifact/utils/__init__.py +0 -0
- mlflow/store/artifact/utils/models.py +148 -0
- mlflow/store/db/__init__.py +0 -0
- mlflow/store/db/base_sql_model.py +3 -0
- mlflow/store/db/db_types.py +10 -0
- mlflow/store/db/utils.py +314 -0
- mlflow/store/db_migrations/__init__.py +0 -0
- mlflow/store/db_migrations/alembic.ini +74 -0
- mlflow/store/db_migrations/env.py +84 -0
- mlflow/store/db_migrations/versions/0584bdc529eb_add_cascading_deletion_to_datasets_from_experiments.py +88 -0
- mlflow/store/db_migrations/versions/0a8213491aaa_drop_duplicate_killed_constraint.py +49 -0
- mlflow/store/db_migrations/versions/0c779009ac13_add_deleted_time_field_to_runs_table.py +24 -0
- mlflow/store/db_migrations/versions/181f10493468_allow_nulls_for_metric_values.py +35 -0
- mlflow/store/db_migrations/versions/27a6a02d2cf1_add_model_version_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/2b4d017a5e9b_add_model_registry_tables_to_db.py +77 -0
- mlflow/store/db_migrations/versions/2d6e25af4d3e_increase_max_param_val_length.py +33 -0
- mlflow/store/db_migrations/versions/3500859a5d39_add_model_aliases_table.py +50 -0
- mlflow/store/db_migrations/versions/39d1c3be5f05_add_is_nan_constraint_for_metrics_tables_if_necessary.py +41 -0
- mlflow/store/db_migrations/versions/400f98739977_add_logged_model_tables.py +123 -0
- mlflow/store/db_migrations/versions/4465047574b1_increase_max_dataset_schema_size.py +38 -0
- mlflow/store/db_migrations/versions/451aebb31d03_add_metric_step.py +35 -0
- mlflow/store/db_migrations/versions/5b0e9adcef9c_add_cascade_deletion_to_trace_tables_fk.py +40 -0
- mlflow/store/db_migrations/versions/6953534de441_add_step_to_inputs_table.py +25 -0
- mlflow/store/db_migrations/versions/728d730b5ebd_add_registered_model_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/7ac759974ad8_update_run_tags_with_larger_limit.py +36 -0
- mlflow/store/db_migrations/versions/7f2a7d5fae7d_add_datasets_inputs_input_tags_tables.py +82 -0
- mlflow/store/db_migrations/versions/84291f40a231_add_run_link_to_model_version.py +26 -0
- mlflow/store/db_migrations/versions/867495a8f9d4_add_trace_tables.py +90 -0
- mlflow/store/db_migrations/versions/89d4b8295536_create_latest_metrics_table.py +169 -0
- mlflow/store/db_migrations/versions/90e64c465722_migrate_user_column_to_tags.py +64 -0
- mlflow/store/db_migrations/versions/97727af70f4d_creation_time_last_update_time_experiments.py +25 -0
- mlflow/store/db_migrations/versions/__init__.py +0 -0
- mlflow/store/db_migrations/versions/a8c4a736bde6_allow_nulls_for_run_id.py +27 -0
- mlflow/store/db_migrations/versions/acf3f17fdcc7_add_storage_location_field_to_model_.py +29 -0
- mlflow/store/db_migrations/versions/bd07f7e963c5_create_index_on_run_uuid.py +26 -0
- mlflow/store/db_migrations/versions/bda7b8c39065_increase_model_version_tag_value_limit.py +38 -0
- mlflow/store/db_migrations/versions/c48cb773bb87_reset_default_value_for_is_nan_in_metrics_table_for_mysql.py +41 -0
- mlflow/store/db_migrations/versions/cbc13b556ace_add_v3_trace_schema_columns.py +31 -0
- mlflow/store/db_migrations/versions/cc1f77228345_change_param_value_length_to_500.py +34 -0
- mlflow/store/db_migrations/versions/cfd24bdc0731_update_run_status_constraint_with_killed.py +78 -0
- mlflow/store/db_migrations/versions/df50e92ffc5e_add_experiment_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/f5a4f2784254_increase_run_tag_value_limit.py +36 -0
- mlflow/store/entities/__init__.py +3 -0
- mlflow/store/entities/paged_list.py +18 -0
- mlflow/store/model_registry/__init__.py +10 -0
- mlflow/store/model_registry/abstract_store.py +1081 -0
- mlflow/store/model_registry/base_rest_store.py +44 -0
- mlflow/store/model_registry/databricks_workspace_model_registry_rest_store.py +37 -0
- mlflow/store/model_registry/dbmodels/__init__.py +0 -0
- mlflow/store/model_registry/dbmodels/models.py +206 -0
- mlflow/store/model_registry/file_store.py +1091 -0
- mlflow/store/model_registry/rest_store.py +481 -0
- mlflow/store/model_registry/sqlalchemy_store.py +1286 -0
- mlflow/store/tracking/__init__.py +23 -0
- mlflow/store/tracking/abstract_store.py +816 -0
- mlflow/store/tracking/dbmodels/__init__.py +0 -0
- mlflow/store/tracking/dbmodels/initial_models.py +243 -0
- mlflow/store/tracking/dbmodels/models.py +1073 -0
- mlflow/store/tracking/file_store.py +2438 -0
- mlflow/store/tracking/postgres_managed_identity.py +146 -0
- mlflow/store/tracking/rest_store.py +1131 -0
- mlflow/store/tracking/sqlalchemy_store.py +2785 -0
- mlflow/system_metrics/__init__.py +61 -0
- mlflow/system_metrics/metrics/__init__.py +0 -0
- mlflow/system_metrics/metrics/base_metrics_monitor.py +32 -0
- mlflow/system_metrics/metrics/cpu_monitor.py +23 -0
- mlflow/system_metrics/metrics/disk_monitor.py +21 -0
- mlflow/system_metrics/metrics/gpu_monitor.py +71 -0
- mlflow/system_metrics/metrics/network_monitor.py +34 -0
- mlflow/system_metrics/metrics/rocm_monitor.py +123 -0
- mlflow/system_metrics/system_metrics_monitor.py +198 -0
- mlflow/tracing/__init__.py +16 -0
- mlflow/tracing/assessment.py +356 -0
- mlflow/tracing/client.py +531 -0
- mlflow/tracing/config.py +125 -0
- mlflow/tracing/constant.py +105 -0
- mlflow/tracing/destination.py +81 -0
- mlflow/tracing/display/__init__.py +40 -0
- mlflow/tracing/display/display_handler.py +196 -0
- mlflow/tracing/export/async_export_queue.py +186 -0
- mlflow/tracing/export/inference_table.py +138 -0
- mlflow/tracing/export/mlflow_v3.py +137 -0
- mlflow/tracing/export/utils.py +70 -0
- mlflow/tracing/fluent.py +1417 -0
- mlflow/tracing/processor/base_mlflow.py +199 -0
- mlflow/tracing/processor/inference_table.py +175 -0
- mlflow/tracing/processor/mlflow_v3.py +47 -0
- mlflow/tracing/processor/otel.py +73 -0
- mlflow/tracing/provider.py +487 -0
- mlflow/tracing/trace_manager.py +200 -0
- mlflow/tracing/utils/__init__.py +616 -0
- mlflow/tracing/utils/artifact_utils.py +28 -0
- mlflow/tracing/utils/copy.py +55 -0
- mlflow/tracing/utils/environment.py +55 -0
- mlflow/tracing/utils/exception.py +21 -0
- mlflow/tracing/utils/once.py +35 -0
- mlflow/tracing/utils/otlp.py +63 -0
- mlflow/tracing/utils/processor.py +54 -0
- mlflow/tracing/utils/search.py +292 -0
- mlflow/tracing/utils/timeout.py +250 -0
- mlflow/tracing/utils/token.py +19 -0
- mlflow/tracing/utils/truncation.py +124 -0
- mlflow/tracing/utils/warning.py +76 -0
- mlflow/tracking/__init__.py +39 -0
- mlflow/tracking/_model_registry/__init__.py +1 -0
- mlflow/tracking/_model_registry/client.py +764 -0
- mlflow/tracking/_model_registry/fluent.py +853 -0
- mlflow/tracking/_model_registry/registry.py +67 -0
- mlflow/tracking/_model_registry/utils.py +251 -0
- mlflow/tracking/_tracking_service/__init__.py +0 -0
- mlflow/tracking/_tracking_service/client.py +883 -0
- mlflow/tracking/_tracking_service/registry.py +56 -0
- mlflow/tracking/_tracking_service/utils.py +275 -0
- mlflow/tracking/artifact_utils.py +179 -0
- mlflow/tracking/client.py +5900 -0
- mlflow/tracking/context/__init__.py +0 -0
- mlflow/tracking/context/abstract_context.py +35 -0
- mlflow/tracking/context/databricks_cluster_context.py +15 -0
- mlflow/tracking/context/databricks_command_context.py +15 -0
- mlflow/tracking/context/databricks_job_context.py +49 -0
- mlflow/tracking/context/databricks_notebook_context.py +41 -0
- mlflow/tracking/context/databricks_repo_context.py +43 -0
- mlflow/tracking/context/default_context.py +51 -0
- mlflow/tracking/context/git_context.py +32 -0
- mlflow/tracking/context/registry.py +98 -0
- mlflow/tracking/context/system_environment_context.py +15 -0
- mlflow/tracking/default_experiment/__init__.py +1 -0
- mlflow/tracking/default_experiment/abstract_context.py +43 -0
- mlflow/tracking/default_experiment/databricks_notebook_experiment_provider.py +44 -0
- mlflow/tracking/default_experiment/registry.py +75 -0
- mlflow/tracking/fluent.py +3595 -0
- mlflow/tracking/metric_value_conversion_utils.py +93 -0
- mlflow/tracking/multimedia.py +206 -0
- mlflow/tracking/registry.py +86 -0
- mlflow/tracking/request_auth/__init__.py +0 -0
- mlflow/tracking/request_auth/abstract_request_auth_provider.py +34 -0
- mlflow/tracking/request_auth/registry.py +60 -0
- mlflow/tracking/request_header/__init__.py +0 -0
- mlflow/tracking/request_header/abstract_request_header_provider.py +36 -0
- mlflow/tracking/request_header/databricks_request_header_provider.py +38 -0
- mlflow/tracking/request_header/default_request_header_provider.py +17 -0
- mlflow/tracking/request_header/registry.py +79 -0
- mlflow/transformers/__init__.py +2982 -0
- mlflow/transformers/flavor_config.py +258 -0
- mlflow/transformers/hub_utils.py +83 -0
- mlflow/transformers/llm_inference_utils.py +468 -0
- mlflow/transformers/model_io.py +301 -0
- mlflow/transformers/peft.py +51 -0
- mlflow/transformers/signature.py +183 -0
- mlflow/transformers/torch_utils.py +55 -0
- mlflow/types/__init__.py +21 -0
- mlflow/types/agent.py +270 -0
- mlflow/types/chat.py +240 -0
- mlflow/types/llm.py +935 -0
- mlflow/types/responses.py +139 -0
- mlflow/types/responses_helpers.py +416 -0
- mlflow/types/schema.py +1505 -0
- mlflow/types/type_hints.py +647 -0
- mlflow/types/utils.py +753 -0
- mlflow/utils/__init__.py +283 -0
- mlflow/utils/_capture_modules.py +256 -0
- mlflow/utils/_capture_transformers_modules.py +75 -0
- mlflow/utils/_spark_utils.py +201 -0
- mlflow/utils/_unity_catalog_oss_utils.py +97 -0
- mlflow/utils/_unity_catalog_utils.py +479 -0
- mlflow/utils/annotations.py +218 -0
- mlflow/utils/arguments_utils.py +16 -0
- mlflow/utils/async_logging/__init__.py +1 -0
- mlflow/utils/async_logging/async_artifacts_logging_queue.py +258 -0
- mlflow/utils/async_logging/async_logging_queue.py +366 -0
- mlflow/utils/async_logging/run_artifact.py +38 -0
- mlflow/utils/async_logging/run_batch.py +58 -0
- mlflow/utils/async_logging/run_operations.py +49 -0
- mlflow/utils/autologging_utils/__init__.py +737 -0
- mlflow/utils/autologging_utils/client.py +432 -0
- mlflow/utils/autologging_utils/config.py +33 -0
- mlflow/utils/autologging_utils/events.py +294 -0
- mlflow/utils/autologging_utils/logging_and_warnings.py +328 -0
- mlflow/utils/autologging_utils/metrics_queue.py +71 -0
- mlflow/utils/autologging_utils/safety.py +1104 -0
- mlflow/utils/autologging_utils/versioning.py +95 -0
- mlflow/utils/checkpoint_utils.py +206 -0
- mlflow/utils/class_utils.py +6 -0
- mlflow/utils/cli_args.py +257 -0
- mlflow/utils/conda.py +354 -0
- mlflow/utils/credentials.py +231 -0
- mlflow/utils/data_utils.py +17 -0
- mlflow/utils/databricks_utils.py +1436 -0
- mlflow/utils/docstring_utils.py +477 -0
- mlflow/utils/doctor.py +133 -0
- mlflow/utils/download_cloud_file_chunk.py +43 -0
- mlflow/utils/env_manager.py +16 -0
- mlflow/utils/env_pack.py +131 -0
- mlflow/utils/environment.py +1009 -0
- mlflow/utils/exception_utils.py +14 -0
- mlflow/utils/file_utils.py +978 -0
- mlflow/utils/git_utils.py +77 -0
- mlflow/utils/gorilla.py +797 -0
- mlflow/utils/import_hooks/__init__.py +363 -0
- mlflow/utils/lazy_load.py +51 -0
- mlflow/utils/logging_utils.py +168 -0
- mlflow/utils/mime_type_utils.py +58 -0
- mlflow/utils/mlflow_tags.py +103 -0
- mlflow/utils/model_utils.py +486 -0
- mlflow/utils/name_utils.py +346 -0
- mlflow/utils/nfs_on_spark.py +62 -0
- mlflow/utils/openai_utils.py +164 -0
- mlflow/utils/os.py +12 -0
- mlflow/utils/oss_registry_utils.py +29 -0
- mlflow/utils/plugins.py +17 -0
- mlflow/utils/process.py +182 -0
- mlflow/utils/promptlab_utils.py +146 -0
- mlflow/utils/proto_json_utils.py +743 -0
- mlflow/utils/pydantic_utils.py +54 -0
- mlflow/utils/request_utils.py +279 -0
- mlflow/utils/requirements_utils.py +704 -0
- mlflow/utils/rest_utils.py +673 -0
- mlflow/utils/search_logged_model_utils.py +127 -0
- mlflow/utils/search_utils.py +2111 -0
- mlflow/utils/secure_loading.py +221 -0
- mlflow/utils/security_validation.py +384 -0
- mlflow/utils/server_cli_utils.py +61 -0
- mlflow/utils/spark_utils.py +15 -0
- mlflow/utils/string_utils.py +138 -0
- mlflow/utils/thread_utils.py +63 -0
- mlflow/utils/time.py +54 -0
- mlflow/utils/timeout.py +42 -0
- mlflow/utils/uri.py +572 -0
- mlflow/utils/validation.py +662 -0
- mlflow/utils/virtualenv.py +458 -0
- mlflow/utils/warnings_utils.py +25 -0
- mlflow/utils/yaml_utils.py +179 -0
- mlflow/version.py +24 -0
@@ -0,0 +1,604 @@
|
|
1
|
+
"""
|
2
|
+
Scoring server for python model format.
|
3
|
+
The passed int model is expected to have function:
|
4
|
+
predict(pandas.Dataframe) -> pandas.DataFrame
|
5
|
+
|
6
|
+
Input, expected in text/csv or application/json format,
|
7
|
+
is parsed into pandas.DataFrame and passed to the model.
|
8
|
+
|
9
|
+
Defines four endpoints:
|
10
|
+
/ping used for health check
|
11
|
+
/health (same as /ping)
|
12
|
+
/version used for getting the mlflow version
|
13
|
+
/invocations used for scoring
|
14
|
+
"""
|
15
|
+
|
16
|
+
import asyncio
|
17
|
+
import inspect
|
18
|
+
import json
|
19
|
+
import logging
|
20
|
+
import os
|
21
|
+
import shlex
|
22
|
+
import sys
|
23
|
+
import traceback
|
24
|
+
from functools import wraps
|
25
|
+
from typing import Any, NamedTuple, Optional
|
26
|
+
|
27
|
+
from mlflow.environment_variables import (
|
28
|
+
_MLFLOW_IS_IN_SERVING_ENVIRONMENT,
|
29
|
+
MLFLOW_SCORING_SERVER_REQUEST_TIMEOUT,
|
30
|
+
)
|
31
|
+
|
32
|
+
# NB: We need to be careful what we import form mlflow here. Scoring server is used from within
|
33
|
+
# model's conda environment. The version of mlflow doing the serving (outside) and the version of
|
34
|
+
# mlflow in the model's conda environment (inside) can differ. We should therefore keep mlflow
|
35
|
+
# dependencies to the minimum here.
|
36
|
+
# ALl of the mlflow dependencies below need to be backwards compatible.
|
37
|
+
from mlflow.exceptions import MlflowException
|
38
|
+
from mlflow.pyfunc.model import _log_warning_if_params_not_in_predict_signature
|
39
|
+
from mlflow.types import ParamSchema, Schema
|
40
|
+
from mlflow.utils import reraise
|
41
|
+
from mlflow.utils.file_utils import path_to_local_file_uri
|
42
|
+
from mlflow.utils.proto_json_utils import (
|
43
|
+
MlflowInvalidInputException,
|
44
|
+
NumpyEncoder,
|
45
|
+
_get_jsonable_obj,
|
46
|
+
dataframe_from_parsed_json,
|
47
|
+
parse_tf_serving_input,
|
48
|
+
)
|
49
|
+
from mlflow.version import VERSION
|
50
|
+
|
51
|
+
try:
|
52
|
+
from mlflow.pyfunc import PyFuncModel, load_model
|
53
|
+
except ImportError:
|
54
|
+
from mlflow.pyfunc import load_pyfunc as load_model
|
55
|
+
from io import StringIO
|
56
|
+
|
57
|
+
from mlflow.protos.databricks_pb2 import BAD_REQUEST, INVALID_PARAMETER_VALUE
|
58
|
+
from mlflow.pyfunc.utils.serving_data_parser import is_unified_llm_input
|
59
|
+
|
60
|
+
_SERVER_MODEL_PATH = "__pyfunc_model_path__"
|
61
|
+
SERVING_MODEL_CONFIG = "SERVING_MODEL_CONFIG"
|
62
|
+
|
63
|
+
CONTENT_TYPE_CSV = "text/csv"
|
64
|
+
CONTENT_TYPE_JSON = "application/json"
|
65
|
+
|
66
|
+
CONTENT_TYPES = [
|
67
|
+
CONTENT_TYPE_CSV,
|
68
|
+
CONTENT_TYPE_JSON,
|
69
|
+
]
|
70
|
+
|
71
|
+
_logger = logging.getLogger(__name__)
|
72
|
+
|
73
|
+
DF_RECORDS = "dataframe_records"
|
74
|
+
DF_SPLIT = "dataframe_split"
|
75
|
+
INSTANCES = "instances"
|
76
|
+
INPUTS = "inputs"
|
77
|
+
|
78
|
+
SUPPORTED_FORMATS = {DF_RECORDS, DF_SPLIT, INSTANCES, INPUTS}
|
79
|
+
SERVING_PARAMS_KEY = "params"
|
80
|
+
|
81
|
+
REQUIRED_INPUT_FORMAT = (
|
82
|
+
f"The input must be a JSON dictionary with exactly one of the input fields {SUPPORTED_FORMATS}"
|
83
|
+
)
|
84
|
+
SCORING_PROTOCOL_CHANGE_INFO = (
|
85
|
+
"IMPORTANT: The MLflow Model scoring protocol has changed in MLflow version 2.0. If you are"
|
86
|
+
" seeing this error, you are likely using an outdated scoring request format. To resolve the"
|
87
|
+
" error, either update your request format or adjust your MLflow Model's requirements file to"
|
88
|
+
" specify an older version of MLflow (for example, change the 'mlflow' requirement specifier"
|
89
|
+
" to 'mlflow==1.30.0'). If you are making a request using the MLflow client"
|
90
|
+
" (e.g. via `mlflow.pyfunc.spark_udf()`), upgrade your MLflow client to a version >= 2.0 in"
|
91
|
+
" order to use the new request format. For more information about the updated MLflow"
|
92
|
+
" Model scoring protocol in MLflow 2.0, see"
|
93
|
+
" https://mlflow.org/docs/latest/models.html#deploy-mlflow-models."
|
94
|
+
)
|
95
|
+
|
96
|
+
|
97
|
+
def load_model_with_mlflow_config(model_uri):
|
98
|
+
extra_kwargs = {}
|
99
|
+
if model_config_json := os.environ.get(SERVING_MODEL_CONFIG):
|
100
|
+
extra_kwargs["model_config"] = json.loads(model_config_json)
|
101
|
+
|
102
|
+
return load_model(model_uri, **extra_kwargs)
|
103
|
+
|
104
|
+
|
105
|
+
# Keep this method to maintain compatibility with MLServer
|
106
|
+
# https://github.com/SeldonIO/MLServer/blob/caa173ab099a4ec002a7c252cbcc511646c261a6/runtimes/mlflow/mlserver_mlflow/runtime.py#L13C5-L13C31
|
107
|
+
def infer_and_parse_json_input(json_input, schema: Schema = None):
|
108
|
+
"""
|
109
|
+
Args:
|
110
|
+
json_input: A JSON-formatted string representation of TF serving input or a Pandas
|
111
|
+
DataFrame, or a stream containing such a string representation.
|
112
|
+
schema: Optional schema specification to be used during parsing.
|
113
|
+
"""
|
114
|
+
if isinstance(json_input, dict):
|
115
|
+
decoded_input = json_input
|
116
|
+
else:
|
117
|
+
try:
|
118
|
+
decoded_input = json.loads(json_input)
|
119
|
+
except json.decoder.JSONDecodeError as ex:
|
120
|
+
raise MlflowException(
|
121
|
+
message=(
|
122
|
+
"Failed to parse input from JSON. Ensure that input is a valid JSON"
|
123
|
+
f" formatted string. Error: '{ex}'. Input: \n{json_input}\n"
|
124
|
+
),
|
125
|
+
error_code=BAD_REQUEST,
|
126
|
+
)
|
127
|
+
if isinstance(decoded_input, dict):
|
128
|
+
format_keys = set(decoded_input.keys()).intersection(SUPPORTED_FORMATS)
|
129
|
+
if len(format_keys) != 1:
|
130
|
+
message = f"Received dictionary with input fields: {list(decoded_input.keys())}"
|
131
|
+
raise MlflowException(
|
132
|
+
message=f"{REQUIRED_INPUT_FORMAT}. {message}. {SCORING_PROTOCOL_CHANGE_INFO}",
|
133
|
+
error_code=BAD_REQUEST,
|
134
|
+
)
|
135
|
+
input_format = format_keys.pop()
|
136
|
+
if input_format in (INSTANCES, INPUTS):
|
137
|
+
return parse_tf_serving_input(decoded_input, schema=schema)
|
138
|
+
|
139
|
+
elif input_format in (DF_SPLIT, DF_RECORDS):
|
140
|
+
# NB: skip the dataframe_ prefix
|
141
|
+
pandas_orient = input_format[10:]
|
142
|
+
return dataframe_from_parsed_json(
|
143
|
+
decoded_input[input_format], pandas_orient=pandas_orient, schema=schema
|
144
|
+
)
|
145
|
+
elif isinstance(decoded_input, list):
|
146
|
+
message = "Received a list"
|
147
|
+
raise MlflowException(
|
148
|
+
message=f"{REQUIRED_INPUT_FORMAT}. {message}. {SCORING_PROTOCOL_CHANGE_INFO}",
|
149
|
+
error_code=BAD_REQUEST,
|
150
|
+
)
|
151
|
+
else:
|
152
|
+
message = f"Received unexpected input type '{type(decoded_input)}'"
|
153
|
+
raise MlflowException(
|
154
|
+
message=f"{REQUIRED_INPUT_FORMAT}. {message}.", error_code=BAD_REQUEST
|
155
|
+
)
|
156
|
+
|
157
|
+
|
158
|
+
def _decode_json_input(json_input):
|
159
|
+
"""
|
160
|
+
Args:
|
161
|
+
json_input: A JSON-formatted string representation of TF serving input or a Pandas
|
162
|
+
DataFrame, or a stream containing such a string representation.
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
A dictionary representation of the JSON input.
|
166
|
+
"""
|
167
|
+
if isinstance(json_input, dict):
|
168
|
+
return json_input
|
169
|
+
|
170
|
+
try:
|
171
|
+
decoded_input = json.loads(json_input)
|
172
|
+
except json.decoder.JSONDecodeError as ex:
|
173
|
+
raise MlflowInvalidInputException(
|
174
|
+
"Ensure that input is a valid JSON formatted string. "
|
175
|
+
f"Error: '{ex!r}'\nInput: \n{json_input}\n"
|
176
|
+
) from ex
|
177
|
+
|
178
|
+
if isinstance(decoded_input, dict):
|
179
|
+
return decoded_input
|
180
|
+
if isinstance(decoded_input, list):
|
181
|
+
raise MlflowInvalidInputException(f"{REQUIRED_INPUT_FORMAT}. Received a list.")
|
182
|
+
|
183
|
+
raise MlflowInvalidInputException(
|
184
|
+
f"{REQUIRED_INPUT_FORMAT}. Received unexpected input type '{type(decoded_input)}."
|
185
|
+
)
|
186
|
+
|
187
|
+
|
188
|
+
def _split_data_and_params_for_llm_input(json_input, param_schema: Optional[ParamSchema]):
|
189
|
+
data = {}
|
190
|
+
params = {}
|
191
|
+
schema_params = {param.name for param in param_schema.params} if param_schema else {}
|
192
|
+
|
193
|
+
for key, value in json_input.items():
|
194
|
+
# if the model defines a param schema, then we can add
|
195
|
+
# it to the params dict. otherwise, add it to the data
|
196
|
+
# dict to prevent it from being ignored at inference time
|
197
|
+
if key in schema_params:
|
198
|
+
params[key] = value
|
199
|
+
else:
|
200
|
+
data[key] = value
|
201
|
+
|
202
|
+
return data, params
|
203
|
+
|
204
|
+
|
205
|
+
def _split_data_and_params(json_input):
|
206
|
+
input_dict = _decode_json_input(json_input)
|
207
|
+
data = {k: v for k, v in input_dict.items() if k in SUPPORTED_FORMATS}
|
208
|
+
params = input_dict.pop(SERVING_PARAMS_KEY, None)
|
209
|
+
return data, params
|
210
|
+
|
211
|
+
|
212
|
+
def infer_and_parse_data(data, schema: Schema = None):
|
213
|
+
"""
|
214
|
+
Args:
|
215
|
+
data: A dictionary representation of TF serving input or a Pandas
|
216
|
+
DataFrame, or a stream containing such a string representation.
|
217
|
+
schema: Optional schema specification to be used during parsing.
|
218
|
+
"""
|
219
|
+
|
220
|
+
format_keys = set(data.keys()).intersection(SUPPORTED_FORMATS)
|
221
|
+
if len(format_keys) != 1:
|
222
|
+
message = f"Received dictionary with input fields: {list(data.keys())}"
|
223
|
+
raise MlflowException(
|
224
|
+
message=f"{REQUIRED_INPUT_FORMAT}. {message}. {SCORING_PROTOCOL_CHANGE_INFO}",
|
225
|
+
error_code=BAD_REQUEST,
|
226
|
+
)
|
227
|
+
input_format = format_keys.pop()
|
228
|
+
if input_format in (INSTANCES, INPUTS):
|
229
|
+
return parse_tf_serving_input(data, schema=schema)
|
230
|
+
|
231
|
+
if input_format in (DF_SPLIT, DF_RECORDS):
|
232
|
+
pandas_orient = input_format[10:] # skip the dataframe_ prefix
|
233
|
+
return dataframe_from_parsed_json(
|
234
|
+
data[input_format], pandas_orient=pandas_orient, schema=schema
|
235
|
+
)
|
236
|
+
|
237
|
+
|
238
|
+
def parse_csv_input(csv_input, schema: Schema = None):
|
239
|
+
"""
|
240
|
+
Args:
|
241
|
+
csv_input: A CSV-formatted string representation of a Pandas DataFrame, or a stream
|
242
|
+
containing such a string representation.
|
243
|
+
schema: Optional schema specification to be used during parsing.
|
244
|
+
"""
|
245
|
+
import pandas as pd
|
246
|
+
|
247
|
+
try:
|
248
|
+
if schema is None:
|
249
|
+
return pd.read_csv(csv_input)
|
250
|
+
else:
|
251
|
+
dtypes = dict(zip(schema.input_names(), schema.pandas_types()))
|
252
|
+
return pd.read_csv(csv_input, dtype=dtypes)
|
253
|
+
except Exception as e:
|
254
|
+
_handle_serving_error(
|
255
|
+
error_message=(
|
256
|
+
"Failed to parse input as a Pandas DataFrame. Ensure that the input is"
|
257
|
+
" a valid CSV-formatted Pandas DataFrame produced using the"
|
258
|
+
f" `pandas.DataFrame.to_csv()` method. Error: '{e}'"
|
259
|
+
),
|
260
|
+
error_code=BAD_REQUEST,
|
261
|
+
)
|
262
|
+
|
263
|
+
|
264
|
+
def unwrapped_predictions_to_json(raw_predictions, output):
|
265
|
+
predictions = _get_jsonable_obj(raw_predictions, pandas_orient="records")
|
266
|
+
return json.dump(predictions, output, cls=NumpyEncoder)
|
267
|
+
|
268
|
+
|
269
|
+
def predictions_to_json(raw_predictions, output, metadata=None):
|
270
|
+
if metadata and "predictions" in metadata:
|
271
|
+
raise MlflowException(
|
272
|
+
"metadata cannot contain 'predictions' key", error_code=INVALID_PARAMETER_VALUE
|
273
|
+
)
|
274
|
+
predictions = _get_jsonable_obj(raw_predictions, pandas_orient="records")
|
275
|
+
return json.dump({"predictions": predictions, **(metadata or {})}, output, cls=NumpyEncoder)
|
276
|
+
|
277
|
+
|
278
|
+
def _handle_serving_error(error_message, error_code, include_traceback=True):
|
279
|
+
"""
|
280
|
+
Logs information about an exception thrown by model inference code that is currently being
|
281
|
+
handled and reraises it with the specified error message. The exception stack trace
|
282
|
+
is also included in the reraised error message.
|
283
|
+
|
284
|
+
Args:
|
285
|
+
error_message: A message for the reraised exception.
|
286
|
+
error_code: An appropriate error code for the reraised exception. This should be one of
|
287
|
+
the codes listed in the `mlflow.protos.databricks_pb2` proto.
|
288
|
+
include_traceback: Whether to include the current traceback in the returned error.
|
289
|
+
"""
|
290
|
+
if include_traceback:
|
291
|
+
traceback_buf = StringIO()
|
292
|
+
traceback.print_exc(file=traceback_buf)
|
293
|
+
traceback_str = traceback_buf.getvalue()
|
294
|
+
e = MlflowException(message=error_message, error_code=error_code, stack_trace=traceback_str)
|
295
|
+
else:
|
296
|
+
e = MlflowException(message=error_message, error_code=error_code)
|
297
|
+
reraise(MlflowException, e)
|
298
|
+
|
299
|
+
|
300
|
+
class InvocationsResponse(NamedTuple):
|
301
|
+
response: str
|
302
|
+
status: int
|
303
|
+
mimetype: str
|
304
|
+
|
305
|
+
|
306
|
+
def invocations(data, content_type, model, input_schema):
|
307
|
+
type_parts = list(map(str.strip, content_type.split(";")))
|
308
|
+
mime_type = type_parts[0]
|
309
|
+
parameter_value_pairs = type_parts[1:]
|
310
|
+
parameter_values = {
|
311
|
+
key: value for pair in parameter_value_pairs for key, _, value in [pair.partition("=")]
|
312
|
+
}
|
313
|
+
|
314
|
+
charset = parameter_values.get("charset", "utf-8").lower()
|
315
|
+
if charset != "utf-8":
|
316
|
+
return InvocationsResponse(
|
317
|
+
response="The scoring server only supports UTF-8",
|
318
|
+
status=415,
|
319
|
+
mimetype="text/plain",
|
320
|
+
)
|
321
|
+
|
322
|
+
unexpected_content_parameters = set(parameter_values.keys()).difference({"charset"})
|
323
|
+
if unexpected_content_parameters:
|
324
|
+
return InvocationsResponse(
|
325
|
+
response=(
|
326
|
+
f"Unrecognized content type parameters: "
|
327
|
+
f"{', '.join(unexpected_content_parameters)}. "
|
328
|
+
f"{SCORING_PROTOCOL_CHANGE_INFO}"
|
329
|
+
),
|
330
|
+
status=415,
|
331
|
+
mimetype="text/plain",
|
332
|
+
)
|
333
|
+
|
334
|
+
# The traditional JSON request/response format, wraps the data with one of the supported keys
|
335
|
+
# like "dataframe_split" and "predictions". For LLM use cases, we also support unwrapped JSON
|
336
|
+
# payload, to provide unified prediction interface.
|
337
|
+
should_parse_as_unified_llm_input = False
|
338
|
+
|
339
|
+
if mime_type == CONTENT_TYPE_CSV:
|
340
|
+
# Convert from CSV to pandas
|
341
|
+
if isinstance(data, bytes):
|
342
|
+
data = data.decode("utf-8")
|
343
|
+
csv_input = StringIO(data)
|
344
|
+
data = parse_csv_input(csv_input=csv_input, schema=input_schema)
|
345
|
+
params = None
|
346
|
+
elif mime_type == CONTENT_TYPE_JSON:
|
347
|
+
parsed_json_input = _parse_json_data(data, model.metadata, input_schema)
|
348
|
+
data = parsed_json_input.data
|
349
|
+
params = parsed_json_input.params
|
350
|
+
should_parse_as_unified_llm_input = parsed_json_input.is_unified_llm_input
|
351
|
+
else:
|
352
|
+
return InvocationsResponse(
|
353
|
+
response=(
|
354
|
+
"This predictor only supports the following content types:"
|
355
|
+
f" Types: {CONTENT_TYPES}."
|
356
|
+
f" Got '{content_type}'."
|
357
|
+
),
|
358
|
+
status=415,
|
359
|
+
mimetype="text/plain",
|
360
|
+
)
|
361
|
+
|
362
|
+
# Do the prediction
|
363
|
+
# NB: utils._validate_serving_input mimic the scoring process here to validate input_example
|
364
|
+
# work for serving, so any changes here should be reflected there as well
|
365
|
+
try:
|
366
|
+
if "params" in inspect.signature(model.predict).parameters:
|
367
|
+
raw_predictions = model.predict(data, params=params)
|
368
|
+
else:
|
369
|
+
_log_warning_if_params_not_in_predict_signature(_logger, params)
|
370
|
+
raw_predictions = model.predict(data)
|
371
|
+
except MlflowException as e:
|
372
|
+
if "Failed to enforce schema" in e.message:
|
373
|
+
_logger.warning(
|
374
|
+
"If using `instances` as input key, we internally convert "
|
375
|
+
"the data type from `records` (List[Dict]) type to "
|
376
|
+
"`list` (Dict[str, List]) type if the data is a pandas "
|
377
|
+
"dataframe representation. This might cause schema changes. "
|
378
|
+
"Please use `inputs` to avoid this conversion.\n"
|
379
|
+
)
|
380
|
+
e.message = f"Failed to predict data '{data}'. \nError: {e.message}"
|
381
|
+
raise e
|
382
|
+
except Exception:
|
383
|
+
raise MlflowException(
|
384
|
+
message=(
|
385
|
+
"Encountered an unexpected error while evaluating the model. Verify"
|
386
|
+
" that the serialized input Dataframe is compatible with the model for"
|
387
|
+
" inference."
|
388
|
+
),
|
389
|
+
error_code=BAD_REQUEST,
|
390
|
+
stack_trace=traceback.format_exc(),
|
391
|
+
)
|
392
|
+
result = StringIO()
|
393
|
+
|
394
|
+
# if the data was formatted using the unified LLM format,
|
395
|
+
# then return the data without the "predictions" key
|
396
|
+
if should_parse_as_unified_llm_input:
|
397
|
+
unwrapped_predictions_to_json(raw_predictions, result)
|
398
|
+
else:
|
399
|
+
predictions_to_json(raw_predictions, result)
|
400
|
+
|
401
|
+
return InvocationsResponse(response=result.getvalue(), status=200, mimetype="application/json")
|
402
|
+
|
403
|
+
|
404
|
+
class ParsedJsonInput(NamedTuple):
|
405
|
+
data: Any
|
406
|
+
params: Optional[dict[str, Any]]
|
407
|
+
is_unified_llm_input: bool
|
408
|
+
|
409
|
+
|
410
|
+
def _parse_json_data(data, metadata, input_schema):
|
411
|
+
json_input = _decode_json_input(data)
|
412
|
+
_is_unified_llm_input = is_unified_llm_input(json_input)
|
413
|
+
# no data parsing for unified LLM input format
|
414
|
+
if _is_unified_llm_input:
|
415
|
+
# Unified LLM input format
|
416
|
+
if hasattr(metadata, "get_params_schema"):
|
417
|
+
params_schema = metadata.get_params_schema()
|
418
|
+
else:
|
419
|
+
params_schema = None
|
420
|
+
data, params = _split_data_and_params_for_llm_input(json_input, params_schema)
|
421
|
+
else:
|
422
|
+
# Traditional json input format
|
423
|
+
data, params = _split_data_and_params(data)
|
424
|
+
# data only needs to be parsed if the model signature is not from type hint
|
425
|
+
# default to True for backwards compatibility
|
426
|
+
should_parse_data = (
|
427
|
+
not metadata._is_signature_from_type_hint()
|
428
|
+
if hasattr(metadata, "_is_signature_from_type_hint")
|
429
|
+
else True
|
430
|
+
)
|
431
|
+
if should_parse_data:
|
432
|
+
data = infer_and_parse_data(data, input_schema)
|
433
|
+
else:
|
434
|
+
if INPUTS not in data:
|
435
|
+
raise MlflowException.invalid_parameter_value(
|
436
|
+
"Request payload must be a dictionary with 'inputs' key when "
|
437
|
+
f"the model contains a valid type hint. Found keys in payload: {data.keys()}."
|
438
|
+
)
|
439
|
+
data = data[INPUTS]
|
440
|
+
return ParsedJsonInput(data, params, _is_unified_llm_input)
|
441
|
+
|
442
|
+
|
443
|
+
def _async_catch_mlflow_exception(func):
|
444
|
+
from fastapi.responses import Response
|
445
|
+
|
446
|
+
@wraps(func)
|
447
|
+
async def wrapper(*args, **kwargs):
|
448
|
+
try:
|
449
|
+
return await func(*args, **kwargs)
|
450
|
+
except MlflowException as e:
|
451
|
+
return Response(
|
452
|
+
content=e.serialize_as_json(),
|
453
|
+
status_code=e.get_http_status_code(),
|
454
|
+
media_type="application/json",
|
455
|
+
)
|
456
|
+
|
457
|
+
return wrapper
|
458
|
+
|
459
|
+
|
460
|
+
def init(model: PyFuncModel):
|
461
|
+
"""
|
462
|
+
Initialize the server. Loads pyfunc model from the path.
|
463
|
+
"""
|
464
|
+
from fastapi import FastAPI, Request
|
465
|
+
from fastapi.responses import Response
|
466
|
+
|
467
|
+
app = FastAPI()
|
468
|
+
input_schema = model.metadata.get_input_schema()
|
469
|
+
# set the environment variable to indicate that we are in a serving environment
|
470
|
+
os.environ[_MLFLOW_IS_IN_SERVING_ENVIRONMENT.name] = "true"
|
471
|
+
timeout = MLFLOW_SCORING_SERVER_REQUEST_TIMEOUT.get()
|
472
|
+
|
473
|
+
@app.middleware("http")
|
474
|
+
async def timeout_middleware(request: Request, call_next):
|
475
|
+
try:
|
476
|
+
return await asyncio.wait_for(call_next(request), timeout=timeout)
|
477
|
+
except (asyncio.TimeoutError, TimeoutError):
|
478
|
+
return Response(
|
479
|
+
content="Request processing time exceeded limit",
|
480
|
+
status_code=504,
|
481
|
+
media_type="application/json",
|
482
|
+
)
|
483
|
+
|
484
|
+
@app.route("/ping", methods=["GET"])
|
485
|
+
@app.route("/health", methods=["GET"])
|
486
|
+
async def ping(request: Request):
|
487
|
+
"""
|
488
|
+
Determine if the container is working and healthy.
|
489
|
+
We declare it healthy if we can load the model successfully.
|
490
|
+
"""
|
491
|
+
health = model is not None
|
492
|
+
status = 200 if health else 404
|
493
|
+
return Response(content="\n", status_code=status, media_type="application/json")
|
494
|
+
|
495
|
+
@app.route("/version", methods=["GET"])
|
496
|
+
async def version(request: Request):
|
497
|
+
"""
|
498
|
+
Returns the current mlflow version.
|
499
|
+
"""
|
500
|
+
return Response(content=VERSION, status_code=200, media_type="application/json")
|
501
|
+
|
502
|
+
@app.route("/invocations", methods=["POST"])
|
503
|
+
@_async_catch_mlflow_exception
|
504
|
+
async def transformation(request: Request):
|
505
|
+
"""
|
506
|
+
Do an inference on a single batch of data. In this sample server,
|
507
|
+
we take data as CSV or json, convert it to a Pandas DataFrame or Numpy,
|
508
|
+
generate predictions and convert them back to json.
|
509
|
+
"""
|
510
|
+
|
511
|
+
data = await request.body()
|
512
|
+
content_type = request.headers.get("content-type")
|
513
|
+
# TODO: convert "invocations" to an async method to make internal logic fully non-blocking.
|
514
|
+
result = await asyncio.to_thread(invocations, data, content_type, model, input_schema)
|
515
|
+
|
516
|
+
return Response(
|
517
|
+
content=result.response, status_code=result.status, media_type=result.mimetype
|
518
|
+
)
|
519
|
+
|
520
|
+
return app
|
521
|
+
|
522
|
+
|
523
|
+
def _predict(model_uri, input_path, output_path, content_type):
|
524
|
+
from mlflow.pyfunc.utils.environment import _simulate_serving_environment
|
525
|
+
|
526
|
+
with _simulate_serving_environment():
|
527
|
+
pyfunc_model = load_model(model_uri)
|
528
|
+
|
529
|
+
should_parse_as_unified_llm_input = False
|
530
|
+
if content_type == "json":
|
531
|
+
if input_path is None:
|
532
|
+
input_str = sys.stdin.read()
|
533
|
+
else:
|
534
|
+
with open(input_path) as f:
|
535
|
+
input_str = f.read()
|
536
|
+
parsed_json_input = _parse_json_data(
|
537
|
+
data=input_str,
|
538
|
+
metadata=pyfunc_model.metadata,
|
539
|
+
input_schema=pyfunc_model.metadata.get_input_schema(),
|
540
|
+
)
|
541
|
+
df = parsed_json_input.data
|
542
|
+
params = parsed_json_input.params
|
543
|
+
should_parse_as_unified_llm_input = parsed_json_input.is_unified_llm_input
|
544
|
+
elif content_type == "csv":
|
545
|
+
df = (
|
546
|
+
parse_csv_input(input_path)
|
547
|
+
if input_path is not None
|
548
|
+
else parse_csv_input(sys.stdin)
|
549
|
+
)
|
550
|
+
params = None
|
551
|
+
else:
|
552
|
+
raise Exception(f"Unknown content type '{content_type}'")
|
553
|
+
|
554
|
+
if "params" in inspect.signature(pyfunc_model.predict).parameters:
|
555
|
+
raw_predictions = pyfunc_model.predict(df, params=params)
|
556
|
+
else:
|
557
|
+
_log_warning_if_params_not_in_predict_signature(_logger, params)
|
558
|
+
raw_predictions = pyfunc_model.predict(df)
|
559
|
+
|
560
|
+
parse_output_func = (
|
561
|
+
unwrapped_predictions_to_json
|
562
|
+
if should_parse_as_unified_llm_input
|
563
|
+
else predictions_to_json
|
564
|
+
)
|
565
|
+
|
566
|
+
if output_path is None:
|
567
|
+
parse_output_func(raw_predictions, sys.stdout)
|
568
|
+
else:
|
569
|
+
with open(output_path, "w") as fout:
|
570
|
+
parse_output_func(raw_predictions, fout)
|
571
|
+
|
572
|
+
|
573
|
+
def _serve(model_uri, port, host):
|
574
|
+
pyfunc_model = load_model(model_uri)
|
575
|
+
init(pyfunc_model).run(port=port, host=host)
|
576
|
+
|
577
|
+
|
578
|
+
def get_cmd(
|
579
|
+
model_uri: str,
|
580
|
+
port: Optional[int] = None,
|
581
|
+
host: Optional[int] = None,
|
582
|
+
timeout: Optional[int] = None,
|
583
|
+
nworkers: Optional[int] = None,
|
584
|
+
) -> tuple[str, dict[str, str]]:
|
585
|
+
local_uri = path_to_local_file_uri(model_uri)
|
586
|
+
timeout = timeout or MLFLOW_SCORING_SERVER_REQUEST_TIMEOUT.get()
|
587
|
+
|
588
|
+
args = []
|
589
|
+
if host:
|
590
|
+
args.append(f"--host {shlex.quote(host)}")
|
591
|
+
|
592
|
+
if port:
|
593
|
+
args.append(f"--port {port}")
|
594
|
+
|
595
|
+
if nworkers:
|
596
|
+
args.append(f"--workers {nworkers}")
|
597
|
+
|
598
|
+
command = f"uvicorn {' '.join(args)} mlflow.pyfunc.scoring_server.app:app"
|
599
|
+
|
600
|
+
command_env = os.environ.copy()
|
601
|
+
command_env[_SERVER_MODEL_PATH] = local_uri
|
602
|
+
command_env[MLFLOW_SCORING_SERVER_REQUEST_TIMEOUT.name] = str(timeout)
|
603
|
+
|
604
|
+
return command, command_env
|