# CLI और SDK मार्गदर्शिका

## ओवरव्यू

Clore.ai प्रदान करता है **REST API** जो GPU मार्केटप्लेेस तक पूर्ण प्रोग्रामेटिक पहुंच सक्षम बनाता है — सर्वर सूचीबद्ध करना, ऑर्डर बनाना, डिप्लॉयमेंट मॉनिटर करना, और रेंटल रद्द करना।

> **नोट:** इस समय कोई आधिकारिक CLI बाइनरी उपलब्ध नहीं है। सभी ऑटोमेशन सीधे REST API के माध्यम से ऐसे टूल्स का उपयोग करके किया जाता है `curl`, Python, या Node.js।

**बेस URL:** `https://api.clore.ai/v1`

**प्रतिक्रिया प्रारूप:** JSON। प्रत्येक प्रतिक्रिया में एक शामिल होता है `code` फ़ील्ड जो स्थिति दर्शाता है।

***

## प्रामाणिकरण

अपनी API कुंजी उत्पन्न करें से [Clore.ai डैशबोर्ड](https://clore.ai):

1. अपने खाते में लॉग इन करें
2. नेविगेट करें **API** सेटिंग्स में सेक्शन
3. अपनी API कुंजी जनरेट और कॉपी करें

**हेडर प्रारूप:**

```
auth: YOUR_API_KEY
```

> ⚠️ **महत्वपूर्ण:** auth हेडर है `auth`, **नहीं** `Authorization: Bearer`। गलत प्रारूप का उपयोग करने पर कोड लौटेगा `3` (अमान्य API टोकन)।

**उदाहरण:**

```bash
curl -H 'auth: YOUR_API_KEY' 'https://api.clore.ai/v1/marketplace'
```

***

## क्विक स्टार्ट

### मार्केटप्लेस सर्वर सूचीबद्ध करें

सभी उपलब्ध GPU सर्वरों ब्राउज़ करें:

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/marketplace'
```

**प्रतिक्रिया:**

```json
{
  "servers": [
    {
      "id": 6,
      "owner": 4,
      "mrl": 73,
      "price": {
        "on_demand": { "bitcoin": 0.00001 },
        "spot": { "bitcoin": 0.000001 }
      },
      "rented": false,
      "specs": {
        "cpu": "Intel Core i9-11900",
        "ram": 62.67,
        "gpu": "1x NVIDIA GeForce GTX 1080 Ti",
        "gpuram": 11,
        "net": { "up": 26.38, "down": 118.42, "cc": "CZ" }
      }
    }
  ],
  "my_servers": [1, 2, 4],
  "code": 0
}
```

***

### अपने ऑर्डर प्राप्त करें

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/my_orders'
```

पूरा/समाप्त ऑर्डर शामिल करें:

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/my_orders?return_completed=true'
```

***

### एक ऑर्डर बनाएं (ऑन-डिमांड)

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "currency": "bitcoin",
    "image": "cloreai/ubuntu20.04-jupyter",
    "renting_server": 6,
    "type": "on-demand",
    "ports": {
      "22": "tcp",
      "8888": "http"
    },
    "ssh_password": "YourSSHPassword123",
    "jupyter_token": "YourJupyterToken123"
  }' \
  'https://api.clore.ai/v1/create_order'
```

**प्रतिक्रिया:**

```json
{ "code": 0 }
```

***

### एक स्पॉट ऑर्डर बनाएं

स्पॉट ऑर्डर सस्ते होते हैं लेकिन बिड से बाहर हो सकते हैं। आप प्रति दिन अपनी कीमत सेट करते हैं:

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "currency": "bitcoin",
    "image": "cloreai/ubuntu20.04-jupyter",
    "renting_server": 6,
    "type": "spot",
    "spotprice": 0.000005,
    "ports": {
      "22": "tcp",
      "8888": "http"
    },
    "ssh_password": "YourSSHPassword123"
  }' \
  'https://api.clore.ai/v1/create_order'
