Metadata-Version: 2.1
Name: pashudhan-ai
Version: 0.6.0
Summary: Official Python SDK for the Pashudhan Nutri AI API — Supports B2C individual & B2B cooperative platforms
Home-page: https://pashudhan-nutri-ai.web.app/enterprise
Author: Pashudhan Nutri AI
Author-email: api@pashudhan.ai
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# Pashudhan Nutri AI — Official Python SDK

[![PyPI version](https://badge.fury.io/py/pashudhan-ai.svg)](https://badge.fury.io/py/pashudhan-ai)

The official Python client library for the [Pashudhan Nutri AI API](https://pashudhan-nutri-ai.web.app/enterprise).

**Zero formulation logic is exposed** — all ICAR-NDRI / NASEM 2021 equations, Linear Programming, AI critique, recommendation rules, and regional databases run securely on Pashudhan's Cloud Run backend. You supply the animal profile and receive optimized diets with actionable veterinary insights.

## What's new in v0.5.0

- **`client.cooperative`** — Full B2B Cooperative Platform API (branding, webhooks, rules, products, WhatsApp, farmer analytics)
- **`WebhookVerifier`** — Verify incoming Pashudhan webhook signatures (HMAC-SHA256)

## Installation

```bash
pip install pashudhan_ai
```

## Quickstart — B2C (Individual)

```python
import pashudhan_ai

client = pashudhan_ai.Client(api_key="pd_your_api_key_here")

result = client.formulate(
    animal_type       = "buffalo",
    breed             = "Murrah",
    body_weight_kg    = 500,
    milk_yield_kg_day = 12.0,
    fat_pct           = 7.0,
    production_stage  = "early_lactation",
    state             = "Haryana",
    month             = 6,
)

least_cost = result.least_cost
print(f"Cost: {least_cost.total_cost_local_day}/day")
for ing in least_cost.ingredients:
    print(f"  {ing.name}: {ing.kg_fresh_day} kg")

# AI Nutritionist critique (Pro/ProMax plans)
if result.ai_explanation:
    print("AI says:", result.ai_explanation)
```

## Quickstart — B2B (Cooperative Platform)

For dairy cooperatives, agri-tech companies, and feed manufacturers embedding Pashudhan AI under their own brand.

Your `pd_` Enterprise API key serves **two roles**:
1. **API authentication** — sent as `x-api-key` header on every call.
2. **Webhook signing secret** — used by Pashudhan to HMAC-SHA256-sign outgoing webhook payloads. You verify with the same key.

```python
import pashudhan_ai

client = pashudhan_ai.Client(api_key="pd_your_enterprise_key")
coop   = client.cooperative

# 1. Set white-label branding
coop.set_branding(
    company_name    = "Amul Dairy Tech",
    tagline         = "Smart Nutrition for Every Farmer",
    logo_url        = "https://cdn.amul.com/logo.png",
    primary_color   = "#B71C1C",   # → --primary CSS variable on tenant pages
    secondary_color = "#F57F17",
    contact_email   = "support@amuldairy.com",
)

# 2. Connect your WhatsApp number
coop.set_whatsapp(
    phone_number_id = "123456789012345",    # from Meta Business Manager
    access_token    = "EAABwzLixnjY...",    # System User Token
    verify_token    = "my_custom_secret",   # you choose this
    display_name    = "Amul Krishi Sahayak",
)
# Register in Meta Developer Console:
#   GET  https://pashudhan-nutri-ai.web.app/api/whatsapp/coop/{your_coop_id}
#   POST https://pashudhan-nutri-ai.web.app/api/whatsapp/coop/{your_coop_id}

# 3. Add your product catalog
prod = coop.add_product(
    name           = "MilkBoost Mineral Mix",
    sku            = "AMBMM-500",
    category       = "mineral_supplement",
    target_nutrient= "Ca_pct_DM",
    dose_g_per_day = 100,
    price_inr      = 85,
    product_link   = "https://shop.amul.com/milkboost",
)

# 4. Create recommendation rules
coop.add_rule(
    nutrient_key       = "Ca_pct_DM",         # Calcium
    trigger_condition  = "deficit_pct_above",  # fire when >10% short
    threshold          = 10,
    recommendation_type= "product",
    product_id         = prod["id"],
    suggested_qty_g    = 100,
    message_template   = "Ca deficit {gap_pct}%! Add {qty}g of {source} daily.",
    priority           = 3,
)
coop.add_rule(
    nutrient_key       = "Zn_mg_kg",
    trigger_condition  = "below_absolute",     # fire when Zn < 40 mg/kg absolute
    threshold          = 40,
    recommendation_type= "ingredient",
    ingredient_id      = "zinc_sulfate",
    ingredient_name    = "Zinc Sulfate",
    suggested_qty_g    = 5,
)

# 5. Register webhooks
coop.add_webhook(
    url="https://api.amuldairy.com/events",
    events=["*"],                              # receive all events
    description="Main ERP webhook",
)
coop.add_webhook(
    url="https://sms.amul.com/alerts",
    events=["deficiency.detected"],            # deficiency alerts only
)

# 6. Farmer analytics
dash = coop.get_dashboard()
print(f"Farmers: {dash['total_farmers']}, API calls: {dash['api_calls_used']}/{dash['api_calls_limit']}")

# 7. Webhook delivery logs
for wh in coop.list_webhooks():
    logs = coop.get_webhook_logs(wh["id"])
    print(f"{wh['url']}: {len(logs)} deliveries")
```

## Verify Incoming Webhooks

```python
from pashudhan_ai import WebhookVerifier

verifier = WebhookVerifier(api_key="pd_your_enterprise_key")

# Flask example:
from flask import Flask, request, abort, jsonify
app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def webhook():
    raw_body  = request.get_data()        # IMPORTANT: raw bytes BEFORE parsing
    signature = request.headers.get("X-Pashudhan-Signature", "")

    if not verifier.verify(raw_body, signature):
        abort(401, "Invalid webhook signature")

    event = request.json                  # now safe to parse
    if event["event"] == "recommendation.triggered":
        for rec in event["data"]["recommendations"]:
            # Push to your ERP / send SMS / etc.
            print(f"Push to farmer: {rec['message']} → buy: {rec['link']}")
    elif event["event"] == "deficiency.detected":
        deficiencies = event["data"]["deficiencies"]
        # Alert your field team
    elif event["event"] == "formulation.complete":
        data = event["data"]["formulation"]
        print(f"Ration: ₹{data['ration_cost_inr']}/day for {data['breed']}")

    return jsonify({"ok": True})
```

### Webhook Signature Details

| Property | Value |
|----------|-------|
| Header | `X-Pashudhan-Signature` |
| Format | Raw HMAC-SHA256 hexdigest — **no** `sha256=` prefix |
| Signing key | Your `pd_` API key (same as `x-api-key`) |
| Algorithm | HMAC-SHA256 over the raw UTF-8 body bytes |

**Always verify the raw body bytes before parsing.** Re-serializing JSON changes key order and breaks the signature.

## Webhook Event Envelope

Every event has this structure:

```json
{
  "event":          "formulation.complete",
  "timestamp":      "2026-09-04T12:00:00.123Z",
  "cooperative_id": "uid_abc123",
  "api_version":    "2026-09",
  "data": {
    ...event-specific fields...
  }
}
```

| Event | `data` contents | When |
|-------|----------------|------|
| `formulation.complete` | `formulation: {farmer_id, breed, ration_cost_inr, formulation_id}` | Every formulation |
| `deficiency.detected` | `deficiencies: {nutrient_key: {provided, required, gap_pct}}` | Any nutrient > 10% short |
| `recommendation.triggered` | `recommendations: [{rule_id, nutrient_key, gap_pct, type, source_name, link, ...}]` | Rules matched |
| `farmer.registered` | `{farmer_id, channel}` | First WhatsApp message from new farmer |

## Retry Policy

3 delivery attempts: **immediately → 5 seconds → 30 seconds → 5 minutes**. Endpoint must return HTTP 2xx within 10 seconds.

## Nutrient Keys

| Key | Nutrient | Unit | Standard |
|-----|----------|------|----------|
| `TDN_pct_DM` | Total Digestible Nutrients | % | NASEM/ICAR |
| `NEL_Mcal_kg` | Net Energy Lactation | Mcal/kg | NASEM/ICAR |
| `CP_pct_DM` | Crude Protein | % | NASEM/ICAR |
| `RUP_pct_CP` | Rumen Undegradable Protein | % of CP | NASEM |
| `NDF_pct_DM` | Neutral Detergent Fiber | % | NASEM/ICAR |
| `Ca_pct_DM` | Calcium | g | NASEM/ICAR |
| `P_pct_DM` | Phosphorus | g | NASEM/ICAR |
| `Zn_mg_kg` | Zinc | mg/kg | NASEM/ICAR |
| `Cu_mg_kg` | Copper | mg/kg | NASEM/ICAR |
| `vit_A_IU_kg` | Vitamin A | IU/kg | NASEM/ICAR |
| `vit_D_IU_kg` | Vitamin D | IU/kg | NASEM/ICAR |
| `EE_pct_DM` | Ether Extract / Fat | % | NASEM/ICAR |

**Standards routing** is automatic: ICAR-NDRI for Indian indigenous breeds (Sahiwal, Gir, Murrah, etc.) and all buffaloes. NASEM 2021 for crossbreeds (HF, Jersey) and Western/USA breeds.

## Configuration Guide

### Animal Parameters

- `animal_type`: `"cow"`, `"buffalo"`, `"heifer"`, `"bull"`
- `breed`: `"HF_crossbred"`, `"Sahiwal"`, `"Murrah"`, `"Gir"`, `"Jersey"`, etc.
- `body_weight_kg`: 10–1500 kg
- `milk_yield_kg_day`: 0–100 kg/day
- `production_stage`: `"early_lactation"`, `"mid_lactation"`, `"late_lactation"`, `"dry"`, `"pre_calving"`, `"growing"`

### Environmental Parameters

- `state`: Indian state (determines regional ingredient prices)
- `month`: 1–12 (seasonal availability)
- `location`: City name or `"lat,lon"` for live THI heat-stress data

## Security & IP Protection

All ICAR-NDRI+NASEM equations, Linear Programming solver, AI critique models, recommendation rule engine, ingredient databases, and regional pricing logic run exclusively on Pashudhan's secure Cloud Run backend. Nothing is exposed in this package.

## Documentation

Full API reference: [Developer Portal](https://pashudhan-nutri-ai.web.app/enterprise)
