-
Notifications
You must be signed in to change notification settings - Fork 0
review interface
The review interface (/review) provides a split-pane human-in-the-loop (HITL) view for reviewing and correcting extracted document data page-by-page.
File: frontend/src/components/review/review-interface.tsx
The interface is a full-height flexbox column with three sections:
┌─────────────────────────────────────────────────────────┐
│ Header: Navigation │ Confidence Badge │ Shortcuts │
├────────────────────────┬────────────────────────────────┤
│ │ │
│ Left Pane │ Right Pane │
│ Original Document │ Extracted Data │
│ (PDF.js viewer) │ (Markdown / structured) │
│ │ │
├────────────────────────┴────────────────────────────────┤
│ Action Bar: [✓ Approve] [✎ Edit] [⚑ Flag] │
└─────────────────────────────────────────────────────────┘
| Element | Description |
|---|---|
| Page navigation |
◀ Page N (X of Y) ▶ with chevron buttons |
| Confidence badge | Color-coded score for the current page |
| Progress text | X reviewed, Y remaining |
| Keyboard shortcut hints | Enter=Approve F=Flag E=Edit Arrows=Navigate |
- Title bar: "Original Document"
- PDF viewer rendering the source page with page-level navigation and sync support
- Keeps the selected page aligned with the extracted-content panel during review flow
- Title bar: "Extracted Data"
- Scrollable content area rendering the extracted markdown
- Displayed in a
<pre>block withprosetypography for readability - Falls back to "No content extracted" when markdown is empty
Three action buttons with distinct visual treatment:
| Button | Color | Keyboard | Behavior |
|---|---|---|---|
| Approve | Green (bg-green-600) |
Enter |
Calls onApprove(pageNum), advances to next page |
| Edit | Gray / Blue toggle | E |
Toggles edit mode (button turns blue when active) |
| Flag | Amber (bg-amber-100) |
F |
Calls onFlag(pageNum, reason), advances to next page |
interface ReviewPage {
pageNum: number;
confidence: number;
markdown: string;
extraction?: Record<string, unknown>;
}
interface ReviewInterfaceProps {
docId: string;
pages: ReviewPage[];
onApprove: (pageNum: number) => void;
onEdit: (pageNum: number, data: Record<string, unknown>) => void;
onFlag: (pageNum: number, reason: string) => void;
}The parent component is responsible for:
- Fetching review pages via
getReviewPages(docId)from the API client - Sorting pages by confidence (lowest first) to implement the smart queue
- Handling approve/edit/flag callbacks (persisting decisions to the backend)
The ConfidenceBadge component (frontend/src/components/common/confidence-badge.tsx) applies color thresholds:
| Range | Color | Meaning |
|---|---|---|
| > 0.9 | Green | High confidence — likely auto-approvable |
| 0.7 – 0.9 | Amber | Medium confidence — review recommended |
| < 0.7 | Red | Low confidence — requires human verification |
These thresholds align with the backend HITL configuration:
hitl:
auto_approve_threshold: 0.9
review_threshold: 0.7See Settings for full HITL configuration.
All shortcuts are active when not in edit mode:
| Key | Action |
|---|---|
Enter |
Approve current page and advance |
F |
Flag current page and advance |
E |
Toggle edit mode |
ArrowRight |
Navigate to next page |
ArrowLeft |
Navigate to previous page |
The keyboard handler disables during edit mode to prevent accidental approvals:
useEffect(() => {
function handleKeyDown(e: KeyboardEvent) {
if (isEditing) return;
switch (e.key) {
case "Enter":
if (currentPage) onApprove(currentPage.pageNum);
goNext();
break;
case "f": case "F":
if (currentPage) onFlag(currentPage.pageNum, "Flagged via keyboard");
goNext();
break;
case "e": case "E":
setIsEditing(true);
break;
case "ArrowRight": goNext(); break;
case "ArrowLeft": goPrev(); break;
}
}
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [currentPage, isEditing, onApprove, onFlag, goNext, goPrev]);Pages are expected to arrive sorted by confidence ascending (lowest first). This means the reviewer works through the most uncertain pages first, maximizing the value of human attention. The parent component should sort before passing the pages prop:
const sorted = reviewPages.sort((a, b) => a.confidence - b.confidence);The header displays a real-time progress indicator:
{reviewed} reviewed, {total - reviewed} remaining
Where reviewed equals the current page index (pages before the current one are considered reviewed).
When a compliance review has been run and includes VLM (Vision Language Model) findings, the review interface shows a "Visual findings" badge in the page divider for pages with vision-channel compliance findings.
- The badge appears as a violet pill:
👁 Visual findings - Clicking the badge navigates to the compliance page (
/compliance?doc={docId}) - Data is fetched lazily via
getComplianceReport(docId)on page load — non-blocking, best-effort - If no compliance report exists yet (e.g., compliance hasn't been run), no badges appear
This provides cross-referencing between the review and compliance workflows, helping reviewers identify pages that have been flagged by the visual compliance system.
Props added to ReviewInterface:
-
vlmPages?: Set<number>— set of page numbers with VLM findings, passed from parent
Props added to PageDivider:
-
hasVlmFindings?: boolean— whether the page has VLM findings -
docId?: string— for constructing the compliance link
Fetch review pages (GET /api/review/{docId}/pages)
→ Fetch compliance report (GET /api/compliance/{docId}/report) — async, best-effort
→ Build vlmPages set from findings with evaluation_channels including "vision"
→ Display first page in split-pane view
→ Page divider shows VLM badge if page has visual findings
→ Reviewer: Approve ──▶ POST approve, next page
Edit ──▶ Modify extraction, save
Flag ──▶ POST flag with reason, next page
→ When all pages reviewed → status transitions to "reviewed"
- Frontend Overview — Architecture and component map
- Upload Flow — How documents arrive at the review stage
- Compliance Dashboard — Post-review compliance analysis
-
Settings — HITL threshold configuration (
auto_approve_threshold,review_threshold)
Auto-synced from wiki/ on the main repo. Edit there, not here — direct wiki edits will be overwritten.