From 301784883375860a7c693db97fe8f279e5380caf Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Sat, 19 Oct 2019 16:51:45 -0400
Subject: image stuff

---
 src/client/views/RecommendationsBox.tsx | 185 ++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 src/client/views/RecommendationsBox.tsx

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

diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
new file mode 100644
index 000000000..3938a8690
--- /dev/null
+++ b/src/client/views/RecommendationsBox.tsx
@@ -0,0 +1,185 @@
+import { observer } from "mobx-react";
+import React = require("react");
+import { observable, action } from "mobx";
+import Measure from "react-measure";
+import "./RecommendationsBox.scss";
+import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
+import { DocumentIcon } from "./nodes/DocumentIcon";
+import { StrCast, NumCast } from "../../new_fields/Types";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { ObjectField } from "../../new_fields/ObjectField";
+import { DocumentView } from "./nodes/DocumentView";
+import { DocumentType } from '../documents/DocumentTypes';
+import { ClientRecommender } from "../ClientRecommender";
+import { DocServer } from "../DocServer";
+import { Id } from "../../new_fields/FieldSymbols";
+import { FieldView, FieldViewProps } from "./nodes/FieldView";
+import { DocumentManager } from "../util/DocumentManager";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { library } from "@fortawesome/fontawesome-svg-core";
+import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
+import { DocUtils } from "../documents/Documents";
+
+export interface RecProps {
+    documents: { preview: Doc, similarity: number }[];
+    node: Doc;
+}
+
+library.add(faBullseye, faLink);
+
+@observer
+export class RecommendationsBox extends React.Component<FieldViewProps> {
+
+    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
+
+    static Instance: RecommendationsBox;
+    // @observable private _display: boolean = false;
+    @observable private _pageX: number = 0;
+    @observable private _pageY: number = 0;
+    @observable private _width: number = 0;
+    @observable private _height: number = 0;
+    // @observable private _documents: { preview: Doc, score: number }[] = [];
+    private previewDocs: Doc[] = [];
+
+    constructor(props: FieldViewProps) {
+        super(props);
+        RecommendationsBox.Instance = this;
+    }
+
+    private DocumentIcon(doc: Doc) {
+        let layoutresult = StrCast(doc.type);
+        let renderDoc = doc;
+        //let box: number[] = [];
+        if (layoutresult.indexOf(DocumentType.COL) !== -1) {
+            renderDoc = Doc.MakeDelegate(renderDoc);
+            let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => {
+                var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
+                let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
+                return {
+                    x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
+                    r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
+                };
+            }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
+        }
+        let returnXDimension = () => 150;
+        let returnYDimension = () => 150;
+        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+        //let scale = () => 1;
+        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
+        newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
+        newRenderDoc.autoHeight = false;
+        const docview = <div>
+            <DocumentView
+                fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
+                Document={newRenderDoc}
+                addDocument={returnFalse}
+                removeDocument={returnFalse}
+                ruleProvider={undefined}
+                ScreenToLocalTransform={Transform.Identity}
+                addDocTab={returnFalse}
+                pinToPres={returnFalse}
+                renderDepth={1}
+                PanelWidth={returnXDimension}
+                PanelHeight={returnYDimension}
+                focus={emptyFunction}
+                backgroundColor={returnEmptyString}
+                parentActive={returnFalse}
+                whenActiveChanged={returnFalse}
+                bringToFront={emptyFunction}
+                zoomToScale={emptyFunction}
+                getScale={returnOne}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                ContentScaling={scale}
+            />
+        </div>;
+        return docview;
+
+    }
+
+    // @action
+    // closeMenu = () => {
+    //     this._display = false;
+    //     this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
+    //     this.previewDocs = [];
+    // }
+
+    // @action
+    // resetDocuments = () => {
+    //     this._documents = [];
+    // }
+
+    // @action
+    // displayRecommendations(x: number, y: number) {
+    //     this._pageX = x;
+    //     this._pageY = y;
+    //     this._display = true;
+    // }
+
+    static readonly buffer = 20;
+
+    // get pageX() {
+    //     const x = this._pageX;
+    //     if (x < 0) {
+    //         return 0;
+    //     }
+    //     const width = this._width;
+    //     if (x + width > window.innerWidth - RecommendationsBox.buffer) {
+    //         return window.innerWidth - RecommendationsBox.buffer - width;
+    //     }
+    //     return x;
+    // }
+
+    // get pageY() {
+    //     const y = this._pageY;
+    //     if (y < 0) {
+    //         return 0;
+    //     }
+    //     const height = this._height;
+    //     if (y + height > window.innerHeight - RecommendationsBox.buffer) {
+    //         return window.innerHeight - RecommendationsBox.buffer - height;
+    //     }
+    //     return y;
+    // }
+
+    render() {
+        // if (!this._display) {
+        //     return null;
+        // }
+        // let style = { left: this.pageX, top: this.pageY };
+        //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
+        let title = StrCast((this.props.Document.sourceDoc as Doc).title);
+        if (title.length > 15) {
+            title = title.substring(0, 15) + "...";
+        }
+        return (
+            // <Measure offset onResize={action((r: any) => { this._width = r.offset.width; this._height = r.offset.height; })}>
+            // {({ measureRef }) => (
+            <div className="rec-scroll">
+                <p>Recommendations for "{title}"</p>
+                {DocListCast(this.props.Document.data).map(doc => {
+                    return (
+                        <div className="content">
+                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+                                {this.DocumentIcon(doc)}
+                            </span>
+                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+                            </div>
+                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+                            </div>
+                        </div>
+                    );
+                })}
+
+            </div>
+            // );
+            // }
+
+            // </Measure>
+        );
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 1676ddcf9f4da6f9926e2e48eea4302ae9f2efe5 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Fri, 25 Oct 2019 16:21:45 -0400
Subject: images show up, react errors

---
 src/client/ClientRecommender.tsx                   | 78 ++++++++++++----------
 src/client/cognitive_services/CognitiveServices.ts |  5 +-
 src/client/views/RecommendationsBox.tsx            |  2 +-
 3 files changed, 47 insertions(+), 38 deletions(-)

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

diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx
index 97efedd89..ae2413d1d 100644
--- a/src/client/ClientRecommender.tsx
+++ b/src/client/ClientRecommender.tsx
@@ -1,4 +1,4 @@
-import { Doc } from "../new_fields/Doc";
+import { Doc, FieldResult } from "../new_fields/Doc";
 import { StrCast, Cast } from "../new_fields/Types";
 import { List } from "../new_fields/List";
 import { CognitiveServices } from "./cognitive_services/CognitiveServices";
@@ -147,47 +147,55 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     public async extractText(dataDoc: Doc, extDoc: Doc, internal: boolean = true, isMainDoc: boolean = false, image: boolean = false) {
-        let fielddata = Cast(dataDoc.data, RichTextField);
-        if (image && extDoc.generatedTags) {
-            console.log(Cast(extDoc.generatedTags, listSpec("string")));
+        let data: string = "";
+        let taglist: FieldResult<List<string>> = undefined;
+        if (image && extDoc.generatedTags) { // TODO: Automatically generate tags. Need to ask Sam about this.
+            taglist = Cast(extDoc.generatedTags, listSpec("string"));
+            taglist!.forEach(tag => {
+                data += tag + ", ";
+            });
+        }
+        else {
+            let fielddata = Cast(dataDoc.data, RichTextField);
+            fielddata ? data = fielddata[ToPlainText]() : data = "";
         }
-        let data: string;
-        fielddata ? data = fielddata[ToPlainText]() : data = "";
-        let converter = async (results: any, data: string) => {
+
+        let converter = async (results: any, data: string, isImage: boolean = false) => {
             let keyterms = new List<string>(); // raw keywords
             // let keyterms_counted = new List<string>(); // keywords, where each keyword is repeated. input to w2v
             let kp_string: string = ""; // keywords*frequency concatenated into a string. input into TF
             let highKP: string[] = [""]; // most frequent keyphrase
             let high = 0;
-            results.documents.forEach((doc: any) => {
-                let keyPhrases = doc.keyPhrases;
-                keyPhrases.map((kp: string) => {
-                    keyterms.push(kp);
-                    const frequency = this.countFrequencies(kp, data); // frequency of keyphrase in paragraph
-                    kp_string += kp + ", "; // ensures that if frequency is 0 for some reason kp is still added
-                    for (let i = 0; i < frequency - 1; i++) {
-                        kp_string += kp + ", "; // weights repeated keywords higher
-                    }
-                    // replaces highKP with new one
-                    if (frequency > high) {
-                        high = frequency;
-                        highKP = [kp];
-                    }
-                    // appends to current highKP phrase
-                    else if (frequency === high) {
-                        highKP.push(kp);
-                    }
-                    // let words = kp.split(" "); // separates phrase into words
-                    // words = this.removeStopWords(words); // removes stop words if they appear in phrases
-                    // words.forEach((word) => {
-                    //     for (let i = 0; i < frequency; i++) {
-                    //         keyterms_counted.push(word);
-                    //     }
-                    // });
+
+            if (isImage) {
+                kp_string = data;
+                if (taglist) {
+                    keyterms = taglist;
+                    highKP = [taglist[0]];
+                }
+            }
+            else { // text processing
+                results.documents.forEach((doc: any) => {
+                    let keyPhrases = doc.keyPhrases;
+                    keyPhrases.map((kp: string) => {
+                        keyterms.push(kp);
+                        const frequency = this.countFrequencies(kp, data); // frequency of keyphrase in paragraph
+                        kp_string += kp + ", "; // ensures that if frequency is 0 for some reason kp is still added
+                        for (let i = 0; i < frequency - 1; i++) {
+                            kp_string += kp + ", "; // weights repeated keywords higher
+                        }
+                        // replaces highKP with new one
+                        if (frequency > high) {
+                            high = frequency;
+                            highKP = [kp];
+                        }
+                        // appends to current highKP phrase
+                        else if (frequency === high) {
+                            highKP.push(kp);
+                        }
+                    });
                 });
-            });
-            // const kts_counted = new List<string>();
-            // keyterms_counted.forEach(kt => kts_counted.push(kt.toLowerCase()));
+            }
             if (kp_string.length > 2) kp_string = kp_string.substring(0, kp_string.length - 2);
             console.log("kp string: ", kp_string);
             let values = "";
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index b0e9138a4..d496b442e 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -9,6 +9,7 @@ import { UndoManager } from "../util/UndoManager";
 import requestPromise = require("request-promise");
 import { List } from "../../new_fields/List";
 import { ClientRecommender } from "../ClientRecommender";
+import { ImageBox } from "../views/nodes/ImageBox";
 
 type APIManager<D> = { converter: BodyConverter<D>, requester: RequestExecutor };
 type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise<string>;
@@ -288,12 +289,12 @@ export namespace CognitiveServices {
                 );
             }
 
-            export const analyzer = async (dataDoc: Doc, target: Doc, keys: string[], data: string, converter: TextConverter, isMainDoc: boolean = false, internal: boolean = true) => {
+            export const analyzer = async (dataDoc: Doc, target: Doc, keys: string[], data: string, converter: TextConverter, isMainDoc: boolean = false, isInternal: boolean = true) => {
                 let results = await ExecuteQuery(Service.Text, Manager, data);
                 console.log(results);
                 let { keyterms, external_recommendations, kp_string } = await converter(results, data);
                 target[keys[0]] = keyterms;
-                if (internal) {
+                if (isInternal) {
                     //await vectorize([data], dataDoc, isMainDoc);
                     await vectorize(kp_string, dataDoc, isMainDoc);
                 } else {
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 3938a8690..c50550bef 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -143,7 +143,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
     //     return y;
     // }
 
-    render() {
+    render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
         // if (!this._display) {
         //     return null;
         // }
-- 
cgit v1.2.3-70-g09d2


From 96dbd7d4fd1759ad1a5135ca94d46970ca31168f Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Wed, 30 Oct 2019 18:26:11 -0400
Subject: ui issues, max depth

---
 package.json                            |  5 ++-
 src/client/views/RecommendationsBox.tsx | 70 +++++++++++++++++++++------------
 2 files changed, 47 insertions(+), 28 deletions(-)

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

diff --git a/package.json b/package.json
index b3cf9102b..fde685eba 100644
--- a/package.json
+++ b/package.json
@@ -57,8 +57,9 @@
         "@hig/theme-context": "^2.1.3",
         "@hig/theme-data": "^2.3.3",
         "@tensorflow-models/universal-sentence-encoder": "^1.2.0",
-        "@tensorflow/tfjs": "^1.2.9",
-        "@tensorflow/tfjs-node": "^1.2.11",
+        "@tensorflow/tfjs": "^1.3.1",
+        "@tensorflow/tfjs-core": "^1.3.1",
+        "@tensorflow/tfjs-node": "^1.3.1",
         "@trendmicro/react-dropdown": "^1.3.0",
         "@types/adm-zip": "^0.4.32",
         "@types/animejs": "^2.0.2",
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index c50550bef..fd128bfca 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -1,6 +1,6 @@
 import { observer } from "mobx-react";
 import React = require("react");
-import { observable, action } from "mobx";
+import { observable, action, computed } from "mobx";
 import Measure from "react-measure";
 import "./RecommendationsBox.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
@@ -33,18 +33,17 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
 
     public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
 
-    static Instance: RecommendationsBox;
     // @observable private _display: boolean = false;
     @observable private _pageX: number = 0;
     @observable private _pageY: number = 0;
     @observable private _width: number = 0;
     @observable private _height: number = 0;
+    private _docViews: JSX.Element[] = [];
     // @observable private _documents: { preview: Doc, score: number }[] = [];
     private previewDocs: Doc[] = [];
 
     constructor(props: FieldViewProps) {
         super(props);
-        RecommendationsBox.Instance = this;
     }
 
     private DocumentIcon(doc: Doc) {
@@ -143,6 +142,45 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
     //     return y;
     // }
 
+    get createDocViews() {
+        return DocListCast(this.props.Document.data).map(doc => {
+            return (
+                <div className="content">
+                    <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+                        {this.DocumentIcon(doc)}
+                    </span>
+                    <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+                    <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+                        <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+                    </div>
+                    <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+                        <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+                    </div>
+                </div>
+            );
+        });
+    }
+
+    // componentDidMount() {
+    //     this._docViews = DocListCast(this.props.Document.data).map(doc => {
+    //         return (
+    //             <div className="content">
+    //                 <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+    //                     {this.DocumentIcon(doc)}
+    //                 </span>
+    //                 <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+    //                 <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+    //                 </div>
+    //                 <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+    //                 </div>
+    //             </div>
+    //         );
+    //     })
+
+    // }
+
     render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
         // if (!this._display) {
         //     return null;
@@ -154,32 +192,12 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
             title = title.substring(0, 15) + "...";
         }
         return (
-            // <Measure offset onResize={action((r: any) => { this._width = r.offset.width; this._height = r.offset.height; })}>
-            // {({ measureRef }) => (
             <div className="rec-scroll">
                 <p>Recommendations for "{title}"</p>
-                {DocListCast(this.props.Document.data).map(doc => {
-                    return (
-                        <div className="content">
-                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-                                {this.DocumentIcon(doc)}
-                            </span>
-                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-                            </div>
-                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-                            </div>
-                        </div>
-                    );
-                })}
-
+                {this.createDocViews}
             </div>
-            // );
-            // }
-
-            // </Measure>
         );
     }
+    // 
+    // 
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 3d5e2bf61e04fa700eccac10d19ea6dde436f6bd Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Thu, 31 Oct 2019 11:57:08 -0400
Subject: fixed depth problem

---
 src/client/ClientRecommender.tsx        | 63 ++++++++++++++++++++++++++------
 src/client/views/RecommendationsBox.tsx | 64 ++++++++++++++++-----------------
 src/client/views/nodes/ImageBox.tsx     |  1 +
 3 files changed, 83 insertions(+), 45 deletions(-)

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

diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx
index 90dd240b6..364ec0fe0 100644
--- a/src/client/ClientRecommender.tsx
+++ b/src/client/ClientRecommender.tsx
@@ -1,7 +1,7 @@
 import { Doc, FieldResult } from "../new_fields/Doc";
 import { StrCast, Cast } from "../new_fields/Types";
 import { List } from "../new_fields/List";
-import { CognitiveServices } from "./cognitive_services/CognitiveServices";
+import { CognitiveServices, Confidence, Tag, Service } from "./cognitive_services/CognitiveServices";
 import React = require("react");
 import { observer } from "mobx-react";
 import { observable, action, computed, reaction } from "mobx";
@@ -14,6 +14,8 @@ import { RichTextField } from "../new_fields/RichTextField";
 import { ToPlainText } from "../new_fields/FieldSymbols";
 import { listSpec } from "../new_fields/Schema";
 import { Identified } from "./Network";
+import { ComputedField } from "../new_fields/ScriptField";
+import { ImageField } from "../new_fields/URLField";
 
 export interface RecommenderProps {
     title: string;
@@ -31,9 +33,13 @@ export interface RecommenderDocument {
     score: number;
 }
 
+const fieldkey = "data";
+
 @observer
 export class ClientRecommender extends React.Component<RecommenderProps> {
 
+
+
     static Instance: ClientRecommender;
     private mainDoc?: RecommenderDocument;
     private docVectors: Set<RecommenderDocument> = new Set();
@@ -45,10 +51,6 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
         super(props);
         if (!ClientRecommender.Instance) ClientRecommender.Instance = this;
         ClientRecommender.Instance.docVectors = new Set();
-        const parameters: any = {};
-        Identified.PostToServer("/IBMAnalysis", parameters).then(response => {
-            console.log("ANALYSIS RESULTS! ", response);
-        });
         //ClientRecommender.Instance.corr_matrix = [[0, 0], [0, 0]];
     }
 
@@ -97,6 +99,10 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     public computeSimilarities(distance_metric: string) {
+        const parameters: any = {};
+        Identified.PostToServer("/IBMAnalysis", parameters).then(response => {
+            console.log("ANALYSIS RESULTS! ", response);
+        });
         ClientRecommender.Instance.docVectors.forEach((doc: RecommenderDocument) => {
             if (ClientRecommender.Instance.mainDoc) {
                 const distance = ClientRecommender.Instance.distance(ClientRecommender.Instance.mainDoc.vectorDoc, doc.vectorDoc, distance_metric);
@@ -147,6 +153,39 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
         }
     }
 
+    /***
+     * Generates tags for an image using Cognitive Services
+     */
+
+    generateMetadata = async (dataDoc: Doc, extDoc: Doc, 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(" ", "_");
+                tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`);
+            });
+            extDoc.generatedTags = tagsList;
+            tagDoc.title = "Generated Tags Doc";
+            tagDoc.confidence = threshold;
+            return tagDoc;
+        };
+        const url = this.url(dataDoc);
+        if (url) {
+            return CognitiveServices.Image.Appliers.ProcessImage(extDoc, ["generatedTagsDoc"], url, Service.ComputerVision, converter);
+        }
+    }
+
+    /***
+     * Gets URL of image
+     */
+
+    private url(dataDoc: Doc) {
+        let data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField);
+        return data ? data.url.href : undefined;
+    }
+
     /***
      * Uses Cognitive Services to extract keywords from a document
      */
@@ -154,17 +193,19 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
     public async extractText(dataDoc: Doc, extDoc: Doc, internal: boolean = true, isMainDoc: boolean = false, image: boolean = false) {
         let data: string = "";
         let taglist: FieldResult<List<string>> = undefined;
-        if (image && extDoc.generatedTags) { // TODO: Automatically generate tags. Need to ask Sam about this.
-            taglist = Cast(extDoc.generatedTags, listSpec("string"));
-            taglist!.forEach(tag => {
-                data += tag + ", ";
-            });
+        if (image) {
+            if (!extDoc.generatedTags) await this.generateMetadata(dataDoc, extDoc);  // TODO: Automatically generate tags. Need to ask Sam about this.
+            if (extDoc.generatedTags) {
+                taglist = Cast(extDoc.generatedTags, listSpec("string"));
+                taglist!.forEach(tag => {
+                    data += tag + ", ";
+                });
+            }
         }
         else {
             let fielddata = Cast(dataDoc.data, RichTextField);
             fielddata ? data = fielddata[ToPlainText]() : data = "";
         }
-
         let converter = async (results: any, data: string, isImage: boolean = false) => {
             let keyterms = new List<string>(); // raw keywords
             // let keyterms_counted = new List<string>(); // keywords, where each keyword is repeated. input to w2v
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index fd128bfca..0e3cfd729 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -1,6 +1,6 @@
 import { observer } from "mobx-react";
 import React = require("react");
-import { observable, action, computed } from "mobx";
+import { observable, action, computed, runInAction } from "mobx";
 import Measure from "react-measure";
 import "./RecommendationsBox.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
@@ -38,7 +38,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
     @observable private _pageY: number = 0;
     @observable private _width: number = 0;
     @observable private _height: number = 0;
-    private _docViews: JSX.Element[] = [];
+    @observable.shallow private _docViews: JSX.Element[] = [];
     // @observable private _documents: { preview: Doc, score: number }[] = [];
     private previewDocs: Doc[] = [];
 
@@ -46,20 +46,13 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
         super(props);
     }
 
+    @action
     private DocumentIcon(doc: Doc) {
         let layoutresult = StrCast(doc.type);
         let renderDoc = doc;
         //let box: number[] = [];
         if (layoutresult.indexOf(DocumentType.COL) !== -1) {
             renderDoc = Doc.MakeDelegate(renderDoc);
-            let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => {
-                var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
-                let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
-                return {
-                    x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
-                    r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
-                };
-            }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
         }
         let returnXDimension = () => 150;
         let returnYDimension = () => 150;
@@ -142,27 +135,8 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
     //     return y;
     // }
 
-    get createDocViews() {
-        return DocListCast(this.props.Document.data).map(doc => {
-            return (
-                <div className="content">
-                    <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-                        {this.DocumentIcon(doc)}
-                    </span>
-                    <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-                    <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-                        <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-                    </div>
-                    <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-                        <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-                    </div>
-                </div>
-            );
-        });
-    }
-
-    // componentDidMount() {
-    //     this._docViews = DocListCast(this.props.Document.data).map(doc => {
+    // get createDocViews() {
+    //     return DocListCast(this.props.Document.data).map(doc => {
     //         return (
     //             <div className="content">
     //                 <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
@@ -177,10 +151,32 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
     //                 </div>
     //             </div>
     //         );
-    //     })
-
+    //     });
     // }
 
+    componentDidMount() { //TODO: invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set
+        runInAction(() => {
+            if (this._docViews.length === 0) {
+                this._docViews = DocListCast(this.props.Document.data).map(doc => {
+                    return (
+                        <div className="content">
+                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+                                {this.DocumentIcon(doc)}
+                            </span>
+                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+                            </div>
+                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+                            </div>
+                        </div>
+                    );
+                });
+            }
+        });
+    }
+
     render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
         // if (!this._display) {
         //     return null;
@@ -194,7 +190,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
         return (
             <div className="rec-scroll">
                 <p>Recommendations for "{title}"</p>
-                {this.createDocViews}
+                {this._docViews}
             </div>
         );
     }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 7816c0fe8..1bf2724c3 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -248,6 +248,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
     onDotDown(index: number) {
         this.Document.curPage = index;
     }
+
     @computed private get url() {
         let data = Cast(Doc.GetProto(this.props.Document)[this.props.fieldKey], ImageField);
         return data ? data.url.href : undefined;
-- 
cgit v1.2.3-70-g09d2

