Skip to main content

Installation

npm install @bijou/sdk
# or
yarn add @bijou/sdk
# or
pnpm add @bijou/sdk

Quick Start

import { BijouClient } from '@bijou/sdk';
import fs from 'fs';

// Initialize the client
const client = new BijouClient({ apiKey: 'bijou_your-key' });

// Detect an image
const buffer = fs.readFileSync('image.jpg');
const result = await client.detect(buffer);

console.log(`Prediction: ${result.prediction}`);
console.log(`Confidence: ${(result.confidence * 100).toFixed(1)}%`);
console.log(`Verdict: ${result.verdict}`);

Client Options

import { BijouClient } from '@bijou/sdk';

const client = new BijouClient({
  apiKey: 'bijou_your-key',              // Required
  baseUrl: 'https://api.trybijou.com/v1', // Optional
  timeout: 30000,                         // Optional, ms
  maxRetries: 3,                          // Optional
});

Detection Methods

From Buffer (Node.js)

import fs from 'fs';

const buffer = fs.readFileSync('image.jpg');
const result = await client.detect(buffer);

From Blob (Browser)

// From file input
const file = document.querySelector('input[type="file"]').files[0];
const result = await client.detect(file);

// From fetch
const response = await fetch('https://example.com/image.jpg');
const blob = await response.blob();
const result = await client.detect(blob);

From Base64 String

const base64 = 'iVBORw0KGgoAAAANSUhEUg...';
const result = await client.detect(base64);

// With data URL prefix (automatically stripped)
const dataUrl = 'data:image/jpeg;base64,iVBORw0KGgo...';
const result = await client.detect(dataUrl);

Detection Result

The DetectionResult object contains:
interface DetectionResult {
  prediction: 'ai' | 'real' | 'uncertain';
  confidence: number;           // 0.0 - 1.0
  ensembleScore: number;        // 0.0 - 1.0
  verdict: 'ai_generated' | 'likely_real' | 'uncertain';
  modelsSucceeded: number;
  modelsTotal: number;
  modelResults: Record<string, { score: number; latency_ms: number }>;
  detectionLatencyMs: number;
}

Error Handling

import {
  BijouClient,
  BijouAPIError,
  BijouInsufficientCreditsError,
  BijouRateLimitError,
  BijouValidationError,
  BijouTimeoutError,
} from '@bijou/sdk';

const client = new BijouClient({ apiKey: 'bijou_your-key' });

try {
  const result = await client.detect(imageBuffer);

} catch (error) {
  if (error instanceof BijouInsufficientCreditsError) {
    console.log(`Out of credits: ${error.message}`);

  } else if (error instanceof BijouRateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter}s`);

  } else if (error instanceof BijouValidationError) {
    console.log(`Invalid input: ${error.message}`);

  } else if (error instanceof BijouTimeoutError) {
    console.log(`Timed out after ${error.timeoutMs}ms`);

  } else if (error instanceof BijouAPIError) {
    console.log(`API error: ${error.message} (HTTP ${error.statusCode})`);
  }
}

Batch Detection

Process multiple images efficiently:
import { BijouClient } from '@bijou/sdk';
import fs from 'fs';
import path from 'path';

const client = new BijouClient({ apiKey: 'bijou_your-key' });

// Load images
const imageDir = './images';
const images = fs.readdirSync(imageDir)
  .filter(f => f.endsWith('.jpg'))
  .map(f => fs.readFileSync(path.join(imageDir, f)));

// Submit batch job
const job = await client.detectBatch(images);
console.log(`Job ID: ${job.jobId}`);

// Wait for results
const results = await client.waitForBatch(job.jobId);

for (const result of results.results) {
  console.log(`${result.prediction}: ${(result.confidence * 100).toFixed(1)}%`);
}

Factory Function

Use createClient for a more functional style:
import { createClient } from '@bijou/sdk';

const client = createClient({ apiKey: 'bijou_your-key' });
const result = await client.detect(imageBuffer);

Environment Variables

import { BijouClient } from '@bijou/sdk';

const client = new BijouClient({
  apiKey: process.env.BIJOU_API_KEY!,
});

Browser Usage

The SDK works in browsers too:
import { BijouClient } from '@bijou/sdk';

const client = new BijouClient({ apiKey: 'bijou_your-key' });

// From file input
document.querySelector('input[type="file"]')?.addEventListener('change', async (e) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (!file) return;

  try {
    const result = await client.detect(file);
    console.log(`Prediction: ${result.prediction}`);
  } catch (error) {
    console.error('Detection failed:', error);
  }
});
Never expose your API key in client-side code in production. Use a backend proxy to keep your key secure.

Full Example (Node.js)

#!/usr/bin/env npx ts-node
/**
 * Bijou AI Detection Example
 */
import { BijouClient, BijouInsufficientCreditsError } from '@bijou/sdk';
import fs from 'fs';
import path from 'path';

async function main() {
  // Initialize client
  const apiKey = process.env.BIJOU_API_KEY;
  if (!apiKey) {
    console.log('Set BIJOU_API_KEY environment variable');
    process.exit(1);
  }

  const client = new BijouClient({ apiKey });

  // Process images
  const imageDir = './test_images';
  const files = fs.readdirSync(imageDir).filter(f => f.endsWith('.jpg'));

  for (const file of files) {
    try {
      const buffer = fs.readFileSync(path.join(imageDir, file));
      const result = await client.detect(buffer);

      const status = result.prediction === 'ai' ? '🤖 AI' : '📷 Real';
      console.log(`${file}: ${status} (${(result.confidence * 100).toFixed(1)}%)`);

      // Show individual model scores
      for (const [model, data] of Object.entries(result.modelResults)) {
        console.log(`  ${model}: ${data.score.toFixed(2)}`);
      }

    } catch (error) {
      if (error instanceof BijouInsufficientCreditsError) {
        console.log('Out of credits! Buy more at trybijou.com/profile');
        break;
      }
      throw error;
    }
  }
}

main().catch(console.error);

TypeScript Types

All types are exported for use in your application:
import type {
  BijouClientOptions,
  DetectionResult,
  DetectionOptions,
  ModelScore,
  BatchDetectionResult,
  BatchJobStatus,
  CreditBalance,
} from '@bijou/sdk';