Metadata-Version: 2.4
Name: praisonai-svc
Version: 1.1.0
Summary: A unified framework that turns any PraisonAI Python package into a web service on Azure
Project-URL: Homepage, https://praison.ai
Project-URL: Documentation, https://mervinpraison.github.io/PraisonAI-SVC
Project-URL: Repository, https://github.com/MervinPraison/PraisonAI-SVC
Project-URL: Issues, https://github.com/MervinPraison/PraisonAI-SVC/issues
Author: MervinPraison
License-Expression: MIT
License-File: LICENSE
Keywords: azure,fastapi,microservices,praisonai,serverless
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: azure-data-tables>=12.6.0
Requires-Dist: azure-identity>=1.19.0
Requires-Dist: azure-storage-blob>=12.23.0
Requires-Dist: azure-storage-queue>=12.12.0
Requires-Dist: click>=8.1.7
Requires-Dist: fastapi>=0.115.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic-settings>=2.6.0
Requires-Dist: pydantic>=2.9.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: python-multipart>=0.0.12
Requires-Dist: pyyaml>=6.0.2
Requires-Dist: tenacity>=9.0.0
Requires-Dist: uvicorn[standard]>=0.32.0
Provides-Extra: dev
Requires-Dist: black>=24.10.0; extra == 'dev'
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
Requires-Dist: pytest>=8.3.0; extra == 'dev'
Requires-Dist: ruff>=0.7.0; extra == 'dev'
Description-Content-Type: text/markdown

# PraisonAI Service Framework

A unified framework that turns any PraisonAI Python package into a web service on Azure using just **one file per package**.

## Features

✅ **One-file service creation** - Only a `handlers.py` file needed  
✅ **Azure-native** - Uses Container Apps, Blob Storage, Queue, Table Storage  
✅ **Cost-predictable** - Scale-to-zero, hard-capped replicas (£15-25/month)  
✅ **Production-ready** - Retry logic, idempotency, monitoring  
✅ **Secure** - API keys, rate limiting, CORS  
✅ **Fast** - Built with FastAPI and async/await  

## Quick Start

### Installation

```bash
# Using uv (recommended)
uv pip install praisonai-svc

# Using pip
pip install praisonai-svc
```

### Create a New Service

```bash
praisonai-svc new my-service --package praisonaippt
cd my-service
```

### Implement Your Handler

Edit `handlers.py`:

```python
import io
from praisonai_svc import ServiceApp
from praisonaippt import build_ppt

app = ServiceApp("PraisonAI PPT")

@app.job
def generate_ppt(payload: dict) -> tuple[bytes, str, str]:
    """Generate PowerPoint from YAML."""
    buf = io.BytesIO()
    build_ppt(payload, out=buf)
    return (
        buf.getvalue(),
        "application/vnd.openxmlformats-officedocument.presentationml.presentation",
        "slides.pptx",
    )

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app.get_app(), host="0.0.0.0", port=8080)
```

### Configure Environment

Create `.env`:

```bash
PRAISONAI_AZURE_STORAGE_CONNECTION_STRING=your_connection_string
PRAISONAI_API_KEY=your_secret_key
```

### Run Locally

```bash
python handlers.py
```

### Test the API

```bash
# Create a job
curl -X POST http://localhost:8080/jobs \
  -H "Content-Type: application/json" \
  -d '{"payload": {"title": "My Presentation"}}'

# Check job status
curl http://localhost:8080/jobs/{job_id}

# Download result
curl http://localhost:8080/jobs/{job_id}/download
```

## Local Testing

Test locally in 4 simple steps:

### 1. Install

```bash
pip install praisonai-svc
```

### 2. Create Service

```bash
praisonai-svc new my-service
cd my-service
```

### 3. Set Up Azure (Choose One)

**Option A: Local Testing (No Azure Account)**
```bash
# Install and start Azurite
npm install -g azurite
azurite --silent

# Use this in .env:
PRAISONAI_AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;"
```

**Option B: Real Azure**
```bash
# Get from Azure Portal → Storage Account → Access Keys
PRAISONAI_AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;..."
```

### 4. Run & Test

```bash
# Start service
python handlers.py

# Test (in another terminal)
curl http://localhost:8080/health
curl -X POST http://localhost:8080/jobs \
  -H "Content-Type: application/json" \
  -d '{"payload": {"title": "Test"}}'
```