```

***

### ऑर्डर स्थिति जांचें

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/my_orders'
```

सक्रिय ऑर्डरों में शामिल हैं `pub_cluster` (होस्टनाम) और `tcp_ports` SSH एक्सेस के लिए:

```json
{
  "id": 38,
  "pub_cluster": ["n1.c1.clorecloud.net", "n2.c1.clorecloud.net"],
  "tcp_ports": ["22:10000"],
  "http_port": "8888",
  "expired": false
}
```

अपने किराए पर लिये सर्वर में SSH करें:

```bash
ssh root@n1.c1.clorecloud.net -p 10000
```

***

### ऑर्डर रद्द करें

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "id": 38
  }' \
  'https://api.clore.ai/v1/cancel_order'
```

वैकल्पिक रूप से सर्वर के साथ समस्या रिपोर्ट करें:

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "id": 38,
    "issue": "GPU गर्म हो रहा था और प्रदर्शन को धीमा कर रहा था"
  }' \
  'https://api.clore.ai/v1/cancel_order'
```

***

## Python SDK

एक हल्का रैपर उपयोग करते हुए `requests` लाइब्रेरी। इसे इंस्टॉल करें:

```bash
pip install requests
```

### CloreClient क्लास

```python
import requests
import time

class CloreClient:
    """Clore.ai REST API के लिए साधारण Python SDK."""
    
    BASE_URL = "https://api.clore.ai/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({"auth": api_key})
    
    def _get(self, endpoint: str, params: dict = None) -> dict:
        url = f"{self.BASE_URL}/{endpoint}"
        response = self.session.get(url, params=params)
        response.raise_for_status()
        data = response.json()
        if data.get("code") != 0:
            raise CloreAPIError(data)
        return data
    
    def _post(self, endpoint: str, body: dict) -> dict:
        url = f"{self.BASE_URL}/{endpoint}"
        self.session.headers.update({"Content-type": "application/json"})
        response = self.session.post(url, json=body)
        response.raise_for_status()
        data = response.json()
        if data.get("code") != 0:
            raise CloreAPIError(data)
        return data
    
    def list_servers(self) -> list:
        """मार्केटप्लेस पर सभी उपलब्ध सर्वर प्राप्त करें."""
        data = self._get("marketplace")
        return data["servers"]
    
    def get_server_details(self, server_id: int) -> dict:
        """किसी विशिष्ट सर्वर के लिए स्पॉट मार्केटप्लेस जानकारी प्राप्त करें."""
        data = self._get("spot_marketplace", params={"market": server_id})
        return data["market"]
    
    def create_order(
        self,
        server_id: int,
        image: str,
        order_type: str = "on-demand",
        currency: str = "bitcoin",
        spotprice: float = None,
        ports: dict = None,
        ssh_password: str = None,
        ssh_key: str = None,
        jupyter_token: str = None,
        env: dict = None,
        command: str = None,
    ) -> dict:
        """
        एक ऑन-डिमांड या स्पॉट ऑर्डर बनाएं।
        
        आर्ग्स:
            server_id: रेंट करने के लिए सर्वर का ID
            image: Docker इमेज (जैसे 'cloreai/ubuntu20.04-jupyter')
            order_type: 'on-demand' या 'spot'
            currency: 'bitcoin' (डिफ़ॉल्ट)
            spotprice: स्पॉट ऑर्डरों के लिए आवश्यक — प्रति दिन की कीमत BTC में
            ports: पोर्ट फॉरवर्डिंग, उदाहरण {"22": "tcp", "8888": "http"}
            ssh_password: SSH पासवर्ड (केवल अल्फ़ान्यूमेरिक अक्षर)
            ssh_key: SSH पब्लिक की
            jupyter_token: Jupyter नोटबुक टोकन
            env: पर्यावरण चर (डिक्ट)
            command: कंटेनर शुरू होने के बाद चलाने का शेल कमांड
        """
        if order_type == "spot" and spotprice is None:
            raise ValueError("स्पॉट ऑर्डरों के लिए spotprice आवश्यक है")
        
        body = {
            "currency": currency,
            "image": image,
            "renting_server": server_id,
            "type": order_type,
        }
        
        if spotprice is not None:
            body["spotprice"] = spotprice
        if ports:
            body["ports"] = ports
        if ssh_password:
            body["ssh_password"] = ssh_password
        if ssh_key:
            body["ssh_key"] = ssh_key
        if jupyter_token:
            body["jupyter_token"] = jupyter_token
        if env:
            body["env"] = env
        if command:
            body["command"] = command
        
        return self._post("create_order", body)
    
    def get_orders(self, include_completed: bool = False) -> list:
        """अपने सक्रिय (और वैकल्पिक रूप से पूर्ण) ऑर्डर प्राप्त करें."""
        params = {"return_completed": "true"} if include_completed else {}
        data = self._get("my_orders", params=params)
        return data["orders"]
    
    def cancel_order(self, order_id: int, issue: str = None) -> dict:
        """एक ऑर्डर रद्द करें। वैकल्पिक रूप से एक समस्या रिपोर्ट करें."""
        body = {"id": order_id}
        if issue:
            body["issue"] = issue
        return self._post("cancel_order", body)
    
    def get_wallets(self) -> list:
        """अपने वॉलेट और बैलेंस प्राप्त करें."""
        data = self._get("wallets")
        return data["wallets"]
    
    def get_my_servers(self) -> list:
        """वो सर्वर प्राप्त करें जिन्हें आप मार्केटप्लेस को प्रदान कर रहे हैं."""
        data = self._get("my_servers")
        return data["servers"]


class CloreAPIError(Exception):
    """जब Clore API शून्य से भिन्न कोड लौटाता है तो उठाया जाता है।"""
    
    ERROR_CODES = {
        0: "सामान्य",
        1: "डेटाबेस त्रुटि",
        2: "अमान्य इनपुट डेटा",
        3: "अमान्य API टोकन",
        4: "अमान्य अंतबिंदु",
        5: "रेट लिमिट पार (1 req/sec)",
        6: "त्रुटि (त्रुटि फ़ील्ड देखें)",
    }
    
    def __init__(self, response: dict):
        self.code = response.get("code")
        self.error = response.get("error", "")
        message = self.ERROR_CODES.get(self.code, f"Unknown code {self.code}")
        if self.error:
            message = f"{message}: {self.error}"
        super().__init__(f"Clore API error {self.code}: {message}")
```

