opik 0.1.1__tar.gz
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.
- opik-0.1.1/PKG-INFO +42 -0
- opik-0.1.1/README.md +8 -0
- opik-0.1.1/pyproject.toml +6 -0
- opik-0.1.1/setup.cfg +4 -0
- opik-0.1.1/setup.py +56 -0
- opik-0.1.1/src/opik/__init__.py +24 -0
- opik-0.1.1/src/opik/_logging.py +34 -0
- opik-0.1.1/src/opik/api_objects/__init__.py +0 -0
- opik-0.1.1/src/opik/api_objects/constants.py +6 -0
- opik-0.1.1/src/opik/api_objects/dataset/__init__.py +4 -0
- opik-0.1.1/src/opik/api_objects/dataset/converters.py +76 -0
- opik-0.1.1/src/opik/api_objects/dataset/dataset.py +227 -0
- opik-0.1.1/src/opik/api_objects/dataset/dataset_item.py +36 -0
- opik-0.1.1/src/opik/api_objects/experiment/__init__.py +3 -0
- opik-0.1.1/src/opik/api_objects/experiment/experiment.py +45 -0
- opik-0.1.1/src/opik/api_objects/experiment/experiment_item.py +10 -0
- opik-0.1.1/src/opik/api_objects/helpers.py +24 -0
- opik-0.1.1/src/opik/api_objects/opik_client.py +385 -0
- opik-0.1.1/src/opik/api_objects/span.py +207 -0
- opik-0.1.1/src/opik/api_objects/trace.py +196 -0
- opik-0.1.1/src/opik/api_objects/validation_helpers.py +43 -0
- opik-0.1.1/src/opik/config.py +105 -0
- opik-0.1.1/src/opik/context_storage.py +79 -0
- opik-0.1.1/src/opik/datetime_helpers.py +10 -0
- opik-0.1.1/src/opik/decorator/__init__.py +0 -0
- opik-0.1.1/src/opik/decorator/arguments_helpers.py +34 -0
- opik-0.1.1/src/opik/decorator/base_track_decorator.py +478 -0
- opik-0.1.1/src/opik/decorator/generator_wrappers.py +90 -0
- opik-0.1.1/src/opik/decorator/inspect_helpers.py +37 -0
- opik-0.1.1/src/opik/decorator/tracker.py +65 -0
- opik-0.1.1/src/opik/dict_utils.py +47 -0
- opik-0.1.1/src/opik/evaluation/__init__.py +3 -0
- opik-0.1.1/src/opik/evaluation/evaluator.py +86 -0
- opik-0.1.1/src/opik/evaluation/metrics/__init__.py +28 -0
- opik-0.1.1/src/opik/evaluation/metrics/base_metric.py +26 -0
- opik-0.1.1/src/opik/evaluation/metrics/exceptions.py +4 -0
- opik-0.1.1/src/opik/evaluation/metrics/heuristics/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/heuristics/contains.py +58 -0
- opik-0.1.1/src/opik/evaluation/metrics/heuristics/equals.py +57 -0
- opik-0.1.1/src/opik/evaluation/metrics/heuristics/is_json.py +47 -0
- opik-0.1.1/src/opik/evaluation/metrics/heuristics/levenshtein_ratio.py +61 -0
- opik-0.1.1/src/opik/evaluation/metrics/heuristics/regex_match.py +55 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/answer_relevance/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/answer_relevance/metric.py +121 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/answer_relevance/template.py +136 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/context_precision/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/context_precision/metric.py +143 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/context_precision/template.py +127 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/context_recall/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/context_recall/metric.py +141 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/context_recall/template.py +144 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/factuality/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/factuality/metric.py +135 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/factuality/template.py +128 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/hallucination/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/hallucination/metric.py +122 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/hallucination/template.py +73 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/moderation/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/moderation/metric.py +114 -0
- opik-0.1.1/src/opik/evaluation/metrics/llm_judges/moderation/template.py +83 -0
- opik-0.1.1/src/opik/evaluation/metrics/models.py +8 -0
- opik-0.1.1/src/opik/evaluation/metrics/score_result.py +11 -0
- opik-0.1.1/src/opik/evaluation/models/__init__.py +0 -0
- opik-0.1.1/src/opik/evaluation/models/base_model.py +21 -0
- opik-0.1.1/src/opik/evaluation/models/langchain_chat_model.py +23 -0
- opik-0.1.1/src/opik/evaluation/models/models_factory.py +13 -0
- opik-0.1.1/src/opik/evaluation/report.py +83 -0
- opik-0.1.1/src/opik/evaluation/scores_logger.py +26 -0
- opik-0.1.1/src/opik/evaluation/scoring_runner.py +76 -0
- opik-0.1.1/src/opik/evaluation/task_output.py +16 -0
- opik-0.1.1/src/opik/evaluation/task_runner.py +74 -0
- opik-0.1.1/src/opik/evaluation/test_case.py +9 -0
- opik-0.1.1/src/opik/evaluation/test_result.py +12 -0
- opik-0.1.1/src/opik/evaluation/types.py +4 -0
- opik-0.1.1/src/opik/exceptions.py +10 -0
- opik-0.1.1/src/opik/hooks.py +5 -0
- opik-0.1.1/src/opik/httpx_client.py +29 -0
- opik-0.1.1/src/opik/integrations/__init__.py +0 -0
- opik-0.1.1/src/opik/integrations/langchain/__init__.py +4 -0
- opik-0.1.1/src/opik/integrations/langchain/openai_run_helpers.py +50 -0
- opik-0.1.1/src/opik/integrations/langchain/opik_tracer.py +233 -0
- opik-0.1.1/src/opik/integrations/openai/__init__.py +3 -0
- opik-0.1.1/src/opik/integrations/openai/chunks_aggregator.py +64 -0
- opik-0.1.1/src/opik/integrations/openai/openai_decorator.py +161 -0
- opik-0.1.1/src/opik/integrations/openai/opik_tracker.py +32 -0
- opik-0.1.1/src/opik/integrations/openai/stream_wrappers.py +60 -0
- opik-0.1.1/src/opik/logging_messages.py +39 -0
- opik-0.1.1/src/opik/message_processing/__init__.py +0 -0
- opik-0.1.1/src/opik/message_processing/api.py +0 -0
- opik-0.1.1/src/opik/message_processing/jsonable_encoder.py +57 -0
- opik-0.1.1/src/opik/message_processing/message_processors.py +165 -0
- opik-0.1.1/src/opik/message_processing/messages.py +90 -0
- opik-0.1.1/src/opik/message_processing/queue_consumer.py +48 -0
- opik-0.1.1/src/opik/message_processing/streamer.py +57 -0
- opik-0.1.1/src/opik/message_processing/streamer_constructors.py +35 -0
- opik-0.1.1/src/opik/opik_context.py +31 -0
- opik-0.1.1/src/opik/package_version.py +11 -0
- opik-0.1.1/src/opik/rest_api/__init__.py +195 -0
- opik-0.1.1/src/opik/rest_api/client.py +164 -0
- opik-0.1.1/src/opik/rest_api/core/__init__.py +30 -0
- opik-0.1.1/src/opik/rest_api/core/api_error.py +17 -0
- opik-0.1.1/src/opik/rest_api/core/client_wrapper.py +57 -0
- opik-0.1.1/src/opik/rest_api/core/datetime_utils.py +30 -0
- opik-0.1.1/src/opik/rest_api/core/file.py +43 -0
- opik-0.1.1/src/opik/rest_api/core/http_client.py +545 -0
- opik-0.1.1/src/opik/rest_api/core/jsonable_encoder.py +105 -0
- opik-0.1.1/src/opik/rest_api/core/pydantic_utilities.py +28 -0
- opik-0.1.1/src/opik/rest_api/core/query_encoder.py +39 -0
- opik-0.1.1/src/opik/rest_api/core/remove_none_from_dict.py +11 -0
- opik-0.1.1/src/opik/rest_api/core/request_options.py +32 -0
- opik-0.1.1/src/opik/rest_api/datasets/__init__.py +1 -0
- opik-0.1.1/src/opik/rest_api/datasets/client.py +1407 -0
- opik-0.1.1/src/opik/rest_api/environment.py +7 -0
- opik-0.1.1/src/opik/rest_api/errors/__init__.py +15 -0
- opik-0.1.1/src/opik/rest_api/errors/bad_request_error.py +9 -0
- opik-0.1.1/src/opik/rest_api/errors/conflict_error.py +9 -0
- opik-0.1.1/src/opik/rest_api/errors/not_found_error.py +10 -0
- opik-0.1.1/src/opik/rest_api/errors/not_implemented_error.py +10 -0
- opik-0.1.1/src/opik/rest_api/errors/unprocessable_entity_error.py +9 -0
- opik-0.1.1/src/opik/rest_api/experiments/__init__.py +1 -0
- opik-0.1.1/src/opik/rest_api/experiments/client.py +646 -0
- opik-0.1.1/src/opik/rest_api/feedback_definitions/__init__.py +5 -0
- opik-0.1.1/src/opik/rest_api/feedback_definitions/client.py +542 -0
- opik-0.1.1/src/opik/rest_api/feedback_definitions/types/__init__.py +5 -0
- opik-0.1.1/src/opik/rest_api/feedback_definitions/types/find_feedback_definitions_request_type.py +7 -0
- opik-0.1.1/src/opik/rest_api/projects/__init__.py +1 -0
- opik-0.1.1/src/opik/rest_api/projects/client.py +557 -0
- opik-0.1.1/src/opik/rest_api/spans/__init__.py +5 -0
- opik-0.1.1/src/opik/rest_api/spans/client.py +1153 -0
- opik-0.1.1/src/opik/rest_api/spans/types/__init__.py +6 -0
- opik-0.1.1/src/opik/rest_api/spans/types/get_spans_by_project_request_type.py +7 -0
- opik-0.1.1/src/opik/rest_api/spans/types/span_write_type.py +5 -0
- opik-0.1.1/src/opik/rest_api/traces/__init__.py +1 -0
- opik-0.1.1/src/opik/rest_api/traces/client.py +1047 -0
- opik-0.1.1/src/opik/rest_api/types/__init__.py +173 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_definition.py +47 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_definition_create.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_definition_public.py +47 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_definition_update.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_detail.py +42 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_detail_create.py +42 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_detail_public.py +42 -0
- opik-0.1.1/src/opik/rest_api/types/categorical_feedback_detail_update.py +42 -0
- opik-0.1.1/src/opik/rest_api/types/dataset.py +50 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item.py +56 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_batch.py +53 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_compare.py +56 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_compare_source.py +7 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_page_compare.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_public.py +56 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_public_source.py +7 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_source.py +7 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_write.py +50 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_item_write_source.py +7 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/dataset_public.py +50 -0
- opik-0.1.1/src/opik/rest_api/types/delete_feedback_score.py +42 -0
- opik-0.1.1/src/opik/rest_api/types/error_message.py +42 -0
- opik-0.1.1/src/opik/rest_api/types/error_message_public.py +44 -0
- opik-0.1.1/src/opik/rest_api/types/experiment.py +52 -0
- opik-0.1.1/src/opik/rest_api/types/experiment_item.py +54 -0
- opik-0.1.1/src/opik/rest_api/types/experiment_item_compare.py +54 -0
- opik-0.1.1/src/opik/rest_api/types/experiment_item_public.py +49 -0
- opik-0.1.1/src/opik/rest_api/types/experiment_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/experiment_public.py +51 -0
- opik-0.1.1/src/opik/rest_api/types/feedback.py +149 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_create.py +127 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_definition_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_object_public.py +151 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_public.py +149 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score.py +51 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_average.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_average_public.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_batch.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_batch_item.py +53 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_batch_item_source.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_compare.py +51 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_compare_source.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_public.py +51 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_public_source.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_score_source.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/feedback_update.py +127 -0
- opik-0.1.1/src/opik/rest_api/types/json_node.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/json_node_compare.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/json_node_public.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/json_node_write.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_definition.py +47 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_definition_create.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_definition_public.py +47 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_definition_update.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_detail.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_detail_create.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_detail_public.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/numerical_feedback_detail_update.py +43 -0
- opik-0.1.1/src/opik/rest_api/types/project.py +48 -0
- opik-0.1.1/src/opik/rest_api/types/project_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/project_public.py +48 -0
- opik-0.1.1/src/opik/rest_api/types/span.py +67 -0
- opik-0.1.1/src/opik/rest_api/types/span_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/span_public.py +62 -0
- opik-0.1.1/src/opik/rest_api/types/span_public_type.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/span_type.py +5 -0
- opik-0.1.1/src/opik/rest_api/types/trace.py +62 -0
- opik-0.1.1/src/opik/rest_api/types/trace_page_public.py +46 -0
- opik-0.1.1/src/opik/rest_api/types/trace_public.py +57 -0
- opik-0.1.1/src/opik/synchronization.py +21 -0
- opik-0.1.1/src/opik/types.py +60 -0
- opik-0.1.1/src/opik/validation/__init__.py +0 -0
- opik-0.1.1/src/opik/validation/feedback_score.py +47 -0
- opik-0.1.1/src/opik/validation/result.py +28 -0
- opik-0.1.1/src/opik/validation/usage.py +49 -0
- opik-0.1.1/src/opik/validation/validator.py +9 -0
- opik-0.1.1/src/opik.egg-info/PKG-INFO +42 -0
- opik-0.1.1/src/opik.egg-info/SOURCES.txt +219 -0
- opik-0.1.1/src/opik.egg-info/dependency_links.txt +1 -0
- opik-0.1.1/src/opik.egg-info/entry_points.txt +2 -0
- opik-0.1.1/src/opik.egg-info/not-zip-safe +1 -0
- opik-0.1.1/src/opik.egg-info/requires.txt +12 -0
- opik-0.1.1/src/opik.egg-info/top_level.txt +1 -0
opik-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: opik
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Comet tool for logging and evaluating LLM traces
|
|
5
|
+
Home-page: https://www.comet.com
|
|
6
|
+
Author: Comet ML Inc.
|
|
7
|
+
Author-email: mail@comet.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Source code, https://github.com/comet-ml/opik
|
|
10
|
+
Keywords: opik
|
|
11
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Natural Language :: English
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: httpx<1.0.0
|
|
23
|
+
Requires-Dist: langchain_community<1.0.0
|
|
24
|
+
Requires-Dist: langchain_openai<1.0.0
|
|
25
|
+
Requires-Dist: levenshtein~=0.25.1
|
|
26
|
+
Requires-Dist: openai<2.0.0
|
|
27
|
+
Requires-Dist: pandas<3.0.0,>=2.0.0
|
|
28
|
+
Requires-Dist: pydantic-settings<3.0.0,>=2.0.0
|
|
29
|
+
Requires-Dist: pydantic<3.0.0,>=2.0.0
|
|
30
|
+
Requires-Dist: pytest
|
|
31
|
+
Requires-Dist: tqdm
|
|
32
|
+
Requires-Dist: uuid7<1.0.0
|
|
33
|
+
Requires-Dist: rich
|
|
34
|
+
|
|
35
|
+
# opik-python
|
|
36
|
+
|
|
37
|
+
To install package in development mode run `pip install -e .` from the repository root directory.
|
|
38
|
+
|
|
39
|
+
# Linters
|
|
40
|
+
|
|
41
|
+
Before pushing your changes please run `pre-commit run --all-files` from the python/sdk directory.
|
|
42
|
+
It will install and run required linters.
|
opik-0.1.1/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# opik-python
|
|
2
|
+
|
|
3
|
+
To install package in development mode run `pip install -e .` from the repository root directory.
|
|
4
|
+
|
|
5
|
+
# Linters
|
|
6
|
+
|
|
7
|
+
Before pushing your changes please run `pre-commit run --all-files` from the python/sdk directory.
|
|
8
|
+
It will install and run required linters.
|
opik-0.1.1/setup.cfg
ADDED
opik-0.1.1/setup.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from setuptools import find_packages, setup
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
project_urls = {"Source code": "https://github.com/comet-ml/opik"}
|
|
7
|
+
this_directory = Path(__file__).parent
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
author="Comet ML Inc.",
|
|
11
|
+
author_email="mail@comet.com",
|
|
12
|
+
python_requires=">=3.8",
|
|
13
|
+
classifiers=[
|
|
14
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Natural Language :: English",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.8",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
],
|
|
24
|
+
description="Comet tool for logging and evaluating LLM traces",
|
|
25
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
26
|
+
long_description_content_type="text/markdown",
|
|
27
|
+
install_requires=[
|
|
28
|
+
"httpx<1.0.0",
|
|
29
|
+
"langchain_community<1.0.0",
|
|
30
|
+
"langchain_openai<1.0.0",
|
|
31
|
+
"levenshtein~=0.25.1",
|
|
32
|
+
"openai<2.0.0",
|
|
33
|
+
"pandas>=2.0.0,<3.0.0",
|
|
34
|
+
"pydantic-settings>=2.0.0,<3.0.0",
|
|
35
|
+
"pydantic>=2.0.0,<3.0.0",
|
|
36
|
+
"pytest",
|
|
37
|
+
"tqdm",
|
|
38
|
+
"uuid7<1.0.0",
|
|
39
|
+
"rich",
|
|
40
|
+
],
|
|
41
|
+
entry_points={
|
|
42
|
+
"pytest11": [
|
|
43
|
+
"opik = opik.plugins.pytest.hooks",
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
include_package_data=True,
|
|
47
|
+
keywords="opik",
|
|
48
|
+
name="opik",
|
|
49
|
+
packages=find_packages("src"),
|
|
50
|
+
package_dir={"": "src"},
|
|
51
|
+
url="https://www.comet.com",
|
|
52
|
+
project_urls=project_urls,
|
|
53
|
+
version=os.environ.get("VERSION", "0.0.1"),
|
|
54
|
+
zip_safe=False,
|
|
55
|
+
license="MIT",
|
|
56
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from .decorator.tracker import track, flush_tracker
|
|
2
|
+
from .api_objects.opik_client import Opik
|
|
3
|
+
from .api_objects.trace import Trace
|
|
4
|
+
from .api_objects.span import Span
|
|
5
|
+
from .api_objects.dataset.dataset_item import DatasetItem
|
|
6
|
+
from .api_objects.dataset import Dataset
|
|
7
|
+
from . import _logging
|
|
8
|
+
from . import package_version
|
|
9
|
+
from .plugins.pytest.decorator import llm_unit
|
|
10
|
+
|
|
11
|
+
_logging.setup()
|
|
12
|
+
|
|
13
|
+
__version__ = package_version.VERSION
|
|
14
|
+
__all__ = [
|
|
15
|
+
"__version__",
|
|
16
|
+
"track",
|
|
17
|
+
"flush_tracker",
|
|
18
|
+
"Opik",
|
|
19
|
+
"Trace",
|
|
20
|
+
"Span",
|
|
21
|
+
"DatasetItem",
|
|
22
|
+
"Dataset",
|
|
23
|
+
"llm_unit",
|
|
24
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from . import config
|
|
6
|
+
|
|
7
|
+
CONSOLE_MSG_FORMAT = "OPIK: %(message)s"
|
|
8
|
+
|
|
9
|
+
FILE_MSG_FORMAT = "%(asctime)s OPIK %(levelname)s: %(message)s"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def setup() -> None:
|
|
13
|
+
opik_root_logger = logging.getLogger("opik")
|
|
14
|
+
config_ = config.OpikConfig()
|
|
15
|
+
|
|
16
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
17
|
+
console_level = config_.console_logging_level
|
|
18
|
+
console_handler.setLevel(console_level)
|
|
19
|
+
console_handler.setFormatter(logging.Formatter(CONSOLE_MSG_FORMAT))
|
|
20
|
+
|
|
21
|
+
opik_root_logger.addHandler(console_handler)
|
|
22
|
+
|
|
23
|
+
root_level = console_handler.level
|
|
24
|
+
|
|
25
|
+
if config_.file_logging_level is not None:
|
|
26
|
+
file_handler = logging.FileHandler(config_.logging_file)
|
|
27
|
+
file_level = config_.file_logging_level
|
|
28
|
+
file_handler.setLevel(file_level)
|
|
29
|
+
file_handler.setFormatter(logging.Formatter(FILE_MSG_FORMAT))
|
|
30
|
+
opik_root_logger.addHandler(file_handler)
|
|
31
|
+
|
|
32
|
+
root_level = min(root_level, file_handler.level)
|
|
33
|
+
|
|
34
|
+
opik_root_logger.setLevel(level=root_level)
|
|
File without changes
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from typing import List, Callable, Any, Dict
|
|
5
|
+
|
|
6
|
+
from . import dataset_item
|
|
7
|
+
|
|
8
|
+
ItemConstructor = Callable[[Any], dataset_item.DatasetItem]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def to_pandas(
|
|
12
|
+
items: List[dataset_item.DatasetItem], keys_mapping: Dict[str, str]
|
|
13
|
+
) -> pd.DataFrame:
|
|
14
|
+
new_item_dicts = []
|
|
15
|
+
|
|
16
|
+
for item in items:
|
|
17
|
+
new_item_dict = {
|
|
18
|
+
keys_mapping.get(key, key): value for key, value in item.__dict__.items()
|
|
19
|
+
}
|
|
20
|
+
new_item_dicts.append(new_item_dict)
|
|
21
|
+
|
|
22
|
+
return pd.DataFrame(new_item_dicts)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def from_pandas(
|
|
26
|
+
dataframe: pd.DataFrame,
|
|
27
|
+
keys_mapping: Dict[str, str],
|
|
28
|
+
ignore_keys: List[str],
|
|
29
|
+
) -> List[dataset_item.DatasetItem]:
|
|
30
|
+
result = []
|
|
31
|
+
ignore_keys = [] if ignore_keys is None else ignore_keys
|
|
32
|
+
for _, row in dataframe.iterrows():
|
|
33
|
+
item_kwargs = {
|
|
34
|
+
keys_mapping.get(key, key): value
|
|
35
|
+
for key, value in row.items()
|
|
36
|
+
if key not in ignore_keys
|
|
37
|
+
}
|
|
38
|
+
result.append(dataset_item.DatasetItem(**item_kwargs))
|
|
39
|
+
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def to_json(items: List[dataset_item.DatasetItem], keys_mapping: Dict[str, str]) -> str:
|
|
44
|
+
new_item_dicts = []
|
|
45
|
+
|
|
46
|
+
for item in items:
|
|
47
|
+
item_dict = item.__dict__
|
|
48
|
+
new_item_dict = {
|
|
49
|
+
keys_mapping.get(key, key): value for key, value in item_dict.items()
|
|
50
|
+
}
|
|
51
|
+
new_item_dicts.append(new_item_dict)
|
|
52
|
+
|
|
53
|
+
result: str = json.dumps(new_item_dicts, indent=2)
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def from_json(
|
|
58
|
+
value: str, keys_mapping: Dict[str, str], ignore_keys: List[str]
|
|
59
|
+
) -> List[dataset_item.DatasetItem]:
|
|
60
|
+
result = []
|
|
61
|
+
item_dicts: List[Dict[str, Any]] = json.loads(value)
|
|
62
|
+
|
|
63
|
+
for item_dict in item_dicts:
|
|
64
|
+
item_kwargs = {
|
|
65
|
+
keys_mapping.get(key, key): value
|
|
66
|
+
for key, value in item_dict.items()
|
|
67
|
+
if key not in ignore_keys
|
|
68
|
+
}
|
|
69
|
+
result.append(dataset_item.DatasetItem(**item_kwargs))
|
|
70
|
+
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def from_dicts(dict_items: List[Dict[str, Any]]) -> List[dataset_item.DatasetItem]:
|
|
75
|
+
items = [dataset_item.DatasetItem(**dict_item) for dict_item in dict_items]
|
|
76
|
+
return items
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import json
|
|
3
|
+
from typing import Optional, Any, List, Dict, Union, cast
|
|
4
|
+
|
|
5
|
+
from opik.rest_api import client as rest_api_client
|
|
6
|
+
from opik.rest_api.types import dataset_item as rest_dataset_item
|
|
7
|
+
from opik import exceptions
|
|
8
|
+
|
|
9
|
+
from .. import helpers, constants
|
|
10
|
+
from . import dataset_item, converters
|
|
11
|
+
|
|
12
|
+
import pandas
|
|
13
|
+
|
|
14
|
+
LOGGER = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Dataset:
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
name: str,
|
|
21
|
+
description: Optional[str],
|
|
22
|
+
rest_client: rest_api_client.OpikApi,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
A Dataset object. This object should not be created directly, instead use :meth:`opik.Opik.create_dataset` or :meth:`opik.Opik.get_dataset`.
|
|
26
|
+
"""
|
|
27
|
+
self._name = name
|
|
28
|
+
self._description = description
|
|
29
|
+
self._rest_client = rest_client
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def name(self) -> str:
|
|
33
|
+
"""The name of the dataset."""
|
|
34
|
+
return self._name
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def description(self) -> Optional[str]:
|
|
38
|
+
"""The description of the dataset."""
|
|
39
|
+
return self._description
|
|
40
|
+
|
|
41
|
+
def insert(
|
|
42
|
+
self, items: Union[List[dataset_item.DatasetItem], List[Dict[str, Any]]]
|
|
43
|
+
) -> None:
|
|
44
|
+
"""
|
|
45
|
+
Insert new items into the dataset.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
items: List of DatasetItem objects or dicts (which will be converted to DatasetItem objects)
|
|
49
|
+
to add to the dataset.
|
|
50
|
+
"""
|
|
51
|
+
if len(items) > 0 and isinstance(items[0], dict):
|
|
52
|
+
items = converters.from_dicts(items) # type: ignore
|
|
53
|
+
|
|
54
|
+
items = cast(List[dataset_item.DatasetItem], items)
|
|
55
|
+
|
|
56
|
+
rest_items = [
|
|
57
|
+
rest_dataset_item.DatasetItem(
|
|
58
|
+
id=item.id if item.id is not None else helpers.generate_id(), # type: ignore
|
|
59
|
+
input=item.input, # type: ignore
|
|
60
|
+
expected_output=item.expected_output, # type: ignore
|
|
61
|
+
metadata=item.metadata, # type: ignore
|
|
62
|
+
trace_id=item.trace_id, # type: ignore
|
|
63
|
+
span_id=item.span_id, # type: ignore
|
|
64
|
+
source=item.source, # type: ignore
|
|
65
|
+
)
|
|
66
|
+
for item in items
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
batches = helpers.list_to_batches(
|
|
70
|
+
rest_items, batch_size=constants.DATASET_ITEMS_MAX_BATCH_SIZE
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
for batch in batches:
|
|
74
|
+
LOGGER.debug("Sending dataset items batch: %s", batch)
|
|
75
|
+
self._rest_client.datasets.create_or_update_dataset_items(
|
|
76
|
+
dataset_name=self._name, items=batch
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def update(self, items: List[dataset_item.DatasetItem]) -> None:
|
|
80
|
+
"""
|
|
81
|
+
Update existing items in the dataset.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
items: List of DatasetItem objects to update in the dataset. You need to provide the full item object as it will override what has been supplied previously.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
DatasetItemUpdateOperationRequiresItemId: If any item in the list is missing an id.
|
|
88
|
+
"""
|
|
89
|
+
for item in items:
|
|
90
|
+
if item.id is None: # TODO: implement proper exception
|
|
91
|
+
raise exceptions.DatasetItemUpdateOperationRequiresItemId(
|
|
92
|
+
"Missing id for dataset item to update: %s", item
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
self.insert(items)
|
|
96
|
+
|
|
97
|
+
def delete(self, items_ids: List[str]) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Delete items from the dataset.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
items_ids: List of item ids to delete.
|
|
103
|
+
"""
|
|
104
|
+
batches = helpers.list_to_batches(
|
|
105
|
+
items_ids, batch_size=constants.DATASET_ITEMS_MAX_BATCH_SIZE
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
for batch in batches:
|
|
109
|
+
LOGGER.debug("Deleting dataset items batch: %s", batch)
|
|
110
|
+
self._rest_client.datasets.delete_dataset_items(item_ids=batch)
|
|
111
|
+
|
|
112
|
+
def clear(self) -> None:
|
|
113
|
+
"""
|
|
114
|
+
Delete all items from the given dataset.
|
|
115
|
+
"""
|
|
116
|
+
all_items = self.get_all_items()
|
|
117
|
+
item_ids = [item.id for item in all_items if item.id is not None]
|
|
118
|
+
self.delete(item_ids)
|
|
119
|
+
|
|
120
|
+
def to_pandas(self) -> pandas.DataFrame:
|
|
121
|
+
"""
|
|
122
|
+
Convert the dataset to a pandas DataFrame.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
A pandas DataFrame containing all items in the dataset.
|
|
126
|
+
"""
|
|
127
|
+
dataset_items = self.get_all_items()
|
|
128
|
+
|
|
129
|
+
return converters.to_pandas(dataset_items, keys_mapping={})
|
|
130
|
+
|
|
131
|
+
def to_json(self) -> str:
|
|
132
|
+
"""
|
|
133
|
+
Convert the dataset to a JSON string.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
A JSON string representation of all items in the dataset.
|
|
137
|
+
"""
|
|
138
|
+
dataset_items = self.get_all_items()
|
|
139
|
+
|
|
140
|
+
return converters.to_json(dataset_items, keys_mapping={})
|
|
141
|
+
|
|
142
|
+
def get_all_items(self) -> List[dataset_item.DatasetItem]:
|
|
143
|
+
"""
|
|
144
|
+
Retrieve all items from the dataset.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
A list of DatasetItem objects representing all items in the dataset.
|
|
148
|
+
"""
|
|
149
|
+
results: List[dataset_item.DatasetItem] = []
|
|
150
|
+
|
|
151
|
+
while True:
|
|
152
|
+
stream = self._rest_client.datasets.stream_dataset_items(
|
|
153
|
+
dataset_name=self._name,
|
|
154
|
+
last_retrieved_id=results[-1].id if len(results) > 0 else None,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
item_bytes = b"".join(stream)
|
|
158
|
+
stream_results: List[dataset_item.DatasetItem] = []
|
|
159
|
+
for line in item_bytes.split(b"\n"):
|
|
160
|
+
if len(line) == 0:
|
|
161
|
+
continue
|
|
162
|
+
|
|
163
|
+
item_content: Dict[str, Any] = json.loads(line.decode("utf-8").strip())
|
|
164
|
+
|
|
165
|
+
item = dataset_item.DatasetItem(
|
|
166
|
+
id=item_content.get("id"), # type: ignore
|
|
167
|
+
input=item_content.get("input"), # type: ignore
|
|
168
|
+
expected_output=item_content.get("expected_output"), # type: ignore
|
|
169
|
+
metadata=item_content.get("metadata"), # type: ignore
|
|
170
|
+
trace_id=item_content.get("trace_id"), # type: ignore
|
|
171
|
+
span_id=item_content.get("span_id"), # type: ignore
|
|
172
|
+
source=item_content.get("source"), # type: ignore
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
stream_results.append(item)
|
|
176
|
+
|
|
177
|
+
if len(stream_results) == 0:
|
|
178
|
+
break
|
|
179
|
+
|
|
180
|
+
results.extend(stream_results)
|
|
181
|
+
|
|
182
|
+
return results
|
|
183
|
+
|
|
184
|
+
def insert_from_json(
|
|
185
|
+
self,
|
|
186
|
+
json_array: str,
|
|
187
|
+
keys_mapping: Optional[Dict[str, str]] = None,
|
|
188
|
+
ignore_keys: Optional[List[str]] = None,
|
|
189
|
+
) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Args:
|
|
192
|
+
json_array: json string of format: "[{...}, {...}, {...}]" where every dictionary
|
|
193
|
+
is to be transformed into dataset item
|
|
194
|
+
keys_mapping: dictionary that maps json keys to item fields names
|
|
195
|
+
Example: {'Expected output': 'expected_output'}
|
|
196
|
+
ignore_keys: if your json dicts contain keys that are not needed for DatasetItem
|
|
197
|
+
construction - pass them as ignore_keys argument
|
|
198
|
+
"""
|
|
199
|
+
keys_mapping = {} if keys_mapping is None else keys_mapping
|
|
200
|
+
ignore_keys = [] if ignore_keys is None else ignore_keys
|
|
201
|
+
|
|
202
|
+
new_items = converters.from_json(
|
|
203
|
+
json_array, keys_mapping=keys_mapping, ignore_keys=ignore_keys
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
self.insert(new_items)
|
|
207
|
+
|
|
208
|
+
def insert_from_pandas(
|
|
209
|
+
self,
|
|
210
|
+
dataframe: pandas.DataFrame,
|
|
211
|
+
keys_mapping: Optional[Dict[str, str]] = None,
|
|
212
|
+
ignore_keys: Optional[List[str]] = None,
|
|
213
|
+
) -> None:
|
|
214
|
+
"""
|
|
215
|
+
Args:
|
|
216
|
+
dataframe: pandas dataframe
|
|
217
|
+
keys_mapping: Dictionary that maps dataframe column names to dataset item field names.
|
|
218
|
+
Example: {'Expected output': 'expected_output'}
|
|
219
|
+
ignore_keys: if your dataframe contains columns that are not needed for DatasetItem
|
|
220
|
+
construction - pass them as ignore_keys argument
|
|
221
|
+
"""
|
|
222
|
+
keys_mapping = {} if keys_mapping is None else keys_mapping
|
|
223
|
+
ignore_keys = [] if ignore_keys is None else ignore_keys
|
|
224
|
+
|
|
225
|
+
new_items = converters.from_pandas(dataframe, keys_mapping, ignore_keys)
|
|
226
|
+
|
|
227
|
+
self.insert(new_items)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Optional, Dict, Any
|
|
2
|
+
import dataclasses
|
|
3
|
+
from .. import constants
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclasses.dataclass
|
|
7
|
+
class DatasetItem:
|
|
8
|
+
"""A DatasetItem object representing an item in a dataset."""
|
|
9
|
+
|
|
10
|
+
input: Dict[str, Any]
|
|
11
|
+
"""The input data for the dataset item."""
|
|
12
|
+
|
|
13
|
+
expected_output: Optional[Dict[str, Any]] = None
|
|
14
|
+
"""The expected output for the dataset item."""
|
|
15
|
+
|
|
16
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
17
|
+
"""Additional metadata associated with the dataset item."""
|
|
18
|
+
|
|
19
|
+
trace_id: Optional[str] = None
|
|
20
|
+
"""The ID of the trace associated with this dataset item."""
|
|
21
|
+
|
|
22
|
+
span_id: Optional[str] = None
|
|
23
|
+
"""The ID of the span associated with this dataset item."""
|
|
24
|
+
|
|
25
|
+
id: Optional[str] = None
|
|
26
|
+
"""The unique identifier for this dataset item."""
|
|
27
|
+
|
|
28
|
+
source: str = constants.DATASET_SOURCE_SDK
|
|
29
|
+
"""The source of the dataset item. Defaults to DATASET_SOURCE_SDK."""
|
|
30
|
+
|
|
31
|
+
def get_content(self) -> Dict[str, Any]:
|
|
32
|
+
return {
|
|
33
|
+
"input": self.input,
|
|
34
|
+
"expected_output": self.expected_output,
|
|
35
|
+
"metadata": self.metadata,
|
|
36
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from opik.rest_api import client as rest_api_client
|
|
5
|
+
from opik.rest_api.types import experiment_item as rest_experiment_item
|
|
6
|
+
from . import experiment_item
|
|
7
|
+
from .. import helpers, constants
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
LOGGER = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Experiment:
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
id: str,
|
|
17
|
+
name: str,
|
|
18
|
+
dataset_name: str,
|
|
19
|
+
rest_client: rest_api_client.OpikApi,
|
|
20
|
+
) -> None:
|
|
21
|
+
self._id = id
|
|
22
|
+
self._name = name
|
|
23
|
+
self._dataset_name = dataset_name
|
|
24
|
+
self._rest_client = rest_client
|
|
25
|
+
|
|
26
|
+
def insert(self, experiment_items: List[experiment_item.ExperimentItem]) -> None:
|
|
27
|
+
rest_experiment_items = [
|
|
28
|
+
rest_experiment_item.ExperimentItem(
|
|
29
|
+
id=item.id if item.id is not None else helpers.generate_id(),
|
|
30
|
+
experiment_id=self._id,
|
|
31
|
+
dataset_item_id=item.dataset_item_id,
|
|
32
|
+
trace_id=item.trace_id,
|
|
33
|
+
)
|
|
34
|
+
for item in experiment_items
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
batches = helpers.list_to_batches(
|
|
38
|
+
rest_experiment_items, batch_size=constants.EXPERIMENT_ITEMS_MAX_BATCH_SIZE
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
for batch in batches:
|
|
42
|
+
LOGGER.debug("Sending experiment items batch: %s", batch)
|
|
43
|
+
self._rest_client.experiments.create_experiment_items(
|
|
44
|
+
experiment_items=batch,
|
|
45
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import uuid_extensions
|
|
3
|
+
|
|
4
|
+
from typing import List, Any
|
|
5
|
+
|
|
6
|
+
from .. import datetime_helpers
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def generate_id() -> str:
|
|
11
|
+
return str(uuid_extensions.uuid7())
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def datetime_to_iso8601_if_not_None(
|
|
15
|
+
value: Optional[datetime.datetime],
|
|
16
|
+
) -> Optional[str]:
|
|
17
|
+
if value is None:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
return datetime_helpers.datetime_to_iso8601(value)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def list_to_batches(items: List[Any], batch_size: int) -> List[List[Any]]:
|
|
24
|
+
return [items[i : i + batch_size] for i in range(0, len(items), batch_size)]
|