Skip to content

Commit e9f637c

Browse files
author
Mike Goitia
committed
Working id create
1 parent 2fe7cac commit e9f637c

File tree

4 files changed

+83
-40
lines changed

4 files changed

+83
-40
lines changed

examples/logging/async_simple_logging.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
import asyncio
33

44
quotient = AsyncQuotientAI()
5-
65
quotient_logger = quotient.logger.init(
76
# Required
8-
app_name="my-app",
7+
app_name="test-id-create",
98
environment="dev",
109
# dynamic labels for slicing/dicing analytics e.g. by customer, feature, etc
1110
tags={"model": "gpt-4o", "feature": "customer-support"},
@@ -19,7 +18,7 @@ async def main():
1918
# Mock retrieved documents
2019
retrieved_documents = [{"page_content": "Sample document"}]
2120

22-
await quotient_logger.log(
21+
log_id = await quotient_logger.log(
2322
user_query="Sample input",
2423
model_output="Sample output",
2524
# Page content from Documents from your retriever used to generate the model output
@@ -40,6 +39,7 @@ async def main():
4039
)
4140

4241
print("Log request sent")
42+
print("Log ID: ", log_id)
4343
print("Press Enter to exit...")
4444

4545
# Use asyncio's run_in_executor to handle blocking input() call

examples/logging/simple_logging.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
quotient = QuotientAI()
44
quotient_logger = quotient.logger.init(
55
# Required
6-
app_name="my-app",
6+
app_name="test-id-create",
77
environment="dev",
88
# dynamic labels for slicing/dicing analytics e.g. by customer, feature, etc
99
tags={"model": "gpt-4o", "feature": "customer-support"},
@@ -14,7 +14,7 @@
1414
# Mock retrieved documents
1515
retrieved_documents = [{"page_content": "Sample document"}]
1616

17-
quotient_logger.log(
17+
log_id = quotient_logger.log(
1818
user_query="Sample input",
1919
model_output="Sample output",
2020
# Page content from Documents from your retriever used to generate the model output
@@ -34,4 +34,6 @@
3434
tags={"model": "gpt-4o-mini", "feature": "customer-support"},
3535
)
3636

37+
print("Log ID: ", log_id)
38+
3739
print("Log created")

quotientai/async_client.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ def __init__(self, api_key: str):
3232
self.token = None
3333
self.token_expiry = 0
3434
self.token_api_key = None
35-
self._token_path = token_dir / ".quotient" / f"{api_key[-6:]+'_' if api_key else ''}auth_token.json"
35+
self._token_path = (
36+
token_dir
37+
/ ".quotient"
38+
/ f"{api_key[-6:]+'_' if api_key else ''}auth_token.json"
39+
)
3640

3741
# Try to load existing token
3842
self._load_token()
@@ -43,7 +47,8 @@ def __init__(self, api_key: str):
4347
)
4448

4549
super().__init__(
46-
base_url="https://api.quotientai.co/api/v1",
50+
# base_url="https://api.quotientai.co/api/v1",
51+
base_url="http://127.0.0.1:8082/api/v1",
4752
headers={"Authorization": auth_header},
4853
)
4954

@@ -56,11 +61,15 @@ def _save_token(self, token: str, expiry: int):
5661
try:
5762
self._token_path.parent.mkdir(parents=True, exist_ok=True)
5863
except Exception:
59-
logger.error(f"could not create directory for token. if you see this error please notify us at contact@quotientai.co")
64+
logger.error(
65+
f"could not create directory for token. if you see this error please notify us at contact@quotientai.co"
66+
)
6067
return None
6168
# Save to disk
6269
with open(self._token_path, "w") as f:
63-
json.dump({"token": token, "expires_at": expiry, "api_key": self.api_key}, f)
70+
json.dump(
71+
{"token": token, "expires_at": expiry, "api_key": self.api_key}, f
72+
)
6473

6574
def _load_token(self):
6675
"""Load token from disk if available"""
@@ -80,10 +89,10 @@ def _load_token(self):
8089
def _is_token_valid(self):
8190
"""Check if token exists and is not expired"""
8291
self._load_token()
83-
92+
8493
if not self.token:
8594
return False
86-
95+
8796
if self.token_api_key != self.api_key:
8897
return False
8998

@@ -210,7 +219,7 @@ def init(
210219
if not (0.0 <= self.sample_rate <= 1.0):
211220
logger.error(f"sample_rate must be between 0.0 and 1.0")
212221
return None
213-
222+
214223
self.hallucination_detection = hallucination_detection
215224
self.inconsistency_detection = inconsistency_detection
216225
self._configured = True
@@ -242,7 +251,9 @@ async def log(
242251
underlying non_blocking_create function.
243252
"""
244253
if not self._configured:
245-
logger.error(f"Logger is not configured. Please call init() before logging.")
254+
logger.error(
255+
f"Logger is not configured. Please call init() before logging."
256+
)
246257
return None
247258

248259
# Merge default tags with any tags provided at log time.
@@ -269,15 +280,19 @@ async def log(
269280
try:
270281
LogDocument(**doc)
271282
except Exception as e:
272-
logger.error(f"Invalid document format: Documents must include 'page_content' field and optional 'metadata' object with string keys.")
283+
logger.error(
284+
f"Invalid document format: Documents must include 'page_content' field and optional 'metadata' object with string keys."
285+
)
273286
return None
274287
else:
275288
actual_type = type(doc).__name__
276-
logger.error(f"Invalid document type: Received {actual_type}, but documents must be strings or dictionaries.")
289+
logger.error(
290+
f"Invalid document type: Received {actual_type}, but documents must be strings or dictionaries."
291+
)
277292
return None
278-
293+
279294
if self._should_sample():
280-
await self.logs_resource.create(
295+
log_id = await self.logs_resource.create(
281296
app_name=self.app_name,
282297
environment=self.environment,
283298
user_query=user_query,
@@ -290,7 +305,7 @@ async def log(
290305
inconsistency_detection=inconsistency_detection,
291306
hallucination_detection_sample_rate=self.hallucination_detection_sample_rate,
292307
)
293-
308+
return log_id
294309
return None
295310

296311

@@ -310,9 +325,11 @@ class AsyncQuotientAI:
310325
def __init__(self, api_key: Optional[str] = None):
311326
self.api_key = api_key or os.environ.get("QUOTIENT_API_KEY")
312327
if not self.api_key:
313-
logger.error("could not find API key. either pass api_key to AsyncQuotientAI() or "
328+
logger.error(
329+
"could not find API key. either pass api_key to AsyncQuotientAI() or "
314330
"set the QUOTIENT_API_KEY environment variable. "
315-
f"if you do not have an API key, you can create one at https://app.quotientai.co in your settings page")
331+
f"if you do not have an API key, you can create one at https://app.quotientai.co in your settings page"
332+
)
316333

317334
self._client = _AsyncQuotientClient(self.api_key)
318335
self.auth = AsyncAuthResource(self._client)
@@ -331,7 +348,8 @@ def __init__(self, api_key: Optional[str] = None):
331348
except Exception as e:
332349
logger.error(
333350
"If you are seeing this error, please check that your API key is correct.\n"
334-
f"If the issue persists, please contact support@quotientai.co\n{traceback.format_exc()}")
351+
f"If the issue persists, please contact support@quotientai.co\n{traceback.format_exc()}"
352+
)
335353
return None
336354

337355
async def evaluate(
@@ -362,9 +380,11 @@ def _validate_parameters(parameters):
362380

363381
invalid_parameters = set(parameters.keys()) - set(valid_parameters)
364382
if invalid_parameters:
365-
logger.error(f"invalid parameters: {', '.join(invalid_parameters)}. \nvalid parameters are: {', '.join(valid_parameters)}")
383+
logger.error(
384+
f"invalid parameters: {', '.join(invalid_parameters)}. \nvalid parameters are: {', '.join(valid_parameters)}"
385+
)
366386
return None
367-
387+
368388
return parameters
369389

370390
v_parameters = _validate_parameters(parameters)

quotientai/client.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from datetime import datetime, timezone
2+
import uuid
13
import json
24
import os
35
import random
@@ -34,7 +36,11 @@ def __init__(self, api_key: str):
3436
self.token = None
3537
self.token_expiry = 0
3638
self.token_api_key = None
37-
self._token_path = token_dir / ".quotient" / f"{api_key[-6:]+'_' if api_key else ''}auth_token.json"
39+
self._token_path = (
40+
token_dir
41+
/ ".quotient"
42+
/ f"{api_key[-6:]+'_' if api_key else ''}auth_token.json"
43+
)
3844

3945
# Try to load existing token
4046
self._load_token()
@@ -45,7 +51,8 @@ def __init__(self, api_key: str):
4551
)
4652

4753
super().__init__(
48-
base_url="https://api.quotientai.co/api/v1",
54+
# base_url="https://api.quotientai.co/api/v1",
55+
base_url="http://127.0.0.1:8082/api/v1",
4956
headers={"Authorization": auth_header},
5057
)
5158

@@ -58,12 +65,16 @@ def _save_token(self, token: str, expiry: int):
5865
try:
5966
self._token_path.parent.mkdir(parents=True, exist_ok=True)
6067
except Exception:
61-
logger.error(f"could not create directory for token. if you see this error please notify us at contact@quotientai.co" )
68+
logger.error(
69+
f"could not create directory for token. if you see this error please notify us at contact@quotientai.co"
70+
)
6271
return None
6372

6473
# Save to disk
6574
with open(self._token_path, "w") as f:
66-
json.dump({"token": token, "expires_at": expiry, "api_key": self.api_key}, f)
75+
json.dump(
76+
{"token": token, "expires_at": expiry, "api_key": self.api_key}, f
77+
)
6778

6879
def _load_token(self):
6980
"""Load token from disk if available"""
@@ -83,10 +94,10 @@ def _load_token(self):
8394
def _is_token_valid(self):
8495
"""Check if token exists and is not expired"""
8596
self._load_token()
86-
97+
8798
if not self.token:
8899
return False
89-
100+
90101
if self.token_api_key != self.api_key:
91102
return False
92103

@@ -241,7 +252,9 @@ def log(
241252
underlying non_blocking_create function.
242253
"""
243254
if not self._configured:
244-
logger.error(f"Logger is not configured. Please call init() before logging.")
255+
logger.error(
256+
f"Logger is not configured. Please call init() before logging."
257+
)
245258
return None
246259

247260
# Merge default tags with any tags provided at log time.
@@ -268,15 +281,18 @@ def log(
268281
try:
269282
LogDocument(**doc)
270283
except Exception as e:
271-
logger.error(f"Invalid document format: Documents must include 'page_content' field and optional 'metadata' object with string keys.")
284+
logger.error(
285+
f"Invalid document format: Documents must include 'page_content' field and optional 'metadata' object with string keys."
286+
)
272287
return None
273288
else:
274289
actual_type = type(doc).__name__
275-
logger.error(f"Invalid document type: Received {actual_type}, but documents must be strings or dictionaries.")
290+
logger.error(
291+
f"Invalid document type: Received {actual_type}, but documents must be strings or dictionaries."
292+
)
276293
return None
277-
278294
if self._should_sample():
279-
self.logs_resource.create(
295+
log_id = self.logs_resource.create(
280296
app_name=self.app_name,
281297
environment=self.environment,
282298
user_query=user_query,
@@ -290,7 +306,7 @@ def log(
290306
hallucination_detection_sample_rate=self.hallucination_detection_sample_rate,
291307
)
292308

293-
return None
309+
return log_id
294310
else:
295311
return None
296312

@@ -308,12 +324,14 @@ class QuotientAI:
308324
will attempt to read from QUOTIENT_API_KEY environment variable.
309325
"""
310326

311-
def __init__(self, api_key: Optional[str] = None):
327+
def __init__(self, api_key: Optional[str] = None):
312328
self.api_key = api_key or os.environ.get("QUOTIENT_API_KEY")
313329
if not self.api_key:
314-
logger.error("could not find API key. either pass api_key to QuotientAI() or "
330+
logger.error(
331+
"could not find API key. either pass api_key to QuotientAI() or "
315332
"set the QUOTIENT_API_KEY environment variable. "
316-
f"if you do not have an API key, you can create one at https://app.quotientai.co in your settings page")
333+
f"if you do not have an API key, you can create one at https://app.quotientai.co in your settings page"
334+
)
317335

318336
_client = _BaseQuotientClient(self.api_key)
319337
self.auth = AuthResource(_client)
@@ -332,7 +350,8 @@ def __init__(self, api_key: Optional[str] = None):
332350
except Exception as e:
333351
logger.error(
334352
"If you are seeing this error, please check that your API key is correct.\n"
335-
f"If the issue persists, please contact support@quotientai.co\n{traceback.format_exc()}")
353+
f"If the issue persists, please contact support@quotientai.co\n{traceback.format_exc()}"
354+
)
336355
return None
337356

338357
def evaluate(
@@ -363,7 +382,9 @@ def _validate_parameters(parameters):
363382

364383
invalid_parameters = set(parameters.keys()) - set(valid_parameters)
365384
if invalid_parameters:
366-
logger.error(f"invalid parameters: {', '.join(invalid_parameters)}. \nvalid parameters are: {', '.join(valid_parameters)}")
385+
logger.error(
386+
f"invalid parameters: {', '.join(invalid_parameters)}. \nvalid parameters are: {', '.join(valid_parameters)}"
387+
)
367388
return None
368389

369390
return parameters

0 commit comments

Comments
 (0)