44
55try :
66 import openai
7- import openai .resources
87except ImportError :
98 raise ModuleNotFoundError ("Please install the OpenAI SDK to use this feature: 'pip install openai'" )
109
@@ -29,14 +28,37 @@ def __init__(self, posthog_client: PostHogClient, **kwargs):
2928 """
3029 super ().__init__ (** kwargs )
3130 self ._ph_client = posthog_client
32- self .chat = WrappedChat (self )
33- self .embeddings = WrappedEmbeddings (self )
34- self .beta = WrappedBeta (self )
35- self .responses = WrappedResponses (self )
3631
32+ # Store original objects after parent initialization (only if they exist)
33+ self ._original_chat = getattr (self , "chat" , None )
34+ self ._original_embeddings = getattr (self , "embeddings" , None )
35+ self ._original_beta = getattr (self , "beta" , None )
36+ self ._original_responses = getattr (self , "responses" , None )
3737
38- class WrappedResponses (openai .resources .responses .Responses ):
39- _client : OpenAI
38+ # Replace with wrapped versions (only if originals exist)
39+ if self ._original_chat is not None :
40+ self .chat = WrappedChat (self , self ._original_chat )
41+
42+ if self ._original_embeddings is not None :
43+ self .embeddings = WrappedEmbeddings (self , self ._original_embeddings )
44+
45+ if self ._original_beta is not None :
46+ self .beta = WrappedBeta (self , self ._original_beta )
47+
48+ if self ._original_responses is not None :
49+ self .responses = WrappedResponses (self , self ._original_responses )
50+
51+
52+ class WrappedResponses :
53+ """Wrapper for OpenAI responses that tracks usage in PostHog."""
54+
55+ def __init__ (self , client : OpenAI , original_responses ):
56+ self ._client = client
57+ self ._original = original_responses
58+
59+ def __getattr__ (self , name ):
60+ """Fallback to original responses object for any methods we don't explicitly handle."""
61+ return getattr (self ._original , name )
4062
4163 def create (
4264 self ,
@@ -69,7 +91,7 @@ def create(
6991 posthog_privacy_mode ,
7092 posthog_groups ,
7193 self ._client .base_url ,
72- super () .create ,
94+ self . _original .create ,
7395 ** kwargs ,
7496 )
7597
@@ -85,7 +107,7 @@ def _create_streaming(
85107 start_time = time .time ()
86108 usage_stats : Dict [str , int ] = {}
87109 final_content = []
88- response = super () .create (** kwargs )
110+ response = self . _original .create (** kwargs )
89111
90112 def generator ():
91113 nonlocal usage_stats
@@ -195,16 +217,32 @@ def _capture_streaming_event(
195217 )
196218
197219
198- class WrappedChat (openai .resources .chat .Chat ):
199- _client : OpenAI
220+ class WrappedChat :
221+ """Wrapper for OpenAI chat that tracks usage in PostHog."""
222+
223+ def __init__ (self , client : OpenAI , original_chat ):
224+ self ._client = client
225+ self ._original = original_chat
226+
227+ def __getattr__ (self , name ):
228+ """Fallback to original chat object for any methods we don't explicitly handle."""
229+ return getattr (self ._original , name )
200230
201231 @property
202232 def completions (self ):
203- return WrappedCompletions (self ._client )
233+ return WrappedCompletions (self ._client , self ._original .completions )
234+
204235
236+ class WrappedCompletions :
237+ """Wrapper for OpenAI chat completions that tracks usage in PostHog."""
205238
206- class WrappedCompletions (openai .resources .chat .completions .Completions ):
207- _client : OpenAI
239+ def __init__ (self , client : OpenAI , original_completions ):
240+ self ._client = client
241+ self ._original = original_completions
242+
243+ def __getattr__ (self , name ):
244+ """Fallback to original completions object for any methods we don't explicitly handle."""
245+ return getattr (self ._original , name )
208246
209247 def create (
210248 self ,
@@ -237,7 +275,7 @@ def create(
237275 posthog_privacy_mode ,
238276 posthog_groups ,
239277 self ._client .base_url ,
240- super () .create ,
278+ self . _original .create ,
241279 ** kwargs ,
242280 )
243281
@@ -257,7 +295,7 @@ def _create_streaming(
257295 if "stream_options" not in kwargs :
258296 kwargs ["stream_options" ] = {}
259297 kwargs ["stream_options" ]["include_usage" ] = True
260- response = super () .create (** kwargs )
298+ response = self . _original .create (** kwargs )
261299
262300 def generator ():
263301 nonlocal usage_stats
@@ -383,8 +421,16 @@ def _capture_streaming_event(
383421 )
384422
385423
386- class WrappedEmbeddings (openai .resources .embeddings .Embeddings ):
387- _client : OpenAI
424+ class WrappedEmbeddings :
425+ """Wrapper for OpenAI embeddings that tracks usage in PostHog."""
426+
427+ def __init__ (self , client : OpenAI , original_embeddings ):
428+ self ._client = client
429+ self ._original = original_embeddings
430+
431+ def __getattr__ (self , name ):
432+ """Fallback to original embeddings object for any methods we don't explicitly handle."""
433+ return getattr (self ._original , name )
388434
389435 def create (
390436 self ,
@@ -402,6 +448,8 @@ def create(
402448 posthog_distinct_id: Optional ID to associate with the usage event.
403449 posthog_trace_id: Optional trace UUID for linking events.
404450 posthog_properties: Optional dictionary of extra properties to include in the event.
451+ posthog_privacy_mode: Whether to anonymize the input and output.
452+ posthog_groups: Optional dictionary of groups to associate with the event.
405453 **kwargs: Any additional parameters for the OpenAI Embeddings API.
406454
407455 Returns:
@@ -411,7 +459,7 @@ def create(
411459 posthog_trace_id = str (uuid .uuid4 ())
412460
413461 start_time = time .time ()
414- response = super () .create (** kwargs )
462+ response = self . _original .create (** kwargs )
415463 end_time = time .time ()
416464
417465 # Extract usage statistics if available
@@ -452,24 +500,48 @@ def create(
452500 return response
453501
454502
455- class WrappedBeta (openai .resources .beta .Beta ):
456- _client : OpenAI
503+ class WrappedBeta :
504+ """Wrapper for OpenAI beta features that tracks usage in PostHog."""
505+
506+ def __init__ (self , client : OpenAI , original_beta ):
507+ self ._client = client
508+ self ._original = original_beta
509+
510+ def __getattr__ (self , name ):
511+ """Fallback to original beta object for any methods we don't explicitly handle."""
512+ return getattr (self ._original , name )
457513
458514 @property
459515 def chat (self ):
460- return WrappedBetaChat (self ._client )
516+ return WrappedBetaChat (self ._client , self . _original . chat )
461517
462518
463- class WrappedBetaChat (openai .resources .beta .chat .Chat ):
464- _client : OpenAI
519+ class WrappedBetaChat :
520+ """Wrapper for OpenAI beta chat that tracks usage in PostHog."""
521+
522+ def __init__ (self , client : OpenAI , original_beta_chat ):
523+ self ._client = client
524+ self ._original = original_beta_chat
525+
526+ def __getattr__ (self , name ):
527+ """Fallback to original beta chat object for any methods we don't explicitly handle."""
528+ return getattr (self ._original , name )
465529
466530 @property
467531 def completions (self ):
468- return WrappedBetaCompletions (self ._client )
532+ return WrappedBetaCompletions (self ._client , self ._original .completions )
533+
534+
535+ class WrappedBetaCompletions :
536+ """Wrapper for OpenAI beta chat completions that tracks usage in PostHog."""
469537
538+ def __init__ (self , client : OpenAI , original_beta_completions ):
539+ self ._client = client
540+ self ._original = original_beta_completions
470541
471- class WrappedBetaCompletions (openai .resources .beta .chat .completions .Completions ):
472- _client : OpenAI
542+ def __getattr__ (self , name ):
543+ """Fallback to original beta completions object for any methods we don't explicitly handle."""
544+ return getattr (self ._original , name )
473545
474546 def parse (
475547 self ,
@@ -489,6 +561,6 @@ def parse(
489561 posthog_privacy_mode ,
490562 posthog_groups ,
491563 self ._client .base_url ,
492- super () .parse ,
564+ self . _original .parse ,
493565 ** kwargs ,
494566 )
0 commit comments