opik 1.8.39__py3-none-any.whl → 1.9.71__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.
- opik/__init__.py +19 -3
- opik/anonymizer/__init__.py +5 -0
- opik/anonymizer/anonymizer.py +12 -0
- opik/anonymizer/factory.py +80 -0
- opik/anonymizer/recursive_anonymizer.py +64 -0
- opik/anonymizer/rules.py +56 -0
- opik/anonymizer/rules_anonymizer.py +35 -0
- opik/api_objects/attachment/attachment_context.py +36 -0
- opik/api_objects/attachment/attachments_extractor.py +153 -0
- opik/api_objects/attachment/client.py +1 -0
- opik/api_objects/attachment/converters.py +2 -0
- opik/api_objects/attachment/decoder.py +18 -0
- opik/api_objects/attachment/decoder_base64.py +83 -0
- opik/api_objects/attachment/decoder_helpers.py +137 -0
- opik/api_objects/data_helpers.py +79 -0
- opik/api_objects/dataset/dataset.py +64 -4
- opik/api_objects/dataset/rest_operations.py +11 -2
- opik/api_objects/experiment/experiment.py +57 -57
- opik/api_objects/experiment/experiment_item.py +2 -1
- opik/api_objects/experiment/experiments_client.py +64 -0
- opik/api_objects/experiment/helpers.py +35 -11
- opik/api_objects/experiment/rest_operations.py +65 -5
- opik/api_objects/helpers.py +8 -5
- opik/api_objects/local_recording.py +81 -0
- opik/api_objects/opik_client.py +600 -108
- opik/api_objects/opik_query_language.py +39 -5
- opik/api_objects/prompt/__init__.py +12 -2
- opik/api_objects/prompt/base_prompt.py +69 -0
- opik/api_objects/prompt/base_prompt_template.py +29 -0
- opik/api_objects/prompt/chat/__init__.py +1 -0
- opik/api_objects/prompt/chat/chat_prompt.py +210 -0
- opik/api_objects/prompt/chat/chat_prompt_template.py +350 -0
- opik/api_objects/prompt/chat/content_renderer_registry.py +203 -0
- opik/api_objects/prompt/client.py +189 -47
- opik/api_objects/prompt/text/__init__.py +1 -0
- opik/api_objects/prompt/text/prompt.py +174 -0
- opik/api_objects/prompt/{prompt_template.py → text/prompt_template.py} +10 -6
- opik/api_objects/prompt/types.py +23 -0
- opik/api_objects/search_helpers.py +89 -0
- opik/api_objects/span/span_data.py +35 -25
- opik/api_objects/threads/threads_client.py +39 -5
- opik/api_objects/trace/trace_client.py +52 -2
- opik/api_objects/trace/trace_data.py +15 -24
- opik/api_objects/validation_helpers.py +3 -3
- opik/cli/__init__.py +5 -0
- opik/cli/__main__.py +6 -0
- opik/cli/configure.py +66 -0
- opik/cli/exports/__init__.py +131 -0
- opik/cli/exports/dataset.py +278 -0
- opik/cli/exports/experiment.py +784 -0
- opik/cli/exports/project.py +685 -0
- opik/cli/exports/prompt.py +578 -0
- opik/cli/exports/utils.py +406 -0
- opik/cli/harbor.py +39 -0
- opik/cli/healthcheck.py +21 -0
- opik/cli/imports/__init__.py +439 -0
- opik/cli/imports/dataset.py +143 -0
- opik/cli/imports/experiment.py +1192 -0
- opik/cli/imports/project.py +262 -0
- opik/cli/imports/prompt.py +177 -0
- opik/cli/imports/utils.py +280 -0
- opik/cli/main.py +49 -0
- opik/cli/proxy.py +93 -0
- opik/cli/usage_report/__init__.py +16 -0
- opik/cli/usage_report/charts.py +783 -0
- opik/cli/usage_report/cli.py +274 -0
- opik/cli/usage_report/constants.py +9 -0
- opik/cli/usage_report/extraction.py +749 -0
- opik/cli/usage_report/pdf.py +244 -0
- opik/cli/usage_report/statistics.py +78 -0
- opik/cli/usage_report/utils.py +235 -0
- opik/config.py +13 -7
- opik/configurator/configure.py +17 -0
- opik/datetime_helpers.py +12 -0
- opik/decorator/arguments_helpers.py +9 -1
- opik/decorator/base_track_decorator.py +205 -133
- opik/decorator/context_manager/span_context_manager.py +123 -0
- opik/decorator/context_manager/trace_context_manager.py +84 -0
- opik/decorator/opik_args/__init__.py +13 -0
- opik/decorator/opik_args/api_classes.py +71 -0
- opik/decorator/opik_args/helpers.py +120 -0
- opik/decorator/span_creation_handler.py +25 -6
- opik/dict_utils.py +3 -3
- opik/evaluation/__init__.py +13 -2
- opik/evaluation/engine/engine.py +272 -75
- opik/evaluation/engine/evaluation_tasks_executor.py +6 -3
- opik/evaluation/engine/helpers.py +31 -6
- opik/evaluation/engine/metrics_evaluator.py +237 -0
- opik/evaluation/evaluation_result.py +168 -2
- opik/evaluation/evaluator.py +533 -62
- opik/evaluation/metrics/__init__.py +103 -4
- opik/evaluation/metrics/aggregated_metric.py +35 -6
- opik/evaluation/metrics/base_metric.py +1 -1
- opik/evaluation/metrics/conversation/__init__.py +48 -0
- opik/evaluation/metrics/conversation/conversation_thread_metric.py +56 -2
- opik/evaluation/metrics/conversation/g_eval_wrappers.py +19 -0
- opik/evaluation/metrics/conversation/helpers.py +14 -15
- opik/evaluation/metrics/conversation/heuristics/__init__.py +14 -0
- opik/evaluation/metrics/conversation/heuristics/degeneration/__init__.py +3 -0
- opik/evaluation/metrics/conversation/heuristics/degeneration/metric.py +189 -0
- opik/evaluation/metrics/conversation/heuristics/degeneration/phrases.py +12 -0
- opik/evaluation/metrics/conversation/heuristics/knowledge_retention/__init__.py +3 -0
- opik/evaluation/metrics/conversation/heuristics/knowledge_retention/metric.py +172 -0
- opik/evaluation/metrics/conversation/llm_judges/__init__.py +32 -0
- opik/evaluation/metrics/conversation/{conversational_coherence → llm_judges/conversational_coherence}/metric.py +22 -17
- opik/evaluation/metrics/conversation/{conversational_coherence → llm_judges/conversational_coherence}/templates.py +1 -1
- opik/evaluation/metrics/conversation/llm_judges/g_eval_wrappers.py +442 -0
- opik/evaluation/metrics/conversation/{session_completeness → llm_judges/session_completeness}/metric.py +13 -7
- opik/evaluation/metrics/conversation/{session_completeness → llm_judges/session_completeness}/templates.py +1 -1
- opik/evaluation/metrics/conversation/llm_judges/user_frustration/__init__.py +0 -0
- opik/evaluation/metrics/conversation/{user_frustration → llm_judges/user_frustration}/metric.py +21 -14
- opik/evaluation/metrics/conversation/{user_frustration → llm_judges/user_frustration}/templates.py +1 -1
- opik/evaluation/metrics/conversation/types.py +4 -5
- opik/evaluation/metrics/conversation_types.py +9 -0
- opik/evaluation/metrics/heuristics/bertscore.py +107 -0
- opik/evaluation/metrics/heuristics/bleu.py +35 -15
- opik/evaluation/metrics/heuristics/chrf.py +127 -0
- opik/evaluation/metrics/heuristics/contains.py +47 -11
- opik/evaluation/metrics/heuristics/distribution_metrics.py +331 -0
- opik/evaluation/metrics/heuristics/gleu.py +113 -0
- opik/evaluation/metrics/heuristics/language_adherence.py +123 -0
- opik/evaluation/metrics/heuristics/meteor.py +119 -0
- opik/evaluation/metrics/heuristics/prompt_injection.py +150 -0
- opik/evaluation/metrics/heuristics/readability.py +129 -0
- opik/evaluation/metrics/heuristics/rouge.py +26 -9
- opik/evaluation/metrics/heuristics/spearman.py +88 -0
- opik/evaluation/metrics/heuristics/tone.py +155 -0
- opik/evaluation/metrics/heuristics/vader_sentiment.py +77 -0
- opik/evaluation/metrics/llm_judges/answer_relevance/metric.py +20 -5
- opik/evaluation/metrics/llm_judges/context_precision/metric.py +20 -6
- opik/evaluation/metrics/llm_judges/context_recall/metric.py +20 -6
- opik/evaluation/metrics/llm_judges/g_eval/__init__.py +5 -0
- opik/evaluation/metrics/llm_judges/g_eval/metric.py +219 -68
- opik/evaluation/metrics/llm_judges/g_eval/parser.py +102 -52
- opik/evaluation/metrics/llm_judges/g_eval/presets.py +209 -0
- opik/evaluation/metrics/llm_judges/g_eval_presets/__init__.py +36 -0
- opik/evaluation/metrics/llm_judges/g_eval_presets/agent_assessment.py +77 -0
- opik/evaluation/metrics/llm_judges/g_eval_presets/bias_classifier.py +181 -0
- opik/evaluation/metrics/llm_judges/g_eval_presets/compliance_risk.py +41 -0
- opik/evaluation/metrics/llm_judges/g_eval_presets/prompt_uncertainty.py +41 -0
- opik/evaluation/metrics/llm_judges/g_eval_presets/qa_suite.py +146 -0
- opik/evaluation/metrics/llm_judges/hallucination/metric.py +16 -3
- opik/evaluation/metrics/llm_judges/llm_juries/__init__.py +3 -0
- opik/evaluation/metrics/llm_judges/llm_juries/metric.py +76 -0
- opik/evaluation/metrics/llm_judges/moderation/metric.py +16 -4
- opik/evaluation/metrics/llm_judges/structure_output_compliance/__init__.py +0 -0
- opik/evaluation/metrics/llm_judges/structure_output_compliance/metric.py +144 -0
- opik/evaluation/metrics/llm_judges/structure_output_compliance/parser.py +79 -0
- opik/evaluation/metrics/llm_judges/structure_output_compliance/schema.py +15 -0
- opik/evaluation/metrics/llm_judges/structure_output_compliance/template.py +50 -0
- opik/evaluation/metrics/llm_judges/syc_eval/__init__.py +0 -0
- opik/evaluation/metrics/llm_judges/syc_eval/metric.py +252 -0
- opik/evaluation/metrics/llm_judges/syc_eval/parser.py +82 -0
- opik/evaluation/metrics/llm_judges/syc_eval/template.py +155 -0
- opik/evaluation/metrics/llm_judges/trajectory_accuracy/metric.py +20 -5
- opik/evaluation/metrics/llm_judges/usefulness/metric.py +16 -4
- opik/evaluation/metrics/ragas_metric.py +43 -23
- opik/evaluation/models/__init__.py +8 -0
- opik/evaluation/models/base_model.py +107 -1
- opik/evaluation/models/langchain/langchain_chat_model.py +15 -7
- opik/evaluation/models/langchain/message_converters.py +97 -15
- opik/evaluation/models/litellm/litellm_chat_model.py +156 -29
- opik/evaluation/models/litellm/util.py +125 -0
- opik/evaluation/models/litellm/warning_filters.py +16 -4
- opik/evaluation/models/model_capabilities.py +187 -0
- opik/evaluation/models/models_factory.py +25 -3
- opik/evaluation/preprocessing.py +92 -0
- opik/evaluation/report.py +70 -12
- opik/evaluation/rest_operations.py +49 -45
- opik/evaluation/samplers/__init__.py +4 -0
- opik/evaluation/samplers/base_dataset_sampler.py +40 -0
- opik/evaluation/samplers/random_dataset_sampler.py +48 -0
- opik/evaluation/score_statistics.py +66 -0
- opik/evaluation/scorers/__init__.py +4 -0
- opik/evaluation/scorers/scorer_function.py +55 -0
- opik/evaluation/scorers/scorer_wrapper_metric.py +130 -0
- opik/evaluation/test_case.py +3 -2
- opik/evaluation/test_result.py +1 -0
- opik/evaluation/threads/evaluator.py +31 -3
- opik/evaluation/threads/helpers.py +3 -2
- opik/evaluation/types.py +9 -1
- opik/exceptions.py +33 -0
- opik/file_upload/file_uploader.py +13 -0
- opik/file_upload/upload_options.py +2 -0
- opik/hooks/__init__.py +23 -0
- opik/hooks/anonymizer_hook.py +36 -0
- opik/hooks/httpx_client_hook.py +112 -0
- opik/httpx_client.py +12 -9
- opik/id_helpers.py +18 -0
- opik/integrations/adk/graph/subgraph_edges_builders.py +1 -2
- opik/integrations/adk/helpers.py +16 -7
- opik/integrations/adk/legacy_opik_tracer.py +7 -4
- opik/integrations/adk/opik_tracer.py +14 -1
- opik/integrations/adk/patchers/adk_otel_tracer/opik_adk_otel_tracer.py +7 -3
- opik/integrations/adk/recursive_callback_injector.py +4 -7
- opik/integrations/bedrock/converse/__init__.py +0 -0
- opik/integrations/bedrock/converse/chunks_aggregator.py +188 -0
- opik/integrations/bedrock/{converse_decorator.py → converse/converse_decorator.py} +4 -3
- opik/integrations/bedrock/invoke_agent_decorator.py +5 -4
- opik/integrations/bedrock/invoke_model/__init__.py +0 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/__init__.py +78 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/api.py +45 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/base.py +23 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/claude.py +121 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/format_detector.py +107 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/llama.py +108 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/mistral.py +118 -0
- opik/integrations/bedrock/invoke_model/chunks_aggregator/nova.py +99 -0
- opik/integrations/bedrock/invoke_model/invoke_model_decorator.py +178 -0
- opik/integrations/bedrock/invoke_model/response_types.py +34 -0
- opik/integrations/bedrock/invoke_model/stream_wrappers.py +122 -0
- opik/integrations/bedrock/invoke_model/usage_converters.py +87 -0
- opik/integrations/bedrock/invoke_model/usage_extraction.py +108 -0
- opik/integrations/bedrock/opik_tracker.py +42 -4
- opik/integrations/bedrock/types.py +19 -0
- opik/integrations/crewai/crewai_decorator.py +8 -51
- opik/integrations/crewai/opik_tracker.py +31 -10
- opik/integrations/crewai/patchers/__init__.py +5 -0
- opik/integrations/crewai/patchers/flow.py +118 -0
- opik/integrations/crewai/patchers/litellm_completion.py +30 -0
- opik/integrations/crewai/patchers/llm_client.py +207 -0
- opik/integrations/dspy/callback.py +80 -17
- opik/integrations/dspy/parsers.py +168 -0
- opik/integrations/harbor/__init__.py +17 -0
- opik/integrations/harbor/experiment_service.py +269 -0
- opik/integrations/harbor/opik_tracker.py +528 -0
- opik/integrations/haystack/opik_connector.py +2 -2
- opik/integrations/haystack/opik_tracer.py +3 -7
- opik/integrations/langchain/__init__.py +3 -1
- opik/integrations/langchain/helpers.py +96 -0
- opik/integrations/langchain/langgraph_async_context_bridge.py +131 -0
- opik/integrations/langchain/langgraph_tracer_injector.py +88 -0
- opik/integrations/langchain/opik_encoder_extension.py +1 -1
- opik/integrations/langchain/opik_tracer.py +474 -229
- opik/integrations/litellm/__init__.py +5 -0
- opik/integrations/litellm/completion_chunks_aggregator.py +115 -0
- opik/integrations/litellm/litellm_completion_decorator.py +242 -0
- opik/integrations/litellm/opik_tracker.py +43 -0
- opik/integrations/litellm/stream_patchers.py +151 -0
- opik/integrations/llama_index/callback.py +146 -107
- opik/integrations/openai/agents/opik_tracing_processor.py +1 -2
- opik/integrations/openai/openai_chat_completions_decorator.py +2 -16
- opik/integrations/openai/opik_tracker.py +1 -1
- opik/integrations/sagemaker/auth.py +5 -1
- opik/llm_usage/google_usage.py +3 -1
- opik/llm_usage/opik_usage.py +7 -8
- opik/llm_usage/opik_usage_factory.py +4 -2
- opik/logging_messages.py +6 -0
- opik/message_processing/batching/base_batcher.py +14 -21
- opik/message_processing/batching/batch_manager.py +22 -10
- opik/message_processing/batching/batch_manager_constuctors.py +10 -0
- opik/message_processing/batching/batchers.py +59 -27
- opik/message_processing/batching/flushing_thread.py +0 -3
- opik/message_processing/emulation/__init__.py +0 -0
- opik/message_processing/emulation/emulator_message_processor.py +578 -0
- opik/message_processing/emulation/local_emulator_message_processor.py +140 -0
- opik/message_processing/emulation/models.py +162 -0
- opik/message_processing/encoder_helpers.py +79 -0
- opik/message_processing/messages.py +56 -1
- opik/message_processing/preprocessing/__init__.py +0 -0
- opik/message_processing/preprocessing/attachments_preprocessor.py +70 -0
- opik/message_processing/preprocessing/batching_preprocessor.py +53 -0
- opik/message_processing/preprocessing/constants.py +1 -0
- opik/message_processing/preprocessing/file_upload_preprocessor.py +38 -0
- opik/message_processing/preprocessing/preprocessor.py +36 -0
- opik/message_processing/processors/__init__.py +0 -0
- opik/message_processing/processors/attachments_extraction_processor.py +146 -0
- opik/message_processing/processors/message_processors.py +92 -0
- opik/message_processing/processors/message_processors_chain.py +96 -0
- opik/message_processing/{message_processors.py → processors/online_message_processor.py} +85 -29
- opik/message_processing/queue_consumer.py +9 -3
- opik/message_processing/streamer.py +71 -33
- opik/message_processing/streamer_constructors.py +43 -10
- opik/opik_context.py +16 -4
- opik/plugins/pytest/hooks.py +5 -3
- opik/rest_api/__init__.py +346 -15
- opik/rest_api/alerts/__init__.py +7 -0
- opik/rest_api/alerts/client.py +667 -0
- opik/rest_api/alerts/raw_client.py +1015 -0
- opik/rest_api/alerts/types/__init__.py +7 -0
- opik/rest_api/alerts/types/get_webhook_examples_request_alert_type.py +5 -0
- opik/rest_api/annotation_queues/__init__.py +4 -0
- opik/rest_api/annotation_queues/client.py +668 -0
- opik/rest_api/annotation_queues/raw_client.py +1019 -0
- opik/rest_api/automation_rule_evaluators/client.py +34 -2
- opik/rest_api/automation_rule_evaluators/raw_client.py +24 -0
- opik/rest_api/client.py +15 -0
- opik/rest_api/dashboards/__init__.py +4 -0
- opik/rest_api/dashboards/client.py +462 -0
- opik/rest_api/dashboards/raw_client.py +648 -0
- opik/rest_api/datasets/client.py +1310 -44
- opik/rest_api/datasets/raw_client.py +2269 -358
- opik/rest_api/experiments/__init__.py +2 -2
- opik/rest_api/experiments/client.py +191 -5
- opik/rest_api/experiments/raw_client.py +301 -7
- opik/rest_api/experiments/types/__init__.py +4 -1
- opik/rest_api/experiments/types/experiment_update_status.py +5 -0
- opik/rest_api/experiments/types/experiment_update_type.py +5 -0
- opik/rest_api/experiments/types/experiment_write_status.py +5 -0
- opik/rest_api/feedback_definitions/types/find_feedback_definitions_request_type.py +1 -1
- opik/rest_api/llm_provider_key/client.py +20 -0
- opik/rest_api/llm_provider_key/raw_client.py +20 -0
- opik/rest_api/llm_provider_key/types/provider_api_key_write_provider.py +1 -1
- opik/rest_api/manual_evaluation/__init__.py +4 -0
- opik/rest_api/manual_evaluation/client.py +347 -0
- opik/rest_api/manual_evaluation/raw_client.py +543 -0
- opik/rest_api/optimizations/client.py +145 -9
- opik/rest_api/optimizations/raw_client.py +237 -13
- opik/rest_api/optimizations/types/optimization_update_status.py +3 -1
- opik/rest_api/prompts/__init__.py +2 -2
- opik/rest_api/prompts/client.py +227 -6
- opik/rest_api/prompts/raw_client.py +331 -2
- opik/rest_api/prompts/types/__init__.py +3 -1
- opik/rest_api/prompts/types/create_prompt_version_detail_template_structure.py +5 -0
- opik/rest_api/prompts/types/prompt_write_template_structure.py +5 -0
- opik/rest_api/spans/__init__.py +0 -2
- opik/rest_api/spans/client.py +238 -76
- opik/rest_api/spans/raw_client.py +307 -95
- opik/rest_api/spans/types/__init__.py +0 -2
- opik/rest_api/traces/client.py +572 -161
- opik/rest_api/traces/raw_client.py +736 -229
- opik/rest_api/types/__init__.py +352 -17
- opik/rest_api/types/aggregation_data.py +1 -0
- opik/rest_api/types/alert.py +33 -0
- opik/rest_api/types/alert_alert_type.py +5 -0
- opik/rest_api/types/alert_page_public.py +24 -0
- opik/rest_api/types/alert_public.py +33 -0
- opik/rest_api/types/alert_public_alert_type.py +5 -0
- opik/rest_api/types/alert_trigger.py +27 -0
- opik/rest_api/types/alert_trigger_config.py +28 -0
- opik/rest_api/types/alert_trigger_config_public.py +28 -0
- opik/rest_api/types/alert_trigger_config_public_type.py +10 -0
- opik/rest_api/types/alert_trigger_config_type.py +10 -0
- opik/rest_api/types/alert_trigger_config_write.py +22 -0
- opik/rest_api/types/alert_trigger_config_write_type.py +10 -0
- opik/rest_api/types/alert_trigger_event_type.py +19 -0
- opik/rest_api/types/alert_trigger_public.py +27 -0
- opik/rest_api/types/alert_trigger_public_event_type.py +19 -0
- opik/rest_api/types/alert_trigger_write.py +23 -0
- opik/rest_api/types/alert_trigger_write_event_type.py +19 -0
- opik/rest_api/types/alert_write.py +28 -0
- opik/rest_api/types/alert_write_alert_type.py +5 -0
- opik/rest_api/types/annotation_queue.py +42 -0
- opik/rest_api/types/annotation_queue_batch.py +27 -0
- opik/rest_api/types/annotation_queue_item_ids.py +19 -0
- opik/rest_api/types/annotation_queue_page_public.py +28 -0
- opik/rest_api/types/annotation_queue_public.py +38 -0
- opik/rest_api/types/annotation_queue_public_scope.py +5 -0
- opik/rest_api/types/annotation_queue_reviewer.py +20 -0
- opik/rest_api/types/annotation_queue_reviewer_public.py +20 -0
- opik/rest_api/types/annotation_queue_scope.py +5 -0
- opik/rest_api/types/annotation_queue_write.py +31 -0
- opik/rest_api/types/annotation_queue_write_scope.py +5 -0
- opik/rest_api/types/audio_url.py +19 -0
- opik/rest_api/types/audio_url_public.py +19 -0
- opik/rest_api/types/audio_url_write.py +19 -0
- opik/rest_api/types/automation_rule_evaluator.py +62 -2
- opik/rest_api/types/automation_rule_evaluator_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_llm_as_judge_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_llm_as_judge_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_object_object_public.py +155 -0
- opik/rest_api/types/automation_rule_evaluator_page_public.py +3 -2
- opik/rest_api/types/automation_rule_evaluator_public.py +57 -2
- opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge_public.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge_write.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python_public.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python_write.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update.py +51 -1
- opik/rest_api/types/automation_rule_evaluator_update_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update_span_llm_as_judge.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_update_span_user_defined_metric_python.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_update_trace_thread_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update_trace_thread_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_write.py +51 -1
- opik/rest_api/types/boolean_feedback_definition.py +25 -0
- opik/rest_api/types/boolean_feedback_definition_create.py +20 -0
- opik/rest_api/types/boolean_feedback_definition_public.py +25 -0
- opik/rest_api/types/boolean_feedback_definition_update.py +20 -0
- opik/rest_api/types/boolean_feedback_detail.py +29 -0
- opik/rest_api/types/boolean_feedback_detail_create.py +29 -0
- opik/rest_api/types/boolean_feedback_detail_public.py +29 -0
- opik/rest_api/types/boolean_feedback_detail_update.py +29 -0
- opik/rest_api/types/dashboard_page_public.py +24 -0
- opik/rest_api/types/dashboard_public.py +30 -0
- opik/rest_api/types/dataset.py +4 -0
- opik/rest_api/types/dataset_expansion.py +42 -0
- opik/rest_api/types/dataset_expansion_response.py +39 -0
- opik/rest_api/types/dataset_item.py +2 -0
- opik/rest_api/types/dataset_item_changes_public.py +5 -0
- opik/rest_api/types/dataset_item_compare.py +2 -0
- opik/rest_api/types/dataset_item_filter.py +27 -0
- opik/rest_api/types/dataset_item_filter_operator.py +21 -0
- opik/rest_api/types/dataset_item_page_compare.py +5 -0
- opik/rest_api/types/dataset_item_page_public.py +5 -0
- opik/rest_api/types/dataset_item_public.py +2 -0
- opik/rest_api/types/dataset_item_update.py +39 -0
- opik/rest_api/types/dataset_item_write.py +1 -0
- opik/rest_api/types/dataset_public.py +4 -0
- opik/rest_api/types/dataset_public_status.py +5 -0
- opik/rest_api/types/dataset_status.py +5 -0
- opik/rest_api/types/dataset_version_diff.py +22 -0
- opik/rest_api/types/dataset_version_diff_stats.py +24 -0
- opik/rest_api/types/dataset_version_page_public.py +23 -0
- opik/rest_api/types/dataset_version_public.py +59 -0
- opik/rest_api/types/dataset_version_summary.py +46 -0
- opik/rest_api/types/dataset_version_summary_public.py +46 -0
- opik/rest_api/types/experiment.py +7 -2
- opik/rest_api/types/experiment_group_response.py +2 -0
- opik/rest_api/types/experiment_public.py +7 -2
- opik/rest_api/types/experiment_public_status.py +5 -0
- opik/rest_api/types/experiment_score.py +20 -0
- opik/rest_api/types/experiment_score_public.py +20 -0
- opik/rest_api/types/experiment_score_write.py +20 -0
- opik/rest_api/types/experiment_status.py +5 -0
- opik/rest_api/types/feedback.py +25 -1
- opik/rest_api/types/feedback_create.py +20 -1
- opik/rest_api/types/feedback_object_public.py +27 -1
- opik/rest_api/types/feedback_public.py +25 -1
- opik/rest_api/types/feedback_score_batch_item.py +2 -1
- opik/rest_api/types/feedback_score_batch_item_thread.py +2 -1
- opik/rest_api/types/feedback_score_public.py +4 -0
- opik/rest_api/types/feedback_update.py +20 -1
- opik/rest_api/types/group_content_with_aggregations.py +1 -0
- opik/rest_api/types/group_detail.py +19 -0
- opik/rest_api/types/group_details.py +20 -0
- opik/rest_api/types/guardrail.py +1 -0
- opik/rest_api/types/guardrail_write.py +1 -0
- opik/rest_api/types/ids_holder.py +19 -0
- opik/rest_api/types/image_url.py +20 -0
- opik/rest_api/types/image_url_public.py +20 -0
- opik/rest_api/types/image_url_write.py +20 -0
- opik/rest_api/types/llm_as_judge_message.py +5 -1
- opik/rest_api/types/llm_as_judge_message_content.py +26 -0
- opik/rest_api/types/llm_as_judge_message_content_public.py +26 -0
- opik/rest_api/types/llm_as_judge_message_content_write.py +26 -0
- opik/rest_api/types/llm_as_judge_message_public.py +5 -1
- opik/rest_api/types/llm_as_judge_message_write.py +5 -1
- opik/rest_api/types/llm_as_judge_model_parameters.py +3 -0
- opik/rest_api/types/llm_as_judge_model_parameters_public.py +3 -0
- opik/rest_api/types/llm_as_judge_model_parameters_write.py +3 -0
- opik/rest_api/types/manual_evaluation_request.py +38 -0
- opik/rest_api/types/manual_evaluation_request_entity_type.py +5 -0
- opik/rest_api/types/manual_evaluation_response.py +27 -0
- opik/rest_api/types/optimization.py +4 -2
- opik/rest_api/types/optimization_public.py +4 -2
- opik/rest_api/types/optimization_public_status.py +3 -1
- opik/rest_api/types/optimization_status.py +3 -1
- opik/rest_api/types/optimization_studio_config.py +27 -0
- opik/rest_api/types/optimization_studio_config_public.py +27 -0
- opik/rest_api/types/optimization_studio_config_write.py +27 -0
- opik/rest_api/types/optimization_studio_log.py +22 -0
- opik/rest_api/types/optimization_write.py +4 -2
- opik/rest_api/types/optimization_write_status.py +3 -1
- opik/rest_api/types/project.py +1 -0
- opik/rest_api/types/project_detailed.py +1 -0
- opik/rest_api/types/project_reference.py +31 -0
- opik/rest_api/types/project_reference_public.py +31 -0
- opik/rest_api/types/project_stats_summary_item.py +1 -0
- opik/rest_api/types/prompt.py +6 -0
- opik/rest_api/types/prompt_detail.py +6 -0
- opik/rest_api/types/prompt_detail_template_structure.py +5 -0
- opik/rest_api/types/prompt_public.py +6 -0
- opik/rest_api/types/prompt_public_template_structure.py +5 -0
- opik/rest_api/types/prompt_template_structure.py +5 -0
- opik/rest_api/types/prompt_version.py +3 -0
- opik/rest_api/types/prompt_version_detail.py +3 -0
- opik/rest_api/types/prompt_version_detail_template_structure.py +5 -0
- opik/rest_api/types/prompt_version_link.py +1 -0
- opik/rest_api/types/prompt_version_link_public.py +1 -0
- opik/rest_api/types/prompt_version_page_public.py +5 -0
- opik/rest_api/types/prompt_version_public.py +3 -0
- opik/rest_api/types/prompt_version_public_template_structure.py +5 -0
- opik/rest_api/types/prompt_version_template_structure.py +5 -0
- opik/rest_api/types/prompt_version_update.py +33 -0
- opik/rest_api/types/provider_api_key.py +9 -0
- opik/rest_api/types/provider_api_key_provider.py +1 -1
- opik/rest_api/types/provider_api_key_public.py +9 -0
- opik/rest_api/types/provider_api_key_public_provider.py +1 -1
- opik/rest_api/types/score_name.py +1 -0
- opik/rest_api/types/service_toggles_config.py +18 -0
- opik/rest_api/types/span.py +1 -2
- opik/rest_api/types/span_enrichment_options.py +31 -0
- opik/rest_api/types/span_experiment_item_bulk_write_view.py +1 -2
- opik/rest_api/types/span_filter.py +23 -0
- opik/rest_api/types/span_filter_operator.py +21 -0
- opik/rest_api/types/span_filter_write.py +23 -0
- opik/rest_api/types/span_filter_write_operator.py +21 -0
- opik/rest_api/types/span_llm_as_judge_code.py +27 -0
- opik/rest_api/types/span_llm_as_judge_code_public.py +27 -0
- opik/rest_api/types/span_llm_as_judge_code_write.py +27 -0
- opik/rest_api/types/span_public.py +1 -2
- opik/rest_api/types/span_update.py +46 -0
- opik/rest_api/types/span_user_defined_metric_python_code.py +20 -0
- opik/rest_api/types/span_user_defined_metric_python_code_public.py +20 -0
- opik/rest_api/types/span_user_defined_metric_python_code_write.py +20 -0
- opik/rest_api/types/span_write.py +1 -2
- opik/rest_api/types/studio_evaluation.py +20 -0
- opik/rest_api/types/studio_evaluation_public.py +20 -0
- opik/rest_api/types/studio_evaluation_write.py +20 -0
- opik/rest_api/types/studio_llm_model.py +21 -0
- opik/rest_api/types/studio_llm_model_public.py +21 -0
- opik/rest_api/types/studio_llm_model_write.py +21 -0
- opik/rest_api/types/studio_message.py +20 -0
- opik/rest_api/types/studio_message_public.py +20 -0
- opik/rest_api/types/studio_message_write.py +20 -0
- opik/rest_api/types/studio_metric.py +21 -0
- opik/rest_api/types/studio_metric_public.py +21 -0
- opik/rest_api/types/studio_metric_write.py +21 -0
- opik/rest_api/types/studio_optimizer.py +21 -0
- opik/rest_api/types/studio_optimizer_public.py +21 -0
- opik/rest_api/types/studio_optimizer_write.py +21 -0
- opik/rest_api/types/studio_prompt.py +20 -0
- opik/rest_api/types/studio_prompt_public.py +20 -0
- opik/rest_api/types/studio_prompt_write.py +20 -0
- opik/rest_api/types/trace.py +11 -2
- opik/rest_api/types/trace_enrichment_options.py +32 -0
- opik/rest_api/types/trace_experiment_item_bulk_write_view.py +1 -2
- opik/rest_api/types/trace_filter.py +23 -0
- opik/rest_api/types/trace_filter_operator.py +21 -0
- opik/rest_api/types/trace_filter_write.py +23 -0
- opik/rest_api/types/trace_filter_write_operator.py +21 -0
- opik/rest_api/types/trace_public.py +11 -2
- opik/rest_api/types/trace_thread_filter_write.py +23 -0
- opik/rest_api/types/trace_thread_filter_write_operator.py +21 -0
- opik/rest_api/types/trace_thread_identifier.py +1 -0
- opik/rest_api/types/trace_update.py +39 -0
- opik/rest_api/types/trace_write.py +1 -2
- opik/rest_api/types/value_entry.py +2 -0
- opik/rest_api/types/value_entry_compare.py +2 -0
- opik/rest_api/types/value_entry_experiment_item_bulk_write_view.py +2 -0
- opik/rest_api/types/value_entry_public.py +2 -0
- opik/rest_api/types/video_url.py +19 -0
- opik/rest_api/types/video_url_public.py +19 -0
- opik/rest_api/types/video_url_write.py +19 -0
- opik/rest_api/types/webhook.py +28 -0
- opik/rest_api/types/webhook_examples.py +19 -0
- opik/rest_api/types/webhook_public.py +28 -0
- opik/rest_api/types/webhook_test_result.py +23 -0
- opik/rest_api/types/webhook_test_result_status.py +5 -0
- opik/rest_api/types/webhook_write.py +23 -0
- opik/rest_api/types/welcome_wizard_tracking.py +22 -0
- opik/rest_api/types/workspace_configuration.py +5 -0
- opik/rest_api/welcome_wizard/__init__.py +4 -0
- opik/rest_api/welcome_wizard/client.py +195 -0
- opik/rest_api/welcome_wizard/raw_client.py +208 -0
- opik/rest_api/workspaces/client.py +14 -2
- opik/rest_api/workspaces/raw_client.py +10 -0
- opik/s3_httpx_client.py +14 -1
- opik/simulation/__init__.py +6 -0
- opik/simulation/simulated_user.py +99 -0
- opik/simulation/simulator.py +108 -0
- opik/synchronization.py +5 -6
- opik/{decorator/tracing_runtime_config.py → tracing_runtime_config.py} +6 -7
- opik/types.py +36 -0
- opik/validation/chat_prompt_messages.py +241 -0
- opik/validation/feedback_score.py +3 -3
- opik/validation/validator.py +28 -0
- opik-1.9.71.dist-info/METADATA +370 -0
- opik-1.9.71.dist-info/RECORD +1110 -0
- opik/api_objects/prompt/prompt.py +0 -112
- opik/cli.py +0 -193
- opik/hooks.py +0 -13
- opik/integrations/bedrock/chunks_aggregator.py +0 -55
- opik/integrations/bedrock/helpers.py +0 -8
- opik/rest_api/types/automation_rule_evaluator_object_public.py +0 -100
- opik/rest_api/types/json_node_experiment_item_bulk_write_view.py +0 -5
- opik-1.8.39.dist-info/METADATA +0 -339
- opik-1.8.39.dist-info/RECORD +0 -790
- /opik/{evaluation/metrics/conversation/conversational_coherence → decorator/context_manager}/__init__.py +0 -0
- /opik/evaluation/metrics/conversation/{session_completeness → llm_judges/conversational_coherence}/__init__.py +0 -0
- /opik/evaluation/metrics/conversation/{conversational_coherence → llm_judges/conversational_coherence}/schema.py +0 -0
- /opik/evaluation/metrics/conversation/{user_frustration → llm_judges/session_completeness}/__init__.py +0 -0
- /opik/evaluation/metrics/conversation/{session_completeness → llm_judges/session_completeness}/schema.py +0 -0
- /opik/evaluation/metrics/conversation/{user_frustration → llm_judges/user_frustration}/schema.py +0 -0
- /opik/integrations/bedrock/{stream_wrappers.py → converse/stream_wrappers.py} +0 -0
- /opik/rest_api/{spans/types → types}/span_update_type.py +0 -0
- {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/WHEEL +0 -0
- {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/entry_points.txt +0 -0
- {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/licenses/LICENSE +0 -0
- {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import logging
|
|
3
|
+
from typing import List, Dict, Optional, Any, Union
|
|
4
|
+
|
|
5
|
+
from opik.types import ErrorInfoDict, SpanType
|
|
6
|
+
from . import models, emulator_message_processor
|
|
7
|
+
from .. import messages
|
|
8
|
+
from ...rest_api.types import span_write, trace_write
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
LOGGER = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LocalEmulatorMessageProcessor(
|
|
15
|
+
emulator_message_processor.EmulatorMessageProcessor
|
|
16
|
+
):
|
|
17
|
+
"""This class serves as a replacement for the real backend and collects all logged messages
|
|
18
|
+
locally in memory to be used for evaluation.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, active: bool, merge_duplicates: bool = True) -> None:
|
|
22
|
+
super().__init__(active=active, merge_duplicates=merge_duplicates)
|
|
23
|
+
|
|
24
|
+
def process(
|
|
25
|
+
self,
|
|
26
|
+
message: Union[
|
|
27
|
+
messages.BaseMessage, span_write.SpanWrite, trace_write.TraceWrite
|
|
28
|
+
],
|
|
29
|
+
) -> None:
|
|
30
|
+
if not self.is_active():
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
if hasattr(message, "delivery_attempts") and message.delivery_attempts > 1:
|
|
34
|
+
# skip retries
|
|
35
|
+
LOGGER.debug("Skipping retry of the message: %s", message)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
super().process(message)
|
|
39
|
+
|
|
40
|
+
def create_trace_model(
|
|
41
|
+
self,
|
|
42
|
+
trace_id: str,
|
|
43
|
+
start_time: datetime.datetime,
|
|
44
|
+
name: Optional[str],
|
|
45
|
+
project_name: str,
|
|
46
|
+
input: Any,
|
|
47
|
+
output: Any,
|
|
48
|
+
tags: Optional[List[str]],
|
|
49
|
+
metadata: Optional[Dict[str, Any]],
|
|
50
|
+
end_time: Optional[datetime.datetime],
|
|
51
|
+
spans: Optional[List[models.SpanModel]],
|
|
52
|
+
feedback_scores: Optional[List[models.FeedbackScoreModel]],
|
|
53
|
+
error_info: Optional[ErrorInfoDict],
|
|
54
|
+
thread_id: Optional[str],
|
|
55
|
+
last_updated_at: Optional[datetime.datetime] = None,
|
|
56
|
+
) -> models.TraceModel:
|
|
57
|
+
if spans is None:
|
|
58
|
+
spans = []
|
|
59
|
+
if feedback_scores is None:
|
|
60
|
+
feedback_scores = []
|
|
61
|
+
|
|
62
|
+
return models.TraceModel(
|
|
63
|
+
id=trace_id,
|
|
64
|
+
start_time=start_time,
|
|
65
|
+
name=name,
|
|
66
|
+
project_name=project_name,
|
|
67
|
+
input=input,
|
|
68
|
+
output=output,
|
|
69
|
+
tags=tags,
|
|
70
|
+
metadata=metadata,
|
|
71
|
+
end_time=end_time,
|
|
72
|
+
spans=spans,
|
|
73
|
+
feedback_scores=feedback_scores,
|
|
74
|
+
error_info=error_info,
|
|
75
|
+
thread_id=thread_id,
|
|
76
|
+
last_updated_at=last_updated_at,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def create_span_model(
|
|
80
|
+
self,
|
|
81
|
+
span_id: str,
|
|
82
|
+
start_time: datetime.datetime,
|
|
83
|
+
name: Optional[str],
|
|
84
|
+
input: Any,
|
|
85
|
+
output: Any,
|
|
86
|
+
tags: Optional[List[str]],
|
|
87
|
+
metadata: Optional[Dict[str, Any]],
|
|
88
|
+
type: SpanType,
|
|
89
|
+
usage: Optional[Dict[str, Any]],
|
|
90
|
+
end_time: Optional[datetime.datetime],
|
|
91
|
+
project_name: str,
|
|
92
|
+
spans: Optional[List[models.SpanModel]],
|
|
93
|
+
feedback_scores: Optional[List[models.FeedbackScoreModel]],
|
|
94
|
+
model: Optional[str],
|
|
95
|
+
provider: Optional[str],
|
|
96
|
+
error_info: Optional[ErrorInfoDict],
|
|
97
|
+
total_cost: Optional[float],
|
|
98
|
+
last_updated_at: Optional[datetime.datetime],
|
|
99
|
+
) -> models.SpanModel:
|
|
100
|
+
if spans is None:
|
|
101
|
+
spans = []
|
|
102
|
+
if feedback_scores is None:
|
|
103
|
+
feedback_scores = []
|
|
104
|
+
|
|
105
|
+
return models.SpanModel(
|
|
106
|
+
id=span_id,
|
|
107
|
+
start_time=start_time,
|
|
108
|
+
name=name,
|
|
109
|
+
input=input,
|
|
110
|
+
output=output,
|
|
111
|
+
tags=tags,
|
|
112
|
+
metadata=metadata,
|
|
113
|
+
type=type,
|
|
114
|
+
usage=usage,
|
|
115
|
+
end_time=end_time,
|
|
116
|
+
project_name=project_name,
|
|
117
|
+
spans=spans,
|
|
118
|
+
feedback_scores=feedback_scores,
|
|
119
|
+
model=model,
|
|
120
|
+
provider=provider,
|
|
121
|
+
error_info=error_info,
|
|
122
|
+
total_cost=total_cost,
|
|
123
|
+
last_updated_at=last_updated_at,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def create_feedback_score_model(
|
|
127
|
+
self,
|
|
128
|
+
score_id: str,
|
|
129
|
+
name: str,
|
|
130
|
+
value: float,
|
|
131
|
+
category_name: Optional[str],
|
|
132
|
+
reason: Optional[str],
|
|
133
|
+
) -> models.FeedbackScoreModel:
|
|
134
|
+
return models.FeedbackScoreModel(
|
|
135
|
+
id=score_id,
|
|
136
|
+
name=name,
|
|
137
|
+
value=value,
|
|
138
|
+
category_name=category_name,
|
|
139
|
+
reason=reason,
|
|
140
|
+
)
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from typing import List, Any, Optional, Dict
|
|
2
|
+
|
|
3
|
+
from opik.config import OPIK_PROJECT_DEFAULT_NAME
|
|
4
|
+
from opik.types import ErrorInfoDict
|
|
5
|
+
|
|
6
|
+
import dataclasses
|
|
7
|
+
import datetime
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclasses.dataclass
|
|
11
|
+
class FeedbackScoreModel:
|
|
12
|
+
"""
|
|
13
|
+
Represents a model for a feedback score used to evaluate specific spans or traces.
|
|
14
|
+
|
|
15
|
+
This class stores and manages feedback scores linked to defined criteria, including
|
|
16
|
+
identifiers, names, values, categories, and explanations for each score.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
id: Unique identifier for the feedback score.
|
|
20
|
+
name: Name associated with the feedback score.
|
|
21
|
+
value: The numerical value of the feedback score.
|
|
22
|
+
category_name: Category to which the feedback score belongs, if any.
|
|
23
|
+
reason: Reason or explanation for the feedback score, if available.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
id: str
|
|
27
|
+
name: str
|
|
28
|
+
value: float
|
|
29
|
+
category_name: Optional[str] = None
|
|
30
|
+
reason: Optional[str] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclasses.dataclass
|
|
34
|
+
class SpanModel:
|
|
35
|
+
"""
|
|
36
|
+
Represents a span model used to describe specific points in a process, their metadata,
|
|
37
|
+
and associated data.
|
|
38
|
+
|
|
39
|
+
This class is used to store and manipulate structured data for events or
|
|
40
|
+
spans, including metadata, time markers, associated input/output, tags,
|
|
41
|
+
and additional properties. It serves as a representative structure for recording
|
|
42
|
+
and organizing event-specific information, often used in applications like
|
|
43
|
+
logging, distributed tracing, or data processing pipelines.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
id: Unique identifier for the span.
|
|
47
|
+
start_time: Start time of the span.
|
|
48
|
+
name: Name of the span, if provided.
|
|
49
|
+
input: Input data associated with the span, if any.
|
|
50
|
+
output: Output data associated with the span, if any.
|
|
51
|
+
tags: List of tags linked to the span.
|
|
52
|
+
metadata: Additional metadata for the span.
|
|
53
|
+
type: Type of the span, defaulting to "general".
|
|
54
|
+
usage: Usage-related information for the span.
|
|
55
|
+
end_time: End time of the span, if available.
|
|
56
|
+
project_name: Name of the project the span is associated with,
|
|
57
|
+
defaulting to a predefined project name.
|
|
58
|
+
spans: List of nested spans related to this span.
|
|
59
|
+
feedback_scores: List of feedback scores associated
|
|
60
|
+
with the span.
|
|
61
|
+
model: Model identification used, if applicable.
|
|
62
|
+
provider: Provider of the span or associated services, if any.
|
|
63
|
+
error_info: Error information or diagnostics
|
|
64
|
+
for the span, if applicable.
|
|
65
|
+
total_cost: Total cost incurred associated with this span,
|
|
66
|
+
if relevant.
|
|
67
|
+
last_updated_at: Timestamp of when the span was
|
|
68
|
+
last updated, if available.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
id: str
|
|
72
|
+
start_time: datetime.datetime
|
|
73
|
+
name: Optional[str] = None
|
|
74
|
+
input: Optional[Dict[str, Any]] = None
|
|
75
|
+
output: Optional[Dict[str, Any]] = None
|
|
76
|
+
tags: Optional[List[str]] = None
|
|
77
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
78
|
+
type: str = "general"
|
|
79
|
+
usage: Optional[Dict[str, Any]] = None
|
|
80
|
+
end_time: Optional[datetime.datetime] = None
|
|
81
|
+
project_name: str = OPIK_PROJECT_DEFAULT_NAME
|
|
82
|
+
spans: List["SpanModel"] = dataclasses.field(default_factory=list)
|
|
83
|
+
feedback_scores: List[FeedbackScoreModel] = dataclasses.field(default_factory=list)
|
|
84
|
+
model: Optional[str] = None
|
|
85
|
+
provider: Optional[str] = None
|
|
86
|
+
error_info: Optional[ErrorInfoDict] = None
|
|
87
|
+
total_cost: Optional[float] = None
|
|
88
|
+
last_updated_at: Optional[datetime.datetime] = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclasses.dataclass
|
|
92
|
+
class ExperimentItemModel:
|
|
93
|
+
"""
|
|
94
|
+
Represents an experiment item model that links a trace to a dataset item in an experiment.
|
|
95
|
+
|
|
96
|
+
Attributes:
|
|
97
|
+
id: Unique identifier for the experiment item.
|
|
98
|
+
experiment_id: The ID of the experiment this item belongs to.
|
|
99
|
+
trace_id: The ID of the trace associated with this experiment item.
|
|
100
|
+
dataset_item_id: The ID of the dataset item associated with this experiment item.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
id: str
|
|
104
|
+
experiment_id: str
|
|
105
|
+
trace_id: str
|
|
106
|
+
dataset_item_id: str
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclasses.dataclass
|
|
110
|
+
class TraceModel:
|
|
111
|
+
"""
|
|
112
|
+
Represents a trace model that encapsulates data about a trace, its related metadata,
|
|
113
|
+
and associated spans. It is used for tracking and analyzing data during execution
|
|
114
|
+
or processing tasks.
|
|
115
|
+
|
|
116
|
+
This class provides a structure to represent trace information, including the start
|
|
117
|
+
and end times, associated project details, input/output data, feedback scores, error
|
|
118
|
+
information, and thread association. It is designed to handle optional fields for
|
|
119
|
+
flexible use across various scenarios.
|
|
120
|
+
|
|
121
|
+
Attributes:
|
|
122
|
+
id: Unique identifier for the trace.
|
|
123
|
+
start_time: Timestamp representing the start of the trace.
|
|
124
|
+
name: Optional name for the trace, which can provide a descriptive
|
|
125
|
+
label.
|
|
126
|
+
project_name: Name of the project associated with the trace.
|
|
127
|
+
input: Optional dictionary containing the input data
|
|
128
|
+
associated with the trace.
|
|
129
|
+
output: Optional dictionary containing the output data
|
|
130
|
+
generated by the trace.
|
|
131
|
+
tags: Optional list of tags associated with the trace for
|
|
132
|
+
classification or filtering purposes.
|
|
133
|
+
metadata: Optional metadata providing additional
|
|
134
|
+
information about the trace.
|
|
135
|
+
end_time: Timestamp representing the end of the
|
|
136
|
+
trace.
|
|
137
|
+
spans: List of spans associated with the trace, representing
|
|
138
|
+
individual processing parts or segments within the trace.
|
|
139
|
+
feedback_scores: List of feedback scores associated
|
|
140
|
+
with the trace.
|
|
141
|
+
error_info: Optional dictionary containing information
|
|
142
|
+
about errors encountered during the trace.
|
|
143
|
+
thread_id: Optional identifier of the thread associated with the
|
|
144
|
+
trace.
|
|
145
|
+
last_updated_at: Timestamp for when the trace was
|
|
146
|
+
last updated.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
id: str
|
|
150
|
+
start_time: datetime.datetime
|
|
151
|
+
name: Optional[str]
|
|
152
|
+
project_name: str
|
|
153
|
+
input: Optional[Dict[str, Any]] = None
|
|
154
|
+
output: Optional[Dict[str, Any]] = None
|
|
155
|
+
tags: Optional[List[str]] = None
|
|
156
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
157
|
+
end_time: Optional[datetime.datetime] = None
|
|
158
|
+
spans: List[SpanModel] = dataclasses.field(default_factory=list)
|
|
159
|
+
feedback_scores: List[FeedbackScoreModel] = dataclasses.field(default_factory=list)
|
|
160
|
+
error_info: Optional[ErrorInfoDict] = None
|
|
161
|
+
thread_id: Optional[str] = None
|
|
162
|
+
last_updated_at: Optional[datetime.datetime] = None
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from typing import Dict, Any, Set, List, Literal
|
|
2
|
+
|
|
3
|
+
import opik.hooks
|
|
4
|
+
|
|
5
|
+
from .. import jsonable_encoder
|
|
6
|
+
from ..anonymizer import anonymizer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def encode_and_anonymize(
|
|
10
|
+
kwargs_dict: Dict[str, Any],
|
|
11
|
+
fields_to_anonymize: Set[str],
|
|
12
|
+
object_type: Literal["span", "trace"],
|
|
13
|
+
) -> Dict[str, Any]:
|
|
14
|
+
"""
|
|
15
|
+
Encodes and anonymizes the data in the given dictionary based on the specified
|
|
16
|
+
fields using registered anonymizers. If no anonymizers are registered, the
|
|
17
|
+
function simply encodes the dictionary without anonymization.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
kwargs_dict: The dictionary containing the data to encode
|
|
21
|
+
and anonymize.
|
|
22
|
+
fields_to_anonymize: The set of fields within the dictionary to
|
|
23
|
+
anonymize.
|
|
24
|
+
object_type: A string indicating the type of object ('span' or 'trace')
|
|
25
|
+
that was used to create the kwargs_dict. This is passed to anonymizers
|
|
26
|
+
to provide context about the source object.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
A dictionary that has been encoded and, if applicable, anonymized.
|
|
30
|
+
"""
|
|
31
|
+
# check if any anonymizer was registered
|
|
32
|
+
encoded_obj = jsonable_encoder.encode(kwargs_dict)
|
|
33
|
+
if not opik.hooks.has_anonymizers():
|
|
34
|
+
return encoded_obj
|
|
35
|
+
|
|
36
|
+
anonymizers = opik.hooks.get_anonymizers()
|
|
37
|
+
return anonymize_encoded_obj(
|
|
38
|
+
obj=encoded_obj,
|
|
39
|
+
fields_to_anonymize=fields_to_anonymize,
|
|
40
|
+
anonymizers=anonymizers,
|
|
41
|
+
object_type=object_type,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def anonymize_encoded_obj(
|
|
46
|
+
obj: Dict[str, Any],
|
|
47
|
+
fields_to_anonymize: Set[str],
|
|
48
|
+
anonymizers: List[anonymizer.Anonymizer],
|
|
49
|
+
object_type: Literal["span", "trace"],
|
|
50
|
+
) -> Dict[str, Any]:
|
|
51
|
+
"""
|
|
52
|
+
Anonymizes specified fields in an encoded dictionary using the provided anonymizers.
|
|
53
|
+
This function iterates over the given set of field names and applies each anonymizer
|
|
54
|
+
to the corresponding field in the dictionary, if present. The anonymizers are expected
|
|
55
|
+
to implement an `anonymize` method that takes the field value, field name, and object type
|
|
56
|
+
as arguments. Only fields present in the dictionary and listed in `fields_to_anonymize`
|
|
57
|
+
are anonymized.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
obj: The encoded dictionary whose fields are to be anonymized.
|
|
61
|
+
fields_to_anonymize: A set of field names within the dictionary to anonymize.
|
|
62
|
+
anonymizers: A list of anonymizer instances to apply to each field.
|
|
63
|
+
object_type: A string indicating the type of object ('span' or 'trace'),
|
|
64
|
+
providing context for anonymization.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
The dictionary with specified fields anonymized using the provided anonymizers.
|
|
68
|
+
"""
|
|
69
|
+
if isinstance(obj, dict):
|
|
70
|
+
for field_name in fields_to_anonymize:
|
|
71
|
+
if field_name in obj:
|
|
72
|
+
for anonymizer_instance in anonymizers:
|
|
73
|
+
obj[field_name] = anonymizer_instance.anonymize(
|
|
74
|
+
obj[field_name],
|
|
75
|
+
field_name=field_name,
|
|
76
|
+
object_type=object_type,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return obj
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import datetime
|
|
3
3
|
from dataclasses import field
|
|
4
|
-
from typing import Optional, Any, Dict, List, Union, Literal
|
|
4
|
+
from typing import Optional, Any, Dict, List, Union, Literal, Set
|
|
5
5
|
|
|
6
6
|
from . import arguments_utils
|
|
7
|
+
from .preprocessing import constants
|
|
7
8
|
from ..rest_api.types import span_write, trace_write
|
|
8
9
|
from ..types import SpanType, ErrorInfoDict, LLMProvider, AttachmentEntityType
|
|
9
10
|
|
|
@@ -11,6 +12,7 @@ from ..types import SpanType, ErrorInfoDict, LLMProvider, AttachmentEntityType
|
|
|
11
12
|
@dataclasses.dataclass
|
|
12
13
|
class BaseMessage:
|
|
13
14
|
delivery_time: float = field(init=False, default=0.0)
|
|
15
|
+
delivery_attempts: int = field(init=False, default=1)
|
|
14
16
|
|
|
15
17
|
def as_payload_dict(self) -> Dict[str, Any]:
|
|
16
18
|
# we are not using dataclasses.as_dict() here
|
|
@@ -18,6 +20,10 @@ class BaseMessage:
|
|
|
18
20
|
data = {**self.__dict__}
|
|
19
21
|
if "delivery_time" in data:
|
|
20
22
|
data.pop("delivery_time")
|
|
23
|
+
if "delivery_attempts" in data:
|
|
24
|
+
data.pop("delivery_attempts")
|
|
25
|
+
if constants.MARKER_ATTRIBUTE_NAME in data:
|
|
26
|
+
data.pop(constants.MARKER_ATTRIBUTE_NAME)
|
|
21
27
|
return data
|
|
22
28
|
|
|
23
29
|
|
|
@@ -47,6 +53,10 @@ class CreateTraceMessage(BaseMessage):
|
|
|
47
53
|
data["id"] = data.pop("trace_id")
|
|
48
54
|
return data
|
|
49
55
|
|
|
56
|
+
@staticmethod
|
|
57
|
+
def fields_to_anonymize() -> Set[str]:
|
|
58
|
+
return {"input", "output", "metadata"}
|
|
59
|
+
|
|
50
60
|
|
|
51
61
|
@dataclasses.dataclass
|
|
52
62
|
class UpdateTraceMessage(BaseMessage):
|
|
@@ -75,6 +85,10 @@ class UpdateTraceMessage(BaseMessage):
|
|
|
75
85
|
data["id"] = data.pop("trace_id")
|
|
76
86
|
return data
|
|
77
87
|
|
|
88
|
+
@staticmethod
|
|
89
|
+
def fields_to_anonymize() -> Set[str]:
|
|
90
|
+
return {"input", "output", "metadata"}
|
|
91
|
+
|
|
78
92
|
|
|
79
93
|
@dataclasses.dataclass
|
|
80
94
|
class CreateSpanMessage(BaseMessage):
|
|
@@ -109,6 +123,10 @@ class CreateSpanMessage(BaseMessage):
|
|
|
109
123
|
data["total_estimated_cost"] = data.pop("total_cost")
|
|
110
124
|
return data
|
|
111
125
|
|
|
126
|
+
@staticmethod
|
|
127
|
+
def fields_to_anonymize() -> Set[str]:
|
|
128
|
+
return {"input", "output", "metadata"}
|
|
129
|
+
|
|
112
130
|
|
|
113
131
|
@dataclasses.dataclass
|
|
114
132
|
class UpdateSpanMessage(BaseMessage):
|
|
@@ -141,6 +159,10 @@ class UpdateSpanMessage(BaseMessage):
|
|
|
141
159
|
data["total_estimated_cost"] = data.pop("total_cost")
|
|
142
160
|
return data
|
|
143
161
|
|
|
162
|
+
@staticmethod
|
|
163
|
+
def fields_to_anonymize() -> Set[str]:
|
|
164
|
+
return {"input", "output", "metadata"}
|
|
165
|
+
|
|
144
166
|
|
|
145
167
|
@dataclasses.dataclass
|
|
146
168
|
class FeedbackScoreMessage(BaseMessage):
|
|
@@ -197,11 +219,19 @@ class AddThreadsFeedbackScoresBatchMessage(BaseMessage):
|
|
|
197
219
|
class CreateSpansBatchMessage(BaseMessage):
|
|
198
220
|
batch: List[span_write.SpanWrite]
|
|
199
221
|
|
|
222
|
+
@staticmethod
|
|
223
|
+
def fields_to_anonymize() -> Set[str]:
|
|
224
|
+
return {"input", "output", "metadata"}
|
|
225
|
+
|
|
200
226
|
|
|
201
227
|
@dataclasses.dataclass
|
|
202
228
|
class CreateTraceBatchMessage(BaseMessage):
|
|
203
229
|
batch: List[trace_write.TraceWrite]
|
|
204
230
|
|
|
231
|
+
@staticmethod
|
|
232
|
+
def fields_to_anonymize() -> Set[str]:
|
|
233
|
+
return {"input", "output", "metadata"}
|
|
234
|
+
|
|
205
235
|
|
|
206
236
|
@dataclasses.dataclass
|
|
207
237
|
class GuardrailBatchItemMessage(BaseMessage):
|
|
@@ -230,6 +260,25 @@ class GuardrailBatchMessage(BaseMessage):
|
|
|
230
260
|
return data
|
|
231
261
|
|
|
232
262
|
|
|
263
|
+
@dataclasses.dataclass
|
|
264
|
+
class ExperimentItemMessage(BaseMessage):
|
|
265
|
+
"""
|
|
266
|
+
There is no handler for that in the message processor, it exists
|
|
267
|
+
only as an item of CreateExperimentItemsBatchMessage
|
|
268
|
+
"""
|
|
269
|
+
|
|
270
|
+
id: str
|
|
271
|
+
experiment_id: str
|
|
272
|
+
trace_id: str
|
|
273
|
+
dataset_item_id: str
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@dataclasses.dataclass
|
|
277
|
+
class CreateExperimentItemsBatchMessage(BaseMessage):
|
|
278
|
+
batch: List[ExperimentItemMessage]
|
|
279
|
+
supports_batching: bool = True
|
|
280
|
+
|
|
281
|
+
|
|
233
282
|
@dataclasses.dataclass
|
|
234
283
|
class CreateAttachmentMessage(BaseMessage):
|
|
235
284
|
file_path: str
|
|
@@ -239,3 +288,9 @@ class CreateAttachmentMessage(BaseMessage):
|
|
|
239
288
|
entity_id: str
|
|
240
289
|
project_name: str
|
|
241
290
|
encoded_url_override: str
|
|
291
|
+
delete_after_upload: bool = False
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
@dataclasses.dataclass
|
|
295
|
+
class AttachmentSupportingMessage(BaseMessage):
|
|
296
|
+
original_message: BaseMessage
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import Optional, Union
|
|
2
|
+
|
|
3
|
+
from opik.message_processing import messages
|
|
4
|
+
|
|
5
|
+
from . import constants, preprocessor
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AttachmentsPreprocessor(preprocessor.MessagePreprocessor):
|
|
9
|
+
def __init__(self, enabled: bool = True) -> None:
|
|
10
|
+
self._enabled = enabled
|
|
11
|
+
|
|
12
|
+
def preprocess(
|
|
13
|
+
self, message: Optional[messages.BaseMessage]
|
|
14
|
+
) -> Optional[messages.BaseMessage]:
|
|
15
|
+
"""
|
|
16
|
+
Processes a given message and ensures that it is converted into a specialized
|
|
17
|
+
message type if applicable. If the message is already pre-processed, it
|
|
18
|
+
returns the original message to avoid infinite recursion.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
message: The message object to be processed.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
The processed message, either in its original form
|
|
25
|
+
or converted into a message type supporting embedded attachments.
|
|
26
|
+
"""
|
|
27
|
+
if not self._enabled:
|
|
28
|
+
return message
|
|
29
|
+
|
|
30
|
+
if message is None:
|
|
31
|
+
# possibly already pre-processed by other preprocessors
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
if hasattr(message, constants.MARKER_ATTRIBUTE_NAME):
|
|
35
|
+
# already pre-processed - just return the original message to avoid infinite recursion
|
|
36
|
+
return message
|
|
37
|
+
|
|
38
|
+
if _has_potential_content_with_attachments(message):
|
|
39
|
+
return messages.AttachmentSupportingMessage(message)
|
|
40
|
+
else:
|
|
41
|
+
return message
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _has_potential_content_with_attachments(message: messages.BaseMessage) -> bool:
|
|
45
|
+
# Check if it's an Update message - always process these
|
|
46
|
+
if isinstance(message, (messages.UpdateSpanMessage, messages.UpdateTraceMessage)):
|
|
47
|
+
return _message_has_field_of_interest_set(message)
|
|
48
|
+
|
|
49
|
+
# Check if it's a Create message with end_time set - only process these
|
|
50
|
+
if isinstance(message, (messages.CreateSpanMessage, messages.CreateTraceMessage)):
|
|
51
|
+
if message.end_time is not None:
|
|
52
|
+
return _message_has_field_of_interest_set(message)
|
|
53
|
+
|
|
54
|
+
# All other message types should not be wrapped
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _message_has_field_of_interest_set(
|
|
59
|
+
message: Union[
|
|
60
|
+
messages.UpdateSpanMessage,
|
|
61
|
+
messages.UpdateTraceMessage,
|
|
62
|
+
messages.CreateSpanMessage,
|
|
63
|
+
messages.CreateTraceMessage,
|
|
64
|
+
],
|
|
65
|
+
) -> bool:
|
|
66
|
+
return (
|
|
67
|
+
message.input is not None
|
|
68
|
+
or message.output is not None
|
|
69
|
+
or message.metadata is not None
|
|
70
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from . import preprocessor
|
|
4
|
+
from .. import messages
|
|
5
|
+
from ..batching import batch_manager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BatchingPreprocessor(preprocessor.MessagePreprocessor):
|
|
9
|
+
"""
|
|
10
|
+
Handles message batching during preprocessing.
|
|
11
|
+
|
|
12
|
+
The BatchingPreprocessor class processes messages, enabling efficient message
|
|
13
|
+
batching if a batching manager is provided. It supports starting, stopping,
|
|
14
|
+
flushing, and checking the state of the batching manager, ensuring that
|
|
15
|
+
messages are processed or delegated based on their batching capabilities.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, batching_manager: Optional[batch_manager.BatchManager]) -> None:
|
|
19
|
+
self._batch_manager = batching_manager
|
|
20
|
+
|
|
21
|
+
def preprocess(
|
|
22
|
+
self, message: Optional[messages.BaseMessage]
|
|
23
|
+
) -> Optional[messages.BaseMessage]:
|
|
24
|
+
if message is None:
|
|
25
|
+
# possibly already processed
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
self._batch_manager is not None
|
|
30
|
+
and self._batch_manager.message_supports_batching(message)
|
|
31
|
+
):
|
|
32
|
+
self._batch_manager.process_message(message)
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
return message
|
|
36
|
+
|
|
37
|
+
def start(self) -> None:
|
|
38
|
+
if self._batch_manager is not None:
|
|
39
|
+
self._batch_manager.start()
|
|
40
|
+
|
|
41
|
+
def stop(self) -> None:
|
|
42
|
+
if self._batch_manager is not None:
|
|
43
|
+
self._batch_manager.stop()
|
|
44
|
+
|
|
45
|
+
def flush(self) -> None:
|
|
46
|
+
if self._batch_manager is not None:
|
|
47
|
+
self._batch_manager.flush()
|
|
48
|
+
|
|
49
|
+
def is_empty(self) -> bool:
|
|
50
|
+
if self._batch_manager is not None:
|
|
51
|
+
return self._batch_manager.is_empty()
|
|
52
|
+
|
|
53
|
+
return True
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MARKER_ATTRIBUTE_NAME = "_preprocessed_for_attachments"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from opik.file_upload import base_upload_manager
|
|
4
|
+
|
|
5
|
+
from . import preprocessor
|
|
6
|
+
from .. import messages
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FileUploadPreprocessor(preprocessor.MessagePreprocessor):
|
|
10
|
+
"""
|
|
11
|
+
Preprocesses messages to handle file uploads.
|
|
12
|
+
|
|
13
|
+
This class is responsible for processing messages to determine if they support
|
|
14
|
+
file uploads and delegating the upload task to a file upload manager. It also
|
|
15
|
+
provides functionality to flush pending uploads with configurable timeout and
|
|
16
|
+
sleep intervals.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self, file_upload_manager: base_upload_manager.BaseFileUploadManager
|
|
21
|
+
) -> None:
|
|
22
|
+
self._file_upload_manager = file_upload_manager
|
|
23
|
+
|
|
24
|
+
def preprocess(
|
|
25
|
+
self, message: Optional[messages.BaseMessage]
|
|
26
|
+
) -> Optional[messages.BaseMessage]:
|
|
27
|
+
if message is None:
|
|
28
|
+
# possibly already processed
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
if base_upload_manager.message_supports_upload(message):
|
|
32
|
+
self._file_upload_manager.upload(message)
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
return message
|
|
36
|
+
|
|
37
|
+
def flush(self, timeout: Optional[float], sleep_time: int) -> bool:
|
|
38
|
+
return self._file_upload_manager.flush(timeout=timeout, sleep_time=sleep_time)
|