From cb95d4b43238538f59babcaa0b0d9dabb9b393b7 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 23 Jul 2019 22:07:13 -0400
Subject: Ink recognition and presentation view toggle

---
 src/client/views/InkingCanvas.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'src/client/views/InkingCanvas.tsx')

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 3e0d7b476..e48b45b56 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -10,6 +10,8 @@ import { undoBatch, UndoManager } from "../util/UndoManager";
 import { StrokeData, InkField, InkTool } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
 import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
+import { CognitiveServices } from "../cognitive_services/CognitiveServices";
+import { ContextMenu } from "./ContextMenu";
 
 interface InkCanvasProps {
     getScreenTransform: () => Transform;
@@ -178,7 +180,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     render() {
         let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None ? "canSelect" : "noSelect";
         return (
-            <div className="inkingCanvas" >
+            <div className="inkingCanvas">
                 <div className={`inkingCanvas-${svgCanvasStyle}`} onPointerDown={this.onPointerDown} />
                 {this.props.children()}
                 {this.drawnPaths}
-- 
cgit v1.2.3-70-g09d2


From d6cef0815815c2587b9cc791e6a37c742aba1b45 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Thu, 25 Jul 2019 03:31:34 -0400
Subject: cognitive services refactor, buxton python script fixes, covered up
 imagebox context menu bug

---
 src/client/cognitive_services/CognitiveServices.ts | 151 +++++++++++----------
 src/client/views/InkingCanvas.tsx                  |   4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   2 +-
 src/client/views/nodes/ImageBox.tsx                |   6 +-
 src/scraping/buxton/scraper.py                     |  17 +--
 5 files changed, 93 insertions(+), 87 deletions(-)

(limited to 'src/client/views/InkingCanvas.tsx')

diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index dcd27f858..d689b424d 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -1,5 +1,5 @@
 import * as request from "request-promise";
-import { Doc, Field } from "../../new_fields/Doc";
+import { Doc, Field, Opt } from "../../new_fields/Doc";
 import { Cast } from "../../new_fields/Types";
 import { ImageField } from "../../new_fields/URLField";
 import { List } from "../../new_fields/List";
@@ -10,7 +10,15 @@ import { CompileScript } from "../util/Scripting";
 import { ComputedField } from "../../new_fields/ScriptField";
 import { InkData } from "../../new_fields/InkField";
 
-export enum Services {
+type APIManager<D> = { requester: RequestExecutor<D>, applier: AnalysisApplier };
+type RequestExecutor<D> = (apiKey: string, data: D, service: Service) => Promise<string>;
+type AnalysisApplier = (target: Doc, ...args: any) => any;
+type Converter = (results: any) => Field;
+
+export type Tag = { name: string, confidence: number };
+export type Rectangle = { top: number, left: number, width: number, height: number };
+
+export enum Service {
     ComputerVision = "vision",
     Face = "face",
     Handwriting = "handwriting"
@@ -25,11 +33,6 @@ export enum Confidence {
     Excellent = 0.95
 }
 
-export type Tag = { name: string, confidence: number };
-export type Rectangle = { top: number, left: number, width: number, height: number };
-export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle };
-export type Converter = (results: any) => Field;
-
 /**
  * A file that handles all interactions with Microsoft Azure's Cognitive
  * Services APIs. These machine learning endpoints allow basic data analytics for
@@ -37,19 +40,33 @@ export type Converter = (results: any) => Field;
  */
 export namespace CognitiveServices {
 
+    const executeQuery = async <D, R>(service: Service, executor: RequestExecutor<D>, data: D): Promise<Opt<R>> => {
+        return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => {
+            let apiKey = await response.text();
+            if (!apiKey) {
+                return undefined;
+            }
+
+            let results: Opt<R>;
+            try {
+                results = await executor(apiKey, data, service).then(json => JSON.parse(json));
+            } catch {
+                results = undefined;
+            }
+            return results;
+        });
+    };
+
     export namespace Image {
 
-        export const analyze = async (imageUrl: string, service: Services) => {
-            return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => {
-                let apiKey = await response.text();
-                if (!apiKey) {
-                    return undefined;
-                }
+        export const Manager: APIManager<string> = {
+
+            requester: (async (apiKey: string, imageUrl: string, service: Service) => {
                 let uriBase;
                 let parameters;
 
                 switch (service) {
-                    case Services.Face:
+                    case Service.Face:
                         uriBase = 'face/v1.0/detect';
                         parameters = {
                             'returnFaceId': 'true',
@@ -58,7 +75,7 @@ export namespace CognitiveServices {
                                 'emotion,hair,makeup,occlusion,accessories,blur,exposure,noise'
                         };
                         break;
-                    case Services.ComputerVision:
+                    case Service.ComputerVision:
                         uriBase = 'vision/v2.0/analyze';
                         parameters = {
                             'visualFeatures': 'Categories,Description,Color,Objects,Tags,Adult',
@@ -78,35 +95,32 @@ export namespace CognitiveServices {
                     }
                 };
 
-                let results: any;
-                try {
-                    results = await request.post(options).then(response => JSON.parse(response));
-                } catch (e) {
-                    results = undefined;
-                }
-                return results;
-            });
-        };
+                return request.post(options);
+            }) as RequestExecutor<string>,
 
-        const analyzeDocument = async (target: Doc, service: Services, converter: Converter, storageKey: string) => {
-            let imageData = Cast(target.data, ImageField);
-            if (!imageData || await Cast(target[storageKey], Doc)) {
-                return;
-            }
-            let toStore: any;
-            let results = await analyze(imageData.url.href, service);
-            if (!results) {
-                toStore = "Cognitive Services could not process the given image URL.";
-            } else {
-                if (!results.length) {
-                    toStore = converter(results);
+            applier: (async (target: Doc, service: Service, converter: Converter, storageKey: string) => {
+                let imageData = Cast(target.data, ImageField);
+                if (!imageData || await Cast(target[storageKey], Doc)) {
+                    return;
+                }
+                let toStore: any;
+                let results = await executeQuery<string, any>(service, Manager.requester, imageData.url.href);
+                if (!results) {
+                    toStore = "Cognitive Services could not process the given image URL.";
                 } else {
-                    toStore = results.length > 0 ? converter(results) : "Empty list returned.";
+                    if (!results.length) {
+                        toStore = converter(results);
+                    } else {
+                        toStore = results.length > 0 ? converter(results) : "Empty list returned.";
+                    }
                 }
-            }
-            target[storageKey] = toStore;
+                target[storageKey] = toStore;
+            }) as AnalysisApplier
+
         };
 
+        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;
@@ -120,7 +134,7 @@ export namespace CognitiveServices {
                 tagDoc.confidence = threshold;
                 return tagDoc;
             };
-            analyzeDocument(target, Services.ComputerVision, converter, "generatedTags");
+            Manager.applier(target, Service.ComputerVision, converter, "generatedTags");
         };
 
         export const extractFaces = async (target: Doc) => {
@@ -129,48 +143,24 @@ export namespace CognitiveServices {
                 results.map((face: Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!));
                 return faceDocs;
             };
-            analyzeDocument(target, Services.Face, converter, "faces");
+            Manager.applier(target, Service.Face, converter, "faces");
         };
 
     }
 
     export namespace Inking {
 
-        export interface AzureStrokeData {
-            id: number;
-            points: string;
-            language?: string;
-        }
-
-        export interface HandwritingUnit {
-            version: number;
-            language: string;
-            unit: string;
-            strokes: AzureStrokeData[];
-        }
-
-        export const analyze = async (inkData: InkData, target: Doc) => {
-            return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${Services.Handwriting}`)).then(async response => {
-                let apiKey = await response.text();
-                if (!apiKey) {
-                    return undefined;
-                }
+        export const Manager: APIManager<InkData> = {
 
+            requester: (async (apiKey: string, inkData: InkData) => {
                 let xhttp = new XMLHttpRequest();
                 let serverAddress = "https://api.cognitive.microsoft.com";
                 let endpoint = serverAddress + "/inkrecognizer/v1.0-preview/recognize";
 
-                let requestExecutor = (resolve: any, reject: any) => {
-                    let result: any;
-                    let body = format(inkData);
-
+                let promisified = (resolve: any, reject: any) => {
                     xhttp.onreadystatechange = function () {
                         if (this.readyState === 4) {
-                            try {
-                                result = JSON.parse(xhttp.responseText);
-                            } catch (e) {
-                                return reject(e);
-                            }
+                            let result = xhttp.responseText;
                             switch (this.status) {
                                 case 200:
                                     return resolve(result);
@@ -184,11 +174,14 @@ export namespace CognitiveServices {
                     xhttp.open("PUT", endpoint, true);
                     xhttp.setRequestHeader('Ocp-Apim-Subscription-Key', apiKey);
                     xhttp.setRequestHeader('Content-Type', 'application/json');
-                    xhttp.send(body);
+                    xhttp.send(format(inkData));
                 };
 
-                let results = await new Promise<any>(requestExecutor);
+                return new Promise<any>(promisified);
+            }) as RequestExecutor<InkData>,
 
+            applier: (async (target: Doc, inkData: InkData) => {
+                let results = await executeQuery<InkData, any>(Service.Handwriting, Manager.requester, inkData);
                 if (results) {
                     results.recognitionUnits && (results = results.recognitionUnits);
                     target.inkAnalysis = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis");
@@ -196,9 +189,23 @@ export namespace CognitiveServices {
                     let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1);
                     target.handwriting = individualWords.join(" ");
                 }
-            });
+            }) as AnalysisApplier
+
         };
 
+        export interface AzureStrokeData {
+            id: number;
+            points: string;
+            language?: string;
+        }
+
+        export interface HandwritingUnit {
+            version: number;
+            language: string;
+            unit: string;
+            strokes: AzureStrokeData[];
+        }
+
         const format = (inkData: InkData): string => {
             let entries = inkData.entries(), next = entries.next();
             let strokes: AzureStrokeData[] = [], id = 0;
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index e48b45b56..c4cd863d1 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -6,12 +6,10 @@ import "./InkingCanvas.scss";
 import { InkingControl } from "./InkingControl";
 import { InkingStroke } from "./InkingStroke";
 import React = require("react");
-import { undoBatch, UndoManager } from "../util/UndoManager";
+import { UndoManager } from "../util/UndoManager";
 import { StrokeData, InkField, InkTool } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
 import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
-import { CognitiveServices } from "../cognitive_services/CognitiveServices";
-import { ContextMenu } from "./ContextMenu";
 
 interface InkCanvasProps {
     getScreenTransform: () => Transform;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index bd5c6f84b..4b7ddd49d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -519,7 +519,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                 if (!data) {
                     return;
                 }
-                CognitiveServices.Inking.analyze(data.inkData, Doc.GetProto(this.props.Document));
+                CognitiveServices.Inking.Manager.applier(Doc.GetProto(this.props.Document), data.inkData);
             }
         });
     }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 89ad18dd6..3d77696fe 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -216,9 +216,9 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
             });
 
             let modes: ContextMenuProps[] = [];
-            let dataDoc = Doc.GetProto(this.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" });
+            // let dataDoc = Doc.GetProto(this.Document);
+            modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(this.Document), icon: "tag" });
+            modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(this.Document), icon: "camera" });
 
             ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs });
             ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes });
diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py
index 700269727..14490cfe4 100644
--- a/src/scraping/buxton/scraper.py
+++ b/src/scraping/buxton/scraper.py
@@ -15,6 +15,7 @@ source = "./source"
 dist = "../../server/public/files"
 
 db = MongoClient("localhost", 27017)["Dash"]
+target_collection = db.newDocuments
 schema_guids = []
 
 
@@ -84,7 +85,7 @@ def write_schema(parse_results, display_fields, storage_key):
             "height": 600,
             "panX": 0,
             "panY": 0,
-            "zoomBasis": 0.5,
+            "zoomBasis": 1,
             "zIndex": 2,
             "libraryBrush": False,
             "viewType": 2
@@ -106,8 +107,8 @@ def write_schema(parse_results, display_fields, storage_key):
     fields["isPrototype"] = True
     fields["page"] = -1
 
-    db.newDocuments.insert_one(data_doc)
-    db.newDocuments.insert_one(view_doc)
+    target_collection.insert_one(data_doc)
+    target_collection.insert_one(view_doc)
 
     data_doc_guid = data_doc["_id"]
     print(f"inserted view document ({view_doc_guid})")
@@ -158,8 +159,8 @@ def write_text_doc(content):
         "__type": "Doc"
     }
 
-    db.newDocuments.insert_one(view_doc)
-    db.newDocuments.insert_one(data_doc)
+    target_collection.insert_one(view_doc)
+    target_collection.insert_one(data_doc)
 
     return view_doc_guid
 
@@ -209,8 +210,8 @@ def write_image(folder, name):
         "__type": "Doc"
     }
 
-    db.newDocuments.insert_one(view_doc)
-    db.newDocuments.insert_one(data_doc)
+    target_collection.insert_one(view_doc)
+    target_collection.insert_one(data_doc)
 
     return view_doc_guid
 
@@ -372,7 +373,7 @@ parent_guid = write_schema({
 }, ["title", "short_description", "original_price"], "data")
 
 print("appending parent schema to main workspace...\n")
-db.newDocuments.update_one(
+target_collection.update_one(
     {"fields.title": "WS collection 1"},
     {"$push": {"fields.data.fields": {"fieldId": parent_guid, "__type": "proxy"}}}
 )
-- 
cgit v1.2.3-70-g09d2