### पूर्ण कार्यशील उदाहरण

```python
import os
from clore_client import CloreClient, CloreAPIError

# क्लाइंट इनिशियलाइज़ करें
client = CloreClient(api_key=os.environ["CLORE_API_KEY"])

# 1. मार्केटप्लेस ब्राउज़ करें
servers = client.list_servers()
print(f"Marketplace पर {len(servers)} सर्वर मिले")

# 2. उपलब्ध RTX 4090 सर्वरों को फ़िल्टर करें
rtx4090_servers = [
    s for s in servers
    if "4090" in s["specs"].get("gpu", "") and not s["rented"]
]

if not rtx4090_servers:
    print("कोई उपलब्ध RTX 4090 सर्वर नहीं मिला")
    exit(1)

# 3. सबसे सस्ता चुनें
cheapest = min(rtx4090_servers, key=lambda s: s["price"]["on_demand"]["bitcoin"])
print(f"सबसे सस्ता RTX 4090: सर्वर ID {cheapest['id']}, "
      f"कीमत {cheapest['price']['on_demand']['bitcoin']:.8f} BTC/दिन")

# 4. एक ऑर्डर बनाएं
try:
    client.create_order(
        server_id=cheapest["id"],
        image="cloreai/ubuntu20.04-jupyter",
        order_type="on-demand",
        currency="bitcoin",
        ports={"22": "tcp", "8888": "http"},
        ssh_password="SecurePass123",
        jupyter_token="MyToken123",
    )
    print("ऑर्डर सफलतापूर्वक बनाया गया!")
except CloreAPIError as e:
    print(f"ऑर्डर बनाने में विफल: {e}")
    exit(1)

# 5. अपने ऑर्डर जांचें
orders = client.get_orders()
for order in orders:
    if not order.get("expired"):
        cluster = order.get("pub_cluster", [])
        tcp = order.get("tcp_ports", [])
        print(f"ऑर्डर {order['id']}: सर्वर {order['si']}")
        if cluster and tcp:
            ssh_port = tcp[0].split(":")[1]
            print(f"  SSH: ssh root@{cluster[0]} -p {ssh_port}")
```

