mirror of
https://github.com/zadam/trilium.git
synced 2026-05-07 05:47:26 +02:00
feat(ocr): warn about OCR confidence too low
This commit is contained in:
@@ -2093,7 +2093,9 @@
|
||||
"process_now": "Process OCR",
|
||||
"processing": "Processing...",
|
||||
"processing_started": "OCR processing has been started. Please wait a moment and refresh.",
|
||||
"processing_complete": "OCR processing complete.",
|
||||
"processing_failed": "Failed to start OCR processing",
|
||||
"text_filtered_low_confidence": "OCR detected text with {{confidence}}% confidence, but it was discarded because your minimum threshold is {{threshold}}%.\n\nYou can adjust the threshold in Options → Media.",
|
||||
"view_extracted_text": "View extracted text (OCR)"
|
||||
},
|
||||
"command_palette": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "./ReadOnlyTextRepresentation.css";
|
||||
|
||||
import type { TextRepresentationResponse } from "@triliumnext/commons";
|
||||
import type { OCRProcessResponse, TextRepresentationResponse } from "@triliumnext/commons";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
import { t } from "../../services/i18n";
|
||||
@@ -62,10 +62,27 @@ export function TextRepresentation({ textUrl, processUrl }: TextRepresentationPr
|
||||
async function processOCR() {
|
||||
setProcessing(true);
|
||||
try {
|
||||
const response = await server.post<{ success: boolean; message?: string }>(processUrl, { forceReprocess: true });
|
||||
const response = await server.post<OCRProcessResponse>(processUrl, { forceReprocess: true });
|
||||
if (response.success) {
|
||||
toast.showMessage(t("ocr.processing_started"));
|
||||
setTimeout(fetchText, 2000);
|
||||
const result = response.result;
|
||||
const minConfidence = response.minConfidence ?? 0;
|
||||
|
||||
// Check if text was filtered due to low confidence
|
||||
if (result && !result.text && result.confidence > 0 && minConfidence > 0) {
|
||||
const confidencePercent = Math.round(result.confidence * 100);
|
||||
const thresholdPercent = Math.round(minConfidence * 100);
|
||||
toast.showMessage(
|
||||
t("ocr.text_filtered_low_confidence", {
|
||||
confidence: confidencePercent,
|
||||
threshold: thresholdPercent
|
||||
}),
|
||||
10000, // Show for 10 seconds since this is important info
|
||||
"bx bx-info-circle"
|
||||
);
|
||||
} else {
|
||||
toast.showMessage(t("ocr.processing_complete"));
|
||||
}
|
||||
setTimeout(fetchText, 500);
|
||||
} else {
|
||||
toast.showError(response.message || t("ocr.processing_failed"));
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { TextRepresentationResponse } from "@triliumnext/commons";
|
||||
import type { OCRProcessResponse, TextRepresentationResponse } from "@triliumnext/commons";
|
||||
import type { Request } from "express";
|
||||
|
||||
import becca from "../../becca/becca.js";
|
||||
import ocrService from "../../services/ocr/ocr_service.js";
|
||||
import options from "../../services/options.js";
|
||||
import sql from "../../services/sql.js";
|
||||
|
||||
function getMinConfidenceThreshold(): number {
|
||||
const minConfidence = options.getOption('ocrMinConfidence') ?? 0;
|
||||
return parseFloat(minConfidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/ocr/process-note/{noteId}:
|
||||
@@ -48,7 +54,7 @@ import sql from "../../services/sql.js";
|
||||
* - session: []
|
||||
* tags: ["ocr"]
|
||||
*/
|
||||
async function processNoteOCR(req: Request<{ noteId: string }>) {
|
||||
async function processNoteOCR(req: Request<{ noteId: string }>): Promise<OCRProcessResponse | [number, OCRProcessResponse]> {
|
||||
const { noteId } = req.params;
|
||||
const { language, forceReprocess = false } = req.body || {};
|
||||
|
||||
@@ -62,7 +68,11 @@ async function processNoteOCR(req: Request<{ noteId: string }>) {
|
||||
return [400, { success: false, message: 'Note is not an image or has unsupported format' }];
|
||||
}
|
||||
|
||||
return { success: true, result };
|
||||
return {
|
||||
success: true,
|
||||
result,
|
||||
minConfidence: getMinConfidenceThreshold()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +118,7 @@ async function processNoteOCR(req: Request<{ noteId: string }>) {
|
||||
* - session: []
|
||||
* tags: ["ocr"]
|
||||
*/
|
||||
async function processAttachmentOCR(req: Request<{ attachmentId: string }>) {
|
||||
async function processAttachmentOCR(req: Request<{ attachmentId: string }>): Promise<OCRProcessResponse | [number, OCRProcessResponse]> {
|
||||
const { attachmentId } = req.params;
|
||||
const { language, forceReprocess = false } = req.body || {};
|
||||
|
||||
@@ -122,7 +132,11 @@ async function processAttachmentOCR(req: Request<{ attachmentId: string }>) {
|
||||
return [400, { success: false, message: 'Attachment is not an image or has unsupported format' }];
|
||||
}
|
||||
|
||||
return { success: true, result };
|
||||
return {
|
||||
success: true,
|
||||
result,
|
||||
minConfidence: getMinConfidenceThreshold()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -295,6 +295,20 @@ export interface TextRepresentationResponse {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface OCRProcessResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
result?: {
|
||||
text: string;
|
||||
confidence: number;
|
||||
extractedAt: string;
|
||||
language?: string;
|
||||
pageCount?: number;
|
||||
};
|
||||
/** The minimum confidence threshold that was applied (0-1 scale). */
|
||||
minConfidence?: number;
|
||||
}
|
||||
|
||||
export interface IconRegistry {
|
||||
sources: {
|
||||
prefix: string;
|
||||
|
||||
Reference in New Issue
Block a user