progress
This commit is contained in:
parent
e005a42254
commit
e155b4a2a1
26 changed files with 468 additions and 36 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"Ведите",
|
||||
"навык",
|
||||
"Навыки",
|
||||
"skils",
|
||||
"typedataset"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -38,8 +38,9 @@ git clone https://gitlab.com/robossembler/webservice
|
|||
Для работы Генератора Датасетов нужно задать следующие переменные в окружении `bash`
|
||||
|
||||
```bash
|
||||
export PYTHON_BLENDER="путь_к_директории_с_файлами_из_rcg_pipeline"
|
||||
export PYTHON_BLENDER_PROC="путь_к_генератору_датасетов_renderBOPdataset.py"
|
||||
export PYTHON_BLENDER="/путь_к_директории_с_файлами_из/rcg_pipeline"
|
||||
export PYTHON_BLENDER_PROC="/путь_к_генератору_датасетов_/renderBOPdataset.py"
|
||||
export PYTHON_EDUCATION="absolute_path/webp/education.py"
|
||||
```
|
||||
|
||||
## Запуск сервера
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
import { BehaviorTreesPresentation } from "../../features/behavior_trees/behavior_trees";
|
||||
import { DatasetsPresentation } from "../../features/datasets/datasets_presentation";
|
||||
import { WeightsPresentation } from "../../features/weights/weights_presentation";
|
||||
import { ProjectsPresentation } from "../../features/projects/projects_presentation";
|
||||
import { extensions } from "../extensions/extensions";
|
||||
import { Routes } from "../interfaces/router";
|
||||
|
||||
extensions();
|
||||
|
||||
export const httpRoutes: Routes[] = [new ProjectsPresentation(), new DatasetsPresentation(), new BehaviorTreesPresentation()].map((el) => el.call());
|
||||
export const httpRoutes: Routes[] = [
|
||||
new ProjectsPresentation(),
|
||||
new DatasetsPresentation(),
|
||||
new BehaviorTreesPresentation(),
|
||||
new WeightsPresentation(),
|
||||
].map((el) => el.call());
|
||||
|
|
|
@ -9,11 +9,15 @@ import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_da
|
|||
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||
import { DatasetValidationModel, ProcessStatus } from "../models/dataset_validation_model";
|
||||
|
||||
export class ProcessWatcherAndDatabaseUpdateService extends TypedEvent<Result<ExecError | SpawnError, ExecutorResult>> {
|
||||
export class ProcessWatcherAndDatabaseUpdateService<A> extends TypedEvent<
|
||||
Result<ExecError | SpawnError, ExecutorResult>
|
||||
> {
|
||||
databaseId: ObjectId;
|
||||
constructor(databaseId: ObjectId) {
|
||||
model: A;
|
||||
constructor(databaseId: ObjectId, model: A) {
|
||||
super();
|
||||
this.databaseId = databaseId;
|
||||
this.model = model;
|
||||
this.on((event) => this.lister(event));
|
||||
}
|
||||
|
||||
|
@ -21,7 +25,9 @@ export class ProcessWatcherAndDatabaseUpdateService extends TypedEvent<Result<Ex
|
|||
event.fold(
|
||||
async (success) => {
|
||||
if (success.event == EXEC_EVENT.END) {
|
||||
const dbModel = await DatasetDBModel.findById(this.databaseId);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const dbModel = await this.model.findById(this.databaseId);
|
||||
if (dbModel !== null) {
|
||||
dbModel.local_path;
|
||||
dbModel.processStatus = ProcessStatus.END;
|
||||
|
@ -31,7 +37,9 @@ export class ProcessWatcherAndDatabaseUpdateService extends TypedEvent<Result<Ex
|
|||
}
|
||||
},
|
||||
async (error) => {
|
||||
const dbModel = await DatasetDBModel.findById(this.databaseId);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const dbModel = await this.model.findById(this.databaseId);
|
||||
if (dbModel !== null) {
|
||||
dbModel.processStatus = ProcessStatus.ERROR;
|
||||
dbModel.processLogs = error.message;
|
||||
|
|
|
@ -14,14 +14,13 @@ export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
|
|||
return (await new ReadByIdDataBaseModelUseCase<IDatasetModel>(DatasetDBModel).call(id)).map(async (model) => {
|
||||
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
|
||||
await DatasetDBModel.findById(id).updateOne({ processStatus: "RUN" });
|
||||
console.log(`blenderproc run $PYTHON_BLENDER_PROC --cfg '${JSON.stringify(model)}'`);
|
||||
return new ExecProcessUseCase().call(
|
||||
`${model.project.rootDir}/`,
|
||||
`blenderproc run $PYTHON_BLENDER_PROC --cfg '${JSON.stringify(model)}'`,
|
||||
id,
|
||||
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId)
|
||||
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId, DatasetDBModel)
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Mongoose, Schema, model } from "mongoose";
|
||||
import { Schema, model } from "mongoose";
|
||||
import { IDatasetModel } from "./dataset_validation_model";
|
||||
import { projectSchema } from "../../_projects/models/project_database_model";
|
||||
|
||||
|
||||
export const DatasetSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { ObjectId } from "mongoose";
|
||||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { ExecProcessUseCase, IsHaveActiveProcessUseCase } from "../../../core/usecases/exec_process_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { ProcessWatcherAndDatabaseUpdateService } from "../../datasets/domain/create_dataset_scenario";
|
||||
import { WeightDBModel, IWeightModel } from "../models/weights_validation_model";
|
||||
|
||||
export class ExecWeightProcessScenario extends CallbackStrategyWithIdQuery {
|
||||
idValidationExpression = new MongoIdValidation();
|
||||
call = async (id: string): ResponseBase => {
|
||||
return (await new ReadByIdDataBaseModelUseCase<IWeightModel>(WeightDBModel).call(id)).map(async (model) => {
|
||||
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
|
||||
await WeightDBModel.findById(id).updateOne({ processStatus: "RUN" });
|
||||
|
||||
if (typeof model.project === "object" && typeof model.datasetId === "object") {
|
||||
console.log(
|
||||
`python3 $PYTHON_EDUCATION --path ${model.project.rootDir} --name ${model.name} --datasetName ${model.datasetId.name}`
|
||||
);
|
||||
return new ExecProcessUseCase().call(
|
||||
`${model.project.rootDir}/`,
|
||||
`python3 $PYTHON_EDUCATION --path ${model.project.rootDir} --name ${model.name} --datasetName ${model.datasetId.name}`,
|
||||
id,
|
||||
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId, WeightDBModel)
|
||||
);
|
||||
}
|
||||
return Result.error("model project is not object");
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
11
server/src/features/weights/models/weights_database_model.ts
Normal file
11
server/src/features/weights/models/weights_database_model.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { IsMongoId, IsString } from "class-validator";
|
||||
import { IWeightModel } from "./weights_validation_model";
|
||||
|
||||
export class WeightValidationModel implements IWeightModel {
|
||||
@IsString()
|
||||
public name: string;
|
||||
@IsMongoId()
|
||||
public datasetId: string;
|
||||
@IsMongoId()
|
||||
public project: string;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { IProjectModel, projectSchema } from "../../_projects/models/project_database_model";
|
||||
import { datasetSchema } from "../../datasets/models/dataset_database_model";
|
||||
import { IDatasetModel } from "../../datasets/models/dataset_validation_model";
|
||||
|
||||
export interface IWeightModel {
|
||||
name: string;
|
||||
datasetId: string | IDatasetModel;
|
||||
project: string | IProjectModel;
|
||||
}
|
||||
export const WeightSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
local_path: {
|
||||
type: String,
|
||||
},
|
||||
neuralNetworkName: {
|
||||
type: String,
|
||||
},
|
||||
processStatus: {
|
||||
type: String,
|
||||
default: "none",
|
||||
},
|
||||
// the user selects
|
||||
isFinished: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
datasetId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: datasetSchema,
|
||||
autopopulate: true,
|
||||
require: true,
|
||||
},
|
||||
project: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: projectSchema,
|
||||
autopopulate: true,
|
||||
require: true,
|
||||
},
|
||||
processLogs: {
|
||||
type: String,
|
||||
},
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const weightSchema = "Weight";
|
||||
|
||||
export const WeightDBModel = model<IWeightModel>(weightSchema, WeightSchema);
|
19
server/src/features/weights/weights_presentation.ts
Normal file
19
server/src/features/weights/weights_presentation.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { ExecWeightProcessScenario } from "./domain/exec_weights_process_scenario";
|
||||
import { WeightValidationModel } from "./models/weights_database_model";
|
||||
import { WeightDBModel } from "./models/weights_validation_model";
|
||||
|
||||
export class WeightsPresentation extends CrudController<WeightValidationModel, typeof WeightDBModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "weights",
|
||||
validationModel: WeightValidationModel,
|
||||
databaseModel: WeightDBModel,
|
||||
});
|
||||
this.subRoutes.push({
|
||||
method: "GET",
|
||||
subUrl: "exec",
|
||||
fn: new ExecWeightProcessScenario(),
|
||||
});
|
||||
}
|
||||
}
|
|
@ -54,7 +54,7 @@ export const ArrayExtensions = () => {
|
|||
if ([].repeat === undefined) {
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Array.prototype.repeat = function (quantity) {
|
||||
return Array(quantity).fill(this[0]);
|
||||
return Array(quantity).fill(this).flat(1);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
3
ui/src/core/model/style.ts
Normal file
3
ui/src/core/model/style.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export interface IStyle{
|
||||
style?: React.CSSProperties;
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
import * as React from "react";
|
||||
import { CoreText, CoreTextType } from "../text/text";
|
||||
import { IStyle } from "../../model/style";
|
||||
|
||||
export interface IButtonProps {
|
||||
export interface IButtonProps extends IStyle {
|
||||
block?: boolean;
|
||||
filled?: boolean;
|
||||
text?: string;
|
||||
onClick?: any;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export function CoreButton(props: IButtonProps) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from "react";
|
||||
import { Result } from "../../helper/result";
|
||||
import { IStyle } from "../../model/style";
|
||||
|
||||
export interface IIconsProps {
|
||||
export interface IIconsProps extends IStyle {
|
||||
type: string;
|
||||
style?: React.CSSProperties;
|
||||
onClick?: Function;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import * as React from "react";
|
||||
import { CoreText, CoreTextType } from "../text/text";
|
||||
import { IStyle } from "../../model/style";
|
||||
|
||||
interface IInputProps {
|
||||
interface IInputProps extends IStyle {
|
||||
label: string;
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
style?: React.CSSProperties;
|
||||
validation?: (value: string) => boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import * as React from "react";
|
||||
import { Typography } from "antd";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { IStyle } from "../../model/style";
|
||||
|
||||
const { Link } = Typography;
|
||||
|
||||
export interface ILinkTypography {
|
||||
export interface ILinkTypography extends IStyle {
|
||||
path: string;
|
||||
text: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export const LinkTypography: React.FunctionComponent<ILinkTypography> = (
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from "react";
|
||||
import { CoreText, CoreTextType } from "../text/text";
|
||||
import { IStyle } from "../../model/style";
|
||||
|
||||
interface ISelectCoreProps {
|
||||
interface ISelectCoreProps extends IStyle {
|
||||
items: string[];
|
||||
value: string;
|
||||
label: string;
|
||||
onChange: (value: string) => void;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
export const SelectCore = (props: ISelectCoreProps) => {
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
|
|
|
@ -133,7 +133,6 @@ export const CardDataSet = (props: ICardDataSetProps) => {
|
|||
/>):null}
|
||||
{props.processStatus === ProcessStatus.RUN ? (<>
|
||||
<CoreButton
|
||||
|
||||
onClick={() => {
|
||||
if (props.type.isEqual(CardDataSetType.COMPLETED) && props.onClickButton && props.id) {
|
||||
props.onClickButton(props.id);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
74
ui/src/features/skils/skil_card.tsx
Normal file
74
ui/src/features/skils/skil_card.tsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { Icon } from "../../core/ui/icons/icons";
|
||||
import { CoreText, CoreTextType } from "../../core/ui/text/text";
|
||||
import { ProcessStatus } from "../dataset/dataset_model";
|
||||
|
||||
export interface ISkillCardProps {
|
||||
processStatus?: string;
|
||||
name?: string;
|
||||
emptyOnClick?: Function;
|
||||
empty: boolean;
|
||||
}
|
||||
|
||||
export const SkillCard = (props: ISkillCardProps) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
margin: 10,
|
||||
backgroundColor: "#f7f2fa",
|
||||
borderRadius: 10,
|
||||
padding: 10,
|
||||
width: 150,
|
||||
height: 100,
|
||||
alignContent: "center",
|
||||
}}
|
||||
>
|
||||
{props.empty ? (
|
||||
<div
|
||||
onClick={() => {
|
||||
if (props.empty && props.emptyOnClick) props.emptyOnClick();
|
||||
}}
|
||||
style={{ display: "flex", justifyContent: "center", alignItems: "center" }}
|
||||
>
|
||||
<Icon type="PlusCircle" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<CoreText text={props.name ?? ""} type={CoreTextType.medium} />
|
||||
{props.processStatus === ProcessStatus.END ? (
|
||||
<CoreButton
|
||||
onClick={() => {
|
||||
// if (props.type.isEqual(CardDataSetType.COMPLETED) && props.onClickButton && props.id) {
|
||||
// props.onClickButton(props.id);
|
||||
// }
|
||||
}}
|
||||
text="Завершен"
|
||||
/>
|
||||
) : null}
|
||||
{props.processStatus === ProcessStatus.RUN ? (
|
||||
<>
|
||||
<CoreButton
|
||||
onClick={() => {
|
||||
// if (props.type.isEqual(CardDataSetType.COMPLETED) && props.onClickButton && props.id) {
|
||||
// props.onClickButton(props.id);
|
||||
}}
|
||||
block={true}
|
||||
text="Стоп"
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
{props.processStatus === ProcessStatus.ERROR ? (
|
||||
<CoreButton
|
||||
style={{
|
||||
backgroundColor: "red",
|
||||
}}
|
||||
onClick={() => {}}
|
||||
filled={true}
|
||||
text="Ошибка"
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
32
ui/src/features/skils/skills_repository.tsx
Normal file
32
ui/src/features/skils/skills_repository.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { Result } from "../../core/helper/result";
|
||||
import { HttpError, HttpMethod, HttpRepository } from "../../core/repository/http_repository";
|
||||
import { UUID } from "../all_projects/data/project_repository";
|
||||
import { IDatasetModel } from "../dataset/dataset_model";
|
||||
import { SkillModel } from "./skills_store";
|
||||
export interface IEducations {
|
||||
_id: string;
|
||||
name: string;
|
||||
processStatus: string;
|
||||
isFinished: boolean;
|
||||
datasetId: any;
|
||||
project: any;
|
||||
__v: number;
|
||||
}
|
||||
|
||||
export class SkillsRepository extends HttpRepository {
|
||||
getAllSkills = async () => {
|
||||
return this._jsonRequest<IEducations[]>(HttpMethod.GET, "/weights");
|
||||
};
|
||||
deleteSkill = async (id: string) => {
|
||||
return this._jsonRequest<void>(HttpMethod.DELETE, `/weights?id=${id}`);
|
||||
};
|
||||
addNewSkill = async (model: SkillModel) => {
|
||||
return this._jsonRequest(HttpMethod.POST, "/weights", model);
|
||||
};
|
||||
getDatasetsActiveProject = async (): Promise<Result<HttpError, IDatasetModel[]>> => {
|
||||
return this._jsonRequest<IDatasetModel[]>(HttpMethod.GET, "/datasets");
|
||||
};
|
||||
getActiveProjectId(): Promise<Result<HttpError, UUID>> {
|
||||
return this._jsonRequest<UUID>(HttpMethod.GET, "/projects/get/active/project/id");
|
||||
}
|
||||
}
|
|
@ -1,20 +1,97 @@
|
|||
import React from "react";
|
||||
import { MainPage } from "../../core/ui/pages/main_page";
|
||||
import { CoreText, CoreTextType } from "../../core/ui/text/text";
|
||||
import { DrawersSkill, SkillStore } from "./skills_store";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { SkillCard } from "./skil_card";
|
||||
import { Drawer } from "antd";
|
||||
import { CoreInput } from "../../core/ui/input/input";
|
||||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { CoreSwitch } from "../../core/ui/switch/switch";
|
||||
|
||||
interface IItem {
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
const skills: IItem[] = [{ name: "ML", isActive: true }];
|
||||
|
||||
export const SkillPath = "/skills";
|
||||
export const SkillScreen = () => {
|
||||
export const SkillScreen = observer(() => {
|
||||
const [store] = React.useState(() => new SkillStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, [store]);
|
||||
return (
|
||||
<>
|
||||
<MainPage
|
||||
page={"Навыки"}
|
||||
|
||||
panelChildren={
|
||||
<div style={{ justifyContent: "center", display: "flex", padding: 10 }}>
|
||||
{skills.map((el) => (
|
||||
<CoreText text={el.name} type={CoreTextType.header} />
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
bodyChildren={
|
||||
<>
|
||||
<div style={{ display: "flex", width: "100%" }}>
|
||||
|
||||
</div>
|
||||
</>
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(150px,1px))",
|
||||
width: "100%",
|
||||
gap: 20,
|
||||
margin: 12,
|
||||
overflow: "auto",
|
||||
height: window.innerHeight,
|
||||
}}
|
||||
>
|
||||
{store.skils?.map((el) => (
|
||||
<SkillCard name={el.name} processStatus={el.processStatus} empty={false} />
|
||||
))}
|
||||
<SkillCard empty={true} emptyOnClick={() => store.edtDrawer(DrawersSkill.NEW_SKILL, true)} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Drawer
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => store.edtDrawer(DrawersSkill.NEW_SKILL, false)}
|
||||
open={store.drawers.find((el) => el.name === DrawersSkill.NEW_SKILL)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
<CoreInput value={store.skill.name} label={"Имя навыка"} onChange={(e) => store.changeSkillName(e)} />
|
||||
<div style={{ height: "100%" }}>
|
||||
{store.datasets?.map((el) => (
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid rgb(103, 80, 164)",
|
||||
backgroundColor: "rgb(254, 247, 255)",
|
||||
borderRadius: 12,
|
||||
margin: 10,
|
||||
padding: 10,
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{el.name}
|
||||
<CoreSwitch
|
||||
isSelected={store.skill.datasetId.isEqual(el._id)}
|
||||
id={el._id}
|
||||
onChange={() => store.selectDataset(el._id)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton text="Сохранить" filled={true} onClick={() => store.saveSkill()} />
|
||||
<div style={{ width: 10 }} />
|
||||
<CoreButton text="Отмена" onClick={() => store.edtDrawer(DrawersSkill.NEW_SKILL, false)} />
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,3 +1,93 @@
|
|||
export class SkillStore{
|
||||
|
||||
}
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { HttpError } from "../../core/repository/http_repository";
|
||||
import { UiErrorState } from "../../core/store/base_store";
|
||||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { IEducations as ISkils, SkillsRepository as SkillsHttpRepository } from "./skills_repository";
|
||||
import { Drawer } from "../dataset/dataset_store";
|
||||
import { IDatasetModel } from "../dataset/dataset_model";
|
||||
import { Result } from "../../core/helper/result";
|
||||
import { message } from "antd";
|
||||
import { UUID } from "../all_projects/data/project_repository";
|
||||
|
||||
export enum DrawersSkill {
|
||||
NEW_SKILL = "Новый навык",
|
||||
}
|
||||
|
||||
export class SkillModel {
|
||||
constructor(public name: string, public datasetId: string, public project: string) {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
static empty() {
|
||||
return new SkillModel("", "", "");
|
||||
}
|
||||
valid(): Result<string, SkillModel> {
|
||||
if (this.name.isEmpty()) {
|
||||
return Result.error("name is empty");
|
||||
}
|
||||
if (this.datasetId.isEmpty()) {
|
||||
return Result.error("datasetId is empty");
|
||||
}
|
||||
if (this.project.isEmpty()) {
|
||||
return Result.error("project is empty");
|
||||
}
|
||||
return Result.ok(this);
|
||||
}
|
||||
}
|
||||
export class SkillStore extends UiErrorState<HttpError> {
|
||||
drawers: Drawer[];
|
||||
skillsHttpRepository: SkillsHttpRepository;
|
||||
skils?: ISkils[];
|
||||
datasets?: IDatasetModel[];
|
||||
activeProjectId?: UUID;
|
||||
skill: SkillModel;
|
||||
titleDrawer: string = DrawersSkill.NEW_SKILL;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.drawers = Object.entries(DrawersSkill).map((k, v) => {
|
||||
return {
|
||||
name: k.at(1) ?? "",
|
||||
status: false,
|
||||
};
|
||||
});
|
||||
this.skill = SkillModel.empty();
|
||||
this.skillsHttpRepository = new SkillsHttpRepository();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
errorHandingStrategy: (error: HttpError) => {};
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
await this.mapOk("skils", this.skillsHttpRepository.getAllSkills());
|
||||
await this.mapOk("datasets", this.skillsHttpRepository.getDatasetsActiveProject());
|
||||
await this.mapOk("activeProjectId", this.skillsHttpRepository.getActiveProjectId());
|
||||
};
|
||||
changeSkillName(name: string): void {
|
||||
this.skill.name = name;
|
||||
}
|
||||
saveSkill() {
|
||||
console.log(this.activeProjectId);
|
||||
this.skill.project = this.activeProjectId?.id ?? "";
|
||||
this.skill.valid().fold(
|
||||
async (model) => {
|
||||
(await this.skillsHttpRepository.addNewSkill(model)).fold(
|
||||
(s) => {
|
||||
message.success("Новый ");
|
||||
this.skill = SkillModel.empty();
|
||||
},
|
||||
(e) => message.error(e.message)
|
||||
);
|
||||
},
|
||||
async (e) => message.error(e)
|
||||
);
|
||||
}
|
||||
selectDataset(id: string): void {
|
||||
this.skill.datasetId = id;
|
||||
}
|
||||
edtDrawer(drawerName: DrawersSkill, status: boolean): void {
|
||||
this.drawers = this.drawers.map((el) => {
|
||||
if (el.name === drawerName) {
|
||||
el.status = status;
|
||||
}
|
||||
return el;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
28
web_p/education.py
Normal file
28
web_p/education.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import shutil
|
||||
import argparse
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--path")
|
||||
parser.add_argument("--name")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def copy_and_move_folder(src, dst, folder):
|
||||
try:
|
||||
if os.path.exists(dst + "/education/") is False:
|
||||
Path(dst + "/education/").mkdir(parents=True, exist_ok=True)
|
||||
if os.path.exists(dst + "/education/" + folder + "/"):
|
||||
shutil.rmtree(dst + "/education/" + folder + "/")
|
||||
|
||||
shutil.copytree(src, dst + "/education/" + folder + "/")
|
||||
|
||||
except shutil.Error as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
||||
source_folder = os.path.dirname(os.path.abspath(__file__)) + "/education"
|
||||
|
||||
copy_and_move_folder(source_folder, args.path, args.name)
|
3
web_p/education/metadata.json
Normal file
3
web_p/education/metadata.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"numberOfEpochs": 1
|
||||
}
|
BIN
web_p/education/yolov8n.pt
Normal file
BIN
web_p/education/yolov8n.pt
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue