Split one file into many.
A packet arrives as one file. It leaves as separate files. Each piece knows what it is and which pages it came from.
Classify decides. Split cuts.
We keep the two apart on purpose. One of them thinks, so it can be wrong. The other moves bytes, so it cannot.
- 01
Find where each document starts
Classify reads the packet page by page. It marks the first page of each document. That is a bigger deal than it sounds. An invoice followed by another invoice looks identical on every page.
- 02
Read the plan before you pay for it
Set materialize to false. You get the page ranges and no files. Nothing is created and nothing is billed. Read the ranges. Move a boundary, or decide the packet was one document all along.
- 03
Cut. No model in the room.
Split runs no model. It copies pages into new files. That is the whole job. Each child keeps the parent metadata and points back at the file it came from. Call it twice and you still get one set of files.
- 04
Hand the pieces to the next step
You get a flat list of file ids. Paste it into extract, or redact, or sign. The 100-segment ceiling matches the limit downstream, so one packet always fits in one call.
Messy in. Addressable out.
Scanned, born-digital, or recorded. The boundaries come from the pages themselves, not from a filename that nobody keeps clean.
A bad cut is a bad decision, not a bad knife.
So the decision carries the score, the threshold, and the place where a person steps in.
- BoundariesWhat people assume Splitting a packet is a model problem.What happens Deciding is. Cutting is not. Classify makes every judgment call. Split runs no model, so it holds no opinion to get wrong.
- ConfidenceWhat people assume You get a percentage and a shrug.What happens Every page gets a score from 0 to 5. A segment takes the lowest score inside it. The one shaky page is exactly where the boundary is wrong.
- ReviewWhat people assume You find out downstream, in a support ticket.What happens Send anything at 3 or below to a person, before the cut. The gap between classify and split is a real stopping point, not an afterthought.
- TuningWhat people assume Collect examples. Retrain. Wait two weeks.What happens There is no training set to collect. You tune with a sentence. Describe the class better, re-run the page, and see the change now.
The files nobody wants to open.
Each one arrives as a single upload. Each one holds half a dozen documents that belong to different people.
Split is boring. That is the feature.
No model runs in the cut. Same packet, same ranges, same files, every time. You can retry it, cache it, and reason about it at 2 a.m. When a cut looks wrong, it went wrong one call earlier, in classify. And classify hands you a score and a page number to prove it.
The interesting part sits in that earlier call. That is where the score lives, where a person can step in, and where one better sentence changes the result. We would rather keep the guesswork in one place than spread it across two.
Same cut. Different day job.
The three paths differ in who holds the page ranges. What comes out is identical.
Two calls to cut. One to use the pieces.
Classify the pages, then cut on the boundaries. That is the whole capability. The third call below is extract, because every piece is its own file now. Look at the ranges between the first two calls.
import { CloudRakerClient } from "@cloudraker/api";
const client = new CloudRakerClient({ token: "YOUR_API_KEY" });
const packet = { url: "https://example.com/intake-packet.pdf" };
// 1 - Find where each document starts, page by page
const classified = await client.classify({
body: {
file: packet,
granularity: "page",
classes: [
{ id: "invoice", description: "A vendor invoice with a total due." },
{ id: "w9", description: "An IRS Form W-9." },
{ id: "agreement", description: "A signed services agreement." },
],
},
});
// 2 - Cut the packet on those boundaries (no model runs here)
const run = await client.split({
body: { file: packet, classifyRunId: classified.id },
});
for (const piece of run.output.splits) {
console.log(piece.classId, piece.startPage, piece.endPage, piece.confidence);
}
// 3 - Every child is addressable on its own
const data = await client.extract({
body: {
files: run.output.documentIds.map((id) => ({ id })),
schema: {
type: "object",
properties: { total_due: { type: ["number", "null"] } },
},
citations: true,
},
});
console.log(data.output?.value);from cloudraker.client import CloudRaker
client = CloudRaker(token="YOUR_API_KEY")
packet = {"url": "https://example.com/intake-packet.pdf"}
# 1 - Find where each document starts, page by page
classified = client.classify(
file=packet,
granularity="page",
classes=[
{"id": "invoice", "description": "A vendor invoice with a total due."},
{"id": "w9", "description": "An IRS Form W-9."},
{"id": "agreement", "description": "A signed services agreement."},
],
)
# 2 - Cut the packet on those boundaries (no model runs here)
run = client.split(file=packet, classify_run_id=classified.id)
for piece in run.output.splits:
print(piece.class_id, piece.start_page, piece.end_page, piece.confidence)
# 3 - Every child is addressable on its own
data = client.extract(
files=[{"id": file_id} for file_id in run.output.document_ids],
schema={
"type": "object",
"properties": {"total_due": {"type": ["number", "null"]}},
},
citations=True,
)
print(data.output.value)Split is one of many.
Same foundation under each one. Pick the door that fits how you work.
Try it dry. Looking is free.
Point Split at a packet with materialize off. Read the ranges it proposes. If they look right, cut. If they do not, sharpen one sentence and run it again.