arize-phoenix 3.16.0__py3-none-any.whl → 7.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arize-phoenix might be problematic. Click here for more details.
- arize_phoenix-7.7.0.dist-info/METADATA +261 -0
- arize_phoenix-7.7.0.dist-info/RECORD +345 -0
- {arize_phoenix-3.16.0.dist-info → arize_phoenix-7.7.0.dist-info}/WHEEL +1 -1
- arize_phoenix-7.7.0.dist-info/entry_points.txt +3 -0
- phoenix/__init__.py +86 -14
- phoenix/auth.py +309 -0
- phoenix/config.py +675 -45
- phoenix/core/model.py +32 -30
- phoenix/core/model_schema.py +102 -109
- phoenix/core/model_schema_adapter.py +48 -45
- phoenix/datetime_utils.py +24 -3
- phoenix/db/README.md +54 -0
- phoenix/db/__init__.py +4 -0
- phoenix/db/alembic.ini +85 -0
- phoenix/db/bulk_inserter.py +294 -0
- phoenix/db/engines.py +208 -0
- phoenix/db/enums.py +20 -0
- phoenix/db/facilitator.py +113 -0
- phoenix/db/helpers.py +159 -0
- phoenix/db/insertion/constants.py +2 -0
- phoenix/db/insertion/dataset.py +227 -0
- phoenix/db/insertion/document_annotation.py +171 -0
- phoenix/db/insertion/evaluation.py +191 -0
- phoenix/db/insertion/helpers.py +98 -0
- phoenix/db/insertion/span.py +193 -0
- phoenix/db/insertion/span_annotation.py +158 -0
- phoenix/db/insertion/trace_annotation.py +158 -0
- phoenix/db/insertion/types.py +256 -0
- phoenix/db/migrate.py +86 -0
- phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
- phoenix/db/migrations/env.py +114 -0
- phoenix/db/migrations/script.py.mako +26 -0
- phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
- phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
- phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
- phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
- phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
- phoenix/db/models.py +807 -0
- phoenix/exceptions.py +5 -1
- phoenix/experiments/__init__.py +6 -0
- phoenix/experiments/evaluators/__init__.py +29 -0
- phoenix/experiments/evaluators/base.py +158 -0
- phoenix/experiments/evaluators/code_evaluators.py +184 -0
- phoenix/experiments/evaluators/llm_evaluators.py +473 -0
- phoenix/experiments/evaluators/utils.py +236 -0
- phoenix/experiments/functions.py +772 -0
- phoenix/experiments/tracing.py +86 -0
- phoenix/experiments/types.py +726 -0
- phoenix/experiments/utils.py +25 -0
- phoenix/inferences/__init__.py +0 -0
- phoenix/{datasets → inferences}/errors.py +6 -5
- phoenix/{datasets → inferences}/fixtures.py +49 -42
- phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
- phoenix/{datasets → inferences}/schema.py +11 -11
- phoenix/{datasets → inferences}/validation.py +13 -14
- phoenix/logging/__init__.py +3 -0
- phoenix/logging/_config.py +90 -0
- phoenix/logging/_filter.py +6 -0
- phoenix/logging/_formatter.py +69 -0
- phoenix/metrics/__init__.py +5 -4
- phoenix/metrics/binning.py +4 -3
- phoenix/metrics/metrics.py +2 -1
- phoenix/metrics/mixins.py +7 -6
- phoenix/metrics/retrieval_metrics.py +2 -1
- phoenix/metrics/timeseries.py +5 -4
- phoenix/metrics/wrappers.py +9 -3
- phoenix/pointcloud/clustering.py +5 -5
- phoenix/pointcloud/pointcloud.py +7 -5
- phoenix/pointcloud/projectors.py +5 -6
- phoenix/pointcloud/umap_parameters.py +53 -52
- phoenix/server/api/README.md +28 -0
- phoenix/server/api/auth.py +44 -0
- phoenix/server/api/context.py +152 -9
- phoenix/server/api/dataloaders/__init__.py +91 -0
- phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
- phoenix/server/api/dataloaders/cache/__init__.py +3 -0
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
- phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
- phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
- phoenix/server/api/dataloaders/document_evaluations.py +31 -0
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
- phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
- phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
- phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
- phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
- phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
- phoenix/server/api/dataloaders/project_by_name.py +31 -0
- phoenix/server/api/dataloaders/record_counts.py +116 -0
- phoenix/server/api/dataloaders/session_io.py +79 -0
- phoenix/server/api/dataloaders/session_num_traces.py +30 -0
- phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
- phoenix/server/api/dataloaders/session_token_usages.py +41 -0
- phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
- phoenix/server/api/dataloaders/span_annotations.py +26 -0
- phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
- phoenix/server/api/dataloaders/span_descendants.py +57 -0
- phoenix/server/api/dataloaders/span_projects.py +33 -0
- phoenix/server/api/dataloaders/token_counts.py +124 -0
- phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
- phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
- phoenix/server/api/dataloaders/user_roles.py +30 -0
- phoenix/server/api/dataloaders/users.py +33 -0
- phoenix/server/api/exceptions.py +48 -0
- phoenix/server/api/helpers/__init__.py +12 -0
- phoenix/server/api/helpers/dataset_helpers.py +217 -0
- phoenix/server/api/helpers/experiment_run_filters.py +763 -0
- phoenix/server/api/helpers/playground_clients.py +948 -0
- phoenix/server/api/helpers/playground_registry.py +70 -0
- phoenix/server/api/helpers/playground_spans.py +455 -0
- phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
- phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
- phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
- phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
- phoenix/server/api/input_types/ClearProjectInput.py +15 -0
- phoenix/server/api/input_types/ClusterInput.py +2 -2
- phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
- phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
- phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
- phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
- phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
- phoenix/server/api/input_types/DatasetSort.py +17 -0
- phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
- phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
- phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
- phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
- phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
- phoenix/server/api/input_types/DimensionFilter.py +4 -4
- phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
- phoenix/server/api/input_types/Granularity.py +1 -1
- phoenix/server/api/input_types/InvocationParameters.py +162 -0
- phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
- phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
- phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
- phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
- phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
- phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
- phoenix/server/api/input_types/SpanSort.py +134 -69
- phoenix/server/api/input_types/TemplateOptions.py +10 -0
- phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
- phoenix/server/api/input_types/UserRoleInput.py +9 -0
- phoenix/server/api/mutations/__init__.py +28 -0
- phoenix/server/api/mutations/api_key_mutations.py +167 -0
- phoenix/server/api/mutations/chat_mutations.py +593 -0
- phoenix/server/api/mutations/dataset_mutations.py +591 -0
- phoenix/server/api/mutations/experiment_mutations.py +75 -0
- phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
- phoenix/server/api/mutations/project_mutations.py +57 -0
- phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
- phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
- phoenix/server/api/mutations/user_mutations.py +329 -0
- phoenix/server/api/openapi/__init__.py +0 -0
- phoenix/server/api/openapi/main.py +17 -0
- phoenix/server/api/openapi/schema.py +16 -0
- phoenix/server/api/queries.py +738 -0
- phoenix/server/api/routers/__init__.py +11 -0
- phoenix/server/api/routers/auth.py +284 -0
- phoenix/server/api/routers/embeddings.py +26 -0
- phoenix/server/api/routers/oauth2.py +488 -0
- phoenix/server/api/routers/v1/__init__.py +64 -0
- phoenix/server/api/routers/v1/datasets.py +1017 -0
- phoenix/server/api/routers/v1/evaluations.py +362 -0
- phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
- phoenix/server/api/routers/v1/experiment_runs.py +167 -0
- phoenix/server/api/routers/v1/experiments.py +308 -0
- phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
- phoenix/server/api/routers/v1/spans.py +267 -0
- phoenix/server/api/routers/v1/traces.py +208 -0
- phoenix/server/api/routers/v1/utils.py +95 -0
- phoenix/server/api/schema.py +44 -247
- phoenix/server/api/subscriptions.py +597 -0
- phoenix/server/api/types/Annotation.py +21 -0
- phoenix/server/api/types/AnnotationSummary.py +55 -0
- phoenix/server/api/types/AnnotatorKind.py +16 -0
- phoenix/server/api/types/ApiKey.py +27 -0
- phoenix/server/api/types/AuthMethod.py +9 -0
- phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
- phoenix/server/api/types/Cluster.py +25 -24
- phoenix/server/api/types/CreateDatasetPayload.py +8 -0
- phoenix/server/api/types/DataQualityMetric.py +31 -13
- phoenix/server/api/types/Dataset.py +288 -63
- phoenix/server/api/types/DatasetExample.py +85 -0
- phoenix/server/api/types/DatasetExampleRevision.py +34 -0
- phoenix/server/api/types/DatasetVersion.py +14 -0
- phoenix/server/api/types/Dimension.py +32 -31
- phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
- phoenix/server/api/types/EmbeddingDimension.py +56 -49
- phoenix/server/api/types/Evaluation.py +25 -31
- phoenix/server/api/types/EvaluationSummary.py +30 -50
- phoenix/server/api/types/Event.py +20 -20
- phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
- phoenix/server/api/types/Experiment.py +152 -0
- phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
- phoenix/server/api/types/ExperimentComparison.py +17 -0
- phoenix/server/api/types/ExperimentRun.py +119 -0
- phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
- phoenix/server/api/types/GenerativeModel.py +9 -0
- phoenix/server/api/types/GenerativeProvider.py +85 -0
- phoenix/server/api/types/Inferences.py +80 -0
- phoenix/server/api/types/InferencesRole.py +23 -0
- phoenix/server/api/types/LabelFraction.py +7 -0
- phoenix/server/api/types/MimeType.py +2 -2
- phoenix/server/api/types/Model.py +54 -54
- phoenix/server/api/types/PerformanceMetric.py +8 -5
- phoenix/server/api/types/Project.py +407 -142
- phoenix/server/api/types/ProjectSession.py +139 -0
- phoenix/server/api/types/Segments.py +4 -4
- phoenix/server/api/types/Span.py +221 -176
- phoenix/server/api/types/SpanAnnotation.py +43 -0
- phoenix/server/api/types/SpanIOValue.py +15 -0
- phoenix/server/api/types/SystemApiKey.py +9 -0
- phoenix/server/api/types/TemplateLanguage.py +10 -0
- phoenix/server/api/types/TimeSeries.py +19 -15
- phoenix/server/api/types/TokenUsage.py +11 -0
- phoenix/server/api/types/Trace.py +154 -0
- phoenix/server/api/types/TraceAnnotation.py +45 -0
- phoenix/server/api/types/UMAPPoints.py +7 -7
- phoenix/server/api/types/User.py +60 -0
- phoenix/server/api/types/UserApiKey.py +45 -0
- phoenix/server/api/types/UserRole.py +15 -0
- phoenix/server/api/types/node.py +13 -107
- phoenix/server/api/types/pagination.py +156 -57
- phoenix/server/api/utils.py +34 -0
- phoenix/server/app.py +864 -115
- phoenix/server/bearer_auth.py +163 -0
- phoenix/server/dml_event.py +136 -0
- phoenix/server/dml_event_handler.py +256 -0
- phoenix/server/email/__init__.py +0 -0
- phoenix/server/email/sender.py +97 -0
- phoenix/server/email/templates/__init__.py +0 -0
- phoenix/server/email/templates/password_reset.html +19 -0
- phoenix/server/email/types.py +11 -0
- phoenix/server/grpc_server.py +102 -0
- phoenix/server/jwt_store.py +505 -0
- phoenix/server/main.py +305 -116
- phoenix/server/oauth2.py +52 -0
- phoenix/server/openapi/__init__.py +0 -0
- phoenix/server/prometheus.py +111 -0
- phoenix/server/rate_limiters.py +188 -0
- phoenix/server/static/.vite/manifest.json +87 -0
- phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
- phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
- phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
- phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
- phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
- phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
- phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
- phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
- phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
- phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
- phoenix/server/telemetry.py +68 -0
- phoenix/server/templates/index.html +82 -23
- phoenix/server/thread_server.py +3 -3
- phoenix/server/types.py +275 -0
- phoenix/services.py +27 -18
- phoenix/session/client.py +743 -68
- phoenix/session/data_extractor.py +31 -7
- phoenix/session/evaluation.py +3 -9
- phoenix/session/session.py +263 -219
- phoenix/settings.py +22 -0
- phoenix/trace/__init__.py +2 -22
- phoenix/trace/attributes.py +338 -0
- phoenix/trace/dsl/README.md +116 -0
- phoenix/trace/dsl/filter.py +663 -213
- phoenix/trace/dsl/helpers.py +73 -21
- phoenix/trace/dsl/query.py +574 -201
- phoenix/trace/exporter.py +24 -19
- phoenix/trace/fixtures.py +368 -32
- phoenix/trace/otel.py +71 -219
- phoenix/trace/projects.py +3 -2
- phoenix/trace/schemas.py +33 -11
- phoenix/trace/span_evaluations.py +21 -16
- phoenix/trace/span_json_decoder.py +6 -4
- phoenix/trace/span_json_encoder.py +2 -2
- phoenix/trace/trace_dataset.py +47 -32
- phoenix/trace/utils.py +21 -4
- phoenix/utilities/__init__.py +0 -26
- phoenix/utilities/client.py +132 -0
- phoenix/utilities/deprecation.py +31 -0
- phoenix/utilities/error_handling.py +3 -2
- phoenix/utilities/json.py +109 -0
- phoenix/utilities/logging.py +8 -0
- phoenix/utilities/project.py +2 -2
- phoenix/utilities/re.py +49 -0
- phoenix/utilities/span_store.py +0 -23
- phoenix/utilities/template_formatters.py +99 -0
- phoenix/version.py +1 -1
- arize_phoenix-3.16.0.dist-info/METADATA +0 -495
- arize_phoenix-3.16.0.dist-info/RECORD +0 -178
- phoenix/core/project.py +0 -617
- phoenix/core/traces.py +0 -100
- phoenix/experimental/evals/__init__.py +0 -73
- phoenix/experimental/evals/evaluators.py +0 -413
- phoenix/experimental/evals/functions/__init__.py +0 -4
- phoenix/experimental/evals/functions/classify.py +0 -453
- phoenix/experimental/evals/functions/executor.py +0 -353
- phoenix/experimental/evals/functions/generate.py +0 -138
- phoenix/experimental/evals/functions/processing.py +0 -76
- phoenix/experimental/evals/models/__init__.py +0 -14
- phoenix/experimental/evals/models/anthropic.py +0 -175
- phoenix/experimental/evals/models/base.py +0 -170
- phoenix/experimental/evals/models/bedrock.py +0 -221
- phoenix/experimental/evals/models/litellm.py +0 -134
- phoenix/experimental/evals/models/openai.py +0 -448
- phoenix/experimental/evals/models/rate_limiters.py +0 -246
- phoenix/experimental/evals/models/vertex.py +0 -173
- phoenix/experimental/evals/models/vertexai.py +0 -186
- phoenix/experimental/evals/retrievals.py +0 -96
- phoenix/experimental/evals/templates/__init__.py +0 -50
- phoenix/experimental/evals/templates/default_templates.py +0 -472
- phoenix/experimental/evals/templates/template.py +0 -195
- phoenix/experimental/evals/utils/__init__.py +0 -172
- phoenix/experimental/evals/utils/threads.py +0 -27
- phoenix/server/api/helpers.py +0 -11
- phoenix/server/api/routers/evaluation_handler.py +0 -109
- phoenix/server/api/routers/span_handler.py +0 -70
- phoenix/server/api/routers/trace_handler.py +0 -60
- phoenix/server/api/types/DatasetRole.py +0 -23
- phoenix/server/static/index.css +0 -6
- phoenix/server/static/index.js +0 -7447
- phoenix/storage/span_store/__init__.py +0 -23
- phoenix/storage/span_store/text_file.py +0 -85
- phoenix/trace/dsl/missing.py +0 -60
- phoenix/trace/langchain/__init__.py +0 -3
- phoenix/trace/langchain/instrumentor.py +0 -35
- phoenix/trace/llama_index/__init__.py +0 -3
- phoenix/trace/llama_index/callback.py +0 -102
- phoenix/trace/openai/__init__.py +0 -3
- phoenix/trace/openai/instrumentor.py +0 -30
- {arize_phoenix-3.16.0.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.16.0.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/LICENSE +0 -0
- /phoenix/{datasets → db/insertion}/__init__.py +0 -0
- /phoenix/{experimental → db/migrations}/__init__.py +0 -0
- /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from phoenix.config import (
|
|
6
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT,
|
|
7
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_HTTP_ENDPOINT,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from opentelemetry.trace import TracerProvider
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def normalize_http_collector_endpoint(endpoint: str) -> str:
|
|
17
|
+
normalized_endpoint = endpoint
|
|
18
|
+
if not normalized_endpoint.startswith("http://") and not normalized_endpoint.startswith(
|
|
19
|
+
"https://"
|
|
20
|
+
):
|
|
21
|
+
logger.warning(
|
|
22
|
+
"HTTP collector endpoint should include the protocol (http:// or https://)."
|
|
23
|
+
"Assuming http."
|
|
24
|
+
)
|
|
25
|
+
# assume http if no protocol is provided
|
|
26
|
+
normalized_endpoint = f"http://{endpoint}"
|
|
27
|
+
if normalized_endpoint.endswith("/v1/traces"):
|
|
28
|
+
logger.warning(
|
|
29
|
+
"HTTP collector endpoint should not include the /v1/traces path. Removing it."
|
|
30
|
+
)
|
|
31
|
+
# remove the /v1/traces path
|
|
32
|
+
normalized_endpoint = normalized_endpoint[: -len("/v1/traces")]
|
|
33
|
+
# remove trailing slashes
|
|
34
|
+
normalized_endpoint = normalized_endpoint.rstrip("/")
|
|
35
|
+
return normalized_endpoint
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def initialize_opentelemetry_tracer_provider() -> "TracerProvider":
|
|
39
|
+
logger.info("Initializing OpenTelemetry tracer provider")
|
|
40
|
+
from opentelemetry.sdk import trace as trace_sdk
|
|
41
|
+
from opentelemetry.sdk.resources import Resource
|
|
42
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
43
|
+
from opentelemetry.semconv.resource import ResourceAttributes
|
|
44
|
+
|
|
45
|
+
tracer_provider = trace_sdk.TracerProvider(
|
|
46
|
+
resource=Resource(attributes={ResourceAttributes.SERVICE_NAME: "arize-phoenix-server"})
|
|
47
|
+
)
|
|
48
|
+
if http_endpoint := os.getenv(
|
|
49
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_HTTP_ENDPOINT
|
|
50
|
+
):
|
|
51
|
+
logger.info(f"Using HTTP collector endpoint: {http_endpoint}")
|
|
52
|
+
http_endpoint = normalize_http_collector_endpoint(http_endpoint) + "/v1/traces"
|
|
53
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
54
|
+
OTLPSpanExporter as HttpExporter,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(HttpExporter(http_endpoint)))
|
|
58
|
+
if grpc_endpoint := os.getenv(
|
|
59
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT
|
|
60
|
+
):
|
|
61
|
+
logger.info(f"Using gRPC collector endpoint: {grpc_endpoint}")
|
|
62
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
63
|
+
OTLPSpanExporter as GrpcExporter,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(GrpcExporter(grpc_endpoint)))
|
|
67
|
+
logger.info("🔭 OpenTelemetry tracer provider initialized")
|
|
68
|
+
return tracer_provider
|
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
{%- set rendered_chunks = [] -%}
|
|
2
|
+
{%- set css_links = [] -%}
|
|
3
|
+
{%- set js_scripts = [] -%}
|
|
4
|
+
{%- macro collect_assets(chunk_name, level=0) -%}
|
|
5
|
+
{% if chunk_name not in rendered_chunks %}
|
|
6
|
+
{% set _ = rendered_chunks.append(chunk_name) %}
|
|
7
|
+
{% set chunk = manifest[chunk_name] %}
|
|
8
|
+
{% if chunk.css %}
|
|
9
|
+
{% for css_file in chunk.css %}
|
|
10
|
+
{% if css_file not in css_links %}
|
|
11
|
+
{% set _ = css_links.append((basename, css_file)) %}
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% endfor %}
|
|
14
|
+
{% endif %}
|
|
15
|
+
{% if chunk.imports %}
|
|
16
|
+
{% for import in chunk.imports %}
|
|
17
|
+
{% set _ = collect_assets(import, level + 1) %}
|
|
18
|
+
{% endfor %}
|
|
19
|
+
{% endif %}
|
|
20
|
+
{% if chunk.file.endswith('.js') %}
|
|
21
|
+
{% if chunk.file not in js_scripts %}
|
|
22
|
+
{% set _ = js_scripts.append((basename, chunk.file, level == 0)) %}
|
|
23
|
+
{% endif %}
|
|
24
|
+
{% elif chunk.file.endswith('.css') %}
|
|
25
|
+
{% if chunk.file not in css_links %}
|
|
26
|
+
{% set _ = css_links.append((basename, chunk.file)) %}
|
|
27
|
+
{% endif %}
|
|
28
|
+
{% endif %}
|
|
29
|
+
{% endif %}
|
|
30
|
+
{%- endmacro -%}
|
|
31
|
+
{%- macro render_css() -%}
|
|
32
|
+
{%- for basename, css_file in css_links -%}
|
|
33
|
+
<link rel="stylesheet" href="{{ basename }}/{{ css_file }}">
|
|
34
|
+
{% endfor -%}
|
|
35
|
+
{%- endmacro -%}
|
|
36
|
+
{%- macro render_js() -%}
|
|
37
|
+
{%- for basename, js_file, is_entry in js_scripts -%}
|
|
38
|
+
{%- if is_entry -%}
|
|
39
|
+
<script type="module" src="{{ basename }}/{{ js_file }}"></script>
|
|
40
|
+
{% else -%}
|
|
41
|
+
<link rel="modulepreload" href="{{ basename }}/{{ js_file }}">
|
|
42
|
+
{% endif -%}
|
|
43
|
+
{%- endfor -%}
|
|
44
|
+
{%- endmacro -%}
|
|
1
45
|
<!DOCTYPE html>
|
|
2
46
|
<html>
|
|
3
47
|
<head>
|
|
@@ -11,37 +55,52 @@
|
|
|
11
55
|
<meta property="og:description" content="AI Observability & Evaluation" />
|
|
12
56
|
<meta property="og:image" content="https://raw.githubusercontent.com/Arize-ai/phoenix-assets/main/images/socal/social-preview-horizontal.jpg" />
|
|
13
57
|
<meta name="theme-color" content="#ffffff" />
|
|
14
|
-
<link rel="stylesheet" src="{{basename}}/index.css"></link>
|
|
15
58
|
<link
|
|
16
59
|
rel="stylesheet"
|
|
17
60
|
href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap"
|
|
18
61
|
/>
|
|
62
|
+
{% if not is_development -%}
|
|
63
|
+
{% set _ = collect_assets('index.tsx') -%}
|
|
64
|
+
{{- render_css() -}}
|
|
65
|
+
{%- endif -%}
|
|
19
66
|
<script src="{{basename}}/modernizr.js"></script>
|
|
20
67
|
</head>
|
|
21
68
|
<body>
|
|
22
69
|
<div id="root"></div>
|
|
23
70
|
<script>(function() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
Object.defineProperty(window, "Config", {
|
|
72
|
+
// Place any server-side injected config here
|
|
73
|
+
// E.g. default UMAP parameters etc. that needs to be
|
|
74
|
+
// injected into the client before React runs
|
|
75
|
+
value: Object.freeze({
|
|
76
|
+
basename: "{{basename}}",
|
|
77
|
+
platformVersion: "{{platform_version}}",
|
|
78
|
+
hasInferences: Boolean("{{has_inferences}}" == "True"),
|
|
79
|
+
hasCorpus: Boolean("{{has_corpus}}" == "True"),
|
|
80
|
+
UMAP: {
|
|
81
|
+
minDist: parseFloat("{{min_dist}}"),
|
|
82
|
+
nNeighbors: parseInt("{{n_neighbors}}"),
|
|
83
|
+
nSamples: parseInt("{{n_samples}}"),
|
|
84
|
+
},
|
|
85
|
+
authenticationEnabled: Boolean("{{authentication_enabled}}" == "True"),
|
|
86
|
+
oAuth2Idps: {{ oauth2_idps | tojson }},
|
|
87
|
+
websocketsEnabled: Boolean("{{websockets_enabled}}" == "True"),
|
|
88
|
+
}),
|
|
89
|
+
writable: false
|
|
90
|
+
});
|
|
91
|
+
})()</script>
|
|
92
|
+
{% if is_development -%}
|
|
93
|
+
<script type="module">
|
|
94
|
+
import RefreshRuntime from 'http://localhost:5173/@react-refresh'
|
|
95
|
+
RefreshRuntime.injectIntoGlobalHook(window)
|
|
96
|
+
window.$RefreshReg$ = () => {}
|
|
97
|
+
window.$RefreshSig$ = () => (type) => type
|
|
98
|
+
window.__vite_plugin_react_preamble_installed__ = true
|
|
99
|
+
</script>
|
|
100
|
+
<script type="module" src="http://localhost:5173/@vite/client"></script>
|
|
101
|
+
<script type="module" src="http://localhost:5173/index.tsx"></script>
|
|
102
|
+
{%- else -%}
|
|
103
|
+
{{- render_js() -}}
|
|
104
|
+
{%- endif -%}
|
|
46
105
|
</body>
|
|
47
106
|
</html>
|
phoenix/server/thread_server.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
+
from collections.abc import Generator
|
|
3
4
|
from threading import Thread
|
|
4
5
|
from time import sleep, time
|
|
5
|
-
from typing import Generator
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from fastapi import FastAPI
|
|
8
8
|
from uvicorn import Config, Server
|
|
9
9
|
from uvicorn.config import LoopSetupType
|
|
10
10
|
|
|
@@ -24,7 +24,7 @@ class ThreadServer(Server):
|
|
|
24
24
|
|
|
25
25
|
def __init__(
|
|
26
26
|
self,
|
|
27
|
-
app:
|
|
27
|
+
app: FastAPI,
|
|
28
28
|
host: str,
|
|
29
29
|
port: int,
|
|
30
30
|
root_path: str,
|
phoenix/server/types.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from asyncio import Task, create_task, sleep
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
7
|
+
from contextlib import AbstractAsyncContextManager
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from typing import Any, Generic, Optional, Protocol, TypeVar, final
|
|
11
|
+
|
|
12
|
+
from cachetools import LRUCache
|
|
13
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
14
|
+
|
|
15
|
+
from phoenix.auth import CanReadToken, ClaimSet, Token, TokenAttributes
|
|
16
|
+
from phoenix.db import enums, models
|
|
17
|
+
from phoenix.db.helpers import SupportedSQLDialect
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CanSetLastUpdatedAt(Protocol):
|
|
21
|
+
def set(self, table: type[models.Base], id_: int) -> None: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CanGetLastUpdatedAt(Protocol):
|
|
25
|
+
def get(self, table: type[models.Base], id_: Optional[int] = None) -> Optional[datetime]: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class DbSessionFactory:
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
db: Callable[[], AbstractAsyncContextManager[AsyncSession]],
|
|
32
|
+
dialect: str,
|
|
33
|
+
):
|
|
34
|
+
self._db = db
|
|
35
|
+
self.dialect = SupportedSQLDialect(dialect)
|
|
36
|
+
|
|
37
|
+
def __call__(self) -> AbstractAsyncContextManager[AsyncSession]:
|
|
38
|
+
return self._db()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_AnyT = TypeVar("_AnyT")
|
|
42
|
+
_ItemT_contra = TypeVar("_ItemT_contra", contravariant=True)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class CanPutItem(Protocol[_ItemT_contra]):
|
|
46
|
+
def put(self, item: _ItemT_contra) -> None: ...
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class _Batch(CanPutItem[_AnyT], Protocol[_AnyT]):
|
|
50
|
+
@property
|
|
51
|
+
def empty(self) -> bool: ...
|
|
52
|
+
def clear(self) -> None: ...
|
|
53
|
+
def __iter__(self) -> Iterator[_AnyT]: ...
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class _HasBatch(Generic[_ItemT_contra], ABC):
|
|
57
|
+
_batch_factory: Callable[[], _Batch[_ItemT_contra]]
|
|
58
|
+
|
|
59
|
+
def __init__(self) -> None:
|
|
60
|
+
self._batch = self._batch_factory()
|
|
61
|
+
|
|
62
|
+
def put(self, item: _ItemT_contra) -> None:
|
|
63
|
+
self._batch.put(item)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class DaemonTask(ABC):
|
|
67
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
68
|
+
super().__init__(**kwargs)
|
|
69
|
+
self._running = False
|
|
70
|
+
self._tasks: list[Task[None]] = []
|
|
71
|
+
|
|
72
|
+
async def start(self) -> None:
|
|
73
|
+
self._running = True
|
|
74
|
+
if not self._tasks:
|
|
75
|
+
self._tasks.append(create_task(self._run()))
|
|
76
|
+
|
|
77
|
+
async def stop(self) -> None:
|
|
78
|
+
self._running = False
|
|
79
|
+
for task in reversed(self._tasks):
|
|
80
|
+
if not task.done():
|
|
81
|
+
task.cancel()
|
|
82
|
+
self._tasks.clear()
|
|
83
|
+
|
|
84
|
+
async def __aenter__(self) -> None:
|
|
85
|
+
await self.start()
|
|
86
|
+
|
|
87
|
+
async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
|
|
88
|
+
await self.stop()
|
|
89
|
+
|
|
90
|
+
@abstractmethod
|
|
91
|
+
async def _run(self) -> None: ...
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class BatchedCaller(DaemonTask, _HasBatch[_AnyT], Generic[_AnyT], ABC):
|
|
95
|
+
def __init__(self, *, sleep_seconds: float = 0.1, **kwargs: Any) -> None:
|
|
96
|
+
assert sleep_seconds > 0
|
|
97
|
+
super().__init__(**kwargs)
|
|
98
|
+
self._seconds = sleep_seconds
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
async def __call__(self) -> None: ...
|
|
102
|
+
|
|
103
|
+
async def _run(self) -> None:
|
|
104
|
+
while self._running:
|
|
105
|
+
self._tasks.append(create_task(sleep(self._seconds)))
|
|
106
|
+
await self._tasks[-1]
|
|
107
|
+
self._tasks.pop()
|
|
108
|
+
if self._batch.empty:
|
|
109
|
+
continue
|
|
110
|
+
self._tasks.append(create_task(self()))
|
|
111
|
+
await self._tasks[-1]
|
|
112
|
+
self._tasks.pop()
|
|
113
|
+
self._batch.clear()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class LastUpdatedAt:
|
|
117
|
+
def __init__(self) -> None:
|
|
118
|
+
self._cache: defaultdict[
|
|
119
|
+
type[models.Base],
|
|
120
|
+
LRUCache[int, datetime],
|
|
121
|
+
] = defaultdict(lambda: LRUCache(maxsize=100))
|
|
122
|
+
|
|
123
|
+
def get(self, table: type[models.Base], id_: Optional[int] = None) -> Optional[datetime]:
|
|
124
|
+
if not (cache := self._cache.get(table)):
|
|
125
|
+
return None
|
|
126
|
+
if id_ is None:
|
|
127
|
+
return max(filter(bool, cache.values()), default=None)
|
|
128
|
+
return cache.get(id_)
|
|
129
|
+
|
|
130
|
+
def set(self, table: type[models.Base], id_: int) -> None:
|
|
131
|
+
self._cache[table][id_] = datetime.now(timezone.utc)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class PasswordResetToken(Token): ...
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class AccessToken(Token): ...
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class RefreshToken(Token): ...
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class ApiKey(Token): ...
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass(frozen=True)
|
|
147
|
+
class UserTokenAttributes(TokenAttributes):
|
|
148
|
+
user_role: enums.UserRole
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass(frozen=True)
|
|
152
|
+
class RefreshTokenAttributes(UserTokenAttributes): ...
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass(frozen=True)
|
|
156
|
+
class PasswordResetTokenAttributes(UserTokenAttributes): ...
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass(frozen=True)
|
|
160
|
+
class AccessTokenAttributes(UserTokenAttributes):
|
|
161
|
+
refresh_token_id: RefreshTokenId
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@dataclass(frozen=True)
|
|
165
|
+
class ApiKeyAttributes(UserTokenAttributes):
|
|
166
|
+
name: str
|
|
167
|
+
description: Optional[str] = None
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class _DbId(str, ABC):
|
|
171
|
+
table: type[models.Base]
|
|
172
|
+
|
|
173
|
+
def __new__(cls, id_: int) -> _DbId:
|
|
174
|
+
assert isinstance(id_, int)
|
|
175
|
+
return super().__new__(cls, f"{cls.table.__name__}:{id_}")
|
|
176
|
+
|
|
177
|
+
def __int__(self) -> int:
|
|
178
|
+
return int(self.split(":")[1])
|
|
179
|
+
|
|
180
|
+
def __deepcopy__(self, memo: Any) -> _DbId:
|
|
181
|
+
return self
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class TokenId(_DbId, ABC):
|
|
185
|
+
@classmethod
|
|
186
|
+
def parse(cls, value: str) -> Optional[TokenId]:
|
|
187
|
+
table_name, _, id_ = value.partition(":")
|
|
188
|
+
if not id_.isnumeric():
|
|
189
|
+
return None
|
|
190
|
+
for sub in cls.__subclasses__():
|
|
191
|
+
if sub.table.__name__ == table_name:
|
|
192
|
+
return sub(int(id_))
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@final
|
|
197
|
+
class PasswordResetTokenId(TokenId):
|
|
198
|
+
table = models.PasswordResetToken
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@final
|
|
202
|
+
class AccessTokenId(TokenId):
|
|
203
|
+
table = models.AccessToken
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@final
|
|
207
|
+
class RefreshTokenId(TokenId):
|
|
208
|
+
table = models.RefreshToken
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@final
|
|
212
|
+
class ApiKeyId(TokenId):
|
|
213
|
+
table = models.ApiKey
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@final
|
|
217
|
+
class UserId(_DbId):
|
|
218
|
+
table = models.User
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
@dataclass(frozen=True)
|
|
222
|
+
class UserClaimSet(ClaimSet): # type: ignore[override,unused-ignore]
|
|
223
|
+
subject: Optional[UserId] = None
|
|
224
|
+
attributes: Optional[UserTokenAttributes] = None
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@dataclass(frozen=True)
|
|
228
|
+
class PasswordResetTokenClaims(UserClaimSet): # type: ignore[override,unused-ignore]
|
|
229
|
+
token_id: Optional[PasswordResetTokenId] = None
|
|
230
|
+
attributes: Optional[PasswordResetTokenAttributes] = None
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@dataclass(frozen=True)
|
|
234
|
+
class AccessTokenClaims(UserClaimSet): # type: ignore[override,unused-ignore]
|
|
235
|
+
token_id: Optional[AccessTokenId] = None
|
|
236
|
+
attributes: Optional[AccessTokenAttributes] = None
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@dataclass(frozen=True)
|
|
240
|
+
class RefreshTokenClaims(UserClaimSet): # type: ignore[override,unused-ignore]
|
|
241
|
+
token_id: Optional[RefreshTokenId] = None
|
|
242
|
+
attributes: Optional[RefreshTokenAttributes] = None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@dataclass(frozen=True)
|
|
246
|
+
class ApiKeyClaims(UserClaimSet): # type: ignore[override,unused-ignore]
|
|
247
|
+
token_id: Optional[ApiKeyId] = None
|
|
248
|
+
attributes: Optional[ApiKeyAttributes] = None
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class CanRevokeTokens(Protocol):
|
|
252
|
+
async def revoke(self, *token_ids: TokenId) -> None: ...
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class CanLogOutUser(Protocol):
|
|
256
|
+
async def log_out(self, user_id: UserId) -> None: ...
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class TokenStore(CanReadToken, CanRevokeTokens, CanLogOutUser, Protocol):
|
|
260
|
+
async def create_password_reset_token(
|
|
261
|
+
self,
|
|
262
|
+
claims: PasswordResetTokenClaims,
|
|
263
|
+
) -> tuple[PasswordResetToken, PasswordResetTokenId]: ...
|
|
264
|
+
async def create_access_token(
|
|
265
|
+
self,
|
|
266
|
+
claims: AccessTokenClaims,
|
|
267
|
+
) -> tuple[AccessToken, AccessTokenId]: ...
|
|
268
|
+
async def create_refresh_token(
|
|
269
|
+
self,
|
|
270
|
+
claims: RefreshTokenClaims,
|
|
271
|
+
) -> tuple[RefreshToken, RefreshTokenId]: ...
|
|
272
|
+
async def create_api_key(
|
|
273
|
+
self,
|
|
274
|
+
claims: ApiKeyClaims,
|
|
275
|
+
) -> tuple[ApiKey, ApiKeyId]: ...
|
phoenix/services.py
CHANGED
|
@@ -3,9 +3,10 @@ import os
|
|
|
3
3
|
import signal
|
|
4
4
|
import subprocess
|
|
5
5
|
import sys
|
|
6
|
+
from collections.abc import Callable
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from time import sleep, time
|
|
8
|
-
from typing import
|
|
9
|
+
from typing import Optional
|
|
9
10
|
|
|
10
11
|
import psutil
|
|
11
12
|
|
|
@@ -31,7 +32,7 @@ class Service:
|
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
@property
|
|
34
|
-
def command(self) ->
|
|
35
|
+
def command(self) -> list[str]:
|
|
35
36
|
raise NotImplementedError(f"{type(self)} must define `command`")
|
|
36
37
|
|
|
37
38
|
def start(self) -> psutil.Popen:
|
|
@@ -99,40 +100,46 @@ class AppService(Service):
|
|
|
99
100
|
|
|
100
101
|
working_dir = SERVER_DIR
|
|
101
102
|
|
|
102
|
-
# Internal references to the name / directory of the
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
# Internal references to the name / directory of the inferences(s)
|
|
104
|
+
__primary_inferences_name: str
|
|
105
|
+
__reference_inferences_name: Optional[str]
|
|
106
|
+
__corpus_inferences_name: Optional[str]
|
|
106
107
|
__trace_dataset_name: Optional[str]
|
|
107
108
|
|
|
108
109
|
def __init__(
|
|
109
110
|
self,
|
|
111
|
+
database_url: str,
|
|
110
112
|
export_path: Path,
|
|
111
113
|
host: str,
|
|
112
114
|
port: int,
|
|
113
115
|
root_path: str,
|
|
114
|
-
|
|
116
|
+
primary_inferences_name: str,
|
|
115
117
|
umap_params: str,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
reference_inferences_name: Optional[str],
|
|
119
|
+
corpus_inferences_name: Optional[str],
|
|
118
120
|
trace_dataset_name: Optional[str],
|
|
121
|
+
enable_websockets: bool,
|
|
119
122
|
):
|
|
123
|
+
self.database_url = database_url
|
|
120
124
|
self.export_path = export_path
|
|
121
125
|
self.host = host
|
|
122
126
|
self.port = port
|
|
123
127
|
self.root_path = root_path # TODO(mikeldking): Add support for root_path
|
|
124
|
-
self.
|
|
128
|
+
self.__primary_inferences_name = primary_inferences_name
|
|
125
129
|
self.__umap_params = umap_params
|
|
126
|
-
self.
|
|
127
|
-
self.
|
|
130
|
+
self.__reference_inferences_name = reference_inferences_name
|
|
131
|
+
self.__corpus_inferences_name = corpus_inferences_name
|
|
128
132
|
self.__trace_dataset_name = trace_dataset_name
|
|
133
|
+
self.enable_websockets = enable_websockets
|
|
129
134
|
super().__init__()
|
|
130
135
|
|
|
131
136
|
@property
|
|
132
|
-
def command(self) ->
|
|
137
|
+
def command(self) -> list[str]:
|
|
133
138
|
command = [
|
|
134
139
|
sys.executable,
|
|
135
140
|
"main.py",
|
|
141
|
+
"--database-url",
|
|
142
|
+
self.database_url,
|
|
136
143
|
"--export_path",
|
|
137
144
|
str(self.export_path),
|
|
138
145
|
"--host",
|
|
@@ -143,13 +150,15 @@ class AppService(Service):
|
|
|
143
150
|
self.__umap_params,
|
|
144
151
|
"datasets",
|
|
145
152
|
"--primary",
|
|
146
|
-
str(self.
|
|
153
|
+
str(self.__primary_inferences_name),
|
|
147
154
|
]
|
|
148
|
-
if self.
|
|
149
|
-
command.extend(["--reference", str(self.
|
|
150
|
-
if self.
|
|
151
|
-
command.extend(["--corpus", str(self.
|
|
155
|
+
if self.__reference_inferences_name is not None:
|
|
156
|
+
command.extend(["--reference", str(self.__reference_inferences_name)])
|
|
157
|
+
if self.__corpus_inferences_name is not None:
|
|
158
|
+
command.extend(["--corpus", str(self.__corpus_inferences_name)])
|
|
152
159
|
if self.__trace_dataset_name is not None:
|
|
153
160
|
command.extend(["--trace", str(self.__trace_dataset_name)])
|
|
161
|
+
if self.enable_websockets:
|
|
162
|
+
command.append("--enable-websockets")
|
|
154
163
|
logger.info(f"command: {' '.join(command)}")
|
|
155
164
|
return command
|