@@ -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 ()
@@ -56,11 +60,15 @@ def _save_token(self, token: str, expiry: int):
5660 try :
5761 self ._token_path .parent .mkdir (parents = True , exist_ok = True )
5862 except Exception :
59- logger .
error (
f"could not create directory for token. if you see this error please notify us at [email protected] " )
63+ logger .error (
64+ f"could not create directory for token. if you see this error please notify us at [email protected] " 65+ )
6066 return None
6167 # Save to disk
6268 with open (self ._token_path , "w" ) as f :
63- json .dump ({"token" : token , "expires_at" : expiry , "api_key" : self .api_key }, f )
69+ json .dump (
70+ {"token" : token , "expires_at" : expiry , "api_key" : self .api_key }, f
71+ )
6472
6573 def _load_token (self ):
6674 """Load token from disk if available"""
@@ -80,10 +88,10 @@ def _load_token(self):
8088 def _is_token_valid (self ):
8189 """Check if token exists and is not expired"""
8290 self ._load_token ()
83-
91+
8492 if not self .token :
8593 return False
86-
94+
8795 if self .token_api_key != self .api_key :
8896 return False
8997
@@ -210,7 +218,7 @@ def init(
210218 if not (0.0 <= self .sample_rate <= 1.0 ):
211219 logger .error (f"sample_rate must be between 0.0 and 1.0" )
212220 return None
213-
221+
214222 self .hallucination_detection = hallucination_detection
215223 self .inconsistency_detection = inconsistency_detection
216224 self ._configured = True
@@ -242,7 +250,9 @@ async def log(
242250 underlying non_blocking_create function.
243251 """
244252 if not self ._configured :
245- logger .error (f"Logger is not configured. Please call init() before logging." )
253+ logger .error (
254+ f"Logger is not configured. Please call init() before logging."
255+ )
246256 return None
247257
248258 # Merge default tags with any tags provided at log time.
@@ -269,15 +279,19 @@ async def log(
269279 try :
270280 LogDocument (** doc )
271281 except Exception as e :
272- logger .error (f"Invalid document format: Documents must include 'page_content' field and optional 'metadata' object with string keys." )
282+ logger .error (
283+ f"Invalid document format: Documents must include 'page_content' field and optional 'metadata' object with string keys."
284+ )
273285 return None
274286 else :
275287 actual_type = type (doc ).__name__
276- logger .error (f"Invalid document type: Received { actual_type } , but documents must be strings or dictionaries." )
288+ logger .error (
289+ f"Invalid document type: Received { actual_type } , but documents must be strings or dictionaries."
290+ )
277291 return None
278-
292+
279293 if self ._should_sample ():
280- await self .logs_resource .create (
294+ log_id = await self .logs_resource .create (
281295 app_name = self .app_name ,
282296 environment = self .environment ,
283297 user_query = user_query ,
@@ -290,9 +304,40 @@ async def log(
290304 inconsistency_detection = inconsistency_detection ,
291305 hallucination_detection_sample_rate = self .hallucination_detection_sample_rate ,
292306 )
293-
307+ return log_id
294308 return None
295309
310+ async def poll_for_detection (
311+ self , log_id : str , timeout : int = 300 , poll_interval : float = 2.0
312+ ):
313+ """
314+ Get Detection results for a log asynchronously.
315+
316+ This method polls the Detection endpoint until the results are ready or the timeout is reached.
317+
318+ Args:
319+ log_id: The ID of the log to get Detection results for
320+ timeout: Maximum time to wait for results in seconds (default: 300s/5min)
321+ poll_interval: How often to poll the API in seconds (default: 2s)
322+
323+ Returns:
324+ Log object with Detection results if successful, None otherwise
325+ """
326+ if not self ._configured :
327+ logger .error (
328+ f"Logger is not configured. Please call init() before getting Detection results."
329+ )
330+ return None
331+
332+ if not log_id :
333+ logger .error ("Log ID is required for Detection" )
334+ return None
335+
336+ # Call the underlying resource method
337+ return await self .logs_resource .poll_for_detection (
338+ log_id , timeout , poll_interval
339+ )
340+
296341
297342class AsyncQuotientAI :
298343 """
@@ -310,9 +355,11 @@ class AsyncQuotientAI:
310355 def __init__ (self , api_key : Optional [str ] = None ):
311356 self .api_key = api_key or os .environ .get ("QUOTIENT_API_KEY" )
312357 if not self .api_key :
313- logger .error ("could not find API key. either pass api_key to AsyncQuotientAI() or "
358+ logger .error (
359+ "could not find API key. either pass api_key to AsyncQuotientAI() or "
314360 "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" )
361+ f"if you do not have an API key, you can create one at https://app.quotientai.co in your settings page"
362+ )
316363
317364 self ._client = _AsyncQuotientClient (self .api_key )
318365 self .auth = AsyncAuthResource (self ._client )
@@ -331,7 +378,8 @@ def __init__(self, api_key: Optional[str] = None):
331378 except Exception as e :
332379 logger .error (
333380 "If you are seeing this error, please check that your API key is correct.\n "
334- f"If the issue persists, please contact [email protected] \n { traceback .format_exc ()} " )
381+ f"If the issue persists, please contact [email protected] \n { traceback .format_exc ()} " 382+ )
335383 return None
336384
337385 async def evaluate (
@@ -362,9 +410,11 @@ def _validate_parameters(parameters):
362410
363411 invalid_parameters = set (parameters .keys ()) - set (valid_parameters )
364412 if invalid_parameters :
365- logger .error (f"invalid parameters: { ', ' .join (invalid_parameters )} . \n valid parameters are: { ', ' .join (valid_parameters )} " )
413+ logger .error (
414+ f"invalid parameters: { ', ' .join (invalid_parameters )} . \n valid parameters are: { ', ' .join (valid_parameters )} "
415+ )
366416 return None
367-
417+
368418 return parameters
369419
370420 v_parameters = _validate_parameters (parameters )
0 commit comments