That's it! ✅

## Architecture

```
┌─────────────┐
│  WordPress  │
│   Chatbot   │
└──────┬──────┘
       │ POST /jobs
       ▼
┌─────────────────────────────────────┐
│   Azure Container App (FastAPI)     │
│  ┌──────────┐      ┌──────────┐    │
│  │   API    │      │  Worker  │    │
│  └────┬─────┘      └─────┬────┘    │
└───────┼──────────────────┼──────────┘
        │                  │
        ▼                  ▼
   ┌─────────┐        ┌─────────┐
   │  Table  │        │  Queue  │
   │ Storage │        │ Storage │
   └─────────┘        └─────────┘
                           │
                           ▼
                      ┌─────────┐
                      │  Blob   │
                      │ Storage │
                      └─────────┘
```

## API Endpoints

| Method | Path                  | Description                    |
|--------|-----------------------|--------------------------------|
| POST   | `/jobs`               | Create new job                 |
| GET    | `/jobs/{id}`          | Get job status                 |
| GET    | `/jobs/{id}/download` | Get fresh download URL         |
| GET    | `/health`             | Health check                   |

## Configuration

All configuration via environment variables with `PRAISONAI_` prefix:

```bash
# Required
PRAISONAI_AZURE_STORAGE_CONNECTION_STRING=...

# Optional
PRAISONAI_API_KEY=secret
PRAISONAI_CORS_ORIGINS=["https://example.com"]
PRAISONAI_MAX_JOB_DURATION_MINUTES=10
PRAISONAI_MAX_RETRY_COUNT=3
```

## Deployment

### Azure Container Apps

Quick deploy:

```bash
# Build and push image
docker build -t myregistry.azurecr.io/my-service:latest .
docker push myregistry.azurecr.io/my-service:latest

# Deploy to Azure Container Apps
az containerapp create \
  --name my-service \
  --resource-group my-rg \
  --environment my-env \
  --image myregistry.azurecr.io/my-service:latest \
  --target-port 8080 \
  --ingress external \
  --min-replicas 0 \
  --max-replicas 3
```

## Security

### Official Package

⚠️ The only official package is: **praisonai-svc**

Install via:
```bash
pip install praisonai-svc
```

### Typosquatting Protection

We maintain a defensive package for common typo:
- `praisonai-svcs` (plural) → redirects to `praisonai-svc`

PyPI's built-in name similarity protection prevents other typosquatting attempts.

### Report Security Issues

GitHub Issues: https://github.com/MervinPraison/PraisonAI-SVC/issues

## Development

```bash
# Clone repository
git clone https://github.com/MervinPraison/PraisonAI-SVC.git
cd praisonai-svc

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

# Run tests
pytest

# Format code
black src/
ruff check src/ --fix

# Type check
mypy src/
```

## Project Structure

```
praisonai-svc/
├── src/praisonai_svc/          # Main package
│   ├── __init__.py             # Package exports
│   ├── app.py                  # ServiceApp class
│   ├── worker.py               # Worker with exponential backoff
│   ├── cli.py                  # CLI commands
│   ├── models/                 # Data models
│   └── azure/                  # Azure integrations
├── tests/                      # Test suite (20 tests)
├── examples/                   # Example services
├── pyproject.toml              # Package configuration
├── Dockerfile                  # Container image
└── LICENSE                     # MIT License
```

## Key Features

### Core Framework
- **ServiceApp class** - FastAPI app factory
- **@app.job decorator** - Simple handler registration
- **Automatic API generation** - 4 endpoints created automatically
- **CORS middleware** - Configurable cross-origin support
- **Idempotency** - SHA256 JobHash prevents duplicate processing

### Azure Integration
- **Blob Storage** - File storage with retry logic (3 attempts)
- **Queue Storage** - Job queue with poison queue for failures
- **Table Storage** - Job state tracking with retry logic
- **SAS URLs** - On-demand secure download links (1h expiry)

### Reliability
- **Exponential backoff** - Worker polling (1s → 30s)
- **Retry logic** - Max 3 attempts before poison queue
- **Timeout detection** - 10 minute job timeout
- **Error handling** - Comprehensive error messages

### CLI Commands

#### `praisonai-svc new <name>`

**Purpose:** Create a new service from template

