Skip to content

Commit

Permalink
docs: Add Voyage AI integration example notebook (#461)
Browse files Browse the repository at this point in the history
Co-Authored-By: Alex Reibman <[email protected]>
  • Loading branch information
devin-ai-integration[bot] and areibman committed Dec 13, 2024
1 parent 11b83e2 commit 9288655
Show file tree
Hide file tree
Showing 6 changed files with 594 additions and 177 deletions.
160 changes: 92 additions & 68 deletions agentops/llms/providers/voyage.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
"""Voyage AI provider integration for AgentOps."""
import warnings
import sys
import json
import pprint
from typing import Optional, Callable, Dict, Any

import voyageai
from typing import Any, Dict, Optional, Callable
from agentops.llms.providers.instrumented_provider import InstrumentedProvider
from agentops.session import Session
from agentops.event import LLMEvent, ErrorEvent
from agentops.helpers import check_call_stack_for_agent_id, get_ISO_time
from agentops.log_config import logger
from agentops.session import Session
from agentops.singleton import singleton


def _check_python_version() -> None:
"""Check if the current Python version meets Voyage AI requirements."""
if sys.version_info < (3, 9):
warnings.warn(
"Voyage AI SDK requires Python >=3.9. Some functionality may not work correctly.",
UserWarning,
stacklevel=2,
)


@singleton
class VoyageProvider(InstrumentedProvider):
"""Provider for Voyage AI SDK integration.
Expand All @@ -25,96 +37,108 @@ class VoyageProvider(InstrumentedProvider):
original_embed: Optional[Callable] = None
original_embed_async: Optional[Callable] = None

def __init__(self, client):
"""Initialize the Voyage provider with a client instance.
def __init__(self, client=None):
"""Initialize VoyageProvider with optional client."""
super().__init__(client or voyageai)
self._provider_name = "Voyage"
self._client = client or voyageai
self._original_embed = self._client.embed
self._original_embed_async = self._client.aembed
_check_python_version()
self.override()

def embed(self, text: str, **kwargs) -> Dict[str, Any]:
"""Synchronous embedding method.
Args:
client: An initialized Voyage AI client
text: Text to embed
**kwargs: Additional arguments passed to Voyage AI embed method
Returns:
Dict containing embeddings and usage information
"""
super().__init__(client)
self._provider_name = "Voyage"
if not self._check_python_version():
logger.warning("Voyage AI SDK requires Python >=3.9. Some functionality may not work correctly.")
try:
init_timestamp = get_ISO_time()
kwargs["input"] = text
response = self._client.embed(text, **kwargs)
return self.handle_response(response, kwargs, init_timestamp)
except Exception as e:
self._safe_record(None, ErrorEvent(exception=e))
raise

def _check_python_version(self) -> bool:
"""Check if the current Python version meets Voyage AI requirements.
async def aembed(self, text: str, **kwargs) -> Dict[str, Any]:
"""Asynchronous embedding method.
Args:
text: Text to embed
**kwargs: Additional arguments passed to Voyage AI aembed method
Returns:
bool: True if Python version is >= 3.9, False otherwise
Dict containing embeddings and usage information
"""
return sys.version_info >= (3, 9)
try:
init_timestamp = get_ISO_time()
kwargs["input"] = text
response = await self._client.aembed(text, **kwargs)
return self.handle_response(response, kwargs, init_timestamp)
except Exception as e:
self._safe_record(None, ErrorEvent(exception=e))
raise

def handle_response(
self, response: Dict[str, Any], kwargs: Dict[str, Any], init_timestamp: str, session: Optional[Session] = None
) -> Dict[str, Any]:
"""Handle responses for Voyage AI embeddings.
"""Handle response from Voyage AI API calls.
Args:
response: The response from Voyage AI API
kwargs: The keyword arguments used in the API call
init_timestamp: The timestamp when the API call was initiated
session: Optional session for tracking events
response: Raw response from Voyage AI API
kwargs: Original kwargs passed to the API call
init_timestamp: Timestamp when the API call was initiated
session: Optional session for event tracking
Returns:
dict: The original response from the API
Dict containing embeddings and usage information
"""
llm_event = LLMEvent(init_timestamp=init_timestamp, params=kwargs)
if session is not None:
llm_event.session_id = session.session_id

try:
llm_event.returns = response
llm_event.model = kwargs.get("model")
llm_event.prompt = kwargs.get("input")
llm_event.agent_id = check_call_stack_for_agent_id()

# Extract token counts if available
if usage := response.get("usage"):
llm_event.prompt_tokens = usage.get("prompt_tokens")
llm_event.completion_tokens = usage.get("completion_tokens")

llm_event.end_timestamp = get_ISO_time()
self._safe_record(session, llm_event)
except Exception as e:
self._safe_record(session, ErrorEvent(trigger_event=llm_event, exception=e))
kwargs_str = pprint.pformat(kwargs)
response_str = pprint.pformat(response)
logger.warning(
f"Unable to parse response for Voyage call. Skipping upload to AgentOps\n"
f"response:\n {response_str}\n"
f"kwargs:\n {kwargs_str}\n"
# Extract usage information
usage = response.get("usage", {})
tokens = usage.get("prompt_tokens", 0)

# Create LLM event
event = LLMEvent(
provider=self._provider_name,
model=kwargs.get("model", "voyage-01"),
tokens=tokens,
init_timestamp=init_timestamp,
end_timestamp=get_ISO_time(),
prompt=kwargs.get("input", ""),
completion="", # Voyage AI embedding responses don't have completions
cost=0.0, # Cost calculation can be added if needed
session=session,
)

return response
# Track the event
self._safe_record(session, event)

# Return the full response
return response
except Exception as e:
self._safe_record(session, ErrorEvent(exception=e))
raise

def override(self):
"""Override Voyage AI SDK methods with instrumented versions."""
import voyageai

# Store original methods
self.original_embed = voyageai.Client.embed
self.original_embed_async = voyageai.Client.aembed

def patched_embed(self, *args, **kwargs):
init_timestamp = get_ISO_time()
session = kwargs.pop("session", None)
result = self.original_embed(*args, **kwargs)
return self.handle_response(result, kwargs, init_timestamp, session=session)
def patched_embed(*args, **kwargs):
return self.embed(*args, **kwargs)

async def patched_embed_async(self, *args, **kwargs):
init_timestamp = get_ISO_time()
session = kwargs.pop("session", None)
result = await self.original_embed_async(*args, **kwargs)
return self.handle_response(result, kwargs, init_timestamp, session=session)
def patched_embed_async(*args, **kwargs):
return self.aembed(*args, **kwargs)

voyageai.Client.embed = patched_embed
voyageai.Client.aembed = patched_embed_async
self._client.embed = patched_embed
self._client.aembed = patched_embed_async

def undo_override(self):
"""Restore original Voyage AI SDK methods."""
import voyageai

if self.original_embed:
voyageai.Client.embed = self.original_embed
if self.original_embed_async:
voyageai.Client.aembed = self.original_embed_async
self._client.embed = self._original_embed
self._client.aembed = self._original_embed_async
3 changes: 3 additions & 0 deletions docs/v1/examples/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ mode: "wide"
<Card title="REST API" icon="bolt-lightning" href="/v1/examples/restapi">
Create a REST server that performs and observes agent tasks
</Card>
<Card title="Voyage AI" icon={<img src="https://www.github.com/agentops-ai/agentops/blob/main/docs/images/external/voyage/voyage-logo.png?raw=true" alt="Voyage AI" />} iconType="image" href="/v1/integrations/voyage">
High-performance embeddings with comprehensive usage tracking
</Card>
<Card title="xAI" icon={<img src="https://www.github.com/agentops-ai/agentops/blob/main/docs/images/external/openai/xai-logo.png?raw=true" alt="xAI" />} iconType="image" href="/v1/integrations/xai">
Observe the power of Grok and Grok Vision with AgentOps
</Card>
Expand Down
97 changes: 97 additions & 0 deletions docs/v1/integrations/voyage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Voyage AI Integration

<img src="https://github.com/AgentOps-AI/agentops/blob/main/docs/images/external/voyage/voyage-logo.png?raw=true" width="250px" style="max-width: 100%; height: auto;"/>

AgentOps provides seamless integration with Voyage AI's embedding models, allowing you to track and monitor your embedding operations while maintaining high performance.

## Requirements

- Python >= 3.9 (Voyage AI SDK requirement)
- AgentOps library
- Voyage AI API key

## Installation

```bash
pip install agentops voyageai
```

## Basic Usage

Initialize the Voyage AI provider with your client:

```python
import voyageai
from agentops.llms.providers.voyage import VoyageProvider

# Initialize clients
voyage_client = voyageai.Client()
provider = VoyageProvider(voyage_client)
```

Generate embeddings and track usage:

```python
# Create embeddings
text = "The quick brown fox jumps over the lazy dog."
result = provider.embed(text)

print(f"Embedding dimension: {len(result['embeddings'][0])}")
print(f"Token usage: {result['usage']}")
```

## Async Support

The provider supports asynchronous operations for better performance:

```python
import asyncio

async def process_multiple_texts():
texts = [
"First example text",
"Second example text",
"Third example text"
]

# Process texts concurrently
tasks = [provider.aembed(text) for text in texts]
results = await asyncio.gather(*tasks)

return results

# Run async example
results = await process_multiple_texts()
```

## Error Handling

The provider includes comprehensive error handling:

```python
# Handle invalid input
try:
result = provider.embed(None)
except ValueError as e:
print(f"Caught ValueError: {e}")

# Handle API errors
try:
result = provider.embed("test", invalid_param=True)
except Exception as e:
print(f"Caught API error: {e}")
```

## Python Version Compatibility

The Voyage AI SDK requires Python 3.9 or higher. When using an incompatible Python version, the provider will log a warning:

```python
import sys
if sys.version_info < (3, 9):
print("Warning: Voyage AI SDK requires Python >=3.9")
```

## Example Notebook

For a complete example, check out our [Jupyter notebook](https://github.com/AgentOps-AI/agentops/blob/main/examples/voyage/voyage_example.ipynb) demonstrating all features of the Voyage AI integration.
Loading

0 comments on commit 9288655

Please sign in to comment.