Compare commits

..

4 commits
dev ... main

117 changed files with 757 additions and 2742 deletions

View file

@ -20,7 +20,6 @@
"GLTF", "GLTF",
"grau", "grau",
"idontsudo", "idontsudo",
"Pids",
"raycaster", "raycaster",
"skils", "skils",
"typedataset", "typedataset",

61
flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1733935512,
"narHash": "sha256-beDnPaHubnwcsbVPC3rIVtQM3QVFDMmc0dtfHCW5UrA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d55cc4608dae1b42a0ef5c0cf701b501fc7bae58",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

37
flake.nix Normal file
View file

@ -0,0 +1,37 @@
{
description = "Robossembler Development Environments on Nix";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?ref=master";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = import nixpkgs { inherit system; overlays = []; };
in
{
packages = {
frontend = pkgs.writeShellApplication {
name = "frontend";
runtimeInputs = [ pkgs.nodejs ];
text = ''
cd ui && npm i && npm run dev
'';
};
backend = pkgs.writeShellApplication {
name = "frontend";
runtimeInputs = [ pkgs.nodejs ];
text = ''
cd server && npm i && npm run dev
'';
};
};
devShells = {
default = pkgs.mkShell { packages = with pkgs; [ nodejs ]; };
};
}
);
}

82
p.json
View file

@ -1,82 +0,0 @@
{
"process": {
"type": "OBJECT_DETECTION",
"selectProcess": {
"value": {
"_id": "675db885429ef25f8d2efaa2",
"script": "ls -l -a",
"formBuilder": {
"result": "",
"context": "",
"form": [],
"output": "",
"type": "formBuilder"
},
"type": "OBJECT_DETECTION",
"instanceName": "ls -l -a",
"name": "ls",
"isEnd": true,
"createDate": "1734195300981",
"card": "pose_estimate",
"path": "/Users/idontsudo/webservice/server/build/public//process/ls",
"instancePath": "/Users/idontsudo/webservice/server/build/public//process/ls/ls -l -a",
"project": {
"_id": "675eb125281cf9253681efa3",
"description": "e1wq",
"rootDir": "/Users/idontsudo/webservice/server/build/public/f49f8f47-5427-48aa-8aff-c5e7ae4e6efe",
"isActive": true,
"__v": 0
},
"__v": 0,
"lastProcessExecCommand": "ls -l -a --path /Users/idontsudo/webservice/server/build/public/process/ls/ls -l -a --form /Users/idontsudo/webservice/server/build/public/process/ls/ls -l -a/form.json",
"processStatus": "endError",
"lastProcessLogs": "ls: unrecognized option `--path'nnusage: ls [-@ABCFGHILOPRSTUWabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]n"
}
}
},
"datasetObjects": {
"details": []
},
"typedataset": "ObjectDetection",
"models_randomization": {
"loc_range_low": [
-1,
-1,
0
],
"loc_range_high": [
1,
1,
2
]
},
"scene": {
"objects": [],
"lights": []
},
"camera_position": {
"center_shell": [
0,
0,
0
],
"radius_range": [
1,
1.4
],
"elevation_range": [
10,
90
]
},
"generation": {
"n_cam_pose": 5,
"n_sample_on_pose": 3,
"n_series": 100,
"image_format": "JPEG",
"image_size_wh": [
640,
480
]
}
}

View file

@ -1,14 +1 @@
Веб-сервис для отладки Robossembler Framework Веб-сервис для отладки Robossembler Framework
### Миграция данных веб-сервиса
Имеется ввиду перенос данных, хранящихся в БД MongoDB.
Для этого вначале создаётся копия БД с именем `dev` в папке `my_copy`:
```sh
mongodump --host localhost --port 27017 --db dev --out my_copy
```
Затем папка `my_copy` переносится в нужное место (например, на другой сервер). И запускается её восстановление в новом месте (копия БД с именем `dev`):
```sh
mongorestore --host localhost --port 27017 --db dev my_copy/dev
```

View file

@ -15,12 +15,12 @@
"checkCommand": null, "checkCommand": null,
"filter": null "filter": null
}, },
"btRuntimeProcess": { "btBuilderProcess": {
"execCommand": "cd ~/robossembler-ws && source ./install/local_setup.bash; ros2 launch rbs_bt_executor rbs_bt_web.launch.py bt_path:=${bt_path}", "execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
"date": null, "date": null,
"status": null, "status": null,
"delay": 0, "delay": 0,
"checkCommand": null, "checkCommand": null,
"filter": null "filter": null
} }
} }

View file

