Compare commits

..

4 commits
dev ... main

117 changed files with 757 additions and 2742 deletions

View file

@ -20,7 +20,6 @@
"GLTF",
"grau",
"idontsudo",
"Pids",
"raycaster",
"skils",
"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
### Миграция данных веб-сервиса
Имеется ввиду перенос данных, хранящихся в БД 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,8 +15,8 @@
"checkCommand": null,
"filter": null
},
"btRuntimeProcess": {
"execCommand": "cd ~/robossembler-ws && source ./install/local_setup.bash; ros2 launch rbs_bt_executor rbs_bt_web.launch.py bt_path:=${bt_path}",
"btBuilderProcess": {
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
"date": null,
"status": null,
"delay": 0,

View file

@ -9,9 +9,6 @@ import { dirname } from "path";
import { CheckAndCreateStaticFilesFolderUseCase } from "../usecases/check_and_create_static_files_folder_usecase";
import { DataBaseConnectUseCase } from "../usecases/database_connect_usecase";
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 {
init = "init",
@ -88,25 +85,7 @@ export class App extends TypedEvent<ServerStatus> {
this.app.use(express.json());
this.app.use(express.urlencoded({ extended: true }));
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(
fileUpload({
createParentPath: true,

View file

@ -234,7 +234,6 @@ export class CoreHttpController<V> implements ICoreHttpController {
return res.json(ok);
},
(err) => {
return res.status(400).json({ error: String(err) });
}
);

View file

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

View file

@ -7,8 +7,9 @@ export abstract class CreateInstanceScenario<V extends Instance> extends Callbac
abstract validationModel: V;
abstract databaseModel: any;
call = async (model: V): ResponseBase => {
model.instancePath = `${model.path.pathNormalize()}/${model.instanceName}`.pathNormalize();
model.path = model.path.pathNormalize();
model.instancePath = `${model.path}/${model.instanceName}`;
console.log("INSTANCE PATh");
console.log(model.instancePath)
return (await new CreateFolderUseCase().call(model.instancePath)).map(
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.on("message", (e) => {
console.log(JSON.stringify(e));
const spawnError = SpawnError.isError(e);
if (spawnError instanceof SpawnError) {

View file

@ -7,7 +7,6 @@ import { ExecutorResult } from "../models/executor_result";
import { ExecutorProgramService } from "../services/executor_program_service";
export const executorProgramService = new ExecutorProgramService("");
export class KillLastProcessUseCase extends CallbackStrategyWithEmpty {
call = async (): Promise<Result<undefined, string>> => {
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 { GetRobotsUseCase } from "./domain/get_robots_usecase";
import { GetTopicsUseCase } from "./domain/get_topics_usecase";
import { DeleteBehaviorTreeScenario } from "./domain/delete_behavior_tree_scenario";
export class BehaviorTreesPresentation extends CrudController<BehaviorTreeValidationModel, typeof BehaviorTreeDBModel> {
constructor() {
@ -46,11 +43,6 @@ export class BehaviorTreesPresentation extends CrudController<BehaviorTreeValida
subUrl: "topics",
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";
export class BehaviorTreeValidationModel implements IBehaviorTreeModel {
_id: string;
@IsString()
public name: string;
@IsMongoId()
public project: string;
public skills: any;
public xml: string;
public project:string;
public skills:any;
public xml:string;
@IsNumber()
public unixTime: number
}

View file

@ -4,8 +4,6 @@ import { CalculationInstanceValidationModel } from "./models/calculations_instan
import { CalculationInstanceDBModel } from "./models/calculations_instance_database_model";
import { CreateCalculationInstanceScenario } from "./domain/create_calculation_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<
CalculationInstanceValidationModel,
@ -20,12 +18,7 @@ export class CalculationsInstancesPresentation extends CrudController<
super.delete(new DeleteCalculationsInstanceScenario().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({
method: "GET",
subUrl: "exec",

View file

@ -7,21 +7,7 @@ import { ProcessWatcherAndDatabaseUpdateService } from "../../datasets/domain/cr
import { CalculationInstanceDBModel, ICalculationInstance } from "../models/calculations_instance_database_model";
import { Result } from "../../../core/helpers/result";
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 {
idValidationExpression = new MongoIdValidation();
call = async (id: string): ResponseBase =>
@ -37,9 +23,13 @@ export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWith
processStatus: "RUN",
lastProcessExecCommand: execCommand,
});
new ExecProcessScenarioV2().call(execCommand, new ExecProcess(model._id))
new ExecProcessUseCase().call(
// @ts-expect-error
`${model.project.rootDir}/`,
execCommand,
id,
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId, CalculationInstanceDBModel)
);
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";
export interface ICalculationInstance {
_id: string;
script: string;
instancePath: string;
formBuilder: FormBuilderValidationModel;
@ -62,7 +61,6 @@ export const CalculationInstanceSchema = new Schema({
instancePath: {
type: String,
},
project: {
type: Schema.Types.ObjectId,
ref: projectSchema,

View file

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

View file

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

View file

@ -21,7 +21,8 @@ export class ExecInstanceScenario extends CallbackStrategyWithIdQuery {
await new ReadByIdDataBaseModelUseCase<IDigitalTwinsInstanceModel>(DigitalTwinsInstanceDatabaseModel).call(id)
).map(
(document) => (
console.log('DOCUMeNT PATH'),
console.log(document.instancePath.pathNormalize()),
new ExecProcessUseCase().call(
document.instancePath,
`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";
export class GetActiveProjectIdScenario extends CallbackStrategyWithEmpty {
call = async (): Promise<Result<any, { id: string }>> => (
async call(): Promise<Result<any, { id: string }>> {
return (
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/";
model.map((el) => {
const assetLibsAddress = assetAddress + "/libs/objects/" + el.name;
console.log(assetLibsAddress);
el.stlUrl = `${assetAddress}${el.part_path}`;
el.glUrl = `${assetLibsAddress}.glb`;
el.daeUrl = `${assetLibsAddress}.dae`;

View file

@ -1,53 +1,7 @@
import {
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";
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
class ProcessWatcher extends ExecProcessWatcher {
async result(): Promise<any> {
console.log(this);
export class ExecBtBuilderUseCase extends CallbackStrategyWithEmpty {
call(): ResponseBase {
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

@ -1,19 +1,42 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { ExecRunTimeCommandValidationModel } from "./model/run_time_validation_model";
import { CoreHttpController, SubRouter, CallbackStrategyWithIdQuery } from "../../core/controllers/http_controller";
import { ExecBtScenario } from "./domain/exec_bt_builder_usecase";
import { GetRunTimeStatuses } from "./domain/get_run_time_statuses_usecase";
import { StopProcessUseCase } from "./domain/stop_process_usecase";
import { ExecRuntimeDatabaseModel } from "./model/run_time_database_model";
import { CoreHttpController, SubRouter, HttpMethodType, CallbackStrategyWithIdQuery, ResponseBase } from "../../core/controllers/http_controller";
import { ExecBtBuilderUseCase } from "./domain/exec_bt_builder_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() {
super({
url: "run_time",
});
this.subRoutes.push(new SubRouter<any>("POST", "exec/bt", new ExecBtScenario()));
this.subRoutes.push(new SubRouter("GET", "status", new GetRunTimeStatuses()));
this.subRoutes.push(new SubRouter<any>("POST", "kill", new StopProcessUseCase()))
this.subRoutes.push(new SubRouter("POST", "/exec/bt/builder", new ExecBtBuilderUseCase()));
this.subRoutes.push(new SubRouter("POST", "/get/bt/builder/state", new GetBtBuilderStateUseCase()));
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 { extensions } from "./core/extensions/extensions";
import { httpRoutes } from "./core/controllers/routes";
import { executorProgramService } from "./core/usecases/exec_process_usecase";
import { executorProgramServiceV2 } from "./core/scenarios/exec_process_scenario_v2";
import { SpawnProcessUseCase, executorProgramService } from "./core/usecases/exec_process_usecase";
import { ProcessWatcher } from "./features/runtime/service/process_watcher";
extensions();
const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime"), new SocketSubscriber(executorProgramServiceV2, 'realtimeV2',)];
const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime")];
new App(httpRoutes, socketSubscribers).listen();

View file

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

View file

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

View file

@ -1,15 +1,23 @@
import { IsNotEmpty, IsString } from "class-validator";
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 { ValidationModel } from "./validation_model";
import { FormType } from "./form";
import makeAutoObservable from "mobx-store-inheritance";
export class FormBuilderValidationModel extends ValidationModel implements DependencyViewModel {
export class FormBuilderValidationModel
extends ValidationModel
implements DependencyViewModel
{
@IsNotEmpty()
@IsString()
public result: string;
@IsNotEmpty()
@IsString()
public context: string;
public form: string[];
@ -28,26 +36,22 @@ export class FormBuilderValidationModel extends ValidationModel implements Depen
formBuilderValidationModel.context.isEmpty() &&
formBuilderValidationModel.result.isEmpty() &&
formBuilderValidationModel.form.isEmpty();
static test = () => new FormBuilderValidationModel(ffContext, ff1Result, [], "");
static test = () =>
new FormBuilderValidationModel(ffContext, ff1Result, [], "");
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(
``,
`{
"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} }
}
}`,
datasetFormMockContext,
datasetFormMockResult,
[],
""
defaultFormValue
);
static empty = () => new FormBuilderValidationModel("", "", [], "");
static emptyTest = () =>
new FormBuilderValidationModel(``, ``, [], defaultFormValue);
static creteDataSetTest = () =>
new FormBuilderValidationModel(``, scene, [], "");
static emptySimple = () =>
new FormBuilderValidationModel("", simpleFormBuilder, [], "");
static vision = () =>
new FormBuilderValidationModel(
`
@ -92,7 +96,6 @@ export class FormBuilderValidationModel extends ValidationModel implements Depen
};`,
`
{
"process":\${<SelectProcess/>:OBJECT:{"type": "OBJECT_DETECTION"},
"datasetObjects":\${<SelectDetail/>:OBJECT:{"details": []},
"typedataset": \${typedataset:Enum<T>:ObjectDetection},
"models_randomization":{
@ -139,6 +142,3 @@ export const ff1Result = `{
"empty":\${NAME:string:default},
"params": \${ITEM:Array<ITEM>:[]}
}`;
// {
// "process":\${<SelectProcess/>:OBJECT:{"type": "OBJECT_DETECTION"}
// }

View file

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

View file

@ -1,4 +1,3 @@
import { message } from "antd";
import { Result } from "../helper/result";
import { validate, ValidationError } from "class-validator";
@ -27,12 +26,4 @@ export class ValidationModel {
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

@ -141,6 +141,5 @@ export class CoreHttpRepository extends HttpRepository {
return this._jsonRequest<UUID>(HttpMethod.GET, "/projects/get/active/project/id");
}
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 { Result } from "../helper/result";
import { TypedEvent } from "../helper/typed_event";
import { RuntimeModel } from "../../features/behavior_tree_builder/presentation/ui/actions/runtime_actions";
export class SocketRepository extends TypedEvent<any> {
serverURL = "ws://localhost:4001";
socket: Socket | undefined;
async connect(): Promise<Result<boolean, boolean>> {
async connect():Promise<Result<boolean, boolean>> {
const socket = io(this.serverURL);
this.socket = socket;
socket.connect();
socketCoreInstances.forEach((el) => {
socket.on(el.event, (event) => el.emit(event))
})
socket.on('realtime', (d) => {
socket.on('realtime', (d) =>{
this.emit({
event: "realtime",
payload: d
event:"realtime",
payload:d
})
})
if (socket.connected) {
if(socket.connected){
return Result.ok(true)
}
return Result.error(false)
@ -30,14 +26,3 @@ export class SocketRepository extends TypedEvent<any> {
}
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;
}
export abstract class UiLoader {
navigate?: NavigateFunction;
isLoading = false;
async httpHelper<T>(callBack: Promise<Result<any, T>>) {
this.isLoading = true;
@ -76,7 +75,7 @@ export abstract class UiErrorState<T> extends UiLoader {
console.log(error);
};
abstract init(navigate?: NavigateFunction): Promise<any>;
dispose() { }
dispose() {}
errors: UiBaseError[] = [];
}
@ -127,17 +126,7 @@ export abstract class FormState<V, E> extends UiErrorState<E> {
loadClassInstance = (instance: ClassConstructor<V>, viewModel: V) => {
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;
onClose: () => void;
children: React.ReactNode;
width?: number;
}> = ({ isOpen, onClose, children, title, width }) => {
}> = ({ isOpen, onClose, children, title }) => {
return (
<div
style={{
position: "fixed",
top: 0,
right: isOpen ? 0 : (width ?? 300) * -1,
width: width ?? 300,
right: isOpen ? 0 : -300,
width: 300,
height: "100%",
backgroundColor: "#880ef8",
backgroundColor: themeStore.theme.darkSurface,
boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.5)",
transition: "right 0.3s ease",
zIndex: 1000,
}}
>
<div style={{ height: "100%", width: "100%" }}>

View file

@ -1,5 +1,9 @@
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 { FormBuilderStore } from "./form_builder_store";
import { CoreSelect } from "../select/select";
@ -9,8 +13,12 @@ import { CoreText, CoreTextType } from "../text/text";
import { getFormBuilderComponents } from "./forms/form_builder_components";
import { FormBuilderValidationModel } from "../../model/form_builder_validation_model";
export const FormBuilder = observer(
(props: { formBuilder: FormBuilderValidationModel; onChange: (change: FormBuilderValidationModel) => void }) => {
export interface IFormBuilder {
formBuilder: FormBuilderValidationModel;
onChange: (change: FormBuilderValidationModel) => void;
}
export const FormBuilder = observer((props: IFormBuilder) => {
const [store] = React.useState(() => new FormBuilderStore());
React.useEffect(() => {
@ -42,7 +50,9 @@ export const FormBuilder = observer(
key={index}
items={values}
value={element.totalValue ?? element.defaultValue}
onChange={(value) => store.changeTotalValue(element.id, value)}
onChange={(value) =>
store.changeTotalValue(element.id, value)
}
label={element.name}
style={{ margin: 20 }}
/>
@ -50,7 +60,10 @@ export const FormBuilder = observer(
}
if (element.type?.isEqual(InputType.ARRAY)) {
return (
<div key={index} style={{ border: "1px black solid", margin: 20 }}>
<div
key={index}
style={{ border: "1px black solid", margin: 20 }}
>
<div
style={{
display: "flex",
@ -74,49 +87,91 @@ export const FormBuilder = observer(
return (
<div style={{ margin: 20 }}>
<div style={{ display: "flex" }}>
<CoreText text={(element.subType ?? "") + ` ${index}`} type={CoreTextType.medium} />
<CoreText
text={(element.subType ?? "") + ` ${index}`}
type={CoreTextType.medium}
/>
<Icon
style={{ paddingLeft: 20 }}
type="DeleteCircle"
onClick={() => store.deleteTotalValueSubItem(element.id, index)}
onClick={() =>
store.deleteTotalValueSubItem(
element.id,
index
)
}
/>
</div>
{subArray.map((subSubArrayItem: InputBuilderViewModel, subIndex: number) => {
if (subSubArrayItem.type.isEqual(InputType.ENUM)) {
{subArray.map(
(
subSubArrayItem: InputBuilderViewModel,
subIndex: number
) => {
if (
subSubArrayItem.type.isEqual(
InputType.ENUM
)
) {
return (
<>
<CoreSelect
items={subSubArrayItem.values?.map((el) => String(el)) ?? []}
value={subSubArrayItem.totalValue ?? subSubArrayItem.defaultValue}
onChange={(value) => console.log(subSubArrayItem.id)}
items={
subSubArrayItem.values?.map(
(el) => String(el)
) ?? []
}
value={
subSubArrayItem.totalValue ??
subSubArrayItem.defaultValue
}
onChange={(value) => console.log(subSubArrayItem.id)
}
label={element.name}
style={{ margin: 5 }}
/>
</>
);
}
if (subSubArrayItem.type.isEqualMany([InputType.NUMBER, InputType.STRING]))
if (
subSubArrayItem.type.isEqualMany([
InputType.NUMBER,
InputType.STRING,
])
)
return (
<div>
<CoreInput
isFormBuilder={true}
style={{ margin: 5 }}
onChange={(e) => store.changeTotalSubValue(element.id, subIndex, e, index)}
onChange={(e) =>
store.changeTotalSubValue(
element.id,
subIndex,
e,
index
)
}
validation={
subSubArrayItem.type.isEqual(InputType.NUMBER)
subSubArrayItem.type.isEqual(
InputType.NUMBER
)
? (el) => Number().isValid(el)
: undefined
}
error="только числа"
value={subSubArrayItem.totalValue ?? subSubArrayItem.defaultValue}
value={
subSubArrayItem.totalValue ??
subSubArrayItem.defaultValue
}
label={subSubArrayItem.name}
/>
</div>
);
return <>Error</>;
})}
}
)}
</div>
);
})
@ -131,8 +186,12 @@ export const FormBuilder = observer(
return (
<div>
<CoreInput
validation={element.type.isEqual(InputType.NUMBER) ? (el) => Number().isValid(el) : undefined}
isFormBuilder={true}
validation={
element.type.isEqual(InputType.NUMBER)
? (el) => Number().isValid(el)
: undefined
}
onChange={(e) => {
store.changeTotalValue(element.id, e);
}}
@ -147,7 +206,10 @@ export const FormBuilder = observer(
return (
<>
{getFormBuilderComponents(
element.name.replace(">", "").replace("<", "").replace("/", ""),
element.name
.replace(">", "")
.replace("<", "")
.replace("/", ""),
element.totalValue ?? element.defaultValue,
(text) => store.changeTotalValue(element.id, text)
).fold(
@ -166,5 +228,4 @@ export const FormBuilder = observer(
)}
</div>
);
}
);
});

View file

@ -190,9 +190,8 @@ export class FormViewModel {
});
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 {
if (result.isEmpty() && context.isEmpty()) {
return Result.error(undefined);
}

View file

@ -1,10 +1,10 @@
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";
export enum FormBuilderComponents {
SelectDetail = "SelectDetail",
SelectProcess = "SelectProcess",
SelectDataset = "SelectDataset",
}
export interface IFormBuilderComponentsProps<T> {
dependency: T;
@ -18,8 +18,8 @@ export const getFormBuilderComponents = (
if (name.isEqual(FormBuilderComponents.SelectDetail)) {
return Result.ok(<SelectDetail dependency={dependency} onChange={onChange} />);
}
if (name.isEqual(FormBuilderComponents.SelectProcess)) {
return Result.ok(<SelectProcess dependency={dependency} onChange={onChange} />);
if (name.isEqual(FormBuilderComponents.SelectDataset)) {
return Result.ok(<SelectDatasetScreen dependency={dependency} onChange={onChange} />);
}
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,13 +1,16 @@
// @ts-nocheck
import React from "react";
import { IFormBuilderComponentsProps } from "../../form_builder_components";
import { observer } from "mobx-react-lite";
import { ListItem } from "./ui/list_item";
import { SelectDetailStore } from "./select_detail_store";
import { SelectDetailViewModel } from "../model/select_details_model";
import { plainToInstance } from "class-transformer";
export const SelectDetail = observer((props: IFormBuilderComponentsProps<SelectDetailViewModel>) => {
const [store] = React.useState(() => new SelectDetailStore());
React.useEffect(() => {
console.log(props.dependency.details);
store.viewModel = new SelectDetailViewModel(props.dependency.details);
store.isLoading = false;
store.init();

View file

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

View file

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

View file

@ -931,18 +931,6 @@ const getIconSvg = (
/>
</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":
return Result.ok(
<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;
trim?: boolean;
styleContentEditable?: React.CSSProperties;
isFormBuilder?: boolean;
}
export const CoreInput = (props: IInputProps) => {
@ -28,6 +29,15 @@ export const CoreInput = (props: IInputProps) => {
setAppendInnerText(false);
}
}, [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);
return (

View file

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

View file

@ -107,7 +107,7 @@ export const MainPageV2: React.FC<{
overflow: "auto",
}}
>
{/* <div
<div
style={{
alignSelf: "center",
width: 645,
@ -222,7 +222,7 @@ export const MainPageV2: React.FC<{
>
{rightChild}
</div>
</div> */}
</div>
<div style={Object.assign({ width: "100%" }, style)}>{children}</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[];
value: string;
label: string;
onChange: (value: string, index: number) => void;
onChange: (value: string) => void;
}
export const CoreSelect = (props: ICoreSelectProps) => {
const ref = React.useRef<HTMLDivElement>(null);
@ -52,7 +52,7 @@ export const CoreSelect = (props: ICoreSelectProps) => {
key={i}
onClick={() => {
setValue(el);
props.onChange(el, i);
props.onChange(el);
}}
style={{
backgroundColor: "rgba(230, 224, 233, 1)",

View file

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

View file

@ -4,15 +4,20 @@ import { createEditor } from "./ui/editor/editor";
import { SkillTree } from "./ui/skill_tree/skill_tree";
import { BehaviorTreeBuilderStore, DrawerState } from "./behavior_tree_builder_store";
import { observer } from "mobx-react-lite";
import { match } from "ts-pattern";
import { Icon } from "../../../core/ui/icons/icons";
import { CoreText, CoreTextType } from "../../../core/ui/text/text";
import { useNavigate, useParams } from "react-router-dom";
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 { 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 { DrawerV2 } from "../../../core/ui/drawer/drawer";
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
import PopoverV2 from "../../../core/ui/popover/popover";
export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path";
@ -49,9 +54,7 @@ export const BehaviorTreeBuilderScreen = observer(() => {
if (ref.current) {
// @ts-expect-error
const domReact: DOMReact = ref.current.getBoundingClientRect();
// УБЕРИ + 300
store.dragZoneSetOffset(0, domReact.y, domReact.width + 300, domReact.height);
store.dragZoneSetOffset(0, domReact.y, domReact.width, domReact.height);
}
}, [ref.current]);
@ -63,12 +66,8 @@ export const BehaviorTreeBuilderScreen = observer(() => {
}, []);
return (
<MainPageV2
style={{ position: "absolute", height: "100%", overflow: "hidden" }}
bgColor={themeStore.theme.black}
children={
rightChild={
<>
<>
<div style={{ position: "absolute", zIndex: 100 }}>
<div
style={{
width: "100%",
@ -79,9 +78,20 @@ export const BehaviorTreeBuilderScreen = observer(() => {
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: themeStore.theme.greenWhite,
backgroundColor: store.isNeedSaveBtn ? themeStore.theme.greenWhite : undefined,
height: 40,
textAlign: "center",
alignContent: "center",
@ -89,10 +99,21 @@ export const BehaviorTreeBuilderScreen = observer(() => {
borderRadius: 100,
}}
>
{store.isNeedSaveBtn ? (
<Icon style={{ height: 21 }} onClick={() => store.onClickSaveBehaviorTree()} type="Floppy" />
) : undefined}
</div>
) : (
<></>
)}
</div>
</div>
</>
}
style={{ position: "absolute", height: "100%", overflow: "hidden" }}
bgColor={themeStore.theme.black}
children={
<>
<>
<div
style={{
height: "100%",
@ -139,45 +160,10 @@ export const BehaviorTreeBuilderScreen = observer(() => {
}}
/>
</Panel>
{store.panels.map((el, index) => (
<>
<PanelResizeHandle
children={
<>
<PanelResizeHandle>
<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>
</>
))}
</PanelResizeHandle>
<Panel defaultSize={0}> </Panel>
</PanelGroup>
</div>
</>
@ -186,17 +172,8 @@ export const BehaviorTreeBuilderScreen = observer(() => {
title={store.titleDrawer}
onClose={() => store.editDrawer(DrawerState.editThreadBehaviorTree, false)}
isOpen={store.drawers.find((el) => el.name === DrawerState.editThreadBehaviorTree)?.status}
width={window.innerWidth / 2}
>
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
height: "100%",
overflow: "auto",
}}
>
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
<div style={{ height: "100%" }}>
{store.skillTemplates?.getForms(store.selected ?? "").map((formType, index) =>
forms(
@ -209,13 +186,11 @@ export const BehaviorTreeBuilderScreen = observer(() => {
)
.rFind<IForms>((form) => form.name.isEqual(formType))
.fold(
(s) => {
return (
<div key={index} style={{ flex: 1 }}>
(s) => (
<div key={index} style={{ height: "100%" }}>
{s.component}
</div>
);
},
),
() => (
<div key={index + "error"} style={{ height: "100%" }}>
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 { SceneAsset } from "../../../core/model/scene_asset";
import { themeStore } from "../../..";
import { RunTimeActions } from "./ui/actions/runtime_actions";
import { ITopicModel } from "../../topics/topic_view_model";
interface I2DArea {
x: number;
@ -39,31 +37,8 @@ interface I2DArea {
export enum DrawerState {
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> {
panelActions: IActionPanel[] = [
{ name: "Добавить панель", action: () => this.addNewPanel() },
{ name: "Убрать панель", action: (index) => this.removePanel(index) },
{ name: "Runtime", action: (index) => this.changePanel(index, "Runtime", <RunTimeActions />) },
];
sceneAsset?: SceneAsset;
viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty();
behaviorTreeModel: BehaviorTreeModel = BehaviorTreeModel.empty();
@ -76,15 +51,15 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
activeProject: string = "";
behaviorTreeBuilderHttpRepository = new BehaviorTreeBuilderHttpRepository();
canRun = true;
isNeedSaveBtn = true;
isNeedSaveBtn = false;
selected: string = "";
selectedSid: string = "";
nodeBehaviorTree: NodeBehaviorTree[] = [];
navigate?: NavigateFunction;
editor?: NodeEditor<Schemes>;
areaPlugin?: AreaPlugin<Schemes, AreaExtra>;
nodeUpdateObserver?: NodeRerenderObserver;
primitiveViewModel: PrimitiveViewModel;
topics: ITopicModel[];
skillTree: ISkillView = {
name: "",
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() {
super(DrawerState);
makeAutoObservable(this);
@ -116,7 +86,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
this.editor = editor;
this.areaPlugin = area;
};
getAllTopics = () => this.filledOutTemplates.topicsStack.plus(this.topics);
getAllTopics = () => this.filledOutTemplates.topicsStack;
errorHandingStrategy = (_: CoreError) => {};
dragEnd = (e: EventTarget) => {
@ -132,13 +102,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
};
drawSkillCheck = (x: number, y: number, name: string) => {
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 (
drawPoint.x < this.area!.x + this.area!.w &&
drawPoint.x + drawPoint.w > this.area!.x &&
@ -152,7 +115,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
name: name,
id: sid,
});
this.isNeedSaveBtn = true;
if (!name.isEqualMany(Object.keys(SystemPrimitive))) {
this.skillTemplates?.getSkill(name).fold(
(skill) => {
@ -216,7 +179,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
await this.mapOk("sceneAsset", this.behaviorTreeBuilderHttpRepository.getSceneAsset(model.sceneId));
this.isLoading = false;
await this.mapOk("topics", this.behaviorTreeBuilderHttpRepository.getAllTopics());
this.reteForceUpdateObserver?.emit("");
},
async () => {
@ -244,6 +207,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
)
).fold(
(xml) => {
console.log(xml);
this.behaviorTreeModel.skills = this.filledOutTemplates;
this.behaviorTreeModel.scene = NodeBehaviorTree.fromReteScene(
this.editor as NodeEditor<Schemes>,
@ -381,11 +345,4 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
);
}
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 (
<div style={{ overflowX: "scroll", height: "100%", flex: 1 }}>
<div style={{ overflowX: "scroll", height: "100%" }}>
<div>FormBuilder</div>
{store.isBtScreen ? (
<div>
@ -27,6 +27,7 @@ export const FormBuilderForm = observer((props: IPropsForm<Partial<FormBuilderVa
formBuilder={store.viewModel}
onChange={(form) => {
store.viewModel = form;
console.log(form);
}}
/>
<div style={{ height: 100 }} />
@ -80,7 +81,7 @@ export const FormBuilderForm = observer((props: IPropsForm<Partial<FormBuilderVa
store.isModalOpen = false;
}}
>
<FormBuilder formBuilder={store.viewModel} onChange={(form) => (console.log(form), props.onChange(form))} />
<FormBuilder formBuilder={store.viewModel} onChange={() => {}} />
</Modal>
</>
)}

View file

@ -4,7 +4,7 @@ import { BehaviorTreeViewModel } from "../behavior_tree_builder/model/behavior_t
export class BehaviorTreeManagerHttpRepository extends CoreHttpRepository {
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);
getAllBtInstances = async () => this._jsonRequest<BehaviorTreeModel[]>(HttpMethod.GET, this.featureApi);
}

View file

@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite";
import { BehaviorTreeManagerStore } from "./behavior_tree_manager_store";
import React, { useEffect } from "react";
import React from "react";
import { useStore } from "../../core/helper/use_store";
import { ButtonV2, ButtonV2Type } from "../../core/ui/button/button_v2";
import { CoreCard } from "../../core/ui/card/card";
@ -16,13 +16,13 @@ export const BehaviorTreeManagerScreenPath = "/behavior/tree/manager";
export const BehaviorTreeManagerScreen = observer(() => {
const store = useStore(BehaviorTreeManagerStore);
useEffect(() => {}, []);
return (
<>
<MainPageV2
children={
<>
<div style={{ height: "100%", }}>
<div style={{ height: "100%", overflowY: "auto", overflowX: "hidden" }}>
<div style={{ height: 20 }} />
<ButtonV2
icon={<Icon type={"Plus"} style={{ alignSelf: "center", marginLeft: 10, marginRight: 10 }} />}
@ -67,11 +67,7 @@ export const BehaviorTreeManagerScreen = observer(() => {
<div style={{ height: 20 }} />
<InputV2 trim={true} label={"Название"} onChange={(text) => store.updateForm({ name: text })} />
<div style={{ height: 20 }} />
<InputV2
trim={true}
label={"Описание"}
onChange={(text) => store.updateForm({ description: text })}
/>
<InputV2 trim={true} label={"Описание"} onChange={(text) => store.updateForm({ description: text })} />
<div style={{ height: 20 }} />
<SelectV2
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> {
viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty();
navigate?: NavigateFunction;
btTreeModels: BehaviorTreeModel[] = [];
scenes?: SceneModel[];
behaviorTreeManagerHttpRepository = new BehaviorTreeManagerHttpRepository();

View file

@ -14,12 +14,6 @@ export interface ISkils {
}
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`;
subFeatureApi = `/calculations/template`;

View file

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

View file

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

View file

@ -5,7 +5,7 @@ import { Drawer, UiDrawerFormState } from "../../../core/store/base_store";
import { CalculationHttpRepository } from "../data/calculation_http_repository";
import { message } from "antd";
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 { match } from "ts-pattern";
import { plainToInstance } from "class-transformer";
@ -20,17 +20,16 @@ export enum StoreTypes {
empty = "empty",
}
export class CalculationInstanceStore extends UiDrawerFormState<calculationModel, HttpError> {
getTxtLog = (id: string) => this.calculationHttpRepository.getLogs(id);
export class CalculationInstanceStore extends UiDrawerFormState<CalculationModel, HttpError> {
calculationHttpRepository: CalculationHttpRepository = new CalculationHttpRepository();
calculationSocketRepository: CalculationSocketRepository = new CalculationSocketRepository();
activeProjectId?: UUID;
storeType: StoreTypes = StoreTypes.empty;
viewModel: calculationModel = calculationModel.empty();
modelTemplate?: calculationModel[];
editProcess?: calculationModel;
calculationInstances?: calculationModel[];
selectTemplate?: calculationModel;
viewModel: CalculationModel = CalculationModel.empty();
modelTemplate?: CalculationModel[];
editProcess?: CalculationModel;
calculationInstances?: CalculationModel[];
selectTemplate?: CalculationModel;
titleDrawer: string = DrawersSkill.NEW_SKILL;
drawers: Drawer[];
isModalOpen: boolean = false;
@ -42,7 +41,7 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
status: false,
};
});
this.viewModel = calculationModel.empty();
this.viewModel = CalculationModel.empty();
this.calculationSocketRepository.on(this.socketUpdate);
makeAutoObservable(this);
}
@ -68,9 +67,9 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
successMessage: "Процесс запущен",
});
setSelectTemplate = (el: calculationModel) => {
setSelectTemplate = (el: CalculationModel) => {
this.selectTemplate = el;
const instance = plainToInstance(calculationModel, el);
const instance = plainToInstance(CalculationModel, el);
instance.instanceName = this?.viewModel.instanceName;
this.viewModel = instance;
};
@ -85,7 +84,7 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
match(this.storeType)
.with(StoreTypes.empty, () => {})
.with(StoreTypes.newType, async () =>
(await this.viewModel.valid<calculationModel>()).fold(
(await this.viewModel.valid<CalculationModel>()).fold(
async (model) => {
model.project = this.activeProjectId?.id;
@ -100,7 +99,7 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
)
)
.with(StoreTypes.newModel, async () => {
(await this.viewModel.valid<calculationModel>()).fold(
(await this.viewModel.valid<CalculationModel>()).fold(
async (model) => {
delete model._id;
model.project = this.activeProjectId?.id;
@ -129,30 +128,20 @@ export class CalculationInstanceStore extends UiDrawerFormState<calculationModel
saveEdiSkill = async () => {
this.editDrawer(DrawersSkill.EDIT_SKILL, false);
(await this.viewModel.valid<calculationModel>()).fold(
async (model) => (await this.calculationHttpRepository.editCalculation(model), await this.init()),
(await this.viewModel.valid<CalculationModel>()).fold(
async (model) => await this.calculationHttpRepository.editCalculation(model),
async (err) => message.error(err)
);
};
makeEditProcess = (el: calculationModel) => {
makeEditProcess = (el: CalculationModel) => {
this.editProcess = el;
this.loadClassInstance(calculationModel, el);
this.loadClassInstance(CalculationModel, el);
this.editDrawer(DrawersSkill.EDIT_SKILL, true);
};
deleteTemplate = async (el: calculationModel) => {
deleteTemplate = async (el: CalculationModel) => {
await this.messageHttp(this.calculationHttpRepository.deleteTemplate(el._id ?? ""), {
successMessage: "Удален",
});
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 { 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 { IMenuItem } from "../../../../dataset/card_dataset";
import { Icon } from "../../../../../core/ui/icons/icons";
@ -15,9 +15,7 @@ export const getModelCard = (
onEdit: Function,
onDelete: Function,
onPlay: Function,
onPause: Function,
onChangeProcessIsEnd: Function,
onLog: Function
onPause: Function
) => {
const menu: IMenuItem[] = [
{
@ -28,10 +26,6 @@ export const getModelCard = (
onClick: () => onDelete(),
name: "Удалить",
},
{
onClick: () => onChangeProcessIsEnd(),
name: calculationModel.isEnd ? "Вернуть на доработку" : "Завершить",
},
];
const items: MenuProps["items"] = menu.map((el, index) => {
@ -69,8 +63,7 @@ export const getModelCard = (
<Icon
type="Log"
onClick={async () =>
// window.prompt("Copy to clipboard: Ctrl+C, Enter", calculationModel.lastProcessLogs ?? "Not found logs")
onLog()
window.prompt("Copy to clipboard: Ctrl+C, Enter", calculationModel.lastProcessLogs ?? "Not found logs")
}
/>
<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}`);
}
export class PoseEstimateStore extends UiErrorState<any> {
navigate?: NavigateFunction;
poseEstimateRepository = new PoseEstimateRepository();
constructor() {
super();

View file

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

View file

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

View file

@ -1,9 +1,6 @@
import { CoreHttpRepository, HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
import { TopicViewModel } from "./topic_view_model";
import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
export class TopicsHttpRepository extends CoreHttpRepository {
deleteTopic = (id: any) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
export class TopicsHttpRepository extends HttpRepository {
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 { TopicsStore } from "./topics_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";
@ -15,43 +10,12 @@ export const TopicsScreen = observer(() => {
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) => (
<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.type}</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";
export class TopicsStore extends FormState<TopicModel, HttpError> {
importTopic(text: string): void {
this.loadClassInstance(TopicModel, JSON.parse(text))
this.createTopic()
}
viewModel: TopicModel = TopicModel.empty();
topics?: ITopicModel[];
topicsHttpRepository: TopicsHttpRepository = new TopicsHttpRepository();
importTopicModal = false;
constructor() {
super();
makeAutoObservable(this);
}
init = async (navigate?: NavigateFunction | undefined) => {
this.modalCancel();
this.importTopicModal = false;
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 { configure } from "mobx";
import { ThemeStore } from "./core/store/theme_store";
import { FormBuildTest } from "./core/ui/form_builder/test";
configure({
enforceActions: "never",
@ -23,6 +22,5 @@ root.render(
<SocketListener>
<RouterProvider router={router} />
</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.07.2024 @shalenikol release 0.2
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 argparse
@ -17,32 +16,17 @@ import os
import shutil
import json
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
VHACD_PATH = "blenderproc_resources/vhacd"
DIR_MODELS = "models"
# DIR_MESH = "assets/libs/objects/"
DIR_MESH = "assets/libs/objects/"
FILE_LOG_SCENE = "res.txt"
FILE_RBS_INFO = "rbs_info.json"
FILE_GT_COCO = "scene_gt_coco.json"
FILE_PARAMS = "form.json"
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
EXT_MODELS = ".fbx"
TEXTURE_TMPL = "*.jpg"
TEXTURE_IMAGE_TYPES = ["Base Color", "Metallic", "Normal", "Roughness", "Specular IOR Level"]
Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует
@ -73,50 +57,19 @@ def convert2relative(height, width, bbox):
y += h/2
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:
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
for obj in all_meshs:
# Make the object actively participate in the physics simulation
obj.enable_rigidbody(active=True, collision_shape="COMPOUND")
# Also use convex decomposition as collision shapes
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
# print(f"{i} : {obj.get_name()}")
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:
for i,o in enumerate(objs):
loc = o.get_location()
@ -138,21 +91,23 @@ def render() -> int:
rnd_par.image_size_wh[1],
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)
bproc.renderer.enable_segmentation_output(map_by=["category_id", "instance", "name"])
# activate depth rendering
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
for r in range(rnd_par.n_series):
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:
val = rnd_par.models_randomization[PROCEDURAL_TEXTURE]
val = rnd_par.models_randomization["texture_path"]
l_texture = _get_list_texture(val)
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): # объекты сцены
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]
for mat in mats:
# with open(log_txt, "a") as fh:
# fh.write("************* mat\n")
# fh.write(f"{mat}\n")
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"]
mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1]))
val = rnd_mat["metallic"]
mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1]))
if PROCEDURAL_TEXTURE in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat[PROCEDURAL_TEXTURE]
if "texture_path" in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat["texture_path"]
val = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(random.choice(val)))
mat.set_principled_shader_value("Base Color", image)
@ -217,7 +156,7 @@ def render() -> int:
# Define a function that samples 6-DoF poses
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_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
bproc.object.sample_poses(meshs,
@ -293,12 +232,7 @@ def render() -> int:
rec["name"] = objn
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]
if len(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)
shutil.copy2(rnd_par.models.filenames[i], models_dir)
f = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".mtl" # файл материала
@ -349,37 +283,9 @@ def render() -> int:
if Not_Categories_Name:
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
def set_texture_model(name: str, textures: list, model_d) -> None:
"""
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:
def _get_models(par, data) -> int:
global all_meshs
par.models = lambda: None
@ -388,14 +294,13 @@ def _get_models(par, data, models_data) -> int:
return 0 # no models
# загрузим объекты
par.models.names = []
par.models.filenames = []
par.models.textures = []
par.models.names = [] # obj_names
par.models.filenames = [] # obj_filenames
i = 1
for f in data:
nam = f["name"]
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)
if not os.path.isfile(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)
all_meshs += obj
obj[0].set_cp("category_id", i) # начиная с 1
set_texture_model(nam, par.models.textures, models_data)
i += 1
return par.models.n_item
@ -466,6 +370,8 @@ if __name__ == "__main__":
print(f"JSon error: {e}")
exit(-2)
# output_dir = args.path
ds_cfg = cfg["output"] # dataset config
generation = ds_cfg["generation"]
cam_pos = ds_cfg["camera_position"]
@ -493,14 +399,11 @@ if __name__ == "__main__":
rnd_par.models_randomization = models_randomization
rnd_par.loc_range_low = models_randomization["loc_range_low"]
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()
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")
exit(-4)
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

BIN
web_p/train/results.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

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