Metadata-Version: 2.4
Name: pluginai
Version: 1.0.0
Summary: Official Python SDK for PluginAI RAG Platform
Home-page: https://pluginai.space
Author: Plugin AI
Author-email: Plugin AI <support@pluginai.space>
License: MIT
Project-URL: Homepage, https://pluginai.space
Project-URL: Documentation, https://pluginai.space/docs
Project-URL: Source, https://pluginai.space
Keywords: pluginai,rag,chatbot,ai,llm,knowledge-base
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Requires-Dist: build>=0.10; extra == "dev"
Requires-Dist: twine>=4.0; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# PluginAI Python SDK

Official Python SDK for the **PluginAI** RAG platform. Turn your documents into
an intelligent, API-accessible assistant, and query it from any Python app in
under five minutes.

- 🐍 Pure Python, one dependency (`requests`)
- 🔁 Synchronous — works in scripts, notebooks, Flask, Django, FastAPI, anywhere
- 💬 Built-in multi-turn conversation tracking
- 🧯 Rich, catchable exception hierarchy
- ✅ Python 3.8 – 3.12

---

## Installation

```bash
pip install pluginai
```

---

## Quickstart

```python
from pluginai import PluginAI

client = PluginAI(
    api_key="your-api-key",
    workspace="your-workspace-name",
)

response = client.query("What is the refund policy?")
print(response.answer)
```

`print(response)` also works — a `QueryResponse` stringifies to its answer text.

---

## Multi-turn conversations

Every query from the same client shares one `conversation_id`, so the backend
keeps context across turns. Start over with `reset_conversation()`.

```python
client.query("What products do you offer?")
client.query("Which is cheapest?")     # remembers the previous turn

new_id = client.reset_conversation()   # fresh conversation from here on
client.query("Let's start over.")
```

Use it as a context manager to close the HTTP session automatically:

```python
with PluginAI(api_key="...", workspace="...") as client:
    print(client.query("Hello").answer)
```

---

## Agentic queries

For complex, multi-step questions, use `agent_query()` — same signature and
return type as `query()`, but routed through the Agentic RAG pipeline:

```python
response = client.agent_query(
    "Compare the 2023 and 2024 refund policies and summarize what changed."
)
```

---

## Configuration

All constructor parameters:

| Parameter | Type | Default | Description |
|---|---|---|---|
| `api_key` | `str` | **required** | Your workspace API key. |
| `workspace` | `str` | **required** | The workspace name to query. |
| `base_url` | `str` | hosted PluginAI API | PluginAI backend URL. Only override if you self-host (trailing slash stripped). |
| `conversation_id` | `str` | auto-generated | Pass to continue an existing conversation. |
| `timeout` | `int` | `30` | Per-request timeout, in seconds. |
| `max_retries` | `int` | `2` | Retries on transient server errors (502/503/504) only. |
| `on_error` | `callable` | `None` | Called with the exception right before any error is raised. |

---

## The response object

`client.query(...)` returns a `QueryResponse`:

| Attribute / property | Type | Description |
|---|---|---|
| `answer` | `str` | The AI-generated answer text. |
| `status` | `str` | `"success"` or `"no_data"`. |
| `response_time` | `float` | Seconds the backend took. |
| `conversation_id` | `str` | The conversation the query belonged to. |
| `cached` | `bool` | Reserved for future use (always `False`). |
| `is_success` | `bool` | `True` when `status == "success"`. |
| `has_data` | `bool` | `False` when `status == "no_data"`. |

---

## Error handling

Every SDK error inherits from `PluginAIError`, so you can catch that one base
class or handle specific cases:

```python
from pluginai import (
    PluginAI,
    AuthenticationError,
    NoDataError,
    QuotaExceededError,
    TimeoutError,
    PluginAIError,
)

try:
    response = client.query("What is the refund policy?")
    print(response.answer)
except AuthenticationError:
    print("Check your API key.")
except NoDataError:
    print("Upload documents to this workspace first.")
except QuotaExceededError:
    print("Upgrade your plan.")
except TimeoutError:
    print("Increase the `timeout` parameter.")
except PluginAIError as exc:
    print(f"Something went wrong: {exc}")
```

| Exception | Raised when |
|---|---|
| `PluginAIError` | Base class for all SDK errors. |
| `AuthenticationError` | HTTP 401/403 — wrong or inactive API key. |
| `QuotaExceededError` | HTTP 403 mentioning a quota / usage limit. |
| `WorkspaceNotFoundError` | HTTP 404 — workspace doesn't exist. |
| `NoDataError` | Backend returned `status == "no_data"`. |
| `ConnectionError` | Backend unreachable. |
| `TimeoutError` | Request exceeded `timeout`. |
| `RateLimitError` | HTTP 429 — too many requests. |
| `ServerError` | HTTP 5xx — backend error. |

Every exception carries `.message` (str) and `.status_code` (int or `None`).

---

## Framework integration

See the [`examples/`](examples/) directory for runnable samples:

- [`basic_usage.py`](examples/basic_usage.py)
- [`multi_turn_conversation.py`](examples/multi_turn_conversation.py)
- [`error_handling.py`](examples/error_handling.py)
- [`flask_integration.py`](examples/flask_integration.py)
- [`django_integration.py`](examples/django_integration.py)

**Tip:** create the client **once** at app startup and reuse it — that keeps the
connection pool warm instead of paying setup cost on every request.

---

## Development

```bash
git clone <repo-url>
cd pluginai-python
pip install -e ".[dev]"      # or: pip install -r requirements-dev.txt
pytest tests/
```

---

## Publishing to PyPI

```bash
pip install build twine
python -m build              # builds sdist + wheel into dist/
pytest tests/                # make sure everything is green
twine check dist/*
twine upload dist/*          # prompts for your PyPI token
```

---

## License

[MIT](LICENSE) © Plugin AI