***

## Node.js उदाहरण

नेटिव का उपयोग करते हुए `fetch` API (Node.js 18+):

```javascript
const BASE_URL = 'https://api.clore.ai/v1';

class CloreClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.defaultHeaders = {
      'auth': apiKey,
    };
  }

  async get(endpoint, params = {}) {
    const url = new URL(`${BASE_URL}/${endpoint}`);
    Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
    
    const res = await fetch(url.toString(), {
      headers: this.defaultHeaders,
    });
    
    const data = await res.json();
    if (data.code !== 0) {
      throw new Error(`Clore API error ${data.code}: ${data.error || 'unknown'}`);
    }
    return data;
  }

  async post(endpoint, body) {
    const res = await fetch(`${BASE_URL}/${endpoint}`, {
      method: 'POST',
      headers: {
        ...this.defaultHeaders,
        'Content-type': 'application/json',
      },
      body: JSON.stringify(body),
    });
    
    const data = await res.json();
    if (data.code !== 0) {
      throw new Error(`Clore API error ${data.code}: ${data.error || 'unknown'}`);
    }
    return data;
  }

  async listServers() {
    const data = await this.get('marketplace');
    return data.servers;
  }

  async getOrders(includeCompleted = false) {
    const params = includeCompleted ? { return_completed: 'true' } : {};
    const data = await this.get('my_orders', params);
    return data.orders;
  }

  async createOrder({ serverId, image, type = 'on-demand', currency = 'bitcoin', spotprice, ports, sshPassword, jupyterToken, env, command }) {
    const body = {
      currency,
      image,
      renting_server: serverId,
      type,
      ...(spotprice && { spotprice }),
      ...(ports && { ports }),
      ...(sshPassword && { ssh_password: sshPassword }),
      ...(jupyterToken && { jupyter_token: jupyterToken }),
      ...(env && { env }),
      ...(command && { command }),
    };
    return this.post('create_order', body);
  }

  async cancelOrder(orderId, issue = null) {
    const body = { id: orderId };
    if (issue) body.issue = issue;
    return this.post('cancel_order', body);
  }
}

// उपयोग का उदाहरण
const client = new CloreClient(process.env.CLORE_API_KEY);

async function main() {
  // मार्केटप्लेस सूचीबद्ध करें
  const servers = await client.listServers();
  console.log(`मार्केटप्लेस में ${servers.length} सर्वर हैं`);

  // उपलब्ध RTX 4090 सर्वर ढूंढें
  const available = servers.filter(
    s => s.specs.gpu.includes('4090') && !s.rented
  );
  console.log(`उपलब्ध RTX 4090 सर्वर: ${available.length}`);

  // वर्तमान ऑर्डर प्राप्त करें
  const orders = await client.getOrders();
  const activeOrders = orders.filter(o => !o.expired);
  console.log(`सक्रिय ऑर्डर: ${activeOrders.length}`);

  for (const order of activeOrders) {
    const host = order.pub_cluster?.[0];
    const portMapping = order.tcp_ports?.[0];
    if (host && portMapping) {
      const sshPort = portMapping.split(':')[1];
      console.log(`ऑर्डर ${order.id} → ssh root@${host} -p ${sshPort}`);
    }
  }
}

main().catch(console.error);
```

***

## सामान्य वर्कफ़्लो

