aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/ClientRecommender.tsx83
-rw-r--r--src/client/cognitive_services/CognitiveServices.ts24
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/Recommendations.tsx21
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx21
-rw-r--r--src/client/views/nodes/DocumentView.tsx26
-rw-r--r--src/client/views/nodes/ImageBox.tsx16
7 files changed, 104 insertions, 88 deletions
diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx
index 63f85c737..a6d1a32b3 100644
--- a/src/client/ClientRecommender.tsx
+++ b/src/client/ClientRecommender.tsx
@@ -1,5 +1,5 @@
import { Doc } from "../new_fields/Doc";
-import { StrCast } from "../new_fields/Types";
+import { StrCast, Cast } from "../new_fields/Types";
import { List } from "../new_fields/List";
import { CognitiveServices } from "./cognitive_services/CognitiveServices";
import React = require("react");
@@ -8,30 +8,42 @@ import { observable, action, computed, reaction } from "mobx";
var assert = require('assert');
import "./ClientRecommender.scss";
import { JSXElement } from "babel-types";
+import { ToPlainText, RichTextField } from "../new_fields/RichTextField";
export interface RecommenderProps {
title: string;
}
+export interface RecommenderDocument {
+ actualDoc: Doc;
+ vectorDoc: number[];
+ score: number;
+}
+
@observer
export class ClientRecommender extends React.Component<RecommenderProps> {
static Instance: ClientRecommender;
- private docVectors: Set<number[]>;
+ private mainDoc?: RecommenderDocument;
+ private docVectors: Set<RecommenderDocument> = new Set();
@observable private corr_matrix = [[0, 0], [0, 0]];
constructor(props: RecommenderProps) {
//console.log("creating client recommender...");
super(props);
if (!ClientRecommender.Instance) ClientRecommender.Instance = this;
- this.docVectors = new Set<number[]>();
- //this.corr_matrix = [[0, 0], [0, 0]];
+ ClientRecommender.Instance.docVectors = new Set();
+ //ClientRecommender.Instance.corr_matrix = [[0, 0], [0, 0]];
}
@action
public reset_docs() {
- this.docVectors = new Set();
- this.corr_matrix = [[0, 0], [0, 0]];
+ ClientRecommender.Instance.docVectors = new Set();
+ ClientRecommender.Instance.corr_matrix = [[0, 0], [0, 0]];
+ }
+
+ public deleteDocs() {
+ console.log("deleting previews...");
}
/***
@@ -67,11 +79,24 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
}
}
+ public computeSimilarities() {
+ ClientRecommender.Instance.docVectors.forEach((doc: RecommenderDocument) => {
+ if (ClientRecommender.Instance.mainDoc) {
+ const distance = ClientRecommender.Instance.distance(ClientRecommender.Instance.mainDoc.vectorDoc, doc.vectorDoc, "euclidian");
+ doc.score = distance;
+ }
+ }
+ );
+ let doclist = Array.from(ClientRecommender.Instance.docVectors);
+ doclist.sort((a: RecommenderDocument, b: RecommenderDocument) => a.score - b.score);
+ return doclist;
+ }
+
/***
* Computes the mean of a set of vectors
*/
- public mean(paragraph: Set<number[]>) {
+ public mean(paragraph: Set<number[]>, dataDoc: Doc, mainDoc: boolean) {
const n = 200;
const num_words = paragraph.size;
let meanVector = new Array<number>(n).fill(0); // mean vector
@@ -82,14 +107,16 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
}
});
meanVector = meanVector.map(x => x / num_words);
- this.addToDocSet(meanVector);
+ const internalDoc: RecommenderDocument = { actualDoc: dataDoc, vectorDoc: meanVector, score: 0 };
+ if (mainDoc) ClientRecommender.Instance.mainDoc = internalDoc;
+ ClientRecommender.Instance.addToDocSet(internalDoc);
}
return meanVector;
}
- private addToDocSet(vector: number[]) {
- if (this.docVectors) {
- this.docVectors.add(vector);
+ private addToDocSet(internalDoc: RecommenderDocument) {
+ if (ClientRecommender.Instance.docVectors) {
+ ClientRecommender.Instance.docVectors.add(internalDoc);
}
}
@@ -97,9 +124,11 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
* Uses Cognitive Services to extract keywords from a document
*/
- public async extractText(dataDoc: Doc, extDoc: Doc) {
- let data = StrCast(dataDoc.title);
- //console.log(data);
+ public async extractText(dataDoc: Doc, extDoc: Doc, mainDoc: boolean = false) {
+ let fielddata = Cast(dataDoc.data, RichTextField);
+ let data: string;
+ fielddata ? data = fielddata[ToPlainText]() : data = "";
+ console.log(data);
let converter = (results: any) => {
let keyterms = new List<string>();
results.documents.forEach((doc: any) => {
@@ -108,7 +137,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
});
return keyterms;
};
- await CognitiveServices.Text.Appliers.analyzer(extDoc, ["key words"], data, converter);
+ await CognitiveServices.Text.Appliers.analyzer(dataDoc, extDoc, ["key words"], data, converter, mainDoc);
}
/***
@@ -116,7 +145,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
*/
@action
- public createDistanceMatrix(documents: Set<number[]> = this.docVectors) {
+ public createDistanceMatrix(documents: Set<RecommenderDocument> = ClientRecommender.Instance.docVectors) {
const documents_list = Array.from(documents);
const n = documents_list.length;
var matrix = new Array<number>(n).fill(0).map(() => new Array<number>(n).fill(0));
@@ -124,22 +153,22 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
var doc1 = documents_list[i];
for (let j = 0; j < n; j++) {
var doc2 = documents_list[j];
- matrix[i][j] = this.distance(doc1, doc2, "euclidian");
+ matrix[i][j] = ClientRecommender.Instance.distance(doc1.vectorDoc, doc2.vectorDoc, "euclidian");
}
}
- this.corr_matrix = matrix;
+ ClientRecommender.Instance.corr_matrix = matrix;
return matrix;
}
@computed
private get generateRows() {
- const n = this.corr_matrix.length;
+ const n = ClientRecommender.Instance.corr_matrix.length;
let rows: JSX.Element[] = [];
for (let i = 0; i < n; i++) {
let children: JSX.Element[] = [];
for (let j = 0; j < n; j++) {
- //let cell = React.createElement("td", this.corr_matrix[i][j]);
- let cell = <td>{this.corr_matrix[i][j].toFixed(4)}</td>;
+ //let cell = React.createElement("td", ClientRecommender.Instance.corr_matrix[i][j]);
+ let cell = <td>{ClientRecommender.Instance.corr_matrix[i][j].toFixed(4)}</td>;
children.push(cell);
}
//let row = React.createElement("tr", { children: children, key: i });
@@ -151,22 +180,22 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
render() {
return (<div className="wrapper">
- <h3 >{this.props.title ? this.props.title : "hello"}</h3>
+ <h3 >{ClientRecommender.Instance.props.title ? ClientRecommender.Instance.props.title : "hello"}</h3>
{/* <table className="space" >
<tbody>
<tr key="1">
- <td key="1">{this.corr_matrix[0][0].toFixed(4)}</td>
- <td key="2">{this.corr_matrix[0][1].toFixed(4)}</td>
+ <td key="1">{ClientRecommender.Instance.corr_matrix[0][0].toFixed(4)}</td>
+ <td key="2">{ClientRecommender.Instance.corr_matrix[0][1].toFixed(4)}</td>
</tr>
<tr key="2">
- <td key="1">{this.corr_matrix[1][0].toFixed(4)}</td>
- <td key="2">{this.corr_matrix[1][1].toFixed(4)}</td>
+ <td key="1">{ClientRecommender.Instance.corr_matrix[1][0].toFixed(4)}</td>
+ <td key="2">{ClientRecommender.Instance.corr_matrix[1][1].toFixed(4)}</td>
</tr>
</tbody>
</table> */}
<table className="space">
<tbody>
- {this.generateRows}
+ {ClientRecommender.Instance.generateRows}
</tbody>
</table>
</div>);
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index 75d0760ed..874ee433d 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -263,29 +263,35 @@ export namespace CognitiveServices {
export namespace Appliers {
- export async function vectorize(keyterms: any) {
+ export async function vectorize(keyterms: any, dataDoc: Doc, mainDoc: boolean = false) {
console.log("vectorizing...");
//keyterms = ["father", "king"];
let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true };
await requestPromise.post(args).then(async (wordvecs) => {
- var vectorValues = new Set<number[]>();
- wordvecs.forEach((wordvec: any) => {
- //console.log(wordvec.word);
- vectorValues.add(wordvec.values as number[]);
- });
- ClientRecommender.Instance.mean(vectorValues);
+ if (wordvecs.length > 0) {
+ console.log("successful vectorization!");
+ var vectorValues = new Set<number[]>();
+ wordvecs.forEach((wordvec: any) => {
+ //console.log(wordvec.word);
+ vectorValues.add(wordvec.values as number[]);
+ });
+ ClientRecommender.Instance.mean(vectorValues, dataDoc, mainDoc);
+ } // adds document to internal doc set
+ else {
+ console.log("unsuccessful :( word(s) not in vocabulary");
+ }
//console.log(vectorValues.size);
});
}
- export const analyzer = async (target: Doc, keys: string[], data: string, converter: Converter) => {
+ export const analyzer = async (dataDoc: Doc, target: Doc, keys: string[], data: string, converter: Converter, mainDoc: boolean = false) => {
let results = await ExecuteQuery(Service.Text, Manager, data);
console.log(results);
let keyterms = converter(results);
//target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Key Word Analysis");
target[keys[0]] = keyterms;
console.log("analyzed!");
- await vectorize(keyterms);
+ await vectorize(keyterms, dataDoc, mainDoc);
};
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 57eb30439..3a5795077 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -204,6 +204,7 @@ export class MainView extends React.Component {
const targets = document.elementsFromPoint(e.x, e.y);
if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) {
ContextMenu.Instance.closeMenu();
+ Recommendations.Instance.closeMenu();
}
});
diff --git a/src/client/views/Recommendations.tsx b/src/client/views/Recommendations.tsx
index 8569996b3..cf1974c69 100644
--- a/src/client/views/Recommendations.tsx
+++ b/src/client/views/Recommendations.tsx
@@ -10,8 +10,10 @@ import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../
import { Transform } from "../util/Transform";
import { ObjectField } from "../../new_fields/ObjectField";
import { DocumentView } from "./nodes/DocumentView";
-import { DocumentType } from "../documents/Documents";
-
+import { DocumentType } from '../documents/DocumentTypes';
+import { ClientRecommender } from "../ClientRecommender";
+import { DocServer } from "../DocServer";
+import { Id } from "../../new_fields/FieldSymbols";
export interface RecProps {
documents: { preview: Doc, similarity: number }[];
@@ -28,6 +30,7 @@ export class Recommendations extends React.Component<{}> {
@observable private _width: number = 0;
@observable private _height: number = 0;
@observable private _documents: { preview: Doc, score: number }[] = [];
+ private previewDocs: Doc[] = [];
constructor(props: {}) {
super(props);
@@ -52,7 +55,8 @@ export class Recommendations extends React.Component<{}> {
let returnXDimension = () => 50;
let returnYDimension = () => 50;
let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
- let newRenderDoc = Doc.MakeDelegate(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
+ //let scale = () => 1;
+ //let newRenderDoc = Doc.MakeDelegate(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
const docview = <div>
{/* onPointerDown={action(() => {
this._useIcons = !this._useIcons;
@@ -62,7 +66,7 @@ export class Recommendations extends React.Component<{}> {
onPointerLeave={action(() => this._displayDim = 50)} > */}
<DocumentView
fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
- Document={doc}
+ Document={renderDoc}
addDocument={returnFalse}
removeDocument={returnFalse}
ScreenToLocalTransform={Transform.Identity}
@@ -82,9 +86,10 @@ export class Recommendations extends React.Component<{}> {
ContentScaling={scale}
/>
</div>;
- const data = renderDoc.data;
- if (data instanceof ObjectField) newRenderDoc.data = ObjectField.MakeCopy(data);
- newRenderDoc.preview = true;
+ // const data = renderDoc.data;
+ // if (data instanceof ObjectField) newRenderDoc.data = ObjectField.MakeCopy(data);
+ // newRenderDoc.preview = true;
+ // this.previewDocs.push(newRenderDoc);
return docview;
}
@@ -92,6 +97,8 @@ export class Recommendations extends React.Component<{}> {
@action
closeMenu = () => {
this._display = false;
+ this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
+ this.previewDocs = [];
}
@action
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2d4775070..3cef93383 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -857,27 +857,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
input.click();
}
});
- ContextMenu.Instance.addItem({
- description: "Recommender System",
- event: async () => {
- // if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" });
- let activedocs = this.getActiveDocuments();
- let allDocs = await SearchUtil.GetAllDocs();
- allDocs.forEach(doc => console.log(doc.title));
- // clears internal representation of documents as vectors
- ClientRecommender.Instance.reset_docs();
- await Promise.all(allDocs.map((doc: Doc) => {
- console.log(StrCast(doc.title));
- if (doc.type === DocumentType.IMG) {
- console.log(doc.title);
- const extdoc = doc.data_ext as Doc;
- return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc);
- }
- }));
- console.log(ClientRecommender.Instance.createDistanceMatrix());
- },
- icon: "brain"
- });
layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: this.fitToContainer, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" });
layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
layoutItems.push({
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2a6e91272..f708a7a3a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -648,21 +648,31 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" });
let documents: Doc[] = [];
let allDocs = await SearchUtil.GetAllDocs();
- allDocs.forEach(doc => console.log(doc.title));
+ //allDocs.forEach(doc => console.log(doc.title));
// clears internal representation of documents as vectors
ClientRecommender.Instance.reset_docs();
await Promise.all(allDocs.map((doc: Doc) => {
- if (doc.type === DocumentType.IMG) {
- console.log(StrCast(doc.title));
- documents.push(doc);
- const extdoc = doc.data_ext as Doc;
- return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc);
+ let mainDoc: boolean = false;
+ const dataDoc = Doc.GetDataDoc(doc);
+ if (doc.type === DocumentType.TEXT) {
+ if (dataDoc === Doc.GetDataDoc(this.props.Document)) {
+ mainDoc = true;
+ console.log(StrCast(doc.title));
+ }
+ if (!documents.includes(dataDoc)) {
+ documents.push(dataDoc);
+ const extdoc = doc.data_ext as Doc;
+ return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, mainDoc);
+ }
}
}));
console.log(ClientRecommender.Instance.createDistanceMatrix());
+ const doclist = ClientRecommender.Instance.computeSimilarities();
let recDocs: { preview: Doc, score: number }[] = [];
- for (let i = 0; i < documents.length; i++) {
- recDocs.push({ preview: documents[i], score: i });
+ // tslint:disable-next-line: prefer-for-of
+ for (let i = 0; i < doclist.length; i++) {
+ console.log(doclist[i].score);
+ recDocs.push({ preview: doclist[i].actualDoc, score: doclist[i].score });
}
Recommendations.Instance.addDocuments(recDocs);
Recommendations.Instance.displayRecommendations(e.pageX + 100, e.pageY);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ec35465eb..d94e92847 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -240,22 +240,6 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
}
}
- extractText = async () => {
- //let activedocs = this.getActiveDocuments();
- let allDocs = await SearchUtil.GetAllDocs();
- allDocs.forEach(doc => console.log(doc.title));
- // clears internal representation of documents as vectors
- ClientRecommender.Instance.reset_docs();
- await Promise.all(allDocs.map((doc: Doc) => {
- //console.log(StrCast(doc.title));
- if (doc.type === DocumentType.IMG) {
- const extdoc = doc.data_ext as Doc;
- return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc);
- }
- }));
- console.log(ClientRecommender.Instance.createDistanceMatrix());
- }
-
generateMetadata = (threshold: Confidence = Confidence.Excellent) => {
let converter = (results: any) => {
let tagDoc = new Doc;