# Daisi SDK - Python gRPC Wrapper

A modern Python wrapper for the Daisi SDK, providing a clean and Pythonic interface to interact with the Daisi distributed AI network via gRPC.

## Features

- **gRPC-based**: Full gRPC implementation matching the .NET SDK
- **Type-safe**: Full type hints for IDE autocomplete and type checking
- **Streaming support**: Native support for streaming inference responses
- **Session management**: Complete session lifecycle management
- **Comprehensive**: All Daisi services (Auth, Sessions, Inference, Models, Hosts, Peers, Settings, Commands)
- **Production-ready**: Follows PEP standards and best practices

## Installation

```bash
pip install daisi-sdk
```

### Development Installation

```bash
git clone https://github.com/daisinet/daisi-sdk-python.git
cd daisi-sdk-python
pip install -e ".[dev]"
```

## Quick Start

```python
from daisi import DaisiClient

# Initialize client with API key
client = DaisiClient(client_key="your-client-key")

# Create a session
session_id, host = client.session.create(model_name="llama-3")

# Create an inference
inference_id = client.inference.create(
    session_id=session_id,
    initialization_prompt="You are a helpful assistant."
)

# Send inference request with streaming response
for response in client.inference.send("Hello, how are you?"):
    if response.Type == InferenceResponseTypes.InferenceText:
        print(response.Content, end="", flush=True)

# Get statistics
stats = client.inference.stats()
print(f"\nTokens used: {stats.SessionTokenCount}")

# Clean up
client.inference.close_inference()
client.session.close()
client.close()
```

## Configuration

Set your configuration via environment variables:

```bash
export DAISI_CLIENT_KEY="your-client-key"
export DAISI_ORC_ADDRESS="orc.daisi.net"
export DAISI_ORC_PORT="443"
```

Or configure in code:

```python
from daisi import DaisiClient, DaisiConfig

config = DaisiConfig(
    client_key="your-client-key",
    orc_address="orc.daisi.net",
    orc_port=443,
    use_ssl=True
)

client = DaisiClient(
    client_key=config.client_key,
    orc_address=config.orc_address,
    orc_port=config.orc_port
)
```

## Available Clients

The SDK provides specialized clients for each service:

- **`client.auth`**: Authentication operations (create/validate keys, auth codes)
- **`client.session`**: Session management (create, claim, close, connect)
- **`client.inference`**: Inference operations (create, send streaming, stats, close)
- **`client.models`**: Model discovery and requirements
- **`client.hosts`**: Host registration and management
- **`client.peers`**: Peer operations
- **`client.settings`**: Settings management
- **`client.host_commands`**: Host command streaming
- **`client.app_commands`**: App command streaming

## Usage Examples

### Authentication

```python
from daisi import DaisiClient

client = DaisiClient(client_key="initial-key")

# Send auth code
client.auth.send_auth_code("user@example.com")

# Validate auth code and get new client key
client_key, user_name, account_name, account_id = client.auth.validate_auth_code(
    secret_key="secret",
    email_or_phone="user@example.com",
    auth_code="123456",
    app_id="my-app"
)
```

### Session Management

```python
# Create session with preferences
session_id, host = client.session.create(
    model_name="llama-3",
    direct_connect_required=False,
    preferred_region="us-west",
    private_network_only=False
)

# Connect to session
sid, has_capacity, already_connected = client.session.connect(session_id)
```

### Inference with Tool Groups

```python
from protos.v1.models.InferenceModels_pb2 import (
    ThinkChainOfThought,
    InferenceCodingTools,
    InferenceFileTools
)

# Create inference with tools
session_id, inference_id = client.inference.create(
    session_id=session_id,
    think_level=ThinkChainOfThought,
    tool_groups=[InferenceCodingTools, InferenceFileTools]
)

# Send with custom parameters
for response in client.inference.send(
    text="Write a Python function to calculate fibonacci",
    temperature=0.7,
    top_p=0.9,
    max_tokens=2000
):
    print(response.Content, end="")
```

### Models

```python
# Get required models
models_response = client.models.get_required_models()
```

### Hosts

```python
# Get available hosts
hosts = client.hosts.get_hosts()

for host in hosts:
    print(f"{host.Name}: {host.Status} - {host.Region}")
```

## Development

### Generating Protobuf Code

If you modify the .proto files:

```bash
python generate_protos.py
```

### Testing

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=src/daisi

# Run specific test file
pytest tests/test_client.py
```

### Code Quality

```bash
# Format code
black src/ tests/

# Sort imports
isort src/ tests/

# Lint
flake8 src/ tests/

# Type checking
mypy src/

# Run all checks
make lint
```

## Project Structure

```
daisi-sdk-python/
├── src/daisi/              # Main package
│   ├── __init__.py
│   ├── client.py           # Main unified client
│   ├── config.py           # Configuration
│   ├── base_client.py      # Base gRPC client
│   ├── exceptions.py       # Custom exceptions
│   └── clients/            # Service-specific clients
│       ├── auth.py
│       ├── session.py
│       ├── inference.py
│       ├── models.py
│       ├── hosts.py
│       ├── peers.py
│       ├── settings.py
│       └── commands.py
├── protos/v1/              # Protobuf definitions
│   ├── *.proto             # Service definitions
│   └── models/             # Model definitions
├── src/protos/             # Generated Python code
├── tests/                  # Test suite
├── pyproject.toml          # Project configuration
├── generate_protos.py      # Proto generation script
└── README.md
```

## Architecture

The SDK is built on gRPC and Protocol Buffers, matching the .NET SDK architecture:

- **gRPC**: Efficient binary protocol with streaming support
- **Protocol Buffers**: Strongly-typed message definitions
- **Session-based**: Orchestrator (Orc) manages session lifecycle
- **Streaming**: Real-time token-by-token inference responses
- **Direct Connect**: Optional peer-to-peer mode

## Contributing

Contributions are welcome! Ensure:

1. Code follows PEP 8 with Black formatting
2. All tests pass and coverage is maintained
3. Type hints are included
4. Documentation is updated

## License

MIT License - see LICENSE file for details

## Links

- [Daisi Website](https://daisi.net)
- [.NET SDK](https://github.com/daisinet/daisi-sdk-dotnet)
- [Documentation](https://daisi.ai/Learn/SDK)
