# ObserveLLM
## Installation
Install the package from PyPI using:
```bash
   pip install observeLLM
```

Note: It is recommended to use the latest version for optimal performance.

## Middleware Setup
Add the following middleware functions to your FastAPI application in `main.py` or the appropriate entry point.

### 1. Unified Trace Middleware
This middleware creates a unified trace for each incoming request.

```python
from observe_traces.middleware.middleware import create_unified_trace

app = FastAPI()

@app.middleware("http")
async def create_unified_trace_middleware(request: Request, call_next):
    return await create_unified_trace(request, call_next)
```

### 2. Request Context Middleware
This middleware sets the request context for tracking purposes.

```python
from observe_traces.middleware.middleware import set_request_context

@app.middleware("http")
async def set_request_context_middleware(request: Request, call_next):
    metadata = {
        "user_id": request.headers.get("X-User-ID"),
        "user_email": request.headers.get("X-User-Email"),
        "user_role": request.headers.get("X-User-Role"),
    }
    # Add metadata related to your application
    return await set_request_context(request, call_next, metadata)
```

### 3. Langfuse Client Middleware
This middleware initializes and closes the Langfuse client for each request.

```python
from observe_traces.config.langfuse_service import LangfuseClient

@app.middleware("http")
async def create_langfuse_client(request: Request, call_next):
    try:
        obj = LangfuseClient(
            langfuse_public_key='your_langfuse_public_key',
            langfuse_secret_key='your_langfuse_secret_key',
            langfuse_host='your_host_url',
            release='app_version',
            environment='your_environment'
        )
        
        obj.initialize_langfuse_client()
        response = await call_next(request)
    
    finally:
        obj.close_langfuse_client()
    
    return response
```

Note: Follow the middleware setup in the specified order to ensure correct functionality.

## Using Decorators for Tracing
ObserveLLM provides four decorators to enable tracing for different AI/ML components:

- @embedding_tracing → Tracks embedding model calls.

- @llm_tracing → Tracks LLM (Language Model) interactions.

- @reranking_tracing → Tracks reranking models used in search/retrieval.

- @vectordb_tracing → Tracks vector database operations.

### Example: Using the @embedding_tracing Decorator

```python
from observe_traces.tracer.embed_tracer import embedding_tracing

@embedding_tracing(provider='embedding_provider_name')
async def embedding_generation_function(model_name: str, dimension: int, inputs: list, input_type: str):
    ## your custom API calling logic
```

### Example: Using the @llm_tracing Decorator

```python
from observe_traces.tracer.llm_tracer import llm_tracing

@llm_tracing(provider='llm_provider_name')
async def llm_api_calling_function(model_name: str, system_prompt: str, user_prompt:str , user_query:str , **params):
    ## your custom API calling logic
```

Note: The `llm_tracing` decorator expects the following parameters to be present in the decorated function:
- `model`: The name of the LLM model being used
- `system_prompt`: The system prompt/instructions for the LLM
- `chat_messages`: The conversation history or messages to be sent to the LLM


### Example: Using the @reranking_tracing Decorator

```python
from observe_traces.tracer.rerank_tracer import reranking_tracing

@reranking_tracing(provider='reranker_provider_name')
async def reranking_function(model_name: str, query: str, documents: list, top_n: int):
    ## your custom API calling logic
```

### Example: Using the @vectordb_tracing Decorator

```python
from observe_traces.tracer.vector_tracer import vectordb_tracing

## for write operation
@vectordb_tracing(provider='pinecone', operation_type='write')
async def vectordb_function(self, index_host, input, namespace):
    ## your custom API calling logic

## for read operation
@vectordb_tracing(provider='pinecone', operation_type='read')
async def vectordb_function(self, index_host, namespace, top_k, alpha: int, query: str, query_vector_embeds: list, query_sparse_embeds: dict, include_metadata: bool, filter_dict: dict = None):
    ## your custom API calling logic
```

Note: It is essential to define your methods using the above parameters for consistency and compatibility.

## Prerequisite: Self-Hosted Langfuse
To ensure proper logging and tracing, you must have a self-hosted Langfuse instance up and running. Without it, tracing will not function correctly. Configure the langfuse_host, langfuse_public_key, and langfuse_secret_key appropriately to connect your application with Langfuse.






