|
20 | 20 | merge_usage_stats, |
21 | 21 | ) |
22 | 22 | from posthog.ai.gemini.gemini_converter import ( |
| 23 | + extract_gemini_embedding_token_count, |
23 | 24 | extract_gemini_usage_from_chunk, |
24 | 25 | extract_gemini_content_from_chunk, |
25 | 26 | extract_gemini_stop_reason_from_chunk, |
26 | 27 | format_gemini_streaming_output, |
27 | 28 | ) |
| 29 | +from posthog.ai.utils import with_privacy_mode |
28 | 30 | from posthog.ai.sanitization import sanitize_gemini |
29 | 31 | from posthog.client import Client as PostHogClient |
30 | 32 |
|
@@ -432,3 +434,88 @@ async def generate_content_stream( |
432 | 434 | groups, |
433 | 435 | **kwargs, |
434 | 436 | ) |
| 437 | + |
| 438 | + async def embed_content( |
| 439 | + self, |
| 440 | + model: str, |
| 441 | + contents, |
| 442 | + posthog_distinct_id: Optional[str] = None, |
| 443 | + posthog_trace_id: Optional[str] = None, |
| 444 | + posthog_properties: Optional[Dict[str, Any]] = None, |
| 445 | + posthog_privacy_mode: Optional[bool] = None, |
| 446 | + posthog_groups: Optional[Dict[str, Any]] = None, |
| 447 | + **kwargs: Any, |
| 448 | + ): |
| 449 | + """ |
| 450 | + Create embeddings using Gemini's API while tracking usage in PostHog. |
| 451 | +
|
| 452 | + Args: |
| 453 | + model: The model to use (e.g., 'gemini-embedding-001') |
| 454 | + contents: The input content for embedding |
| 455 | + posthog_distinct_id: ID to associate with the usage event (overrides client default) |
| 456 | + posthog_trace_id: Trace UUID for linking events (auto-generated if not provided) |
| 457 | + posthog_properties: Extra properties to include in the event (merged with client defaults) |
| 458 | + posthog_privacy_mode: Whether to redact sensitive information (overrides client default) |
| 459 | + posthog_groups: Group analytics properties (overrides client default) |
| 460 | + **kwargs: Arguments passed to Gemini's embed_content (e.g., config) |
| 461 | + """ |
| 462 | + distinct_id, trace_id, properties, privacy_mode, groups = ( |
| 463 | + self._merge_posthog_params( |
| 464 | + posthog_distinct_id, |
| 465 | + posthog_trace_id, |
| 466 | + posthog_properties, |
| 467 | + posthog_privacy_mode, |
| 468 | + posthog_groups, |
| 469 | + ) |
| 470 | + ) |
| 471 | + |
| 472 | + start_time = time.time() |
| 473 | + response = None |
| 474 | + error = None |
| 475 | + http_status = 200 |
| 476 | + |
| 477 | + try: |
| 478 | + response = await self._client.aio.models.embed_content( |
| 479 | + model=model, contents=contents, **kwargs |
| 480 | + ) |
| 481 | + except Exception as exc: |
| 482 | + error = exc |
| 483 | + http_status = getattr(exc, "status_code", 0) |
| 484 | + finally: |
| 485 | + end_time = time.time() |
| 486 | + latency = end_time - start_time |
| 487 | + |
| 488 | + input_tokens = ( |
| 489 | + extract_gemini_embedding_token_count(response) if response else 0 |
| 490 | + ) |
| 491 | + |
| 492 | + event_properties = { |
| 493 | + "$ai_provider": "gemini", |
| 494 | + "$ai_model": model, |
| 495 | + "$ai_input": with_privacy_mode(self._ph_client, privacy_mode, contents), |
| 496 | + "$ai_http_status": http_status, |
| 497 | + "$ai_input_tokens": input_tokens, |
| 498 | + "$ai_latency": latency, |
| 499 | + "$ai_trace_id": trace_id, |
| 500 | + "$ai_base_url": self._base_url, |
| 501 | + **(properties or {}), |
| 502 | + } |
| 503 | + |
| 504 | + if error: |
| 505 | + event_properties["$ai_is_error"] = True |
| 506 | + event_properties["$ai_error"] = str(error) |
| 507 | + |
| 508 | + if distinct_id is None: |
| 509 | + event_properties["$process_person_profile"] = False |
| 510 | + |
| 511 | + self._ph_client.capture( |
| 512 | + distinct_id=distinct_id or trace_id, |
| 513 | + event="$ai_embedding", |
| 514 | + properties=event_properties, |
| 515 | + groups=groups, |
| 516 | + ) |
| 517 | + |
| 518 | + if error: |
| 519 | + raise error |
| 520 | + |
| 521 | + return response |
0 commit comments