# NeuralDLP Python SDK

Official Python client for the [NeuralDLP](https://neuraldlp.com) API.

**Neural Data Loss Prevention for AI** - Protect sensitive data in AI interactions using advanced semantic understanding.

## Installation

```bash
pip install neuraldlp
```

Or install from source:

```bash
git clone https://github.com/neuraldlp/python-sdk.git
cd python-sdk
pip install -e .
```

## Quick Start

```python
from neuraldlp import NeuralDLP

# Initialize client
client = NeuralDLP(api_key="your_api_key_here")

# Inspect input for sensitive data
result = client.inspect_input(
    text="My email is john@company.com and SSN is 123-45-6789"
)

print(f"Risk Score: {result.risk_score}/100")
print(f"Action: {result.recommended_action}")
print(f"Entities: {len(result.entities)}")

for entity in result.entities:
    print(f"  - {entity.type}: {entity.value}")
```

## Features

- 🔍 **Input Inspection** - Detect PII, secrets, and threats
- 📤 **Output Inspection** - Prevent data leakage in AI responses
- 🔒 **Tokenization** - Replace sensitive data with reversible tokens
- 🔓 **Rehydration** - Restore original values from tokens
- ⚡ **Simple API** - Pythonic interface with type hints
- 🛡️ **Error Handling** - Clear exceptions for all error cases

## Usage Examples

### Basic Inspection

```python
from neuraldlp import NeuralDLP

client = NeuralDLP(api_key="your_api_key")

# Inspect text
result = client.inspect_input("User john@example.com needs help")

if result.is_blocked():
    print("❌ Content blocked by policy")
elif result.should_tokenize():
    print("🔒 Content should be tokenized")
else:
    print("✅ Content is safe")
```

### Tokenization Workflow

```python
# Step 1: Inspect and tokenize automatically
inspection, tokenization = client.inspect_and_tokenize(
    text="Hi, I'm John Doe (john@company.com)",
    tenant_id="acme_corp"
)

if tokenization:
    print(f"Original:    {inspection.entities[0].value}")
    print(f"Tokenized:   {tokenization.transformed_text}")
    print(f"Mapping ID:  {tokenization.mapping_id}")
    
    # Step 2: Send tokenized text to AI model
    ai_response = your_ai_model(tokenization.transformed_text)
    
    # Step 3: Inspect AI output
    output_check = client.inspect_output(
        text=ai_response,
        mapping_id=tokenization.mapping_id
    )
    
    if output_check.leakage_detected:
        print("⚠️  Data leakage detected!")
    
    # Step 4: Rehydrate for end user
    final = client.rehydrate(
        text=ai_response,
        mapping_id=tokenization.mapping_id
    )
    
    print(f"Final response: {final.rehydrated_text}")
```

### Manual Tokenization

```python
from neuraldlp import Entity

# Detect entities first
result = client.inspect_input("Email: john@example.com")

# Tokenize specific entities
tokenization = client.tokenize(
    text="Email: john@example.com",
    entities=result.entities,
    ttl_seconds=3600,  # 1 hour
    deterministic=True  # Same input = same token
)

print(tokenization.transformed_text)
# Output: Email: EMAIL_a1b2c3d4
```

### Context Metadata

```python
# Add context for better policy matching
result = client.inspect_input(
    text="Process payment of $5000",
    tenant_id="acme_corp",
    user_id="user_123",
    application="payment_system",
    metadata={
        "department": "finance",
        "transaction_id": "txn_456"
    }
)
```

### Error Handling

```python
from neuraldlp import (
    NeuralDLP,
    AuthenticationError,
    RateLimitError,
    ValidationError,
    NotFoundError
)

client = NeuralDLP(api_key="your_api_key")

try:
    result = client.inspect_input("sensitive data")
except AuthenticationError:
    print("Invalid API key")
except RateLimitError:
    print("Rate limit exceeded - slow down!")
except ValidationError as e:
    print(f"Invalid request: {e}")
except NotFoundError:
    print("Mapping expired or not found")
```

### Context Manager

```python
# Automatically close connections
with NeuralDLP(api_key="your_api_key") as client:
    result = client.inspect_input("test data")
    print(result.risk_score)
# Client closed automatically
```

### Check Mapping Status

```python
# Check if mapping still exists
status = client.get_mapping_status("map_abc123")

print(f"Exists: {status.exists}")
print(f"Expires in: {status.ttl_seconds}s")
print(f"Expires at: {status.expires_at}")
```

### Delete Mapping

```python
# Clean up mapping when done
client.delete_mapping("map_abc123")
```

## API Reference

### `NeuralDLP`

Main client class.

**Methods:**

- `inspect_input(text, tenant_id, user_id, application, metadata)` - Inspect input text
- `inspect_output(text, mapping_id, tenant_id, user_id)` - Inspect AI output
- `tokenize(text, entities, tenant_id, ttl_seconds, preserve_context, deterministic)` - Tokenize entities
- `rehydrate(text, mapping_id, tenant_id)` - Restore original values
- `inspect_and_tokenize(text, tenant_id, user_id, application, auto_block)` - Combined inspection + tokenization
- `get_mapping_status(mapping_id, tenant_id)` - Check mapping status
- `delete_mapping(mapping_id, tenant_id)` - Delete mapping
- `health_check()` - Check API health

### Models

**`InspectionResult`**
- `request_id: str`
- `risk_score: int` (0-100)
- `entities: List[Entity]`
- `threats: List[Threat]`
- `matched_policies: List[str]`
- `recommended_action: str` (ALLOW, TOKENIZE, BLOCK)
- `processing_time_ms: float`
- `is_safe() -> bool`
- `should_tokenize() -> bool`
- `is_blocked() -> bool`

**`Entity`**
- `type: str`
- `value: str`
- `start: int`
- `end: int`
- `confidence: float`

**`TokenizationResult`**
- `request_id: str`
- `transformed_text: str`
- `mapping_id: str`
- `expires_at: datetime`
- `tokens: List[TokenInfo]`
- `processing_time_ms: float`

**`RehydrationResult`**
- `request_id: str`
- `rehydrated_text: str`
- `confidence: float`
- `restored_entities: List[RestoredEntity]`
- `processing_time_ms: float`

### Exceptions

- `NeuralDLPError` - Base exception
- `AuthenticationError` - Invalid API key
- `RateLimitError` - Rate limit exceeded
- `ValidationError` - Invalid request
- `NotFoundError` - Resource not found

## Configuration

### Environment Variables

```bash
# Set default API key
export NEURALDLP_API_KEY="your_api_key"

# Set custom API endpoint
export NEURALDLP_BASE_URL="https://api.neuraldlp.com"
```

### Custom Configuration

```python
client = NeuralDLP(
    api_key="your_api_key",
    base_url="https://custom-api.example.com",
    timeout=60  # seconds
)
```

## Advanced Usage

### Batch Processing

```python
texts = [
    "User 1: john@example.com",
    "User 2: jane@example.com",
    "User 3: bob@example.com"
]

results = []
for text in texts:
    result = client.inspect_input(text)
    results.append(result)

# Process results
high_risk = [r for r in results if r.risk_score > 70]
print(f"High risk items: {len(high_risk)}")
```

### Integration with FastAPI

```python
from fastapi import FastAPI, HTTPException
from neuraldlp import NeuralDLP, NeuralDLPError

app = FastAPI()
client = NeuralDLP(api_key="your_api_key")

@app.post("/chat")
async def chat(message: str):
    try:
        # Inspect input
        inspection, tokenization = client.inspect_and_tokenize(
            text=message,
            tenant_id="webapp"
        )
        
        if tokenization:
            # Use tokenized text for AI
            ai_response = await call_ai_model(tokenization.transformed_text)
            
            # Rehydrate for user
            final = client.rehydrate(
                text=ai_response,
                mapping_id=tokenization.mapping_id
            )
            return {"response": final.rehydrated_text}
        else:
            # Safe to use as-is
            ai_response = await call_ai_model(message)
            return {"response": ai_response}
            
    except NeuralDLPError as e:
        raise HTTPException(status_code=400, detail=str(e))
```

## Development

### Installation

```bash
# Clone repository
git clone https://github.com/neuraldlp/python-sdk.git
cd python-sdk

# Install dev dependencies
pip install -e ".[dev]"
```

### Running Tests

```bash
# Run all tests
pytest tests/ -v

# Run unit tests only
pytest tests/test_unit.py -v

# Run integration tests only
pytest tests/test_integration.py -v

# Run with coverage
pytest tests/ --cov=neuraldlp --cov-report=html
```

**Test Results:**
- ✅ 35 tests (34 passed, 1 skipped)
- ✅ 91% code coverage
- ✅ Unit + Integration tests

See [TEST_SUMMARY.md](TEST_SUMMARY.md) for detailed test results.

### Code Quality

```bash
# Format code
black neuraldlp/

# Type checking
mypy neuraldlp/

# Lint
flake8 neuraldlp/
```

### Testing Requirements

Integration tests require:
- NeuralDLP API running on `http://localhost:8000`
- Valid API key (default: `demo_12345`)

Set environment variables:
```bash
export NEURALDLP_API_KEY=your_api_key
export NEURALDLP_BASE_URL=http://localhost:8000
```

## Support

- 🌐 Website: [neuraldlp.com](https://neuraldlp.com)
- 📖 Documentation: [docs.neuraldlp.com](https://docs.neuraldlp.com)
- 💬 Community: [Discord](https://discord.gg/neuraldlp)
- 🐛 Issues: [GitHub Issues](https://github.com/neuraldlp/python-sdk/issues)
- 📧 Email: support@neuraldlp.com

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Links

- [NeuralDLP API Documentation](https://docs.neuraldlp.com)
- [NeuralDLP Website](https://neuraldlp.com)
- [GitHub Repository](https://github.com/neuraldlp/python-sdk)
- [PyPI Package](https://pypi.org/project/neuraldlp/)
