feat: track five most recent project models (#395)

* feat: track most recent 5 models for project

* refactor: set recent model records count in constants

* style: remove empty line whitespaces

* style: remove eol whitespaces
This commit is contained in:
stew-ro 2020-07-09 11:59:08 -07:00 коммит произвёл GitHub
Родитель abc63767e9
Коммит 05850603d5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 63 добавлений и 26 удалений

Просмотреть файл

@ -32,7 +32,7 @@ export const constants = {
convertedImageFormat: "image/jpeg",
convertedImageQuality: 0.7,
convertedThumbnailQuality: 0.2,
recentModelRecordsCount: 5,
apiModelsPath: `/formrecognizer/${apiVersion}/custom/models`,
pdfjsWorkerSrc(version: string) {

Просмотреть файл

@ -147,6 +147,7 @@ export default class MockFactory {
apiUriBase: "localhost",
folderPath: "",
trainRecord: null,
recentModelRecords: [],
predictModelId: "",
};
}

Просмотреть файл

@ -94,6 +94,7 @@ export interface IProject {
apiKey?: string | ISecureString;
folderPath: string;
trainRecord: ITrainRecordProps;
recentModelRecords: IRecentModel[];
predictModelId: string;
}
@ -281,6 +282,18 @@ export interface IFieldInfo {
fields: IField[];
}
export interface IRecentModel {
readonly composedTrainResults?: object;
readonly accuracies?: object;
readonly averageAccuracy?: number;
readonly modelInfo: {
readonly isComposed: boolean;
readonly modelId: string;
readonly createdDateTime: string;
readonly modelName: string;
};
}
/**
* Enum of supported error codes
*/

Просмотреть файл

@ -5,7 +5,7 @@ import React from "react";
import {connect} from "react-redux";
import url from "url";
import { RouteComponentProps } from "react-router-dom";
import { IProject, IConnection, IAppSettings, IApplicationState, AppError, ErrorCode } from "../../../../models/applicationState";
import { IProject, IConnection, IAppSettings, IApplicationState, AppError, ErrorCode, IRecentModel } from "../../../../models/applicationState";
import { constants } from "../../../../common/constants";
import ServiceHelper from "../../../../services/serviceHelper";
import { IColumn,
@ -341,10 +341,8 @@ export default class ModelComposePage extends React.Component<IModelComposePageP
const composedModels = this.reloadComposedModel(this.state.composedModelList);
let composedModelIds = [];
let predictModelFlag = false;
if (this.state.composeModelId.length !== 0) {
composedModelIds = this.getComposedIds();
predictModelFlag = true;
if (composedModelIds.indexOf(this.state.composeModelId[0]) === -1) {
const idURL = constants.apiModelsPath + "/" + this.state.composeModelId[0];
composedModels.push(await this.getComposeModelByURl(idURL));
@ -359,10 +357,6 @@ export default class ModelComposePage extends React.Component<IModelComposePageP
models = models.filter((m) => composedModelIds.indexOf(m.modelId) === -1);
this.allModels = composedModels.concat(models);
if (predictModelFlag) {
const updatedProject = this.buildUpdatedProject(this.state.composeModelId[0]);
await this.props.actions.saveProject(updatedProject, false, false);
}
this.setState({
modelList: this.allModels,
nextLink: link,
@ -377,10 +371,27 @@ export default class ModelComposePage extends React.Component<IModelComposePageP
}
}
private buildUpdatedProject = (modelId: string): IProject => {
private buildUpdatedProject = (composedModel: object): IProject => {
const newTrainRecord = {
modelInfo: {
createdDateTime: composedModel["modelInfo"]["createdDateTime"],
modelId: composedModel["modelInfo"]["modelId"],
modelName: composedModel["modelInfo"]["modelName"],
isComposed: true,
},
composedTrainResults: composedModel["composedTrainResults"]
} as IRecentModel;
const recentModelRecords: IRecentModel[] = this.props.project.recentModelRecords ?
[...this.props.project.recentModelRecords] : [];
recentModelRecords.unshift(newTrainRecord);
if (recentModelRecords.length > constants.recentModelRecordsCount) {
recentModelRecords.pop();
}
return {
...this.props.project,
predictModelId: modelId,
recentModelRecords,
predictModelId: newTrainRecord.modelInfo.modelId,
};
}
@ -399,7 +410,7 @@ export default class ModelComposePage extends React.Component<IModelComposePageP
private getComposeModelByURl = async (idURL) => {
const composedRes = await this.getResponse(idURL);
const composedModel: IModel = composedRes.data.modelInfo;
composedModel.iconName = "combine";
composedModel.iconName = "Combine";
composedModel.key = composedModel.modelId;
return composedModel;
}
@ -632,18 +643,23 @@ export default class ModelComposePage extends React.Component<IModelComposePageP
modelIds: idList,
modelName: name,
};
const link = constants.apiModelsPath + "/compose";
const composeRes = await this.post(link, payload);
await this.waitUntilModelIsReady(composeRes["headers"]["location"]);
const composedModelId = this.getComposeModelId(composeRes);
const composedModel = await this.waitUntilModelIsReady(composeRes["headers"]["location"]);
const updatedProject = this.buildUpdatedProject(composedModel);
await this.props.actions.saveProject(updatedProject, false, false);
const newCols = this.state.columns;
newCols.forEach((ncol) => {
ncol.isSorted = false;
ncol.isSortedDescending = true;
});
this.setState({
isComposing: false,
composeModelId: [composedModelId],
composeModelId: [composedModel["modelInfo"]["modelId"]],
columns: newCols,
});
} catch (error) {
@ -655,13 +671,6 @@ export default class ModelComposePage extends React.Component<IModelComposePageP
}, 5000);
}
/** get the model Id of new composed model */
private getComposeModelId = (composeRes: any): string => {
const location = composeRes["headers"]["location"];
const splitGroup = location.split("/");
return splitGroup[splitGroup.length - 1];
}
private async post(link, payload): Promise<any> {
const baseURL = url.resolve(
this.props.project.apiUriBase,

Просмотреть файл

@ -10,7 +10,7 @@ import IProjectActions, * as projectActions from "../../../../redux/actions/proj
import IApplicationActions, * as applicationActions from "../../../../redux/actions/applicationActions";
import IAppTitleActions, * as appTitleActions from "../../../../redux/actions/appTitleActions";
import {
IApplicationState, IConnection, IProject, IAppSettings, FieldType,
IApplicationState, IConnection, IProject, IAppSettings, FieldType, IRecentModel,
} from "../../../../models/applicationState";
import TrainChart from "./trainChart";
import TrainPanel from "./trainPanel";
@ -327,8 +327,16 @@ export default class TrainPage extends React.Component<ITrainPageProps, ITrainPa
}
private buildUpdatedProject = (newTrainRecord: ITrainRecordProps): IProject => {
const recentModelRecords: IRecentModel[] = this.props.project.recentModelRecords ?
[...this.props.project.recentModelRecords] : [];
recentModelRecords.unshift({...newTrainRecord, isComposed: false} as IRecentModel);
if (recentModelRecords.length > constants.recentModelRecordsCount) {
recentModelRecords.pop();
}
return {
...this.props.project,
recentModelRecords,
trainRecord: newTrainRecord,
predictModelId: newTrainRecord.modelInfo.modelId,
};
@ -356,6 +364,7 @@ export default class TrainPage extends React.Component<ITrainPageProps, ITrainPa
modelId: response["modelInfo"]["modelId"],
createdDateTime: response["modelInfo"]["createdDateTime"],
modelName: response["modelInfo"]["modelName"],
isComposed: false,
},
averageAccuracy: response["trainResult"]["averageModelAccuracy"],
accuracies: this.buildAccuracies(response["trainResult"]["fields"]),

Просмотреть файл

@ -8,6 +8,7 @@ export interface ITrainRecordProps {
accuracies?: object;
averageAccuracy: number;
modelInfo: {
isComposed?: boolean;
modelId: string;
createdDateTime: string;
modelName: string;
@ -26,10 +27,14 @@ export default class TrainRecord extends React.Component<ITrainRecordProps, ITra
<p>
{this.props.modelInfo.modelId}
</p>
<h6> Model Name: </h6>
<p>
{this.props.modelInfo.modelName}
</p>
{this.props.modelInfo.modelName &&
[
<h6> Model Name: </h6>,
<p>
{this.props.modelInfo.modelName}
</p>
]
}
<h6> Created date and time: </h6>
<p>
{new Date(this.props.modelInfo.createdDateTime).toLocaleString()}