web-app-demo/Frontend/src/app/components/processor-selection/processor-selection.component.ts (225 lines of code) (raw):

/** * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint new-cap: ["error", { "capIsNew": false }]*/ import { Component, DoCheck, OnInit } from "@angular/core"; import { Subscription } from "rxjs"; import { DataSharingServiceService } from "src/app/data-sharing-service.service"; import { DocumentAnnotation } from "../../document-annotation"; import { AppComponent } from "../../app.component"; const LAYER2 = "layer2"; const RED = "#FF0000"; const BLUE = "#0000FF"; const ORANGE = "#FFA500"; export interface File { content: string; name: string; type: string; size: number; } @Component({ selector: "app-processor-selection", templateUrl: "./processor-selection.component.html", styleUrls: ["./processor-selection.component.css"], }) /** * ProcessSelectionComponent - handles file processing */ export class ProcessorSelectionComponent implements OnInit, DoCheck { selectedProcessor = ""; processorList: any = {}; processorSelectionList: string[] = []; /** * constructor for ProcessorSelectionComponent * @constructor * @param {DataSharingServiceService} data - data sharing service */ constructor(public data: DataSharingServiceService) {} processor!: string; fileName: string = ""; file!: any; showBounding!: boolean; showError!: boolean; documentProto!: any; processIsDone!: boolean; processInProgress = false; subscription!: Subscription; url!: string[]; backend!: string; /** * On init setup subscribed variables and inits backend * @return {void} */ async ngOnInit(): Promise<void> { this.url = location.href.split("-"); this.url.splice(0, 3); this.backend = "https://backend-" + this.url.join("-"); await fetch(this.backend + "api/init", { method: "GET", mode: "cors", }) .then(async (response) => { const json = await response.json(); if (json["resultStatus"] == "ERROR") { throw new Error(json.errorMessage); } }) .catch((error) => { this.data.changeShowError(true); this.data.changeErrorMessage(error); }); this.getAvailableProcessors(); this.subscription = this.data.processor.subscribe( (message) => (this.processor = message) ); this.subscription = this.data.fileName.subscribe( (message) => (this.fileName = message) ); this.subscription = this.data.file.subscribe( (message) => (this.file = message) ); this.subscription = this.data.showBounding.subscribe( (message) => (this.showBounding = message) ); this.subscription = this.data.documentProto.subscribe( (message) => (this.documentProto = message) ); this.subscription = this.data.processingIsDone.subscribe( (message) => (this.processIsDone = message) ); this.subscription = this.data.showError.subscribe( (message) => (this.showError = message) ); } /** * checks if selected processor has changed * @return {void} */ ngDoCheck() { if ( this.selectedProcessor != "" && this.processor != this.selectedProcessor ) { this.data.changeProcessor(this.selectedProcessor); } } /** * gets the available processors * @return {void} */ getAvailableProcessors() { fetch(this.backend + "api/processor/list", { method: "GET", mode: "cors", }) .then(async (response) => { const json = await response.json(); if (json["resultStatus"] == "ERROR") { throw new Error(json["errorMessage"]); } const retrievedProcessor = json["processor_list"]; for (let i = 0; i < retrievedProcessor.length; i++) { const key = retrievedProcessor[i].split("_")[0]; const value = retrievedProcessor[i]; this.processorSelectionList.push(key); this.processorList[key] = value; } }) .catch((error) => { this.data.changeShowError(true); this.data.changeErrorMessage(error); }); } /** * Process uploaded document * @return {void} */ processDocument() { this.data.changeProcessInProgress(true); if (this.fileName == "" || this.file == null) { this.data.changeProcessInProgress(false); this.data.changeShowError(true); this.data.changeErrorMessage("ERROR : PDF was not selected"); return; } else if (this.file.type != "application/pdf") { this.data.changeShowError(true); this.data.changeErrorMessage( "ERROR : File type does not match accepted type (PDF)" ); return; } const data = new FormData(); data.append("file", this.file); data.append("filename", this.fileName); data.append("fileProcessorType", this.processorList[this.processor]); data.append("showBounding", String(this.showBounding)); fetch(this.backend + "api/docai", { method: "POST", mode: "cors", body: data, }) .then(async (response) => { const json = await response.json(); if ( json["resultStatus"] != undefined && json["resultStatus"] == "ERROR" ) { throw new Error(json["errorMessage"]); } else { this.data.changeDocumentProto(json); return json; } }) .then(() => { this.data.changeProcessIsDone(true); this.data.changeProcessInProgress(false); const canvas = <HTMLCanvasElement>document.getElementById(LAYER2)!; const context = canvas.getContext("2d")!; const background = new Image(); background.src = "data:image/png;base64," + this.documentProto.document.pages[0].image.content; // Make sure the image is loaded first otherwise nothing will draw. background.onload = () => { context.drawImage( background, 0, 0, background.width, background.height, 0, 0, canvas.width, canvas.height ); this.drawBoxes(context, canvas); }; }) .catch((error) => { this.data.changeShowError(true); this.data.changeErrorMessage(error); this.data.changeProcessInProgress(false); }); } /** * Calls drawBoundingBoxes to draw bounding boxes for document * @param {CanvasRenderingContext2D} context - the context of rendered canvas * @param {HTMLCanvasElement} canvas - canvas to draw on * @return {void} */ drawBoxes(context: CanvasRenderingContext2D, canvas: HTMLCanvasElement) { const data = this.documentProto; const drawClient = new DocumentAnnotation(); switch (this.processor) { case "FORM": for (let i = 0; i < data.document.pages[0].formFields.length; i++) { drawClient.drawBoundingBoxes( context, canvas, data.document.pages[0].formFields[i].fieldName.boundingPoly, BLUE, "stroke", [] ); drawClient.drawBoundingBoxes( context, canvas, data.document.pages[0].formFields[i].fieldValue.boundingPoly, RED, "stroke", [] ); } break; case "OCR": for (let i = 0; i < data.document.pages[0].blocks.length; i++) { drawClient.drawBoundingBoxes( context, canvas, data.document.pages[0].blocks[i].layout.boundingPoly, ORANGE, "stroke", [] ); } break; case "INVOICE": for (let i = 0; i < data.document.entities.length; i++) { drawClient.drawBoundingBoxes( context, canvas, data.document.entities[i].pageAnchor.pageRefs[0].boundingPoly, BLUE, "stroke", [] ); } break; } } }