AI / Jarvis Block

Machine learning features for modern applications
The AI Block brings powerful machine learning capabilities to your application without the complexity of building ML infrastructure. Leverage pre-built AI features for text analysis, image recognition, recommendations, content moderation, and more—all through a simple REST API.
Features
- Text Analysis - Sentiment, entities, key phrases, and language detection
- Image Recognition - Classification, object detection, and OCR
- Smart Recommendations - Personalized suggestions based on user behavior
- Content Moderation - Detect inappropriate content and spam
- Embeddings - Vector representations for semantic search and similarity
- Language Translation - Translate text between 100+ languages
- Summarization - Generate concise summaries of long text
- Classification - Custom text and image classification
Quick Start
npm install @23blocks/sdk
API Endpoint
| Service | URL |
|---|---|
| AI (Jarvis) | https://jarvis.api.us.23blocks.com |
Environment Routing: Use the same URL for all environments. Your API key determines the environment:
pk_test_*/sk_test_*→ Routes to Stagingpk_live_*/sk_live_*→ Routes to Production
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { ai: 'https://jarvis.api.us.23blocks.com' },
apiKey: 'your-api-key', // Use pk_test_* for staging, pk_live_* for production
});
// Analyze sentiment
const sentiment = await client.ai.analyzeSentiment({
text: 'This product is amazing!'
});
// { score: 0.92, label: 'positive' }
// Get recommendations
const recs = await client.ai.recommend({
userId: 'user_123',
context: 'product-page',
limit: 5
});
// Moderate content
const moderation = await client.ai.moderate({
text: 'Some user-generated content...'
});
Authentication
All API requests require authentication using your API credentials.
Required Headers
X-App-Id: your-app-id
X-Api-Key: your-api-key
Content-Type: application/json
User Identity Registration (Required)
Every user must be registered with the Jarvis Block before calling any endpoint. Without registration, all API calls return 404 with error code usr-not-registered. This is the most common integration issue.
Jarvis uses a register-once, execute-many pattern. Each user identity is registered once per tenant, then all subsequent API calls work using the user's unique_id from Auth Block.
Why Registration Is Required
Jarvis tracks per-user state: conversations, prompt executions, entity ownership, feedback, and usage limits. The registration step creates the internal identity record that links the Auth Block user to Jarvis resources.
Register a User
POST /identities/:user_unique_id/register
Self-registration — users can register themselves using their own JWT. No special scope required:
curl -X POST https://jarvis.api.us.23blocks.com/identities/usr_abc123/register \
-H "Authorization: Bearer user-jwt-token" \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json"
Admin registration — register a user on their behalf (requires identities:write scope):
curl -X POST https://jarvis.api.us.23blocks.com/identities/usr_abc123/register \
-H "Authorization: Bearer admin-jwt-token" \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json"
Response (201 Created):
{
"data": {
"id": "identity_abc123",
"type": "identity",
"attributes": {
"user_unique_id": "usr_abc123",
"status": "active",
"registered_at": "2026-05-20T10:00:00Z"
}
}
}
Calling register on an already-registered user returns the existing identity (idempotent).
The Error Without Registration
If you skip registration and call any Jarvis endpoint:
{
"error": {
"code": "usr-not-registered",
"message": "User not registered in this tenant",
"status": 404
}
}
Affected Endpoints
All Jarvis endpoints require a registered identity except the register endpoint itself:
| Endpoint Category | Examples |
|---|---|
| Prompts | Execute, render, feedback |
| Agents | Runtime, threads, messages, runs |
| Entities | Create, update, query digital twins |
| Entity Files | Upload, list, query files on entities |
| Clusters | Create, manage entity groups |
| Conversations | Create, list, message |
| Identities | All endpoints except /register |
Integration Pattern
Register users during your onboarding flow, right after authentication:
// After successful Auth Block login
const user = await authClient.signIn({ email, password });
// Register with Jarvis (idempotent — safe to call every login)
await fetch(`https://jarvis.api.us.23blocks.com/identities/${user.unique_id}/register`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${user.jwt}`,
'X-App-Id': APP_ID,
'X-Api-Key': API_KEY,
'Content-Type': 'application/json'
}
});
// Now all Jarvis endpoints work for this user
Since registration is idempotent, you can safely call it on every login without checking if the user is already registered.
Text Analysis API
Analyze text for sentiment, entities, and more.
Analyze Sentiment
Determine the emotional tone of text.
POST /ai/v1/text/sentiment
Request Body:
{
"data": {
"type": "sentiment_requests",
"attributes": {
"text": "I absolutely love this product! It exceeded all my expectations.",
"language": "en"
}
}
}
Response:
{
"data": {
"type": "sentiment_results",
"id": "sent_abc123",
"attributes": {
"score": 0.92,
"label": "positive",
"confidence": 0.97,
"scores": {
"positive": 0.92,
"neutral": 0.06,
"negative": 0.02
}
}
}
}
Extract Entities
Identify named entities in text.
POST /ai/v1/text/entities
Request Body:
{
"data": {
"type": "entity_requests",
"attributes": {
"text": "Apple CEO Tim Cook announced new products at the event in Cupertino, California.",
"types": ["PERSON", "ORG", "LOCATION"]
}
}
}
Response:
{
"data": {
"type": "entity_results",
"id": "ent_xyz789",
"attributes": {
"entities": [
{
"text": "Apple",
"type": "ORG",
"start": 0,
"end": 5,
"confidence": 0.98
},
{
"text": "Tim Cook",
"type": "PERSON",
"start": 10,
"end": 18,
"confidence": 0.99
},
{
"text": "Cupertino",
"type": "LOCATION",
"start": 62,
"end": 71,
"confidence": 0.96
},
{
"text": "California",
"type": "LOCATION",
"start": 73,
"end": 83,
"confidence": 0.99
}
]
}
}
}
Entity Types:
| Type | Description |
|---|---|
PERSON | People, including fictional |
ORG | Companies, agencies, institutions |
LOCATION | Countries, cities, addresses |
DATE | Dates and times |
MONEY | Monetary values |
PRODUCT | Products and vehicles |
EVENT | Named events |
WORK_OF_ART | Titles of books, songs, etc. |
Extract Key Phrases
Identify important phrases in text.
POST /ai/v1/text/key-phrases
Request Body:
{
"data": {
"type": "key_phrase_requests",
"attributes": {
"text": "The new machine learning algorithm significantly improves prediction accuracy while reducing computational costs.",
"max_phrases": 5
}
}
}
Response:
{
"data": {
"type": "key_phrase_results",
"attributes": {
"key_phrases": [
{ "phrase": "machine learning algorithm", "score": 0.95 },
{ "phrase": "prediction accuracy", "score": 0.89 },
{ "phrase": "computational costs", "score": 0.85 }
]
}
}
}
Detect Language
Identify the language of text.
POST /ai/v1/text/language
Request Body:
{
"data": {
"type": "language_requests",
"attributes": {
"text": "Bonjour, comment allez-vous?"
}
}
}
Response:
{
"data": {
"type": "language_results",
"attributes": {
"language": "fr",
"language_name": "French",
"confidence": 0.99,
"alternatives": [
{ "language": "it", "language_name": "Italian", "confidence": 0.01 }
]
}
}
}
Summarize Text
Generate a concise summary of long text.
POST /ai/v1/text/summarize
Request Body:
{
"data": {
"type": "summarize_requests",
"attributes": {
"text": "Your long article text here...",
"max_length": 100,
"style": "extractive"
}
}
}
Response:
{
"data": {
"type": "summarize_results",
"attributes": {
"summary": "A concise summary of the input text...",
"length": 85,
"compression_ratio": 0.15
}
}
}
Image Analysis API
Analyze images for classification, objects, and text.
Classify Image
Categorize an image.
POST /ai/v1/image/classify
Request Body:
{
"data": {
"type": "image_classify_requests",
"attributes": {
"image_url": "https://example.com/photo.jpg",
"max_labels": 5
}
}
}
Response:
{
"data": {
"type": "image_classify_results",
"attributes": {
"labels": [
{ "label": "dog", "confidence": 0.97 },
{ "label": "golden retriever", "confidence": 0.94 },
{ "label": "pet", "confidence": 0.92 },
{ "label": "animal", "confidence": 0.99 },
{ "label": "outdoor", "confidence": 0.78 }
]
}
}
}
Detect Objects
Identify and locate objects in an image.
POST /ai/v1/image/detect
Request Body:
{
"data": {
"type": "object_detect_requests",
"attributes": {
"image_url": "https://example.com/street.jpg",
"min_confidence": 0.7
}
}
}
Response:
{
"data": {
"type": "object_detect_results",
"attributes": {
"objects": [
{
"label": "car",
"confidence": 0.95,
"bounding_box": {
"x": 120,
"y": 200,
"width": 350,
"height": 180
}
},
{
"label": "person",
"confidence": 0.88,
"bounding_box": {
"x": 50,
"y": 100,
"width": 80,
"height": 250
}
}
]
}
}
}
Extract Text (OCR)
Extract text from images.
POST /ai/v1/image/ocr
Request Body:
{
"data": {
"type": "ocr_requests",
"attributes": {
"image_url": "https://example.com/document.jpg",
"detect_orientation": true
}
}
}
Response:
{
"data": {
"type": "ocr_results",
"attributes": {
"text": "Extracted text from the image...",
"blocks": [
{
"text": "INVOICE",
"confidence": 0.99,
"bounding_box": { "x": 50, "y": 20, "width": 150, "height": 30 }
},
{
"text": "Order #12345",
"confidence": 0.97,
"bounding_box": { "x": 50, "y": 60, "width": 200, "height": 25 }
}
],
"language": "en",
"orientation": 0
}
}
}
Recommendations API
Generate personalized recommendations.
Get Recommendations
POST /ai/v1/recommendations
Request Body:
{
"data": {
"type": "recommendation_requests",
"attributes": {
"user_id": "user_abc123",
"context": "product-page",
"item_id": "prod_xyz789",
"limit": 5,
"filters": {
"category": "electronics",
"price_max": 500
}
}
}
}
Response:
{
"data": {
"type": "recommendation_results",
"attributes": {
"recommendations": [
{
"item_id": "prod_001",
"score": 0.95,
"reason": "Users who viewed this also viewed"
},
{
"item_id": "prod_002",
"score": 0.87,
"reason": "Similar products"
},
{
"item_id": "prod_003",
"score": 0.82,
"reason": "Based on your history"
}
],
"model_version": "v2.3"
}
}
}
Track User Event
Record user interactions for better recommendations.
POST /ai/v1/recommendations/events
Request Body:
{
"data": {
"type": "recommendation_events",
"attributes": {
"user_id": "user_abc123",
"event_type": "purchase",
"item_id": "prod_xyz789",
"timestamp": "2025-01-15T10:30:00Z",
"metadata": {
"quantity": 1,
"price": 299.99
}
}
}
}
Event Types:
| Event | Description |
|---|---|
view | User viewed an item |
click | User clicked on an item |
add_to_cart | Item added to cart |
purchase | Item purchased |
rating | User rated an item |
like | User liked an item |
Content Moderation API
Detect inappropriate content.
Moderate Text
POST /ai/v1/moderation/text
Request Body:
{
"data": {
"type": "moderation_requests",
"attributes": {
"text": "User-generated content to check...",
"categories": ["hate", "violence", "sexual", "spam"]
}
}
}
Response:
{
"data": {
"type": "moderation_results",
"attributes": {
"flagged": false,
"categories": {
"hate": { "flagged": false, "score": 0.02 },
"violence": { "flagged": false, "score": 0.01 },
"sexual": { "flagged": false, "score": 0.00 },
"spam": { "flagged": false, "score": 0.05 }
},
"action": "allow"
}
}
}
Moderate Image
POST /ai/v1/moderation/image
Request Body:
{
"data": {
"type": "image_moderation_requests",
"attributes": {
"image_url": "https://example.com/user-upload.jpg",
"categories": ["adult", "violence", "hate"]
}
}
}
Response:
{
"data": {
"type": "image_moderation_results",
"attributes": {
"flagged": false,
"categories": {
"adult": { "flagged": false, "score": 0.03 },
"violence": { "flagged": false, "score": 0.01 },
"hate": { "flagged": false, "score": 0.00 }
},
"action": "allow"
}
}
}
Embeddings API
Generate vector embeddings for semantic operations.
Generate Embeddings
POST /ai/v1/embeddings
Request Body:
{
"data": {
"type": "embedding_requests",
"attributes": {
"inputs": [
"Machine learning is transforming technology",
"AI is revolutionizing software development"
],
"model": "text-embedding-3"
}
}
}
Response:
{
"data": {
"type": "embedding_results",
"attributes": {
"embeddings": [
{
"index": 0,
"embedding": [0.023, -0.045, 0.089, ...],
"dimensions": 1536
},
{
"index": 1,
"embedding": [0.031, -0.052, 0.076, ...],
"dimensions": 1536
}
],
"model": "text-embedding-3",
"usage": {
"tokens": 18
}
}
}
}
Compute Similarity
Compare text similarity.
POST /ai/v1/embeddings/similarity
Request Body:
{
"data": {
"type": "similarity_requests",
"attributes": {
"source": "How do I reset my password?",
"targets": [
"I forgot my login credentials",
"Change my account password",
"What's the weather today?"
]
}
}
}
Response:
{
"data": {
"type": "similarity_results",
"attributes": {
"similarities": [
{ "index": 0, "score": 0.89 },
{ "index": 1, "score": 0.94 },
{ "index": 2, "score": 0.12 }
]
}
}
}
Translation API
Translate text between languages.
Translate Text
POST /ai/v1/translate
Request Body:
{
"data": {
"type": "translation_requests",
"attributes": {
"text": "Hello, how are you today?",
"source_language": "en",
"target_language": "es"
}
}
}
Response:
{
"data": {
"type": "translation_results",
"attributes": {
"translated_text": "Hola, como estas hoy?",
"source_language": "en",
"target_language": "es",
"confidence": 0.98
}
}
}
Supported Languages
Get list of supported languages.
GET /ai/v1/translate/languages
Classification API
Create custom classifiers.
Create Classifier
POST /ai/v1/classifiers
Request Body:
{
"data": {
"type": "classifiers",
"attributes": {
"name": "support-ticket-classifier",
"description": "Classify customer support tickets",
"labels": ["billing", "technical", "general", "urgent"]
}
}
}
Train Classifier
POST /ai/v1/classifiers/:classifier_id/train
Request Body:
{
"data": {
"type": "training_data",
"attributes": {
"examples": [
{ "text": "I was charged twice", "label": "billing" },
{ "text": "App keeps crashing", "label": "technical" },
{ "text": "How do I change settings?", "label": "general" },
{ "text": "URGENT: Service is down!", "label": "urgent" }
]
}
}
}
Classify Text
POST /ai/v1/classifiers/:classifier_id/classify
Request Body:
{
"data": {
"type": "classification_requests",
"attributes": {
"text": "My payment didn't go through"
}
}
}
Response:
{
"data": {
"type": "classification_results",
"attributes": {
"predictions": [
{ "label": "billing", "confidence": 0.92 },
{ "label": "technical", "confidence": 0.05 },
{ "label": "general", "confidence": 0.02 },
{ "label": "urgent", "confidence": 0.01 }
]
}
}
}
Prompt Rendering API
Render dynamic prompts with variable substitution and array transformations.
Render Prompt
Render a prompt template with placeholder values.
POST /ai/v1/prompts/:unique_id/render
Request Body:
{
"placeholders": {
"simple_string": "Hello",
"string_array": ["url1", "url2", "url3"],
"nested_object": {
"title": "My Title",
"metadata": { "author": "John" }
},
"object_array": [
{ "claim": "Fact 1", "priority": "high" },
{ "claim": "Fact 2", "priority": "low" }
]
}
}
Response:
{
"data": {
"type": "rendered_prompts",
"id": 12345,
"attributes": {
"prompt_unique_id": "prompt_abc123",
"rendered_content": "The rendered prompt text with substituted values...",
"placeholders_used": ["simple_string", "string_array", "nested_object"]
}
}
}
The response id field is now an integer (previously UUID). Use prompt_unique_id for the UUID identifier.
Placeholder Syntax
| Pattern | Example | Description |
|---|---|---|
| Simple | {{name}} | Basic variable substitution |
| Nested object | {{user.email}} | Access nested object fields |
| Array index | {{items[0]}} | Access array element by index |
| Combined | {{steps[0].title}} | Index access + field access |
Pipe Transforms for Arrays
Transform array values using pipe syntax: {{placeholder\|transform}}
| Transform | Syntax | Input | Output |
|---|---|---|---|
| Default | {{urls}} | ["a", "b"] | a\nb (newline-joined) |
| Bullets | {{urls|bullets}} | ["a", "b"] | - a\n- b |
| Numbered | {{urls|numbered}} | ["a", "b"] | 1. a\n2. b |
| Join | {{urls|join:, }} | ["a", "b"] | a, b |
| Length | {{urls|length}} | ["a", "b"] | 2 |
| First | {{urls|first}} | ["a", "b"] | a |
| Last | {{urls|last}} | ["a", "b"] | b |
| Field | {{users|field:name}} | [{name: "John"}, {name: "Jane"}] | John\nJane |
Examples
Simple variable substitution:
Prompt template: "Hello {{name}}, welcome to {{company}}!"
Placeholders: { "name": "Alice", "company": "Acme Corp" }
Result: "Hello Alice, welcome to Acme Corp!"
Array with bullets:
Prompt template: "Sources:\n{{urls|bullets}}"
Placeholders: { "urls": ["https://example.com", "https://test.com"] }
Result: "Sources:\n- https://example.com\n- https://test.com"
Nested object access:
Prompt template: "Author: {{metadata.author}}, Published: {{metadata.date}}"
Placeholders: { "metadata": { "author": "John Doe", "date": "2026-01-15" } }
Result: "Author: John Doe, Published: 2026-01-15"
Object array with field extraction:
Prompt template: "Claims to verify:\n{{claims|field:text|numbered}}"
Placeholders: { "claims": [{ "text": "Fact 1" }, { "text": "Fact 2" }] }
Result: "Claims to verify:\n1. Fact 1\n2. Fact 2"
Prompt Templates (PromptHub)
The AI Block includes PromptHub — a library of 10 research-backed prompt engineering templates. Each template provides structured sections, help text, and {{placeholder}} substitution for dynamic values.
Template Library
Templates are organized into three tiers:
Universal Templates
| Template | Description | Key Sections |
|---|---|---|
| Freeform | Open-ended prompt for any task | System instructions, user input |
| Persona Agent | Role-based prompts with expertise context | Role definition, expertise areas, behavioral guidelines, constraints |
| Structured Output | Enforce JSON, tables, or specific formats | Output schema, format rules, validation criteria |
Reasoning & Quality Templates
| Template | Description | Key Sections |
|---|---|---|
| Chain of Thought | Step-by-step reasoning for complex problems | Problem statement, reasoning steps, conclusion format |
| Few-Shot Learning | Teach by example with input/output pairs | Examples (input/output), task instruction, output format |
| Self-Critique | LLM reviews and improves its own output | Initial task, critique criteria, revision instructions |
Specialized Templates
| Template | Description | Key Sections |
|---|---|---|
| RAG Context | Grounded generation with retrieved documents | Context documents, query, citation format, source attribution |
| Research Query | Multi-source research with structured findings | Research topic, source types, findings format, evidence requirements |
| Fact Check | Verify claims against evidence | Claims list, evidence sources, confidence scoring, verdict format |
| Knowledge Generation | Generate structured knowledge from unstructured data | Input data, knowledge schema, extraction rules, output structure |
List Available Templates
GET /prompts
Returns all prompt templates available in your tenant, including PromptHub defaults and any custom prompts.
curl -X GET https://jarvis.api.us.23blocks.com/prompts \
-H "Authorization: Bearer your-jwt-token" \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key"
Create from Template
POST /prompts
Create a new prompt based on a PromptHub template or from scratch:
curl -X POST https://jarvis.api.us.23blocks.com/prompts \
-H "Authorization: Bearer your-jwt-token" \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Support Classifier",
"content": "You are a support ticket classifier.\n\nClassify the following ticket into one of these categories: {{categories|join:, }}\n\nTicket: {{ticket_text}}\n\nRespond with JSON: {\"category\": \"...\", \"confidence\": 0.0-1.0}",
"description": "Classifies support tickets using structured output"
}'
Execute a Prompt
POST /prompts/:unique_id/execute
Render and execute a prompt against a configured LLM in one call:
curl -X POST https://jarvis.api.us.23blocks.com/prompts/prompt_abc123/execute \
-H "Authorization: Bearer your-jwt-token" \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"placeholders": {
"categories": ["billing", "technical", "general", "urgent"],
"ticket_text": "I was charged twice for my subscription"
}
}'
Response:
{
"data": {
"type": "prompt_executions",
"id": "exec_xyz789",
"attributes": {
"prompt_unique_id": "prompt_abc123",
"rendered_content": "You are a support ticket classifier...",
"response": "{\"category\": \"billing\", \"confidence\": 0.95}",
"model": "gpt-4o",
"tokens_used": 142,
"execution_time_ms": 820
}
}
}
Getting Started with PromptHub
- Register your user with Jarvis (see User Identity Registration)
- Browse templates —
GET /promptsreturns all available templates - Render a prompt —
POST /prompts/:uid/renderwith your placeholder values - Execute against LLM —
POST /prompts/:uid/executeto render + run in one call - Iterate — Create versions, test with different inputs, compare results
All 10 PromptHub templates are pre-loaded in every tenant. You can use them directly or clone them as starting points for custom prompts.
Webhooks
Configure webhooks for AI events.
Register Webhook
POST /ai/v1/webhooks
Request Body:
{
"data": {
"type": "webhooks",
"attributes": {
"url": "https://your-app.com/webhooks/ai",
"events": [
"moderation.flagged",
"classifier.trained",
"batch.completed"
],
"secret": "your-webhook-secret"
}
}
}
Webhook Events
| Event | Description |
|---|---|
moderation.flagged | Content was flagged by moderation |
classifier.trained | Custom classifier finished training |
batch.completed | Batch processing job completed |
Error Handling
Error Response Format
{
"errors": [
{
"status": "400",
"code": "invalid_image_format",
"title": "Invalid Image Format",
"detail": "The image format 'bmp' is not supported. Supported formats: jpg, png, gif, webp.",
"source": {
"parameter": "image_url"
}
}
]
}
Common Error Codes
| Code | Status | Description |
|---|---|---|
text_too_long | 400 | Input text exceeds maximum length |
invalid_image_format | 400 | Unsupported image format |
invalid_language | 400 | Language code not supported |
classifier_not_found | 404 | Custom classifier does not exist |
model_unavailable | 503 | AI model temporarily unavailable |
rate_limit_exceeded | 429 | Too many requests |
SDK Examples
React Sentiment Component
import { useState } from 'react';
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { ai: 'https://jarvis.api.us.23blocks.com' },
appId: 'your-app-id',
});
function SentimentAnalyzer() {
const [text, setText] = useState('');
const [sentiment, setSentiment] = useState(null);
const [loading, setLoading] = useState(false);
const analyzeSentiment = async () => {
if (!text.trim()) return;
setLoading(true);
try {
const result = await client.ai.analyzeSentiment({ text });
setSentiment(result);
} finally {
setLoading(false);
}
};
const getSentimentColor = (label) => {
switch (label) {
case 'positive': return 'text-green-500';
case 'negative': return 'text-red-500';
default: return 'text-gray-500';
}
};
return (
<div className="sentiment-analyzer">
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Enter text to analyze..."
rows={4}
/>
<button onClick={analyzeSentiment} disabled={loading}>
{loading ? 'Analyzing...' : 'Analyze Sentiment'}
</button>
{sentiment && (
<div className="result">
<p className={getSentimentColor(sentiment.label)}>
{sentiment.label.toUpperCase()} ({(sentiment.score * 100).toFixed(1)}%)
</p>
<div className="confidence-bar">
<div
style={{ width: `${sentiment.confidence * 100}%` }}
className="confidence-fill"
/>
</div>
</div>
)}
</div>
);
}
Content Moderation Hook
import { useState, useCallback } from 'react';
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { ai: 'https://jarvis.api.us.23blocks.com' },
appId: 'your-app-id',
});
function useContentModeration() {
const [isChecking, setIsChecking] = useState(false);
const moderateContent = useCallback(async (content: string) => {
setIsChecking(true);
try {
const result = await client.ai.moderate({
text: content,
categories: ['hate', 'violence', 'sexual', 'spam']
});
return {
isApproved: !result.flagged,
flags: Object.entries(result.categories)
.filter(([_, data]) => data.flagged)
.map(([category]) => category),
action: result.action
};
} finally {
setIsChecking(false);
}
}, []);
return { moderateContent, isChecking };
}
// Usage in a form
function CommentForm() {
const { moderateContent, isChecking } = useContentModeration();
const [comment, setComment] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
const moderation = await moderateContent(comment);
if (!moderation.isApproved) {
setError(`Comment flagged for: ${moderation.flags.join(', ')}`);
return;
}
// Submit the comment...
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={comment}
onChange={(e) => setComment(e.target.value)}
placeholder="Write a comment..."
/>
{error && <p className="error">{error}</p>}
<button type="submit" disabled={isChecking}>
{isChecking ? 'Checking...' : 'Post Comment'}
</button>
</form>
);
}
Rate Limits
| Plan | Requests/minute | Text chars/request | Images/minute |
|---|---|---|---|
| Free | 60 | 5,000 | 10 |
| Starter | 300 | 25,000 | 60 |
| Growth | 1,000 | 100,000 | 200 |
| Enterprise | Custom | Custom | Custom |
Best Practices
Text Analysis
- Batch when possible - Send multiple texts in a single request
- Specify language - Improves accuracy when you know the language
- Clean input - Remove irrelevant formatting or markup
Image Analysis
- Optimize images - Resize large images before sending
- Use URLs - Prefer image URLs over base64 for large images
- Set confidence thresholds - Filter low-confidence results
Recommendations
- Track events - The more user events, the better recommendations
- Use context - Provide page/section context for relevance
- Apply filters - Filter by availability, category, etc.
Content Moderation
- Moderate early - Check content before displaying to others
- Use appropriate categories - Only check relevant categories
- Handle flags gracefully - Provide helpful feedback to users
Related Blocks
- Search Block - Full-text search with AI-powered relevance
- Content Block - Headless CMS with AI enrichment
- Onboarding Block - Personalized onboarding with AI