communitai-moderationRepository SDK
Python SDK
The official Python SDK for CommunitAI's Moderation-as-a-Service API. Built with Pydantic for type safety, supporting both sync and async operations.
Installation
bash
uv venv --python 3.13
uv add /path/to/communitai/packages/sdk-pythonUse the current repository SDK. Package publication is a separate release step.
Requires standard Python 3.13 or 3.14.
Quick Start
python
from communitai_moderation import CommunitAIModerator
import os
# Initialize the client
client = CommunitAIModerator(api_key=os.environ["COMMUNITAI_API_KEY"])
# Moderate content
result = client.moderate(
content="Hello, world!",
content_type="text",
)
print(result.decision) # "approve" | "reject" | "warn" | "review"
print(result.confidence)Configuration
The client accepts the following configuration options:
| Option | Type |
|---|---|
api_keyrequired | str |
base_url | strDefault: "https://www.communitai.org" |
timeout | floatDefault: 30.0 |
max_retries | intDefault: 3 |
debug | boolDefault: False |
python
client = CommunitAIModerator(
api_key=os.environ["COMMUNITAI_API_KEY"],
timeout=10.0,
max_retries=5,
debug=True,
)Sync vs Async
The SDK provides both synchronous and asynchronous clients:
python
# Synchronous (blocking)
from communitai_moderation import CommunitAIModerator
client = CommunitAIModerator(api_key="...")
with client:
result = client.moderate(content="Hello!")
# Asynchronous (non-blocking)
from communitai_moderation import AsyncCommunitAIModerator
import asyncio
async def main():
async with AsyncCommunitAIModerator(api_key="...") as client:
result = await client.moderate(content="Hello!")
print(result.decision)
asyncio.run(main())Single Moderation
python
from communitai_moderation import (
ContentType,
ModerationContext,
ModerationOptions,
RulesConfig,
RuleInterpretation,
)
# Basic moderation
result = client.moderate(
content="Check out my post!",
content_type=ContentType.TEXT,
)
# With context and options
result = client.moderate(
content="Buy now! Limited time offer!",
content_type=ContentType.TEXT,
context=ModerationContext(
community_id="marketplace",
author_reputation=75,
metadata={
"post_type": "listing",
"category": "electronics",
},
),
rules_config=RulesConfig(
use_global_safety=True,
interpretation=RuleInterpretation.MODERATE,
),
options=ModerationOptions(
explain=True,
),
)
# Handle the result
match result.decision:
case "approve":
publish_post(post)
case "reject":
print(f"Rejected: {result.explanation}")
case "warn":
publish_with_flag(post)
case "review":
queue_for_review(post, result)Batch Moderation
python
from communitai_moderation import BatchRequest, BatchItem, Priority
# Submit a batch
batch = client.moderate_batch(
BatchRequest(
items=[
BatchItem(external_id=post.id, content=post.body)
for post in posts
],
priority=Priority.NORMAL,
)
)
print(f"Submitted batch {batch.job_id}")
# Poll for status
import time
status = client.get_batch_status(batch.job_id)
while status.status in ("queued", "processing"):
print(f"Progress: {status.items_processed}/{status.items_total}")
time.sleep(1)
status = client.get_batch_status(batch.job_id)
# Get results with data
status = client.get_batch_status(batch.job_id, include_results=True)
for result in status.results or []:
print(f"{result.external_id}: {result.decision}")Custom Rules
python
from communitai_moderation import (
CreateRuleRequest,
RuleDefinition,
RuleType,
RuleAction,
RuleSeverity,
)
# Create a rule
rule = client.create_rule(
CreateRuleRequest(
name="No Spam Links",
description="Block messages with suspicious links",
rule_type=RuleType.COMBINED,
rule_definition=RuleDefinition(
keywords=["click here"],
patterns=[r"bit\.ly/\w+"],
semantic_categories=["spam"],
semantic_threshold=0.7,
),
action=RuleAction.REJECT,
severity=RuleSeverity.MODERATE,
)
)
# List rules
rules = client.list_rules()
for r in rules:
print(f"{r.name}: {r.action.value}")
# Update a rule
from communitai_moderation import UpdateRuleRequest
updated = client.update_rule(
rule.id,
UpdateRuleRequest(is_active=False),
)
# Delete a rule
client.delete_rule(rule.id)Analytics
python
# Get analytics
analytics = client.get_analytics(
days=30,
include=["decisions", "latency", "usage"],
)
if analytics.decisions:
print(f"Total requests: {analytics.decisions.total_requests}")
print(f"Approvals: {analytics.decisions.decisions.approve}")
print(f"Rejections: {analytics.decisions.decisions.reject}")
if analytics.latency:
print(f"P50 latency: {analytics.latency.p50_ms}ms")
print(f"P99 latency: {analytics.latency.p99_ms}ms")
if analytics.usage:
current = analytics.usage.current_month
print(f"Requests this month: {current.total_requests}")
print(f"Projected month-end: {current.projected_month_end}")Error Handling
The SDK provides typed exception classes for common error scenarios:
python
from communitai_moderation.errors import (
CommunitAIError,
AuthenticationError,
RateLimitError,
ValidationError,
QuotaExceededError,
ServerError,
RetryExhaustedError,
TimeoutError,
)
try:
result = client.moderate(content="...")
except AuthenticationError as e:
# Invalid or missing API key
print(f"Auth failed: {e.message}")
except RateLimitError as e:
# Too many requests
print(f"Rate limited: {e.message}")
except QuotaExceededError as e:
# Monthly quota exceeded
print("Quota exceeded. Upgrade your plan.")
except ValidationError as e:
# Invalid request parameters
print(f"Validation failed: {e.details}")
except ServerError as e:
# Server-side error
print(f"Server error: {e.message}")
except RetryExhaustedError as e:
# All retries failed
print(f"Failed after {e.attempts} attempts: {e.last_error}")
except TimeoutError as e:
# Request timed out
print(f"Request timed out")
except CommunitAIError as e:
# Other API error
print(f"API error: {e.code} - {e.message}")Context Manager
Use context managers to ensure proper resource cleanup:
python
# Sync client
with CommunitAIModerator(api_key="...") as client:
result = client.moderate(content="Hello!")
# Connection is automatically closed
# Async client
async with AsyncCommunitAIModerator(api_key="...") as client:
result = await client.moderate(content="Hello!")
# Connection is automatically closed
# Manual cleanup (if not using context manager)
client = CommunitAIModerator(api_key="...")
try:
result = client.moderate(content="Hello!")
finally:
client.close()Type Hints
All types are available for static type checking:
python
from communitai_moderation import (
# Configuration
CommunitAIConfig,
# Moderation
ContentType,
ModerationContext,
ModerationOptions,
RulesConfig,
RuleInterpretation,
ModerationDecision,
ModerationResult,
RuleTriggered,
# Batch
BatchItem,
BatchRequest,
BatchResponse,
BatchStatus,
BatchStatusResponse,
BatchItemResult,
Priority,
# Rules
CustomRule,
CreateRuleRequest,
UpdateRuleRequest,
RuleDefinition,
RuleType,
RuleAction,
RuleSeverity,
# Analytics
AnalyticsResponse,
DecisionAnalytics,
LatencyAnalytics,
UsageAnalytics,
CustomRulesAnalytics,
)
# Type checking works with Pydantic models
def process_result(result: ModerationResult) -> None:
if result.decision == ModerationDecision.REJECT:
print(f"Rejected with confidence {result.confidence}")Best Practices
Reuse the client instance
Create one client instance and reuse it across your application.
# Good - create once
client = CommunitAIModerator(api_key=os.environ["COMMUNITAI_API_KEY"])
def moderate_content(content: str) -> ModerationResult:
return client.moderate(content=content)
# Bad - creating new instances
def moderate_content(content: str) -> ModerationResult:
client = CommunitAIModerator(api_key=api_key) # Don't do this
return client.moderate(content=content)Use async for high throughput
Use the async client for concurrent moderation in web servers.
from fastapi import FastAPI
from communitai_moderation import AsyncCommunitAIModerator
app = FastAPI()
client = AsyncCommunitAIModerator(api_key=os.environ["COMMUNITAI_API_KEY"])
@app.post("/moderate")
async def moderate(content: str):
result = await client.moderate(content=content)
return {"decision": result.decision.value}
@app.on_event("shutdown")
async def shutdown():
await client.close()Use pattern matching for decisions
Handle each moderation decision with structural pattern matching.
match result.decision:
case ModerationDecision.APPROVE:
await publish_content()
case ModerationDecision.REJECT:
await notify_user(result.explanation)
case ModerationDecision.WARN:
await publish_with_flag()
case ModerationDecision.REVIEW:
await queue_for_review()