# Roovy SDK

A Python SDK for generating WhatsApp Flows and Message Templates using LLMs. Generate valid,
schema-compliant JSON from natural language descriptions.

## Features

- 🚀 **Simple API** - Generate WhatsApp Flows and Message Templates with a single function call
- ✅ **Schema Validation** - Built-in Pydantic models ensure valid output
- 🔄 **Auto-Retry** - Automatic retries with error feedback for better results
- 📡 **Streaming Support** - Stream responses for real-time feedback
- 🔌 **Provider Agnostic** - Works with OpenAI, Groq, Ollama, or any
  OpenAI-compatible API
- 📝 **Type Safe** - Full type hints and Pydantic models
- 📋 **Dual Output** - Template generation returns both creation and send payloads

## Installation

```bash
pip install roovy-sdk
```

## Quick Start

### Generate a WhatsApp Flow

```python
from roovy_sdk import RoovyClient

client = RoovyClient(
    api_key="your-api-key",
    base_url="https://api.openai.com/v1",  # or any OpenAI-compatible endpoint
    model="gpt-4o",
)

# Generate a WhatsApp Flow from natural language
flow = client.generate(
    "Create a customer feedback form with name, email, rating (1-5 stars), and comments"
)

# Access the validated flow
print(flow.model_dump_json(indent=2, by_alias=True))
```

### Generate a Message Template

```python
# Generate both creation + send payloads
result = client.generate_template(
    "Send John a shipping notification for order ORD-456"
)

# Template creation JSON (register with Meta for approval)
print(result.creation.model_dump_json(indent=2))

# Send message JSON (ready to send to user)
print(result.send.model_dump_json(indent=2))
```

**Smart placeholder extraction:** The SDK automatically extracts values from your prompt into the send payload. If no meaningful values are found, it uses descriptive placeholders like `<CUSTOMER_NAME>`.

## Configuration

### Using Environment Variables

```python
import os
from roovy_sdk import RoovyClient

os.environ["ROOVY_API_KEY"] = "your-api-key"
os.environ["ROOVY_BASE_URL"] = "https://api.openai.com/v1"
os.environ["ROOVY_MODEL"] = "gpt-4o"

client = RoovyClient()
```

### Provider Examples

**OpenAI:**

```python
client = RoovyClient(
    api_key="sk-...",
    base_url="https://api.openai.com/v1",
    model="gpt-4o",
)
```

**Groq:**

```python
client = RoovyClient(
    api_key="gsk_...",
    base_url="https://api.groq.com/openai/v1",
    model="llama-3.3-70b-versatile",
)
```

**Ollama (local):**

```python
client = RoovyClient(
    api_key="ollama",  # any non-empty string
    base_url="http://localhost:11434/v1",
    model="llama3.2",
)
```

## Advanced Usage

### Streaming Generation

```python
def on_chunk(chunk: str):
    print(chunk, end="", flush=True)

# Stream a flow
flow = client.generate_stream(
    "Create a booking form for a concert",
    on_chunk=on_chunk,
)

# Stream a template
result = client.generate_template_stream(
    "Create a promotional offer template with image",
    on_chunk=on_chunk,
)
```

### Custom Retry Settings

```python
flow = client.generate(
    "Create a survey form",
    max_retries=5,
    temperature=0.3,
)
```

### Custom System Prompt

```python
flow = client.generate(
    "Create a registration form",
    system_prompt="You are a WhatsApp Flows expert...",
)
```

### Direct Schema Access

```python
from roovy_sdk.schema import (
    WhatsAppFlow,
    Screen,
    TextInput,
    Footer,
    validate_flow,
)

# Build flows programmatically
screen = Screen(
    id="WELCOME",
    title="Welcome",
    layout=SingleColumnLayout(
        type="SingleColumnLayout",
        children=[
            TextHeading(type="TextHeading", text="Hello!"),
        ]
    )
)

# Validate any JSON against the schema
result = validate_flow({"version": "7.2", "screens": [...]})
if result["success"]:
    flow = result["data"]
```

### Template Validation

```python
from roovy_sdk import validate_template_result

result = validate_template_result({
    "creation": {"name": "my_template", "category": "UTILITY", "components": [...]},
    "send": {"messaging_product": "whatsapp", "to": "...", "type": "template", "template": {...}}
})
if result["success"]:
    template = result["data"]  # TemplateResult object
```

## Schema Reference

### Flow Components

The SDK includes complete Pydantic models for all WhatsApp Flow components:

**Text:** `TextHeading`, `TextSubheading`, `TextBody`, `TextCaption`

**Input:** `TextInput`, `TextArea`, `Dropdown`, `RadioButtonsGroup`, `ChipsSelector`, `CheckboxGroup`, `OptIn`

**Date/Media:** `CalendarPicker`, `DatePicker`, `PhotoPicker`, `DocumentPicker`, `Image`

**Navigation:** `Footer`, `Button`, `EmbeddedLink`

**Conditional:** `If`, `Switch`

**Container:** `Form`, `SingleColumnLayout`

### Template Components

**Result:** `TemplateResult` (contains `.creation` and `.send`)

**Creation:** `TemplateCreation`, `HeaderComponent`, `BodyComponent`, `FooterComponent`, `ButtonsComponent`

**Buttons:** `QuickReplyButton`, `UrlButton`, `PhoneNumberButton`

**Send:** `TemplateSend`, `SendComponent`, `TextParameter`, `ImageParameter`, `VideoParameter`, `DocumentParameter`

