OCR Integration for entire document

This commit is contained in:
Timo 2021-03-30 19:08:54 +03:00
parent 8470501b08
commit 05625c72de
17 changed files with 283 additions and 33 deletions

View File

@ -7,7 +7,7 @@ To re-generate http rune swagger
YOu need swagger-codegen installed `brew install swagger-codegen`
```
BASE=https://timo-redaction-dev-2.iqser.cloud/
BASE=https://redapi-staging.iqser.cloud/
URL="$BASE"v2/api-docs?group=redaction-gateway-v1
mkdir -p /tmp/swagger
swagger-codegen generate -i "$URL" -l typescript-angular -o /tmp/swagger

View File

@ -89,7 +89,7 @@ export class FileStatusWrapper {
}
get status() {
return this.fileStatus.status === 'REPROCESS' ? 'PROCESSING' : this.fileStatus.status;
return this.fileStatus.status === 'REPROCESS' || this.fileStatus.status === 'OCR_PROCESSING' ? 'PROCESSING' : this.fileStatus.status;
}
get numberOfPages() {
@ -105,7 +105,7 @@ export class FileStatusWrapper {
}
get isProcessing() {
return [FileStatus.StatusEnum.REPROCESS, FileStatus.StatusEnum.PROCESSING].includes(this.status);
return [FileStatus.StatusEnum.REPROCESS, FileStatus.StatusEnum.OCR_PROCESSING, FileStatus.StatusEnum.PROCESSING].includes(this.status);
}
get statusSort() {

View File

@ -49,6 +49,7 @@ export class IconsModule {
'needs-work',
'new-tab',
'notification',
'ocr',
'page',
'pages',
'plus',

View File

@ -44,6 +44,8 @@
<redaction-circle-button (action)="setToUnderApproval()" *ngIf="canUndoApproval" tooltip="project-overview.under-approval" type="dark-bg" icon="red:undo">
</redaction-circle-button>
<redaction-circle-button (action)="ocr()" *ngIf="canOcr" tooltip="project-overview.ocr-file" type="dark-bg" icon="red:ocr"></redaction-circle-button>
<redaction-circle-button
(action)="reanalyse()"
*ngIf="canReanalyse"

View File

@ -59,6 +59,10 @@ export class ProjectOverviewBulkActionsComponent {
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canReanalyseFile(file), true);
}
public get canOcr() {
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canOcrFile(file), true);
}
public get fileStatuses() {
return this.selectedFiles.map((file) => file.fileStatus.status);
}
@ -85,6 +89,10 @@ export class ProjectOverviewBulkActionsComponent {
this._performBulkAction(this._reanalysisControllerService.reanalyzeFilesForProject(fileIds, this._appStateService.activeProject.projectId));
}
ocr() {
this._performBulkAction(this._fileActionService.ocrFile(this.selectedFiles));
}
// Under review
public get canSetToUnderReview() {
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canSetUnderReview(file), true);

View File

@ -103,6 +103,16 @@
>
</redaction-circle-button>
<redaction-circle-button
(action)="ocrFile($event, fileStatus)"
*ngIf="permissionsService.canOcrFile(fileStatus)"
[tooltipPosition]="tooltipPosition"
[type]="buttonType"
icon="red:ocr"
tooltip="project-overview.ocr-file"
>
</redaction-circle-button>
<!-- reanalyse file preview -->
<redaction-circle-button
(action)="reanalyseFile($event, fileStatus, 100)"

View File

@ -83,6 +83,13 @@ export class FileActionsComponent implements OnInit {
});
}
ocrFile($event: MouseEvent, fileStatus: FileStatusWrapper) {
$event.stopPropagation();
this._fileActionService.ocrFile(fileStatus).subscribe(() => {
this.reloadProjects('ocr-file');
});
}
setFileUnderReview($event: MouseEvent, fileStatus: FileStatusWrapper, ignoreDialogChanges = false) {
$event.stopPropagation();
// this._fileActionService.setFileUnderReview(fileStatus).subscribe(() => {

View File

@ -102,4 +102,14 @@ export class FileActionService {
this._appStateService.activeProjectId
);
}
ocrFile(fileStatus: FileStatusWrapper | FileStatusWrapper[]) {
if (!isArray(fileStatus)) {
fileStatus = [fileStatus];
}
return this._reanalysisControllerService.ocrFiles(
fileStatus.map((f) => f.fileId),
this._appStateService.activeProjectId
);
}
}

View File

@ -1,6 +1,6 @@
<div [matTooltipClass]="tooltipClass" [matTooltipPosition]="tooltipPosition" [matTooltip]="tooltip | translate">
<button
(click)="action.emit($event)"
(click)="performAction($event)"
[class.dark-bg]="type === 'dark-bg'"
[class.primary]="type === 'primary'"
[class.warn]="type === 'warn'"

View File

@ -20,4 +20,10 @@ export class CircleButtonComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
performAction($event: any) {
if (!this.disabled) {
this.action.emit($event);
}
}
}

View File

@ -1,6 +1,6 @@
<redaction-circle-button
[disabled]="!canDownloadFiles"
(click)="downloadFiles($event)"
(action)="downloadFiles($event)"
[tooltipClass]="tooltipClass"
[tooltipPosition]="tooltipPosition"
[type]="type"

View File

@ -287,4 +287,14 @@ export class PermissionsService {
}
return user.isUser;
}
canOcrFile(fileStatus?: FileStatusWrapper) {
if (!fileStatus) {
fileStatus = this._appStateService.activeFile;
}
if (!fileStatus) {
return false;
}
return fileStatus.status === 'UNASSIGNED' || fileStatus.status === 'UNDER_REVIEW' || fileStatus.status === 'UNDER_APPROVAL';
}
}

View File

@ -1,6 +1,6 @@
{
"OAUTH_URL": "https://timo-redaction-dev.iqser.cloud/auth/realms/redaction",
"API_URL": "https://timo-redaction-dev-2.iqser.cloud",
"OAUTH_URL": "https://redkc-staging.iqser.cloud/auth/realms/redaction",
"API_URL": "https://redapi-staging.iqser.cloud",
"OAUTH_CLIENT_ID": "redaction",
"BACKEND_APP_VERSION": "4.4.40",
"FRONTEND_APP_VERSION": "1.1",

View File

@ -192,6 +192,7 @@
"upload-document": "Upload Document",
"download-redacted-files": "Download Redacted Files"
},
"ocr-file": "OCR Document",
"download-file": "Download",
"download-file-disabled": "Download is only permitted for approved files",
"under-approval": "For Approval",

View File

@ -0,0 +1,23 @@
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512"
xmlns="http://www.w3.org/2000/svg">
<g>
<path
d="m488.472 232.468h-464.944c-12.973 0-23.528 10.554-23.528 23.528v32.072c0 12.974 10.555 23.528 23.534 23.528 4.142 0 7.497-3.358 7.497-7.5s-3.361-7.5-7.503-7.5c-4.703 0-8.528-3.826-8.528-8.528v-32.072c0-4.703 3.826-8.528 8.528-8.528h464.943c4.703 0 8.528 3.826 8.528 8.528v32.072c0 4.703-3.826 8.528-8.528 8.528-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5c12.974 0 23.528-10.555 23.528-23.528v-32.072c.001-12.974-10.554-23.528-23.527-23.528z"/>
<path
d="m55.597 215.403c4.142 0 7.5-3.358 7.5-7.5v-184.371c0-.285.231-.516.516-.516h384.774c.285 0 .516.231.516.516v184.371c0 4.142 3.358 7.5 7.5 7.5s7.5-3.358 7.5-7.5v-184.371c0-8.556-6.96-15.516-15.516-15.516h-384.774c-8.556 0-15.516 6.96-15.516 15.516v184.371c0 4.142 3.358 7.5 7.5 7.5z"/>
<path
d="m472.436 264.532h-432.872c-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5h8.532v208.936c0 8.556 6.96 15.516 15.516 15.516h384.774c8.556 0 15.516-6.96 15.516-15.516v-208.936h8.532c4.142 0 7.5-3.358 7.5-7.5s-3.356-7.5-7.498-7.5zm-23.533 223.936c0 .285-.231.516-.516.516h-384.774c-.285 0-.516-.231-.516-.516v-208.936h385.807v208.936z"/>
<path
d="m111.709 311.597h288.581c4.142 0 7.5-3.358 7.5-7.5s-3.358-7.5-7.5-7.5h-288.581c-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5z"/>
<path
d="m111.709 351.677h288.581c4.142 0 7.5-3.358 7.5-7.5s-3.358-7.5-7.5-7.5h-288.581c-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5z"/>
<path
d="m111.709 391.758h288.581c4.142 0 7.5-3.358 7.5-7.5s-3.358-7.5-7.5-7.5h-288.581c-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5z"/>
<path
d="m111.709 431.839h288.581c4.142 0 7.5-3.358 7.5-7.5s-3.358-7.5-7.5-7.5h-288.581c-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5z"/>
<path
d="m143.774 215.403c1.919 0 3.839-.732 5.303-2.197l70.014-70.014c3.079-3.079 7.964-3.35 11.364-.63l28.875 23.101c2.984 2.388 7.287 2.149 9.988-.553l76.841-76.841c3.327-3.326 8.74-3.327 12.067 0l60.809 60.809c2.929 2.929 7.678 2.929 10.606 0 2.929-2.929 2.929-7.678 0-10.606l-60.809-60.81c-9.176-9.174-24.105-9.174-33.28 0l-72.094 72.095-23.633-18.907c-9.375-7.501-22.849-6.755-31.341 1.736l-70.013 70.014c-2.929 2.929-2.929 7.678 0 10.606 1.465 1.465 3.384 2.197 5.303 2.197z"/>
<path
d="m175.323 99.686c0-19.606-15.951-35.557-35.557-35.557s-35.557 15.951-35.557 35.557 15.951 35.556 35.557 35.556 35.557-15.95 35.557-35.556zm-56.114 0c0-11.335 9.222-20.557 20.557-20.557s20.557 9.222 20.557 20.557c0 11.334-9.222 20.556-20.557 20.556s-20.557-9.222-20.557-20.556z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -21,9 +21,9 @@ import { Configuration } from '../configuration';
@Injectable()
export class ReanalysisControllerService {
protected basePath = '';
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
protected basePath = '';
constructor(protected httpClient: HttpClient, @Optional() @Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (basePath) {
@ -35,11 +35,168 @@ export class ReanalysisControllerService {
}
}
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
/**
* Ocr and reanalyze a file
* None
* @param projectId projectId
* @param fileId fileId
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public ocrFile(projectId: string, fileId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public ocrFile(projectId: string, fileId: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public ocrFile(projectId: string, fileId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public ocrFile(projectId: string, fileId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (projectId === null || projectId === undefined) {
throw new Error('Required parameter projectId was null or undefined when calling ocrFile.');
}
if (fileId === null || fileId === undefined) {
throw new Error('Required parameter fileId was null or undefined when calling ocrFile.');
}
let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required
if (this.configuration.accessToken) {
const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken;
headers = headers.set('Authorization', 'Bearer ' + accessToken);
}
// to determine the Accept header
const httpHeaderAccepts: string[] = [];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [];
return this.httpClient.request<any>(
'post',
`${this.basePath}/ocr/reanalyze/${encodeURIComponent(String(projectId))}/${encodeURIComponent(String(fileId))}`,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* Ocr and reanalyze multiple files for a project
* None
* @param body fileIds
* @param projectId projectId
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public ocrFiles(body: Array<string>, projectId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public ocrFiles(body: Array<string>, projectId: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public ocrFiles(body: Array<string>, projectId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public ocrFiles(body: Array<string>, projectId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (body === null || body === undefined) {
throw new Error('Required parameter body was null or undefined when calling ocrFiles.');
}
if (projectId === null || projectId === undefined) {
throw new Error('Required parameter projectId was null or undefined when calling ocrFiles.');
}
let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required
if (this.configuration.accessToken) {
const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken;
headers = headers.set('Authorization', 'Bearer ' + accessToken);
}
// to determine the Accept header
const httpHeaderAccepts: string[] = [];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = ['application/json'];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
headers = headers.set('Content-Type', httpContentTypeSelected);
}
return this.httpClient.request<any>('post', `${this.basePath}/ocr/reanalyze/${encodeURIComponent(String(projectId))}/bulk`, {
body: body,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
});
}
/**
* Ocr and reanalyze a project
* None
* @param projectId projectId
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public ocrProject(projectId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public ocrProject(projectId: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public ocrProject(projectId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public ocrProject(projectId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (projectId === null || projectId === undefined) {
throw new Error('Required parameter projectId was null or undefined when calling ocrProject.');
}
let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required
if (this.configuration.accessToken) {
const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken;
headers = headers.set('Authorization', 'Bearer ' + accessToken);
}
// to determine the Accept header
const httpHeaderAccepts: string[] = [];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [];
return this.httpClient.request<any>('post', `${this.basePath}/ocr/reanalyze/${encodeURIComponent(String(projectId))}`, {
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
});
}
/**
* Reanalyze a file
* None
* @param projectId projectId
* @param fileId fileId
* @param priority priority
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
@ -99,16 +256,32 @@ export class ReanalysisControllerService {
* None
* @param body fileIds
* @param projectId projectId
* @param force force
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public reanalyzeFilesForProject(body: Array<string>, projectId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public reanalyzeFilesForProject(body: Array<string>, projectId: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public reanalyzeFilesForProject(body: Array<string>, projectId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public reanalyzeFilesForProject(body: Array<string>, projectId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
public reanalyzeFilesForProject(body: Array<string>, projectId: string, force?: boolean, observe?: 'body', reportProgress?: boolean): Observable<any>;
public reanalyzeFilesForProject(
body: Array<string>,
projectId: string,
force?: boolean,
observe?: 'response',
reportProgress?: boolean
): Observable<HttpResponse<any>>;
public reanalyzeFilesForProject(
body: Array<string>,
projectId: string,
force?: boolean,
observe?: 'events',
reportProgress?: boolean
): Observable<HttpEvent<any>>;
public reanalyzeFilesForProject(
body: Array<string>,
projectId: string,
force?: boolean,
observe: any = 'body',
reportProgress: boolean = false
): Observable<any> {
if (body === null || body === undefined) {
throw new Error('Required parameter body was null or undefined when calling reanalyzeFilesForProject.');
}
@ -117,6 +290,11 @@ export class ReanalysisControllerService {
throw new Error('Required parameter projectId was null or undefined when calling reanalyzeFilesForProject.');
}
let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() });
if (force !== undefined && force !== null) {
queryParameters = queryParameters.set('force', <any>force);
}
let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required
@ -141,6 +319,7 @@ export class ReanalysisControllerService {
return this.httpClient.request<any>('post', `${this.basePath}/reanalyze/${encodeURIComponent(String(projectId))}/bulk`, {
body: body,
params: queryParameters,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
@ -157,11 +336,8 @@ export class ReanalysisControllerService {
* @param reportProgress flag to report request and response progress.
*/
public reanalyzeProject(projectId: string, force?: boolean, observe?: 'body', reportProgress?: boolean): Observable<any>;
public reanalyzeProject(projectId: string, force?: boolean, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public reanalyzeProject(projectId: string, force?: boolean, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public reanalyzeProject(projectId: string, force?: boolean, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (projectId === null || projectId === undefined) {
throw new Error('Required parameter projectId was null or undefined when calling reanalyzeProject.');
@ -198,18 +374,4 @@ export class ReanalysisControllerService {
reportProgress: reportProgress
});
}
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
}

View File

@ -111,11 +111,21 @@ export interface FileStatus {
}
export namespace FileStatus {
export type StatusEnum = 'UNPROCESSED' | 'REPROCESS' | 'PROCESSING' | 'ERROR' | 'UNASSIGNED' | 'UNDER_REVIEW' | 'UNDER_APPROVAL' | 'APPROVED';
export type StatusEnum =
| 'UNPROCESSED'
| 'REPROCESS'
| 'PROCESSING'
| 'OCR_PROCESSING'
| 'ERROR'
| 'UNASSIGNED'
| 'UNDER_REVIEW'
| 'UNDER_APPROVAL'
| 'APPROVED';
export const StatusEnum = {
UNPROCESSED: 'UNPROCESSED' as StatusEnum,
REPROCESS: 'REPROCESS' as StatusEnum,
PROCESSING: 'PROCESSING' as StatusEnum,
OCR_PROCESSING: 'OCR_PROCESSING' as StatusEnum,
ERROR: 'ERROR' as StatusEnum,
UNASSIGNED: 'UNASSIGNED' as StatusEnum,
UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum,