Metadata-Version: 2.4
Name: veezoo
Version: 0.1.0
Summary: Official Python SDK for the Veezoo API
Author-email: Veezoo AG <support@veezoo.com>
License-Expression: MIT
Project-URL: Homepage, https://www.veezoo.com
Keywords: veezoo,api,vql,analytics,business-intelligence,natural-language
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Database
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.0.0
Requires-Dist: rich>=13.0.0
Provides-Extra: pandas
Requires-Dist: pandas>=1.4.0; extra == "pandas"
Provides-Extra: interactive
Requires-Dist: prompt_toolkit>=3.0.0; extra == "interactive"
Requires-Dist: pygments>=2.0.0; extra == "interactive"
Requires-Dist: plotext>=5.0.0; extra == "interactive"
Provides-Extra: all
Requires-Dist: veezoo[pandas]; extra == "all"
Requires-Dist: veezoo[interactive]; extra == "all"
Provides-Extra: dev
Requires-Dist: veezoo[all]; extra == "dev"
Requires-Dist: pytest>=7.0.0; extra == "dev"
Dynamic: license-file

# Veezoo Python SDK

The official Python SDK for the [Veezoo API](https://docs.veezoo.com/api/beta/introduction). This library allows you to interact programmatically with Veezoo, enabling you to integrate Veezoo into your own applications and workflows.

## Installation

```bash
pip install veezoo
```

With optional features:

```bash
# With pandas DataFrame support
pip install 'veezoo[pandas]'

# With interactive mode (rich REPL)
pip install 'veezoo[interactive]'

# With all features
pip install 'veezoo[all]'
```

## Quick Start

### Using the CLI

The CLI can be invoked as `veezoo` or the shorter alias `vz`:

```bash
# Configure your API key (stored securely in ~/.veezoo/config.json)
vz configure --api-key YOUR_API_KEY

# Test the connection
vz ping

# Ask a natural-language question
vz ask "How many customers do we have?" --kg-id my-kg

# Run a VQL query
vz query "var x from kb.Customer; select(count(x))" --kg-id my-kg

# Output as JSON or CSV
vz query "select(count(kb.Sales))" --kg-id my-kg --format json
vz query "select(count(kb.Sales))" --kg-id my-kg --format csv
```

### Using the Python Library

```python
from veezoo import VeezooClient

# Initialize the client with your API key
client = VeezooClient(api_key="your-api-key")

# Check connectivity
if client.ping():
    print("Connected to Veezoo!")

# Run a VQL query
result = client.run_vql_query(
    kg_id="my-knowledge-graph",
    vql="""
    var customers from kb.Customer
    var retCount = count(customers)
    select(retCount)
    """
)

# Access the data
for row in result.data:
    print(row.values())

# Convert to dictionary format
print(result.data.to_dicts())
```

## Command Line Interface (CLI)

The Veezoo SDK includes a powerful command-line interface. You can use either `veezoo` or the shorter alias `vz`.

### Configuration

```bash
# Interactive configuration (prompts for API key)
veezoo configure

# Configure with options
veezoo configure --api-key YOUR_API_KEY --kg-id my-default-kg

# View current configuration
veezoo config

# Clear configuration (logout)
veezoo logout
```

You can also use environment variables:

```bash
export VEEZOO_API_KEY=your-api-key
export VEEZOO_KG_ID=my-knowledge-graph
```

### Ask Questions

```bash
# Ask a natural-language question
vz ask "How many customers do we have?" --kg-id my-kg

# Continue the same conversation
vz ask "Break down by region" --kg-id my-kg --conversation-id <conversation-id>

# Ask in a specific language
vz ask "Umsatz letztes Jahr" --kg-id my-kg --language de

# Get the full raw API response as JSON
vz ask "How many customers do we have?" --kg-id my-kg --raw

# Keep human-readable conversation output, but render answer tables as JSON
vz ask "How many customers do we have?" --kg-id my-kg --format json

# Show VQL / SQL for answer messages
vz ask "How many customers do we have?" --kg-id my-kg --show-vql --show-sql
```

`ask` options:

- `--kg-id` selects the Knowledge Graph to query. If omitted, the configured default KG is used.
- `--conversation-id` continues an existing conversation for follow-up questions.
- `--language` sets the question language, for example `en` or `de`.
- `--raw` prints the full raw API question response as JSON.
- `--format` controls how structured answer data is rendered in the default human-readable output.
- Supported formats are `table` (default), `json`, and `csv`.
- Note: `--raw` and `--format json` intentionally produce different JSON formats. `--raw` returns the raw API response, while `--format json` renders only answer tables as row-oriented JSON within the human-readable output.
- `--show-vql` shows the VQL for each answer in human output.
- `--show-sql` shows the SQL for each answer in human output.

### Run Queries

```bash
# Basic query
vz query "var x from kb.Customer; select(count(x))" --kg-id my-kg

# Query with default KG from config
vz query "select(count(kb.Sales))"

# Query output formats
vz query "select(count(kb.Sales))" --format table
vz query "select(count(kb.Sales))" --format json
vz query "select(count(kb.Sales))" --format csv

# Read query from file
vz query -i my-query.vql --kg-id my-kg

# Pipe query from stdin
echo "select(count(kb.Customer))" | vz query --kg-id my-kg
```

`query` options:

- `--format table` renders the result as a terminal table.
- `--format json` prints the result rows as JSON.
- `--format csv` prints the result as CSV.
- `--show-sql` prints the generated SQL.
- `--show-rewriting` prints VQL rewriting steps.

#### Multi-line query input

```bash
# Option 1: Use a file (recommended for complex queries)
cat > query.vql << 'EOF'
var customers from kb.Customer
var state = customers.customers_State_From
var retCount = count(customers) by (state)
select(state, retCount)
EOF
vz query -i query.vql -g my-kg

# Option 2: Use heredoc
vz query -g my-kg << 'EOF'
var customers from kb.Customer
var retCount = count(customers)
select(retCount)
EOF

# Option 3: Use quotes with newlines
vz query "var customers from kb.Customer
var retCount = count(customers)
select(retCount)" -g my-kg

# Option 4: Use $'...' with explicit newlines
vz query $'var user from kb.User\n\nuser.Deleted = false\nvar retCount = count(user)\nselect(retCount)' --kg-id my-kg
```

### Shared Answers

```bash
# Run a shared answer
veezoo shared-answer ANSWER_ID --kg-id my-kg

# Show VQL for shared answer
veezoo shared-answer ANSWER_ID --show-vql
```

### Interactive Mode

Start a rich REPL with syntax highlighting, auto-completion, and multi-line editing:

```bash
# Install interactive dependencies
pip install 'veezoo[interactive]'

# Start interactive mode
vz interactive --kg-id my-kg
vz i -g my-kg  # short alias
```

Interactive mode supports two modes:

- **ask** (default): type natural-language questions directly. Follow-up questions
  automatically reuse the current conversation.
- **vql**: type VQL queries directly, with syntax highlighting and multi-line editing
  (Alt+Enter to execute).

Use `.mode ask` or `.mode vql` to switch, or `.mode` to toggle.

**General commands:**

| Command | Description |
|---------|-------------|
| `.help` | Show help |
| `.mode [ask\|vql]` | Switch or toggle between ask and VQL modes |
| `.ask <question>` | Ask a natural-language question (works in VQL mode too) |
| `.query <vql>` | Run a VQL query (works in ask mode too) |
| `.kg <id>` | Switch Knowledge Graph |
| `.format <fmt>` | Set output: `table`, `json`, `csv` |
| `.history` | Show command history |
| `.clear` | Clear screen |
| `.exit` | Exit interactive mode |

**Ask mode commands:**

| Command | Description |
|---------|-------------|
| `.conversation` | Show current conversation ID |
| `.new` | Start a new conversation |

**VQL mode commands:**

| Command | Description |
|---------|-------------|
| `.sql` | Show SQL from last query |
| `.vql` | Show rewritten VQL from last query |
| `.export <file>` | Export last query result to file |

**Example session:**
```
veezoo [my-kg]> How many customers do we have?

Number of Customer
╭──────────────────────╮
│ Number of Customer   │
├──────────────────────┤
│ 160425               │
╰──────────────────────╯

veezoo [my-kg]> Break down by region

...

veezoo [my-kg]> .mode vql

veezoo [my-kg]> var customers from kb.Customer
.............. var state = customers.state
.............. select(state, count(customers) by (state))
[Alt+Enter]

╭─────────┬───────╮
│ State   │ Count │
├─────────┼───────┤
│ CA      │ 1234  │
│ NY      │ 987   │
│ TX      │ 756   │
╰─────────┴───────╯

3 row(s)

veezoo [my-kg]> .sql
┌─────────────────────────────────────┐
│ SELECT state, COUNT(*) FROM ...     │
└─────────────────────────────────────┘

veezoo [my-kg]> .export results.csv
✓ Exported 3 rows to results.csv

veezoo [my-kg]> .exit
```

### Global Options

```bash
# Override API key for single command
veezoo --api-key OTHER_KEY query "..."

# Get help
veezoo --help
veezoo query --help
```

## Authentication

All API requests require authentication using an API key. You can create and manage API keys in [Veezoo Admin](https://app.veezoo.com/admin/api/keys).

```python
from veezoo import VeezooClient

client = VeezooClient(api_key="your-api-key")
```

## API Reference

### VeezooClient

The main client class for interacting with the Veezoo API.

#### Constructor

```python
VeezooClient(
    api_key: str,           # Required: Your Veezoo API key
    timeout: int = 120      # Optional: Request timeout in seconds
)
```

#### Methods

##### `ping() -> bool`

Check if the API is running and the API key is valid.

```python
if client.ping():
    print("API is accessible!")
```

##### `run_vql_query(kg_id: str, vql: str) -> VqlQueryResult`

Run a VQL query against a Knowledge Graph.

```python
result = client.run_vql_query(
    kg_id="my-sales-kg",
    vql="""
    var customers from kb.Customer
    var state = customers.customers_State_From
    var retCount = count(customers) by (state)
    select(state, retCount)
    """
)

# Access query result
print(f"Columns: {result.data.column_names()}")
print(f"Row count: {len(result.data)}")

# View the generated SQL (if available)
if result.sql:
    print(f"Generated SQL:\n{result.sql}")

# Check rewriting information
for step in result.rewriting.steps:
    print(f"Applied rule: {step.rule} (stage: {step.stage.value})")
```

##### `ask(kg_id: str, question: str, conversation_id: str | None = None, language: str | None = None) -> QuestionResult`

Ask a natural-language question and receive the ordered conversation response.

```python
result = client.ask(
    kg_id="my-sales-kg",
    question="How many customers do we have?"
)

print(result.conversation_id)

for message in result.messages:
    print(message)

# Follow-up in the same conversation
follow_up = client.ask(
    kg_id="my-sales-kg",
    question="Break down by region",
    conversation_id=result.conversation_id,
)
```

For low-level integrations that need the exact API JSON response shape, use
`ask_raw(...)` instead of `ask(...)`.

##### `run_shared_answer(kg_id: str, shared_answer_id: str) -> SharedAnswerResult`

Run an existing shared answer.

```python
result = client.run_shared_answer(
    kg_id="my-sales-kg",
    shared_answer_id="0ece8e2d-b821-476d-bd78-986e8cb62879"
)

# Access the data
for row in result.data:
    print(row.values())
```

### Data Models

#### `VqlQueryResult`

The result of a VQL query.

| Property | Type | Description |
|----------|------|-------------|
| `type` | `str` | Always "VqlQueryResult" |
| `rewriting` | `Rewriting` | Information about VQL rewriting applied |
| `sql` | `str \| None` | The generated SQL query |
| `data` | `Data` | The query result data |

#### `SharedAnswerResult`

The result of a shared answer execution.

| Property | Type | Description |
|----------|------|-------------|
| `type` | `str` | Always "SharedAnswerResult" |
| `vql` | `str \| None` | The non-rewritten VQL of the shared answer |
| `rewriting` | `Rewriting` | Information about VQL rewriting applied |
| `sql` | `str \| None` | The generated SQL query |
| `data` | `Data` | The query result data |

#### `Data`

Contains the query result data in a table-like structure.

```python
# Get column names
column_names = result.data.column_names()

# Iterate over rows
for row in result.data:
    for cell in row:
        print(cell.value)

# Convert to list of lists
data_list = result.data.to_list()

# Convert to list of dictionaries
data_dicts = result.data.to_dicts()

# Convert to pandas DataFrame (requires: pip install veezoo[pandas])
df = result.data.to_dataframe()
```

##### `to_dataframe(infer_types: bool = True) -> pandas.DataFrame`

Converts the data to a pandas DataFrame.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `infer_types` | `bool` | `True` | If True, automatically infers numeric types for columns |

```python
# Basic usage - automatically infers numeric types
df = result.data.to_dataframe()

# Keep all columns as strings
df = result.data.to_dataframe(infer_types=False)
```

#### `Rewriting`

Contains information about VQL rewriting.

```python
# Access rewriting steps
for step in result.rewriting.steps:
    print(f"Stage: {step.stage.value}")
    print(f"Rule: {step.rule}")
    if step.rewritten_vql:
        print(f"Rewritten VQL:\n{step.rewritten_vql}")

# Get the final rewritten VQL
if result.rewriting.rewritten_vql:
    print(f"Final VQL:\n{result.rewriting.rewritten_vql}")
```

### Exceptions

The SDK provides specific exception classes for different error scenarios:

| Exception | HTTP Status | Description |
|-----------|-------------|-------------|
| `VeezooError` | - | Base exception for all SDK errors |
| `VeezooApiError` | - | Base exception for API errors |
| `VeezooAuthenticationError` | 401 | Authentication failed (invalid/missing API key) |
| `VeezooPaymentRequiredError` | 402 | Payment required (subscription issue) |
| `VeezooNotFoundError` | 404 | Resource not found |
| `VeezooRateLimitError` | 429 | Rate limit exceeded |
| `VeezooValidationError` | 400 | Request validation failed |
| `VeezooServerError` | 5xx | Server error |

```python
from veezoo import VeezooClient
from veezoo.exceptions import (
    VeezooAuthenticationError,
    VeezooRateLimitError,
    VeezooNotFoundError,
    VeezooValidationError,
)

try:
    result = client.run_vql_query(kg_id="my-kg", vql="invalid vql")
except VeezooAuthenticationError:
    print("Check your API key!")
except VeezooRateLimitError:
    print("Too many requests, please wait...")
except VeezooNotFoundError:
    print("Knowledge graph not found")
except VeezooValidationError as e:
    print(f"Invalid query: {e.message}")
```

## Rate Limits

API requests are rate-limited:

| Type | Max Requests/Second | Description |
|------|---------------------|-------------|
| Global | 25 | Across all API endpoints |
| Per-endpoint | 10 | Per individual endpoint |

## Examples

### Converting Data to Pandas DataFrame

```python
from veezoo import VeezooClient

client = VeezooClient(api_key="your-api-key")

result = client.run_vql_query(
    kg_id="my-kg",
    vql="var x from kb.Sales; select(x.amount, x.date)"
)

# Convert to DataFrame (requires: pip install veezoo[pandas])
df = result.data.to_dataframe()
print(df)

# Numeric columns are automatically inferred
print(df.dtypes)

# Keep all columns as strings if needed
df_strings = result.data.to_dataframe(infer_types=False)
```

### Advanced Pandas Operations

```python
from veezoo import VeezooClient

client = VeezooClient(api_key="your-api-key")

result = client.run_vql_query(
    kg_id="my-kg",
    vql="""
    var sales from kb.Sales
    var product = sales.product_name
    var revenue = sum(sales.amount) by (product)
    select(product, revenue)
    """
)

df = result.data.to_dataframe()

# Sort by revenue
df_sorted = df.sort_values("revenue", ascending=False)

# Filter top 10
top_10 = df_sorted.head(10)

# Calculate statistics
print(f"Total revenue: {df['revenue'].sum()}")
print(f"Average revenue: {df['revenue'].mean()}")
```

### Exporting to CSV

```python
import csv
from veezoo import VeezooClient

client = VeezooClient(api_key="your-api-key")

result = client.run_vql_query(kg_id="my-kg", vql="...")

with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(result.data.column_names())
    for row in result.data:
        writer.writerow(row.values())
```

### Batch Processing Shared Answers

```python
from veezoo import VeezooClient

client = VeezooClient(api_key="your-api-key")

shared_answer_ids = [
    "answer-id-1",
    "answer-id-2",
    "answer-id-3",
]

results = []
for answer_id in shared_answer_ids:
    result = client.run_shared_answer(
        kg_id="my-kg",
        shared_answer_id=answer_id
    )
    results.append(result.data.to_dicts())
```

## Support

- [API Documentation](https://docs.veezoo.com/api/beta/introduction)
- Email: support@veezoo.com

## License

This SDK is distributed under the MIT License.
