Source code for chariot.inference_store.metadata
from collections.abc import Mapping
from enum import Enum
from hashlib import sha256
from typing import Any
import chariot._apis
from chariot.inference_store import _utils, models
__all__ = [
"create_metadata",
"get_metadata",
"delete_metadata",
"get_metadata_key_type_counts",
"get_metadata_statistics",
"get_data_hash",
"map_to_inference_store_metadata",
]
[docs]
def create_metadata(
model_id: str, inference_id: str, request_body: models.NewExtendedMetadataRequest
) -> models.Metadata | None:
"""Create new metadata for an inference.
:param model_id: The model id.
:type model_id: str
:param inference_id: The id of the inference.
:type inference_id: str
:param request_body: The metadata to attach to the inference.
:type request_body: models.NewMetadataRequest
:return: The metadata details.
:rtype: Optional[models.Metadata]Optional
"""
response = chariot._apis.inferencestore.metadata_api.metadata_model_id_inference_id_post(
model_id=model_id, inference_id=inference_id, body=request_body.model_dump()
)
if not response.data:
return None
return _utils.convert_to_dataclass(response.data.model_dump(), models.Metadata)
[docs]
def get_metadata(model_id: str, inference_id: str) -> list[models.Metadata]:
"""Get all metadata for a particular inference.
:param model_id: The model id.
:type model_id: str
:param inference_id: The id of the inference.
:type inference_id: str
:return: The metadata details.
:rtype: List[models.Metadata]
"""
response = chariot._apis.inferencestore.metadata_api.metadata_model_id_inference_id_get(
model_id=model_id, inference_id=inference_id
)
if not response.data:
return []
return [_utils.convert_to_dataclass(d.model_dump(), models.Metadata) for d in response.data]
[docs]
def delete_metadata(model_id: str, inference_id: str, key: str) -> str | None:
"""Delete metadata for a particular inference and key pair.
:param model_id: The model id.
:type model_id: str
:param inference_id: The id of the inference.
:type inference_id: str
:param key: The key of the metadata to delete.
:type key: str
:return: The deleted metadata id.
:rtype: Optional[str]
"""
response = chariot._apis.inferencestore.metadata_api.metadata_model_id_inference_id_key_delete(
model_id=model_id, inference_id=inference_id, key=key
)
if not response.data:
return None
return response.data
[docs]
def get_metadata_key_type_counts(model_id: str) -> models.MetadataKeyTypeCounts | None:
"""Get metadata key, type counts.
:param model_id: The model id.
:type model_id: str
:return: The count of each metadata key, type pair.
:rtype: Optional[models.MetadataKeyTypeCounts]
"""
response = chariot._apis.inferencestore.metadata_api.metadata_model_id_keys_get(
model_id=model_id
)
if not response.data:
return None
return _utils.convert_to_dataclass(response.data.model_dump(), models.MetadataKeyTypeCounts)
[docs]
def get_metadata_statistics(
model_id: str, request_body: models.NewGetMetadataStatisticsRequest
) -> models.MetadataStatistics | None:
"""Get metadata statistics for a particular metadata key, type pair.
:param model_id: The model id.
:type model_id: str
:param request_body: The metadata statistics criteria.
:type request_body: models.NewGetMetadataStatisticsRequest
:return: The metadata statistics
:rtype: Optional[models.MetadataStatistics]
"""
response = chariot._apis.inferencestore.metadata_api.metadata_model_id_statistics_post(
model_id=model_id, body=request_body.model_dump()
)
if not response.data:
return None
return _utils.convert_to_dataclass(response.data.model_dump(), models.MetadataStatistics)
[docs]
def get_data_hash(data: bytes) -> str:
"""Get the SHA256 hexdigest of the data being inferred upon.
:param data: The input inference data.
:type data: bytes
:return: The data hash.
:rtype: str
"""
return sha256(data).hexdigest()
def _map_value_type(vt: str) -> str | None:
value_type = None
if vt == "str":
value_type = "string"
elif vt == "float":
value_type = "float"
elif vt == "int":
value_type = "int"
elif vt == "dict":
value_type = "json"
return value_type
AllowedCustomMetadataValues = str | float | int | Mapping[str, Any]
CustomMetadata = Mapping[str, AllowedCustomMetadataValues]
class StandardMetadataKeys(str, Enum):
DataSource = "data_source"
Latitude = "latitude"
Longitude = "longitude"
[docs]
def map_to_inference_store_metadata(data: CustomMetadata) -> dict:
"""Map data from a dictionary into the required inference store format.
All keys, types, and values must be strings.
There are a few special keys mapped to the top level inference records
for advanced querying: {"data_source", "latitude", "longitude"}. If the
key doesn't belong to that set it's added to extended metadata.
Valid inference store types are: string, float, int, json
:param data: The metadata.
:type data: dict
:return: The typed metadata.
:rtype: dict
"""
standard_metadata: dict = {}
extended_metadata: list[dict] = []
for key, value in data.items():
value_type = type(value).__name__
vt = _map_value_type(value_type)
if vt is None:
continue
match key:
case StandardMetadataKeys.DataSource:
standard_metadata[key] = str(value)
case StandardMetadataKeys.Latitude | StandardMetadataKeys.Longitude:
standard_metadata[key] = float(value)
case _:
extended_metadata.append({"key": str(key), "type": vt, "value": str(value)})
out = {"standard_metadata": standard_metadata, "extended_metadata": extended_metadata}
return out