Content Moderation Example

AI/ML-powered content moderation workflow demonstrating automated decision making with memory-based pattern learning.

Overview

This example shows:

Code

import { Workflow } from "@mdwr/sdk";

const contentModerationWorkflow = Workflow.create("content_moderation_v1")
  .step("analyze_content", async (ctx) => {
    const { content, contentType, authorId } = ctx.input;

    // Query memory for similar content decisions
    const insights = await ctx.memory.similar({
      situation: "content_moderation",
      context: {
        contentType,
        contentLength: content.length,
        authorId
      }
    });

    // Simulate content analysis (in production, use actual ML model)
    const toxicityScore = Math.random() * 0.5;
    const spamScore = Math.random() * 0.3;
    const hateSpeechScore = Math.random() * 0.4;

    let decision = "approve";
    let reason = "Content passed analysis";
    let confidence = 0.9;

    // Use historical insights
    if (insights.length > 0) {
      const flagged = insights.filter(
        i => i.decision.decision === "flag" || i.decision.decision === "reject"
      );
      if (flagged.length > 0) {
        confidence = 0.7; // Lower confidence if similar content was flagged
      }
    }

    // Decision logic
    if (toxicityScore > 0.4) {
      decision = "flag";
      reason = `High toxicity score: ${toxicityScore.toFixed(2)}`;
      confidence = 0.95;
    } else if (spamScore > 0.25) {
      decision = "flag";
      reason = `High spam score: ${spamScore.toFixed(2)}`;
      confidence = 0.9;
    } else if (hateSpeechScore > 0.3) {
      decision = "reject";
      reason = `Hate speech detected: ${hateSpeechScore.toFixed(2)}`;
      confidence = 0.95;
    }

    return {
      decision,
      reason,
      confidence,
      metadata: {
        toxicityScore,
        spamScore,
        hateSpeechScore,
        contentType,
        contentLength: content.length,
        similarDecisions: insights.length
      }
    };
  }, true)
  .step("check_author_history", async (ctx) => {
    // Only check if content wasn't approved
    if (ctx.state.analyze_content?.decision === "approve") {
      return {
        decision: "skip",
        reason: "Content approved, no need for author check",
        confidence: 1.0
      };
    }

    const { authorId } = ctx.input;

    // Query memory for author's past decisions
    const authorHistory = await ctx.memory.query({
      stepName: "analyze_content",
      limit: 10
    });

    const authorDecisions = authorHistory.filter(
      d => d.context?.authorId === authorId
    );

    const flaggedCount = authorDecisions.filter(
      d => d.decision.decision === "flag" || d.decision.decision === "reject"
    ).length;

    let decision = "proceed";
    let reason = "Author history check passed";
    let confidence = 0.8;

    if (flaggedCount > 3) {
      decision = "escalate";
      reason = `Author has ${flaggedCount} previous flags - escalate to human review`;
      confidence = 0.9;
    } else if (flaggedCount > 0) {
      decision = "review";
      reason = `Author has ${flaggedCount} previous flag(s) - needs review`;
      confidence = 0.85;
    }

    return {
      decision,
      reason,
      confidence,
      metadata: {
        authorId,
        totalDecisions: authorDecisions.length,
        flaggedCount
      }
    };
  }, true)
  .step("apply_action", async (ctx) => {
    const contentDecision = ctx.state.analyze_content?.decision;
    const authorDecision = ctx.state.check_author_history?.decision;

    let action = "none";
    let reason = "No action needed";
    let confidence = 1.0;

    if (contentDecision === "reject") {
      action = "remove";
      reason = "Content rejected - removing";
      confidence = 1.0;
    } else if (contentDecision === "flag" && authorDecision === "escalate") {
      action = "remove_and_ban";
      reason = "Flagged content from repeat offender - remove and ban";
      confidence = 0.95;
    } else if (contentDecision === "flag" || authorDecision === "review") {
      action = "flag_for_review";
      reason = "Flagged for human review";
      confidence = 0.9;
    } else if (contentDecision === "approve") {
      action = "publish";
      reason = "Content approved - publishing";
      confidence = 0.95;
    }

    return {
      decision: action === "publish" ? "success" : "action_taken",
      reason,
      confidence,
      metadata: {
        action,
        contentDecision,
        authorDecision,
        appliedAt: new Date().toISOString()
      }
    };
  }, true);

export default contentModerationWorkflow;

Running the Example

# Deploy the workflow
npx ts-node scripts/deploy.ts

# Execute with sample input
npx ts-node scripts/execute.ts content_moderation_v1

Input Example

{
  "content": "This is a test post",
  "contentType": "post",
  "authorId": "user123"
}

Key Features

Content Analysis

const toxicityScore = Math.random() * 0.5;
const spamScore = Math.random() * 0.3;
const hateSpeechScore = Math.random() * 0.4;

Author History Check

const authorHistory = await ctx.memory.query({
  stepName: "analyze_content",
  limit: 10
});

const flaggedCount = authorDecisions.filter(
  d => d.decision.decision === "flag" || d.decision.decision === "reject"
).length;

Action Application

if (contentDecision === "reject") {
  action = "remove";
} else if (contentDecision === "flag" && authorDecision === "escalate") {
  action = "remove_and_ban";
}

Use Cases

Next Steps