← Back to Cookbook

Blog Post Moderation

AI checks blog submissions for policy violations, then routes to human review or auto-publish.

aiswitchresend

Source

/**
 * Moderates blog post submissions. AI checks for policy violations,
 * then routes to human review or auto-publish.
 */

form blog_submission {
  label: "Submit Blog Post"
  schema: @json {
    {
      "type": "object",
      "required": ["title", "body", "author_email"],
      "properties": {
        "title": { "type": "string", "title": "Title" },
        "body": { "type": "string", "title": "Body" },
        "author_email": { "type": "string", "format": "email", "title": "Author Email" }
      }
    }
  }
}

graph moderate_post {
  label: "Moderate Blog Post"

  root {
    type: code
    label: "Extract post"
    code: @ts { return context.nodes.root.input }
    outputSchema: @json {
      {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "body": { "type": "string" },
          "author_email": { "type": "string", "format": "email" }
        }
      }
    }
  }

  node check_content {
    type: ai
    label: "Check for policy violations"
    kind: object
    model: "google/gemini-2.5-flash"
    prompt: @ts {
      return "Review this blog post for policy violations (spam, hate speech, misinformation, adult content). Return a moderation result.\n\nTitle: " + context.nodes.root.output.title + "\n\nBody: " + context.nodes.root.output.body
    }
    schema: @json {
      {
        "type": "object",
        "required": ["safe", "reason"],
        "properties": {
          "safe": { "type": "boolean" },
          "reason": { "type": "string" },
          "flags": { "type": "array", "items": { "type": "string" } }
        }
      }
    }
  }

  node route {
    type: switch
    label: "Route by safety"
    cases: ["safe", "flagged"]
    router: @ts {
      if (context.nodes.check_content.output.safe) return "safe"
      return "flagged"
    }
  }

  node auto_approve {
    type: code
    label: "Auto-approve"
    code: @ts {
      return {
        status: "published",
        title: context.nodes.root.output.title,
        message: "Post auto-approved by moderation."
      }
    }
  }

  node flag_for_review {
    type: code
    label: "Flag for manual review"
    code: @ts {
      return {
        status: "flagged",
        title: context.nodes.root.output.title,
        reason: context.nodes.check_content.output.reason,
        flags: context.nodes.check_content.output.flags
      }
    }
  }

  node notify_author {
    type: resend
    label: "Notify author"
    from: @ts { return "[email protected]" }
    to: @ts { return "[email protected]" }
    subject: @ts { return "Your post: " + context.nodes.root.output.title }
    text: @ts {
      return "Your blog post has been submitted and is being reviewed. You will hear back shortly."
    }
  }

  flow {
    root -> check_content
    check_content -> route
    route -["safe"]-> auto_approve
    route -["flagged"]-> flag_for_review
    root -> notify_author
  }
}

trigger on_blog_submit {
  form:blog_submission -> moderate_post
  enabled: true
}

Flow

Trigger → graph

Graph nodes