piclets-server / API_DOCUMENTATION.md
Fraser's picture
UPDATE
f9201f6

A newer version of the Gradio SDK is available: 5.49.1

Upgrade

Piclets Discovery Server API Documentation

Overview

The Piclets Discovery Server provides a Gradio-based API for the Piclets discovery game. Each real-world object has ONE canonical Piclet, with variations tracked based on attributes. All data is stored in a public HuggingFace Dataset.

Quick Start

Running Locally

pip install -r requirements.txt
python app.py

Accessing the API

Frontend Integration

import { Client } from "@gradio/client";

const client = await Client.connect("Fraser/piclets-server");
const result = await client.predict("/search_piclet", {
  object_name: "pillow",
  attributes: ["velvet"]
});

API Endpoints

1. Search Piclet

Endpoint: /search_piclet Purpose: Search for canonical Piclet or variations Method: Gradio function call

Input Parameters:

{
  "object_name": "pillow",
  "attributes": ["velvet", "blue"]
}

Response Types:

New Object (no Piclet exists):

{
  "status": "new",
  "message": "No Piclet found for 'pillow'",
  "piclet": null
}

Existing Canonical (exact match):

{
  "status": "existing",
  "message": "Found canonical Piclet for 'pillow'",
  "piclet": {
    "objectName": "pillow",
    "typeId": "pillow_canonical",
    "discoveredBy": "user123",
    "discoveredAt": "2024-07-26T10:30:00",
    "scanCount": 42,
    "picletData": { /* full Piclet data */ }
  }
}

Variation Found:

{
  "status": "variation",
  "message": "Found variation of 'pillow'",
  "piclet": { /* variation data */ },
  "canonicalId": "pillow_canonical"
}

New Variation Suggested:

{
  "status": "new_variation",
  "message": "No variation found for 'pillow' with attributes ['velvet', 'blue']",
  "canonicalId": "pillow_canonical",
  "piclet": null
}

2. Create Canonical

Endpoint: /create_canonical Purpose: Register the first discovery of an object with OAuth verification Method: Gradio function call

Input Parameters:

{
  "object_name": "pillow",
  "piclet_data": "{ /* JSON string of Piclet instance */ }",
  "token_or_username": "hf_xxxxxxxxxxxxx"  // OAuth token or username for testing
}

Success Response:

{
  "success": true,
  "message": "Created canonical Piclet for 'pillow'",
  "piclet": {
    "objectName": "pillow",
    "typeId": "pillow_canonical",
    "discoveredBy": "username123",
    "discovererSub": "987654321",
    "discovererUsername": "username123",
    "discovererName": "Display Name",
    "discovererPicture": "/static-proxy?url=https%3A%2F%2Favatars.huggingface.co%2F...",
    "discoveredAt": "2024-07-26T10:30:00",
    "scanCount": 1,
    "picletData": { /* full Piclet data */ }
  }
}

Error Responses:

{
  "success": false,
  "error": "Invalid OAuth token"
}
{
  "success": false,
  "error": "Failed to save canonical Piclet"
}

Notes:

  • If token_or_username starts with hf_, it's verified as an OAuth token
  • Token verification calls https://huggingface.co/oauth/userinfo
  • User profile is created/updated with cached OAuth fields
  • Legacy mode: Plain usernames create legacy_{username} profiles

3. Create Variation

Endpoint: /create_variation Purpose: Add a variation to an existing canonical Piclet with OAuth verification Method: Gradio function call

Input Parameters:

{
  "canonical_id": "pillow_canonical",
  "attributes": ["velvet", "blue"],
  "piclet_data": "{ /* JSON string of variation data */ }",
  "token_or_username": "hf_xxxxxxxxxxxxx",  // OAuth token or username for testing
  "object_name": "pillow"
}

Success Response:

{
  "success": true,
  "message": "Created variation of 'pillow'",
  "piclet": {
    "typeId": "pillow_001",
    "attributes": ["velvet", "blue"],
    "discoveredBy": "player456",
    "discovererSub": "123456789",
    "discovererUsername": "player456",
    "discovererName": "Player Name",
    "discovererPicture": "/static-proxy?url=https%3A%2F%2Favatars.huggingface.co%2F...",
    "discoveredAt": "2024-07-26T11:00:00",
    "scanCount": 1,
    "picletData": { /* variation data */ }
  }
}

Error Responses:

{
  "success": false,
  "error": "Invalid OAuth token"
}
{
  "success": false,
  "error": "Canonical Piclet not found for 'pillow'"
}

Notes:

  • Same OAuth verification as create_canonical
  • User profile updated with variation discovery (+50 rarity points)
  • Variation numbering is automatic (pillow_001, pillow_002, etc.)

4. Increment Scan Count

Endpoint: /increment_scan_count Purpose: Track how many times a Piclet has been discovered Method: Gradio function call

Input Parameters:

{
  "piclet_id": "pillow_canonical",
  "object_name": "pillow"
}

Success Response:

{
  "success": true,
  "scanCount": 43
}

5. Get Recent Activity

Endpoint: /get_recent_activity Purpose: Get global discovery feed Method: Gradio function call

Input Parameters:

{
  "limit": 20
}

Response:

{
  "success": true,
  "activities": [
    {
      "type": "discovery",
      "objectName": "pillow",
      "typeId": "pillow_canonical",
      "discoveredBy": "user123",
      "discoveredAt": "2024-07-26T10:30:00",
      "scanCount": 42
    },
    {
      "type": "variation",
      "objectName": "pillow",
      "typeId": "pillow_001",
      "attributes": ["velvet", "blue"],
      "discoveredBy": "user456",
      "discoveredAt": "2024-07-26T11:00:00",
      "scanCount": 5
    }
  ]
}

