page_shot / API_GUIDE.md
CatPtain's picture
Upload 2 files
2018c79 verified

API Authentication & Usage Guide

πŸ” Setting Up API Key in Hugging Face Spaces

Step 1: Generate Secure API Key

# Generate random API key (example methods)
node -e "console.log('sk-' + require('crypto').randomBytes(32).toString('hex'))"
# Or use Python
python -c "import secrets; print('sk-' + secrets.token_hex(32))"

Step 2: Configure in HF Spaces

  1. Navigate to your Space: https://huggingface.co/spaces/your-username/space-name
  2. Click "Settings" tab
  3. Click "Variables" section
  4. Add this environment variable:
Variable Value Description
API_KEY sk-your-secure-key-here Single API key for authentication

Step 3: Test Authentication

# Test without API key (should fail if authentication enabled)
curl -X POST https://your-space.hf.space/screenshot \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

# Test with API key (should work)
curl -X POST https://your-space.hf.space/screenshot \
  -H "Authorization: Bearer your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

πŸ“Š Understanding Server Status Responses

Normal Operation

{
  "status": "running",
  "system": { "cpuUsage": "25%" },
  "queue": { "activeRequests": 1, "queuedRequests": 0 }
}

Server Busy (CPU > 95%)

{
  "status": "busy",
  "error": "Server is currently overloaded",
  "cpuUsage": "96%",
  "queueLength": 3
}

Queue Full Response

{
  "status": "busy", 
  "error": "Request queue timeout",
  "queueLength": 10
}

πŸ”„ Implementing Retry Logic

JavaScript Retry Pattern

async function screenshotWithRetry(url, options = {}, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch('/screenshot', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer your-api-key'
        },
        body: JSON.stringify({ url, ...options })
      });

      if (response.ok) {
        return await response.blob();
      }

      if (response.status === 503) {
        const error = await response.json();
        if (error.status === 'busy') {
          console.log(`Attempt ${attempt}: Server busy, retrying...`);
          await new Promise(resolve => setTimeout(resolve, 2000 * attempt));
          continue;
        }
      }

      // Other errors, don't retry
      throw new Error(`API Error: ${response.status}`);
      
    } catch (error) {
      if (attempt === maxRetries) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
}

Python Retry Pattern

import time
import requests
from typing import Optional

def screenshot_with_retry(url: str, api_key: str, max_retries: int = 3) -> Optional[bytes]:
    for attempt in range(1, max_retries + 1):
        try:
            response = requests.post(
                'https://your-space.hf.space/screenshot',
                headers={'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'},
                json={'url': url},
                timeout=30
            )
            
            if response.status_code == 200:
                return response.content
                
            if response.status_code == 503:
                error_data = response.json()
                if error_data.get('status') == 'busy':
                    print(f"Attempt {attempt}: Server busy (CPU: {error_data.get('cpuUsage', 'N/A')})")
                    time.sleep(2 * attempt)
                    continue
                    
            response.raise_for_status()
            
        except requests.RequestException as e:
            if attempt == max_retries:
                raise e
            time.sleep(attempt)
    
    return None

🚨 Rate Limiting & Best Practices

Rate Limit Headers

The API returns rate limiting information:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200

Best Practices

  1. Implement exponential backoff for retries
  2. Cache results when possible
  3. Use appropriate image quality (70-80% usually sufficient)
  4. Monitor your usage via /status endpoint
  5. Handle queue timeouts gracefully

Production Usage Example

class ScreenshotAPI {
  constructor(apiKey, baseUrl) {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
    this.requestCount = 0;
    this.resetTime = 0;
  }

  async screenshot(url, options = {}) {
    // Check rate limit
    if (this.requestCount >= 95 && Date.now() < this.resetTime) {
      throw new Error('Rate limit approached, waiting...');
    }

    const response = await this.makeRequest('/screenshot', {
      method: 'POST',
      body: JSON.stringify({ url, ...options })
    });

    // Update rate limit tracking
    this.requestCount = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
    this.resetTime = parseInt(response.headers.get('X-RateLimit-Reset') || '0') * 1000;

    return response;
  }

  async makeRequest(endpoint, options = {}) {
    return fetch(this.baseUrl + endpoint, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.apiKey}`,
        ...options.headers
      }
    });
  }
}

πŸ”§ Troubleshooting

Common Issues

Error Cause Solution
401 Unauthorized Missing API key Add Authorization: Bearer header
403 Forbidden Invalid API key Check key spelling/validity
503 Service Unavailable Server overloaded Implement retry with delay
429 Too Many Requests Rate limit exceeded Wait for reset time

Performance Optimization

  • Use smaller dimensions for faster processing
  • Lower quality settings for non-critical uses
  • Batch requests with appropriate delays
  • Monitor CPU usage via /status