Jev AI Hub
Start Learning

Classification · Choice

Classify Documents with Jev

Document-type classification with Jev Choice. Different from customer intent: this page asks what the file is, not what the person wants.

Quick answer

Label an uploaded file as invoice, contract, resume, policy, or other from a text excerpt.

Problem

A shared inbox and a Drive folder collect PDFs that have already been turned into text. Downstream parsers are type-specific. You need a label before you run the invoice extractor.

Why Jev fits this task

File type is a closed set. Official primitives: Choice fits unordered labels such as document type. Add other so a novel memo is not forced into contract.

Input state

Send only the fields the questions name. Official docs warn that extra unrelated state costs accuracy.

{
  "filename": "northline-q3.pdf",
  "excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
}

Question

What kind of document is this text excerpt?

Question type: Choice.

Jev schema

{
  "model": "jev-latest",
  "state": {
    "filename": "northline-q3.pdf",
    "excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
  },
  "questions": {
    "doc_type": {
      "type": "choice",
      "instructions": "What type of document is `excerpt`, given `filename`?",
      "criteria": {
        "invoice": "A bill requesting payment, with amount and payee.",
        "contract": "An agreement with parties, terms, or signature blocks.",
        "resume": "A person's work history or skills for hiring.",
        "policy": "Internal or public rules, not a bill or a person's CV.",
        "other": "None of the above, or too little text to tell."
      }
    }
  }
}

Python example

from typesafe_sdk import Choice, TypeSafeClient

state = {
    "filename": "northline-q3.pdf",
    "excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15.",
}

with TypeSafeClient() as client:
    response = client.system_one(
        state=state,
        questions={
        "doc_type": Choice(
            instructions="What type of document is `excerpt`, given `filename`?",
            criteria={
                            "invoice": "A bill requesting payment, with amount and payee.",
                            "contract": "An agreement with parties, terms, or signature blocks.",
                            "resume": "A person's work history or skills for hiring.",
                            "policy": "Internal or public rules, not a bill or a person's CV.",
                            "other": "None of the above, or too little text to tell.",
                        },
        ),
        },
    )

print(response.answers["doc_type"].choice)
print(response.model)

TypeScript example

import { choice, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient();

const response = await client.systemOne({
  state: {
    "filename": "northline-q3.pdf",
    "excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
  },
  questions: {
    doc_type: choice("What type of document is `excerpt`, given `filename`?", {
      invoice: "A bill requesting payment, with amount and payee.",
      contract: "An agreement with parties, terms, or signature blocks.",
      resume: "A person's work history or skills for hiring.",
      policy: "Internal or public rules, not a bill or a person's CV.",
      other: "None of the above, or too little text to tell.",
    }),
  },
});

console.log(response.answers.doc_type.choice);
console.log(response.model);

JavaScript example

import { choice, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient();

const response = await client.systemOne({
  state: {
    "filename": "northline-q3.pdf",
    "excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
  },
  questions: {
    doc_type: choice("What type of document is `excerpt`, given `filename`?", {
      invoice: "A bill requesting payment, with amount and payee.",
      contract: "An agreement with parties, terms, or signature blocks.",
      resume: "A person's work history or skills for hiring.",
      policy: "Internal or public rules, not a bill or a person's CV.",
      other: "None of the above, or too little text to tell.",
    }),
  },
});

console.log(response.answers.doc_type.choice);
console.log(response.model);

cURL example

curl -s https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
{
  "model": "jev-latest",
  "state": {
    "filename": "northline-q3.pdf",
    "excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
  },
  "questions": {
    "doc_type": {
      "type": "choice",
      "instructions": "What type of document is `excerpt`, given `filename`?",
      "criteria": {
        "invoice": "A bill requesting payment, with amount and payee.",
        "contract": "An agreement with parties, terms, or signature blocks.",
        "resume": "A person's work history or skills for hiring.",
        "policy": "Internal or public rules, not a bill or a person's CV.",
        "other": "None of the above, or too little text to tell."
      }
    }
  }
}
EOF

Expected output

{
  "model": "jev-1.13.0",
  "answers": {
    "doc_type": {
      "type": "choice",
      "choice": "invoice",
      "probabilities": {
        "invoice": 0.93,
        "contract": 0.03,
        "resume": 0.01,
        "policy": 0.01,
        "other": 0.02
      },
      "confidence": 0.91
    }
  },
  "usage": {
    "input_tokens": 230,
    "output_tokens": 32
  }
}

Confidence handling

Low confidence: quarantine the file. High-stakes mislabels (contract vs invoice) should use a higher bar than corpus tagging.

Production considerations

After you have a type, run type-specific extractors in code. If you need hierarchy (invoice > utility vs SaaS), official cookbooks describe beam search over nested Choices — that is a second request, not this page.

Intake pipelines, email attachments, and RAG corpus labeling.

When to use Jev

You have a stable taxonomy and a text excerpt.

When not to use Jev

You are classifying customer intent, routing a ticket, or asking 'is this spam?' — those are other examples.

Jev does not read the PDF bytes. OCR and page splitting stay in your pipeline. This example uses text input; experimental image input is covered in the Images tutorial. Do not send a 64k dump of the whole book if the first page decides the type.

Common mistakes

  • Using this URL for intent classification. Intent lives at /examples/intent-detection/.
  • Sending scanned images without OCR.

FAQ

Can Jev classify 75 industry codes?

Official cookbooks show large Choice sets and confidence-based fallback to a parent label. Test your own taxonomy; do not assume a 75-way split is free of errors.

Sources

  1. Primitives (Questions)TypeSafe · accessed 2026-09-20 · documentation
  2. API referenceTypeSafe · accessed 2026-09-20 · documentation
  3. Jev 1.13 jaggednessTypeSafe · 2026-09-17 · accessed 2026-09-20 · documentation

All Jev examples