### सबसे सस्ता RTX 4090 खोजें और इसे किराए पर लें

```python
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def rent_cheapest_rtx4090(image="cloreai/ubuntu20.04-jupyter", ssh_password="SecurePass123"):
    servers = client.list_servers()
    
    # फ़िल्टर: उपलब्ध RTX 4090
    candidates = [
        s for s in servers
        if "4090" in s["specs"].get("gpu", "")
        and not s["rented"]
    ]
    
    if not candidates:
        raise RuntimeError("कोई उपलब्ध RTX 4090 सर्वर नहीं मिला")
    
    # ऑन-डिमांड BTC कीमत के अनुसार सॉर्ट करें
    candidates.sort(key=lambda s: s["price"]["on_demand"]["bitcoin"])
    best = candidates[0]
    
    price_btc = best["price"]["on_demand"]["bitcoin"]
    print(f"सर्वर रेंट कर रहे हैं {best['id']}: {best['specs']['gpu']} @ {price_btc:.8f} BTC/दिन")
    
    client.create_order(
        server_id=best["id"],
        image=image,
        order_type="on-demand",
        currency="bitcoin",
        ports={"22": "tcp"},
        ssh_password=ssh_password,
    )
    
    print("हो गया! SSH कनेक्शन विवरण के लिए अपने ऑर्डर चेक करें.")
    return best["id"]

rent_cheapest_rtx4090()
```

***

### अपने ऑर्डर मॉनिटर करें

```python
import time
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def monitor_orders(poll_interval_seconds=60):
    """ऑर्डरों को पोल करें और स्थिति अपडेट प्रिंट करें."""
    print(f"ऑर्डरों की निगरानी (हर {poll_interval_seconds}s पर पोल किया जा रहा है). रोकने के लिए Ctrl+C.\n")
    
    while True:
        orders = client.get_orders(include_completed=False)
        active = [o for o in orders if not o.get("expired")]
        
        print(f"--- {len(active)} सक्रिय ऑर्डर(स) ---")
        for order in active:
            cluster = order.get("pub_cluster", [])
            tcp = order.get("tcp_ports", [])
            spend = order.get("spend", 0)
            
            ssh_info = ""
            if cluster and tcp:
                port = tcp[0].split(":")[1]
                ssh_info = f" | SSH: {cluster[0]}:{port}"
            
            print(f"  ऑर्डर {order['id']}: सर्वर {order['si']}"
                  f" | खर्च {spend:.8f} BTC{ssh_info}")
        
        if not active:
            print("  कोई सक्रिय ऑर्डर नहीं है.")
        
        print()
        time.sleep(poll_interval_seconds)

monitor_orders()
```

***

### जब कीमत X से नीचे गिरे तो ऑटो-रेंट

```python
import time
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def auto_rent_on_price_drop(
    gpu_model: str = "RTX 4090",
    max_price_btc: float = 0.00015,
    image: str = "cloreai/ubuntu20.04-jupyter",
    ssh_password: str = "SecurePass123",
    check_interval_seconds: int = 120,
):
    """
    मार्केटप्लेस देखें और जब कीमत संकेतक से नीचे गिरे तो GPU को ऑटो-रेंट करें।
    
    आर्ग्स:
        gpu_model: खोजने के लिए GPU नाम (केस-इन्सेंसिटिव)
        max_price_btc: BTC में प्रति दिन अधिकतम स्वीकार्य कीमत
        image: डिप्लॉय करने के लिए Docker इमेज
        ssh_password: कंटेनर के लिए SSH पासवर्ड
        check_interval_seconds: कितनी बार जांचें (रेट लिमिट का सम्मान करें!)
    """
    print(f"{gpu_model} के लिए देख रहे हैं ≤ {max_price_btc:.8f} BTC/दिन...")
    
    while True:
        servers = client.list_servers()
        
        for server in servers:
            gpu = server["specs"].get("gpu", "")
            if gpu_model.lower() not in gpu.lower():
                continue
            if server["rented"]:
                continue
            
            price = server["price"]["on_demand"]["bitcoin"]
            if price <= max_price_btc:
                print(f"🎯 मैच मिला! सर्वर {server['id']}: {gpu} @ {price:.8f} BTC/दिन")
                
                try:
                    client.create_order(
                        server_id=server["id"],
                        image=image,
                        order_type="on-demand",
                        currency="bitcoin",
                        ports={"22": "tcp"},
                        ssh_password=ssh_password,
                        required_price=price,  # इस कीमत को लॉक करें
                    )
                    print(f"✅ सर्वर {server['id']} के लिए ऑर्डर बनाया गया!")
                    return server["id"]
                except Exception as e:
                    print(f"Failed to create order: {e}. Will retry...")
        
        print(f"No match yet. Checking again in {check_interval_seconds}s...")
        time.sleep(check_interval_seconds)

auto_rent_on_price_drop(gpu_model="4090", max_price_btc=0.00012)
```

