arize-phoenix 2.0.0__py3-none-any.whl → 2.2.0rc0__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.

Files changed (34) hide show
  1. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/METADATA +5 -1
  2. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/RECORD +31 -29
  3. phoenix/__init__.py +2 -2
  4. phoenix/core/evals.py +29 -8
  5. phoenix/core/traces.py +45 -34
  6. phoenix/experimental/evals/__init__.py +4 -1
  7. phoenix/experimental/evals/evaluators.py +85 -8
  8. phoenix/experimental/evals/functions/classify.py +16 -41
  9. phoenix/experimental/evals/functions/executor.py +1 -0
  10. phoenix/experimental/evals/models/anthropic.py +171 -0
  11. phoenix/experimental/evals/models/vertex.py +155 -0
  12. phoenix/experimental/evals/templates/__init__.py +2 -0
  13. phoenix/experimental/evals/templates/default_templates.py +12 -0
  14. phoenix/experimental/evals/utils/__init__.py +64 -2
  15. phoenix/server/api/schema.py +24 -0
  16. phoenix/server/app.py +6 -5
  17. phoenix/server/main.py +6 -7
  18. phoenix/server/span_handler.py +7 -7
  19. phoenix/server/static/index.js +586 -499
  20. phoenix/server/templates/index.html +5 -1
  21. phoenix/server/trace_handler.py +56 -0
  22. phoenix/session/session.py +2 -1
  23. phoenix/trace/exporter.py +4 -3
  24. phoenix/trace/langchain/tracer.py +14 -4
  25. phoenix/trace/otel.py +409 -0
  26. phoenix/trace/semantic_conventions.py +2 -0
  27. phoenix/trace/v1/__init__.py +0 -4
  28. phoenix/version.py +1 -0
  29. phoenix/trace/v1/trace_pb2.py +0 -54
  30. phoenix/trace/v1/trace_pb2.pyi +0 -361
  31. phoenix/trace/v1/utils.py +0 -538
  32. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/WHEEL +0 -0
  33. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/licenses/IP_NOTICE +0 -0
  34. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from io import BytesIO
3
- from typing import List, Optional, Tuple
3
+ from typing import Any, Dict, List, Optional, Tuple
4
4
  from urllib.error import HTTPError
5
5
  from urllib.request import urlopen
6
6
  from zipfile import ZipFile
@@ -14,10 +14,11 @@ from phoenix.utilities.logging import printif
14
14
  # This is useful for debugging as well as to just treat the output as a non-parsable category
15
15
  NOT_PARSABLE = "NOT_PARSABLE"
16
16
 
17
- # argument keys in the default openai function call,
17
+ # values in the default openai function call,
18
18
  # defined here only to prevent typos
19
19
  _RESPONSE = "response"
20
20
  _EXPLANATION = "explanation"
21
+ _FUNCTION_NAME = "record_response"
21
22
 
22
23
 
23
24
  def download_benchmark_dataset(task: str, dataset_name: str) -> pd.DataFrame:
@@ -108,3 +109,64 @@ def parse_openai_function_call(raw_output: str) -> Tuple[str, Optional[str]]:
108
109
  unrailed_label = raw_output
109
110
  explanation = None
110
111
  return unrailed_label, explanation
112
+
113
+
114
+ def openai_function_call_kwargs(rails: List[str], provide_explanation: bool) -> Dict[str, Any]:
115
+ """
116
+ Returns keyword arguments needed to invoke an OpenAI model with function
117
+ calling for classification.
118
+
119
+ Args:
120
+ rails (List[str]): The rails to snap the output to.
121
+
122
+ provide_explanation (bool): Whether to provide an explanation.
123
+
124
+ Returns:
125
+ Dict[str, Any]: A dictionary containing function call arguments.
126
+ """
127
+ openai_function = _default_openai_function(rails, provide_explanation)
128
+ return {
129
+ "functions": [openai_function],
130
+ "function_call": {"name": openai_function["name"]},
131
+ }
132
+
133
+
134
+ def _default_openai_function(
135
+ rails: List[str],
136
+ with_explanation: bool = False,
137
+ ) -> Dict[str, Any]:
138
+ """
139
+ Returns a default OpenAI function call for classification.
140
+
141
+ Args:
142
+ rails (List[str]): A list of rails to snap the output to.
143
+
144
+ with_explanation (bool, optional): Whether to include an explanation.
145
+
146
+ Returns:
147
+ Dict[str, Any]: A JSON schema object advertising a function to record
148
+ the result of the LLM's classification.
149
+ """
150
+ properties = {
151
+ **(
152
+ {
153
+ _EXPLANATION: {
154
+ "type": "string",
155
+ "description": "Explanation of the reasoning for your response.",
156
+ },
157
+ }
158
+ if with_explanation
159
+ else {}
160
+ ),
161
+ _RESPONSE: {"type": "string", "description": "Your response.", "enum": rails},
162
+ }
163
+ required = [*([_EXPLANATION] if with_explanation else []), _RESPONSE]
164
+ return {
165
+ "name": _FUNCTION_NAME,
166
+ "description": "A function to record your response.",
167
+ "parameters": {
168
+ "type": "object",
169
+ "properties": properties,
170
+ "required": required,
171
+ },
172
+ }
@@ -202,6 +202,30 @@ class Query:
202
202
  clustered_events=clustered_events,
