11import os
2- from typing import List
2+ from typing import Any , Dict , List , Optional
33
44import httpx
55
1111from quotientai .resources .runs import Run
1212
1313
14-
1514class _BaseQuotientClient (httpx .Client ):
1615 def __init__ (self , api_key : str ):
1716 super ().__init__ (
@@ -25,7 +24,7 @@ def _get(self, path: str) -> dict:
2524 return response
2625
2726 @handle_errors
28- def _post (self , path : str , data : dict = {}) -> dict :
27+ def _post (self , path : str , data : dict = {}, timeout : int = None ) -> dict :
2928 if isinstance (data , dict ):
3029 data = {k : v for k , v in data .items () if v is not None }
3130 elif isinstance (data , list ):
@@ -34,6 +33,7 @@ def _post(self, path: str, data: dict = {}) -> dict:
3433 response = self .post (
3534 url = path ,
3635 json = data ,
36+ timeout = timeout ,
3737 )
3838 return response
3939
@@ -52,6 +52,93 @@ def _delete(self, path: str) -> dict:
5252 return response
5353
5454
55+ class QuotientLogger :
56+ """
57+ Logger interface that wraps the underlying logs resource.
58+ This class handles both configuration (via init) and logging.
59+ """
60+
61+ def __init__ (self , logs_resource ):
62+ self .logs_resource = logs_resource
63+
64+ self .app_name : Optional [str ] = None
65+ self .environment : Optional [str ] = None
66+ self .tags : Dict [str , Any ] = {}
67+ self .hallucination_detection : bool = False
68+ self .inconsistency_detection : bool = False
69+ self ._configured = False
70+
71+ def init (
72+ self ,
73+ * ,
74+ app_name : str ,
75+ environment : str ,
76+ tags : Optional [Dict [str , Any ]] = {},
77+ hallucination_detection : bool = False ,
78+ inconsistency_detection : bool = False ,
79+ ) -> "QuotientLogger" :
80+ """
81+ Configure the logger with the provided parameters and return self.
82+ This method must be called before using log().
83+ """
84+ self .app_name = app_name
85+ self .environment = environment
86+ self .tags = tags or {}
87+ self .hallucination_detection = hallucination_detection
88+ self .inconsistency_detection = inconsistency_detection
89+ self ._configured = True
90+ return self
91+
92+ def log (
93+ self ,
94+ * ,
95+ model_input : str ,
96+ model_output : str ,
97+ documents : List [dict ],
98+ contexts : Optional [List [str ]] = None ,
99+ tags : Optional [Dict [str , Any ]] = {},
100+ hallucination_detection : Optional [bool ] = None ,
101+ inconsistency_detection : Optional [bool ] = None ,
102+ ):
103+ """
104+ Log the model interaction asynchronously.
105+
106+ Merges the default tags (set via init) with any runtime-supplied tags and calls the
107+ underlying non_blocking_create function.
108+ """
109+ if not self ._configured :
110+ raise RuntimeError (
111+ "Logger is not configured. Please call init() before logging."
112+ )
113+
114+ # Merge default tags with any tags provided at log time.
115+ merged_tags = {** self .tags , ** (tags or {})}
116+
117+ # Use the instance variable as the default if not provided
118+ hallucination_detection = (
119+ hallucination_detection
120+ if hallucination_detection is not None
121+ else self .hallucination_detection
122+ )
123+ inconsistency_detection = (
124+ inconsistency_detection
125+ if inconsistency_detection is not None
126+ else self .inconsistency_detection
127+ )
128+
129+ return self .logs_resource .non_blocking_create (
130+ app_name = self .app_name ,
131+ environment = self .environment ,
132+ model_input = model_input ,
133+ model_output = model_output ,
134+ documents = documents ,
135+ contexts = contexts ,
136+ tags = merged_tags ,
137+ hallucination_detection = hallucination_detection ,
138+ inconsistency_detection = inconsistency_detection ,
139+ )
140+
141+
55142class QuotientAI :
56143 """
57144 A client that provides access to the QuotientAI API.
@@ -77,7 +164,10 @@ def __init__(self):
77164 self .models = resources .ModelsResource (_client )
78165 self .runs = resources .RunsResource (_client )
79166 self .metrics = resources .MetricsResource (_client )
167+ self .logs = resources .LogsResource (_client )
80168
169+ # Create an unconfigured logger instance.
170+ self .logger = QuotientLogger (self .logs )
81171
82172 def evaluate (
83173 self ,
0 commit comments