arize-phoenix 3.13.1__py3-none-any.whl → 3.14.1__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-3.13.1.dist-info → arize_phoenix-3.14.1.dist-info}/METADATA +5 -4
- {arize_phoenix-3.13.1.dist-info → arize_phoenix-3.14.1.dist-info}/RECORD +20 -16
- phoenix/config.py +7 -0
- phoenix/core/project.py +0 -1
- phoenix/core/traces.py +1 -1
- phoenix/server/api/routers/evaluation_handler.py +1 -1
- phoenix/server/api/routers/span_handler.py +1 -1
- phoenix/server/api/routers/trace_handler.py +8 -11
- phoenix/server/api/types/Span.py +2 -1
- phoenix/server/app.py +3 -1
- phoenix/server/main.py +30 -1
- phoenix/server/static/index.js +195 -195
- phoenix/storage/__init__.py +0 -0
- phoenix/storage/spanstore/__init__.py +9 -0
- phoenix/storage/spanstore/text_file.py +85 -0
- phoenix/utilities/project.py +13 -0
- phoenix/version.py +1 -1
- {arize_phoenix-3.13.1.dist-info → arize_phoenix-3.14.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-3.13.1.dist-info → arize_phoenix-3.14.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.13.1.dist-info → arize_phoenix-3.14.1.dist-info}/licenses/LICENSE +0 -0
|
File without changes
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import weakref
|
|
2
|
+
from base64 import urlsafe_b64decode, urlsafe_b64encode
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from queue import SimpleQueue
|
|
5
|
+
from threading import Thread
|
|
6
|
+
from typing import Iterator, Optional, Tuple
|
|
7
|
+
|
|
8
|
+
from opentelemetry.proto.trace.v1.trace_pb2 import TracesData
|
|
9
|
+
from typing_extensions import TypeAlias
|
|
10
|
+
|
|
11
|
+
from phoenix.utilities.project import get_project_name
|
|
12
|
+
|
|
13
|
+
_Queue: TypeAlias = "SimpleQueue[Optional[TracesData]]"
|
|
14
|
+
|
|
15
|
+
_END_OF_QUEUE = None
|
|
16
|
+
_DIR_PREFIX = "project."
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TextFileSpanStoreImpl:
|
|
20
|
+
def __init__(self, root: Path) -> None:
|
|
21
|
+
self._root = root
|
|
22
|
+
self._projects = dict(_load_projects(self._root))
|
|
23
|
+
|
|
24
|
+
def save(self, traces_data: TracesData) -> None:
|
|
25
|
+
for resource_spans in traces_data.resource_spans:
|
|
26
|
+
name = get_project_name(resource_spans.resource.attributes)
|
|
27
|
+
if (project := self._projects.get(name)) is None:
|
|
28
|
+
self._projects[name] = project = _Project(name, self._root)
|
|
29
|
+
project.save(TracesData(resource_spans=[resource_spans]))
|
|
30
|
+
|
|
31
|
+
def load(self) -> Iterator[TracesData]:
|
|
32
|
+
queue: _Queue = SimpleQueue()
|
|
33
|
+
Thread(target=self._load_traces_data, args=(queue,)).start()
|
|
34
|
+
while (item := queue.get()) is not _END_OF_QUEUE:
|
|
35
|
+
yield item
|
|
36
|
+
|
|
37
|
+
def _load_traces_data(self, queue: _Queue) -> None:
|
|
38
|
+
"""Load traces data from all projects into the queue"""
|
|
39
|
+
for project in self._projects.values():
|
|
40
|
+
project.load(queue)
|
|
41
|
+
queue.put(_END_OF_QUEUE)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class _Project:
|
|
45
|
+
def __init__(self, name: str, root: Path) -> None:
|
|
46
|
+
self._path = root / f"project.{_b64encode(name.encode())}"
|
|
47
|
+
spans_path = self._path / "spans"
|
|
48
|
+
spans_path.mkdir(parents=True, exist_ok=True)
|
|
49
|
+
self._spans = _Spans(spans_path / "spans.txt")
|
|
50
|
+
|
|
51
|
+
def save(self, traces_data: TracesData) -> None:
|
|
52
|
+
self._spans.save(traces_data)
|
|
53
|
+
|
|
54
|
+
def load(self, queue: _Queue) -> None:
|
|
55
|
+
self._spans.load(queue)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class _Spans:
|
|
59
|
+
def __init__(self, file_path: Path):
|
|
60
|
+
self._path = file_path
|
|
61
|
+
self._file = self._path.open("a")
|
|
62
|
+
weakref.finalize(self, self._file.close)
|
|
63
|
+
|
|
64
|
+
def save(self, traces_data: TracesData) -> None:
|
|
65
|
+
self._file.write(_b64encode(traces_data.SerializeToString()))
|
|
66
|
+
self._file.write("\n")
|
|
67
|
+
|
|
68
|
+
def load(self, queue: _Queue) -> None:
|
|
69
|
+
with self._path.open("r") as f:
|
|
70
|
+
while line := f.readline():
|
|
71
|
+
queue.put(TracesData.FromString(_b64decode(line)))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _load_projects(root: Path) -> Iterator[Tuple[str, _Project]]:
|
|
75
|
+
for dir_path in root.glob(f"{_DIR_PREFIX}*/"):
|
|
76
|
+
name = _b64decode(dir_path.name[len(_DIR_PREFIX) :]).decode()
|
|
77
|
+
yield name, _Project(name, root)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _b64encode(s: bytes) -> str:
|
|
81
|
+
return urlsafe_b64encode(s).decode()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _b64decode(name: str) -> bytes:
|
|
85
|
+
return urlsafe_b64decode(name.encode())
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
from openinference.semconv.resource import ResourceAttributes
|
|
4
|
+
from opentelemetry.proto.common.v1.common_pb2 import KeyValue
|
|
5
|
+
|
|
6
|
+
DEFAULT_PROJECT_NAME = "default"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_project_name(attributes: Iterable[KeyValue]) -> str:
|
|
10
|
+
for kv in attributes:
|
|
11
|
+
if kv.key == ResourceAttributes.PROJECT_NAME and (v := kv.value.string_value):
|
|
12
|
+
return v
|
|
13
|
+
return DEFAULT_PROJECT_NAME
|
phoenix/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "3.
|
|
1
|
+
__version__ = "3.14.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|