divi 0.0.1b0__py3-none-any.whl → 0.0.1b2__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.
- divi/README.md +3 -0
- divi/__init__.py +3 -4
- divi/decorators/obs_openai.py +7 -6
- divi/decorators/observable.py +6 -1
- divi/evaluation/__init__.py +2 -2
- divi/evaluation/evaluator.py +20 -6
- divi/signals/span.py +5 -0
- divi/signals/trace.py +5 -0
- {divi-0.0.1b0.dist-info → divi-0.0.1b2.dist-info}/METADATA +1 -1
- {divi-0.0.1b0.dist-info → divi-0.0.1b2.dist-info}/RECORD +12 -11
- {divi-0.0.1b0.dist-info → divi-0.0.1b2.dist-info}/WHEEL +0 -0
- {divi-0.0.1b0.dist-info → divi-0.0.1b2.dist-info}/licenses/LICENSE +0 -0
divi/README.md
ADDED
divi/__init__.py
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
from typing import Optional
|
2
2
|
|
3
3
|
from .decorators import obs_openai, observable
|
4
|
-
from .evaluation import Evaluator
|
4
|
+
from .evaluation import Evaluator
|
5
5
|
from .services import Auth, Core, DataPark
|
6
6
|
from .session import Session
|
7
|
-
from .signals import Kind
|
8
7
|
|
9
8
|
name: str = "divi"
|
10
9
|
|
@@ -14,5 +13,5 @@ _auth: Optional[Auth] = None
|
|
14
13
|
_datapark: Optional[DataPark] = None
|
15
14
|
_evaluator: Optional[Evaluator] = None
|
16
15
|
|
17
|
-
__version__ = "0.0.
|
18
|
-
__all__ = ["obs_openai", "observable"
|
16
|
+
__version__ = "0.0.1b2"
|
17
|
+
__all__ = ["obs_openai", "observable"]
|
divi/decorators/obs_openai.py
CHANGED
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, TypeVar, Union
|
|
5
5
|
from typing_extensions import Optional
|
6
6
|
|
7
7
|
from divi.decorators.observable import observable
|
8
|
+
from divi.evaluation.evaluator import EvaluatorConfig
|
8
9
|
from divi.evaluation.scores import Score
|
9
10
|
from divi.signals.span import Kind
|
10
11
|
from divi.utils import is_async
|
@@ -19,10 +20,13 @@ def _get_observable_create(
|
|
19
20
|
create: Callable,
|
20
21
|
name: Optional[str] = None,
|
21
22
|
scores: Optional[list[Score]] = None,
|
23
|
+
eval: Optional[EvaluatorConfig] = None,
|
22
24
|
) -> Callable:
|
23
25
|
@functools.wraps(create)
|
24
26
|
def observable_create(*args, stream: bool = False, **kwargs):
|
25
|
-
decorator = observable(
|
27
|
+
decorator = observable(
|
28
|
+
kind=Kind.llm, name=name, scores=scores, eval=eval
|
29
|
+
)
|
26
30
|
return decorator(create)(*args, stream=stream, **kwargs)
|
27
31
|
|
28
32
|
# TODO Async Observable Create
|
@@ -33,16 +37,13 @@ def obs_openai(
|
|
33
37
|
client: C,
|
34
38
|
name: Optional[str] = "Agent",
|
35
39
|
scores: Optional[list[Score]] = None,
|
40
|
+
eval: Optional[EvaluatorConfig] = None,
|
36
41
|
) -> C:
|
37
42
|
"""Make OpenAI client observable."""
|
38
43
|
client.chat.completions.create = _get_observable_create(
|
39
44
|
client.chat.completions.create,
|
40
45
|
name=name,
|
41
46
|
scores=scores,
|
42
|
-
|
43
|
-
client.completions.create = _get_observable_create(
|
44
|
-
client.completions.create,
|
45
|
-
name=name,
|
46
|
-
scores=scores,
|
47
|
+
eval=eval,
|
47
48
|
)
|
48
49
|
return client
|
divi/decorators/observable.py
CHANGED
@@ -15,6 +15,7 @@ from typing import (
|
|
15
15
|
|
16
16
|
from divi.decorators.observe import observe
|
17
17
|
from divi.evaluation.evaluate import evaluate_scores
|
18
|
+
from divi.evaluation.evaluator import EvaluatorConfig
|
18
19
|
from divi.evaluation.scores import Score
|
19
20
|
from divi.session import SessionExtra
|
20
21
|
from divi.signals.span import Kind, Span
|
@@ -43,6 +44,7 @@ def observable(
|
|
43
44
|
*,
|
44
45
|
name: Optional[str] = None,
|
45
46
|
scores: Optional[list[Score]] = None,
|
47
|
+
eval: Optional[EvaluatorConfig] = None,
|
46
48
|
metadata: Optional[Mapping[str, Any]] = None,
|
47
49
|
) -> Callable[[Callable[P, R]], WithSessionExtra[P, R]]: ...
|
48
50
|
|
@@ -56,6 +58,7 @@ def observable(
|
|
56
58
|
name = kwargs.pop("name", None)
|
57
59
|
metadata = kwargs.pop("metadata", None)
|
58
60
|
scores: list[Score] = kwargs.pop("scores", None)
|
61
|
+
eval: EvaluatorConfig = kwargs.pop("eval", None)
|
59
62
|
|
60
63
|
def decorator(func):
|
61
64
|
@functools.wraps(func)
|
@@ -78,7 +81,9 @@ def observable(
|
|
78
81
|
|
79
82
|
# 3. evaluate the scores if they are provided
|
80
83
|
messages = kwargs.get("messages", [])
|
81
|
-
evaluate_scores(
|
84
|
+
evaluate_scores(
|
85
|
+
messages, outputs=result, scores=scores, config=eval
|
86
|
+
)
|
82
87
|
|
83
88
|
return result
|
84
89
|
|
divi/evaluation/__init__.py
CHANGED
divi/evaluation/evaluator.py
CHANGED
@@ -13,8 +13,9 @@ from divi.evaluation.scores import Score
|
|
13
13
|
class EvaluatorConfig:
|
14
14
|
def __init__(
|
15
15
|
self,
|
16
|
-
model: str = "gpt-
|
16
|
+
model: str = "gpt-4o",
|
17
17
|
temperature: float = 0.5,
|
18
|
+
n_rounds: int = 5,
|
18
19
|
max_concurrency: int = 10,
|
19
20
|
api_key: Optional[str] = None,
|
20
21
|
base_url: Optional[str] = None,
|
@@ -23,6 +24,7 @@ class EvaluatorConfig:
|
|
23
24
|
self.api_key = api_key
|
24
25
|
self.base_url = base_url
|
25
26
|
self.temperature = temperature
|
27
|
+
self.n_rounds = n_rounds
|
26
28
|
self.max_concurrency = max_concurrency
|
27
29
|
|
28
30
|
|
@@ -123,7 +125,11 @@ class Evaluator:
|
|
123
125
|
return aggregated_results
|
124
126
|
|
125
127
|
def evaluate_sync(
|
126
|
-
self,
|
128
|
+
self,
|
129
|
+
target: str,
|
130
|
+
conversation: str,
|
131
|
+
scores: list[Score],
|
132
|
+
n_rounds: Optional[int] = None,
|
127
133
|
) -> List[EvaluationScore]:
|
128
134
|
with concurrent.futures.ThreadPoolExecutor(
|
129
135
|
max_workers=self.config.max_concurrency
|
@@ -132,7 +138,7 @@ class Evaluator:
|
|
132
138
|
executor.submit(
|
133
139
|
self._sync_evaluate_once, target, conversation, score
|
134
140
|
)
|
135
|
-
for _ in range(n_rounds)
|
141
|
+
for _ in range(n_rounds if n_rounds else self.config.n_rounds)
|
136
142
|
for score in scores
|
137
143
|
]
|
138
144
|
evaluations = [
|
@@ -143,7 +149,11 @@ class Evaluator:
|
|
143
149
|
)
|
144
150
|
|
145
151
|
async def evaluate_async(
|
146
|
-
self,
|
152
|
+
self,
|
153
|
+
target: str,
|
154
|
+
conversation: str,
|
155
|
+
scores: list[Score],
|
156
|
+
n_rounds: Optional[int] = None,
|
147
157
|
) -> List[EvaluationScore]:
|
148
158
|
semaphore = asyncio.Semaphore(self.config.max_concurrency)
|
149
159
|
|
@@ -153,7 +163,11 @@ class Evaluator:
|
|
153
163
|
target, conversation, score
|
154
164
|
)
|
155
165
|
|
156
|
-
tasks = [
|
166
|
+
tasks = [
|
167
|
+
sem_task(score)
|
168
|
+
for _ in range(n_rounds if n_rounds else self.config.n_rounds)
|
169
|
+
for score in scores
|
170
|
+
]
|
157
171
|
evaluations = await asyncio.gather(*tasks)
|
158
172
|
return self._aggregate_results(
|
159
173
|
[e for e in evaluations if e is not None]
|
@@ -164,7 +178,7 @@ class Evaluator:
|
|
164
178
|
target: str,
|
165
179
|
conversation: str,
|
166
180
|
scores: list[Score],
|
167
|
-
n_rounds: int =
|
181
|
+
n_rounds: Optional[int] = None,
|
168
182
|
mode: Literal["sync", "async"] = "sync",
|
169
183
|
) -> List[EvaluationScore]:
|
170
184
|
if mode == "async":
|
divi/signals/span.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import atexit
|
1
2
|
import os
|
2
3
|
import time
|
3
4
|
from enum import Enum
|
@@ -62,6 +63,8 @@ class Span:
|
|
62
63
|
"""Start the span by recording the current time in nanoseconds."""
|
63
64
|
self.start_time_unix_nano = time.time_ns()
|
64
65
|
self.upsert_span()
|
66
|
+
# Register the end method to be called at exit
|
67
|
+
atexit.register(self.end)
|
65
68
|
|
66
69
|
def end(self):
|
67
70
|
"""End the span by recording the end time in nanoseconds."""
|
@@ -69,6 +72,8 @@ class Span:
|
|
69
72
|
raise ValueError("Span must be started before ending.")
|
70
73
|
self.end_time_unix_nano = time.time_ns()
|
71
74
|
self.upsert_span()
|
75
|
+
# Unregister the end method
|
76
|
+
atexit.unregister(self.end)
|
72
77
|
|
73
78
|
def _add_node(self, trace_id: UUID4, parent_id: Optional[bytes] = None):
|
74
79
|
"""Add node for obs tree."""
|
divi/signals/trace.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import atexit
|
1
2
|
from datetime import UTC, datetime
|
2
3
|
from typing import Optional
|
3
4
|
from uuid import uuid4
|
@@ -63,6 +64,8 @@ class Trace:
|
|
63
64
|
"""Start the trace by recording the current time in nanoseconds."""
|
64
65
|
self.start_time = datetime.now(UTC).isoformat()
|
65
66
|
self.upsert_trace()
|
67
|
+
# Register the end method to be called on exit
|
68
|
+
atexit.register(self.end)
|
66
69
|
|
67
70
|
def end(self):
|
68
71
|
"""End the trace by recording the end time in nanoseconds."""
|
@@ -70,6 +73,8 @@ class Trace:
|
|
70
73
|
raise ValueError("Span must be started before ending.")
|
71
74
|
self.end_time = datetime.now(UTC).isoformat()
|
72
75
|
self.upsert_trace()
|
76
|
+
# Unregister the end method to prevent multiple calls
|
77
|
+
atexit.unregister(self.end)
|
73
78
|
|
74
79
|
def upsert_trace(self):
|
75
80
|
"""Upsert trace with datapark."""
|
@@ -1,13 +1,14 @@
|
|
1
|
-
divi/
|
1
|
+
divi/README.md,sha256=hdw10Mkebd1SGMeA3tPJtlOwbWZzuQ8J-N9YPEHGuXg,67
|
2
|
+
divi/__init__.py,sha256=FNz-nbMRHLhT-JWowhQTK7zMajy2XY0TFPD3Jjar1sw,436
|
2
3
|
divi/utils.py,sha256=fXkjoyo_Lh8AZliKICOP460m0czUcNQjcEcceJbaOVA,1439
|
3
4
|
divi/decorators/__init__.py,sha256=HkyWdC1ctTsVFucCWCkj57JB4NmwONus1d2S2dUbvs4,110
|
4
5
|
divi/decorators/collect.py,sha256=5iUxAnbHYx4ISkFg64IK_4miGdrWgbOXLJxKz8lGIv8,1074
|
5
|
-
divi/decorators/obs_openai.py,sha256=
|
6
|
-
divi/decorators/observable.py,sha256=
|
6
|
+
divi/decorators/obs_openai.py,sha256=eJkPL7T9ribA8Utl8RLvVsp1dRKbS3-Q4vwDfPz16Sg,1414
|
7
|
+
divi/decorators/observable.py,sha256=orDNCP1_uOTwgg71lg2c0qXOv6DtcxufRzuQZqXOrH4,2483
|
7
8
|
divi/decorators/observe.py,sha256=I2RVsp2WQep6iTLSxkAlMP8wiRsSYiiYrxR2hJzPxcI,1211
|
8
|
-
divi/evaluation/__init__.py,sha256=
|
9
|
+
divi/evaluation/__init__.py,sha256=SVu4tYZLgx4juEa1JtkXGcwB_Xuwvh60lbVhYKMseQo,129
|
9
10
|
divi/evaluation/evaluate.py,sha256=lVMCw5vHGa5sJvUyhVDZ9m3Sgl4baCjWhw2OKazhvgM,1861
|
10
|
-
divi/evaluation/evaluator.py,sha256=
|
11
|
+
divi/evaluation/evaluator.py,sha256=D1s6upIOiGTjf24WAQfygYYUI8Lcc65vRgJ2wW2_3Uo,6108
|
11
12
|
divi/evaluation/prompts.py,sha256=4oL8K8X2-zdmTDuAetc53o7Ys_vph-eWYhPmvRKYAng,960
|
12
13
|
divi/evaluation/scores.py,sha256=ZgSxfve-ZivX3WU4TGcgPOSpUQVMbG5a15IQNPeq_bQ,173
|
13
14
|
divi/proto/common/v1/common.proto,sha256=Rx8wr0_tOtQ1NseTMnsav4ApD1MDALzQDBA2IvLRTU0,1775
|
@@ -43,9 +44,9 @@ divi/session/session.py,sha256=QxtEezI447PbtKG2U6cxL1ACae55e8nFfTufAY8pEYI,811
|
|
43
44
|
divi/session/setup.py,sha256=rC1QdCxpdCOaRXmcLEQs4Yuu5UC_aRzKSaqWRPJN4Og,1390
|
44
45
|
divi/session/teardown.py,sha256=YiBz_3yCiljMFEofZ60VmRL5sb8WA5GT7EYF8nFznZ4,133
|
45
46
|
divi/signals/__init__.py,sha256=wfSkkCwkRsFP4aLj8aGHk_k6Y50P5yN44WWlO3XyW18,43
|
46
|
-
divi/signals/span.py,sha256=
|
47
|
-
divi/signals/trace.py,sha256=
|
48
|
-
divi-0.0.
|
49
|
-
divi-0.0.
|
50
|
-
divi-0.0.
|
51
|
-
divi-0.0.
|
47
|
+
divi/signals/span.py,sha256=AQ24C8EKzGceryybX0rBe9B0z43kKaULdR6eOeOCtno,2804
|
48
|
+
divi/signals/trace.py,sha256=US_M2CAYNGUhEa5pppRPJN8dfNA5owgHMFDK2AOrFXA,2345
|
49
|
+
divi-0.0.1b2.dist-info/METADATA,sha256=IS0W_tN3EECkWRlX18GiUtX2idT3lYS2sAF2Z4jmoKA,493
|
50
|
+
divi-0.0.1b2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
51
|
+
divi-0.0.1b2.dist-info/licenses/LICENSE,sha256=5OJuZ4wMMEV0DgF0tofhAlS_KLkaUsZwwwDS2U_GwQ0,1063
|
52
|
+
divi-0.0.1b2.dist-info/RECORD,,
|
File without changes
|
File without changes
|