From 767901272eeea30137330e710cc8cf70fd34f1de Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 23 Jul 2019 03:13:08 -0400
Subject: autotag based on confidence, allow concealment of computed fields
 that resolve to undefined with namespace constant ComputedField.undefined

---
 src/client/views/nodes/FaceRectangles.tsx | 46 +++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 src/client/views/nodes/FaceRectangles.tsx

(limited to 'src/client/views/nodes/FaceRectangles.tsx')

diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx
new file mode 100644
index 000000000..3570531b2
--- /dev/null
+++ b/src/client/views/nodes/FaceRectangles.tsx
@@ -0,0 +1,46 @@
+import React = require("react");
+import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Cast, NumCast } from "../../../new_fields/Types";
+import { observer } from "mobx-react";
+import { Id } from "../../../new_fields/FieldSymbols";
+import FaceRectangle from "./FaceRectangle";
+
+interface FaceRectanglesProps {
+    document: Doc;
+    color: string;
+    backgroundColor: string;
+}
+
+export interface RectangleTemplate {
+    id: string;
+    style: Partial<React.CSSProperties>;
+}
+
+@observer
+export default class FaceRectangles extends React.Component<FaceRectanglesProps> {
+
+    render() {
+        let faces = DocListCast(Doc.GetProto(this.props.document).faces);
+        let templates: RectangleTemplate[] = faces.map(faceDoc => {
+            let rectangle = Cast(faceDoc.faceRectangle, Doc) as Doc;
+            let style = {
+                top: NumCast(rectangle.top),
+                left: NumCast(rectangle.left),
+                width: NumCast(rectangle.width),
+                height: NumCast(rectangle.height),
+                backgroundColor: `${this.props.backgroundColor}33`,
+                border: `solid 2px ${this.props.color}`,
+            } as React.CSSProperties;
+            return {
+                id: rectangle[Id],
+                style: style
+            };
+        });
+        return (
+            <div>
+                {templates.map(rectangle => <FaceRectangle key={rectangle.id} rectangle={rectangle} />)}
+            </div>
+        );
+    }
+
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 5248a770123e312e1684d7147ecb7118dd6ef1e7 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 30 Jul 2019 01:24:37 -0400
Subject: tag generation and faces on extensionDoc

---
 src/client/cognitive_services/CognitiveServices.ts | 40 ++++--------------
 src/client/views/nodes/FaceRectangles.tsx          |  2 +-
 src/client/views/nodes/ImageBox.tsx                | 49 +++++++++++++++++++---
 3 files changed, 54 insertions(+), 37 deletions(-)

(limited to 'src/client/views/nodes/FaceRectangles.tsx')

diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index bbc438a9b..076907f09 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -42,7 +42,7 @@ export enum Confidence {
  */
 export namespace CognitiveServices {
 
-    const executeQuery = async <D, R>(service: Service, manager: APIManager<D>, data: D): Promise<Opt<R>> => {
+    const ExecuteQuery = async <D, R>(service: Service, manager: APIManager<D>, data: D): Promise<Opt<R>> => {
         return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => {
             let apiKey = await response.text();
             if (!apiKey) {
@@ -103,15 +103,15 @@ export namespace CognitiveServices {
                 return request.post(options);
             },
 
-            analyzer: async (target: Doc, keys: string[], service: Service, converter: Converter) => {
+            analyzer: async (target: Doc, keys: string[], url: string, service: Service, converter: Converter) => {
                 let batch = UndoManager.StartBatch("Image Analysis");
-                let imageData = Cast(target.data, ImageField);
+
                 let storageKey = keys[0];
-                if (!imageData || await Cast(target[storageKey], Doc)) {
+                if (!url || await Cast(target[storageKey], Doc)) {
                     return;
                 }
                 let toStore: any;
-                let results = await executeQuery<string, any>(service, Manager, imageData.url.href);
+                let results = await ExecuteQuery<string, any>(service, Manager, url);
                 if (!results) {
                     toStore = "Cognitive Services could not process the given image URL.";
                 } else {
@@ -122,6 +122,7 @@ export namespace CognitiveServices {
                     }
                 }
                 target[storageKey] = toStore;
+
                 batch.end();
             }
 
@@ -129,31 +130,6 @@ export namespace CognitiveServices {
 
         export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle };
 
-        export const generateMetadata = async (target: Doc, threshold: Confidence = Confidence.Excellent) => {
-            let converter = (results: any) => {
-                let tagDoc = new Doc;
-                results.tags.map((tag: Tag) => {
-                    let sanitized = tag.name.replace(" ", "_");
-                    let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`;
-                    let computed = CompileScript(script, { params: { this: "Doc" } });
-                    computed.compiled && (tagDoc[sanitized] = new ComputedField(computed));
-                });
-                tagDoc.title = "Generated Tags";
-                tagDoc.confidence = threshold;
-                return tagDoc;
-            };
-            Manager.analyzer(target, ["generatedTags"], Service.ComputerVision, converter);
-        };
-
-        export const extractFaces = async (target: Doc) => {
-            let converter = (results: any) => {
-                let faceDocs = new List<Doc>();
-                results.map((face: Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!));
-                return faceDocs;
-            };
-            Manager.analyzer(target, ["faces"], Service.Face, converter);
-        };
-
     }
 
     export namespace Inking {
@@ -209,7 +185,8 @@ export namespace CognitiveServices {
 
             analyzer: async (target: Doc, keys: string[], inkData: InkData) => {
                 let batch = UndoManager.StartBatch("Ink Analysis");
-                let results = await executeQuery<InkData, any>(Service.Handwriting, Manager, inkData);
+
+                let results = await ExecuteQuery<InkData, any>(Service.Handwriting, Manager, inkData);
                 if (results) {
                     results.recognitionUnits && (results = results.recognitionUnits);
                     target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis");
@@ -217,6 +194,7 @@ export namespace CognitiveServices {
                     let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1);
                     target[keys[1]] = individualWords.join(" ");
                 }
+
                 batch.end();
             }
 
diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx
index 3570531b2..acf1aced3 100644
--- a/src/client/views/nodes/FaceRectangles.tsx
+++ b/src/client/views/nodes/FaceRectangles.tsx
@@ -20,7 +20,7 @@ export interface RectangleTemplate {
 export default class FaceRectangles extends React.Component<FaceRectanglesProps> {
 
     render() {
-        let faces = DocListCast(Doc.GetProto(this.props.document).faces);
+        let faces = DocListCast(this.props.document.faces);
         let templates: RectangleTemplate[] = faces.map(faceDoc => {
             let rectangle = Cast(faceDoc.faceRectangle, Doc) as Doc;
             let style = {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 29a76b0c8..5554475ec 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -25,9 +25,12 @@ import { Docs, DocumentType } from '../../documents/Documents';
 import { DocServer } from '../../DocServer';
 import { Font } from '@react-pdf/renderer';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { CognitiveServices } from '../../cognitive_services/CognitiveServices';
+import { CognitiveServices, Service, Tag, Confidence } from '../../cognitive_services/CognitiveServices';
 import FaceRectangles from './FaceRectangles';
 import { faEye } from '@fortawesome/free-regular-svg-icons';
+import { ComputedField } from '../../../new_fields/ScriptField';
+import { CompileScript } from '../../util/Scripting';
+import { thisExpression } from 'babel-types';
 var requestImageSize = require('../../util/request-image-size');
 var path = require('path');
 const { Howl } = require('howler');
@@ -226,20 +229,56 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
             funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" });
 
             let modes: ContextMenuProps[] = [];
-            let dataDoc = Doc.GetProto(this.props.Document);
-            modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(dataDoc), icon: "tag" });
-            modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(dataDoc), icon: "camera" });
+            modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" });
+            modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" });
 
             ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs, icon: "asterisk" });
             ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes, icon: "eye" });
         }
     }
 
+    extractFaces = () => {
+        let converter = (results: any) => {
+            let faceDocs = new List<Doc>();
+            results.map((face: CognitiveServices.Image.Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!));
+            return faceDocs;
+        };
+        CognitiveServices.Image.Manager.analyzer(this.extensionDoc, ["faces"], this.url, Service.Face, converter);
+    }
+
+    generateMetadata = (threshold: Confidence = Confidence.Excellent) => {
+        let converter = (results: any) => {
+            let tagDoc = new Doc;
+            let tagsList = new List();
+            results.tags.map((tag: Tag) => {
+                tagsList.push(tag.name);
+                let sanitized = tag.name.replace(" ", "_");
+                let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`;
+                let computed = CompileScript(script, { params: { this: "Doc" } });
+                computed.compiled && (tagDoc[sanitized] = new ComputedField(computed));
+            });
+            this.extensionDoc.generatedTags = tagsList;
+            tagDoc.title = "Generated Tags Doc";
+            tagDoc.confidence = threshold;
+            return tagDoc;
+        };
+        CognitiveServices.Image.Manager.analyzer(this.extensionDoc, ["generatedTagsDoc"], this.url, Service.ComputerVision, converter);
+    }
+
     @action
     onDotDown(index: number) {
         this.Document.curPage = index;
     }
 
+    @computed get fieldExtensionDoc() {
+        return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true");
+    }
+
+    @computed private get url() {
+        let data = Cast(Doc.GetProto(this.props.Document).data, ImageField);
+        return data ? data.url.href : undefined;
+    }
+
     dots(paths: string[]) {
         let nativeWidth = FieldValue(this.Document.nativeWidth, 1);
         let dist = Math.min(nativeWidth / paths.length, 40);
@@ -394,7 +433,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                         style={{ color: [DocListCast(this.extensionDoc.audioAnnotations).length ? "blue" : "gray", "green", "red"][this._audioState] }} icon={faFileAudio} size="sm" />
                 </div>
                 {/* {this.lightbox(paths)} */}
-                <FaceRectangles document={this.props.Document} color={"#0000FF"} backgroundColor={"#0000FF"} />
+                <FaceRectangles document={this.extensionDoc} color={"#0000FF"} backgroundColor={"#0000FF"} />
             </div>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