203
203
  )
204
204
 
205
+ @strawberry.field
206
+ def streaming_last_updated_at(
207
+ self,
208
+ info: Info[Context, None],
209
+ ) -> Optional[datetime]:
210
+ last_updated_at: Optional[datetime] = None
211
+ if (traces := info.context.traces) is not None and (
212
+ traces_last_updated_at := traces.last_updated_at
213
+ ) is not None:
214
+ last_updated_at = (
215
+ traces_last_updated_at
216
+ if last_updated_at is None
217
+ else max(last_updated_at, traces_last_updated_at)
218
+ )
219
+ if (evals := info.context.evals) is not None and (
220
+ evals_last_updated_at := evals.last_updated_at
221
+ ) is not None:
222
+ last_updated_at = (
223
+ evals_last_updated_at
224
+ if last_updated_at is None
225
+ else max(last_updated_at, evals_last_updated_at)
226
+ )
227
+ return last_updated_at
228
+
205
229
  @strawberry.field
206
230
  def spans(
207
231
  self,
phoenix/server/app.py CHANGED
@@ -28,6 +28,7 @@ from phoenix.server.api.context import Context
28
28
  from phoenix.server.api.schema import schema
29
29
  from phoenix.server.evaluation_handler import EvaluationHandler
30
30
  from phoenix.server.span_handler import SpanHandler
31
+ from phoenix.server.trace_handler import TraceHandler
31
32
 
32
33
  logger = logging.getLogger(__name__)
33
34
 
@@ -185,11 +186,11 @@ def create_app(
185
186
  else [
186
187
  Route(
187
188
  "/v1/spans",
188
- type(
189
- "SpanEndpoint",
190
- (SpanHandler,),
191
- {"queue": traces},
192
- ),
189
+ type("SpanEndpoint", (SpanHandler,), {"queue": traces}),
190
+ ),
191
+ Route(
192
+ "/v1/traces",
193
+ type("TraceEndpoint", (TraceHandler,), {"queue": traces}),
193
194
  ),
194
195
  ]
195
196
  )
phoenix/server/main.py CHANGED
@@ -29,6 +29,7 @@ from phoenix.trace.fixtures import (
29
29
  _get_trace_fixture_by_name,
30
30
  get_evals_from_fixture,
31
31
  )
32
+ from phoenix.trace.otel import encode
32
33
  from phoenix.trace.span_json_decoder import json_string_to_span
33
34
 
34
35
  logger = logging.getLogger(__name__)
@@ -148,13 +149,11 @@ if __name__ == "__main__":
148
149
  traces = Traces()
149
150
  evals = Evals()
150
151
  if trace_dataset_name is not None:
151
- fixture_spans = map(
152
- json_string_to_span,
153
- _download_traces_fixture(
154
- _get_trace_fixture_by_name(
155
- trace_dataset_name,
156
- ),
157
- ),
152
+ fixture_spans = (
153
+ encode(json_string_to_span(json_span))
154
+ for json_span in _download_traces_fixture(
155
+ _get_trace_fixture_by_name(trace_dataset_name)
156
+ )
158
157
  )
159
158
  Thread(
160
159
  target=_load_items,
@@ -1,18 +1,18 @@
1
1
  import gzip
2
2
  from typing import Protocol
3
3
 
4
+ import opentelemetry.proto.trace.v1.trace_pb2 as otlp
4
5
  from starlette.endpoints import HTTPEndpoint
5
6
  from starlette.requests import Request
6
7
  from starlette.responses import Response
7
8
 
8
- import phoenix.trace.v1 as pb
9
+ from phoenix.trace.otel import encode
9
10
  from phoenix.trace.schemas import Span
10
11
  from phoenix.trace.span_json_decoder import json_to_span
11
- from phoenix.trace.v1.utils import encode
12
12
 
13
13
 
14
14
  class SupportsPutSpan(Protocol):
15
- def put(self, span: pb.Span) -> None:
15
+ def put(self, span: otlp.Span) -> None:
16
16
  ...
17
17
 
18
18
 
@@ -27,13 +27,13 @@ class SpanHandler(HTTPEndpoint):
27
27
  content_encoding = request.headers.get("content-encoding")
28
28
  if content_encoding == "gzip":
29
29
  body = gzip.decompress(body)
30
- pb_span = pb.Span()
31
- pb_span.ParseFromString(body)
30
+ otlp_span = otlp.Span()
31
+ otlp_span.ParseFromString(body)
32
32
  else:
33
33
  span = json_to_span(await request.json())
34
34
  assert isinstance(span, Span)
35
- pb_span = encode(span)
35
+ otlp_span = encode(span)
36
36
  except Exception:
37
37
  return Response(status_code=422)
38
- self.queue.put(pb_span)
38
+ self.queue.put(otlp_span)
39
39
  return Response()