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
phoenix/server/main.py
CHANGED
|
@@ -1,54 +1,87 @@
|
|
|
1
1
|
import atexit
|
|
2
|
-
import
|
|
2
|
+
import codecs
|
|
3
3
|
import os
|
|
4
|
-
|
|
4
|
+
import sys
|
|
5
|
+
from argparse import SUPPRESS, ArgumentParser
|
|
5
6
|
from pathlib import Path
|
|
6
|
-
from random import random
|
|
7
7
|
from threading import Thread
|
|
8
8
|
from time import sleep, time
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from urllib.parse import urljoin
|
|
10
11
|
|
|
11
|
-
import
|
|
12
|
+
from jinja2 import BaseLoader, Environment
|
|
12
13
|
from uvicorn import Config, Server
|
|
13
14
|
|
|
15
|
+
import phoenix.trace.v1 as pb
|
|
14
16
|
from phoenix.config import (
|
|
15
17
|
EXPORT_DIR,
|
|
18
|
+
get_env_access_token_expiry,
|
|
19
|
+
get_env_auth_settings,
|
|
20
|
+
get_env_database_connection_str,
|
|
21
|
+
get_env_database_schema,
|
|
22
|
+
get_env_db_logging_level,
|
|
23
|
+
get_env_enable_prometheus,
|
|
24
|
+
get_env_enable_websockets,
|
|
25
|
+
get_env_grpc_port,
|
|
16
26
|
get_env_host,
|
|
27
|
+
get_env_host_root_path,
|
|
28
|
+
get_env_log_migrations,
|
|
29
|
+
get_env_logging_level,
|
|
30
|
+
get_env_logging_mode,
|
|
31
|
+
get_env_oauth2_settings,
|
|
32
|
+
get_env_password_reset_token_expiry,
|
|
17
33
|
get_env_port,
|
|
34
|
+
get_env_refresh_token_expiry,
|
|
35
|
+
get_env_smtp_hostname,
|
|
36
|
+
get_env_smtp_mail_from,
|
|
37
|
+
get_env_smtp_password,
|
|
38
|
+
get_env_smtp_port,
|
|
39
|
+
get_env_smtp_username,
|
|
40
|
+
get_env_smtp_validate_certs,
|
|
18
41
|
get_pids_path,
|
|
19
42
|
)
|
|
20
|
-
from phoenix.core.model_schema_adapter import
|
|
21
|
-
from phoenix.
|
|
22
|
-
from phoenix.
|
|
23
|
-
from phoenix.
|
|
43
|
+
from phoenix.core.model_schema_adapter import create_model_from_inferences
|
|
44
|
+
from phoenix.db import get_printable_db_url
|
|
45
|
+
from phoenix.inferences.fixtures import FIXTURES, get_inferences
|
|
46
|
+
from phoenix.inferences.inferences import EMPTY_INFERENCES, Inferences
|
|
47
|
+
from phoenix.logging import setup_logging
|
|
24
48
|
from phoenix.pointcloud.umap_parameters import (
|
|
25
49
|
DEFAULT_MIN_DIST,
|
|
26
50
|
DEFAULT_N_NEIGHBORS,
|
|
27
51
|
DEFAULT_N_SAMPLES,
|
|
28
52
|
UMAPParameters,
|
|
29
53
|
)
|
|
30
|
-
from phoenix.server.app import
|
|
31
|
-
|
|
54
|
+
from phoenix.server.app import (
|
|
55
|
+
ScaffolderConfig,
|
|
56
|
+
_db,
|
|
57
|
+
create_app,
|
|
58
|
+
create_engine_and_run_migrations,
|
|
59
|
+
instrument_engine_if_enabled,
|
|
60
|
+
)
|
|
61
|
+
from phoenix.server.email.sender import SimpleEmailSender
|
|
62
|
+
from phoenix.server.types import DbSessionFactory
|
|
63
|
+
from phoenix.settings import Settings
|
|
32
64
|
from phoenix.trace.fixtures import (
|
|
33
65
|
TRACES_FIXTURES,
|
|
34
|
-
|
|
35
|
-
_get_trace_fixture_by_name,
|
|
66
|
+
get_dataset_fixtures,
|
|
36
67
|
get_evals_from_fixture,
|
|
68
|
+
get_trace_fixtures_by_project_name,
|
|
69
|
+
load_example_traces,
|
|
70
|
+
reset_fixture_span_ids_and_timestamps,
|
|
71
|
+
send_dataset_fixtures,
|
|
37
72
|
)
|
|
38
|
-
from phoenix.trace.otel import
|
|
39
|
-
from phoenix.trace.
|
|
40
|
-
from phoenix.
|
|
41
|
-
|
|
42
|
-
logger = logging.getLogger(__name__)
|
|
73
|
+
from phoenix.trace.otel import decode_otlp_span, encode_span_to_otlp
|
|
74
|
+
from phoenix.trace.schemas import Span
|
|
75
|
+
from phoenix.version import __version__ as phoenix_version
|
|
43
76
|
|
|
44
|
-
_WELCOME_MESSAGE = """
|
|
77
|
+
_WELCOME_MESSAGE = Environment(loader=BaseLoader()).from_string("""
|
|
45
78
|
|
|
46
79
|
██████╗ ██╗ ██╗ ██████╗ ███████╗███╗ ██╗██╗██╗ ██╗
|
|
47
80
|
██╔══██╗██║ ██║██╔═══██╗██╔════╝████╗ ██║██║╚██╗██╔╝
|
|
48
81
|
██████╔╝███████║██║ ██║█████╗ ██╔██╗ ██║██║ ╚███╔╝
|
|
49
82
|
██╔═══╝ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║██║ ██╔██╗
|
|
50
83
|
██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║██║██╔╝ ██╗
|
|
51
|
-
╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝ v{
|
|
84
|
+
╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝ v{{ version }}
|
|
52
85
|
|
|
53
86
|
|
|
|
54
87
|
| 🌎 Join our Community 🌎
|
|
@@ -61,15 +94,22 @@ _WELCOME_MESSAGE = """
|
|
|
61
94
|
| https://docs.arize.com/phoenix
|
|
62
95
|
|
|
|
63
96
|
| 🚀 Phoenix Server 🚀
|
|
64
|
-
| Phoenix UI:
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
97
|
+
| Phoenix UI: {{ ui_path }}
|
|
98
|
+
| Authentication: {{ auth_enabled }}
|
|
99
|
+
| Websockets: {{ websockets_enabled }}
|
|
100
|
+
| Log traces:
|
|
101
|
+
| - gRPC: {{ grpc_path }}
|
|
102
|
+
| - HTTP: {{ http_path }}
|
|
103
|
+
| Storage: {{ storage }}
|
|
104
|
+
{% if schema -%}
|
|
105
|
+
| - Schema: {{ schema }}
|
|
106
|
+
{% endif -%}
|
|
107
|
+
""")
|
|
68
108
|
|
|
69
109
|
|
|
70
110
|
def _write_pid_file_when_ready(
|
|
71
111
|
server: Server,
|
|
72
|
-
wait_up_to_seconds: float =
|
|
112
|
+
wait_up_to_seconds: float = 60,
|
|
73
113
|
) -> None:
|
|
74
114
|
"""Write PID file after server is started (or when time is up)."""
|
|
75
115
|
time_limit = time() + wait_up_to_seconds
|
|
@@ -88,161 +128,310 @@ def _get_pid_file() -> Path:
|
|
|
88
128
|
return get_pids_path() / str(os.getpid())
|
|
89
129
|
|
|
90
130
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class _SupportsPut(Protocol[_Item]):
|
|
95
|
-
def put(self, item: _Item) -> None: ...
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def _load_items(
|
|
99
|
-
queue: _SupportsPut[_Item],
|
|
100
|
-
items: Iterable[_Item],
|
|
101
|
-
simulate_streaming: Optional[bool] = False,
|
|
102
|
-
) -> None:
|
|
103
|
-
for item in items:
|
|
104
|
-
if simulate_streaming:
|
|
105
|
-
sleep(random())
|
|
106
|
-
queue.put(item)
|
|
131
|
+
DEFAULT_UMAP_PARAMS_STR = f"{DEFAULT_MIN_DIST},{DEFAULT_N_NEIGHBORS},{DEFAULT_N_SAMPLES}"
|
|
107
132
|
|
|
108
133
|
|
|
109
|
-
|
|
134
|
+
def main() -> None:
|
|
135
|
+
initialize_settings()
|
|
136
|
+
setup_logging()
|
|
110
137
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
reference_dataset_name: Optional[str]
|
|
138
|
+
primary_inferences_name: str
|
|
139
|
+
reference_inferences_name: Optional[str]
|
|
114
140
|
trace_dataset_name: Optional[str] = None
|
|
115
|
-
simulate_streaming: Optional[bool] = None
|
|
116
141
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
primary_inferences: Inferences = EMPTY_INFERENCES
|
|
143
|
+
reference_inferences: Optional[Inferences] = None
|
|
144
|
+
corpus_inferences: Optional[Inferences] = None
|
|
120
145
|
|
|
121
|
-
# automatically remove the pid file when the process is being gracefully terminated
|
|
122
146
|
atexit.register(_remove_pid_file)
|
|
123
147
|
|
|
124
|
-
parser = ArgumentParser()
|
|
125
|
-
parser.add_argument(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
parser.add_argument("--
|
|
132
|
-
|
|
148
|
+
parser = ArgumentParser(usage="phoenix serve", add_help=False)
|
|
149
|
+
parser.add_argument(
|
|
150
|
+
"-h",
|
|
151
|
+
"--help",
|
|
152
|
+
action="help",
|
|
153
|
+
help=SUPPRESS,
|
|
154
|
+
)
|
|
155
|
+
parser.add_argument("--database-url", required=False, help=SUPPRESS)
|
|
156
|
+
parser.add_argument("--export_path", help=SUPPRESS)
|
|
157
|
+
parser.add_argument("--host", type=str, required=False, help=SUPPRESS)
|
|
158
|
+
parser.add_argument("--port", type=int, required=False, help=SUPPRESS)
|
|
159
|
+
parser.add_argument("--read-only", action="store_true", required=False, help=SUPPRESS)
|
|
160
|
+
parser.add_argument("--no-internet", action="store_true", help=SUPPRESS)
|
|
161
|
+
parser.add_argument(
|
|
162
|
+
"--umap_params", type=str, required=False, default=DEFAULT_UMAP_PARAMS_STR, help=SUPPRESS
|
|
163
|
+
)
|
|
164
|
+
parser.add_argument("--debug", action="store_true", help=SUPPRESS)
|
|
165
|
+
parser.add_argument("--dev", action="store_true", help=SUPPRESS)
|
|
166
|
+
parser.add_argument("--no-ui", action="store_true", help=SUPPRESS)
|
|
167
|
+
parser.add_argument("--enable-websockets", type=str, help=SUPPRESS)
|
|
168
|
+
subparsers = parser.add_subparsers(dest="command", required=True, help=SUPPRESS)
|
|
169
|
+
|
|
133
170
|
serve_parser = subparsers.add_parser("serve")
|
|
171
|
+
serve_parser.add_argument(
|
|
172
|
+
"--with-fixture",
|
|
173
|
+
type=str,
|
|
174
|
+
required=False,
|
|
175
|
+
default="",
|
|
176
|
+
help=("Name of an inference fixture. Example: 'fixture1'"),
|
|
177
|
+
)
|
|
178
|
+
serve_parser.add_argument(
|
|
179
|
+
"--with-trace-fixtures",
|
|
180
|
+
type=str,
|
|
181
|
+
required=False,
|
|
182
|
+
default="",
|
|
183
|
+
help=(
|
|
184
|
+
"Comma separated list of tracing fixture names (spaces are ignored). "
|
|
185
|
+
"Example: 'fixture1, fixture2'"
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
serve_parser.add_argument(
|
|
189
|
+
"--with-projects",
|
|
190
|
+
type=str,
|
|
191
|
+
required=False,
|
|
192
|
+
default="",
|
|
193
|
+
help=(
|
|
194
|
+
"Comma separated list of project names (spaces are ignored). "
|
|
195
|
+
"Example: 'project1, project2'"
|
|
196
|
+
),
|
|
197
|
+
)
|
|
198
|
+
serve_parser.add_argument(
|
|
199
|
+
"--force-fixture-ingestion",
|
|
200
|
+
action="store_true",
|
|
201
|
+
required=False,
|
|
202
|
+
help=(
|
|
203
|
+
"Whether or not to check the database age before adding the fixtures. "
|
|
204
|
+
"Default is False, i.e., fixtures will only be added if the "
|
|
205
|
+
"database is new."
|
|
206
|
+
),
|
|
207
|
+
)
|
|
208
|
+
serve_parser.add_argument(
|
|
209
|
+
"--scaffold-datasets",
|
|
210
|
+
action="store_true",
|
|
211
|
+
required=False,
|
|
212
|
+
help=(
|
|
213
|
+
"Whether or not to add any datasets defined in "
|
|
214
|
+
"the inputted project or trace fixture. "
|
|
215
|
+
"Default is False. "
|
|
216
|
+
),
|
|
217
|
+
)
|
|
218
|
+
|
|
134
219
|
datasets_parser = subparsers.add_parser("datasets")
|
|
135
220
|
datasets_parser.add_argument("--primary", type=str, required=True)
|
|
136
221
|
datasets_parser.add_argument("--reference", type=str, required=False)
|
|
137
222
|
datasets_parser.add_argument("--corpus", type=str, required=False)
|
|
138
223
|
datasets_parser.add_argument("--trace", type=str, required=False)
|
|
224
|
+
|
|
139
225
|
fixture_parser = subparsers.add_parser("fixture")
|
|
140
226
|
fixture_parser.add_argument("fixture", type=str, choices=[fixture.name for fixture in FIXTURES])
|
|
141
|
-
fixture_parser.add_argument("--primary-only",
|
|
227
|
+
fixture_parser.add_argument("--primary-only", action="store_true")
|
|
228
|
+
|
|
142
229
|
trace_fixture_parser = subparsers.add_parser("trace-fixture")
|
|
143
230
|
trace_fixture_parser.add_argument(
|
|
144
231
|
"fixture", type=str, choices=[fixture.name for fixture in TRACES_FIXTURES]
|
|
145
232
|
)
|
|
146
|
-
trace_fixture_parser.add_argument("--simulate-streaming",
|
|
233
|
+
trace_fixture_parser.add_argument("--simulate-streaming", action="store_true")
|
|
234
|
+
|
|
147
235
|
demo_parser = subparsers.add_parser("demo")
|
|
148
236
|
demo_parser.add_argument("fixture", type=str, choices=[fixture.name for fixture in FIXTURES])
|
|
149
237
|
demo_parser.add_argument(
|
|
150
238
|
"trace_fixture", type=str, choices=[fixture.name for fixture in TRACES_FIXTURES]
|
|
151
239
|
)
|
|
152
240
|
demo_parser.add_argument("--simulate-streaming", action="store_true")
|
|
241
|
+
|
|
153
242
|
args = parser.parse_args()
|
|
154
|
-
|
|
155
|
-
|
|
243
|
+
db_connection_str = (
|
|
244
|
+
args.database_url if args.database_url else get_env_database_connection_str()
|
|
245
|
+
)
|
|
246
|
+
export_path = Path(args.export_path) if args.export_path else Path(EXPORT_DIR)
|
|
247
|
+
|
|
248
|
+
force_fixture_ingestion = False
|
|
249
|
+
scaffold_datasets = False
|
|
250
|
+
tracing_fixture_names = set()
|
|
156
251
|
if args.command == "datasets":
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if
|
|
252
|
+
primary_inferences_name = args.primary
|
|
253
|
+
reference_inferences_name = args.reference
|
|
254
|
+
corpus_inferences_name = args.corpus
|
|
255
|
+
primary_inferences = Inferences.from_name(primary_inferences_name)
|
|
256
|
+
reference_inferences = (
|
|
257
|
+
Inferences.from_name(reference_inferences_name)
|
|
258
|
+
if reference_inferences_name is not None
|
|
164
259
|
else None
|
|
165
260
|
)
|
|
166
|
-
|
|
167
|
-
None if
|
|
261
|
+
corpus_inferences = (
|
|
262
|
+
None if corpus_inferences_name is None else Inferences.from_name(corpus_inferences_name)
|
|
168
263
|
)
|
|
169
264
|
elif args.command == "fixture":
|
|
170
265
|
fixture_name = args.fixture
|
|
171
266
|
primary_only = args.primary_only
|
|
172
|
-
|
|
267
|
+
primary_inferences, reference_inferences, corpus_inferences = get_inferences(
|
|
173
268
|
fixture_name,
|
|
174
269
|
args.no_internet,
|
|
175
270
|
)
|
|
176
271
|
if primary_only:
|
|
177
|
-
|
|
178
|
-
|
|
272
|
+
reference_inferences_name = None
|
|
273
|
+
reference_inferences = None
|
|
179
274
|
elif args.command == "trace-fixture":
|
|
180
275
|
trace_dataset_name = args.fixture
|
|
181
|
-
simulate_streaming = args.simulate_streaming
|
|
182
276
|
elif args.command == "demo":
|
|
183
277
|
fixture_name = args.fixture
|
|
184
|
-
|
|
278
|
+
primary_inferences, reference_inferences, corpus_inferences = get_inferences(
|
|
185
279
|
fixture_name,
|
|
186
280
|
args.no_internet,
|
|
187
281
|
)
|
|
188
282
|
trace_dataset_name = args.trace_fixture
|
|
189
|
-
|
|
283
|
+
elif args.command == "serve":
|
|
284
|
+
if args.with_fixture:
|
|
285
|
+
primary_inferences, reference_inferences, corpus_inferences = get_inferences(
|
|
286
|
+
str(args.with_fixture),
|
|
287
|
+
args.no_internet,
|
|
288
|
+
)
|
|
289
|
+
if args.with_trace_fixtures:
|
|
290
|
+
tracing_fixture_names.update(
|
|
291
|
+
[name.strip() for name in args.with_trace_fixtures.split(",")]
|
|
292
|
+
)
|
|
293
|
+
if args.with_projects:
|
|
294
|
+
project_names = [name.strip() for name in args.with_projects.split(",")]
|
|
295
|
+
tracing_fixture_names.update(
|
|
296
|
+
fixture.name
|
|
297
|
+
for name in project_names
|
|
298
|
+
for fixture in get_trace_fixtures_by_project_name(name)
|
|
299
|
+
)
|
|
300
|
+
force_fixture_ingestion = args.force_fixture_ingestion
|
|
301
|
+
scaffold_datasets = args.scaffold_datasets
|
|
302
|
+
host: Optional[str] = args.host or get_env_host()
|
|
303
|
+
if host == "::":
|
|
304
|
+
host = None
|
|
305
|
+
|
|
306
|
+
port = args.port or get_env_port()
|
|
307
|
+
host_root_path = get_env_host_root_path()
|
|
308
|
+
read_only = args.read_only
|
|
190
309
|
|
|
191
|
-
model =
|
|
192
|
-
|
|
193
|
-
|
|
310
|
+
model = create_model_from_inferences(
|
|
311
|
+
primary_inferences,
|
|
312
|
+
reference_inferences,
|
|
194
313
|
)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
314
|
+
|
|
315
|
+
authentication_enabled, secret = get_env_auth_settings()
|
|
316
|
+
|
|
317
|
+
fixture_spans: list[Span] = []
|
|
318
|
+
fixture_evals: list[pb.Evaluation] = []
|
|
198
319
|
if trace_dataset_name is not None:
|
|
199
|
-
fixture_spans =
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
)
|
|
320
|
+
fixture_spans, fixture_evals = reset_fixture_span_ids_and_timestamps(
|
|
321
|
+
(
|
|
322
|
+
# Apply `encode` here because legacy jsonl files contains UUIDs as strings.
|
|
323
|
+
# `encode` removes the hyphens in the UUIDs.
|
|
324
|
+
decode_otlp_span(encode_span_to_otlp(span))
|
|
325
|
+
for span in load_example_traces(trace_dataset_name).to_spans()
|
|
326
|
+
),
|
|
327
|
+
get_evals_from_fixture(trace_dataset_name),
|
|
206
328
|
)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
Thread(
|
|
214
|
-
target=_load_items,
|
|
215
|
-
args=(traces, fixture_evals, simulate_streaming),
|
|
216
|
-
daemon=True,
|
|
217
|
-
).start()
|
|
329
|
+
dataset_fixtures = list(get_dataset_fixtures(trace_dataset_name))
|
|
330
|
+
if not read_only:
|
|
331
|
+
Thread(
|
|
332
|
+
target=send_dataset_fixtures,
|
|
333
|
+
args=(f"http://{host}:{port}", dataset_fixtures),
|
|
334
|
+
).start()
|
|
218
335
|
umap_params_list = args.umap_params.split(",")
|
|
219
336
|
umap_params = UMAPParameters(
|
|
220
337
|
min_dist=float(umap_params_list[0]),
|
|
221
338
|
n_neighbors=int(umap_params_list[1]),
|
|
222
339
|
n_samples=int(umap_params_list[2]),
|
|
223
340
|
)
|
|
224
|
-
|
|
225
|
-
|
|
341
|
+
|
|
342
|
+
if enable_prometheus := get_env_enable_prometheus():
|
|
343
|
+
from phoenix.server.prometheus import start_prometheus
|
|
344
|
+
|
|
345
|
+
start_prometheus()
|
|
346
|
+
|
|
347
|
+
engine = create_engine_and_run_migrations(db_connection_str)
|
|
348
|
+
instrumentation_cleanups = instrument_engine_if_enabled(engine)
|
|
349
|
+
factory = DbSessionFactory(db=_db(engine), dialect=engine.dialect.name)
|
|
350
|
+
corpus_model = (
|
|
351
|
+
None if corpus_inferences is None else create_model_from_inferences(corpus_inferences)
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Get enable_websockets from environment variable or command line argument
|
|
355
|
+
enable_websockets = get_env_enable_websockets()
|
|
356
|
+
if args.enable_websockets is not None:
|
|
357
|
+
enable_websockets = args.enable_websockets.lower() == "true"
|
|
358
|
+
if enable_websockets is None:
|
|
359
|
+
enable_websockets = True
|
|
360
|
+
|
|
361
|
+
# Print information about the server
|
|
362
|
+
root_path = urljoin(f"http://{host}:{port}", host_root_path)
|
|
363
|
+
msg = _WELCOME_MESSAGE.render(
|
|
364
|
+
version=phoenix_version,
|
|
365
|
+
ui_path=root_path,
|
|
366
|
+
grpc_path=f"http://{host}:{get_env_grpc_port()}",
|
|
367
|
+
http_path=urljoin(root_path, "v1/traces"),
|
|
368
|
+
storage=get_printable_db_url(db_connection_str),
|
|
369
|
+
schema=get_env_database_schema(),
|
|
370
|
+
auth_enabled=authentication_enabled,
|
|
371
|
+
websockets_enabled=enable_websockets,
|
|
372
|
+
)
|
|
373
|
+
if sys.platform.startswith("win"):
|
|
374
|
+
msg = codecs.encode(msg, "ascii", errors="ignore").decode("ascii").strip()
|
|
375
|
+
scaffolder_config = ScaffolderConfig(
|
|
376
|
+
db=factory,
|
|
377
|
+
tracing_fixture_names=tracing_fixture_names,
|
|
378
|
+
force_fixture_ingestion=force_fixture_ingestion,
|
|
379
|
+
scaffold_datasets=scaffold_datasets,
|
|
380
|
+
phoenix_url=root_path,
|
|
381
|
+
)
|
|
382
|
+
email_sender = None
|
|
383
|
+
if mail_sever := get_env_smtp_hostname():
|
|
384
|
+
assert (mail_username := get_env_smtp_username()), "SMTP username is required"
|
|
385
|
+
assert (mail_password := get_env_smtp_password()), "SMTP password is required"
|
|
386
|
+
assert (sender_email := get_env_smtp_mail_from()), "SMTP mail_from is required"
|
|
387
|
+
email_sender = SimpleEmailSender(
|
|
388
|
+
smtp_server=mail_sever,
|
|
389
|
+
smtp_port=get_env_smtp_port(),
|
|
390
|
+
username=mail_username,
|
|
391
|
+
password=mail_password,
|
|
392
|
+
sender_email=sender_email,
|
|
393
|
+
connection_method="STARTTLS",
|
|
394
|
+
validate_certs=get_env_smtp_validate_certs(),
|
|
395
|
+
)
|
|
396
|
+
|
|
226
397
|
app = create_app(
|
|
398
|
+
db=factory,
|
|
227
399
|
export_path=export_path,
|
|
228
400
|
model=model,
|
|
401
|
+
enable_websockets=enable_websockets,
|
|
402
|
+
authentication_enabled=authentication_enabled,
|
|
229
403
|
umap_params=umap_params,
|
|
230
|
-
|
|
231
|
-
corpus=None if corpus_dataset is None else create_model_from_datasets(corpus_dataset),
|
|
404
|
+
corpus=corpus_model,
|
|
232
405
|
debug=args.debug,
|
|
406
|
+
dev=args.dev,
|
|
407
|
+
serve_ui=not args.no_ui,
|
|
233
408
|
read_only=read_only,
|
|
234
|
-
|
|
409
|
+
enable_prometheus=enable_prometheus,
|
|
410
|
+
initial_spans=fixture_spans,
|
|
411
|
+
initial_evaluations=fixture_evals,
|
|
412
|
+
startup_callbacks=[lambda: print(msg)],
|
|
413
|
+
shutdown_callbacks=instrumentation_cleanups,
|
|
414
|
+
secret=secret,
|
|
415
|
+
password_reset_token_expiry=get_env_password_reset_token_expiry(),
|
|
416
|
+
access_token_expiry=get_env_access_token_expiry(),
|
|
417
|
+
refresh_token_expiry=get_env_refresh_token_expiry(),
|
|
418
|
+
scaffolder_config=scaffolder_config,
|
|
419
|
+
email_sender=email_sender,
|
|
420
|
+
oauth2_client_configs=get_env_oauth2_settings(),
|
|
235
421
|
)
|
|
236
|
-
|
|
237
|
-
port = args.port or get_env_port()
|
|
238
|
-
server = Server(config=Config(app, host=host, port=port))
|
|
422
|
+
server = Server(config=Config(app, host=host, port=port, root_path=host_root_path)) # type: ignore
|
|
239
423
|
Thread(target=_write_pid_file_when_ready, args=(server,), daemon=True).start()
|
|
240
424
|
|
|
241
|
-
# Print information about the server
|
|
242
|
-
phoenix_version = pkg_resources.get_distribution("arize-phoenix").version
|
|
243
|
-
print(
|
|
244
|
-
_WELCOME_MESSAGE.format(phoenix_version, host if host != "0.0.0.0" else "localhost", port)
|
|
245
|
-
)
|
|
246
|
-
|
|
247
425
|
# Start the server
|
|
248
426
|
server.run()
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def initialize_settings() -> None:
|
|
430
|
+
Settings.logging_mode = get_env_logging_mode()
|
|
431
|
+
Settings.logging_level = get_env_logging_level()
|
|
432
|
+
Settings.db_logging_level = get_env_db_logging_level()
|
|
433
|
+
Settings.log_migrations = get_env_log_migrations()
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
if __name__ == "__main__":
|
|
437
|
+
main()
|
phoenix/server/oauth2.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from authlib.integrations.base_client import BaseApp
|
|
5
|
+
from authlib.integrations.base_client.async_app import AsyncOAuth2Mixin
|
|
6
|
+
from authlib.integrations.base_client.async_openid import AsyncOpenIDMixin
|
|
7
|
+
from authlib.integrations.httpx_client import AsyncOAuth2Client as AsyncHttpxOAuth2Client
|
|
8
|
+
|
|
9
|
+
from phoenix.config import OAuth2ClientConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class OAuth2Client(AsyncOAuth2Mixin, AsyncOpenIDMixin, BaseApp): # type:ignore[misc]
|
|
13
|
+
"""
|
|
14
|
+
An OAuth2 client class that supports OpenID Connect. Adapted from authlib's
|
|
15
|
+
`StarletteOAuth2App` to be useable without integration with Starlette.
|
|
16
|
+
|
|
17
|
+
https://github.com/lepture/authlib/blob/904d66bebd79bf39fb8814353a22bab7d3e092c4/authlib/integrations/starlette_client/apps.py#L58
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
client_cls = AsyncHttpxOAuth2Client
|
|
21
|
+
|
|
22
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
23
|
+
super().__init__(framework=None, *args, **kwargs)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OAuth2Clients:
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self._clients: dict[str, OAuth2Client] = {}
|
|
29
|
+
|
|
30
|
+
def add_client(self, config: OAuth2ClientConfig) -> None:
|
|
31
|
+
if (idp_name := config.idp_name) in self._clients:
|
|
32
|
+
raise ValueError(f"oauth client already registered: {idp_name}")
|
|
33
|
+
client = OAuth2Client(
|
|
34
|
+
client_id=config.client_id,
|
|
35
|
+
client_secret=config.client_secret,
|
|
36
|
+
server_metadata_url=config.oidc_config_url,
|
|
37
|
+
client_kwargs={"scope": "openid email profile"},
|
|
38
|
+
)
|
|
39
|
+
assert isinstance(client, OAuth2Client)
|
|
40
|
+
self._clients[config.idp_name] = client
|
|
41
|
+
|
|
42
|
+
def get_client(self, idp_name: str) -> OAuth2Client:
|
|
43
|
+
if (client := self._clients.get(idp_name)) is None:
|
|
44
|
+
raise ValueError(f"unknown or unregistered OAuth2 client: {idp_name}")
|
|
45
|
+
return client
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_configs(cls, configs: Iterable[OAuth2ClientConfig]) -> "OAuth2Clients":
|
|
49
|
+
oauth2_clients = cls()
|
|
50
|
+
for config in configs:
|
|
51
|
+
oauth2_clients.add_client(config)
|
|
52
|
+
return oauth2_clients
|
|
File without changes
|