***

## WebSocket

Clore.ai REST API वर्तमान में WebSocket endpoint उजागर नहीं करता है। रीयल-टाइम निगरानी के लिए, उपयुक्त अंतराल के साथ polling का उपयोग करें (नीचे दिए गए दर सीमाओं को देखें)।

***

## दर सीमाएँ

| एंडपॉइंट                       | सीमा                       |
| ------------------------------ | -------------------------- |
| अधिकांश एंडपॉइंट               | **1 अनुरोध/सेकंड**         |
| `create_order`                 | **1 अनुरोध/5 सेकंड**       |
| `set_spot_price` (मूल्य कटौती) | एक बार प्रति **600 सेकंड** |

**दर-सीमा प्रतिक्रिया (कोड 5):**

```json
{ "code": 5 }
```

**सर्वोत्तम अभ्यास:**

* जोड़ें `time.sleep(1)` लगातार API कॉल्स के बीच
* के लिए `create_order`, अनुरोधों के बीच कम से कम 5 सेकंड प्रतीक्षा करें
* मॉनिटरिंग लूप्स के लिए 60+ सेकंड के polling अंतराल का उपयोग करें
* यदि आपको मार्केटप्लेस डेटा अक्सर पूछना है तो उसे स्थानीय रूप से कैश करें

**Python सहायक:**

```python
import time

def safe_api_call(fn, *args, delay=1.1, **kwargs):
    """एक API कॉल को दर-सीमा सुरक्षा के साथ रैप करें."""
    result = fn(*args, **kwargs)
    time.sleep(delay)
    return result
```

***

## त्रुटि हैंडलिंग

प्रत्येक API प्रतिक्रिया में एक `code` फील्ड शामिल होता है। एक मान `0` सफलता का संकेत देता है।

### त्रुटि कोड

| कोड | अर्थ                                   | कदम                                       |
| --- | -------------------------------------- | ----------------------------------------- |
| `0` | सफलता                                  | —                                         |
| `1` | डेटाबेस त्रुटि                         | देरी के बाद पुन: प्रयास करें              |
| `2` | अमान्य इनपुट डेटा                      | अपने अनुरोध बॉडी/पैरामीटर जांचें          |
| `3` | अमान्य API टोकन                        | डैशबोर्ड में अपना API कुंजी सत्यापित करें |
| `4` | अमान्य एंडपॉइंट                        | एंडपॉइंट URL जांचें                       |
| `5` | दर-सीमा पार हुई (1 req/sec)            | अनुरोधों के बीच देरी जोड़ें               |
| `6` | एप्लिकेशन त्रुटि (देखें `error` फील्ड) | विस्तार के लिए `error` फील्ड पढ़ें        |

### कोड 6 उप-त्रुटियाँ

| `error` मान                   | अर्थ                                                                                 |
| ----------------------------- | ------------------------------------------------------------------------------------ |
| `exceeded_max_step`           | स्पॉट मूल्य कमी बहुत अधिक; जाँचें `max_step` फील्ड                                   |
| `can_lower_every_600_seconds` | स्पॉट मूल्य को फिर से कम करने से पहले प्रतीक्षा आवश्यक है; जाँचें `time_to_lowering` |