### Supported Template Types

| Type | Category | Description |
|------|----------|-------------|
| Text only | UTILITY / MARKETING | Body with `{{N}}` placeholders |
| Header Text | UTILITY | Static text header + body |
| Image Header | MARKETING | Image header + body |
| Document Header | UTILITY | Document attachment + body |
| Video Header | MARKETING | Video header + body |
| Quick Reply Buttons | UTILITY | Up to 3 quick reply buttons |
| URL Button | MARKETING | Up to 2 URL buttons |
| Call Button | UTILITY | 1 phone number button |
| Authentication (OTP) | AUTHENTICATION | OTP verification message |

## API Reference

### `RoovyClient`

```python
RoovyClient(
    api_key: str | None = None,      # API key (or ROOVY_API_KEY env var)
    base_url: str | None = None,     # Base URL (or ROOVY_BASE_URL env var)
    model: str | None = None,        # Model name (or ROOVY_MODEL env var)
)
```

### `client.generate()`

```python
client.generate(
    prompt: str,                     # Natural language description
    *,
    max_retries: int = 3,           # Number of retry attempts
    temperature: float = 0.2,        # LLM temperature
    system_prompt: str | None = None, # Custom system prompt
) -> WhatsAppFlow
```

### `client.generate_stream()`

```python
client.generate_stream(
    prompt: str,                     # Natural language description
    on_chunk: Callable[[str], None] | None = None,  # Chunk callback
    *,
    temperature: float = 0.2,        # LLM temperature
    system_prompt: str | None = None, # Custom system prompt
) -> WhatsAppFlow
```

### `client.generate_template()`

```python
client.generate_template(
    prompt: str,                     # Natural language description
    *,
    max_retries: int = 3,           # Number of retry attempts
    temperature: float = 0.2,        # LLM temperature
    system_prompt: str | None = None, # Custom system prompt
) -> TemplateResult                  # Has .creation and .send properties
```

### `client.generate_template_stream()`

```python
client.generate_template_stream(
    prompt: str,                     # Natural language description
    on_chunk: Callable[[str], None] | None = None,  # Chunk callback
    *,
    temperature: float = 0.2,        # LLM temperature
    system_prompt: str | None = None, # Custom system prompt
) -> TemplateResult
```

### `validate_flow()`

```python
from roovy_sdk import validate_flow

result = validate_flow(flow_dict)
# Returns: {"success": True, "data": WhatsAppFlow} or {"success": False, "error": ValidationError}
```

### `validate_template_result()`

```python
from roovy_sdk import validate_template_result

result = validate_template_result(template_dict)
# Returns: {"success": True, "data": TemplateResult} or {"success": False, "error": ValidationError}
```

## Changelog

### v0.3.2 (2026-03-03)

**🔧 FLOW Button Support**

- **Fixed:** `generate_template()` now correctly handles FLOW button templates — send payload includes `sub_type: "flow"`, `index`, and `action` parameter with `flow_token`
- **New:** `FlowButton` creation model — `{type: FLOW, text, flow_id, flow_action, navigate_screen}`
- **New:** `FlowAction` + `FlowActionParameter` models for FLOW button send components
- **Updated:** `SendComponent.sub_type` now accepts `"flow"` in addition to `"quick_reply"` and `"url"`
- **Updated:** `SendComponent.index` is now `str` (was `int`) — Meta API requires string indexes (`"0"`, `"1"`)
- **Updated:** `ButtonsComponent` validation enforces max 1 FLOW button

### v0.3.1 (2026-03-03)

**📖 Documentation & PyPI Update**

- **Updated:** README with full template generation documentation, API reference, and usage examples
- **Added:** Changelog to PyPI project page

### v0.3.0 (2026-03-03)

**🎉 Message Template Generation**

- **New:** `client.generate_template()` — Generate WhatsApp Message Templates from natural language
- **New:** `client.generate_template_stream()` — Streaming version of template generation
- **New:** `TemplateResult` — Returns both template creation JSON (for Meta approval) and send message JSON
- **New:** Smart placeholder extraction — auto-extracts values from prompts into send payload parameters
- **New:** `template_schema.py` — Complete Pydantic models for all template types (Text, Image, Document, Video headers; Quick Reply, URL, Call buttons; OTP/Authentication)
- **New:** Built-in validation for button limits (max 3 Quick Reply, max 2 URL, max 1 Call)
- **New:** `validate_template_result()` and `validate_template_creation()` helpers

### v0.2.3 (2026-03-03)

**🔧 Terminal Screen Fix**

- **Fixed:** Terminal screen in generated flows now shows a thank-you/confirmation message instead of a data review screen
- **Fixed:** System prompt updated with explicit Rule #9 — terminal screens must NOT display user data back as TextBody lines
- **Fixed:** Working example in system prompt corrected to use `"🎉 Booking Confirmed!"` pattern
- **Added:** `"success": true` to terminal screen in examples

### v0.2.2 (2026-03-02)

**📦 Initial Public Release**

- WhatsApp Flow generation from natural language via `client.generate()`
- Streaming support via `client.generate_stream()`
- Complete Pydantic schema for all WhatsApp Flow components (v6.3–v7.2)
- Auto-retry with validation error feedback
- Provider agnostic — works with OpenAI, Groq, Ollama, or any OpenAI-compatible API
- Bundled WhatsApp Flows documentation for enhanced LLM context
- `validate_flow()` helper for validating arbitrary JSON

## License

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