@ -9,9 +9,6 @@ import { dirname } from "path";
import { CheckAndCreateStaticFilesFolderUseCase } from "../usecases/check_and_create_static_files_folder_usecase"; import { CheckAndCreateStaticFilesFolderUseCase } from "../usecases/check_and_create_static_files_folder_usecase";
import { DataBaseConnectUseCase } from "../usecases/database_connect_usecase"; import { DataBaseConnectUseCase } from "../usecases/database_connect_usecase";
import { TypedEvent } from "../helpers/typed_event"; import { TypedEvent } from "../helpers/typed_event";
import { CalculationInstanceDBModel } from "../../features/calculations_instance/models/calculations_instance_database_model";
import * as fs from "fs";
import { WriteFileSystemFileUseCase } from "../usecases/write_file_system_file_usecase";
export enum ServerStatus { export enum ServerStatus {
init = "init", init = "init",
@ -88,25 +85,7 @@ export class App extends TypedEvent<ServerStatus> {
this.app.use(express.json()); this.app.use(express.json());
this.app.use(express.urlencoded({ extended: true })); this.app.use(express.urlencoded({ extended: true }));
this.app.use(express.static(App.staticFilesStoreDir())); this.app.use(express.static(App.staticFilesStoreDir()));
this.app.get('/logs', async (req, res) => {
const id = req.query.id;
if (id === undefined) {
return res.status(400).json('need req query id?=')
}
const calculationInstanceDBModel = await CalculationInstanceDBModel.findById(id)
if (calculationInstanceDBModel === null) {
return res.status(400).json("calcultaion db model is null");
}
const p = App.staticFilesStoreDir() + '/log.txt';
(await new WriteFileSystemFileUseCase().call(p, calculationInstanceDBModel.lastProcessLogs)).map(() => {
return res.sendFile(p);
})
})
this.app.use( this.app.use(
fileUpload({ fileUpload({
createParentPath: true, createParentPath: true,

View file

@ -65,12 +65,12 @@ interface ISubSetFeatureRouter<A> {
method: HttpMethodType; method: HttpMethodType;
subUrl: string; subUrl: string;
fn: fn:
| CallbackStrategyWithValidationModel<A> | CallbackStrategyWithValidationModel<A>
| CallbackStrategyWithEmpty | CallbackStrategyWithEmpty
| CallbackStrategyWithIdQuery | CallbackStrategyWithIdQuery
| CallBackStrategyWithQueryPage | CallBackStrategyWithQueryPage
| CallbackStrategyWithFileUpload | CallbackStrategyWithFileUpload
| CallbackStrategyWithFilesUploads; | CallbackStrategyWithFilesUploads;
} }
abstract class ICoreHttpController { abstract class ICoreHttpController {
@ -234,7 +234,6 @@ export class CoreHttpController<V> implements ICoreHttpController {
return res.json(ok); return res.json(ok);
}, },
(err) => { (err) => {
return res.status(400).json({ error: String(err) }); return res.status(400).json({ error: String(err) });
} }
); );

View file

@ -18,7 +18,7 @@ export class TopicViewModel {
export interface IParam { export interface IParam {
type: string; type: string;
dependency: object; dependency: Object;
} }
export interface Skill { export interface Skill {
SkillPackage: ISkillPackage; SkillPackage: ISkillPackage;

View file

@ -7,8 +7,9 @@ export abstract class CreateInstanceScenario<V extends Instance> extends Callbac
abstract validationModel: V; abstract validationModel: V;
abstract databaseModel: any; abstract databaseModel: any;
call = async (model: V): ResponseBase => { call = async (model: V): ResponseBase => {
model.instancePath = `${model.path.pathNormalize()}/${model.instanceName}`.pathNormalize(); model.instancePath = `${model.path}/${model.instanceName}`;
model.path = model.path.pathNormalize(); console.log("INSTANCE PATh");
console.log(model.instancePath)
return (await new CreateFolderUseCase().call(model.instancePath)).map( return (await new CreateFolderUseCase().call(model.instancePath)).map(
async () => await new CreateDataBaseModelUseCase(this.databaseModel).call(model) async () => await new CreateDataBaseModelUseCase(this.databaseModel).call(model)
); );

View file

@ -1,72 +0,0 @@
import { Disposable, Listener, TypedEvent } from "../helpers/typed_event";
import { GetRootDirUseCase } from "../usecases/get_root_dir_usecase"
import { exec } from 'child_process';
export const activeProcessPids: { [name: string]: { pid: number, status: ProcessStatus } } = {}
export enum ProcessStatus {
run = 'run',
endError = 'endError',
endOk = 'endOk',
userDelete = 'userDelete',
}
class ExecutorProgramServiceV2 extends TypedEvent<{ [name: string]: { pid: number, status: ProcessStatus } }> {}
export const executorProgramServiceV2 = new ExecutorProgramServiceV2();
class ProcessData {
log: string | undefined;
status: ProcessStatus;
constructor(log: string | undefined, status: ProcessStatus) {
if (log !== undefined) {
this.log = log;
}
this.status = status;
}
}
abstract class Watcher {
}
export abstract class ExecProcessWatcher extends TypedEvent<ProcessData> implements Watcher {
logs: string[] = [];
status: ProcessStatus;
constructor() {
super();
this.on((event) => {
if (event.log !== undefined) {
this.logs.push(event.log);
}
this.status = event.status;
if (event.status.isEqualMany([ProcessStatus.endError, ProcessStatus.endOk])) {
this.result()
}
})
}
abstract result(): Promise<any>
}
export class ExecProcessScenarioV2 {
call = (command: string, watcher: ExecProcessWatcher, name?: string): void => {
const process = exec(command, { cwd: new GetRootDirUseCase().call() });
if (process.pid) {
activeProcessPids[name ?? command] = { pid: process.pid, status: ProcessStatus.run };
executorProgramServiceV2.emit(activeProcessPids);
}
process.stdout.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run)))
process.stderr.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run)));
process.on('close', (code) => {
if (code === 0) {
watcher.emit(new ProcessData(undefined, ProcessStatus.endOk))
activeProcessPids[name ?? command] = { pid: process.pid ?? 0, status: ProcessStatus.endOk }
executorProgramServiceV2.emit(activeProcessPids);
} else {
watcher.emit(new ProcessData(undefined, ProcessStatus.endError))
activeProcessPids[name ?? command] = { pid: process.pid ?? 0, status: ProcessStatus.endError };
executorProgramServiceV2.emit(activeProcessPids);
}
});
process.on('error', (err) => watcher.emit(new ProcessData(err.message, ProcessStatus.endError)));
}
}

View file

@ -50,6 +50,7 @@ export class ExecutorProgramService
}; };
worker.send(workerDataExec); worker.send(workerDataExec);
worker.on("message", (e) => { worker.on("message", (e) => {
console.log(JSON.stringify(e));
const spawnError = SpawnError.isError(e); const spawnError = SpawnError.isError(e);
if (spawnError instanceof SpawnError) { if (spawnError instanceof SpawnError) {

View file

@ -7,7 +7,6 @@ import { ExecutorResult } from "../models/executor_result";
import { ExecutorProgramService } from "../services/executor_program_service"; import { ExecutorProgramService } from "../services/executor_program_service";
export const executorProgramService = new ExecutorProgramService(""); export const executorProgramService = new ExecutorProgramService("");
export class KillLastProcessUseCase extends CallbackStrategyWithEmpty { export class KillLastProcessUseCase extends CallbackStrategyWithEmpty {
call = async (): Promise<Result<undefined, string>> => { call = async (): Promise<Result<undefined, string>> => {
executorProgramService.deleteWorker(); executorProgramService.deleteWorker();

View file

@ -1,5 +0,0 @@
import * as os from 'os';
export class GetRootDirUseCase {
call = (): string => os.homedir()
}

View file

@ -8,9 +8,6 @@ import { SaveBtScenario as FillBtScenario } from "./domain/save_bt_scenario";
import { GetCameraUseCase } from "./domain/get_cameras_usecase"; import { GetCameraUseCase } from "./domain/get_cameras_usecase";
import { GetRobotsUseCase } from "./domain/get_robots_usecase"; import { GetRobotsUseCase } from "./domain/get_robots_usecase";
import { GetTopicsUseCase } from "./domain/get_topics_usecase"; import { GetTopicsUseCase } from "./domain/get_topics_usecase";
import { DeleteBehaviorTreeScenario } from "./domain/delete_behavior_tree_scenario";
export class BehaviorTreesPresentation extends CrudController<BehaviorTreeValidationModel, typeof BehaviorTreeDBModel> { export class BehaviorTreesPresentation extends CrudController<BehaviorTreeValidationModel, typeof BehaviorTreeDBModel> {
constructor() { constructor() {
@ -46,11 +43,6 @@ export class BehaviorTreesPresentation extends CrudController<BehaviorTreeValida
subUrl: "topics", subUrl: "topics",
fn: new GetTopicsUseCase() fn: new GetTopicsUseCase()
}) })
this.subRoutes.push({
method: "POST",
subUrl: "delete/bt",
fn: new DeleteBehaviorTreeScenario(),
})
} }
} }

View file

@ -1,16 +0,0 @@
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
import { StaticFilesProject } from "../../../core/models/static_files";
import { DeleteDataBaseModelUseCase } from "../../../core/usecases/delete_database_model_usecase";
import { DeleteRecursiveFolderUseCase } from "../../../core/usecases/delete_recursive_folder_usecase";
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
import { CoreValidation } from "../../../core/validations/core_validation";
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
import { BehaviorTreeDBModel } from "../models/behavior_tree_database_model";
export class DeleteBehaviorTreeScenario extends CallbackStrategyWithIdQuery {
idValidationExpression: CoreValidation = new MongoIdValidation();
call = async (id: string): ResponseBase => (
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
).map(async (model) => (await (new DeleteRecursiveFolderUseCase().call(`${model.rootDir}/${StaticFilesProject.behaviorTrees}`))).map(async () => (await new DeleteDataBaseModelUseCase(BehaviorTreeDBModel).call(id))));
}

View file

@ -2,13 +2,12 @@ import { IsMongoId, IsNumber, IsString } from "class-validator";
import { IBehaviorTreeModel } from "./behavior_tree_database_model"; import { IBehaviorTreeModel } from "./behavior_tree_database_model";
export class BehaviorTreeValidationModel implements IBehaviorTreeModel { export class BehaviorTreeValidationModel implements IBehaviorTreeModel {
_id: string;
@IsString() @IsString()
public name: string; public name: string;
@IsMongoId() @IsMongoId()
public project: string; public project:string;
public skills: any; public skills:any;
public xml: string; public xml:string;
@IsNumber() @IsNumber()
public unixTime: number public unixTime: number
} }

View file

@ -4,8 +4,6 @@ import { CalculationInstanceValidationModel } from "./models/calculations_instan
import { CalculationInstanceDBModel } from "./models/calculations_instance_database_model"; import { CalculationInstanceDBModel } from "./models/calculations_instance_database_model";
import { CreateCalculationInstanceScenario } from "./domain/create_calculation_instance_scenario"; import { CreateCalculationInstanceScenario } from "./domain/create_calculation_instance_scenario";
import { DeleteCalculationsInstanceScenario } from "./domain/delete_calculations_instance_scenario"; import { DeleteCalculationsInstanceScenario } from "./domain/delete_calculations_instance_scenario";
import { GetAllEndCalculationsInstanceActiveProjectScenarios } from "./domain/get_all_end_calculations_instance_active_project_scenarios";
export class CalculationsInstancesPresentation extends CrudController< export class CalculationsInstancesPresentation extends CrudController<
CalculationInstanceValidationModel, CalculationInstanceValidationModel,
@ -20,12 +18,7 @@ export class CalculationsInstancesPresentation extends CrudController<
super.delete(new DeleteCalculationsInstanceScenario().call); super.delete(new DeleteCalculationsInstanceScenario().call);
super.post(new CreateCalculationInstanceScenario().call); super.post(new CreateCalculationInstanceScenario().call);
this.subRoutes.push({
method: "POST",
subUrl: "get/all/end/calculations",
//@ts-expect-error
fn: new GetAllEndCalculationsInstanceActiveProjectScenarios(),
})
this.subRoutes.push({ this.subRoutes.push({
method: "GET", method: "GET",
subUrl: "exec", subUrl: "exec",

View file

@ -7,21 +7,7 @@ import { ProcessWatcherAndDatabaseUpdateService } from "../../datasets/domain/cr
import { CalculationInstanceDBModel, ICalculationInstance } from "../models/calculations_instance_database_model"; import { CalculationInstanceDBModel, ICalculationInstance } from "../models/calculations_instance_database_model";
import { Result } from "../../../core/helpers/result"; import { Result } from "../../../core/helpers/result";
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase"; import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
import { ExecProcessScenarioV2, ExecProcessWatcher } from "../../../core/scenarios/exec_process_scenario_v2";
class ExecProcess extends ExecProcessWatcher {
id: string;
constructor(id: string) {
super()
this.id = id;
}
result = async (): Promise<any> => (await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(this.id)).map(async (model) => {
model.lastProcessLogs = this.logs.join('\n')
model.processStatus = this.status;
// @ts-ignore
await model.save()
});
}
export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWithIdQuery { export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWithIdQuery {
idValidationExpression = new MongoIdValidation(); idValidationExpression = new MongoIdValidation();
call = async (id: string): ResponseBase => call = async (id: string): ResponseBase =>
@ -31,15 +17,19 @@ export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWith
return (await new IsHaveActiveProcessUseCase().call()).map(async () => { return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
const execCommand = `${model.script const execCommand = `${model.script
} --path ${model.instancePath.pathNormalize()} --form ${fileOutPath}`.replace("\n", ""); } --path ${model.instancePath.pathNormalize()} --form ${fileOutPath}`.replace("\n", "");
await new CreateFileUseCase().call(fileOutPath, Buffer.from(JSON.stringify(model.formBuilder))); await new CreateFileUseCase().call(fileOutPath, Buffer.from(JSON.stringify(model.formBuilder)));
await CalculationInstanceDBModel.findById(id).updateOne({ await CalculationInstanceDBModel.findById(id).updateOne({
processStatus: "RUN", processStatus: "RUN",
lastProcessExecCommand: execCommand, lastProcessExecCommand: execCommand,
}); });
new ExecProcessUseCase().call(
new ExecProcessScenarioV2().call(execCommand, new ExecProcess(model._id)) // @ts-expect-error
`${model.project.rootDir}/`,
execCommand,
id,
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId, CalculationInstanceDBModel)
);
return Result.ok("OK"); return Result.ok("OK");
}); });
} }

View file

@ -1,20 +0,0 @@
import { IsString } from "class-validator";
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
import { GetActiveProjectIdScenario } from "../../projects/domain/get_active_project_id_scenario";
import { ICalculationInstance, CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
export class CalculationInstanceType {
@IsString()
type: string;
}
export class GetAllEndCalculationsInstanceActiveProjectScenarios extends CallbackStrategyWithValidationModel<CalculationInstanceType> {
validationModel: CalculationInstanceType = new CalculationInstanceType();
call = async (model: CalculationInstanceType): ResponseBase => (await new GetActiveProjectIdScenario().call()).map(
async (activeProjectModel) => await new SearchManyDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call({ project: activeProjectModel.id, isEnd: true, type: model.type }),
);
}

View file

@ -1,11 +0,0 @@
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_database_model_usecase";
import { CoreValidation } from "../../../core/validations/core_validation";
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
import { ICalculationInstance, CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
// export class LogToProcessUseCase extends CallbackStrategyWithIdQuery {
// idValidationExpression: CoreValidation = new MongoIdValidation();
// call = async (id: string): ResponseBase => (await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(id)).map((model) => );
// }

View file

@ -3,7 +3,6 @@ import { FormBuilderValidationModel } from "../../datasets/models/dataset_valida
import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model"; import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model";
export interface ICalculationInstance { export interface ICalculationInstance {
_id: string;
script: string; script: string;
instancePath: string; instancePath: string;
formBuilder: FormBuilderValidationModel; formBuilder: FormBuilderValidationModel;
@ -62,7 +61,6 @@ export const CalculationInstanceSchema = new Schema({
instancePath: { instancePath: {
type: String, type: String,
}, },
project: { project: {
type: Schema.Types.ObjectId, type: Schema.Types.ObjectId,
ref: projectSchema, ref: projectSchema,

View file

@ -4,7 +4,6 @@ import { FormBuilderValidationModel } from "../../datasets/models/dataset_valida
import { IProjectModel } from "../../projects/models/project_model_database_model"; import { IProjectModel } from "../../projects/models/project_model_database_model";
export class CalculationInstanceValidationModel implements ICalculationInstance { export class CalculationInstanceValidationModel implements ICalculationInstance {
_id: string;
@IsNotEmpty() @IsNotEmpty()
@IsString() @IsString()
instanceName: string; instanceName: string;

View file

@ -15,7 +15,6 @@ export enum ProcessStatus {
END = "END", END = "END",
ERROR = "ERROR", ERROR = "ERROR",
NEW = "NEW", NEW = "NEW",
} }
export interface IDatasetModel { export interface IDatasetModel {
_id?: string; _id?: string;

View file

@ -21,7 +21,8 @@ export class ExecInstanceScenario extends CallbackStrategyWithIdQuery {
await new ReadByIdDataBaseModelUseCase<IDigitalTwinsInstanceModel>(DigitalTwinsInstanceDatabaseModel).call(id) await new ReadByIdDataBaseModelUseCase<IDigitalTwinsInstanceModel>(DigitalTwinsInstanceDatabaseModel).call(id)
).map( ).map(
(document) => ( (document) => (
console.log('DOCUMeNT PATH'),
console.log(document.instancePath.pathNormalize()),
new ExecProcessUseCase().call( new ExecProcessUseCase().call(
document.instancePath, document.instancePath,
`python3 $GET_INTERFACES --path ${document.instancePath.pathNormalize()} --package '${JSON.stringify( `python3 $GET_INTERFACES --path ${document.instancePath.pathNormalize()} --package '${JSON.stringify(

View file

@ -4,8 +4,9 @@ import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_dat
import { IProjectModel, ProjectDBModel } from "../models/project_model_database_model"; import { IProjectModel, ProjectDBModel } from "../models/project_model_database_model";
export class GetActiveProjectIdScenario extends CallbackStrategyWithEmpty { export class GetActiveProjectIdScenario extends CallbackStrategyWithEmpty {
call = async (): Promise<Result<any, { id: string }>> => ( async call(): Promise<Result<any, { id: string }>> {
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects") return (
).map((model) => Result.ok({ id: model._id })); await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
).map((model) => Result.ok({ id: model._id }));
}
} }

View file

@ -35,6 +35,7 @@ export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWit
"/assets/"; "/assets/";
model.map((el) => { model.map((el) => {
const assetLibsAddress = assetAddress + "/libs/objects/" + el.name; const assetLibsAddress = assetAddress + "/libs/objects/" + el.name;
console.log(assetLibsAddress);
el.stlUrl = `${assetAddress}${el.part_path}`; el.stlUrl = `${assetAddress}${el.part_path}`;
el.glUrl = `${assetLibsAddress}.glb`; el.glUrl = `${assetLibsAddress}.glb`;
el.daeUrl = `${assetLibsAddress}.dae`; el.daeUrl = `${assetLibsAddress}.dae`;

View file

@ -1,53 +1,7 @@
import { import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
CallbackStrategyWithIdQuery,
CallbackStrategyWithValidationModel,
ResponseBase,
} from "../../../core/controllers/http_controller";
import { StaticFilesProject } from "../../../core/models/static_files";
import {
ExecProcessScenarioV2,
ExecProcessWatcher,
activeProcessPids,
} from "../../../core/scenarios/exec_process_scenario_v2";
import { ReadByIdDataBaseModelScenario } from "../../../core/scenarios/read_by_id_database_model_scenario";
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
import { CoreValidation } from "../../../core/validations/core_validation";
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
import { BehaviorTreeDBModel } from "../../behavior_trees/models/behavior_tree_database_model";
import { BehaviorTreeValidationModel } from "../../behavior_trees/models/behavior_tree_validation_model";
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
import { GetCommandScenario } from "./get_command_scenario";
class ProcessWatcher extends ExecProcessWatcher { export class ExecBtBuilderUseCase extends CallbackStrategyWithEmpty {
async result(): Promise<any> { call(): ResponseBase {
console.log(this); throw new Error("Method not implemented.");
} }
} }
export enum Proceed {
EXEC_BT = "EXEC_BT",
}
export class ExecBtScenario extends CallbackStrategyWithIdQuery {
idValidationExpression: CoreValidation = new MongoIdValidation();
call = async (id: string): ResponseBase =>
(await new ReadByIdDataBaseModelScenario<BehaviorTreeValidationModel>(BehaviorTreeDBModel).call(id)).map(
async (behaviorTreeValidationModel) =>
(
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
{ isActive: true },
"no active projects"
)
).map(async (model) =>
(await new GetCommandScenario().call("btRuntimeProcess")).map((execProcessData) =>
new ExecProcessScenarioV2().call(
execProcessData.execCommand.replace(
"${bt_path}",
`${model.rootDir}/${StaticFilesProject.behaviorTrees}/${behaviorTreeValidationModel.name}/bt.xml`
),
new ProcessWatcher(),
Proceed.EXEC_BT
)
)
)
);
}

View file

@ -1,7 +0,0 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
import { Result } from "../../../core/helpers/result";
import { activeProcessPids } from "../../../core/scenarios/exec_process_scenario_v2";
export class GetRunTimeStatuses extends CallbackStrategyWithEmpty {
call = async (): ResponseBase => Result.ok(activeProcessPids);
}

View file

@ -0,0 +1,10 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
import { Result } from "../../../core/helpers/result";
import { SpawnProcessUseCase } from "../../../core/usecases/exec_process_usecase";
import { GetCommandScenario } from "./get_command_scenario";
import { ProcessWatcher } from "../service/process_watcher";
import { App } from "../../../core/controllers/app";
export class GetSimulationStateScenario extends CallbackStrategyWithEmpty {
call = async (): ResponseBase => Result.ok("");
}

View file

@ -1,51 +0,0 @@
import { IsString } from "class-validator";
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
import { ProcessStatus, activeProcessPids } from "../../../core/scenarios/exec_process_scenario_v2";
import { Result } from "../../../core/helpers/result";
import { GetRootDirUseCase } from "../../../core/usecases/get_root_dir_usecase";
import { exec } from 'child_process';
export class StopProcessModel {
@IsString()
pid: string
}
export class StopProcessUseCase extends CallbackStrategyWithValidationModel<StopProcessModel> {
validationModel: StopProcessModel = new StopProcessModel();
call = async (model: StopProcessModel): ResponseBase => {
try {
if (activeProcessPids[model.pid] === undefined) {
return Result.error('missing pid');
}
const processKillStatus = await new Promise<string>((resolve, reject) => {
try {
exec(`kill ${activeProcessPids[model.pid].pid}`, { cwd: new GetRootDirUseCase().call() }, (error, stdout, stderr) => {
if (error) {
reject(`Ошибка: ${stderr}`); return;
}
if (stderr) {
reject(`Ошибка: ${stderr}`);
return;
}
resolve('Process kill')
});
} catch (e) {
resolve('Process kill')
}
})
if (processKillStatus == 'Process kill') {
activeProcessPids[model.pid].status = ProcessStatus.userDelete;
}
return Result.ok(processKillStatus);
} catch (error) {
return Result.ok(error)
}
}
}

View file

@ -11,4 +11,4 @@ export interface ExecProcess {
delay: number; delay: number;
checkCommand: null; checkCommand: null;
filter: null; filter: null;
} }

View file

@ -1,19 +1,42 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { ExecRunTimeCommandValidationModel } from "./model/run_time_validation_model"; import { ExecRunTimeCommandValidationModel } from "./model/run_time_validation_model";
import { CoreHttpController, SubRouter, CallbackStrategyWithIdQuery } from "../../core/controllers/http_controller"; import { ExecRuntimeDatabaseModel } from "./model/run_time_database_model";
import { ExecBtScenario } from "./domain/exec_bt_builder_usecase"; import { CoreHttpController, SubRouter, HttpMethodType, CallbackStrategyWithIdQuery, ResponseBase } from "../../core/controllers/http_controller";
import { GetRunTimeStatuses } from "./domain/get_run_time_statuses_usecase"; import { ExecBtBuilderUseCase } from "./domain/exec_bt_builder_usecase";
import { StopProcessUseCase } from "./domain/stop_process_usecase"; import { ExecSimulationUseCase } from "./domain/exec_simulation_usecase";
import { GetBtBuilderStateUseCase } from "./domain/get_bt_builder_status_usecase";
import { GetSimulationStateScenario } from "./domain/get_simulation_state_usecase";
import { MongoIdValidation } from "../../core/validations/mongo_id_validation";
import { CoreValidation } from "../../core/validations/core_validation";
import { ReadByIdDataBaseModelUseCase } from "../../core/usecases/read_by_id_database_model_usecase";
import { ICalculationInstance, CalculationInstanceDBModel } from "../calculations_instance/models/calculations_instance_database_model";
import { Result } from "../../core/helpers/result";
import { SpawnProcessUseCase } from "../../core/usecases/exec_process_usecase";
import { ProcessWatcher } from "./service/process_watcher";
class ExecAnalyzeScenario extends CallbackStrategyWithIdQuery {
export class RunTimePresentation extends CoreHttpController<ExecRunTimeCommandValidationModel> { idValidationExpression: CoreValidation = new MongoIdValidation()
call = async (id: string) =>
(await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(id)).map(async (model) =>
(await new SpawnProcessUseCase().call('/Users/idontsudo/webservice', `nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${model.instancePath}`, "", new ProcessWatcher())).map(() => Result.ok('ok'),),
)
}
export class RunTimePresentation extends CrudController<ExecRunTimeCommandValidationModel, any> {
constructor() { constructor() {
super({ super({
url: "run_time", url: "run_time",
}); });
this.subRoutes.push(new SubRouter<any>("POST", "exec/bt", new ExecBtScenario())); this.subRoutes.push(new SubRouter("POST", "/exec/bt/builder", new ExecBtBuilderUseCase()));
this.subRoutes.push(new SubRouter("GET", "status", new GetRunTimeStatuses())); this.subRoutes.push(new SubRouter("POST", "/get/bt/builder/state", new GetBtBuilderStateUseCase()));
this.subRoutes.push(new SubRouter<any>("POST", "kill", new StopProcessUseCase())) this.subRoutes.push(new SubRouter("POST", "/get/simulator/state", new GetSimulationStateScenario()));
this.subRoutes.push(new SubRouter('POST', "exec/analyze", new ExecAnalyzeScenario()))
this.subRoutes.push({
method: "POST",
subUrl: "/exec/simulation/",
fn: new ExecSimulationUseCase(),
});
} }
} }

View file

@ -3,11 +3,11 @@ import { App } from "./core/controllers/app";
import { SocketSubscriber } from "./core/controllers/socket_controller"; import { SocketSubscriber } from "./core/controllers/socket_controller";
import { extensions } from "./core/extensions/extensions"; import { extensions } from "./core/extensions/extensions";
import { httpRoutes } from "./core/controllers/routes"; import { httpRoutes } from "./core/controllers/routes";
import { executorProgramService } from "./core/usecases/exec_process_usecase"; import { SpawnProcessUseCase, executorProgramService } from "./core/usecases/exec_process_usecase";
import { executorProgramServiceV2 } from "./core/scenarios/exec_process_scenario_v2"; import { ProcessWatcher } from "./features/runtime/service/process_watcher";
extensions(); extensions();
const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime"), new SocketSubscriber(executorProgramServiceV2, 'realtimeV2',)]; const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime")];
new App(httpRoutes, socketSubscribers).listen(); new App(httpRoutes, socketSubscribers).listen();

View file

@ -1,14 +1,7 @@
/* eslint-disable no-extend-native */
import { Result } from "../helper/result"; import { Result } from "../helper/result";
/* eslint-disable @typescript-eslint/no-this-alias */ /* eslint-disable @typescript-eslint/no-this-alias */
export const ArrayExtensions = () => { export const ArrayExtensions = () => {
if (Array.prototype.plus === undefined) {
Array.prototype.plus = function (array) {
array.forEach((el) => this.push(el))
return this;
}
}
if ([].indexOfR === undefined) { if ([].indexOfR === undefined) {
Array.prototype.indexOfR = function (element) { Array.prototype.indexOfR = function (element) {
if (this.indexOf(element) === -1) { if (this.indexOf(element) === -1) {
@ -17,11 +10,6 @@ export const ArrayExtensions = () => {
return Result.ok(this); return Result.ok(this);
}; };
} }
if ([].whereOne === undefined) {
Array.prototype.whereOne = function (predicate) {
return this.filter(predicate).atR(0);
}
}
if ([].atR === undefined) { if ([].atR === undefined) {
Array.prototype.atR = function (index) { Array.prototype.atR = function (index) {
if (index === undefined) { if (index === undefined) {

View file

@ -30,8 +30,6 @@ declare global {
someR(predicate: (value: T) => boolean): Result<void, Array<T>>; someR(predicate: (value: T) => boolean): Result<void, Array<T>>;
updateAll(value: Partial<T>): Array<T>; updateAll(value: Partial<T>): Array<T>;
atR(index: number | undefined): Result<void, T>; atR(index: number | undefined): Result<void, T>;
whereOne(predicate: (value: T) => boolean): Result<void, T>;
plus(array: any[]): Array<T>
} }
interface Date { interface Date {
formatDate(): string; formatDate(): string;

View file

@ -1,15 +1,23 @@
import { IsNotEmpty, IsString } from "class-validator"; import { IsNotEmpty, IsString } from "class-validator";
import { BehaviorTreeBuilderStore } from "../../features/behavior_tree_builder/presentation/behavior_tree_builder_store"; import { BehaviorTreeBuilderStore } from "../../features/behavior_tree_builder/presentation/behavior_tree_builder_store";
import { datasetFormMockContext, datasetFormMockResult, defaultFormValue } from "../../features/dataset/dataset_model"; import {
datasetFormMockContext,
datasetFormMockResult,
defaultFormValue,
} from "../../features/dataset/dataset_model";
import { DependencyViewModel } from "./skill_model"; import { DependencyViewModel } from "./skill_model";
import { ValidationModel } from "./validation_model"; import { ValidationModel } from "./validation_model";
import { FormType } from "./form"; import { FormType } from "./form";
import makeAutoObservable from "mobx-store-inheritance"; import makeAutoObservable from "mobx-store-inheritance";
export class FormBuilderValidationModel extends ValidationModel implements DependencyViewModel { export class FormBuilderValidationModel
extends ValidationModel
implements DependencyViewModel
{
@IsNotEmpty() @IsNotEmpty()
@IsString() @IsString()
public result: string; public result: string;
@IsNotEmpty()
@IsString() @IsString()
public context: string; public context: string;
public form: string[]; public form: string[];
@ -28,26 +36,22 @@ export class FormBuilderValidationModel extends ValidationModel implements Depen
formBuilderValidationModel.context.isEmpty() && formBuilderValidationModel.context.isEmpty() &&
formBuilderValidationModel.result.isEmpty() && formBuilderValidationModel.result.isEmpty() &&
formBuilderValidationModel.form.isEmpty(); formBuilderValidationModel.form.isEmpty();
static test = () => new FormBuilderValidationModel(ffContext, ff1Result, [], ""); static test = () =>
new FormBuilderValidationModel(ffContext, ff1Result, [], "");
static datasetEmpty = () => static datasetEmpty = () =>
new FormBuilderValidationModel(datasetFormMockContext, datasetFormMockResult, [], defaultFormValue);
static empty = () => new FormBuilderValidationModel("", "", [], "");
static emptyTest = () => new FormBuilderValidationModel(``, ``, [], defaultFormValue);
static creteDataSetTest = () => new FormBuilderValidationModel(``, scene, [], "");
static emptySimple = () => new FormBuilderValidationModel("", simpleFormBuilder, [], "");
static eee = () =>
new FormBuilderValidationModel( new FormBuilderValidationModel(
``, datasetFormMockContext,
`{ datasetFormMockResult,
"robot_name": \${ROBOT_NAME:string:rbs_arm},
"pose": {
"position": { "x": \${X:number:0.1}, "y": \${Y:number:0.1}, "z": \${Z:number:0.7} },
"orientation": { "x": \${X:number:0.1}, "y": \${Y:number:0.1}, "z": \${Z:number:0.7} }
}
}`,
[], [],
"" defaultFormValue
); );
static empty = () => new FormBuilderValidationModel("", "", [], "");
static emptyTest = () =>
new FormBuilderValidationModel(``, ``, [], defaultFormValue);
static creteDataSetTest = () =>
new FormBuilderValidationModel(``, scene, [], "");
static emptySimple = () =>
new FormBuilderValidationModel("", simpleFormBuilder, [], "");
static vision = () => static vision = () =>
new FormBuilderValidationModel( new FormBuilderValidationModel(
` `
@ -92,7 +96,6 @@ export class FormBuilderValidationModel extends ValidationModel implements Depen
};`, };`,
` `
{ {
"process":\${<SelectProcess/>:OBJECT:{"type": "OBJECT_DETECTION"},
"datasetObjects":\${<SelectDetail/>:OBJECT:{"details": []}, "datasetObjects":\${<SelectDetail/>:OBJECT:{"details": []},
"typedataset": \${typedataset:Enum<T>:ObjectDetection}, "typedataset": \${typedataset:Enum<T>:ObjectDetection},
"models_randomization":{ "models_randomization":{
@ -139,6 +142,3 @@ export const ff1Result = `{
"empty":\${NAME:string:default}, "empty":\${NAME:string:default},
"params": \${ITEM:Array<ITEM>:[]} "params": \${ITEM:Array<ITEM>:[]}
}`; }`;
// {
// "process":\${<SelectProcess/>:OBJECT:{"type": "OBJECT_DETECTION"}
// }

View file

@ -36,7 +36,7 @@ export interface IWeightsDependency {
export interface IDeviceDependency { export interface IDeviceDependency {
sid: string; sid: string;
} }
export interface IDependency { } export interface IDependency {}
export interface IParam { export interface IParam {
isFilled: boolean; isFilled: boolean;
type: string; type: string;
@ -276,7 +276,7 @@ export class SkillModel extends ValidationModel implements ISkill {
} }
export class SkillDependency implements IDependency { export class SkillDependency implements IDependency {
constructor(public skills: ISkillDependency[]) { } constructor(public skills: ISkillDependency[]) {}
static empty() { static empty() {
return new SkillDependency([]); return new SkillDependency([]);
} }
@ -424,27 +424,24 @@ export class Skills {
.flat(1) .flat(1)
.filter((el) => el !== ""); .filter((el) => el !== "");
getDependencyBySkillLabelAndType = (skillType: string, sid: string): DependencyViewModel => this.skills getDependencyBySkillLabelAndType = (skillType: string, sid: string): DependencyViewModel =>
.reduce<DependencyViewModel[]>((acc, skill) => { this.skills
if (skill.sid?.isEqual(sid)) { .reduce<DependencyViewModel[]>((acc, skill) => {
skill.BTAction.map((action) => { if (skill.sid?.isEqual(sid)) {
action.param.map((param) => { skill.BTAction.map((action) => {
action.param.map((param) => {
if (param.type.isEqual(skillType)) { if (param.type.isEqualR(skillType)) {
acc.push(param?.dependency ?? DependencyViewModel.empty());
}
acc.push(param?.dependency ?? DependencyViewModel.empty()); return param;
} });
return action;
return param;
}); });
return action; }
});
}
return acc; return acc;
}, []) }, [])
.at(0) ?? DependencyViewModel.empty() .at(0) ?? DependencyViewModel.empty();
static isEmpty(model: Skills): Result<void, void> { static isEmpty(model: Skills): Result<void, void> {
if (model.skills.isEmpty()) { if (model.skills.isEmpty()) {
return Result.error(undefined); return Result.error(undefined);

View file

@ -1,4 +1,3 @@
import { message } from "antd";
import { Result } from "../helper/result"; import { Result } from "../helper/result";
import { validate, ValidationError } from "class-validator"; import { validate, ValidationError } from "class-validator";
@ -27,12 +26,4 @@ export class ValidationModel {
return Result.ok(this as unknown as T); return Result.ok(this as unknown as T);
} }
}; };
validMessage = async<T>(): Promise<Result<string, T>> => {
const result = await this.valid<T>();
if (result.isFailure()) {
message.error(result.error);
}
return result;
}
} }

View file

@ -132,7 +132,7 @@ export class CoreHttpRepository extends HttpRepository {
getAssetsActiveProject = async (): Promise<Result<HttpError, Parts[]>> => { getAssetsActiveProject = async (): Promise<Result<HttpError, Parts[]>> => {
return this._jsonRequest<Parts[]>(HttpMethod.GET, "/projects/assets"); return this._jsonRequest<Parts[]>(HttpMethod.GET, "/projects/assets");
}; };
getSceneAsset = (id: string) => getSceneAsset = (id: string) =>
this._jsonToClassInstanceRequest(HttpMethod.GET, `/scenes/by_id?id=${id}`, SceneAsset) as Promise< this._jsonToClassInstanceRequest(HttpMethod.GET, `/scenes/by_id?id=${id}`, SceneAsset) as Promise<
Result<HttpError, SceneAsset> Result<HttpError, SceneAsset>
@ -141,6 +141,5 @@ export class CoreHttpRepository extends HttpRepository {
return this._jsonRequest<UUID>(HttpMethod.GET, "/projects/get/active/project/id"); return this._jsonRequest<UUID>(HttpMethod.GET, "/projects/get/active/project/id");
} }
getAllScenes = () => this._jsonRequest<SceneModel[]>(HttpMethod.GET, "/scenes"); getAllScenes = () => this._jsonRequest<SceneModel[]>(HttpMethod.GET, "/scenes");
getAllTopics = () => this._jsonRequest(HttpMethod.GET, `/topics`);
} }

View file

@ -1,27 +1,23 @@
import { Socket, io } from "socket.io-client"; import { Socket, io } from "socket.io-client";
import { Result } from "../helper/result"; import { Result } from "../helper/result";
import { TypedEvent } from "../helper/typed_event"; import { TypedEvent } from "../helper/typed_event";
import { RuntimeModel } from "../../features/behavior_tree_builder/presentation/ui/actions/runtime_actions";
export class SocketRepository extends TypedEvent<any> { export class SocketRepository extends TypedEvent<any> {
serverURL = "ws://localhost:4001"; serverURL = "ws://localhost:4001";
socket: Socket | undefined; socket: Socket | undefined;
async connect(): Promise<Result<boolean, boolean>> { async connect():Promise<Result<boolean, boolean>> {
const socket = io(this.serverURL); const socket = io(this.serverURL);
this.socket = socket; this.socket = socket;
socket.connect(); socket.connect();
socketCoreInstances.forEach((el) => { socket.on('realtime', (d) =>{
socket.on(el.event, (event) => el.emit(event))
})
socket.on('realtime', (d) => {
this.emit({ this.emit({
event: "realtime", event:"realtime",
payload: d payload:d
}) })
}) })
if (socket.connected) { if(socket.connected){
return Result.ok(true) return Result.ok(true)
} }
return Result.error(false) return Result.error(false)
@ -29,15 +25,4 @@ export class SocketRepository extends TypedEvent<any> {
} }
export const socketRepository = new SocketRepository() export const socketRepository = new SocketRepository()
export abstract class SocketCore<T> extends TypedEvent<T> {
abstract event: string
}
export class RunTimeSocketRepository extends SocketCore<RuntimeModel> {
event = 'realtimeV2';
}
export const runTimeSocketRepository = new RunTimeSocketRepository();
const socketCoreInstances: SocketCore<any>[] = [runTimeSocketRepository]

View file

@ -17,7 +17,6 @@ interface IMessage {
errorMessage?: string; errorMessage?: string;
} }
export abstract class UiLoader { export abstract class UiLoader {
navigate?: NavigateFunction;
isLoading = false; isLoading = false;
async httpHelper<T>(callBack: Promise<Result<any, T>>) { async httpHelper<T>(callBack: Promise<Result<any, T>>) {
this.isLoading = true; this.isLoading = true;
@ -76,7 +75,7 @@ export abstract class UiErrorState<T> extends UiLoader {
console.log(error); console.log(error);
}; };
abstract init(navigate?: NavigateFunction): Promise<any>; abstract init(navigate?: NavigateFunction): Promise<any>;
dispose() { } dispose() {}
errors: UiBaseError[] = []; errors: UiBaseError[] = [];
} }
@ -127,17 +126,7 @@ export abstract class FormState<V, E> extends UiErrorState<E> {
loadClassInstance = (instance: ClassConstructor<V>, viewModel: V) => { loadClassInstance = (instance: ClassConstructor<V>, viewModel: V) => {
this.viewModel = plainToInstance(instance, viewModel); this.viewModel = plainToInstance(instance, viewModel);
}; };
isModalOpen: boolean = false;
modalShow = () => {
this.isModalOpen = true;
};
modalClickOk = () => {
this.isModalOpen = false;
};
modalCancel = () => {
this.isModalOpen = false;
};
} }

View file

@ -7,20 +7,20 @@ export const DrawerV2: React.FC<{
title?: string; title?: string;
onClose: () => void; onClose: () => void;
children: React.ReactNode; children: React.ReactNode;
width?: number; }> = ({ isOpen, onClose, children, title }) => {
}> = ({ isOpen, onClose, children, title, width }) => {
return ( return (
<div <div
style={{ style={{
position: "fixed", position: "fixed",
top: 0, top: 0,
right: isOpen ? 0 : (width ?? 300) * -1, right: isOpen ? 0 : -300,
width: width ?? 300, width: 300,
height: "100%", height: "100%",
backgroundColor: "#880ef8", backgroundColor: themeStore.theme.darkSurface,
boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.5)", boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.5)",
transition: "right 0.3s ease", transition: "right 0.3s ease",
zIndex: 1000, zIndex: 1000,
}} }}
> >
<div style={{ height: "100%", width: "100%" }}> <div style={{ height: "100%", width: "100%" }}>

View file

@ -1,5 +1,9 @@
import * as React from "react"; import * as React from "react";
import { FormViewModel, InputBuilderViewModel, InputType } from "./form_view_model"; import {
FormViewModel,
InputBuilderViewModel,
InputType,
} from "./form_view_model";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { FormBuilderStore } from "./form_builder_store"; import { FormBuilderStore } from "./form_builder_store";
import { CoreSelect } from "../select/select"; import { CoreSelect } from "../select/select";
@ -9,162 +13,219 @@ import { CoreText, CoreTextType } from "../text/text";
import { getFormBuilderComponents } from "./forms/form_builder_components"; import { getFormBuilderComponents } from "./forms/form_builder_components";
import { FormBuilderValidationModel } from "../../model/form_builder_validation_model"; import { FormBuilderValidationModel } from "../../model/form_builder_validation_model";
export const FormBuilder = observer( export interface IFormBuilder {
(props: { formBuilder: FormBuilderValidationModel; onChange: (change: FormBuilderValidationModel) => void }) => { formBuilder: FormBuilderValidationModel;
const [store] = React.useState(() => new FormBuilderStore()); onChange: (change: FormBuilderValidationModel) => void;
}
React.useEffect(() => { export const FormBuilder = observer((props: IFormBuilder) => {
store.init(props.formBuilder.context, props.formBuilder.result); const [store] = React.useState(() => new FormBuilderStore());
if (props.formBuilder.form.isNotEmpty()) {
store.formViewModel = new FormViewModel(
props.formBuilder.form.map((el) => InputBuilderViewModel.fromJSON(el)),
props.formBuilder.result,
props.formBuilder.context
);
props.formBuilder.form.map((el) => InputBuilderViewModel.fromJSON(el));
}
store.changerForm.on((event) => {
if (event) props.onChange(event);
});
}, []);
return ( React.useEffect(() => {
<div> store.init(props.formBuilder.context, props.formBuilder.result);
{store.isError ? ( if (props.formBuilder.form.isNotEmpty()) {
<>Error</> store.formViewModel = new FormViewModel(
) : ( props.formBuilder.form.map((el) => InputBuilderViewModel.fromJSON(el)),
<div> props.formBuilder.result,
{store.formViewModel?.inputs?.map((element, index) => { props.formBuilder.context
if (element.type?.isEqual(InputType.ENUM)) { );
const values = element.values as string[]; props.formBuilder.form.map((el) => InputBuilderViewModel.fromJSON(el));
return ( }
<CoreSelect store.changerForm.on((event) => {
key={index} if (event) props.onChange(event);
items={values} });
value={element.totalValue ?? element.defaultValue} }, []);
onChange={(value) => store.changeTotalValue(element.id, value)}
label={element.name}
style={{ margin: 20 }}
/>
);
}
if (element.type?.isEqual(InputType.ARRAY)) {
return (
<div key={index} style={{ border: "1px black solid", margin: 20 }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
margin: 20,
alignItems: "center",
paddingRight: 20,
}}
onClick={() => {
store.open(element.id);
}}
>
<CoreText text={element.name} type={CoreTextType.large} />
<Icon type="PlusCircle" style={{ width: 33 }} />
</div>
{element.isOpen ? ( return (
<div style={{ margin: 20 }}> <div>
{element.totalValue instanceof Array {store.isError ? (
? element.totalValue?.map((subArray, index) => { <>Error</>
return ( ) : (
<div style={{ margin: 20 }}> <div>
<div style={{ display: "flex" }}> {store.formViewModel?.inputs?.map((element, index) => {
<CoreText text={(element.subType ?? "") + ` ${index}`} type={CoreTextType.medium} /> if (element.type?.isEqual(InputType.ENUM)) {
<Icon const values = element.values as string[];
style={{ paddingLeft: 20 }} return (
type="DeleteCircle" <CoreSelect
onClick={() => store.deleteTotalValueSubItem(element.id, index)} key={index}
/> items={values}
</div> value={element.totalValue ?? element.defaultValue}
onChange={(value) =>
store.changeTotalValue(element.id, value)
}
label={element.name}
style={{ margin: 20 }}
/>
);
}
if (element.type?.isEqual(InputType.ARRAY)) {
return (
<div
key={index}
style={{ border: "1px black solid", margin: 20 }}
>
<div
style={{
display: "flex",
justifyContent: "space-between",
margin: 20,
alignItems: "center",
paddingRight: 20,
}}
onClick={() => {
store.open(element.id);
}}
>
<CoreText text={element.name} type={CoreTextType.large} />
<Icon type="PlusCircle" style={{ width: 33 }} />
</div>
{subArray.map((subSubArrayItem: InputBuilderViewModel, subIndex: number) => { {element.isOpen ? (
if (subSubArrayItem.type.isEqual(InputType.ENUM)) { <div style={{ margin: 20 }}>
{element.totalValue instanceof Array
? element.totalValue?.map((subArray, index) => {
return (
<div style={{ margin: 20 }}>
<div style={{ display: "flex" }}>
<CoreText
text={(element.subType ?? "") + ` ${index}`}
type={CoreTextType.medium}
/>
<Icon
style={{ paddingLeft: 20 }}
type="DeleteCircle"
onClick={() =>
store.deleteTotalValueSubItem(
element.id,
index
)
}
/>
</div>
{subArray.map(
(
subSubArrayItem: InputBuilderViewModel,
subIndex: number
) => {
if (
subSubArrayItem.type.isEqual(
InputType.ENUM
)
) {
return ( return (
<> <>
<CoreSelect <CoreSelect
items={subSubArrayItem.values?.map((el) => String(el)) ?? []} items={
value={subSubArrayItem.totalValue ?? subSubArrayItem.defaultValue} subSubArrayItem.values?.map(
onChange={(value) => console.log(subSubArrayItem.id)} (el) => String(el)
) ?? []
}
value={
subSubArrayItem.totalValue ??
subSubArrayItem.defaultValue
}
onChange={(value) => console.log(subSubArrayItem.id)
}
label={element.name} label={element.name}
style={{ margin: 5 }} style={{ margin: 5 }}
/> />
</> </>
); );
} }
if (subSubArrayItem.type.isEqualMany([InputType.NUMBER, InputType.STRING])) if (
subSubArrayItem.type.isEqualMany([
InputType.NUMBER,
InputType.STRING,
])
)
return ( return (
<div> <div>
<CoreInput <CoreInput
isFormBuilder={true}
style={{ margin: 5 }} style={{ margin: 5 }}
onChange={(e) => store.changeTotalSubValue(element.id, subIndex, e, index)} onChange={(e) =>
store.changeTotalSubValue(
element.id,
subIndex,
e,
index
)
}
validation={ validation={
subSubArrayItem.type.isEqual(InputType.NUMBER) subSubArrayItem.type.isEqual(
InputType.NUMBER
)
? (el) => Number().isValid(el) ? (el) => Number().isValid(el)
: undefined : undefined
} }
error="только числа" error="только числа"
value={subSubArrayItem.totalValue ?? subSubArrayItem.defaultValue} value={
subSubArrayItem.totalValue ??
subSubArrayItem.defaultValue
}
label={subSubArrayItem.name} label={subSubArrayItem.name}
/> />
</div> </div>
); );
return <>Error</>; return <>Error</>;
})} }
</div> )}
); </div>
}) );
: null} })
</div> : null}
) : null} </div>
</div> ) : null}
); </div>
} );
}
if (element.type?.isEqualMany([InputType.NUMBER, InputType.STRING])) if (element.type?.isEqualMany([InputType.NUMBER, InputType.STRING]))
return ( return (
<div> <div>
<CoreInput <CoreInput
isFormBuilder={true}
validation={element.type.isEqual(InputType.NUMBER) ? (el) => Number().isValid(el) : undefined} validation={
onChange={(e) => { element.type.isEqual(InputType.NUMBER)
store.changeTotalValue(element.id, e); ? (el) => Number().isValid(el)
}} : undefined
value={element.totalValue ?? element.defaultValue} }
error="только числа" onChange={(e) => {
label={element.name} store.changeTotalValue(element.id, e);
style={{ margin: 20 }} }}
/> value={element.totalValue ?? element.defaultValue}
</div> error="только числа"
); label={element.name}
if (element.type?.isEqual(InputType.OBJECT)) style={{ margin: 20 }}
return ( />
<> </div>
{getFormBuilderComponents( );
element.name.replace(">", "").replace("<", "").replace("/", ""), if (element.type?.isEqual(InputType.OBJECT))
element.totalValue ?? element.defaultValue, return (
(text) => store.changeTotalValue(element.id, text) <>
).fold( {getFormBuilderComponents(
(s) => ( element.name
<>{s}</> .replace(">", "")
), .replace("<", "")
(error) => ( .replace("/", ""),
<>{error}</> element.totalValue ?? element.defaultValue,
) (text) => store.changeTotalValue(element.id, text)
)} ).fold(
</> (s) => (
); <>{s}</>
),
(error) => (
<>{error}</>
)
)}
</>
);
return <div>Error {String(element)}</div>; return <div>Error {String(element)}</div>;
})} })}
</div> </div>
)} )}
</div> </div>
); );
} });
);

View file

@ -95,7 +95,7 @@ export class FormViewModel {
.replace(/[^\x00-\x7F]/g, "") .replace(/[^\x00-\x7F]/g, "")
.replaceAll("\n", "") .replaceAll("\n", "")
.replaceAll("\\", "") .replaceAll("\\", "")
// .replaceAll("/", "") // .replaceAll("/", "")
); );
} catch (error) { } catch (error) {
console.log("ERROR: FormViewModel json() " + result); console.log("ERROR: FormViewModel json() " + result);
@ -190,9 +190,8 @@ export class FormViewModel {
}); });
return result as unknown as string; return result as unknown as string;
} }
static fromString(result: string = '', context: string = ''): Result<void, FormViewModel> { static fromString(result: string, context: string): Result<void, FormViewModel> {
try { try {
if (result.isEmpty() && context.isEmpty()) { if (result.isEmpty() && context.isEmpty()) {
return Result.error(undefined); return Result.error(undefined);
} }

View file

@ -1,10 +1,10 @@
import { Result } from "../../../helper/result"; import { Result } from "../../../helper/result";
import { SelectProcess } from "./select_dataset/presentation/select_process"; import { SelectDatasetScreen } from "./select_dataset/presentation/select_dataset_screen";
import { SelectDetail } from "./select_detail/presentation/select_detail_screen"; import { SelectDetail } from "./select_detail/presentation/select_detail_screen";
export enum FormBuilderComponents { export enum FormBuilderComponents {
SelectDetail = "SelectDetail", SelectDetail = "SelectDetail",
SelectProcess = "SelectProcess", SelectDataset = "SelectDataset",
} }
export interface IFormBuilderComponentsProps<T> { export interface IFormBuilderComponentsProps<T> {
dependency: T; dependency: T;
@ -18,8 +18,8 @@ export const getFormBuilderComponents = (
if (name.isEqual(FormBuilderComponents.SelectDetail)) { if (name.isEqual(FormBuilderComponents.SelectDetail)) {
return Result.ok(<SelectDetail dependency={dependency} onChange={onChange} />); return Result.ok(<SelectDetail dependency={dependency} onChange={onChange} />);
} }
if (name.isEqual(FormBuilderComponents.SelectProcess)) { if (name.isEqual(FormBuilderComponents.SelectDataset)) {
return Result.ok(<SelectProcess dependency={dependency} onChange={onChange} />); return Result.ok(<SelectDatasetScreen dependency={dependency} onChange={onChange} />);
} }
return Result.error(name); return Result.error(name);
}; };

View file

@ -1,5 +0,0 @@
import { CoreHttpRepository, HttpMethod } from "../../../../../repository/core_http_repository";
export class SelectProcessRepository extends CoreHttpRepository {
getAllProcessByType = (type: string) => this._jsonRequest(HttpMethod.POST, '/calculations/instances/get/all/end/calculations', { type: type })
}

View file

@ -1,18 +0,0 @@
import { IsObject, IsString } from "class-validator";
import { ValidationModel } from "../../../../../model/validation_model";
import { CalculationModel } from "../../../../../../features/calculation_instance/model/calculation_model";
export class SelectProcessModel extends ValidationModel {
@IsString()
type: string = '';
@IsObject()
selectProcess?: SelectProcess;
}
export interface SelectProcess {
value: CalculationModel;
}

View file

@ -0,0 +1,6 @@
import { observer } from "mobx-react-lite";
import { IFormBuilderComponentsProps } from "../../form_builder_components";
export const SelectDatasetScreen = observer((props:IFormBuilderComponentsProps<any>) => {
return <>SELECT DATASET</>;
});

View file

@ -1,48 +0,0 @@
import React, { useState } from "react";
import { observer } from "mobx-react-lite";
import { IFormBuilderComponentsProps } from "../../form_builder_components";
import { useStore } from "../../../../../helper/use_store";
import { SelectProcessStore } from "./select_process_store";
import { useEffect } from "react";
import { SelectProcessModel } from "../model/select_process_model";
import { Loader } from "../../../../loader/loader";
import { CoreSelect } from "../../../../select/select";
import { message } from "antd";
import { CalculationModel } from "../../../../../../features/calculation_instance/model/calculation_model";
export const SelectProcess = observer((props: IFormBuilderComponentsProps<SelectProcessModel>) => {
const [store] = useState(new SelectProcessStore());
useEffect(() => {
if (typeof props.dependency === "string") {
store.loadClassInstance(SelectProcessModel, JSON.parse(props.dependency));
} else {
store.loadClassInstance(SelectProcessModel, props.dependency);
}
store.init();
}, []);
return (
<div>
{store.isLoading ? (
<Loader />
) : (
<div>
<CoreSelect
items={store.calculationInstances.map((el) => el.instanceName)}
value={store.viewModel?.selectProcess?.value.instanceName ?? ""}
label={`Процесс тип ${store?.viewModel?.type ?? ""}`}
onChange={async (value: string, index: number) => {
store.updateForm({
selectProcess: { value: store.calculationInstances.at(index) ?? CalculationModel.empty() },
});
(await store.viewModel.valid<SelectProcessModel>()).fold(
(model) => props.onChange(model),
(error) => message.error(error)
);
}}
/>
</div>
)}
</div>
);
});

View file

@ -1,26 +0,0 @@
import { NavigateFunction } from "react-router-dom";
import { FormState } from "../../../../../store/base_store";
import { SelectProcessModel } from "../model/select_process_model";
import { SelectProcessRepository } from "../data/select_process_repository";
import { CalculationModel } from "../../../../../../features/calculation_instance/model/calculation_model";
import makeAutoObservable from "mobx-store-inheritance";
export class SelectProcessStore extends FormState<SelectProcessModel, any> {
selectProcessRepository = new SelectProcessRepository();
viewModel: SelectProcessModel;
calculationInstances: CalculationModel[] = [];
constructor() {
super();
makeAutoObservable(this);
}
async init(navigate?: NavigateFunction | undefined): Promise<any> {
await this.mapOk('calculationInstances', this.selectProcessRepository.getAllProcessByType(this.viewModel.type));
this.calculationInstances = this.calculationInstances.map((el) => {
// @ts-ignore
delete el['formBuilder'];
return el;
})
}
}

View file

@ -1,18 +1,21 @@
// @ts-nocheck
import React from "react"; import React from "react";
import { IFormBuilderComponentsProps } from "../../form_builder_components"; import { IFormBuilderComponentsProps } from "../../form_builder_components";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { ListItem } from "./ui/list_item"; import { ListItem } from "./ui/list_item";
import { SelectDetailStore } from "./select_detail_store"; import { SelectDetailStore } from "./select_detail_store";
import { SelectDetailViewModel } from "../model/select_details_model"; import { SelectDetailViewModel } from "../model/select_details_model";
import { plainToInstance } from "class-transformer";
export const SelectDetail = observer((props: IFormBuilderComponentsProps<SelectDetailViewModel>) => { export const SelectDetail = observer((props: IFormBuilderComponentsProps<SelectDetailViewModel>) => {
const [store] = React.useState(() => new SelectDetailStore()); const [store] = React.useState(() => new SelectDetailStore());
React.useEffect(() => { React.useEffect(() => {
console.log(props.dependency.details);
store.viewModel = new SelectDetailViewModel(props.dependency.details); store.viewModel = new SelectDetailViewModel(props.dependency.details);
store.isLoading = false; store.isLoading = false;
store.init(); store.init();
}, []); }, []);
return ( return (
<div> <div>
{store.isLoading ? ( {store.isLoading ? (

View file

@ -16,6 +16,7 @@ export const ListItem = (props: IListItemProps) => {
backgroundColor: "rgba(254, 247, 255, 1)", backgroundColor: "rgba(254, 247, 255, 1)",
border: "1px #6750a4 solid", border: "1px #6750a4 solid",
width: "100%", width: "100%",
height: 110,
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
alignItems: "center", alignItems: "center",

View file

@ -9,7 +9,7 @@ import { FormBuilder } from "./form_builder";
import makeAutoObservable from "mobx-store-inheritance"; import makeAutoObservable from "mobx-store-inheritance";
class FormBuilderTextStore extends ModalStore { class FormBuilderTextStore extends ModalStore {
viewModel = FormBuilderValidationModel.eee(); viewModel = FormBuilderValidationModel.empty();
constructor() { constructor() {
super(); super();
makeAutoObservable(this); makeAutoObservable(this);
@ -21,7 +21,6 @@ export const FormBuildTest = observer(() => {
return ( return (
<div> <div>
<InputV2 label={"result"} onChange={(text) => (store.viewModel.result = text)} /> <InputV2 label={"result"} onChange={(text) => (store.viewModel.result = text)} />
<InputV2 label={"context"} onChange={(text) => (store.viewModel.context = text)} /> <InputV2 label={"context"} onChange={(text) => (store.viewModel.context = text)} />
<CoreButton text="click" onClick={() => (store.isModalOpen = true)} /> <CoreButton text="click" onClick={() => (store.isModalOpen = true)} />
@ -34,16 +33,15 @@ export const FormBuildTest = observer(() => {
onCancel={() => { onCancel={() => {
store.isModalOpen = false; store.isModalOpen = false;
}} }}
></Modal> >
<div style={{height:50}}/> <FormBuilder
<FormBuilder formBuilder={store.viewModel}
formBuilder={store.viewModel} onChange={(e) => {
onChange={(e) => { console.log(e.output);
console.log(e) // console.log(JSON.stringify(e.output))
// console.log(e.output); }}
console.log(JSON.stringify(e.output)) />
}} </Modal>
/>
</div> </div>
); );
}); });

View file

@ -931,18 +931,6 @@ const getIconSvg = (
/> />
</svg> </svg>
); );
case "3points":
return Result.ok(
<svg
xmlns="http://www.w3.org/2000/svg"
width={width ? width : "20"}
height={height ? height : "20"}
viewBox="0 0 128 512"
>
<path d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z" />
</svg>
);
case "Move": case "Move":
return Result.ok( return Result.ok(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xmlSpace="preserve"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xmlSpace="preserve">

View file

@ -16,6 +16,7 @@ interface IInputProps extends IStyle {
type?: CoreInputType; type?: CoreInputType;
trim?: boolean; trim?: boolean;
styleContentEditable?: React.CSSProperties; styleContentEditable?: React.CSSProperties;
isFormBuilder?: boolean;
} }
export const CoreInput = (props: IInputProps) => { export const CoreInput = (props: IInputProps) => {
@ -28,6 +29,15 @@ export const CoreInput = (props: IInputProps) => {
setAppendInnerText(false); setAppendInnerText(false);
} }
}, [ref, value, isAppendInnerText, setAppendInnerText, props]); }, [ref, value, isAppendInnerText, setAppendInnerText, props]);
// React.useEffect(() => {
// if (props.isFormBuilder) {
// if (ref.current && props.value) {
// ref.current.innerText = value;
// setValue(props.value);
// console.log(props.value);
// }
// }
// }, [props.value]);
const isSmall = props.type !== undefined && props.type.isEqual(CoreInputType.small); const isSmall = props.type !== undefined && props.type.isEqual(CoreInputType.small);
return ( return (

View file

@ -2,16 +2,15 @@ import { themeStore } from "../../..";
import { Icon } from "../icons/icons"; import { Icon } from "../icons/icons";
import { CoreText, CoreTextType, FontType } from "../text/text"; import { CoreText, CoreTextType, FontType } from "../text/text";
export const InputV2: React.FC<{ interface InputV2Props {
style?: React.CSSProperties;
label: string; label: string;
value?: string; value?: string;
trim?: boolean; trim?: boolean;
validation?: (value: string) => boolean;
error?: string;
height?: number; height?: number;
onChange?: (text: string) => void; onChange?: (text: string) => void;
}> = ({ label, height, value, onChange, trim }) => {
}
export const InputV2: React.FC<InputV2Props> = ({ label, height, value, onChange, trim }) => {
return ( return (
<div <div
style={{ style={{

View file

@ -107,7 +107,7 @@ export const MainPageV2: React.FC<{
overflow: "auto", overflow: "auto",
}} }}
> >
{/* <div <div
style={{ style={{
alignSelf: "center", alignSelf: "center",
width: 645, width: 645,
@ -222,7 +222,7 @@ export const MainPageV2: React.FC<{
> >
{rightChild} {rightChild}
</div> </div>
</div> */} </div>
<div style={Object.assign({ width: "100%" }, style)}>{children}</div> <div style={Object.assign({ width: "100%" }, style)}>{children}</div>
</div> </div>

View file

@ -1,46 +0,0 @@
import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";
interface PopoverProps {
content: React.ReactNode;
children: React.ReactNode;
}
const PopoverV2: React.FC<PopoverProps> = ({ content, children }) => {
const [visible, setVisible] = useState(false);
const ref = useRef<HTMLDivElement>(null);
const togglePopover = () => {
setVisible((prev) => !prev);
};
return (
<div
style={{
position: "relative",
display: "inline-block",
}}
onClick={() => togglePopover()}
>
{children}
<div
style={{
position: "absolute",
backgroundColor: "white",
border: "1px solid #ccc;",
borderRadius: "4px",
padding: "10px;",
zIndex: "1000",
transition: "opacity 0.2s ease, visibility 0.2s ease",
opacity: visible ? 1 : 0,
visibility: visible ? "visible" : "hidden",
}}
>
{content}
</div>
</div>
);
};
// visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
// opacity: ${({ visible }) => (visible ? 1 : 0)};
// transition: opacity 0.2s ease, visibility 0.2s ease;
export default PopoverV2;

View file

@ -6,7 +6,7 @@ interface ICoreSelectProps extends IStyle {
items: string[]; items: string[];
value: string; value: string;
label: string; label: string;
onChange: (value: string, index: number) => void; onChange: (value: string) => void;
} }
export const CoreSelect = (props: ICoreSelectProps) => { export const CoreSelect = (props: ICoreSelectProps) => {
const ref = React.useRef<HTMLDivElement>(null); const ref = React.useRef<HTMLDivElement>(null);
@ -52,7 +52,7 @@ export const CoreSelect = (props: ICoreSelectProps) => {
key={i} key={i}
onClick={() => { onClick={() => {
setValue(el); setValue(el);
props.onChange(el, i); props.onChange(el);
}} }}
style={{ style={{
backgroundColor: "rgba(230, 224, 233, 1)", backgroundColor: "rgba(230, 224, 233, 1)",

View file

@ -21,6 +21,7 @@ export class BehaviorTreeBuilderHttpRepository extends CoreHttpRepository {
`${this.featureApi}/by_id?id=${id}`, `${this.featureApi}/by_id?id=${id}`,
BehaviorTreeModel BehaviorTreeModel
) as unknown as Promise<Result<HttpError, BehaviorTreeModel>>; ) as unknown as Promise<Result<HttpError, BehaviorTreeModel>>;
deleteBt = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
editBt = async (model: BehaviorTreeModel) => { editBt = async (model: BehaviorTreeModel) => {
await this._jsonRequest(HttpMethod.POST, `${this.featureApi}/fill/tree`, model); await this._jsonRequest(HttpMethod.POST, `${this.featureApi}/fill/tree`, model);
model.__v = undefined model.__v = undefined

View file

@ -4,15 +4,20 @@ import { createEditor } from "./ui/editor/editor";
import { SkillTree } from "./ui/skill_tree/skill_tree"; import { SkillTree } from "./ui/skill_tree/skill_tree";
import { BehaviorTreeBuilderStore, DrawerState } from "./behavior_tree_builder_store"; import { BehaviorTreeBuilderStore, DrawerState } from "./behavior_tree_builder_store";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { match } from "ts-pattern";
import { Icon } from "../../../core/ui/icons/icons"; import { Icon } from "../../../core/ui/icons/icons";
import { CoreText, CoreTextType } from "../../../core/ui/text/text"; import { CoreText, CoreTextType } from "../../../core/ui/text/text";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { IForms, forms } from "./ui/forms/forms"; import { IForms, forms } from "./ui/forms/forms";
import { ButtonV2, ButtonV2Type } from "../../../core/ui/button/button_v2";
import { CoreCard } from "../../../core/ui/card/card";
import { themeStore } from "../../.."; import { themeStore } from "../../..";
import { CoreModal } from "../../../core/ui/modal/modal";
import { InputV2 } from "../../../core/ui/input/input_v2";
import { SelectV2 } from "../../../core/ui/select/select_v2";
import { MainPageV2 } from "../../../core/ui/pages/main_page_v2"; import { MainPageV2 } from "../../../core/ui/pages/main_page_v2";
import { DrawerV2 } from "../../../core/ui/drawer/drawer"; import { DrawerV2 } from "../../../core/ui/drawer/drawer";
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
import PopoverV2 from "../../../core/ui/popover/popover";
export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path"; export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path";
@ -49,9 +54,7 @@ export const BehaviorTreeBuilderScreen = observer(() => {
if (ref.current) { if (ref.current) {
// @ts-expect-error // @ts-expect-error
const domReact: DOMReact = ref.current.getBoundingClientRect(); const domReact: DOMReact = ref.current.getBoundingClientRect();
store.dragZoneSetOffset(0, domReact.y, domReact.width, domReact.height);
// УБЕРИ + 300
store.dragZoneSetOffset(0, domReact.y, domReact.width + 300, domReact.height);
} }
}, [ref.current]); }, [ref.current]);
@ -63,36 +66,54 @@ export const BehaviorTreeBuilderScreen = observer(() => {
}, []); }, []);
return ( return (
<MainPageV2 <MainPageV2
rightChild={
<>
<div
style={{
width: "100%",
display: "flex",
flexDirection: "row",
justifyContent: "end",
paddingRight: 30,
alignItems: "center",
}}
>
{/* <ButtonV2 style={{ height: 40 }} onClick={() => {}} text="Запуск" textColor={themeStore.theme.black} />
<div style={{ width: 10 }} />
<ButtonV2
style={{ height: 40 }}
onClick={() => {}}
text="Стоп"
type={ButtonV2Type.empty}
textColor={themeStore.theme.greenWhite}
/>
<div style={{ width: 10 }} /> */}
{store.isNeedSaveBtn ? (
<div
style={{
backgroundColor: store.isNeedSaveBtn ? themeStore.theme.greenWhite : undefined,
height: 40,
textAlign: "center",
alignContent: "center",
width: 40,
borderRadius: 100,
}}
>
{store.isNeedSaveBtn ? (
<Icon style={{ height: 21 }} onClick={() => store.onClickSaveBehaviorTree()} type="Floppy" />
) : undefined}
</div>
) : (
<></>
)}
</div>
</>
}
style={{ position: "absolute", height: "100%", overflow: "hidden" }} style={{ position: "absolute", height: "100%", overflow: "hidden" }}
bgColor={themeStore.theme.black} bgColor={themeStore.theme.black}
children={ children={
<> <>
<> <>
<div style={{ position: "absolute", zIndex: 100 }}>
<div
style={{
width: "100%",
display: "flex",
flexDirection: "row",
justifyContent: "end",
paddingRight: 30,
alignItems: "center",
}}
>
<div
style={{
backgroundColor: themeStore.theme.greenWhite,
height: 40,
textAlign: "center",
alignContent: "center",
width: 40,
borderRadius: 100,
}}
>
<Icon style={{ height: 21 }} onClick={() => store.onClickSaveBehaviorTree()} type="Floppy" />
</div>
</div>
</div>
<div <div
style={{ style={{
height: "100%", height: "100%",
@ -139,45 +160,10 @@ export const BehaviorTreeBuilderScreen = observer(() => {
}} }}
/> />
</Panel> </Panel>
{store.panels.map((el, index) => ( <PanelResizeHandle>
<> <div style={{ width: 10, height: "100%", backgroundColor: "beige" }}></div>
<PanelResizeHandle </PanelResizeHandle>
children={ <Panel defaultSize={0}> </Panel>
<>
<div style={{ width: 10, height: "100%", backgroundColor: "beige" }}></div>
</>
}
></PanelResizeHandle>
<Panel
style={{ backgroundColor: "rgb(29, 27, 32)" }}
defaultSize={el.size}
onResize={(size) => store.panelResize(size, index)}
>
<div
style={{
display: "flex",
width: "100%",
justifyContent: "space-between",
backgroundColor: "beige",
}}
>
<PopoverV2
children={<Icon type={"3points"} height={26} />}
content={
<div style={{ width: "max-content", padding: 10 }}>
{store.panelActions.map((el, i) => (
<CoreText type={CoreTextType.medium} text={el.name} onClick={() => el.action(index)} />
))}
</div>
}
/>
<div style={{ color: "black", alignContent: "center", paddingRight: 10 }}>{el.name}</div>
</div>
{el.body}
</Panel>
</>
))}
</PanelGroup> </PanelGroup>
</div> </div>
</> </>
@ -186,17 +172,8 @@ export const BehaviorTreeBuilderScreen = observer(() => {
title={store.titleDrawer} title={store.titleDrawer}
onClose={() => store.editDrawer(DrawerState.editThreadBehaviorTree, false)} onClose={() => store.editDrawer(DrawerState.editThreadBehaviorTree, false)}
isOpen={store.drawers.find((el) => el.name === DrawerState.editThreadBehaviorTree)?.status} isOpen={store.drawers.find((el) => el.name === DrawerState.editThreadBehaviorTree)?.status}
width={window.innerWidth / 2}
> >
<div <div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
height: "100%",
overflow: "auto",
}}
>
<div style={{ height: "100%" }}> <div style={{ height: "100%" }}>
{store.skillTemplates?.getForms(store.selected ?? "").map((formType, index) => {store.skillTemplates?.getForms(store.selected ?? "").map((formType, index) =>
forms( forms(
@ -209,13 +186,11 @@ export const BehaviorTreeBuilderScreen = observer(() => {
) )
.rFind<IForms>((form) => form.name.isEqual(formType)) .rFind<IForms>((form) => form.name.isEqual(formType))
.fold( .fold(
(s) => { (s) => (
return ( <div key={index} style={{ height: "100%" }}>
<div key={index} style={{ flex: 1 }}> {s.component}
{s.component} </div>
</div> ),
);
},
() => ( () => (
<div key={index + "error"} style={{ height: "100%" }}> <div key={index + "error"} style={{ height: "100%" }}>
Error: Unknown form type {formType} Error: Unknown form type {formType}

View file

@ -26,8 +26,6 @@ import { BehaviorTreeModel } from "../model/behavior_tree_model";
import { PrimitiveViewModel, SystemPrimitive } from "../model/primitive_view_model"; import { PrimitiveViewModel, SystemPrimitive } from "../model/primitive_view_model";
import { SceneAsset } from "../../../core/model/scene_asset"; import { SceneAsset } from "../../../core/model/scene_asset";
import { themeStore } from "../../.."; import { themeStore } from "../../..";
import { RunTimeActions } from "./ui/actions/runtime_actions";
import { ITopicModel } from "../../topics/topic_view_model";
interface I2DArea { interface I2DArea {
x: number; x: number;
@ -39,31 +37,8 @@ interface I2DArea {
export enum DrawerState { export enum DrawerState {
editThreadBehaviorTree = "Редактирование", editThreadBehaviorTree = "Редактирование",
} }
interface IActionPanel {
name: string;
selectIsClosePopover?: boolean;
action: (index: number) => void;
}
export class PanelBody {
body?: React.ReactNode;
size: number = 0;
name: string = "выберите тип панели";
constructor(body: React.ReactNode | undefined, name: string | undefined, size: number | undefined) {
makeAutoObservable(this);
if (name) this.name = name;
if (body) this.body = body;
if (size) this.size = size;
}
}
export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeViewModel, CoreError> { export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeViewModel, CoreError> {
panelActions: IActionPanel[] = [
{ name: "Добавить панель", action: () => this.addNewPanel() },
{ name: "Убрать панель", action: (index) => this.removePanel(index) },
{ name: "Runtime", action: (index) => this.changePanel(index, "Runtime", <RunTimeActions />) },
];
sceneAsset?: SceneAsset; sceneAsset?: SceneAsset;
viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty(); viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty();
behaviorTreeModel: BehaviorTreeModel = BehaviorTreeModel.empty(); behaviorTreeModel: BehaviorTreeModel = BehaviorTreeModel.empty();
@ -76,15 +51,15 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
activeProject: string = ""; activeProject: string = "";
behaviorTreeBuilderHttpRepository = new BehaviorTreeBuilderHttpRepository(); behaviorTreeBuilderHttpRepository = new BehaviorTreeBuilderHttpRepository();
canRun = true; canRun = true;
isNeedSaveBtn = true; isNeedSaveBtn = false;
selected: string = ""; selected: string = "";
selectedSid: string = ""; selectedSid: string = "";
nodeBehaviorTree: NodeBehaviorTree[] = []; nodeBehaviorTree: NodeBehaviorTree[] = [];
navigate?: NavigateFunction;
editor?: NodeEditor<Schemes>; editor?: NodeEditor<Schemes>;
areaPlugin?: AreaPlugin<Schemes, AreaExtra>; areaPlugin?: AreaPlugin<Schemes, AreaExtra>;
nodeUpdateObserver?: NodeRerenderObserver; nodeUpdateObserver?: NodeRerenderObserver;
primitiveViewModel: PrimitiveViewModel; primitiveViewModel: PrimitiveViewModel;
topics: ITopicModel[];
skillTree: ISkillView = { skillTree: ISkillView = {
name: "", name: "",
children: [ children: [
@ -95,12 +70,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
}, },
], ],
}; };
panels: PanelBody[] = [new PanelBody(undefined, undefined, undefined)];
addNewPanel = () => this.panels.push(new PanelBody(undefined, undefined, undefined));
removePanel = (index: number) =>
this.panels.length !== 1
? (this.panels = this.panels.filter((_, i) => i !== index))
: message.error("должна быть хоть одна панель");
constructor() { constructor() {
super(DrawerState); super(DrawerState);
makeAutoObservable(this); makeAutoObservable(this);
@ -116,7 +86,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
this.editor = editor; this.editor = editor;
this.areaPlugin = area; this.areaPlugin = area;
}; };
getAllTopics = () => this.filledOutTemplates.topicsStack.plus(this.topics); getAllTopics = () => this.filledOutTemplates.topicsStack;
errorHandingStrategy = (_: CoreError) => {}; errorHandingStrategy = (_: CoreError) => {};
dragEnd = (e: EventTarget) => { dragEnd = (e: EventTarget) => {
@ -132,13 +102,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
}; };
drawSkillCheck = (x: number, y: number, name: string) => { drawSkillCheck = (x: number, y: number, name: string) => {
const drawPoint = { x: x, y: y, w: 1, h: 1 }; const drawPoint = { x: x, y: y, w: 1, h: 1 };
console.log(
drawPoint.x < this.area!.x + this.area!.w &&
drawPoint.x + drawPoint.w > this.area!.x &&
drawPoint.y < this.area!.y + this.area!.h &&
drawPoint.y + drawPoint.h > this.area!.y
);
if ( if (
drawPoint.x < this.area!.x + this.area!.w && drawPoint.x < this.area!.x + this.area!.w &&
drawPoint.x + drawPoint.w > this.area!.x && drawPoint.x + drawPoint.w > this.area!.x &&
@ -152,7 +115,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
name: name, name: name,
id: sid, id: sid,
}); });
this.isNeedSaveBtn = true;
if (!name.isEqualMany(Object.keys(SystemPrimitive))) { if (!name.isEqualMany(Object.keys(SystemPrimitive))) {
this.skillTemplates?.getSkill(name).fold( this.skillTemplates?.getSkill(name).fold(
(skill) => { (skill) => {
@ -216,7 +179,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
await this.mapOk("sceneAsset", this.behaviorTreeBuilderHttpRepository.getSceneAsset(model.sceneId)); await this.mapOk("sceneAsset", this.behaviorTreeBuilderHttpRepository.getSceneAsset(model.sceneId));
this.isLoading = false; this.isLoading = false;
await this.mapOk("topics", this.behaviorTreeBuilderHttpRepository.getAllTopics());
this.reteForceUpdateObserver?.emit(""); this.reteForceUpdateObserver?.emit("");
}, },
async () => { async () => {
@ -244,6 +207,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
) )
).fold( ).fold(
(xml) => { (xml) => {
console.log(xml);
this.behaviorTreeModel.skills = this.filledOutTemplates; this.behaviorTreeModel.skills = this.filledOutTemplates;
this.behaviorTreeModel.scene = NodeBehaviorTree.fromReteScene( this.behaviorTreeModel.scene = NodeBehaviorTree.fromReteScene(
this.editor as NodeEditor<Schemes>, this.editor as NodeEditor<Schemes>,
@ -381,11 +345,4 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
); );
} }
changeSceneViewModel = (text: string) => {}; changeSceneViewModel = (text: string) => {};
changePanel = (index: number, name: string, body?: React.ReactNode) => {
this.panels = this.panels.replacePropIndex({ name: name, body: body }, index);
};
panelResize = (size: number, index: number) => {
this.panels.replacePropIndex({ size: size }, index);
};
} }

View file

@ -1,94 +0,0 @@
import { NavigateFunction, useParams } from "react-router-dom";
import { CoreHttpRepository, HttpMethod } from "../../../../../core/repository/core_http_repository";
import { CoreError, UiErrorState } from "../../../../../core/store/base_store";
import { ProcessStatus } from "../../../../dataset/dataset_model";
import makeAutoObservable from "mobx-store-inheritance";
import { useStore } from "../../../../../core/helper/use_store";
import { Loader } from "../../../../../core/ui/loader/loader";
import { useEffect } from "react";
import {
RunTimeSocketRepository,
runTimeSocketRepository,
} from "../../../../../core/repository/core_socket_repository";
import { observer } from "mobx-react-lite";
interface IPid {
pid: string;
}
export interface RuntimeModel {
[name: string]: { pid: number; status: String };
}
export class RunTimeHttpRepository extends CoreHttpRepository {
feature = "/run_time";
stop = (model: IPid) => this._jsonRequest(HttpMethod.POST, this.feature + "/kill", model);
getStatuses = () => this._jsonRequest<RuntimeModel>(HttpMethod.GET, this.feature + "/status");
execBt = (id: string) => this._jsonRequest(HttpMethod.POST, this.feature + `/exec/bt?id=${id}`);
}
// export class RunTimeSocketRepository extends SockeCore {}
export class RunTimeStore extends UiErrorState<CoreError> {
runTimeHttpRepository: RunTimeHttpRepository = new RunTimeHttpRepository();
runTimeSocketRepository: RunTimeSocketRepository = runTimeSocketRepository;
pageId: string;
runTime?: RuntimeModel = {};
constructor() {
super();
makeAutoObservable(this);
runTimeSocketRepository.on((event) => (console.log(event), (this.runTime = event)));
}
async init(navigate?: NavigateFunction | undefined): Promise<any> {
this.mapOk("runTime", this.runTimeHttpRepository.getStatuses());
this.navigate = navigate;
}
executeBt = () => this.runTimeHttpRepository.execBt(this.pageId);
initParam = (id: string) => (this.pageId = id);
isExecuteBt = (): boolean => {
if (this.runTime === undefined) {
return false;
}
if (
this.runTime["EXEC_BT"] !== undefined &&
this.runTime["EXEC_BT"]["status"] !== undefined &&
this.runTime["EXEC_BT"]["status"] === "endOk"
) {
return false;
}
return true;
};
}
export const RunTimeActions = observer(() => {
const store = useStore(RunTimeStore);
const params = useParams();
useEffect(() => {
store.initParam(params.id as string);
}, []);
return (
<div style={{ width: "100%" }}>
{store.isLoading ? (
<Loader />
) : (
<>
{store.isExecuteBt() ? (
<>
<div
style={{ justifyContent: "center", color: "white", justifySelf: "center" }}
onClick={() => store.executeBt()}
>
Дерево запущено
</div>
</>
) : (
<>
<div
style={{ justifyContent: "center", color: "white", justifySelf: "center" }}
onClick={() => store.executeBt()}
>
Запустить дерево
</div>
</>
)}
</>
)}
</div>
);
});

View file

@ -19,7 +19,7 @@ export const FormBuilderForm = observer((props: IPropsForm<Partial<FormBuilderVa
}, []); }, []);
return ( return (
<div style={{ overflowX: "scroll", height: "100%", flex: 1 }}> <div style={{ overflowX: "scroll", height: "100%" }}>
<div>FormBuilder</div> <div>FormBuilder</div>
{store.isBtScreen ? ( {store.isBtScreen ? (
<div> <div>
@ -27,6 +27,7 @@ export const FormBuilderForm = observer((props: IPropsForm<Partial<FormBuilderVa
formBuilder={store.viewModel} formBuilder={store.viewModel}
onChange={(form) => { onChange={(form) => {
store.viewModel = form; store.viewModel = form;
console.log(form);
}} }}
/> />
<div style={{ height: 100 }} /> <div style={{ height: 100 }} />
@ -80,7 +81,7 @@ export const FormBuilderForm = observer((props: IPropsForm<Partial<FormBuilderVa
store.isModalOpen = false; store.isModalOpen = false;
}} }}
> >
<FormBuilder formBuilder={store.viewModel} onChange={(form) => (console.log(form), props.onChange(form))} /> <FormBuilder formBuilder={store.viewModel} onChange={() => {}} />
</Modal> </Modal>
</> </>
)} )}

View file

@ -4,7 +4,7 @@ import { BehaviorTreeViewModel } from "../behavior_tree_builder/model/behavior_t
export class BehaviorTreeManagerHttpRepository extends CoreHttpRepository { export class BehaviorTreeManagerHttpRepository extends CoreHttpRepository {
featureApi = `/behavior/trees`; featureApi = `/behavior/trees`;
deleteBt = (id: string) => this._jsonRequest(HttpMethod.POST, `${this.featureApi}/delete/bt?id=${id}`); deleteBt = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
saveNewBt = async (model: BehaviorTreeViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model); saveNewBt = async (model: BehaviorTreeViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model);
getAllBtInstances = async () => this._jsonRequest<BehaviorTreeModel[]>(HttpMethod.GET, this.featureApi); getAllBtInstances = async () => this._jsonRequest<BehaviorTreeModel[]>(HttpMethod.GET, this.featureApi);
} }

View file

@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { BehaviorTreeManagerStore } from "./behavior_tree_manager_store"; import { BehaviorTreeManagerStore } from "./behavior_tree_manager_store";
import React, { useEffect } from "react"; import React from "react";
import { useStore } from "../../core/helper/use_store"; import { useStore } from "../../core/helper/use_store";
import { ButtonV2, ButtonV2Type } from "../../core/ui/button/button_v2"; import { ButtonV2, ButtonV2Type } from "../../core/ui/button/button_v2";
import { CoreCard } from "../../core/ui/card/card"; import { CoreCard } from "../../core/ui/card/card";
@ -16,13 +16,13 @@ export const BehaviorTreeManagerScreenPath = "/behavior/tree/manager";
export const BehaviorTreeManagerScreen = observer(() => { export const BehaviorTreeManagerScreen = observer(() => {
const store = useStore(BehaviorTreeManagerStore); const store = useStore(BehaviorTreeManagerStore);
useEffect(() => {}, []);
return ( return (
<> <>
<MainPageV2 <MainPageV2
children={ children={
<> <>
<div style={{ height: "100%", }}> <div style={{ height: "100%", overflowY: "auto", overflowX: "hidden" }}>
<div style={{ height: 20 }} /> <div style={{ height: 20 }} />
<ButtonV2 <ButtonV2
icon={<Icon type={"Plus"} style={{ alignSelf: "center", marginLeft: 10, marginRight: 10 }} />} icon={<Icon type={"Plus"} style={{ alignSelf: "center", marginLeft: 10, marginRight: 10 }} />}
@ -65,13 +65,9 @@ export const BehaviorTreeManagerScreen = observer(() => {
}} }}
/> />
<div style={{ height: 20 }} /> <div style={{ height: 20 }} />
<InputV2 trim={true} label={"Название"} onChange={(text) => store.updateForm({ name: text })} /> <InputV2 trim={true} label={"Название"} onChange={(text) => store.updateForm({ name: text })} />
<div style={{ height: 20 }} /> <div style={{ height: 20 }} />
<InputV2 <InputV2 trim={true} label={"Описание"} onChange={(text) => store.updateForm({ description: text })} />
trim={true}
label={"Описание"}
onChange={(text) => store.updateForm({ description: text })}
/>
<div style={{ height: 20 }} /> <div style={{ height: 20 }} />
<SelectV2 <SelectV2
items={store.scenes?.map((el) => ({ name: el.name, value: el._id })) ?? []} items={store.scenes?.map((el) => ({ name: el.name, value: el._id })) ?? []}

View file

@ -12,6 +12,7 @@ export enum DrawerState {
} }
export class BehaviorTreeManagerStore extends UiDrawerFormState<BehaviorTreeViewModel, CoreError> { export class BehaviorTreeManagerStore extends UiDrawerFormState<BehaviorTreeViewModel, CoreError> {
viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty(); viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty();
navigate?: NavigateFunction;
btTreeModels: BehaviorTreeModel[] = []; btTreeModels: BehaviorTreeModel[] = [];
scenes?: SceneModel[]; scenes?: SceneModel[];
behaviorTreeManagerHttpRepository = new BehaviorTreeManagerHttpRepository(); behaviorTreeManagerHttpRepository = new BehaviorTreeManagerHttpRepository();

View file

@ -14,13 +14,7 @@ export interface ISkils {
} }
export class CalculationHttpRepository extends CoreHttpRepository { export class CalculationHttpRepository extends CoreHttpRepository {
async getLogs(id: string) {
await this._request(HttpMethod.GET, `/logs?id=${id}`)
window.location.href = 'http://localhost:4001/log.txt';
}
featureApi = `/calculations/instances`; featureApi = `/calculations/instances`;
subFeatureApi = `/calculations/template`; subFeatureApi = `/calculations/template`;

View file

@ -4,9 +4,7 @@ import { FormBuilderValidationModel } from "../../../core/model/form_builder_val
export enum ModelMachineLearningTypes { export enum ModelMachineLearningTypes {
OBJECT_DETECTION = "OBJECT_DETECTION", OBJECT_DETECTION = "OBJECT_DETECTION",
POSE_ESTIMATION = "POSE_ESTIMATION", POSE_ESTIMATE = "POSE_ESTIMATE",
BOP_DATASET = "BOP_DATASET",
WEIGHTS = "WEIGHTS",
} }
export class CalculationModel extends ValidationModel { export class CalculationModel extends ValidationModel {

View file

@ -28,6 +28,7 @@ export const CalculationInstanceScreenPath = "/calculation";
export const CalculationInstanceScreen = observer(() => { export const CalculationInstanceScreen = observer(() => {
const store = useStore(CalculationInstanceStore); const store = useStore(CalculationInstanceStore);
return ( return (
<> <>
<MainPage <MainPage
@ -59,9 +60,7 @@ export const CalculationInstanceScreen = observer(() => {
() => store.makeEditProcess(el), () => store.makeEditProcess(el),
() => store.deleteInstance(el._id ?? ""), () => store.deleteInstance(el._id ?? ""),
() => store.execSkill(el._id ?? ""), () => store.execSkill(el._id ?? ""),
() => store.execSkill(el._id ?? ""), () => store.execSkill(el._id ?? "")
() => store.changeProcessStatus(el._id ?? ""),
() => store.getTxtLog(el._id ?? "")
)} )}
</span> </span>
); );
@ -95,10 +94,7 @@ export const CalculationInstanceScreen = observer(() => {
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}> <div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
<FormBuilder <FormBuilder
formBuilder={store.editProcess?.formBuilder ?? FormBuilderValidationModel.empty()} formBuilder={store.editProcess?.formBuilder ?? FormBuilderValidationModel.empty()}
onChange={(formBuilder) => { onChange={(formBuilder) => store.updateForm({ formBuilder: formBuilder })}
console.log(formBuilder);
store.updateForm({ formBuilder: formBuilder });
}}
/> />
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
@ -138,7 +134,7 @@ export const CalculationInstanceScreen = observer(() => {
<CoreSelect <CoreSelect
items={Object.keys(ModelMachineLearningTypes)} items={Object.keys(ModelMachineLearningTypes)}
value={store.viewModel.type} value={store.viewModel.type}
label={"Тип вычисления"} label={"Тип навыка"}
onChange={(text: string) => store.updateForm({ type: text })} onChange={(text: string) => store.updateForm({ type: text })}
/> />
<CoreSelect <CoreSelect
@ -147,16 +143,8 @@ export const CalculationInstanceScreen = observer(() => {
label={"Тип карточки"} label={"Тип карточки"}
onChange={(text: string) => store.updateForm({ card: text })} onChange={(text: string) => store.updateForm({ card: text })}
/> />
<CoreInput <CoreInput label="Имя" onChange={(text) => store.updateForm({ name: text })} />
trim={true} <CoreInput label="Команда для запуска" onChange={(text) => store.updateForm({ script: text })} />
label="Имя"
onChange={(text) => store.updateForm({ name: text.replaceAll("\n", "") })}
/>
<CoreInput
trim={true}
label="Команда для запуска"
onChange={(text) => store.updateForm({ script: text.replaceAll("\n", "") })}
/>
<InputV2 <InputV2
label="FormBuilder Result" label="FormBuilder Result"
onChange={(text) => (store.viewModel.formBuilder.result = text)} onChange={(text) => (store.viewModel.formBuilder.result = text)}
@ -218,7 +206,7 @@ export const CalculationInstanceScreen = observer(() => {
store.isModalOpen = false; store.isModalOpen = false;
}} }}
> >
<FormBuilder formBuilder={store.viewModel.formBuilder} onChange={(e) => {}} /> <FormBuilder formBuilder={store.viewModel.formBuilder} onChange={() => {}} />
</Modal> </Modal>
</> </>
); );

View file

@ -5,7 +5,7 @@ import { Drawer, UiDrawerFormState } from "../../../core/store/base_store";
import { CalculationHttpRepository } from "../data/calculation_http_repository"; import { CalculationHttpRepository } from "../data/calculation_http_repository";
import { message } from "antd"; import { message } from "antd";
import { UUID } from "../../all_projects/data/project_http_repository"; import { UUID } from "../../all_projects/data/project_http_repository";
import { CalculationModel as calculationModel } from "../model/calculation_model"; import { CalculationModel } from "../model/calculation_model";
import { ProcessUpdate, CalculationSocketRepository } from "../data/calculation_socket_repository"; import { ProcessUpdate, CalculationSocketRepository } from "../data/calculation_socket_repository";
import { match } from "ts-pattern"; import { match } from "ts-pattern";
import { plainToInstance } from "class-transformer"; import { plainToInstance } from "class-transformer";
@ -20,17 +20,16 @@ export enum StoreTypes {
empty = "empty", empty = "empty",
} }
export class CalculationInstanceStore extends UiDrawerFormState<calculationModel, HttpError> { export class CalculationInstanceStore extends UiDrawerFormState<CalculationModel, HttpError> {
getTxtLog = (id: string) => this.calculationHttpRepository.getLogs(id);
calculationHttpRepository: CalculationHttpRepository = new CalculationHttpRepository(); calculationHttpRepository: CalculationHttpRepository = new CalculationHttpRepository();
calculationSocketRepository: CalculationSocketRepository = new CalculationSocketRepository(); calculationSocketRepository: CalculationSocketRepository = new CalculationSocketRepository();
activeProjectId?: UUID; activeProjectId?: UUID;
storeType: StoreTypes = StoreTypes.empty; storeType: StoreTypes = StoreTypes.empty;
viewModel: calculationModel = calculationModel.empty(); viewModel: CalculationModel = CalculationModel.empty();
modelTemplate?: calculationModel[]; modelTemplate?: CalculationModel[];
editProcess?: calculationModel; editProcess?: CalculationModel;
calculationInstances?: calculationModel[]; calculationInstances?: CalculationModel[];
selectTemplate?: calculationModel; selectTemplate?: CalculationModel;
titleDrawer: string = DrawersSkill.NEW_SKILL; titleDrawer: string = DrawersSkill.NEW_SKILL;
drawers: Drawer[]; drawers: Drawer[];
isModalOpen: boolean = false; isModalOpen: boolean = false;
@ -42,7 +41,7 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
status: false, status: false,
}; };
}); });
this.viewModel = calculationModel.empty(); this.viewModel = CalculationModel.empty();
this.calculationSocketRepository.on(this.socketUpdate); this.calculationSocketRepository.on(this.socketUpdate);
makeAutoObservable(this); makeAutoObservable(this);
} }
@ -68,9 +67,9 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
successMessage: "Процесс запущен", successMessage: "Процесс запущен",
}); });
setSelectTemplate = (el: calculationModel) => { setSelectTemplate = (el: CalculationModel) => {
this.selectTemplate = el; this.selectTemplate = el;
const instance = plainToInstance(calculationModel, el); const instance = plainToInstance(CalculationModel, el);
instance.instanceName = this?.viewModel.instanceName; instance.instanceName = this?.viewModel.instanceName;
this.viewModel = instance; this.viewModel = instance;
}; };
@ -85,7 +84,7 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
match(this.storeType) match(this.storeType)
.with(StoreTypes.empty, () => {}) .with(StoreTypes.empty, () => {})
.with(StoreTypes.newType, async () => .with(StoreTypes.newType, async () =>
(await this.viewModel.valid<calculationModel>()).fold( (await this.viewModel.valid<CalculationModel>()).fold(
async (model) => { async (model) => {
model.project = this.activeProjectId?.id; model.project = this.activeProjectId?.id;
@ -100,7 +99,7 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
) )
) )
.with(StoreTypes.newModel, async () => { .with(StoreTypes.newModel, async () => {
(await this.viewModel.valid<calculationModel>()).fold( (await this.viewModel.valid<CalculationModel>()).fold(
async (model) => { async (model) => {
delete model._id; delete model._id;
model.project = this.activeProjectId?.id; model.project = this.activeProjectId?.id;
@ -129,30 +128,20 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
saveEdiSkill = async () => { saveEdiSkill = async () => {
this.editDrawer(DrawersSkill.EDIT_SKILL, false); this.editDrawer(DrawersSkill.EDIT_SKILL, false);
(await this.viewModel.valid<calculationModel>()).fold( (await this.viewModel.valid<CalculationModel>()).fold(
async (model) => (await this.calculationHttpRepository.editCalculation(model), await this.init()), async (model) => await this.calculationHttpRepository.editCalculation(model),
async (err) => message.error(err) async (err) => message.error(err)
); );
}; };
makeEditProcess = (el: calculationModel) => { makeEditProcess = (el: CalculationModel) => {
this.editProcess = el; this.editProcess = el;
this.loadClassInstance(calculationModel, el); this.loadClassInstance(CalculationModel, el);
this.editDrawer(DrawersSkill.EDIT_SKILL, true); this.editDrawer(DrawersSkill.EDIT_SKILL, true);
}; };
deleteTemplate = async (el: calculationModel) => { deleteTemplate = async (el: CalculationModel) => {
await this.messageHttp(this.calculationHttpRepository.deleteTemplate(el._id ?? ""), { await this.messageHttp(this.calculationHttpRepository.deleteTemplate(el._id ?? ""), {
successMessage: "Удален", successMessage: "Удален",
}); });
await this.mapOk("modelTemplate", this.calculationHttpRepository.getAllTemplates()); await this.mapOk("modelTemplate", this.calculationHttpRepository.getAllTemplates());
}; };
changeProcessStatus = async (id: string) =>
this!
.calculationInstances!.whereOne((el) => el._id === id)
.map(
async (calculationModel) => (
(calculationModel.isEnd = !calculationModel.isEnd),
await this.calculationHttpRepository.editCalculation(calculationModel),
await this.init(undefined)
)
);
} }

View file

@ -1,6 +1,6 @@
import { match } from "ts-pattern"; import { match } from "ts-pattern";
import { PoseEstimateCard } from "./pose_estimate_card/model_card"; import { PoseEstimateCard } from "./pose_estimate_card/model_card";
import { Dropdown, MenuProps, } from "antd"; import { Dropdown, MenuProps, message } from "antd";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text"; import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
import { IMenuItem } from "../../../../dataset/card_dataset"; import { IMenuItem } from "../../../../dataset/card_dataset";
import { Icon } from "../../../../../core/ui/icons/icons"; import { Icon } from "../../../../../core/ui/icons/icons";
@ -15,9 +15,7 @@ export const getModelCard = (
onEdit: Function, onEdit: Function,
onDelete: Function, onDelete: Function,
onPlay: Function, onPlay: Function,
onPause: Function, onPause: Function
onChangeProcessIsEnd: Function,
onLog: Function
) => { ) => {
const menu: IMenuItem[] = [ const menu: IMenuItem[] = [
{ {
@ -28,10 +26,6 @@ export const getModelCard = (
onClick: () => onDelete(), onClick: () => onDelete(),
name: "Удалить", name: "Удалить",
}, },
{
onClick: () => onChangeProcessIsEnd(),
name: calculationModel.isEnd ? "Вернуть на доработку" : "Завершить",
},
]; ];
const items: MenuProps["items"] = menu.map((el, index) => { const items: MenuProps["items"] = menu.map((el, index) => {
@ -69,8 +63,7 @@ export const getModelCard = (
<Icon <Icon
type="Log" type="Log"
onClick={async () => onClick={async () =>
// window.prompt("Copy to clipboard: Ctrl+C, Enter", calculationModel.lastProcessLogs ?? "Not found logs") window.prompt("Copy to clipboard: Ctrl+C, Enter", calculationModel.lastProcessLogs ?? "Not found logs")
onLog()
} }
/> />
<Icon <Icon

View file

@ -26,6 +26,7 @@ export class PoseEstimateRepository extends HttpRepository {
execAnalyze = (id: string) => this._jsonRequest(HttpMethod.POST, `/run_time/exec/analyze?id=${id}`); execAnalyze = (id: string) => this._jsonRequest(HttpMethod.POST, `/run_time/exec/analyze?id=${id}`);
} }
export class PoseEstimateStore extends UiErrorState<any> { export class PoseEstimateStore extends UiErrorState<any> {
navigate?: NavigateFunction;
poseEstimateRepository = new PoseEstimateRepository(); poseEstimateRepository = new PoseEstimateRepository();
constructor() { constructor() {
super(); super();

View file

@ -12,6 +12,7 @@ import { useStore } from "../../core/helper/use_store";
import { FormBuilder } from "../../core/ui/form_builder/form_builder"; import { FormBuilder } from "../../core/ui/form_builder/form_builder";
import { ButtonV2 } from "../../core/ui/button/button_v2"; import { ButtonV2 } from "../../core/ui/button/button_v2";
import { Result } from "../../core/helper/result"; import { Result } from "../../core/helper/result";
import { plainToInstance } from "class-transformer";
export const isValidJson = <T,>(json: any): Result<string, T> => { export const isValidJson = <T,>(json: any): Result<string, T> => {
try { try {
@ -287,4 +288,3 @@ export const SkillsScreen = observer(() => {
</> </>
); );
}); });

View file

@ -21,7 +21,6 @@ export class TopicViewModel extends ValidationModel {
export interface ITopicModel { export interface ITopicModel {
digitalTwinId?: string; digitalTwinId?: string;
sid?: string; sid?: string;
_id?: string;
name: string; name: string;
type: string; type: string;
} }

View file

@ -1,9 +1,6 @@
import { CoreHttpRepository, HttpMethod, HttpRepository } from "../../core/repository/core_http_repository"; import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
import { TopicViewModel } from "./topic_view_model";
export class TopicsHttpRepository extends CoreHttpRepository { export class TopicsHttpRepository extends HttpRepository {
deleteTopic = (id: any) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
featureApi = "/topics"; featureApi = "/topics";
createTopics = (model: TopicViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model); getAllTopics = () => this._jsonRequest(HttpMethod.GET, this.featureApi);
} }

View file

@ -2,11 +2,6 @@ import React from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { TopicsStore } from "./topics_store"; import { TopicsStore } from "./topics_store";
import { useStore } from "../../core/helper/use_store"; import { useStore } from "../../core/helper/use_store";
import { CoreButton } from "../../core/ui/button/button";
import { CoreModal } from "../../core/ui/modal/modal";
import { InputV2 } from "../../core/ui/input/input_v2";
import { CoreText, CoreTextType } from "../../core/ui/text/text";
import { CoreInput } from "../../core/ui/input/input";
export const TopicsScreenPath = "/topics"; export const TopicsScreenPath = "/topics";
@ -15,43 +10,12 @@ export const TopicsScreen = observer(() => {
return ( return (
<> <>
<div style={{ display: "flex" }}>
<CoreButton text="добавить новый топик" style={{ width: 200 }} onClick={() => store.modalShow()} />
<CoreButton text="импорт топика" style={{ width: 200 }} onClick={() => store.openTopicModal()} />
</div>
{store.topics?.map((el) => ( {store.topics?.map((el) => (
<div style={{ margin: 10, border: "1px solid red" }}> <div style={{ margin: 10, border: "1px solid red" }}>
<CoreText text="Delete" type={CoreTextType.header} onClick={() => store.deleteTopic(el._id ?? "")} />
<CoreText
text="Copy"
type={CoreTextType.header}
onClick={() => window.prompt("Copy to clipboard: Ctrl+C, Enter", JSON.stringify(el))}
/>
<div>{el.name}</div> <div>{el.name}</div>
<div>{el.type}</div> <div>{el.type}</div>
</div> </div>
))} ))}
<CoreModal
isOpen={store.isModalOpen}
onClose={() => store.modalCancel()}
children={
<div>
<InputV2 label={"type"} onChange={(text) => store.updateForm({ type: text })} />
<InputV2 label={"name"} onChange={(text) => store.updateForm({ name: text })} />
<CoreButton text="new" onClick={() => store.createTopic()} />
</div>
}
/>
<CoreModal
isOpen={store.importTopicModal}
onClose={() => store.cancelImportTopicModal()}
children={
<div>
<InputV2 onChange={(text) => store.importTopic(text)} label="import" />
</div>
}
/>
</> </>
); );
}); });

View file

@ -6,35 +6,14 @@ import { NavigateFunction } from "react-router-dom";
import { TopicsHttpRepository } from "./topics_repository"; import { TopicsHttpRepository } from "./topics_repository";
export class TopicsStore extends FormState<TopicModel, HttpError> { export class TopicsStore extends FormState<TopicModel, HttpError> {
importTopic(text: string): void {
this.loadClassInstance(TopicModel, JSON.parse(text))
this.createTopic()
}
viewModel: TopicModel = TopicModel.empty(); viewModel: TopicModel = TopicModel.empty();
topics?: ITopicModel[]; topics?: ITopicModel[];
topicsHttpRepository: TopicsHttpRepository = new TopicsHttpRepository(); topicsHttpRepository: TopicsHttpRepository = new TopicsHttpRepository();
importTopicModal = false;
constructor() { constructor() {
super(); super();
makeAutoObservable(this); makeAutoObservable(this);
} }
init = async (navigate?: NavigateFunction | undefined) => { init = async (navigate?: NavigateFunction | undefined) => {
this.modalCancel();
this.importTopicModal = false;
await this.mapOk("topics", this.topicsHttpRepository.getAllTopics()); await this.mapOk("topics", this.topicsHttpRepository.getAllTopics());
}; };
cancelImportTopicModal = () => {
this.importTopicModal = false;
}
openTopicModal = () => {
this.importTopicModal = true;
}
deleteTopic = async (id: string) => (await (this.topicsHttpRepository.deleteTopic(id))).map(() => this.init());
createTopic = async () =>
(await this.viewModel.validMessage<TopicModel>()).map(async (model) =>
(await this.topicsHttpRepository.createTopics(model)).map(() => this.init())
);
} }

View file

@ -7,7 +7,6 @@ import { RouterProvider } from "react-router-dom";
import { router } from "./core/routers/routers"; import { router } from "./core/routers/routers";
import { configure } from "mobx"; import { configure } from "mobx";
import { ThemeStore } from "./core/store/theme_store"; import { ThemeStore } from "./core/store/theme_store";
import { FormBuildTest } from "./core/ui/form_builder/test";
configure({ configure({
enforceActions: "never", enforceActions: "never",
@ -23,6 +22,5 @@ root.render(
<SocketListener> <SocketListener>
<RouterProvider router={router} /> <RouterProvider router={router} />
</SocketListener> </SocketListener>
{/* <FormBuildTest /> */}
</> </>
); );

View file

@ -1,6 +0,0 @@
{
"_id": "67b43b59ba78351d1a11d74a",
"name": "/rgbd_camera/camera_info",
"type": "sensor_msgs/msg/CameraInfo",
"__v": 0
}

View file

@ -1,6 +0,0 @@
{
"_id": "67b43b20ba78351d1a11d747",
"name": "/rgbd_camera/image",
"type": "sensor_msgs/msg/Image",
"__v": 0
}

View file

@ -1,196 +0,0 @@
"""
NVIDIA from jtremblay@gmail.com
"""
# Networks
import torch
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.utils.data
import torchvision.models as models
class DopeNetwork(nn.Module):
def __init__(
self,
pretrained=False,
numBeliefMap=9,
numAffinity=16,
stop_at_stage=6, # number of stages to process (if less than total number of stages)
):
super(DopeNetwork, self).__init__()
self.stop_at_stage = stop_at_stage
vgg_full = models.vgg19(pretrained=False).features
self.vgg = nn.Sequential()
for i_layer in range(24):
self.vgg.add_module(str(i_layer), vgg_full[i_layer])
# Add some layers
i_layer = 23
self.vgg.add_module(
str(i_layer), nn.Conv2d(512, 256, kernel_size=3, stride=1, padding=1)
)
self.vgg.add_module(str(i_layer + 1), nn.ReLU(inplace=True))
self.vgg.add_module(
str(i_layer + 2), nn.Conv2d(256, 128, kernel_size=3, stride=1, padding=1)
)
self.vgg.add_module(str(i_layer + 3), nn.ReLU(inplace=True))
# print('---Belief------------------------------------------------')
# _2 are the belief map stages
self.m1_2 = DopeNetwork.create_stage(128, numBeliefMap, True)
self.m2_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m3_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m4_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m5_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m6_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
# print('---Affinity----------------------------------------------')
# _1 are the affinity map stages
self.m1_1 = DopeNetwork.create_stage(128, numAffinity, True)
self.m2_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m3_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m4_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m5_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m6_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
def forward(self, x):
"""Runs inference on the neural network"""
out1 = self.vgg(x)
out1_2 = self.m1_2(out1)
out1_1 = self.m1_1(out1)
if self.stop_at_stage == 1:
return [out1_2], [out1_1]
out2 = torch.cat([out1_2, out1_1, out1], 1)
out2_2 = self.m2_2(out2)
out2_1 = self.m2_1(out2)
if self.stop_at_stage == 2:
return [out1_2, out2_2], [out1_1, out2_1]
out3 = torch.cat([out2_2, out2_1, out1], 1)
out3_2 = self.m3_2(out3)
out3_1 = self.m3_1(out3)
if self.stop_at_stage == 3:
return [out1_2, out2_2, out3_2], [out1_1, out2_1, out3_1]
out4 = torch.cat([out3_2, out3_1, out1], 1)
out4_2 = self.m4_2(out4)
out4_1 = self.m4_1(out4)
if self.stop_at_stage == 4:
return [out1_2, out2_2, out3_2, out4_2], [out1_1, out2_1, out3_1, out4_1]
out5 = torch.cat([out4_2, out4_1, out1], 1)
out5_2 = self.m5_2(out5)
out5_1 = self.m5_1(out5)
if self.stop_at_stage == 5:
return [out1_2, out2_2, out3_2, out4_2, out5_2], [
out1_1,
out2_1,
out3_1,
out4_1,
out5_1,
]
out6 = torch.cat([out5_2, out5_1, out1], 1)
out6_2 = self.m6_2(out6)
out6_1 = self.m6_1(out6)
return [out1_2, out2_2, out3_2, out4_2, out5_2, out6_2], [
out1_1,
out2_1,
out3_1,
out4_1,
out5_1,
out6_1,
]
@staticmethod
def create_stage(in_channels, out_channels, first=False):
"""Create the neural network layers for a single stage."""
model = nn.Sequential()
mid_channels = 128
if first:
padding = 1
kernel = 3
count = 6
final_channels = 512
else:
padding = 3
kernel = 7
count = 10
final_channels = mid_channels
# First convolution
model.add_module(
"0",
nn.Conv2d(
in_channels, mid_channels, kernel_size=kernel, stride=1, padding=padding
),
)
# Middle convolutions
i = 1
while i < count - 1:
model.add_module(str(i), nn.ReLU(inplace=True))
i += 1
model.add_module(
str(i),
nn.Conv2d(
mid_channels,
mid_channels,
kernel_size=kernel,
stride=1,
padding=padding,
),
)
i += 1
# Penultimate convolution
model.add_module(str(i), nn.ReLU(inplace=True))
i += 1
model.add_module(
str(i), nn.Conv2d(mid_channels, final_channels, kernel_size=1, stride=1)
)
i += 1
# Last convolution
model.add_module(str(i), nn.ReLU(inplace=True))
i += 1
model.add_module(
str(i), nn.Conv2d(final_channels, out_channels, kernel_size=1, stride=1)
)
i += 1
return model

View file

@ -1,87 +0,0 @@
{
"_id": "67b33b15f3412f3530fdb337",
"bgColor": "rgba(5, 26, 39, 1)",
"borderColor": "rgba(25, 130, 196, 1)",
"SkillPackage": { "name": "Robossembler", "version": "1", "format": "1.0" },
"Module": { "node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8" },
"BTAction": [
{
"name": "odConfigure",
"type": "run",
"param": [
{
"type": "topic",
"dependency": {
"type": "topic",
"topicType": "sensor_msgs/msg/CameraInfo"
},
"isFilled": false
},
{
"type": "topic",
"dependency": {
"type": "topic",
"topicType": "sensor_msgs/msg/Image"
},
"isFilled": false
},
{
"type": "formBuilder",
"dependency": {
"result": "{\"process\":\\${<SelectProcess/>:OBJECT:{\"type\":\"WEIGHTS\"},\"object_name\":\\${object_name:string:}}",
"context": "",
"form": [],
"output": "",
"type": "formBuilder"
},
"isFilled": false
}
],
"typeAction": "ACTION"
},
{
"name": "odStop",
"type": "stop",
"param": [],
"typeAction": "ACTION"
},
{
"name": "isDetectionRun",
"type": "if",
"param": [],
"typeAction": "CONDITION"
},
{
"name": "isDetection",
"type": "if",
"param": [],
"typeAction": "CONDITION"
}
],
"topicsOut": [
{
"name": "lc_yolo/object_detection",
"type": "rbs_skill_interfaces/msg/BoundBox"
},
{
"name": "lc_yolo/detect_image",
"type": "sensor_msgs/msg/Image"
}
],
"Launch": {
"executable": "od_yolo_lc.py",
"package": "rbss_objectdetection"
},
"Settings": {
"result": "{\"params\": \\${ITEM:Array<ITEM>:[]}}",
"context": "type ITEM = {\"name\": \\${NAME:string:default},\"value\": \\${VALUE:string:default}};",
"form": [
"{\"name\":\"ITEM\",\"type\":\"Array\",\"defaultValue\":\"[]\",\"values\":[{\"name\":\"NAME\",\"type\":\"string\",\"defaultValue\":\"default\",\"isOpen\":false,\"id\":\"fa8b442a-101b-448b-b5fd-55ad64f8e578\"},{\"name\":\"VALUE\",\"type\":\"string\",\"defaultValue\":\"default\",\"isOpen\":false,\"id\":\"c59b86d8-a54b-42da-b2bf-5fdfeff7f711\"}],\"totalValue\":[],\"isOpen\":true,\"subType\":\"ITEM\",\"id\":\"8be7af67-5860-4a3f-bdab-09c75a53bff7\"}"
],
"output": {
"params": []
},
"type": "formBuilder"
},
"__v": 0
}

View file

@ -1,64 +0,0 @@
"""
rbs_train2
Общая задача: web-service pipeline
Реализуемая функция: обучение нейросетевой модели по заданному BOP-датасету
python3 $PYTHON_EDUCATION --path /home/user/webservice/server/build/public/process/proc/inst_proc \
--form /home/user/webservice/server/build/public/process/proc/inst_proc/form.json
28.01.2025 @shalenikol release 0.1
17.02.2025 @shalenikol release 0.2 addon_dir
"""
import argparse
import os
import json
from train_Yolo import train_YoloV8
from train_Dope import train_Dope_i
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--path", required=True, help="Output path for weights")
parser.add_argument("--form", required=True, help="Json-file with training parameters")
args = parser.parse_args()
if not os.path.isdir(args.path):
print(f"Invalid output path '{args.path}'")
exit(-1)
wname = os.path.basename(args.path)
outpath = os.path.dirname(args.path)
if not os.path.isfile(args.form):
print(f"Error: no such file '{args.form}'")
exit(-2)
with open(args.form, "r") as f:
j_data = f.read()
try:
cfg = json.loads(j_data)
except json.JSONDecodeError as e:
print(f"JSon error: {e}")
exit(-3)
cfg = cfg["output"] # edited params
dataset_params = cfg["process"]["selectProcess"]["value"]
dataset_type = dataset_params["type"]
if dataset_type != "BOP_DATASET":
print(f"Error: Invalid dataset type '{dataset_type}'")
exit(-4)
dataset_name = dataset_params["instanceName"]
dataset_path = dataset_params["path"]
dataset_path = dataset_path.replace("//", "/") # !!! TODO !!! Nikita
epoch = cfg["n_epoch"]
pretrain = (cfg["pretrain"] == "True") #False
ttype = cfg["typeWeight"] #"ObjectDetection"
addon_dir = ""
if "addon" in cfg:
addon = cfg["addon"].strip()
if addon and os.path.isdir(addon):
addon_dir = addon
if ttype == "ObjectDetection":
train_YoloV8(dataset_path, wname, dataset_name, outpath, epoch, pretrain, addon_dir)
else:
train_Dope_i(dataset_path, wname, dataset_name, outpath, epoch, pretrain)

View file

@ -8,7 +8,6 @@ import blenderproc as bproc
02.05.2024 @shalenikol release 0.1 02.05.2024 @shalenikol release 0.1
02.07.2024 @shalenikol release 0.2 02.07.2024 @shalenikol release 0.2
28.10.2024 @shalenikol release 0.3 28.10.2024 @shalenikol release 0.3
28.02.2025 @shalenikol release 0.4 blenderproc 2.8.0 + blender 4.2.1 LTS
""" """
import numpy as np import numpy as np
import argparse import argparse
@ -17,32 +16,17 @@ import os
import shutil import shutil
import json import json
from pathlib import Path from pathlib import Path
import time
###########################
# !!! чтобы избежать ошибки в версии 2.8.0
# free(): invalid pointer
# при вызове bproc.writer.write_bop
import pyrender
from pyrender.platforms import egl
###########################
start_time = time.time() # Запоминаем время начала
import bpy import bpy
VHACD_PATH = "blenderproc_resources/vhacd" VHACD_PATH = "blenderproc_resources/vhacd"
DIR_MODELS = "models" DIR_MODELS = "models"
# DIR_MESH = "assets/libs/objects/" DIR_MESH = "assets/libs/objects/"
FILE_LOG_SCENE = "res.txt" FILE_LOG_SCENE = "res.txt"
FILE_RBS_INFO = "rbs_info.json" FILE_RBS_INFO = "rbs_info.json"
FILE_GT_COCO = "scene_gt_coco.json" FILE_GT_COCO = "scene_gt_coco.json"
FILE_PARAMS = "form.json" EXT_MODELS = ".fbx"
PROCEDURAL_TEXTURE = "texture_path" # key in randomization params: for texture types (Noise Textures), (Procedural Patterns) or (Tileable Textures)
EXT_MODELS = ".fbx" # for scene objects (floor ...)
DETAIL_KEY = "daeUrl" # "fbx" # key in dict 'Detail' for mesh path of model
TEXTURE_TMPL = "*.jpg" TEXTURE_TMPL = "*.jpg"
TEXTURE_IMAGE_TYPES = ["Base Color", "Metallic", "Normal", "Roughness", "Specular IOR Level"]
Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует
@ -73,50 +57,19 @@ def convert2relative(height, width, bbox):
y += h/2 y += h/2
return x/width, y/height, w/width, h/height return x/width, y/height, w/width, h/height
def convert_seconds(total_seconds):
hours = int(total_seconds // 3600)
minutes = int((total_seconds % 3600) // 60)
seconds = int(total_seconds % 60)
return f"{hours:02}:{minutes:02}:{seconds:02}"
def render() -> int: def render() -> int:
res_dir = rnd_par.output_dir
log_dir = os.path.dirname(res_dir)
# copy file with randomization params
file_params = os.path.join(res_dir, FILE_PARAMS)
if os.path.isfile(file_params):
shutil.copy2(file_params, log_dir)
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
i = 0 i = 0
for obj in all_meshs: for obj in all_meshs:
# Make the object actively participate in the physics simulation # Make the object actively participate in the physics simulation
obj.enable_rigidbody(active=True, collision_shape="COMPOUND") obj.enable_rigidbody(active=True, collision_shape="COMPOUND")
# Also use convex decomposition as collision shapes # Also use convex decomposition as collision shapes
obj.build_convex_decomposition_collision_shape(VHACD_PATH) obj.build_convex_decomposition_collision_shape(VHACD_PATH)
# # это для procedural texture, но пока не правильно
# fn = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".jpg" # файл с текстурой
# if os.path.isfile(fn):
# material = bproc.material.create_material_from_texture(fn, material_name="texture_model"+str(i))
# # Применяем текстуру к материалу
# obj.replace_materials(material)
tex = rnd_par.models.textures[i] # описание текстур
if tex["is"]:
mat = bproc.material.create("m"+str(i))
for x in tex["t_images"]:
key = list(x.keys())[0]
mat.set_principled_shader_value(key, bpy.data.images.load(filepath=x[key]))
obj.replace_materials(mat)
i += 1 i += 1
# print(f"{i} : {obj.get_name()}") # print(f"{i} : {obj.get_name()}")
objs = all_meshs + rnd_par.scene.objs objs = all_meshs + rnd_par.scene.objs
log_txt = os.path.join(log_dir, FILE_LOG_SCENE) log_txt = os.path.join(os.path.dirname(rnd_par.output_dir), FILE_LOG_SCENE)
with open(log_txt, "w") as fh: with open(log_txt, "w") as fh:
for i,o in enumerate(objs): for i,o in enumerate(objs):
loc = o.get_location() loc = o.get_location()
@ -138,21 +91,23 @@ def render() -> int:
rnd_par.image_size_wh[1], rnd_par.image_size_wh[1],
lens_unit="FOV") lens_unit="FOV")
# Enable transparency so the background becomes transparent
bproc.renderer.set_output_format(enable_transparency=True) # ???
# add segmentation masks (per class and per instance) # add segmentation masks (per class and per instance)
bproc.renderer.enable_segmentation_output(map_by=["category_id", "instance", "name"]) bproc.renderer.enable_segmentation_output(map_by=["category_id", "instance", "name"])
# activate depth rendering # activate depth rendering
bproc.renderer.enable_depth_output(activate_antialiasing=False) bproc.renderer.enable_depth_output(activate_antialiasing=False)
# res_dir = os.path.join(rnd_par.output_dir, rnd_par.ds_name)
res_dir = rnd_par.output_dir
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
# Цикл рендеринга # Цикл рендеринга
# Do multiple times: Position the shapenet objects using the physics simulator and render X images with random camera poses # Do multiple times: Position the shapenet objects using the physics simulator and render X images with random camera poses
for r in range(rnd_par.n_series): for r in range(rnd_par.n_series):
print(f"********** Series : {r+1}") print(f"********** Series : {r+1}")
is_texture = True if PROCEDURAL_TEXTURE in rnd_par.models_randomization else False is_texture = True if "texture_path" in rnd_par.models_randomization else False
if is_texture: if is_texture:
val = rnd_par.models_randomization[PROCEDURAL_TEXTURE] val = rnd_par.models_randomization["texture_path"]
l_texture = _get_list_texture(val) l_texture = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(l_texture[r % len(l_texture)])) image = bpy.data.images.load(filepath=str(l_texture[r % len(l_texture)]))
# один случайный объект в кадре / все заданные объекты # один случайный объект в кадре / все заданные объекты
@ -170,32 +125,16 @@ def render() -> int:
for i,o in enumerate(rnd_par.scene.objs): # объекты сцены for i,o in enumerate(rnd_par.scene.objs): # объекты сцены
rnd_mat = rnd_par.scene.obj_data[i]["material_randomization"] rnd_mat = rnd_par.scene.obj_data[i]["material_randomization"]
# if PROCEDURAL_TEXTURE in rnd_mat: # путь к текстурам (*.jpg)
# mat = bproc.material.create("m"+str(i))
# # for x in tex["t_images"]:
# # key = list(x.keys())[0]
# val = rnd_mat[PROCEDURAL_TEXTURE]
# val = _get_list_texture(val)
# image = bpy.data.images.load(filepath=str(random.choice(val)))
# mat.set_principled_shader_value("Base Color", image)
# o.replace_materials(mat)
mats = o.get_materials() #[0] mats = o.get_materials() #[0]
for mat in mats: for mat in mats:
# with open(log_txt, "a") as fh:
# fh.write("************* mat\n")
# fh.write(f"{mat}\n")
val = rnd_mat["specular"] val = rnd_mat["specular"]
mat.set_principled_shader_value("Specular IOR Level", random.uniform(val[0], val[1])) # для Blender < 4.2 было "Specular" mat.set_principled_shader_value("Specular", random.uniform(val[0], val[1]))
val = rnd_mat["roughness"] val = rnd_mat["roughness"]
mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1])) mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1]))
val = rnd_mat["metallic"] val = rnd_mat["metallic"]
mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1])) mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1]))
if PROCEDURAL_TEXTURE in rnd_mat: # путь к текстурам (*.jpg) if "texture_path" in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat[PROCEDURAL_TEXTURE] val = rnd_mat["texture_path"]
val = _get_list_texture(val) val = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(random.choice(val))) image = bpy.data.images.load(filepath=str(random.choice(val)))
mat.set_principled_shader_value("Base Color", image) mat.set_principled_shader_value("Base Color", image)
@ -217,7 +156,7 @@ def render() -> int:
# Define a function that samples 6-DoF poses # Define a function that samples 6-DoF poses
def sample_pose(obj: bproc.types.MeshObject): def sample_pose(obj: bproc.types.MeshObject):
obj.set_location(np.random.uniform(rnd_par.loc_range_low, rnd_par.loc_range_high)) #[-1, -1, 0], [1, 1, 2])) obj.set_location(np.random.uniform(rnd_par.loc_range_low, rnd_par.loc_range_high)) #[-1, -1, 0], [1, 1, 2]))
obj.set_rotation_euler(bproc.sampler.uniformSO3(around_x=rnd_par.around_x, around_y=rnd_par.around_y, around_z=rnd_par.around_z)) obj.set_rotation_euler(bproc.sampler.uniformSO3())
# Sample the poses of all shapenet objects above the ground without any collisions in-between # Sample the poses of all shapenet objects above the ground without any collisions in-between
bproc.object.sample_poses(meshs, bproc.object.sample_poses(meshs,
@ -293,12 +232,7 @@ def render() -> int:
rec["name"] = objn rec["name"] = objn
rec["model"] = os.path.join(DIR_MODELS, os.path.split(rnd_par.models.filenames[i])[1]) # путь относительный rec["model"] = os.path.join(DIR_MODELS, os.path.split(rnd_par.models.filenames[i])[1]) # путь относительный
t = [obj.get_bound_box(local_coords=True).tolist() for obj in all_meshs if obj.get_name() == objn] t = [obj.get_bound_box(local_coords=True).tolist() for obj in all_meshs if obj.get_name() == objn]
if len(t) > 0: rec["cuboid"] = t[0]
rec["cuboid"] = t[0]
else: # object name does not match file name
rec["Error"] = "!!! object name does not match file name: cuboid is zero"
rec["cuboid"] = np.zeros((8, 3)).tolist()
data.append(rec) data.append(rec)
shutil.copy2(rnd_par.models.filenames[i], models_dir) shutil.copy2(rnd_par.models.filenames[i], models_dir)
f = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".mtl" # файл материала f = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".mtl" # файл материала
@ -349,37 +283,9 @@ def render() -> int:
if Not_Categories_Name: if Not_Categories_Name:
explore(res_dir) explore(res_dir)
end_time = time.time() # время окончания
execution_time = end_time - start_time # время выполнения
with open(log_txt, "a") as fh:
fh.write("*****************\n")
fh.write(f"Время выполнения: {convert_seconds(execution_time)}\n")
return 0 # success return 0 # success
def set_texture_model(name: str, textures: list, model_d) -> None: def _get_models(par, data) -> int:
"""
textures заполняется массивом текстур вида:
[{"is": True, "t_images": [{"Base Color":"/path/to/shkaf_d.png"}, {"Normal":"/path/to/shkaf_n.png"}] }, ... ]
"""
d = {"is": False}
if "models" in model_d:
for model in model_d["models"]:
if model["name"] == name:
path = model["texture_dir"].strip()
if path:
t_images = []
for x in TEXTURE_IMAGE_TYPES:
if x in model:
rel_path = model[x].strip()
if rel_path:
t_images.append({x: os.path.join(path, rel_path)})
if len(t_images):
d["is"] = True
d["t_images"] = t_images
textures.append(d)
def _get_models(par, data, models_data) -> int:
global all_meshs global all_meshs
par.models = lambda: None par.models = lambda: None
@ -388,14 +294,13 @@ def _get_models(par, data, models_data) -> int:
return 0 # no models return 0 # no models
# загрузим объекты # загрузим объекты
par.models.names = [] par.models.names = [] # obj_names
par.models.filenames = [] par.models.filenames = [] # obj_filenames
par.models.textures = []
i = 1 i = 1
for f in data: for f in data:
nam = f["name"] nam = f["name"]
par.models.names.append(nam) par.models.names.append(nam)
ff = f[DETAIL_KEY] # _get_path_model(nam) ff = f["fbx"] # _get_path_model(nam)
par.models.filenames.append(ff) par.models.filenames.append(ff)
if not os.path.isfile(ff): if not os.path.isfile(ff):
print(f"Error: no such file '{ff}'") print(f"Error: no such file '{ff}'")
@ -406,7 +311,6 @@ def _get_models(par, data, models_data) -> int:
obj = bproc.loader.load_obj(ff) obj = bproc.loader.load_obj(ff)
all_meshs += obj all_meshs += obj
obj[0].set_cp("category_id", i) # начиная с 1 obj[0].set_cp("category_id", i) # начиная с 1
set_texture_model(nam, par.models.textures, models_data)
i += 1 i += 1
return par.models.n_item return par.models.n_item
@ -466,6 +370,8 @@ if __name__ == "__main__":
print(f"JSon error: {e}") print(f"JSon error: {e}")
exit(-2) exit(-2)
# output_dir = args.path
ds_cfg = cfg["output"] # dataset config ds_cfg = cfg["output"] # dataset config
generation = ds_cfg["generation"] generation = ds_cfg["generation"]
cam_pos = ds_cfg["camera_position"] cam_pos = ds_cfg["camera_position"]
@ -493,14 +399,11 @@ if __name__ == "__main__":
rnd_par.models_randomization = models_randomization rnd_par.models_randomization = models_randomization
rnd_par.loc_range_low = models_randomization["loc_range_low"] rnd_par.loc_range_low = models_randomization["loc_range_low"]
rnd_par.loc_range_high = models_randomization["loc_range_high"] rnd_par.loc_range_high = models_randomization["loc_range_high"]
rnd_par.around_x = (models_randomization["around_x"] == "True")
rnd_par.around_y = (models_randomization["around_y"] == "True")
rnd_par.around_z = (models_randomization["around_z"] == "True")
bproc.init() bproc.init()
all_meshs = [] all_meshs = []
if _get_models(rnd_par, rnd_par.dataset_objs, models_randomization) <= 0: if _get_models(rnd_par, rnd_par.dataset_objs) <= 0:
print("Error: no models in config") print("Error: no models in config")
exit(-4) exit(-4)
if _get_scene(rnd_par, ds_cfg["scene"]) <= 0: if _get_scene(rnd_par, ds_cfg["scene"]) <= 0:

BIN
web_p/train/F1_curve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
web_p/train/PR_curve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
web_p/train/P_curve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
web_p/train/R_curve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

105
web_p/train/args.yaml Normal file
View file

@ -0,0 +1,105 @@
task: detect
mode: train
model: /home/shalenikol/fork_work/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/weights/od_w01/yolov8n.pt
data: /home/shalenikol/fork_work/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/weights/od_w01/rbs_train.yaml
epochs: 33
time: null
patience: 50
batch: 16
imgsz: 640
save: true
save_period: -1
cache: false
device: null
workers: 8
project: /home/shalenikol/fork_work/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/weights/od_w01
name: train
exist_ok: false
pretrained: true
optimizer: auto
verbose: true
seed: 0
deterministic: true
single_cls: false
rect: false
cos_lr: false
close_mosaic: 10
resume: false
amp: true
fraction: 1.0
profile: false
freeze: null
multi_scale: false
overlap_mask: true
mask_ratio: 4
dropout: 0.0
val: true
split: val
save_json: false
save_hybrid: false
conf: null
iou: 0.7
max_det: 300
half: false
dnn: false
plots: true
source: null
vid_stride: 1
stream_buffer: false
visualize: false
augment: false
agnostic_nms: false
classes: null
retina_masks: false
embed: null
show: false
save_frames: false
save_txt: false
save_conf: false
save_crop: false
show_labels: true
show_conf: true
show_boxes: true
line_width: null
format: torchscript
keras: false
optimize: false
int8: false
dynamic: false
simplify: false
opset: null
workspace: 4
nms: false
lr0: 0.01
lrf: 0.01
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
box: 7.5
cls: 0.5
dfl: 1.5
pose: 12.0
kobj: 1.0
label_smoothing: 0.0
nbs: 64
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
degrees: 0.0
translate: 0.1
scale: 0.5
shear: 0.0
perspective: 0.0
flipud: 0.0
fliplr: 0.5
mosaic: 1.0
mixup: 0.0
copy_paste: 0.0
auto_augment: randaugment
erasing: 0.4
crop_fraction: 1.0
cfg: null
tracker: botsort.yaml
save_dir: /home/shalenikol/fork_work/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/weights/od_w01/train

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
web_p/train/labels.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

34
web_p/train/results.csv Normal file
View file

@ -0,0 +1,34 @@
epoch, train/box_loss, train/cls_loss, train/dfl_loss, metrics/precision(B), metrics/recall(B), metrics/mAP50(B), metrics/mAP50-95(B), val/box_loss, val/cls_loss, val/dfl_loss, lr/pg0, lr/pg1, lr/pg2
1, 0.62674, 1.281, 0.92555, 0.99239, 0.99448, 0.99323, 0.90966, 0.40212, 0.8264, 0.80447, 0.00066247, 0.00066247, 0.00066247
2, 0.60996, 0.71899, 0.93387, 0.9945, 0.99945, 0.99484, 0.91551, 0.43253, 0.60301, 0.8228, 0.0012893, 0.0012893, 0.0012893
3, 0.58648, 0.54879, 0.92909, 1, 0.98871, 0.99494, 0.9213, 0.40211, 0.39327, 0.81593, 0.0018761, 0.0018761, 0.0018761
4, 0.58195, 0.48301, 0.92375, 0.99087, 0.9337, 0.97172, 0.89393, 0.41614, 0.46785, 0.82069, 0.00182, 0.00182, 0.00182
5, 0.56201, 0.44926, 0.92381, 0.99447, 0.99385, 0.99494, 0.94951, 0.34807, 0.32406, 0.8013, 0.00182, 0.00182, 0.00182
6, 0.52696, 0.40581, 0.9068, 0.95813, 0.98343, 0.99281, 0.94494, 0.33023, 0.48053, 0.79401, 0.00176, 0.00176, 0.00176
7, 0.51017, 0.3952, 0.90752, 0.99889, 1, 0.995, 0.95388, 0.3192, 0.33973, 0.7992, 0.0017, 0.0017, 0.0017
8, 0.50772, 0.37889, 0.90238, 0.98351, 0.98842, 0.98581, 0.94918, 0.30154, 0.28504, 0.79667, 0.00164, 0.00164, 0.00164
9, 0.47737, 0.3576, 0.89251, 0.99946, 0.99448, 0.995, 0.97205, 0.28135, 0.23642, 0.79101, 0.00158, 0.00158, 0.00158
10, 0.46587, 0.34547, 0.89324, 0.99948, 1, 0.995, 0.96897, 0.28021, 0.28522, 0.78694, 0.00152, 0.00152, 0.00152
11, 0.45881, 0.33452, 0.89055, 0.99954, 1, 0.995, 0.97012, 0.26364, 0.21443, 0.7813, 0.00146, 0.00146, 0.00146
12, 0.44939, 0.32887, 0.89206, 0.9996, 1, 0.995, 0.98382, 0.24486, 0.20614, 0.78109, 0.0014, 0.0014, 0.0014
13, 0.44388, 0.32289, 0.88796, 0.99932, 1, 0.995, 0.97195, 0.27681, 0.21443, 0.77933, 0.00134, 0.00134, 0.00134
14, 0.43847, 0.31282, 0.88496, 0.99965, 1, 0.995, 0.98019, 0.25014, 0.20255, 0.7775, 0.00128, 0.00128, 0.00128
15, 0.41585, 0.30067, 0.8774, 0.99943, 1, 0.995, 0.97609, 0.25842, 0.21239, 0.78006, 0.00122, 0.00122, 0.00122
16, 0.41436, 0.29784, 0.87488, 0.99964, 1, 0.995, 0.97823, 0.25499, 0.19837, 0.78004, 0.00116, 0.00116, 0.00116
17, 0.414, 0.29771, 0.87575, 0.99943, 1, 0.995, 0.98746, 0.2251, 0.203, 0.77468, 0.0011, 0.0011, 0.0011
18, 0.39273, 0.29075, 0.86927, 0.99445, 1, 0.995, 0.98597, 0.22693, 0.19648, 0.77208, 0.00104, 0.00104, 0.00104
19, 0.40052, 0.28802, 0.87804, 0.99958, 1, 0.995, 0.98541, 0.22268, 0.18749, 0.77233, 0.00098, 0.00098, 0.00098
20, 0.38066, 0.27951, 0.86666, 0.99969, 1, 0.995, 0.98901, 0.20959, 0.1775, 0.7697, 0.00092, 0.00092, 0.00092
21, 0.38115, 0.27813, 0.8658, 0.99964, 1, 0.995, 0.98895, 0.20699, 0.1779, 0.77073, 0.00086, 0.00086, 0.00086
22, 0.37441, 0.27094, 0.87121, 0.99965, 1, 0.995, 0.98975, 0.20138, 0.17235, 0.76785, 0.0008, 0.0008, 0.0008
23, 0.36808, 0.26148, 0.86426, 0.99965, 1, 0.995, 0.98829, 0.19861, 0.1628, 0.76706, 0.00074, 0.00074, 0.00074
24, 0.25547, 0.199, 0.77555, 0.99955, 1, 0.995, 0.98791, 0.21853, 0.18063, 0.76972, 0.00068, 0.00068, 0.00068
25, 0.24799, 0.1969, 0.78404, 0.99958, 1, 0.995, 0.98812, 0.23069, 0.18178, 0.76985, 0.00062, 0.00062, 0.00062
26, 0.24232, 0.1915, 0.78022, 0.99968, 1, 0.995, 0.99024, 0.20883, 0.16788, 0.76752, 0.00056, 0.00056, 0.00056
27, 0.23288, 0.1839, 0.77463, 0.99968, 1, 0.995, 0.99151, 0.2026, 0.16501, 0.76809, 0.0005, 0.0005, 0.0005
28, 0.23066, 0.18012, 0.77547, 0.99961, 1, 0.995, 0.98912, 0.19388, 0.1534, 0.76246, 0.00044, 0.00044, 0.00044
29, 0.22286, 0.17062, 0.77932, 0.9997, 1, 0.995, 0.99039, 0.20566, 0.14978, 0.76601, 0.00038, 0.00038, 0.00038
30, 0.21427, 0.16357, 0.77529, 0.9997, 1, 0.995, 0.99215, 0.18345, 0.14148, 0.76206, 0.00032, 0.00032, 0.00032
31, 0.20895, 0.16067, 0.77189, 0.9997, 1, 0.995, 0.99187, 0.17027, 0.13746, 0.76124, 0.00026, 0.00026, 0.00026
32, 0.20248, 0.15421, 0.77526, 0.9997, 1, 0.995, 0.99246, 0.17229, 0.13828, 0.76056, 0.0002, 0.0002, 0.0002
33, 0.19494, 0.15005, 0.76361, 0.99971, 1, 0.995, 0.99302, 0.16442, 0.12543, 0.76043, 0.00014, 0.00014, 0.00014
1 epoch train/box_loss train/cls_loss train/dfl_loss metrics/precision(B) metrics/recall(B) metrics/mAP50(B) metrics/mAP50-95(B) val/box_loss val/cls_loss val/dfl_loss lr/pg0 lr/pg1 lr/pg2
2 1 0.62674 1.281 0.92555 0.99239 0.99448 0.99323 0.90966 0.40212 0.8264 0.80447 0.00066247 0.00066247 0.00066247
3 2 0.60996 0.71899 0.93387 0.9945 0.99945 0.99484 0.91551 0.43253 0.60301 0.8228 0.0012893 0.0012893 0.0012893
4 3 0.58648 0.54879 0.92909 1 0.98871 0.99494 0.9213 0.40211 0.39327 0.81593 0.0018761 0.0018761 0.0018761
5 4 0.58195 0.48301 0.92375 0.99087 0.9337 0.97172 0.89393 0.41614 0.46785 0.82069 0.00182 0.00182 0.00182
6 5 0.56201 0.44926 0.92381 0.99447 0.99385 0.99494 0.94951 0.34807 0.32406 0.8013 0.00182 0.00182 0.00182
7 6 0.52696 0.40581 0.9068 0.95813 0.98343 0.99281 0.94494 0.33023 0.48053 0.79401 0.00176 0.00176 0.00176
8 7 0.51017 0.3952 0.90752 0.99889 1 0.995 0.95388 0.3192 0.33973 0.7992 0.0017 0.0017 0.0017
9 8 0.50772 0.37889 0.90238 0.98351 0.98842 0.98581 0.94918 0.30154 0.28504 0.79667 0.00164 0.00164 0.00164
10 9 0.47737 0.3576 0.89251 0.99946 0.99448 0.995 0.97205 0.28135 0.23642 0.79101 0.00158 0.00158 0.00158
11 10 0.46587 0.34547 0.89324 0.99948 1 0.995 0.96897 0.28021 0.28522 0.78694 0.00152 0.00152 0.00152
12 11 0.45881 0.33452 0.89055 0.99954 1 0.995 0.97012 0.26364 0.21443 0.7813 0.00146 0.00146 0.00146
13 12 0.44939 0.32887 0.89206 0.9996 1 0.995 0.98382 0.24486 0.20614 0.78109 0.0014 0.0014 0.0014
14 13 0.44388 0.32289 0.88796 0.99932 1 0.995 0.97195 0.27681 0.21443 0.77933 0.00134 0.00134 0.00134
15 14 0.43847 0.31282 0.88496 0.99965 1 0.995 0.98019 0.25014 0.20255 0.7775 0.00128 0.00128 0.00128
16 15 0.41585 0.30067 0.8774 0.99943 1 0.995 0.97609 0.25842 0.21239 0.78006 0.00122 0.00122 0.00122
17 16 0.41436 0.29784 0.87488 0.99964 1 0.995 0.97823 0.25499 0.19837 0.78004 0.00116 0.00116 0.00116
18 17 0.414 0.29771 0.87575 0.99943 1 0.995 0.98746 0.2251 0.203 0.77468 0.0011 0.0011 0.0011
19 18 0.39273 0.29075 0.86927 0.99445 1 0.995 0.98597 0.22693 0.19648 0.77208 0.00104 0.00104 0.00104
20 19 0.40052 0.28802 0.87804 0.99958 1 0.995 0.98541 0.22268 0.18749 0.77233 0.00098 0.00098 0.00098
21 20 0.38066 0.27951 0.86666 0.99969 1 0.995 0.98901 0.20959 0.1775 0.7697 0.00092 0.00092 0.00092
22 21 0.38115 0.27813 0.8658 0.99964 1 0.995 0.98895 0.20699 0.1779 0.77073 0.00086 0.00086 0.00086
23 22 0.37441 0.27094 0.87121 0.99965 1 0.995 0.98975 0.20138 0.17235 0.76785 0.0008 0.0008 0.0008
24 23 0.36808 0.26148 0.86426 0.99965 1 0.995 0.98829 0.19861 0.1628 0.76706 0.00074 0.00074 0.00074
25 24 0.25547 0.199 0.77555 0.99955 1 0.995 0.98791 0.21853 0.18063 0.76972 0.00068 0.00068 0.00068
26 25 0.24799 0.1969 0.78404 0.99958 1 0.995 0.98812 0.23069 0.18178 0.76985 0.00062 0.00062 0.00062
27 26 0.24232 0.1915 0.78022 0.99968 1 0.995 0.99024 0.20883 0.16788 0.76752 0.00056 0.00056 0.00056
28 27 0.23288 0.1839 0.77463 0.99968 1 0.995 0.99151 0.2026 0.16501 0.76809 0.0005 0.0005 0.0005
29 28 0.23066 0.18012 0.77547 0.99961 1 0.995 0.98912 0.19388 0.1534 0.76246 0.00044 0.00044 0.00044
30 29 0.22286 0.17062 0.77932 0.9997 1 0.995 0.99039 0.20566 0.14978 0.76601 0.00038 0.00038 0.00038
31 30 0.21427 0.16357 0.77529 0.9997 1 0.995 0.99215 0.18345 0.14148 0.76206 0.00032 0.00032 0.00032
32 31 0.20895 0.16067 0.77189 0.9997 1 0.995 0.99187 0.17027 0.13746 0.76124 0.00026 0.00026 0.00026
33 32 0.20248 0.15421 0.77526 0.9997 1 0.995 0.99246 0.17229 0.13828 0.76056 0.0002 0.0002 0.0002
34 33 0.19494 0.15005 0.76361 0.99971 1 0.995 0.99302 0.16442 0.12543 0.76043 0.00014 0.00014 0.00014

Some files were not shown because too many files have changed in this diff Show more