Classification + RTIO API Documentation
Synced from the TurfAI source on 2026-06-21.
Overview
This document describes the Classification with RTIO (Role/Tasks/Instructions/Output) feature. The system uses a 2-phase approach to classify documents and either match them to existing extraction prompts or generate new ones.
RTIO Format: A structured prompt template consisting of:
- Role: System and user role definitions for the LLM
- Tasks: Specific extraction tasks to perform
- Instructions: Clear guidelines for output formatting and validation
- Output: Expected output format and example structure
Architecture:
- DMS: Orchestrates classification and RTIO generation
- Processors: Execute LLM operations (classification, semantic matching, RTIO generation)
- UI: Handles user interaction, preview, and saving
Flow Diagram
User Uploads Document
↓
[1] Classification Job (2-phase)
Phase 1: Generic classification (document_type, category, key_features)
Phase 2: Semantic matching against available prompts
↓
Response:
- If match found → matched_prompt_id + extraction data
- If no match → rtio_available: true
↓
[2] User clicks "Generate RTIO" (if no match)
↓
RTIO Generation Job
Analyzes document structure
Generates extraction prompt
↓
Response: rtio_prompt (JSON structure)
↓
[3] UI Preview & Edit
User reviews generated prompt
Can edit title/description
↓
[4] User clicks "Save"
↓
POST /api/prompts (existing endpoint)
Saves as user-level promptAPI Endpoints
1. Classification Job
Endpoint: POST /api/jobs/collection/:collection_id/generate
Purpose: Classify a document and find matching extraction prompt
Request:
{
"job_type": "classification",
"document_ids": [123],
"metadata": {},
"config": {}
}Response (when match found):
{
"job_id": "classify_1731234567890",
"success": true,
"message": "Classification job submitted"
}Then poll: GET /api/jobs/classify_1731234567890/status
Result (match found):
{
"status": "completed",
"result": {
"extraction_result": {
"classification": "Offer Letter",
"document_type": "Offer Letter",
"category": "Employment",
"key_features": ["company_name", "salary", "joining_date"],
"confidence": 0.92,
"reasoning": "Document contains standard offer letter...",
"matched_prompt_id": 15,
"match_confidence": 0.88,
"match_reasoning": "Strong semantic match with Offer Letter extraction prompt"
},
"metadata": {
"document_name": "offer_letter.pdf",
"category": "Employment",
"classification_method": "generic_classification_with_semantic_matching"
}
}
}Result (no match found - RTIO available):
{
"status": "completed",
"result": {
"extraction_result": {
"classification": "Custom Employment Agreement",
"document_type": "Custom Employment Agreement",
"category": "Employment",
"key_features": ["employer", "employee", "terms", "compensation"],
"confidence": 0.85,
"reasoning": "Document is a custom employment agreement...",
"matched_prompt_id": null,
"match_confidence": 0.0,
"match_reasoning": ""
},
"metadata": {
"document_name": "custom_agreement.pdf",
"category": "Employment",
"classification_method": "generic_classification_with_semantic_matching"
}
}
}UI Logic:
if (result.extraction_result.matched_prompt_id) {
// Match found - use the matched prompt for extraction
const promptId = result.extraction_result.matched_prompt_id;
// Proceed with extraction using this prompt
} else {
// No match - show "Generate RTIO" button
showGenerateRTIOButton(result.extraction_result);
}2. Generate RTIO
Endpoint: POST /api/prompts/generate-rtio
Purpose: Generate a custom extraction prompt based on document analysis
Request:
{
"document_id": 123,
"classification_result": {
"document_type": "Custom Employment Agreement",
"category": "Employment",
"key_features": ["employer", "employee", "terms", "compensation"],
"confidence": 0.85
}
}Response:
{
"success": true,
"rtio_prompt": {
"title": "Extract Custom Employment Agreement Details",
"description": "Extracts key information from custom employment agreements",
"section": "Employment",
"roles": [
{
"role": "system",
"prompt": "You are an employment document specialist trained to extract structured information..."
},
{
"role": "user",
"prompt": "From the provided employment agreement, extract the following fields:\n- Employer name\n- Employee name..."
}
],
"tasks": [
"Extract employer and employee information",
"Identify compensation structure and terms",
"Extract contract duration and termination clauses"
],
"instructions": [
"Return output as valid JSON",
"Use keys: employer, employee, compensation, start_date, etc.",
"Mark unclear fields as null"
],
"outputFormat": "json",
"exampleOutput": {
"employer": "Acme Corporation",
"employee": "John Doe",
"compensation": "$120,000 per year",
"start_date": "2025-01-15",
"duration": "Permanent",
"benefits": ["Health insurance", "401k"]
},
"level": "user",
"version": "1.0.0"
},
"confidence": 0.85,
"generated_from_classification": {
"document_type": "Custom Employment Agreement",
"category": "Employment"
},
"message": "RTIO prompt generated successfully. You can now preview and save it."
}Error Responses:
// 400 Bad Request - Missing parameters
{
"error": {
"status": 400,
"message": "document_id and classification_result required"
}
}
// 403 Forbidden - Not document owner
{
"error": {
"status": 403,
"message": "You do not own this document"
}
}
// 408 Request Timeout - Generation took too long
{
"error": {
"status": 408,
"message": "RTIO generation timed out. Please try again with a smaller document."
}
}
// 500 Internal Server Error - Generation failed
{
"error": {
"status": 500,
"message": "Failed to generate RTIO",
"details": {
"error": "LLM request failed"
}
}
}3. Save RTIO Prompt
Endpoint: POST /api/prompts (existing Strapi endpoint)
Purpose: Save the generated RTIO as a user-level prompt
Request:
{
"data": {
"title": "My Custom Employment Agreement Extractor",
"description": "Custom prompt for extracting employment agreement details",
"section": "Employment",
"roles": [
{
"role": "system",
"prompt": "..."
},
{
"role": "user",
"prompt": "..."
}
],
"tasks": [...],
"instructions": [...],
"outputFormat": "json",
"exampleOutput": {...},
"level": "user",
"version": "1.0.0"
}
}Response:
{
"id": 156,
"title": "My Custom Employment Agreement Extractor",
"description": "Custom prompt for extracting employment agreement details",
"section": "Employment",
"level": "user",
"owner": {
"id": 5,
"username": "john_doe"
},
"createdAt": "2025-11-06T12:34:56.789Z",
"updatedAt": "2025-11-06T12:34:56.789Z"
}Notes:
levelis automatically set to"user"for non-admin usersowneris automatically set to current user- Only Super Admin can create
level: "system"prompts
UI Integration Guide
Complete Flow Implementation
// Step 1: Classify document
async function classifyDocument(documentId, collectionId) {
const response = await fetch(`/api/jobs/collection/${collectionId}/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
},
body: JSON.stringify({
job_type: 'classification',
document_ids: [documentId],
metadata: {},
config: {}
})
});
const { job_id } = await response.json();
// Poll for result
return await pollJobStatus(job_id);
}
// Step 2: Check if RTIO is available
function handleClassificationResult(result) {
const classification = result.extraction_result;
if (classification.matched_prompt_id) {
// Match found - proceed with extraction
console.log('Matched prompt:', classification.matched_prompt_id);
console.log('Match confidence:', classification.match_confidence);
return {
hasMatch: true,
promptId: classification.matched_prompt_id,
classification
};
} else {
// No match - offer RTIO generation
console.log('No match found. RTIO generation available.');
return {
hasMatch: false,
rtioAvailable: true,
classification
};
}
}
// Step 3: Generate RTIO (if no match)
async function generateRTIO(documentId, classificationResult) {
const response = await fetch('/api/prompts/generate-rtio', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
},
body: JSON.stringify({
document_id: documentId,
classification_result: classificationResult
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error?.message || 'RTIO generation failed');
}
return await response.json();
}
// Step 4: Preview and edit RTIO
function showRTIOPreview(rtioData) {
// Display in modal or panel
const { rtio_prompt, confidence } = rtioData;
// Allow user to edit title and description
const editablePrompt = {
...rtio_prompt,
title: userEditedTitle || rtio_prompt.title,
description: userEditedDescription || rtio_prompt.description
};
return editablePrompt;
}
// Step 5: Save RTIO prompt
async function saveRTIOPrompt(rtioPrompt) {
const response = await fetch('/api/prompts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
},
body: JSON.stringify({
data: rtioPrompt
})
});
if (!response.ok) {
throw new Error('Failed to save RTIO prompt');
}
const savedPrompt = await response.json();
console.log('✅ RTIO prompt saved:', savedPrompt.id);
return savedPrompt;
}
// Complete workflow
async function classifyAndExtractWorkflow(documentId, collectionId) {
try {
// 1. Classify
const classificationResult = await classifyDocument(documentId, collectionId);
const analysis = handleClassificationResult(classificationResult.result);
if (analysis.hasMatch) {
// Use matched prompt for extraction
console.log('Using matched prompt:', analysis.promptId);
// Proceed with extraction...
} else if (analysis.rtioAvailable) {
// Show "Generate RTIO" button
const userWantsRTIO = await showGenerateRTIODialog();
if (userWantsRTIO) {
// 2. Generate RTIO
const rtioData = await generateRTIO(documentId, analysis.classification);
// 3. Preview and allow editing
const editedPrompt = await showRTIOPreview(rtioData);
// 4. Save if user confirms
const userConfirmed = await showSaveConfirmDialog();
if (userConfirmed) {
const savedPrompt = await saveRTIOPrompt(editedPrompt);
// 5. Now use the saved prompt for extraction
console.log('Using newly saved prompt:', savedPrompt.id);
// Proceed with extraction...
}
}
}
} catch (error) {
console.error('Workflow error:', error);
showErrorMessage(error.message);
}
}Testing
Test Case 1: Known Document Type (Match Found)
Upload: Aadhaar Card document
Expected:
- Classification returns
document_type: "Aadhaar Card" matched_prompt_idis set (system prompt for Aadhaar)match_confidence>= 0.7- UI proceeds directly to extraction
Test Case 2: Unknown Document Type (RTIO Generation)
Upload: Custom contract document
Expected:
- Classification returns
document_type: "Custom Contract" matched_prompt_idis null- UI shows "Generate RTIO" button
- User clicks → RTIO generated
- User previews → edits title → saves
- Prompt saved as user-level
- Available for future extractions
Test Case 3: Error Handling
Scenarios:
- Upload very large document → RTIO generation timeout (408)
- Try to generate RTIO for someone else's document → Forbidden (403)
- Missing classification_result → Bad Request (400)
Performance Expectations
- Classification: 3-5 seconds (2 LLM calls)
- RTIO Generation: 8-15 seconds (complex LLM generation)
- Total Time (classify + RTIO): ~20 seconds maximum
Cost Considerations
- Classification (per document): ~$0.02 (2 LLM calls with Vertex AI)
- RTIO Generation (per prompt): ~$0.03-0.05 (longer generation)
- Total (full classify + RTIO cycle): ~$0.05-0.07
Security
- All endpoints require authentication (
Authorization: Bearer <token>) - Users can only access their own documents
- Users can only create user-level prompts (not system-level)
- RTIO prompts automatically scoped to user
Future Enhancements
- RTIO Refinement: Allow users to regenerate RTIOs with feedback
- RTIO Sharing: Share user-generated prompts with team
- RTIO Templates: Provide starter templates for common document types
- Batch RTIO: Generate RTIOs for multiple documents at once
- RTIO Analytics: Track which RTIOs are most used/accurate
Support
For questions or issues:
- Backend API: Check DMS logs (
dms/logs/) - Processor issues: Check processor logs (
processors/logs/) - Router issues: Check router logs (
router/logs/)
Key Log Messages:
✅ Prepared semantic matching metadata- Classification setup successful🎯 Generating RTIO for document- RTIO generation started✅ RTIO generation completed successfully- RTIO ready❌ RTIO generation failed- Check error details