From 0b902031fae1615e8c49b0b182aaeb34bb835d56 Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Fri, 21 Mar 2025 12:15:01 +0100 Subject: [PATCH 1/6] feat: add description attribute for nlu values --- api/src/nlp/dto/nlp-value.dto.ts | 12 +++++++++++- api/src/nlp/schemas/nlp-value.schema.ts | 8 +++++++- frontend/src/components/nlp/components/NlpValue.tsx | 8 ++++++++ .../src/components/nlp/components/NlpValueForm.tsx | 9 +++++++++ frontend/src/types/nlp-value.types.ts | 3 ++- 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/api/src/nlp/dto/nlp-value.dto.ts b/api/src/nlp/dto/nlp-value.dto.ts index 7fecb0e5..dd729936 100644 --- a/api/src/nlp/dto/nlp-value.dto.ts +++ b/api/src/nlp/dto/nlp-value.dto.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -39,6 +39,11 @@ export class NlpValueCreateDto { @IsObject() metadata?: Record; + @ApiPropertyOptional({ type: String }) + @IsString() + @IsOptional() + doc?: string; + @ApiPropertyOptional({ description: 'Nlp value is builtin', type: Boolean }) @IsOptional() @IsBoolean() @@ -77,6 +82,11 @@ export class NlpValueUpdateDto { @IsObjectId({ message: 'Entity must be a valid ObjectId' }) entity?: string | null; + @ApiPropertyOptional({ type: String }) + @IsString() + @IsOptional() + doc?: string; + @ApiPropertyOptional({ description: 'Nlp value is builtin', type: Boolean }) @IsOptional() @IsBoolean() diff --git a/api/src/nlp/schemas/nlp-value.schema.ts b/api/src/nlp/schemas/nlp-value.schema.ts index a5f2e4be..5748ccf3 100644 --- a/api/src/nlp/schemas/nlp-value.schema.ts +++ b/api/src/nlp/schemas/nlp-value.schema.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -46,6 +46,12 @@ export class NlpValueStub extends BaseSchema { @Prop({ type: JSON, default: {} }) metadata: Record; + /** + * Description of the entity's value purpose. + */ + @Prop({ type: String }) + doc?: string; + /** * Either or not this value a built-in (either fixtures or shipped along with the 3rd party ai). */ diff --git a/frontend/src/components/nlp/components/NlpValue.tsx b/frontend/src/components/nlp/components/NlpValue.tsx index 1864eb43..7f365435 100644 --- a/frontend/src/components/nlp/components/NlpValue.tsx +++ b/frontend/src/components/nlp/components/NlpValue.tsx @@ -111,6 +111,14 @@ export const NlpValues = ({ entityId }: { entityId: string }) => { disableColumnMenu: true, renderHeader, }, + { + flex: 3, + field: "doc", + headerName: t("label.doc"), + sortable: true, + disableColumnMenu: true, + renderHeader, + }, { flex: 3, field: "synonyms", diff --git a/frontend/src/components/nlp/components/NlpValueForm.tsx b/frontend/src/components/nlp/components/NlpValueForm.tsx index f066a62d..e9e154be 100644 --- a/frontend/src/components/nlp/components/NlpValueForm.tsx +++ b/frontend/src/components/nlp/components/NlpValueForm.tsx @@ -61,6 +61,7 @@ export const NlpValueForm: FC< >({ defaultValues: { value: data?.value || "", + doc: data?.doc || "", expressions: data?.expressions || [], }, }); @@ -84,6 +85,7 @@ export const NlpValueForm: FC< reset({ value: data.value, expressions: data.expressions, + doc: data.doc, }); } else { reset(); @@ -102,6 +104,13 @@ export const NlpValueForm: FC< {...register("value", validationRules.value)} /> + + + {canHaveSynonyms ? ( diff --git a/frontend/src/types/nlp-value.types.ts b/frontend/src/types/nlp-value.types.ts index 92e3de68..7b7a1e5e 100644 --- a/frontend/src/types/nlp-value.types.ts +++ b/frontend/src/types/nlp-value.types.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -15,6 +15,7 @@ export interface INlpValueAttributes { entity: string; foreign_id?: string; value: string; + doc?: string; expressions?: string[]; metadata?: Record; builtin?: boolean; From 7b111868ed3f698d04560997b21ffffd2b59e40b Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Fri, 21 Mar 2025 15:16:58 +0100 Subject: [PATCH 2/6] feat: add support for search on nlp value description --- api/src/nlp/controllers/nlp-value.controller.ts | 6 ++++-- frontend/src/components/nlp/components/NlpValue.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/api/src/nlp/controllers/nlp-value.controller.ts b/api/src/nlp/controllers/nlp-value.controller.ts index 74a17d48..1cd3aadb 100644 --- a/api/src/nlp/controllers/nlp-value.controller.ts +++ b/api/src/nlp/controllers/nlp-value.controller.ts @@ -93,7 +93,9 @@ export class NlpValueController extends BaseController< @Get('count') async filterCount( @Query( - new SearchFilterPipe({ allowedFields: ['entity', 'value'] }), + new SearchFilterPipe({ + allowedFields: ['entity', 'value', 'doc'], + }), ) filters?: TFilterQuery, ) { @@ -142,7 +144,7 @@ export class NlpValueController extends BaseController< @Query(PopulatePipe) populate: string[], @Query( new SearchFilterPipe({ - allowedFields: ['entity', 'value'], + allowedFields: ['entity', 'value', 'doc'], }), ) filters: TFilterQuery, diff --git a/frontend/src/components/nlp/components/NlpValue.tsx b/frontend/src/components/nlp/components/NlpValue.tsx index 7f365435..5d9b79d0 100644 --- a/frontend/src/components/nlp/components/NlpValue.tsx +++ b/frontend/src/components/nlp/components/NlpValue.tsx @@ -55,7 +55,7 @@ export const NlpValues = ({ entityId }: { entityId: string }) => { const canHaveSynonyms = nlpEntity?.lookups?.[0] === NlpLookups.keywords; const { onSearch, searchPayload } = useSearch({ $eq: [{ entity: entityId }], - $iLike: ["value"], + $or: ["doc","value"] }); const { dataGridProps } = useFind( { entity: EntityType.NLP_VALUE }, From e58d55cc547d1d4f6fc24ae3ec61e0ee52d560ef Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Fri, 21 Mar 2025 15:20:31 +0100 Subject: [PATCH 3/6] feat: apply feedback --- api/src/nlp/dto/nlp-value.dto.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/nlp/dto/nlp-value.dto.ts b/api/src/nlp/dto/nlp-value.dto.ts index dd729936..5c1c42d9 100644 --- a/api/src/nlp/dto/nlp-value.dto.ts +++ b/api/src/nlp/dto/nlp-value.dto.ts @@ -39,7 +39,7 @@ export class NlpValueCreateDto { @IsObject() metadata?: Record; - @ApiPropertyOptional({ type: String }) + @ApiPropertyOptional({ description: 'Nlp Value Description', type: String }) @IsString() @IsOptional() doc?: string; @@ -82,7 +82,7 @@ export class NlpValueUpdateDto { @IsObjectId({ message: 'Entity must be a valid ObjectId' }) entity?: string | null; - @ApiPropertyOptional({ type: String }) + @ApiPropertyOptional({ description: 'Nlp Value Description', type: String }) @IsString() @IsOptional() doc?: string; From ab33a320bc9c5076d264d970e9b3d104252f3722 Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Fri, 21 Mar 2025 15:25:11 +0100 Subject: [PATCH 4/6] feat: fix typo --- frontend/src/components/nlp/components/NlpValue.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/nlp/components/NlpValue.tsx b/frontend/src/components/nlp/components/NlpValue.tsx index 5d9b79d0..894bee1c 100644 --- a/frontend/src/components/nlp/components/NlpValue.tsx +++ b/frontend/src/components/nlp/components/NlpValue.tsx @@ -55,7 +55,7 @@ export const NlpValues = ({ entityId }: { entityId: string }) => { const canHaveSynonyms = nlpEntity?.lookups?.[0] === NlpLookups.keywords; const { onSearch, searchPayload } = useSearch({ $eq: [{ entity: entityId }], - $or: ["doc","value"] + $or: ["doc", "value"] }); const { dataGridProps } = useFind( { entity: EntityType.NLP_VALUE }, From 96b6226a32e8ebf3ff45583c453e29a5bea334f4 Mon Sep 17 00:00:00 2001 From: Med Marrouchi Date: Mon, 24 Mar 2025 08:49:40 +0100 Subject: [PATCH 5/6] Update api/src/nlp/schemas/nlp-value.schema.ts --- api/src/nlp/schemas/nlp-value.schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/nlp/schemas/nlp-value.schema.ts b/api/src/nlp/schemas/nlp-value.schema.ts index 5748ccf3..523eaa3e 100644 --- a/api/src/nlp/schemas/nlp-value.schema.ts +++ b/api/src/nlp/schemas/nlp-value.schema.ts @@ -49,7 +49,7 @@ export class NlpValueStub extends BaseSchema { /** * Description of the entity's value purpose. */ - @Prop({ type: String }) + @Prop({ type: String, default: '' }) doc?: string; /** From 67c4bc753f2e660bb5f5ac8cc35a9d4eb944d246 Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Mon, 24 Mar 2025 10:12:40 +0100 Subject: [PATCH 6/6] feat: re-adapt unit tests for schema change --- api/src/nlp/controllers/nlp-sample.controller.spec.ts | 3 ++- api/src/nlp/controllers/nlp-value.controller.spec.ts | 5 ++++- api/src/utils/test/fixtures/nlpvalue.ts | 7 ++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/src/nlp/controllers/nlp-sample.controller.spec.ts b/api/src/nlp/controllers/nlp-sample.controller.spec.ts index 832e21da..2e82b180 100644 --- a/api/src/nlp/controllers/nlp-sample.controller.spec.ts +++ b/api/src/nlp/controllers/nlp-sample.controller.spec.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -379,6 +379,7 @@ describe('NlpSampleController', () => { expressions: [], builtin: false, entity: priceValueEntity!.id, + doc: '', }; const textSample = { text: 'How much does a BMW cost?', diff --git a/api/src/nlp/controllers/nlp-value.controller.spec.ts b/api/src/nlp/controllers/nlp-value.controller.spec.ts index d78b336f..9108cf97 100644 --- a/api/src/nlp/controllers/nlp-value.controller.spec.ts +++ b/api/src/nlp/controllers/nlp-value.controller.spec.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -157,6 +157,7 @@ describe('NlpValueController', () => { expressions: ['synonym1', 'synonym2'], metadata: { firstkey: 'firstvalue', secondKey: 1995 }, builtin: false, + doc: '', }; const result = await nlpValueController.create(value); expect(result).toEqualPayload(value); @@ -223,6 +224,7 @@ describe('NlpValueController', () => { value: 'updated', expressions: [], builtin: true, + doc: '', }; const result = await nlpValueController.updateOne( positiveValue!.id, @@ -241,6 +243,7 @@ describe('NlpValueController', () => { value: 'updated', expressions: [], builtin: true, + doc: '', }), ).rejects.toThrow(getUpdateOneError(NlpValue.name, jhonNlpValue!.id)); }); diff --git a/api/src/utils/test/fixtures/nlpvalue.ts b/api/src/utils/test/fixtures/nlpvalue.ts index fa882014..fe8714b6 100644 --- a/api/src/utils/test/fixtures/nlpvalue.ts +++ b/api/src/utils/test/fixtures/nlpvalue.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -19,30 +19,35 @@ export const nlpValueFixtures: NlpValueCreateDto[] = [ value: 'positive', expressions: [], builtin: true, + doc: '', }, { entity: '0', value: 'negative', expressions: [], builtin: true, + doc: '', }, { entity: '1', value: 'jhon', expressions: ['john', 'joohn', 'jhonny'], builtin: true, + doc: '', }, { entity: '0', value: 'greeting', expressions: ['heello', 'Hello', 'hi', 'heyy'], builtin: true, + doc: '', }, { entity: '0', value: 'goodbye', expressions: ['bye', 'bye bye'], builtin: true, + doc: '', }, ];