**Usage:**
```bash
praisonai-svc new my-service
# or with package integration
praisonai-svc new my-service --package praisonaippt
```

**What it does:**
1. Creates a new directory with your service name
2. Generates `handlers.py` with ServiceApp boilerplate
3. Creates `.env.example` with required configuration
4. Creates `README.md` with setup instructions
5. Generates `pyproject.toml` with dependencies

**Output:**
```
✅ Service created: my-service/
   ├── handlers.py
   ├── .env.example
   ├── README.md
   └── pyproject.toml
```

**Next steps after creation:**
```bash
cd my-service
cp .env.example .env
# Edit .env with your Azure credentials
# Edit handlers.py to implement your logic
```

---

#### `praisonai-svc run`

**Purpose:** Run the service locally for development

**Usage:**
```bash
cd my-service
praisonai-svc run
```

**What it does:**
1. Loads environment variables from `.env`
2. Starts FastAPI server on `http://localhost:8080`
3. Starts worker process for job processing
4. Enables hot-reload for development

**Output:**
```
INFO:     Started server process [12345]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8080
```

**Test it:**
```bash
# Health check
curl http://localhost:8080/health

# Create a job
curl -X POST http://localhost:8080/jobs \
  -H "Content-Type: application/json" \
  -d '{"payload": {"title": "Test"}}'
```

---

#### `praisonai-svc deploy`

**Purpose:** Deploy service to Azure Container Apps

**Usage:**
```bash
cd my-service
praisonai-svc deploy
```

**What it does:**
1. Validates Azure CLI is installed and authenticated
2. Builds Docker image from your service
3. Pushes image to Azure Container Registry
4. Creates/updates Azure Container App
5. Configures environment variables
6. Sets up scaling rules (min 0, max 3 replicas)

**Prerequisites:**
- Azure CLI installed: `brew install azure-cli`
- Logged in: `az login`
- Resource group and container registry created

**Output:**
```
🔨 Building Docker image...
✅ Image built: myregistry.azurecr.io/my-service:latest

📤 Pushing to Azure Container Registry...
✅ Image pushed

🚀 Deploying to Azure Container Apps...
✅ Deployed: https://my-service.azurecontainerapps.io

📊 Service URL: https://my-service.azurecontainerapps.io
```

**What happens:**
- Service is deployed with scale-to-zero (no cost when idle)
- Auto-scales based on HTTP requests (0-3 replicas)
- Environment variables from `.env` are configured
- HTTPS endpoint is automatically provisioned

---

#### `praisonai-svc logs`

**Purpose:** View real-time logs from deployed service

**Usage:**
```bash
cd my-service
praisonai-svc logs

# Follow logs (like tail -f)
praisonai-svc logs --follow

# Show last 100 lines
praisonai-svc logs --tail 100
```

**What it does:**
1. Connects to Azure Container Apps
2. Streams application logs in real-time
3. Shows both API and worker logs
4. Displays timestamps and log levels

**Output:**
```
2025-11-04 21:00:15 INFO  [API] Started server
2025-11-04 21:00:20 INFO  [API] POST /jobs - 201 Created
2025-11-04 21:00:21 INFO  [Worker] Processing job abc123
2025-11-04 21:00:25 INFO  [Worker] Job abc123 completed
2025-11-04 21:00:26 INFO  [API] GET /jobs/abc123 - 200 OK
```

**Useful for:**
- Debugging production issues
- Monitoring job processing
- Tracking API requests
- Identifying errors

## Testing

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=praisonai_svc

# Run specific test file
pytest tests/test_integration.py -v
```

**Test Results:** 20/20 tests passing ✅

## Examples

See [examples/](./examples/) directory:
- `examples/ppt-service/` - PowerPoint generation example

## Documentation

- [PRD](./PRD.md) - Complete product requirements
- GitHub: https://github.com/MervinPraison/PraisonAI-SVC
- Issues: https://github.com/MervinPraison/PraisonAI-SVC/issues

## License

MIT License - see [LICENSE](./LICENSE) file

## Contributing

Contributions welcome! Please open an issue or pull request on GitHub.

## Support

- GitHub Issues: https://github.com/MervinPraison/PraisonAI-SVC/issues
- Documentation: https://mervinpraison.github.io/PraisonAI-SVC
- Website: https://praison.ai
