Comprehensive Guide to Document Analyzers
May 16, 2026 · View on GitHub
Last Updated: 2026-01-09
Overview
OpenContracts supports document analyzers that run as Celery tasks within the main application. These analyzers can automatically process documents and create annotations.
1. Database Structure
The Analyzer model has these key fields:
id: CharField (primary key, max length 1024)manifest: JSON field for analyzer configurationdescription: Text fielddisabled: Boolean flagis_public: Boolean for visibilityicon: File fieldtask_name: CharField pointing to the Celery task (required)
2. How Analyzers Work
Task-based Analyzers
- Run within the main application as Celery tasks
- Defined by
task_namefield pointing to a Python callable - Integrated with the main application environment
- Have access to all application models and utilities
- Full documentation on implementation available in register-doc-analyzer.md
3. Analysis Process
Analysis Flow:
- System creates Analysis record
- Celery task is dispatched using the
task_name - Analysis runs in-process within the application
- Results stored directly in the database
- Annotations and metadata are created
4. Permissions & Security
Granular permissions available:
- permission_analyzer
- publish_analyzer
- create_analyzer
- read_analyzer
- update_analyzer
- remove_analyzer
Each analysis tracks:
- Creator
- Public/private status
- Document access permissions
5. Implementation Requirements
Task-based Analyzer Requirements:
- Valid Python import path in
task_name - Task must exist in codebase
- Must use
@doc_analyzer_taskdecorator - Must return valid analysis results
- See register-doc-analyzer.md for detailed implementation guide
6. Analyzer Registration
Database Creation
analyzer = Analyzer.objects.create(
id="task.analyzer.unique.id", # Required unique identifier
description="Document Analyzer Description",
task_name="opencontractserver.tasks.module.task_name", # Python import path
creator=user,
manifest={}, # Optional configuration
is_public=True, # Optional visibility setting
)
Implementation Requirements
-
Must be decorated with
@doc_analyzer_task() -
Must accept parameters:
doc_id: str # Document ID to analyze analysis_id: str # Analysis record ID corpus_id: str # Optional corpus ID -
Must return a tuple of 4 or 5 elements:
- 4-element return (default message "No Return Message"):
(doc_annotations, span_label_pairs, metadata, task_pass) - 5-element return (with custom message):
(doc_annotations, span_label_pairs, metadata, task_pass, message)
Where:
doc_annotations: List[str]- Document-level labelsspan_label_pairs: List[Tuple[TextSpan, str]]- Text annotations with labelsmetadata: List[Dict[str, Any]]- Must include 'data' keytask_pass: bool- Success indicatormessage: str(optional) - Stored inAnalysis.result_message(on success) orAnalysis.error_message(on failure)
- 4-element return (default message "No Return Message"):
For complete implementation details, see the decorator source at opencontractserver/shared/decorators.py and the detailed walkthrough at docs/walkthrough/advanced/register-doc-analyzer.md.
Validation Rules
- Task name must be unique
- Task must exist at specified path
- Must use
@doc_analyzer_taskdecorator - Return values must match schema
Execution Flow
- Analysis created referencing task-based analyzer
- System loads task by name
- Task executed through Celery
- Results processed and stored
- Analysis completion marked
Available Features
- Access to document content (PDF, text extracts, PAWLS tokens)
- Annotation and label creation
- Corpus-wide analysis integration
- Automatic result storage
- Error handling and retries
Annotation Review & User Feedback
Analyzer-generated annotations can be reviewed and curated by humans through the
UserFeedback system (opencontractserver/feedback/models.py).
Each UserFeedback row links to a single Annotation and stores:
approved/rejected— mutually exclusive boolean flags (enforced viaclean()).comment— free-text reviewer note.markdown— long-form reviewer commentary.metadata— JSON for tool-specific review data.
The feedback layer is exposed via GraphQL:
| Mutation / Query | Purpose |
|---|---|
approveAnnotation | Mark an annotation as reviewer-approved; returns UserFeedbackType. |
rejectAnnotation | Mark an annotation as reviewer-rejected; returns UserFeedbackType. |
userFeedback | Connection of feedback rows visible to the requesting user. |
UserFeedback carries its own object-level permissions (approve, reject,
comment, etc.) and is filtered via the standard visible_to_user pattern.
This makes it suitable both for analyst QA workflows on automated extractions
and for crowd-sourced annotation review on public corpuses.