# Content moderation

Source: https://docs.temprl.org/examples/content-moderation

> Check thousands of user posts against a content policy concurrently with Simo AsyncClient, removing clear violations and queuing borderline ones.

Check user posts against your policy, many at a time. Clear violations are removed, clear passes are published, and the borderline ones go to a moderator, which is where people add the most value.

**Python**

```python
import asyncio
from simoai import AsyncClient, Choice, Noul

POLICY = """No harassment or threats against a person. No spam or scams.
No sharing of someone else's personal information. Criticism of products and companies is allowed."""

QUESTIONS = {
    "violates": Noul("The post breaks the community policy"),
    "reason": Choice("Which rule does the post break, if any?", {
        "none":       "it breaks no rule",
        "harassment": "harassment or threats against a person",
        "spam":       "spam, scams or unsolicited advertising",
        "privacy":    "someone else's personal information",
    }),
}

async def moderate(posts: list[str]) -> list[tuple[str, str]]:
    async with AsyncClient(max_concurrency=16) as c:
        results = await asyncio.gather(*(c.ask({"policy": POLICY, "post": p}, QUESTIONS) for p in posts))
    out = []
    for post, r in zip(posts, results):
        p = r["violates"].noul
        verdict = "remove" if p > 0.95 else "publish" if p < 0.05 else "moderator"
        out.append((verdict, r["reason"].choice))
    return out

posts = ["This blender is the worst product I've bought, avoid it.",
         "Click here to claim your free crypto!!! limited time",
         "I know where you live, @jake. Watch yourself."]
for verdict, reason in asyncio.run(moderate(posts)):
    print(verdict, reason)
# publish none
# remove spam
# remove harassment
```

**JavaScript**

```javascript
const POLICY = `No harassment or threats against a person. No spam or scams.
No sharing of someone else's personal information. Criticism of products and companies is allowed.`;

const QUESTIONS = {
  violates: { type: "noul", instructions: "The post breaks the community policy" },
  reason: {
    type: "choice",
    instructions: "Which rule does the post break, if any?",
    criteria: {
      none: "it breaks no rule",
      harassment: "harassment or threats against a person",
      spam: "spam, scams or unsolicited advertising",
      privacy: "someone else's personal information",
    },
  },
};

async function check(post) {
  const res = await fetch("https://api.temprl.org/v1/ask", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SIMO_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: "simo-1-pro", state: { policy: POLICY, post }, questions: QUESTIONS }),
  });
  const { answers: a } = await res.json();
  const p = a.violates.noul;
  return { verdict: p > 0.95 ? "remove" : p < 0.05 ? "publish" : "moderator", reason: a.reason.choice };
}

// Up to 16 at a time
async function moderate(posts, limit = 16) {
  const out = new Array(posts.length);
  let next = 0;
  await Promise.all(Array.from({ length: limit }, async () => {
    while (next < posts.length) { const i = next++; out[i] = await check(posts[i]); }
  }));
  return out;
}
```

## Why it works

- **The policy is in the state**, so changing a rule is a text edit, not a retraining job.
- **Two thresholds, three outcomes.** Calibration makes "remove above 0.95" mean about 1 wrongful removal in 20 among the closest calls, and you can tighten it.
- **Concurrency is cheap.** `max_concurrency` caps requests in flight; each post is a short read.