### Python त्रुटि हैंडलिंग उदाहरण

```python
from clore_client import CloreClient, CloreAPIError
import time

client = CloreClient(api_key="YOUR_API_KEY")

def create_order_with_retry(server_id, image, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.create_order(
                server_id=server_id,
                image=image,
                order_type="on-demand",
                currency="bitcoin",
                ports={"22": "tcp"},
                ssh_password="SecurePass123",
            )
        except CloreAPIError as e:
            if e.code == 5:  # Rate limit
                print(f"Rate limited. Waiting 5s... (attempt {attempt+1}/{max_retries})")
                time.sleep(5)
            elif e.code == 3:  # Bad API key
                print("Invalid API key! Check your CLORE_API_KEY.")
                raise
            elif e.code == 2:  # Bad input
                print(f"Invalid request: {e}")
                raise
            else:
                print(f"API error: {e}. Retrying in 3s...")
                time.sleep(3)
    
    raise RuntimeError(f"Failed after {max_retries} attempts")
```

### JavaScript त्रुटि हैंडलिंग उदाहरण

```javascript
async function createOrderWithRetry(client, serverConfig, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await client.createOrder(serverConfig);
    } catch (err) {
      const code = parseInt(err.message.match(/error (\d+)/)?.[1]);
      
      if (code === 5) {
        console.log(`Rate limited. Waiting 5s... (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(r => setTimeout(r, 5000));
      } else if (code === 3) {
        throw new Error('Invalid API key');
      } else {
        console.log(`API error: ${err.message}. Retrying in 3s...`);
        await new Promise(r => setTimeout(r, 3000));
      }
    }
  }
  throw new Error(`Failed after ${maxRetries} attempts`);
}
```

***

## उपलब्ध Docker इमेजेज

Clore.ai GPU वर्कलोड के लिए अनुकूलित पूर्व-निर्मित इमेजेज प्रदान करता है:

| इमेज                          | विवरण                     |
| ----------------------------- | ------------------------- |
| `cloreai/ubuntu20.04-jupyter` | Ubuntu 20.04 + JupyterLab |
| `cloreai/ubuntu22.04-jupyter` | Ubuntu 22.04 + JupyterLab |

आप किसी भी सार्वजनिक Docker Hub इमेज का भी उपयोग कर सकते हैं। GPU पहुँच के लिए, CUDA-सक्षम इमेजेज का उपयोग करें, उदाहरण के लिए:

```
nvidia/cuda:12.1.0-devel-ubuntu22.04
```

***

## पोर्ट फॉरवर्डिंग

ऑर्डर बनाते समय, एक्सपोज़ करने के लिए पोर्ट निर्दिष्ट करें:

```json
{
  "ports": {
    "22": "tcp",
    "8888": "http",
    "6006": "http"
  }
}
```

* **`"tcp"`** — डायरेक्ट TCP पोर्ट फॉरवर्डिंग (SSH, कस्टम सर्वरों के लिए)
* **`"http"`** — HTTPS प्रॉक्सी (Jupyter, वेब UIs के लिए)। प्रत्येक के लिए केवल एक HTTP पोर्ट की अनुमति है `http_port` फील्ड।

ऑर्डर निर्माण के बाद, कनेक्शन विवरण में दिखाई देते हैं `my_orders`:

```json
{
  "pub_cluster": ["n1.c1.clorecloud.net", "n2.c1.clorecloud.net"],
  "tcp_ports": ["22:10000"],
  "http_port": "8888"
}
```

SSH के माध्यम से कनेक्ट करें:

```bash
ssh root@n1.c1.clorecloud.net -p 10000
```

ब्राउज़र के माध्यम से Jupyter तक पहुँचें: `https://n1.c1.clorecloud.net` (उपयोग करता है कि `http_port`)
