Skip to content

Commit 8ef6327

Browse files
Extends base fern client with eval utilities (#18)
* Release 0.8.6b0 * Evaluation utils for the Humanloop SDK. --------- Co-authored-by: fern-api <115122769+fern-api[bot]@users.noreply.github.com>
1 parent 302cef3 commit 8ef6327

File tree

11 files changed

+809
-168
lines changed

11 files changed

+809
-168
lines changed

.fernignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
# Specify files that shouldn't be modified by Fern
22

3+
src/humanloop/eval_utils.py
4+
src/humanloop/client.py
5+
mypy.ini
6+

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ client.prompts.log(
4141
messages=[{"role": "user", "content": "What really happened at Roswell?"}],
4242
inputs={"person": "Trump"},
4343
created_at=datetime.datetime.fromisoformat(
44-
"2024-07-19 00:29:35.178000+00:00",
44+
"2024-07-18 23:29:35.178000+00:00",
4545
),
4646
provider_latency=6.5931549072265625,
4747
output_message={
@@ -88,7 +88,7 @@ async def main() -> None:
8888
],
8989
inputs={"person": "Trump"},
9090
created_at=datetime.datetime.fromisoformat(
91-
"2024-07-19 00:29:35.178000+00:00",
91+
"2024-07-18 23:29:35.178000+00:00",
9292
),
9393
provider_latency=6.5931549072265625,
9494
output_message={

mypy.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[mypy]
2+
exclude = ^src/humanloop/eval_utils\.py$

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "humanloop"
3-
version = "0.8.5"
3+
version = "0.8.6b0"
44
description = ""
55
readme = "README.md"
66
authors = []

reference.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ client.prompts.log(
5656
messages=[{"role": "user", "content": "What really happened at Roswell?"}],
5757
inputs={"person": "Trump"},
5858
created_at=datetime.datetime.fromisoformat(
59-
"2024-07-19 00:29:35.178000+00:00",
59+
"2024-07-18 23:29:35.178000+00:00",
6060
),
6161
provider_latency=6.5931549072265625,
6262
output_message={
@@ -6258,10 +6258,10 @@ client.flows.log(
62586258
output="The patient is likely experiencing a myocardial infarction. Immediate medical attention is required.",
62596259
trace_status="incomplete",
62606260
start_time=datetime.datetime.fromisoformat(
6261-
"2024-07-08 22:40:35+00:00",
6261+
"2024-07-08 21:40:35+00:00",
62626262
),
62636263
end_time=datetime.datetime.fromisoformat(
6264-
"2024-07-08 22:40:39+00:00",
6264+
"2024-07-08 21:40:39+00:00",
62656265
),
62666266
)
62676267

src/humanloop/base_client.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# This file was auto-generated by Fern from our API Definition.
2+
3+
import typing
4+
from .environment import HumanloopEnvironment
5+
import os
6+
import httpx
7+
from .core.api_error import ApiError
8+
from .core.client_wrapper import SyncClientWrapper
9+
from .prompts.client import PromptsClient
10+
from .tools.client import ToolsClient
11+
from .datasets.client import DatasetsClient
12+
from .evaluators.client import EvaluatorsClient
13+
from .flows.client import FlowsClient
14+
from .directories.client import DirectoriesClient
15+
from .files.client import FilesClient
16+
from .evaluations.client import EvaluationsClient
17+
from .logs.client import LogsClient
18+
from .core.client_wrapper import AsyncClientWrapper
19+
from .prompts.client import AsyncPromptsClient
20+
from .tools.client import AsyncToolsClient
21+
from .datasets.client import AsyncDatasetsClient
22+
from .evaluators.client import AsyncEvaluatorsClient
23+
from .flows.client import AsyncFlowsClient
24+
from .directories.client import AsyncDirectoriesClient
25+
from .files.client import AsyncFilesClient
26+
from .evaluations.client import AsyncEvaluationsClient
27+
from .logs.client import AsyncLogsClient
28+
29+
30+
class BaseHumanloop:
31+
"""
32+
Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
33+
34+
Parameters
35+
----------
36+
base_url : typing.Optional[str]
37+
The base url to use for requests from the client.
38+
39+
environment : HumanloopEnvironment
40+
The environment to use for requests from the client. from .environment import HumanloopEnvironment
41+
42+
43+
44+
Defaults to HumanloopEnvironment.DEFAULT
45+
46+
47+
48+
api_key : typing.Optional[str]
49+
timeout : typing.Optional[float]
50+
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
51+
52+
follow_redirects : typing.Optional[bool]
53+
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
54+
55+
httpx_client : typing.Optional[httpx.Client]
56+
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
57+
58+
Examples
59+
--------
60+
from humanloop import Humanloop
61+
62+
client = Humanloop(
63+
api_key="YOUR_API_KEY",
64+
)
65+
"""
66+
67+
def __init__(
68+
self,
69+
*,
70+
base_url: typing.Optional[str] = None,
71+
environment: HumanloopEnvironment = HumanloopEnvironment.DEFAULT,
72+
api_key: typing.Optional[str] = os.getenv("HUMANLOOP_API_KEY"),
73+
timeout: typing.Optional[float] = None,
74+
follow_redirects: typing.Optional[bool] = True,
75+
httpx_client: typing.Optional[httpx.Client] = None,
76+
):
77+
_defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
78+
if api_key is None:
79+
raise ApiError(
80+
body="The client must be instantiated be either passing in api_key or setting HUMANLOOP_API_KEY"
81+
)
82+
self._client_wrapper = SyncClientWrapper(
83+
base_url=_get_base_url(base_url=base_url, environment=environment),
84+
api_key=api_key,
85+
httpx_client=httpx_client
86+
if httpx_client is not None
87+
else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
88+
if follow_redirects is not None
89+
else httpx.Client(timeout=_defaulted_timeout),
90+
timeout=_defaulted_timeout,
91+
)
92+
self.prompts = PromptsClient(client_wrapper=self._client_wrapper)
93+
self.tools = ToolsClient(client_wrapper=self._client_wrapper)
94+
self.datasets = DatasetsClient(client_wrapper=self._client_wrapper)
95+
self.evaluators = EvaluatorsClient(client_wrapper=self._client_wrapper)
96+
self.flows = FlowsClient(client_wrapper=self._client_wrapper)
97+
self.directories = DirectoriesClient(client_wrapper=self._client_wrapper)
98+
self.files = FilesClient(client_wrapper=self._client_wrapper)
99+
self.evaluations = EvaluationsClient(client_wrapper=self._client_wrapper)
100+
self.logs = LogsClient(client_wrapper=self._client_wrapper)
101+
102+
103+
class AsyncBaseHumanloop:
104+
"""
105+
Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
106+
107+
Parameters
108+
----------
109+
base_url : typing.Optional[str]
110+
The base url to use for requests from the client.
111+
112+
environment : HumanloopEnvironment
113+
The environment to use for requests from the client. from .environment import HumanloopEnvironment
114+
115+
116+
117+
Defaults to HumanloopEnvironment.DEFAULT
118+
119+
120+
121+
api_key : typing.Optional[str]
122+
timeout : typing.Optional[float]
123+
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
124+
125+
follow_redirects : typing.Optional[bool]
126+
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
127+
128+
httpx_client : typing.Optional[httpx.AsyncClient]
129+
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
130+
131+
Examples
132+
--------
133+
from humanloop import AsyncHumanloop
134+
135+
client = AsyncHumanloop(
136+
api_key="YOUR_API_KEY",
137+
)
138+
"""
139+
140+
def __init__(
141+
self,
142+
*,
143+
base_url: typing.Optional[str] = None,
144+
environment: HumanloopEnvironment = HumanloopEnvironment.DEFAULT,
145+
api_key: typing.Optional[str] = os.getenv("HUMANLOOP_API_KEY"),
146+
timeout: typing.Optional[float] = None,
147+
follow_redirects: typing.Optional[bool] = True,
148+
httpx_client: typing.Optional[httpx.AsyncClient] = None,
149+
):
150+
_defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
151+
if api_key is None:
152+
raise ApiError(
153+
body="The client must be instantiated be either passing in api_key or setting HUMANLOOP_API_KEY"
154+
)
155+
self._client_wrapper = AsyncClientWrapper(
156+
base_url=_get_base_url(base_url=base_url, environment=environment),
157+
api_key=api_key,
158+
httpx_client=httpx_client
159+
if httpx_client is not None
160+
else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
161+
if follow_redirects is not None
162+
else httpx.AsyncClient(timeout=_defaulted_timeout),
163+
timeout=_defaulted_timeout,
164+
)
165+
self.prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper)
166+
self.tools = AsyncToolsClient(client_wrapper=self._client_wrapper)
167+
self.datasets = AsyncDatasetsClient(client_wrapper=self._client_wrapper)
168+
self.evaluators = AsyncEvaluatorsClient(client_wrapper=self._client_wrapper)
169+
self.flows = AsyncFlowsClient(client_wrapper=self._client_wrapper)
170+
self.directories = AsyncDirectoriesClient(client_wrapper=self._client_wrapper)
171+
self.files = AsyncFilesClient(client_wrapper=self._client_wrapper)
172+
self.evaluations = AsyncEvaluationsClient(client_wrapper=self._client_wrapper)
173+
self.logs = AsyncLogsClient(client_wrapper=self._client_wrapper)
174+
175+
176+
def _get_base_url(*, base_url: typing.Optional[str] = None, environment: HumanloopEnvironment) -> str:
177+
if base_url is not None:
178+
return base_url
179+
elif environment is not None:
180+
return environment.value
181+
else:
182+
raise Exception("Please pass in either base_url or environment to construct the client")

0 commit comments

Comments
 (0)