Skip to content

Commit 8be9909

Browse files
author
Mike Goitia
committed
add polling
1 parent e9f637c commit 8be9909

File tree

5 files changed

+341
-8
lines changed

5 files changed

+341
-8
lines changed

examples/logging/async_simple_logging.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
tags={"model": "gpt-4o", "feature": "customer-support"},
1111
hallucination_detection=True,
1212
inconsistency_detection=True,
13-
sample_rate=1.0,
13+
hallucination_detection_sample_rate=1.0,
1414
)
1515

1616

@@ -40,6 +40,37 @@ async def main():
4040

4141
print("Log request sent")
4242
print("Log ID: ", log_id)
43+
print("Log created, waiting for detection results...")
44+
45+
# Poll for detection results with a timeout of 60 seconds
46+
# You can adjust timeout and poll_interval based on your needs
47+
detection_results = await quotient_logger.poll_for_detection(
48+
log_id=log_id,
49+
timeout=60, # Wait up to 60 seconds for results
50+
poll_interval=2.0, # Check every 2 seconds
51+
)
52+
53+
if detection_results:
54+
print("\nDetection Results:")
55+
print(f"Status: {detection_results.status}")
56+
print(f"Has hallucination: {detection_results.has_hallucination}")
57+
58+
if detection_results.has_hallucination is not None:
59+
print(f"Has hallucinations: {detection_results.has_hallucination}")
60+
61+
if detection_results.evaluations:
62+
print(f"\nFound {len(detection_results.evaluations)} evaluations")
63+
for i, eval in enumerate(detection_results.evaluations):
64+
print(f"\nEvaluation {i+1}:")
65+
print(f"Sentence: {eval.get('sentence', 'N/A')}")
66+
print(f"Is hallucinated: {eval.get('is_hallucinated', 'N/A')}")
67+
else:
68+
print(
69+
"\nNo detection results received. The detection might still be in progress or failed."
70+
)
71+
print("You can try again later with:")
72+
print(f"await quotient_logger.get_detection(log_id='{log_id}')")
73+
4374
print("Press Enter to exit...")
4475

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

examples/logging/simple_logging.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
quotient = QuotientAI()
44
quotient_logger = quotient.logger.init(
55
# Required
6-
app_name="test-id-create",
6+
app_name="my-app",
77
environment="dev",
88
# dynamic labels for slicing/dicing analytics e.g. by customer, feature, etc
99
tags={"model": "gpt-4o", "feature": "customer-support"},
1010
hallucination_detection=True,
1111
inconsistency_detection=True,
12+
hallucination_detection_sample_rate=1.0,
1213
)
1314

1415
# Mock retrieved documents
@@ -35,5 +36,33 @@
3536
)
3637

3738
print("Log ID: ", log_id)
39+
print("Log created, waiting for detection results...")
3840

39-
print("Log created")
41+
# Poll for detection results with a timeout of 60 seconds
42+
# You can adjust timeout and poll_interval based on your needs
43+
detection_results = quotient_logger.poll_for_detection(
44+
log_id=log_id,
45+
timeout=60, # Wait up to 60 seconds for results
46+
poll_interval=2.0, # Check every 2 seconds
47+
)
48+
49+
if detection_results:
50+
print("\nDetection Results:")
51+
print(f"Status: {detection_results.status}")
52+
print(f"Has hallucination: {detection_results.has_hallucination}")
53+
54+
if detection_results.has_hallucination is not None:
55+
print(f"Has hallucinations: {detection_results.has_hallucination}")
56+
57+
if detection_results.evaluations:
58+
print(f"\nFound {len(detection_results.evaluations)} evaluations")
59+
for i, eval in enumerate(detection_results.evaluations):
60+
print(f"\nEvaluation {i+1}:")
61+
print(f"Sentence: {eval.get('sentence', 'N/A')}")
62+
print(f"Is hallucinated: {eval.get('is_hallucinated', 'N/A')}")
63+
else:
64+
print(
65+
"\nNo detection results received. The detection might still be in progress or failed."
66+
)
67+
print("You can try again later with:")
68+
print(f"quotient_logger.get_detection(log_id='{log_id}')")

quotientai/async_client.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,37 @@ async def log(
308308
return log_id
309309
return None
310310

311+
async def poll_for_detection(
312+
self, log_id: str, timeout: int = 300, poll_interval: float = 2.0
313+
):
314+
"""
315+
Get Detection results for a log asynchronously.
316+
317+
This method polls the Detection endpoint until the results are ready or the timeout is reached.
318+
319+
Args:
320+
log_id: The ID of the log to get Detection results for
321+
timeout: Maximum time to wait for results in seconds (default: 300s/5min)
322+
poll_interval: How often to poll the API in seconds (default: 2s)
323+
324+
Returns:
325+
Log object with Detection results if successful, None otherwise
326+
"""
327+
if not self._configured:
328+
logger.error(
329+
f"Logger is not configured. Please call init() before getting Detection results."
330+
)
331+
return None
332+
333+
if not log_id:
334+
logger.error("Log ID is required for Detection")
335+
return None
336+
337+
# Call the underlying resource method
338+
return await self.logs_resource.poll_for_detection(
339+
log_id, timeout, poll_interval
340+
)
341+
311342

312343
class AsyncQuotientAI:
313344
"""

quotientai/client.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from datetime import datetime, timezone
2-
import uuid
31
import json
42
import os
53
import random
@@ -310,6 +308,35 @@ def log(
310308
else:
311309
return None
312310

311+
def poll_for_detection(
312+
self, log_id: str, timeout: int = 300, poll_interval: float = 2.0
313+
):
314+
"""
315+
Get Detection results for a log.
316+
317+
This method polls the Detection endpoint until the results are ready or the timeout is reached.
318+
319+
Args:
320+
log_id: The ID of the log to get Detection results for
321+
timeout: Maximum time to wait for results in seconds (default: 300s/5min)
322+
poll_interval: How often to poll the API in seconds (default: 2s)
323+
324+
Returns:
325+
Log object with Detection results if successful, None otherwise
326+
"""
327+
if not self._configured:
328+
logger.error(
329+
f"Logger is not configured. Please call init() before getting Detection results."
330+
)
331+
return None
332+
333+
if not log_id:
334+
logger.error("Log ID is required for Detection")
335+
return None
336+
337+
# Call the underlying resource method
338+
return self.logs_resource.poll_for_detection(log_id, timeout, poll_interval)
339+
313340

314341
class QuotientAI:
315342
"""

0 commit comments

Comments
 (0)