6. Get Leaderboard

Endpoint: /get_leaderboard Purpose: Get top discoverers by rarity score Method: Gradio function call

Input Parameters:

{
  "limit": 10
}

Response:

{
  "success": true,
  "leaderboard": [
    {
      "rank": 1,
      "username": "explorer123",
      "totalFinds": 156,
      "uniqueFinds": 45,
      "rarityScore": 2340
    },
    {
      "rank": 2,
      "username": "hunter456",
      "totalFinds": 134,
      "uniqueFinds": 38,
      "rarityScore": 1890
    }
  ]
}

7. Get User Profile

Endpoint: /get_user_profile Purpose: Get individual user's discovery statistics Method: Gradio function call

Input Parameters:

{
  "sub": "987654321"  // HuggingFace user ID (preferred) or username for legacy
}

Response:

{
  "success": true,
  "profile": {
    "sub": "987654321",
    "preferred_username": "player123",
    "name": "Player Display Name",
    "picture": "/static-proxy?url=https%3A%2F%2Favatars.huggingface.co%2F...",
    "email": "[email protected]",
    "joinedAt": "2024-07-01T10:00:00",
    "lastSeen": "2024-07-26T12:00:00",
    "discoveries": ["pillow_canonical", "chair_002", "lamp_canonical"],
    "uniqueFinds": 2,
    "totalFinds": 3,
    "rarityScore": 250,
    "visibility": "public"
  }
}

Notes:

  • Profile keyed by sub (stable HF user ID), not username
  • OAuth fields (preferred_username, name, picture) cached and refreshed on each login
  • Legacy profiles have sub = "legacy_{username}"
  • Visibility can be "public" or "private" (future feature)

Object Normalization Rules

The server normalizes object names for consistent storage:

  1. Convert to lowercase
  2. Remove articles (the, a, an)
  3. Handle pluralization:
    • pillows β†’ pillow
    • berries β†’ berry
    • leaves β†’ leaf
    • boxes β†’ box
  4. Replace spaces with underscores
  5. Remove special characters

Examples:

  • "The Blue Pillow" β†’ pillow
  • "wooden chairs" β†’ wooden_chair
  • "A pair of glasses" β†’ pair_of_glass

Rarity Tiers

Based on scan count:

  • Legendary: ≀ 5 scans
  • Epic: 6-20 scans
  • Rare: 21-50 scans
  • Uncommon: 51-100 scans
  • Common: > 100 scans

Scoring System

  • Canonical Discovery: +100 rarity points
  • Variation Discovery: +50 rarity points
  • Scan Bonus: Additional points based on rarity tier

Error Handling

All endpoints return consistent error structures:

{
  "success": false,
  "error": "Description of what went wrong"
}

Common error scenarios:

  • Piclet not found
  • Invalid JSON data
  • Failed to save to dataset
  • Network/connection errors

Rate Limiting

Currently no rate limiting implemented. For production:

  • Consider adding per-user rate limits
  • Implement cooldowns for discoveries
  • Cache frequent requests

Authentication

OAuth Token Verification (Production Mode):

  • Frontend sends Authorization: Bearer <hf_token> headers
  • Server verifies tokens via https://huggingface.co/oauth/userinfo
  • Returns user info: sub (stable ID), preferred_username, name, picture, email
  • User profiles keyed by sub (HF user ID) instead of username
  • Usernames can change, but sub remains stable

Legacy Mode (Testing Only):

  • For backward compatibility, endpoints accept plain usernames
  • If token doesn't start with hf_, treated as username
  • Creates legacy user profile with sub = "legacy_{username}"

Example OAuth Flow:

// Frontend: Get OAuth token from HuggingFace Space
import { HfInference } from "https://cdn.jsdelivr.net/npm/@huggingface/inference/+esm";
const auth = await hfAuth.signIn();

// Make authenticated request
const response = await fetch('/api/endpoint', {
  headers: {
    'Authorization': `Bearer ${auth.accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ /* payload */ })
});

Token Verification Process:

  1. Extract Bearer token from Authorization header
  2. Call https://huggingface.co/oauth/userinfo with token
  3. Verify response status 200
  4. Extract user info (sub, preferred_username, name, picture)
  5. Get or create user profile using sub as key
  6. Cache profile fields on each request

Data Storage

All data stored in HuggingFace Dataset:

  • Repository: Fraser/piclets
  • Type: Public dataset
  • Structure:
    • piclets/ - Canonical and variation data
    • users/ - User profiles
    • metadata/ - Global statistics

Best Practices

  1. Always normalize object names before searching
  2. Check for existing Piclets before creating new ones
  3. Increment scan counts when rediscovering
  4. Cache responses on the client side
  5. Handle network errors gracefully
  6. Validate JSON data before sending

Example Workflow

  1. User scans an object (e.g., pillow)
  2. Extract object name and attributes from caption
  3. Search for existing Piclet
  4. If new:
    • Create canonical Piclet
    • Award discovery bonus
  5. If variation:
    • Create or retrieve variation
    • Update scan count
  6. Update user profile
  7. Refresh activity feed

Support

For issues or questions:

  • Check CLAUDE.md for implementation details
  • Review example code in app.py
  • Open an issue in the repository