From 414532647f4d1b0c6fea96f3fc83ea94c8e69eb1 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Wed, 29 Jan 2025 16:41:47 +0100 Subject: [PATCH 01/13] big delete --- .../src/annotator/buildNlpAnnotator.ts | 15 - .../src/annotator/fetcher/api/index.ts | 23 - .../src/annotator/fetcher/api/nlpApi.ts | 135 ----- .../src/annotator/fetcher/api/nlpApiType.ts | 51 -- .../src/annotator/fetcher/api/nlpFakeApi.ts | 15 - .../src/annotator/fetcher/api/nlpLocalApi.ts | 53 -- .../src/annotator/fetcher/index.ts | 3 - .../src/annotator/fetcher/mapper/index.ts | 3 - .../fetcher/mapper/nlpMapper.spec.ts | 121 ----- .../src/annotator/fetcher/mapper/nlpMapper.ts | 48 -- .../src/annotator/fetcher/nlpFetcher.spec.ts | 55 -- .../src/annotator/fetcher/nlpFetcher.ts | 50 -- .../courDeCassation/src/annotator/index.ts | 3 - .../src/annotator/test/generator/index.ts | 3 - .../test/generator/nlpAnnotationsGenerator.ts | 55 -- .../src/annotator/test/server/index.ts | 3 - .../annotator/test/server/nlpFakeServer.ts | 14 - ...otateDocumentsWithoutAnnotationsWithNlp.ts | 27 - .../scripts/fillLossOfAllTreatedDocuments.ts | 13 - .../src/scripts/reAnnotateFreeDocuments.ts | 19 - packages/generic/backend/src/index.ts | 4 +- .../src/lib/annotator/annotatorConfigType.ts | 30 -- .../src/lib/annotator/buildAnnotator.spec.ts | 64 --- .../src/lib/annotator/buildAnnotator.ts | 475 ------------------ .../backend/src/lib/annotator/index.ts | 6 - .../src/lib/connector/buildConnector.ts | 2 + .../core/src/modules/document/documentType.ts | 13 +- .../src/modules/document/lib/buildDocument.ts | 2 +- .../src/modules/document/lib/getNextStatus.ts | 10 - 29 files changed, 5 insertions(+), 1310 deletions(-) delete mode 100644 packages/courDeCassation/src/annotator/buildNlpAnnotator.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/api/index.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/api/nlpApi.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/api/nlpApiType.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/api/nlpFakeApi.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/api/nlpLocalApi.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/index.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/mapper/index.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.spec.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/nlpFetcher.spec.ts delete mode 100644 packages/courDeCassation/src/annotator/fetcher/nlpFetcher.ts delete mode 100644 packages/courDeCassation/src/annotator/index.ts delete mode 100644 packages/courDeCassation/src/annotator/test/generator/index.ts delete mode 100644 packages/courDeCassation/src/annotator/test/generator/nlpAnnotationsGenerator.ts delete mode 100644 packages/courDeCassation/src/annotator/test/server/index.ts delete mode 100644 packages/courDeCassation/src/annotator/test/server/nlpFakeServer.ts delete mode 100644 packages/courDeCassation/src/scripts/annotateDocumentsWithoutAnnotationsWithNlp.ts delete mode 100644 packages/courDeCassation/src/scripts/fillLossOfAllTreatedDocuments.ts delete mode 100644 packages/courDeCassation/src/scripts/reAnnotateFreeDocuments.ts delete mode 100644 packages/generic/backend/src/lib/annotator/annotatorConfigType.ts delete mode 100644 packages/generic/backend/src/lib/annotator/buildAnnotator.spec.ts delete mode 100644 packages/generic/backend/src/lib/annotator/buildAnnotator.ts delete mode 100644 packages/generic/backend/src/lib/annotator/index.ts diff --git a/packages/courDeCassation/src/annotator/buildNlpAnnotator.ts b/packages/courDeCassation/src/annotator/buildNlpAnnotator.ts deleted file mode 100644 index 5ce0617b5..000000000 --- a/packages/courDeCassation/src/annotator/buildNlpAnnotator.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { buildAnnotator, annotatorConfigType } from '@label/backend'; -import { settingsType } from '@label/core'; -import { buildNlpFetcher } from './fetcher'; - -export { buildNlpAnnotator }; - -function buildNlpAnnotator(settings: settingsType) { - const nlpApiBaseUrl = process.env.NLP_PSEUDONYMISATION_API_URL; - const nlpAnnotatorConfig: annotatorConfigType = { - name: 'NLP', - ...buildNlpFetcher(nlpApiBaseUrl), - }; - - return buildAnnotator(settings, nlpAnnotatorConfig); -} diff --git a/packages/courDeCassation/src/annotator/fetcher/api/index.ts b/packages/courDeCassation/src/annotator/fetcher/api/index.ts deleted file mode 100644 index 4202c30ad..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/api/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { dependencyManager } from '@label/backend'; -import { buildNlpApi } from './nlpApi'; -import { buildNlpFakeApi } from './nlpFakeApi'; -import { buildNlpLocalApi } from './nlpLocalApi'; -import { nlpResponseType } from './nlpApiType'; -import * as dotenv from 'dotenv'; - -export { buildApi as buildNlpApi }; - -export type { nlpResponseType }; - -if (process.env.RUN_MODE === 'LOCAL') { - dotenv.config(); -} - -const buildApi = dependencyManager.inject({ - forLocal: - process.env.NLP_PSEUDONYMISATION_API_ENABLED === 'true' - ? buildNlpApi - : buildNlpLocalApi, - forProd: buildNlpApi, - forTest: buildNlpFakeApi, -}); diff --git a/packages/courDeCassation/src/annotator/fetcher/api/nlpApi.ts b/packages/courDeCassation/src/annotator/fetcher/api/nlpApi.ts deleted file mode 100644 index 77b2cfb0a..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/api/nlpApi.ts +++ /dev/null @@ -1,135 +0,0 @@ -import axios, { AxiosError, AxiosResponse } from 'axios'; -import { idModule, settingsModule } from '@label/core'; -import { nlpApiType, nlpResponseType, nlpLossType } from './nlpApiType'; -import { logger } from '@label/backend'; - -export { buildNlpApi }; - -type nlpRequestParametersType = { - idLabel: string; - idDecision: string; - sourceId: number; - sourceName: string; - text: string; - parties?: Array; - categories?: string[]; - additionalTerms?: string; -}; - -function buildNlpApi(nlpApiBaseUrl: string): nlpApiType { - return { - async fetchNlpAnnotations(settings, document) { - const filteredSettings = settingsModule.lib.computeFilteredSettings( - settings, - document.decisionMetadata.categoriesToOmit, - document.decisionMetadata.additionalTermsToAnnotate, - document.decisionMetadata.computedAdditionalTerms, - document.decisionMetadata.additionalTermsParsingFailed, - document.decisionMetadata.motivationOccultation, - ); - const nlpCategories = settingsModule.lib.getCategories(filteredSettings, { - status: ['visible', 'alwaysVisible', 'annotable'], - canBeAnnotatedBy: 'NLP', - }); - const nlpRequestParameters: nlpRequestParametersType = { - idLabel: idModule.lib.convertToString(document._id), - idDecision: document.externalId, - sourceId: document.documentNumber, - sourceName: document.source, - text: document.text, - parties: document.decisionMetadata.parties, - categories: nlpCategories, - additionalTerms: - document.decisionMetadata.additionalTermsToAnnotate === '' - ? undefined - : document.decisionMetadata.additionalTermsToAnnotate, - }; - - const startTime = Date.now(); - return await axios({ - data: nlpRequestParameters, - headers: { 'Content-Type': 'application/json' }, - method: 'post', - url: `${nlpApiBaseUrl}/ner`, - timeout: 600000, - }) - .then((response: AxiosResponse) => { - if (response.status != 200) { - logger.error({ - operationName: 'callNlpNerEndpoint', - msg: `${response.status} ${response.statusText}`, - }); - throw new Error(`${response.status} ${response.statusText}`); - } else { - const endTime = Date.now(); - const duration = endTime - startTime; - logger.log({ - operationName: 'callNlpNerEndpoint', - msg: `Decision ${document.source}:${document.documentNumber} has been treated by NLP API (NER) in ${duration}ms`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - callNlpNerEndpointDuration: duration, - }, - }); - return response.data as nlpResponseType; - } - }) - .catch(async (error: AxiosError) => { - // To avoid a 429 too many request error after a timeout - await new Promise((_) => setTimeout(_, 4000)); - if (error.response) { - logger.error({ - operationName: 'callNlpNerEndpoint', - msg: `${error.response.status} ${error.response.statusText}`, - }); - throw new Error( - `${error.response.status} ${error.response.statusText}`, - ); - } - logger.error({ - operationName: 'callNlpNerEndpoint', - msg: `${error.code ?? 'Unknown'} on /ner`, - }); - throw new Error(`${error.code ?? 'Unknown'} on /ner`); - }); - }, - async fetchNlpLoss(document, treatments) { - return await axios({ - data: { text: document.text, treatments }, - headers: { 'Content-Type': 'application/json' }, - method: 'post', - url: `${nlpApiBaseUrl}/loss`, - }) - .then((response: AxiosResponse) => { - if (response.status != 200) { - logger.error({ - operationName: 'callNlpLossEndpoint', - msg: `${response.status} ${response.statusText}`, - }); - throw new Error(`${response.status} ${response.statusText}`); - } else { - return response.data as nlpLossType; - } - }) - .catch((error: AxiosError) => { - if (error.response) { - logger.error({ - operationName: 'callNlpLossEndpoint', - msg: `${error.response.status} ${error.response.statusText}`, - }); - throw new Error( - `${error.response.status} ${error.response.statusText}`, - ); - } - logger.error({ - operationName: 'callNlpLossEndpoint', - msg: `${error.code ?? 'Unknown'} on /loss`, - }); - throw new Error(`${error.code ?? 'Unknown'} on /loss`); - }); - }, - }; -} diff --git a/packages/courDeCassation/src/annotator/fetcher/api/nlpApiType.ts b/packages/courDeCassation/src/annotator/fetcher/api/nlpApiType.ts deleted file mode 100644 index 0ed28ad1a..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/api/nlpApiType.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { documentType, settingsType } from '@label/core'; -import { LabelTreatment } from 'dbsder-api-types'; - -export type { nlpApiType, nlpResponseType, nlpLossType, nlpVersion }; - -type nlpApiType = { - fetchNlpAnnotations: ( - settings: settingsType, - document: documentType, - ) => Promise; - fetchNlpLoss: ( - document: documentType, - treatments: LabelTreatment[], - ) => Promise; -}; - -type nlpVersionDetails = { - version: string; - date: string; -}; -type nlpVersion = { - juriSpacyTokenizer: nlpVersionDetails; - juritools: nlpVersionDetails; - pseudonymisationApi: nlpVersionDetails; - model: { - name: string; - }; -}; - -type nlpResponseType = { - entities: nlpAnnotationType[]; - checklist?: documentType['checklist']; - newCategoriesToAnnotate?: string[]; - newCategoriesToUnAnnotate?: string[]; - additionalTermsToAnnotate?: string[]; - additionalTermsToUnAnnotate?: string[]; - additionalTermsParsingFailed?: boolean; - versions: nlpVersion; -}; - -type nlpAnnotationType = { - text: string; - start: number; - end: number; - category: string; - source: string; - score: number; - entityId: string; -}; - -type nlpLossType = number; diff --git a/packages/courDeCassation/src/annotator/fetcher/api/nlpFakeApi.ts b/packages/courDeCassation/src/annotator/fetcher/api/nlpFakeApi.ts deleted file mode 100644 index b3dec69e9..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/api/nlpFakeApi.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { nlpFakeServer } from '../../test/server'; -import { nlpApiType } from './nlpApiType'; - -export { buildNlpFakeApi }; - -function buildNlpFakeApi(): nlpApiType { - return { - async fetchNlpAnnotations() { - return nlpFakeServer.getNlpAnnotations(); - }, - async fetchNlpLoss() { - return 0; - }, - }; -} diff --git a/packages/courDeCassation/src/annotator/fetcher/api/nlpLocalApi.ts b/packages/courDeCassation/src/annotator/fetcher/api/nlpLocalApi.ts deleted file mode 100644 index 69295ca8c..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/api/nlpLocalApi.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { promises as fs } from 'fs'; -import { settingsModule } from '@label/core'; -import { nlpApiType, nlpResponseType } from './nlpApiType'; - -export { buildNlpLocalApi }; - -const pathToNlpAnnotations = './storage/annotations/'; - -function buildNlpLocalApi(): nlpApiType { - return { - async fetchNlpAnnotations(settings, document) { - const filteredSettings = settingsModule.lib.computeFilteredSettings( - settings, - document.decisionMetadata.categoriesToOmit, - document.decisionMetadata.additionalTermsToAnnotate, - document.decisionMetadata.computedAdditionalTerms, - document.decisionMetadata.additionalTermsParsingFailed, - document.decisionMetadata.motivationOccultation, - ); - const annotations = JSON.parse( - await fs.readFile( - `${pathToNlpAnnotations}${document.documentNumber}.json`, - { - encoding: 'utf8', - }, - ), - ) as nlpResponseType; - - const availableCategories = settingsModule.lib.getCategories( - filteredSettings, - { - status: ['visible', 'alwaysVisible', 'annotable'], - canBeAnnotatedBy: 'NLP', - }, - ); - - return { - ...annotations, - entities: annotations.entities.filter((entity) => - availableCategories.includes(entity.category), - ), - checklist: annotations.checklist, - newCategoriesToAnnotate: annotations.newCategoriesToAnnotate, - newCategoriesToUnAnnotate: annotations.newCategoriesToUnAnnotate, - additionalTermsToAnnotate: annotations.additionalTermsToAnnotate, - additionalTermsToUnAnnotate: annotations.additionalTermsToUnAnnotate, - }; - }, - async fetchNlpLoss() { - return 0; - }, - }; -} diff --git a/packages/courDeCassation/src/annotator/fetcher/index.ts b/packages/courDeCassation/src/annotator/fetcher/index.ts deleted file mode 100644 index c6c4fa274..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { buildNlpFetcher } from './nlpFetcher'; - -export { buildNlpFetcher }; diff --git a/packages/courDeCassation/src/annotator/fetcher/mapper/index.ts b/packages/courDeCassation/src/annotator/fetcher/mapper/index.ts deleted file mode 100644 index 44a437f47..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/mapper/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { nlpMapper } from './nlpMapper'; - -export { nlpMapper }; diff --git a/packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.spec.ts b/packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.spec.ts deleted file mode 100644 index feb432aaa..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { documentModule } from '@label/core'; -import { nlpResponseType } from '../api'; -import { nlpMapper } from './nlpMapper'; - -const nlpVersion = { - juriSpacyTokenizer: { - version: '0.13.21', - date: '2024-01-01 12:00:00', - }, - juritools: { - version: '0.13.21', - date: '2024-01-01 12:00:00', - }, - pseudonymisationApi: { - version: '0.13.21', - date: '2024-01-01 12:00:00', - }, - model: { - name: 'new_categories_model.pt', - }, -}; - -const nlpAnnotations: nlpResponseType = { - entities: [ - { - text: 'ANNOTATION1', - start: 0, - end: 11, - category: 'LABEL1', - source: 'NLP', - score: 0.5, - entityId: 'LABEL1_annotation1', - }, - { - text: 'ANNOTATION2', - start: 12, - end: 23, - category: 'LABEL2', - source: 'NLP', - score: 0.6, - entityId: 'LABEL2_annotation2', - }, - ], - checklist: [], - versions: nlpVersion, -}; - -const nlpAnnotationsWithAdditionalTerms: nlpResponseType = { - entities: [ - { - text: 'ANNOTATION1', - start: 0, - end: 11, - category: 'LABEL1', - source: 'NLP', - score: 0.5, - entityId: 'LABEL1_annotation1', - }, - { - text: 'ANNOTATION2', - start: 12, - end: 23, - category: 'LABEL2', - source: 'NLP', - score: 0.6, - entityId: 'LABEL2_annotation2', - }, - ], - checklist: [], - additionalTermsToUnAnnotate: ['blabla', 'toto'], - versions: nlpVersion, -}; - -const document = documentModule.generator.generate({ - text: 'ANNOTATION1 ANNOTATION2', -}); - -describe('nlpMapper', () => { - describe('mapNlpAnnotationsToAnnotations', () => { - it('should convert the nlp annotations into our annotations', () => { - const annotations = nlpMapper.mapNlpAnnotationsToAnnotations( - nlpAnnotations, - document, - ); - - expect(annotations[0]).toEqual({ - category: 'LABEL1', - entityId: 'LABEL1_annotation1', - start: 0, - text: 'ANNOTATION1', - certaintyScore: 0.5, - }); - expect(annotations[1]).toEqual({ - category: 'LABEL2', - entityId: 'LABEL2_annotation2', - start: 12, - text: 'ANNOTATION2', - certaintyScore: 0.6, - }); - }); - }); - describe('mapNlpAdditionalTerms', () => { - it('should return undefined if there is no additionalTerms', () => { - const additionalTerms = nlpMapper.mapNlpAdditionalTerms(nlpAnnotations); - - expect(additionalTerms).toEqual(undefined); - }); - }); - describe('mapNlpAdditionalTerms', () => { - it('should return mapped additional terms', () => { - const additionalTerms = nlpMapper.mapNlpAdditionalTerms( - nlpAnnotationsWithAdditionalTerms, - ); - - expect(additionalTerms).toEqual({ - additionalTermsToAnnotate: [], - additionalTermsToUnAnnotate: ['blabla', 'toto'], - }); - }); - }); -}); diff --git a/packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.ts b/packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.ts deleted file mode 100644 index 833738a16..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/mapper/nlpMapper.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { annotationType, annotationModule, documentType } from '@label/core'; -import { nlpResponseType } from '../api'; - -export { nlpMapper }; - -const nlpMapper = { - mapNlpAnnotationsToAnnotations, - mapNlpAdditionalTerms, -}; - -function mapNlpAnnotationsToAnnotations( - nlpAnnotations: nlpResponseType, - document: documentType, -): annotationType[] { - return nlpAnnotations.entities.map((nlpAnnotation) => - annotationModule.lib.buildAnnotation({ - category: nlpAnnotation.category, - entityId: nlpAnnotation.entityId, - start: nlpAnnotation.start, - certaintyScore: nlpAnnotation.score, - text: document.text.substring(nlpAnnotation.start, nlpAnnotation.end), - }), - ); -} - -function mapNlpAdditionalTerms( - nlpResponse: nlpResponseType, -): documentType['decisionMetadata']['computedAdditionalTerms'] { - if ( - nlpResponse.additionalTermsToAnnotate !== undefined || - nlpResponse.additionalTermsToUnAnnotate !== undefined - ) { - const additionalTermsToAnnotate = - nlpResponse.additionalTermsToAnnotate == undefined - ? [] - : nlpResponse.additionalTermsToAnnotate; - const additionalTermsToUnAnnotate = - nlpResponse.additionalTermsToUnAnnotate == undefined - ? [] - : nlpResponse.additionalTermsToUnAnnotate; - return { - additionalTermsToAnnotate, - additionalTermsToUnAnnotate, - }; - } else { - return; - } -} diff --git a/packages/courDeCassation/src/annotator/fetcher/nlpFetcher.spec.ts b/packages/courDeCassation/src/annotator/fetcher/nlpFetcher.spec.ts deleted file mode 100644 index c195576fa..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/nlpFetcher.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { documentType, documentModule, settingsModule } from '@label/core'; -import { nlpFakeServer } from '../test/server'; -import { buildNlpFetcher } from './nlpFetcher'; - -describe('nlpFetcher', () => { - const nlpFetcher = buildNlpFetcher('http://127.0.0.1:8081'); - beforeEach(() => { - nlpFakeServer.reinitialize(); - }); - - describe('fetchAnnotationOfDocument', () => { - const settings = settingsModule.lib.buildSettings({ LABEL: {} }); - let document: documentType; - - beforeEach(() => { - document = documentModule.generator.generate(); - nlpFakeServer.reinitialize(); - }); - - it('should fetch the annotation report from the nlp engine of the given document', async () => { - const { checklist } = await nlpFetcher.fetchAnnotationOfDocument( - settings, - document, - ); - - const nlpAnnotations = nlpFakeServer.getNlpAnnotations(); - expect(checklist).toEqual(nlpAnnotations.checklist); - }); - it('should fetch all the annotations from the nlp engine of the given document', async () => { - const { annotations } = await nlpFetcher.fetchAnnotationOfDocument( - settings, - document, - ); - - const nlpAnnotations = nlpFakeServer.getNlpAnnotations(); - nlpAnnotations.entities.forEach((nlpAnnotation) => { - expect( - annotations.some( - (annotation) => - annotation.start === nlpAnnotation.start && - annotation.category === nlpAnnotation.category, - ), - ).toEqual(true); - }); - }); - it('should return the document id', async () => { - const { documentId } = await nlpFetcher.fetchAnnotationOfDocument( - settings, - document, - ); - - expect(documentId).toEqual(document._id); - }); - }); -}); diff --git a/packages/courDeCassation/src/annotator/fetcher/nlpFetcher.ts b/packages/courDeCassation/src/annotator/fetcher/nlpFetcher.ts deleted file mode 100644 index ba93e4754..000000000 --- a/packages/courDeCassation/src/annotator/fetcher/nlpFetcher.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { documentType, settingsType } from '@label/core'; -import { buildNlpApi } from './api'; -import { nlpMapper } from './mapper'; -import { LabelTreatment } from 'dbsder-api-types'; - -export { buildNlpFetcher }; - -function buildNlpFetcher(nlpApiBaseUrl: string | undefined) { - if (nlpApiBaseUrl == undefined) { - throw new Error('You must provide a valid NLP api URL'); - } - const nlpApi = buildNlpApi(nlpApiBaseUrl); - - return { - async fetchAnnotationOfDocument( - settings: settingsType, - document: documentType, - ) { - const nlpAnnotations = await nlpApi.fetchNlpAnnotations( - settings, - document, - ); - - return { - annotations: nlpMapper.mapNlpAnnotationsToAnnotations( - nlpAnnotations, - document, - ), - documentId: document._id, - checklist: nlpAnnotations.checklist ?? [], - newCategoriesToAnnotate: nlpAnnotations.newCategoriesToAnnotate, - newCategoriesToUnAnnotate: nlpAnnotations.newCategoriesToUnAnnotate, - computedAdditionalTerms: nlpMapper.mapNlpAdditionalTerms( - nlpAnnotations, - ), - additionalTermsParsingFailed: - nlpAnnotations.additionalTermsParsingFailed, - version: nlpAnnotations.versions, - }; - }, - async fetchLossOfDocument( - document: documentType, - treatments: LabelTreatment[], - ) { - const nlpLoss = await nlpApi.fetchNlpLoss(document, treatments); - - return nlpLoss; - }, - }; -} diff --git a/packages/courDeCassation/src/annotator/index.ts b/packages/courDeCassation/src/annotator/index.ts deleted file mode 100644 index 9b2e4f405..000000000 --- a/packages/courDeCassation/src/annotator/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { buildNlpAnnotator } from './buildNlpAnnotator'; - -export { buildNlpAnnotator }; diff --git a/packages/courDeCassation/src/annotator/test/generator/index.ts b/packages/courDeCassation/src/annotator/test/generator/index.ts deleted file mode 100644 index 2f19653c8..000000000 --- a/packages/courDeCassation/src/annotator/test/generator/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { nlpAnnotationsGenerator } from './nlpAnnotationsGenerator'; - -export { nlpAnnotationsGenerator }; diff --git a/packages/courDeCassation/src/annotator/test/generator/nlpAnnotationsGenerator.ts b/packages/courDeCassation/src/annotator/test/generator/nlpAnnotationsGenerator.ts deleted file mode 100644 index f5a5258cd..000000000 --- a/packages/courDeCassation/src/annotator/test/generator/nlpAnnotationsGenerator.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { random } from 'lodash'; -import { documentModule, generatorType } from '@label/core'; -import { nlpResponseType } from '../../fetcher/api'; - -export { nlpAnnotationsGenerator }; - -const nlpAnnotationsGenerator: generatorType = { - generate: ({ entities, checklist, versions } = {}) => ({ - entities: entities ? entities : generateRandomNlpAnnotations(), - checklist: checklist - ? checklist - : documentModule.checklistGenerator.generate(2), - versions: versions ? versions : generateRandomNlpVersion(), - }), -}; - -function generateRandomNlpAnnotations() { - return [...Array(5).keys()].map(() => generateRandomNlpAnnotation()); -} - -function generateRandomNlpAnnotation() { - const start = random(100); - const text = `TEXT_${Math.random()}`; - const entity = { - text: text, - start: start, - end: start + random(8), - score: Math.random(), - category: `LABEL`, - source: `NLP`, - entityId: `LABEL_${text.toLowerCase()}`, - }; - return entity; -} - -function generateRandomNlpVersion() { - const nlpVersion = { - juriSpacyTokenizer: { - version: `VERSION_${Math.random()}`, - date: `DATE_${Math.random()}`, - }, - juritools: { - version: `VERSION_${Math.random()}`, - date: `DATE_${Math.random()}`, - }, - pseudonymisationApi: { - version: `VERSION_${Math.random()}`, - date: `DATE_${Math.random()}`, - }, - model: { - name: `MODEL_${Math.random()}`, - }, - }; - return nlpVersion; -} diff --git a/packages/courDeCassation/src/annotator/test/server/index.ts b/packages/courDeCassation/src/annotator/test/server/index.ts deleted file mode 100644 index e971abaf5..000000000 --- a/packages/courDeCassation/src/annotator/test/server/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { nlpFakeServer } from './nlpFakeServer'; - -export { nlpFakeServer }; diff --git a/packages/courDeCassation/src/annotator/test/server/nlpFakeServer.ts b/packages/courDeCassation/src/annotator/test/server/nlpFakeServer.ts deleted file mode 100644 index 1b5e6decd..000000000 --- a/packages/courDeCassation/src/annotator/test/server/nlpFakeServer.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { nlpAnnotationsGenerator } from '../generator'; - -export { nlpFakeServer }; - -let nlpAnnotations = nlpAnnotationsGenerator.generate(); - -const nlpFakeServer = { - reinitialize: () => { - nlpAnnotations = nlpAnnotationsGenerator.generate(); - }, - getNlpAnnotations() { - return nlpAnnotations; - }, -}; diff --git a/packages/courDeCassation/src/scripts/annotateDocumentsWithoutAnnotationsWithNlp.ts b/packages/courDeCassation/src/scripts/annotateDocumentsWithoutAnnotationsWithNlp.ts deleted file mode 100644 index 9514d6533..000000000 --- a/packages/courDeCassation/src/scripts/annotateDocumentsWithoutAnnotationsWithNlp.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { settingsType } from '@label/core'; -import { buildNlpAnnotator } from '../annotator'; -import { parametersHandler } from '../lib/parametersHandler'; -import * as dotenv from 'dotenv'; - -(async () => { - if (process.env.RUN_MODE === 'LOCAL') { - dotenv.config(); - } - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - backend.runScript( - () => annotateDocumentsWithoutAnnotationsWithNlp(settings), - { - shouldLoadDb: true, - }, - ); -})(); - -async function annotateDocumentsWithoutAnnotationsWithNlp( - settings: settingsType, -) { - const nlpAnnotator = buildNlpAnnotator(settings); - - await nlpAnnotator.annotateDocumentsWithoutAnnotations(); -} diff --git a/packages/courDeCassation/src/scripts/fillLossOfAllTreatedDocuments.ts b/packages/courDeCassation/src/scripts/fillLossOfAllTreatedDocuments.ts deleted file mode 100644 index 0c2ec4501..000000000 --- a/packages/courDeCassation/src/scripts/fillLossOfAllTreatedDocuments.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { buildNlpAnnotator } from '../annotator'; -import { parametersHandler } from '../lib/parametersHandler'; - -(async () => { - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - const nlpAnnotator = buildNlpAnnotator(settings); - - backend.runScript(() => nlpAnnotator.fillLossOfAllTreatedDocuments(), { - shouldLoadDb: true, - }); -})(); diff --git a/packages/courDeCassation/src/scripts/reAnnotateFreeDocuments.ts b/packages/courDeCassation/src/scripts/reAnnotateFreeDocuments.ts deleted file mode 100644 index d3a6834e5..000000000 --- a/packages/courDeCassation/src/scripts/reAnnotateFreeDocuments.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { settingsType } from '@label/core'; -import { buildNlpAnnotator } from '../annotator'; -import { parametersHandler } from '../lib/parametersHandler'; - -(async () => { - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - - backend.runScript(() => reAnnotateFreeDocumentsWithNlp(settings), { - shouldLoadDb: true, - }); -})(); - -async function reAnnotateFreeDocumentsWithNlp(settings: settingsType) { - const nlpAnnotator = buildNlpAnnotator(settings); - - await nlpAnnotator.reAnnotateFreeDocuments(); -} diff --git a/packages/generic/backend/src/index.ts b/packages/generic/backend/src/index.ts index 47db6af9b..9cd14b33a 100644 --- a/packages/generic/backend/src/index.ts +++ b/packages/generic/backend/src/index.ts @@ -1,4 +1,3 @@ -import { buildAnnotator, annotatorConfigType } from './lib/annotator'; import { buildConnector, connectorConfigType } from './lib/connector'; import { buildExporter, exporterConfigType } from './lib/exporter'; import { settingsLoader } from './lib/settingsLoader'; @@ -8,7 +7,6 @@ import { treatmentService } from './modules/treatment'; import { buildDocumentRepository } from './modules/document'; export { - buildAnnotator, buildBackend, buildConnector, buildExporter, @@ -21,4 +19,4 @@ export { treatmentService, }; -export type { annotatorConfigType, connectorConfigType, exporterConfigType }; +export type { connectorConfigType, exporterConfigType }; diff --git a/packages/generic/backend/src/lib/annotator/annotatorConfigType.ts b/packages/generic/backend/src/lib/annotator/annotatorConfigType.ts deleted file mode 100644 index 6cf069de3..000000000 --- a/packages/generic/backend/src/lib/annotator/annotatorConfigType.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { - annotationType, - documentType, - idType, - settingsType, -} from '@label/core'; -import { LabelTreatment } from 'dbsder-api-types'; - -export type { annotatorConfigType }; - -type annotatorConfigType = { - name: string; - fetchAnnotationOfDocument( - settings: settingsType, - document: documentType, - ): Promise<{ - annotations: annotationType[]; - documentId: idType; - checklist: documentType['checklist']; - newCategoriesToAnnotate?: string[]; - newCategoriesToUnAnnotate?: string[]; - computedAdditionalTerms?: documentType['decisionMetadata']['computedAdditionalTerms']; - additionalTermsParsingFailed?: boolean; - version: documentType['nlpVersions']; - }>; - fetchLossOfDocument: ( - document: documentType, - treatments: LabelTreatment[], - ) => Promise; -}; diff --git a/packages/generic/backend/src/lib/annotator/buildAnnotator.spec.ts b/packages/generic/backend/src/lib/annotator/buildAnnotator.spec.ts deleted file mode 100644 index 19bc76232..000000000 --- a/packages/generic/backend/src/lib/annotator/buildAnnotator.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { annotationModule, documentModule, settingsModule } from '@label/core'; -import { range } from 'lodash'; -import { - documentService, - buildDocumentRepository, -} from '../../modules/document'; -import { annotatorConfigType } from './annotatorConfigType'; -import { buildAnnotator } from './buildAnnotator'; - -describe('buildAnnotator', () => { - const settings = settingsModule.lib.buildSettings({ - prenom: { status: 'annotable' }, - }); - describe('annotateDocumentsWithoutAnnotations', () => { - it('should annotate all the documents without annotations', async () => { - await insertNDocumentsWithoutAnnotationsInDb(5); - const fakeAnnotator = buildFakeAnnotatorConfig(); - const annotator = buildAnnotator(settings, fakeAnnotator); - - await annotator.annotateDocumentsWithoutAnnotations(); - - const documentWithoutAnnotations = await documentService.fetchDocumentWithoutAnnotationsNotIn( - [], - ); - expect(documentWithoutAnnotations).toEqual(undefined); - }); - }); -}); - -async function insertNDocumentsWithoutAnnotationsInDb(n: number) { - const documents = [...Array(n).keys()].map(() => - documentModule.generator.generate({ status: 'loaded' }), - ); - - const documentRepository = buildDocumentRepository(); - await Promise.all(documents.map(documentRepository.insert)); - - return documents; -} - -function buildFakeAnnotatorConfig(): annotatorConfigType { - return { - name: 'FAKE_ANNOTATOR', - async fetchAnnotationOfDocument(settings, document) { - const category = Object.keys(settings)[0]; - const annotations = range(5).map((_, index) => - annotationModule.lib.buildAnnotation({ - text: 'TEXT', - start: index * 10, - category, - certaintyScore: Math.random(), - }), - ); - const checklist = documentModule.checklistGenerator.generate(4); - - const version = documentModule.generator.generate().nlpVersions; - - return { annotations, documentId: document._id, checklist, version }; - }, - async fetchLossOfDocument() { - return 0; - }, - }; -} diff --git a/packages/generic/backend/src/lib/annotator/buildAnnotator.ts b/packages/generic/backend/src/lib/annotator/buildAnnotator.ts deleted file mode 100644 index 56ce82098..000000000 --- a/packages/generic/backend/src/lib/annotator/buildAnnotator.ts +++ /dev/null @@ -1,475 +0,0 @@ -import { - annotationType, - documentType, - documentModule, - idType, - idModule, - settingsType, - treatmentModule, - annotationModule, - settingsModule, -} from '@label/core'; -import { documentService } from '../../modules/document'; -import { treatmentService } from '../../modules/treatment'; -import { logger } from '../../utils'; -import { annotatorConfigType } from './annotatorConfigType'; -import { buildPreAssignator } from '../preAssignator'; - -export { buildAnnotator }; - -function buildAnnotator( - settings: settingsType, - annotatorConfig: annotatorConfigType, -) { - return { - annotateDocumentsWithoutAnnotations, - reAnnotateFreeDocuments, - fillLossOfAllTreatedDocuments, - }; - - async function fillLossOfAllTreatedDocuments() { - logger.log({ - operationName: 'fillLossOfAllTreatedDocuments', - msg: 'START', - }); - - const failedDocumentIds: documentType['_id'][] = []; - const documentsCountToFill = await documentService.countDoneDocumentsWithoutLossNotIn( - failedDocumentIds, - ); - logger.log({ - operationName: 'fillLossOfAllTreatedDocuments', - msg: `Found ${documentsCountToFill} documents without loss`, - }); - let currentDocumentToFillLoss: documentType | undefined; - let documentsFilledLossCount = 0; - do { - currentDocumentToFillLoss = await documentService.fetchDoneDocumentWithoutLossNotIn( - failedDocumentIds, - ); - if (currentDocumentToFillLoss) { - documentsFilledLossCount++; - try { - const currentTreatmentsOfDocument = await treatmentService.fetchTreatmentsByDocumentId( - currentDocumentToFillLoss._id, - ); - const loss = await annotatorConfig.fetchLossOfDocument( - currentDocumentToFillLoss, - treatmentModule.lib.concat(currentTreatmentsOfDocument), - ); - await documentService.updateDocumentLoss( - currentDocumentToFillLoss._id, - loss, - ); - } catch (error) { - failedDocumentIds.push(currentDocumentToFillLoss._id); - logger.log({ - operationName: 'fillLossOfAllTreatedDocuments', - msg: `Error while filling loss of document ${idModule.lib.convertToString( - currentDocumentToFillLoss._id, - )}`, - }); - } - } - } while ( - currentDocumentToFillLoss !== undefined && - documentsFilledLossCount < documentsCountToFill - ); - } - - async function annotateDocumentsWithoutAnnotations() { - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: 'START', - }); - - const failedDocumentIds: documentType['_id'][] = []; - const documentsCountToAnnotate = await documentService.countLoadedDocuments(); - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: `Found ${documentsCountToAnnotate} documents to annotate`, - }); - let currentDocumentToAnnotate: documentType | undefined; - let previousDocumentStatus: documentType['status'] | undefined; - let documentsAnnotatedCount = 0; - - do { - previousDocumentStatus = undefined; - currentDocumentToAnnotate = await documentService.fetchDocumentWithoutAnnotationsNotIn( - failedDocumentIds, - ); - if (currentDocumentToAnnotate) { - documentsAnnotatedCount++; - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: `Found a document to annotate. Reserving...`, - }); - previousDocumentStatus = currentDocumentToAnnotate.status; - const nextDocumentStatus = documentModule.lib.getNextStatus({ - status: currentDocumentToAnnotate.status, - publicationCategory: currentDocumentToAnnotate.publicationCategory, - route: currentDocumentToAnnotate.route, - }); - const updatedDocument = await documentService.updateDocumentStatus( - currentDocumentToAnnotate._id, - nextDocumentStatus, - ); - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: `Annotating with ${ - annotatorConfig.name - } : ${documentsAnnotatedCount}/${documentsCountToAnnotate}... ${formatDocumentInfos( - currentDocumentToAnnotate, - )}`, - }); - try { - await annotateDocument(updatedDocument); - } catch (error) { - failedDocumentIds.push(updatedDocument._id); - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: `Error while annotating document ${formatDocumentInfos( - currentDocumentToAnnotate, - )}.`, - data: { - decision: { - sourceId: currentDocumentToAnnotate.documentNumber, - sourceName: currentDocumentToAnnotate.source, - }, - }, - }); - await documentService.updateDocumentStatus( - currentDocumentToAnnotate._id, - previousDocumentStatus, - ); - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: `Document ${formatDocumentInfos( - currentDocumentToAnnotate, - )} free!`, - }); - } - } - } while ( - currentDocumentToAnnotate !== undefined && - documentsAnnotatedCount < documentsCountToAnnotate - ); - - logger.log({ - operationName: 'annotateDocumentsWithoutAnnotations', - msg: 'DONE', - }); - } - - async function reAnnotateFreeDocuments() { - const documentIds = await documentService.fetchFreeDocumentsIds(); - - logger.log({ - operationName: 'reAnnotateFreeDocuments', - msg: `Found ${documentIds.length} free documents to reannotate, deleting their treatments and annotation report.`, - }); - - for (const documentId of documentIds) { - await treatmentService.deleteTreatmentsByDocumentId(documentId); - await documentService.updateDocumentChecklist(documentId, []); - await documentService.updateDocumentStatus(documentId, 'loaded'); - } - } - - async function annotateDocument(document: documentType) { - const previousTreatments = await treatmentService.fetchTreatmentsByDocumentId( - document._id, - ); - if (previousTreatments.length > 0) { - throw new Error( - `Conflict of annotation on document ${formatDocumentInfos( - document, - )}. Skipping...`, - ); - } - - const { - annotations, - documentId, - checklist, - newCategoriesToAnnotate, - newCategoriesToUnAnnotate, - computedAdditionalTerms, - additionalTermsParsingFailed, - version, - } = await annotatorConfig.fetchAnnotationOfDocument(settings, document); - logger.log({ - operationName: 'annotateDocument', - msg: 'NLP annotation succesfully fetched', - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - documentService.updateDocumentNlpVersions(documentId, version); - - if (document.route == 'simple' && annotations.length == 0) { - await documentService.updateDocumentRoute(documentId, 'automatic'); - logger.log({ - operationName: 'annotateDocument', - msg: 'Route switched to automatic', - }); - } - - await createAnnotatorTreatment({ annotations, documentId }); - logger.log({ - operationName: 'annotateDocument', - msg: 'NLP treatment created in DB', - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - - if (document.decisionMetadata.motivationOccultation === true) { - if ( - document.zoning != undefined && - document.zoning.zones?.motivations != undefined && - document.zoning.zones.motivations.length > 0 - ) { - logger.log({ - operationName: 'annotateDocument', - msg: 'Annotate motivation zone because motivationOccultation is true', - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - - createMotivationOccultationTreatment( - documentId, - document.zoning.zones.motivations, - document.text, - annotations, - ); - } else { - logger.log({ - operationName: 'annotateDocument', - msg: `Annotate decision motivation zone impossible because motication zone was not found for document ${formatDocumentInfos( - document, - )}`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - } - } - - if (checklist.length > 0) { - documentService.updateDocumentChecklist(document._id, checklist); - logger.log({ - operationName: 'annotateDocument', - msg: 'Checklist added to document', - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - } - if ( - additionalTermsParsingFailed !== null && - additionalTermsParsingFailed !== undefined - ) { - logger.log({ - operationName: 'annotateDocument', - msg: `additionalTermsParsingFailed found, updating with value ${additionalTermsParsingFailed}`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - await documentService.updateDocumentAdditionalTermsParsingFailed( - documentId, - additionalTermsParsingFailed, - ); - } - - let newCategoriesToOmit = document.decisionMetadata.categoriesToOmit; - if (!!newCategoriesToUnAnnotate) { - logger.log({ - operationName: 'annotateDocument', - msg: `categoriesToUnAnnotate found, adding '${newCategoriesToUnAnnotate}' to categoriesToOmit if not already in`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - newCategoriesToOmit = Array.from( - new Set(newCategoriesToOmit.concat(newCategoriesToUnAnnotate)), - ); - } - - if (!!newCategoriesToAnnotate) { - logger.log({ - operationName: 'annotateDocument', - msg: `categoriesToAnnotate found, removing '${newCategoriesToAnnotate}' from categoriesToOmit if present`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - newCategoriesToOmit = newCategoriesToOmit.filter( - (category) => !newCategoriesToAnnotate.includes(category), - ); - } - - if (document.decisionMetadata.categoriesToOmit != newCategoriesToOmit) { - logger.log({ - operationName: 'annotateDocument', - msg: `updating categoriesToOmit in database`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - documentService.updateDocumentCategoriesToOmit( - documentId, - newCategoriesToOmit, - ); - } - - if (!!computedAdditionalTerms) { - logger.log({ - operationName: 'annotateDocument', - msg: - 'Additionals terms to annotate or to unannotate found, adding to document...', - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - - await documentService.updateDocumentComputedAdditionalTerms( - documentId, - computedAdditionalTerms, - ); - } - - const nextDocumentStatus = documentModule.lib.getNextStatus({ - status: document.status, - publicationCategory: document.publicationCategory, - route: document.route, - }); - - const preAssignator = buildPreAssignator(); - const isPreassignated = await preAssignator.preAssignDocument(document); - - if (!isPreassignated) { - await documentService.updateDocumentStatus( - document._id, - nextDocumentStatus, - ); - } - - logger.log({ - operationName: 'annotateDocument', - msg: `Annotation done for document ${formatDocumentInfos(document)}`, - data: { - decision: { - sourceId: document.documentNumber, - sourceName: document.source, - }, - }, - }); - } - - async function createAnnotatorTreatment({ - annotations, - documentId, - }: { - annotations: annotationType[]; - documentId: idType; - }) { - await treatmentService.createTreatment( - { - documentId, - previousAnnotations: [], - nextAnnotations: annotations, - source: 'NLP', - }, - settings, - ); - } - - async function createMotivationOccultationTreatment( - documentId: documentType['_id'], - motivations: { start: number; end: number }[], - documentText: string, - previousAnnotations: annotationType[], - ) { - const motivationAnnotations: annotationType[] = []; - motivations.forEach((motivation) => { - const motivationText = documentText.substring( - motivation.start, - motivation.end, - ); - - // Suppression des espaces et des sauts de ligne au début du texte - const trimmedStartMotivation = motivationText.replace(/^[\s\r\n]+/, ''); - // Calcul du nombre de caractères retirés au début du texte - const removedCharactersAtStart = - motivationText.length - trimmedStartMotivation.length; - - // Suppression des espaces et des sauts de ligne à la fin du texte - const trimmedMotivation = trimmedStartMotivation.replace( - /[\s\r\n]+$/, - '', - ); - - motivationAnnotations.push( - annotationModule.lib.buildAnnotation({ - start: motivation.start + removedCharactersAtStart, - text: trimmedMotivation, - category: settingsModule.lib.motivationCategoryHandler.getCategoryName(), - certaintyScore: 1, - }), - ); - }); - - const annotationWithoutOverlapping = annotationModule.lib.removeOverlappingAnnotations( - [...previousAnnotations, ...motivationAnnotations], - ); - - await treatmentService.createTreatment( - { - documentId, - previousAnnotations: previousAnnotations, - nextAnnotations: annotationWithoutOverlapping, - source: 'supplementaryAnnotations', - }, - settings, - ); - } - - function formatDocumentInfos(document: documentType) { - return `[${idModule.lib.convertToString(document._id)} ${document.source} ${ - document.documentNumber - }]`; - } -} diff --git a/packages/generic/backend/src/lib/annotator/index.ts b/packages/generic/backend/src/lib/annotator/index.ts deleted file mode 100644 index aa2b71e14..000000000 --- a/packages/generic/backend/src/lib/annotator/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { annotatorConfigType } from './annotatorConfigType'; -import { buildAnnotator } from './buildAnnotator'; - -export { buildAnnotator }; - -export type { annotatorConfigType }; diff --git a/packages/generic/backend/src/lib/connector/buildConnector.ts b/packages/generic/backend/src/lib/connector/buildConnector.ts index bcca44f24..4c7eb76f7 100644 --- a/packages/generic/backend/src/lib/connector/buildConnector.ts +++ b/packages/generic/backend/src/lib/connector/buildConnector.ts @@ -81,6 +81,7 @@ function buildConnector(connectorConfig: connectorConfigType) { msg: 'Insertion done', }); + // To update if (keepLabelTreatments) { if (courtDecision.labelTreatments?.length == 0) { logger.error({ @@ -214,6 +215,7 @@ function buildConnector(connectorConfig: connectorConfigType) { 'recent', ); insertDocument(converted); + // Add labelTreatment import await connectorConfig.updateDocumentLabelStatusToLoaded( converted.externalId, ); diff --git a/packages/generic/core/src/modules/document/documentType.ts b/packages/generic/core/src/modules/document/documentType.ts index 64559ac50..91fdc692f 100644 --- a/packages/generic/core/src/modules/document/documentType.ts +++ b/packages/generic/core/src/modules/document/documentType.ts @@ -412,18 +412,7 @@ const documentModelCommonFields = { source: { kind: 'primitive', content: 'string' }, status: { kind: 'constant', - content: [ - 'done', - 'free', - 'loaded', - 'nlpAnnotating', - 'pending', - 'locked', - 'rejected', - 'saved', - 'toBePublished', - 'toBeConfirmed', - ] as const, + content: ['done', 'free', 'pending', 'locked', 'rejected', 'saved', 'toBePublished', 'toBeConfirmed'] as const, }, title: { kind: 'primitive', content: 'string' }, text: { kind: 'primitive', content: 'string' }, diff --git a/packages/generic/core/src/modules/document/lib/buildDocument.ts b/packages/generic/core/src/modules/document/lib/buildDocument.ts index 7f2331e6c..5e4411d27 100644 --- a/packages/generic/core/src/modules/document/lib/buildDocument.ts +++ b/packages/generic/core/src/modules/document/lib/buildDocument.ts @@ -10,7 +10,7 @@ function buildDocument( ...documentFields, _id: idModule.lib.buildId(), reviewStatus: { hasBeenAmended: false, viewerNames: [] }, - status: 'loaded', + status: 'free', updateDate: new Date().getTime(), }; } diff --git a/packages/generic/core/src/modules/document/lib/getNextStatus.ts b/packages/generic/core/src/modules/document/lib/getNextStatus.ts index 226ce1cf2..dc2f6c54e 100644 --- a/packages/generic/core/src/modules/document/lib/getNextStatus.ts +++ b/packages/generic/core/src/modules/document/lib/getNextStatus.ts @@ -9,16 +9,6 @@ function getNextStatus({ route, }: Pick): documentType['status'] { switch (status) { - case 'loaded': - return 'nlpAnnotating'; - case 'nlpAnnotating': - if (route === 'automatic') { - return 'done'; - } else if (route === 'request') { - return 'toBeConfirmed'; - } else { - return 'free'; - } case 'free': return 'pending'; case 'pending': From 074b3d17cc5a659a44639b19b563fd7514ce5f57 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 31 Jan 2025 09:55:35 +0100 Subject: [PATCH 02/13] delete references to loaded and nlpAnnotating statuses --- .../cleanDocuments/cleanAssignations.ts | 2 - .../cleanDocuments/cleanDocuments.spec.ts | 19 +--- .../scripts/cleanDocuments/cleanDocuments.ts | 6 -- .../cleanDocuments/cleanLoadedDocuments.ts | 58 ------------ .../cleanUnconsistentTreatments.ts | 37 -------- .../lib/preAssignator/buildPreAssignator.ts | 8 +- .../lib/preAssignator/preAssignator.spec.ts | 2 +- .../countLoadedDocuments.spec.ts | 88 ------------------- .../documentService/countLoadedDocuments.ts | 8 -- .../countNlpAnnotatingDocuments.spec.ts | 88 ------------------- .../countNlpAnnotatingDocuments.ts | 8 -- ...tchDocumentWithoutAnnotationsNotIn.spec.ts | 68 -------------- .../fetchDocumentWithoutAnnotationsNotIn.ts | 28 ------ .../document/service/documentService/index.ts | 6 -- .../documentService/updateDocumentStatus.ts | 2 - .../modules/statistic/service/fetchSummary.ts | 4 - .../Admin/Summary/SummaryBox/SummaryBox.tsx | 10 --- .../Admin/Summary/SummaryDataFetcher.tsx | 2 - packages/generic/client/src/wordings/fr.ts | 2 - packages/generic/core/src/api/apiSchema.ts | 8 -- 20 files changed, 7 insertions(+), 447 deletions(-) delete mode 100644 packages/generic/backend/src/app/scripts/cleanDocuments/cleanLoadedDocuments.ts delete mode 100644 packages/generic/backend/src/app/scripts/cleanDocuments/cleanUnconsistentTreatments.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.spec.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.spec.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.spec.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.ts diff --git a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanAssignations.ts b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanAssignations.ts index 1f960d8a3..ad381642c 100644 --- a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanAssignations.ts +++ b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanAssignations.ts @@ -15,8 +15,6 @@ export { cleanAssignations }; async function cleanAssignations() { logger.log({ operationName: 'cleanAssignations', msg: 'START' }); const FORBIDDEN_STATUSES_FOR_ASSIGNATED_DOCUMENT: documentType['status'][] = [ - 'loaded', - 'nlpAnnotating', 'free', ]; const documentRepository = buildDocumentRepository(); diff --git a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.spec.ts b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.spec.ts index 34be66911..400818307 100644 --- a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.spec.ts +++ b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.spec.ts @@ -16,7 +16,6 @@ describe('cleanDocuments', () => { personneMorale: { isSensitive: false, isAnonymized: false }, }); const user = userModule.generator.generate({ role: 'admin' }); - const LOADED_DOCUMENTS_COUNT = 10; const FREE_DOCUMENTS_COUNT = 8; const DONE_DOCUMENTS_COUNT = 5; @@ -26,16 +25,11 @@ describe('cleanDocuments', () => { const treatmentRepository = buildTreatmentRepository(); const userRepository = buildUserRepository(); await userRepository.insert(user); - const documentsToInsert = range(LOADED_DOCUMENTS_COUNT).map(() => - documentModule.generator.generate({ status: 'loaded' }), + const documentsToInsert = range(FREE_DOCUMENTS_COUNT).map(() => + documentModule.generator.generate({ status: 'free' }), ); await documentRepository.insertMany(documentsToInsert); - for (let i = 0; i < FREE_DOCUMENTS_COUNT; i++) { - await documentRepository.updateStatusById( - documentsToInsert[i]._id, - 'free', - ); - } + await Promise.all( range(FREE_DOCUMENTS_COUNT).map(async (i) => { await treatmentService.createEmptyTreatment({ @@ -69,13 +63,6 @@ describe('cleanDocuments', () => { await cleanDocuments(); - const fetchedLoadedDocuments = await documentRepository.findAllByStatusProjection( - ['loaded'], - ['_id'], - ); - expect(fetchedLoadedDocuments.length).toBe( - LOADED_DOCUMENTS_COUNT - FREE_DOCUMENTS_COUNT, - ); const fetchedFreeDocuments = await documentRepository.findAllByStatusProjection( ['free'], ['_id'], diff --git a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.ts b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.ts index 6fb98ef31..fc3e9b714 100644 --- a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.ts +++ b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanDocuments.ts @@ -3,8 +3,6 @@ import { cleanAssignations } from './cleanAssignations'; import { cleanAssignedDocuments } from './cleanAssignedDocuments'; import { cleanDuplicatedDocuments } from './cleanDuplicatedDocuments'; import { cleanFreeDocuments } from './cleanFreeDocuments'; -import { cleanLoadedDocuments } from './cleanLoadedDocuments'; -import { cleanUnconsistentTreatments } from './cleanUnconsistentTreatments'; import { cleanOrphansTreatments } from './cleanOrphansTreatments'; export { cleanDocuments }; @@ -16,14 +14,10 @@ async function cleanDocuments() { await cleanAssignedDocuments(); - await cleanUnconsistentTreatments(); - await cleanAssignations(); await cleanFreeDocuments(); - await cleanLoadedDocuments(); - await cleanOrphansTreatments(); logger.log({ operationName: 'cleanDocuments', msg: 'DONE' }); diff --git a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanLoadedDocuments.ts b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanLoadedDocuments.ts deleted file mode 100644 index 082b6ad68..000000000 --- a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanLoadedDocuments.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { uniq } from 'lodash'; -import { documentService } from '../../../modules/document'; -import { buildDocumentRepository } from '../../../modules/document'; -import { logger } from '../../../utils'; - -export { cleanLoadedDocuments }; - -/** - * Reset all documents that are either loaded or nlpAnnotating - */ -async function cleanLoadedDocuments() { - logger.log({ operationName: 'cleanLoadedDocuments', msg: 'START' }); - - const documentRepository = buildDocumentRepository(); - - logger.log({ - operationName: 'cleanLoadedDocuments', - msg: 'Fetching "loaded" documents', - }); - const loadedDocuments = await documentRepository.findAllByStatusProjection( - ['loaded'], - ['_id'], - ); - - logger.log({ - operationName: 'cleanLoadedDocuments', - msg: `${loadedDocuments.length} loaded documents found`, - }); - - const loadedDocumentsIds = loadedDocuments.map(({ _id }) => _id); - - for (let i = 0, length = loadedDocumentsIds.length; i < length; i++) { - await documentService.resetDocument(loadedDocumentsIds[i]); - } - - logger.log({ - operationName: 'cleanLoadedDocuments', - msg: `"loaded" documents reset. Fetching non-treated documents...`, - }); - const notTreatedDocuments = await documentService.fetchDocumentsWithoutAnnotations(); - logger.log({ - operationName: 'cleanLoadedDocuments', - msg: `${ - notTreatedDocuments.length - } not treated documents found. Status are [${uniq( - notTreatedDocuments.map(({ status }) => status), - ).join(', ')}]. Setting status to loaded...`, - }); - - for (let i = 0, length = notTreatedDocuments.length; i < length; i++) { - await documentService.updateDocumentStatus( - notTreatedDocuments[i]._id, - 'loaded', - ); - } - - logger.log({ operationName: 'cleanLoadedDocuments', msg: 'DONE' }); -} diff --git a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanUnconsistentTreatments.ts b/packages/generic/backend/src/app/scripts/cleanDocuments/cleanUnconsistentTreatments.ts deleted file mode 100644 index ed5ff63ee..000000000 --- a/packages/generic/backend/src/app/scripts/cleanDocuments/cleanUnconsistentTreatments.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { idModule, treatmentModule } from '@label/core'; -import { - buildDocumentRepository, - documentService, -} from '../../../modules/document'; -import { treatmentService } from '../../../modules/treatment'; -import { logger } from '../../../utils'; - -export { cleanUnconsistentTreatments }; - -/** - * Reset documents with unconsistent annotations - */ -async function cleanUnconsistentTreatments() { - logger.log({ operationName: 'cleanUnconsistentTreatments', msg: 'START' }); - const documentRepository = buildDocumentRepository(); - const documents = await documentRepository.findAllProjection(['_id']); - const documentIds = documents.map(({ _id }) => _id); - for (let i = 0, length = documents.length; i < length; i++) { - try { - const treatments = await treatmentService.fetchTreatmentsByDocumentId( - documentIds[i], - ); - treatmentModule.lib.computeAnnotations(treatments); - } catch (error) { - logger.error({ - operationName: 'cleanUnconsistentTreatments', - msg: `Resetting document ${idModule.lib.convertToString( - documents[i]._id, - )}`, - data: error as Record, - }); - await documentService.updateDocumentStatus(documentIds[i], 'loaded'); - } - } - logger.log({ operationName: 'cleanUnconsistentTreatments', msg: 'DONE' }); -} diff --git a/packages/generic/backend/src/lib/preAssignator/buildPreAssignator.ts b/packages/generic/backend/src/lib/preAssignator/buildPreAssignator.ts index fcdb80195..430e28813 100644 --- a/packages/generic/backend/src/lib/preAssignator/buildPreAssignator.ts +++ b/packages/generic/backend/src/lib/preAssignator/buildPreAssignator.ts @@ -17,7 +17,7 @@ function buildPreAssignator() { msg: `Starting preAssignation for document ${document.source} ${document.documentNumber}`, }); - if (document.status === 'nlpAnnotating' || document.status === 'loaded') { + if (document.status === 'free') { const preAssignationForDocument = (await preAssignationService.fetchPreAssignationBySourceAndNumber( document.documentNumber.toString(), @@ -67,11 +67,9 @@ function buildPreAssignator() { } else { logger.error({ operationName: 'preAssignation', - msg: `Document status must be loaded or nlpAnnotating before pre-assign it`, + msg: `Document status must be free before pre-assign it`, }); - throw new Error( - 'Document status must be loaded or nlpAnnotating before pre-assign it', - ); + throw new Error('Document status must be free before pre-assign it'); } } } diff --git a/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts b/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts index 8842c5320..afcb03615 100644 --- a/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts +++ b/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts @@ -28,7 +28,7 @@ describe('buildPreAssignator', () => { const documentNumber = 123456; const source = 'juritest'; const documentToPreAssign = documentModule.generator.generate({ - status: 'loaded', + status: 'free', source: source, documentNumber: documentNumber, }); diff --git a/packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.spec.ts b/packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.spec.ts deleted file mode 100644 index 01e0c06fb..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { assignationModule, documentModule, userModule } from '@label/core'; -import { buildAssignationRepository } from '../../../assignation/repository'; -import { buildUserRepository } from '../../../user/repository'; -import { buildDocumentRepository } from '../../repository'; -import { countLoadedDocuments } from './countLoadedDocuments'; - -describe('countLoadedDocuments', () => { - const documentRepository = buildDocumentRepository(); - const assignationRepository = buildAssignationRepository(); - const userRepository = buildUserRepository(); - - it('should return loaded documents', async () => { - const user = userModule.generator.generate({ - name: 'NAME', - role: 'annotator', - }); - const loadedDocument = documentModule.generator.generate({ - status: 'loaded', - }); - const nlpAnnotatingDocument = documentModule.generator.generate({ - status: 'nlpAnnotating', - }); - const freeDocument = documentModule.generator.generate({ - status: 'free', - }); - const pendingDocument = documentModule.generator.generate({ - status: 'pending', - }); - const savedDocument = documentModule.generator.generate({ - status: 'saved', - }); - const doneDocument = documentModule.generator.generate({ - status: 'done', - }); - const rejectedDocument = documentModule.generator.generate({ - status: 'rejected', - }); - const lockedDocument = documentModule.generator.generate({ - status: 'locked', - }); - const pendingDocumentAssignation = assignationModule.generator.generate({ - documentId: pendingDocument._id, - userId: user._id, - }); - const savedDocumentAssignation = assignationModule.generator.generate({ - documentId: savedDocument._id, - userId: user._id, - }); - const doneDocumentAssignation = assignationModule.generator.generate({ - documentId: doneDocument._id, - userId: user._id, - }); - const rejectedDocumentAssignation = assignationModule.generator.generate({ - documentId: rejectedDocument._id, - userId: user._id, - }); - const lockedDocumentAssignation = assignationModule.generator.generate({ - documentId: lockedDocument._id, - userId: user._id, - }); - await Promise.all( - [ - loadedDocument, - nlpAnnotatingDocument, - freeDocument, - pendingDocument, - savedDocument, - doneDocument, - rejectedDocument, - lockedDocument, - ].map(documentRepository.insert), - ); - await Promise.all( - [ - pendingDocumentAssignation, - savedDocumentAssignation, - doneDocumentAssignation, - rejectedDocumentAssignation, - lockedDocumentAssignation, - ].map(assignationRepository.insert), - ); - await userRepository.insert(user); - - const loadedDocumentsCount = await countLoadedDocuments(); - - expect(loadedDocumentsCount).toEqual([loadedDocument].length); - }); -}); diff --git a/packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.ts b/packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.ts deleted file mode 100644 index abf72b106..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/countLoadedDocuments.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { buildDocumentRepository } from '../../repository'; - -export { countLoadedDocuments }; - -async function countLoadedDocuments() { - const documentRepository = buildDocumentRepository(); - return documentRepository.countByStatus(['loaded']); -} diff --git a/packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.spec.ts b/packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.spec.ts deleted file mode 100644 index 2cfc44365..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { assignationModule, documentModule, userModule } from '@label/core'; -import { buildAssignationRepository } from '../../../assignation/repository'; -import { buildUserRepository } from '../../../user/repository'; -import { buildDocumentRepository } from '../../repository'; -import { countNlpAnnotatingDocuments } from './countNlpAnnotatingDocuments'; - -describe('countNlpAnnotatingDocuments', () => { - const documentRepository = buildDocumentRepository(); - const assignationRepository = buildAssignationRepository(); - const userRepository = buildUserRepository(); - - it('should return nlpAnnotating documents', async () => { - const user = userModule.generator.generate({ - name: 'NAME', - role: 'annotator', - }); - const loadedDocument = documentModule.generator.generate({ - status: 'loaded', - }); - const nlpAnnotatingDocument = documentModule.generator.generate({ - status: 'nlpAnnotating', - }); - const freeDocument = documentModule.generator.generate({ - status: 'free', - }); - const pendingDocument = documentModule.generator.generate({ - status: 'pending', - }); - const savedDocument = documentModule.generator.generate({ - status: 'saved', - }); - const doneDocument = documentModule.generator.generate({ - status: 'done', - }); - const rejectedDocument = documentModule.generator.generate({ - status: 'rejected', - }); - const lockedDocument = documentModule.generator.generate({ - status: 'locked', - }); - const pendingDocumentAssignation = assignationModule.generator.generate({ - documentId: pendingDocument._id, - userId: user._id, - }); - const savedDocumentAssignation = assignationModule.generator.generate({ - documentId: savedDocument._id, - userId: user._id, - }); - const doneDocumentAssignation = assignationModule.generator.generate({ - documentId: doneDocument._id, - userId: user._id, - }); - const rejectedDocumentAssignation = assignationModule.generator.generate({ - documentId: rejectedDocument._id, - userId: user._id, - }); - const lockedDocumentAssignation = assignationModule.generator.generate({ - documentId: lockedDocument._id, - userId: user._id, - }); - await Promise.all( - [ - loadedDocument, - nlpAnnotatingDocument, - freeDocument, - pendingDocument, - savedDocument, - doneDocument, - rejectedDocument, - lockedDocument, - ].map(documentRepository.insert), - ); - await Promise.all( - [ - pendingDocumentAssignation, - savedDocumentAssignation, - doneDocumentAssignation, - rejectedDocumentAssignation, - lockedDocumentAssignation, - ].map(assignationRepository.insert), - ); - await userRepository.insert(user); - - const nlpAnnotatingDocumentsCount = await countNlpAnnotatingDocuments(); - - expect(nlpAnnotatingDocumentsCount).toEqual([nlpAnnotatingDocument].length); - }); -}); diff --git a/packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.ts b/packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.ts deleted file mode 100644 index 50007723e..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/countNlpAnnotatingDocuments.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { buildDocumentRepository } from '../../repository'; - -export { countNlpAnnotatingDocuments }; - -async function countNlpAnnotatingDocuments() { - const documentRepository = buildDocumentRepository(); - return documentRepository.countByStatus(['nlpAnnotating']); -} diff --git a/packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.spec.ts b/packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.spec.ts deleted file mode 100644 index fff74321f..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { documentModule } from '@label/core'; -import { fetchDocumentWithoutAnnotationsNotIn } from './fetchDocumentWithoutAnnotationsNotIn'; -import { buildDocumentRepository } from '../../repository'; - -describe('fetchDocumentWithoutAnnotationsNotIn', () => { - const documentRepository = buildDocumentRepository(); - - it('should fetch all the to annotate in priority order', async () => { - const documentPriority4 = documentModule.generator.generate({ - priority: 4, - status: 'loaded', - }); - const documentPriority3 = documentModule.generator.generate({ - priority: 3, - status: 'loaded', - }); - const documentPriority2 = documentModule.generator.generate({ - priority: 2, - status: 'loaded', - }); - const documentPriority1 = documentModule.generator.generate({ - priority: 1, - status: 'loaded', - }); - const documentPriority0 = documentModule.generator.generate({ - priority: 0, - status: 'loaded', - }); - - documentRepository.insert(documentPriority0); - documentRepository.insert(documentPriority1); - documentRepository.insert(documentPriority2); - documentRepository.insert(documentPriority3); - documentRepository.insert(documentPriority4); - - expect(await fetchDocumentWithoutAnnotationsNotIn([])).toEqual( - documentPriority4, - ); - - expect( - await fetchDocumentWithoutAnnotationsNotIn([documentPriority4._id]), - ).toEqual(documentPriority3); - - expect( - await fetchDocumentWithoutAnnotationsNotIn([ - documentPriority4._id, - documentPriority3._id, - ]), - ).toEqual(documentPriority2); - - expect( - await fetchDocumentWithoutAnnotationsNotIn([ - documentPriority4._id, - documentPriority3._id, - documentPriority2._id, - ]), - ).toEqual(documentPriority1); - - expect( - await fetchDocumentWithoutAnnotationsNotIn([ - documentPriority4._id, - documentPriority3._id, - documentPriority2._id, - documentPriority1._id, - ]), - ).toEqual(documentPriority0); - }); -}); diff --git a/packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.ts b/packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.ts deleted file mode 100644 index 953b6183a..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/fetchDocumentWithoutAnnotationsNotIn.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { documentType } from '@label/core'; -import { treatmentService } from '../../../treatment'; -import { buildDocumentRepository } from '../../repository'; - -export { fetchDocumentWithoutAnnotationsNotIn }; - -async function fetchDocumentWithoutAnnotationsNotIn( - documentIdsToExclude: documentType['_id'][], -): Promise { - const documentRepository = buildDocumentRepository(); - - const treatedDocumentIds = await treatmentService.fetchTreatedDocumentIds(); - const idsNotToSearchIn = [...treatedDocumentIds, ...documentIdsToExclude]; - let document: documentType | undefined; - - const priorities = [4, 3, 2, 1, 0]; - - for (const priority of priorities) { - document = await documentRepository.findOneByStatusAndPriorityNotIn( - { status: 'loaded', priority }, - idsNotToSearchIn, - ); - if (document) { - return document; - } - } - return undefined; -} diff --git a/packages/generic/backend/src/modules/document/service/documentService/index.ts b/packages/generic/backend/src/modules/document/service/documentService/index.ts index 72eaa5a1a..0a4671580 100644 --- a/packages/generic/backend/src/modules/document/service/documentService/index.ts +++ b/packages/generic/backend/src/modules/document/service/documentService/index.ts @@ -5,9 +5,7 @@ import { countDocumentsWithoutAnnotations } from './countDocumentsWithoutAnnotat import { countDoneDocumentsWithoutLossNotIn } from './countDoneDocumentsWithoutLossNotIn'; import { countDoneDocuments } from './countDoneDocuments'; import { countFreeDocuments } from './countFreeDocuments'; -import { countLoadedDocuments } from './countLoadedDocuments'; import { countLockedDocuments } from './countLockedDocuments'; -import { countNlpAnnotatingDocuments } from './countNlpAnnotatingDocuments'; import { countPendingDocuments } from './countPendingDocuments'; import { countRejectedDocuments } from './countRejectedDocuments'; import { countSavedDocuments } from './countSavedDocuments'; @@ -23,7 +21,6 @@ import { fetchDocument } from './fetchDocument'; import { buildFetchDocumentsForUser } from './fetchDocumentsForUser'; import { fetchDocumentBySourceAndDocumentNumber } from './fetchDocumentBySourceAndDocumentNumber'; import { fetchDocumentsReadyToExport } from './fetchDocumentsReadyToExport'; -import { fetchDocumentWithoutAnnotationsNotIn } from './fetchDocumentWithoutAnnotationsNotIn'; import { fetchDoneDocuments } from './fetchDoneDocuments'; import { fetchDoneDocumentWithoutLossNotIn } from './fetchDoneDocumentWithoutLossNotIn'; import { fetchFreeDocumentsIds } from './fetchFreeDocumentsIds'; @@ -70,9 +67,7 @@ function buildDocumentService() { countDoneDocumentsWithoutLossNotIn, countDoneDocuments, countFreeDocuments, - countLoadedDocuments, countLockedDocuments, - countNlpAnnotatingDocuments, countPendingDocuments, countRejectedDocuments, countSavedDocuments, @@ -89,7 +84,6 @@ function buildDocumentService() { fetchDocumentBySourceAndDocumentNumber, fetchDocumentsForUser: buildFetchDocumentsForUser(checkCallAttempts), fetchDocumentsReadyToExport, - fetchDocumentWithoutAnnotationsNotIn, fetchDoneDocuments, fetchDoneDocumentWithoutLossNotIn, fetchFreeDocumentsIds, diff --git a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts b/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts index af660b17e..7f37dedc8 100644 --- a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts +++ b/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts @@ -25,8 +25,6 @@ async function updateDocumentStatus( } if (status === 'free') { await assignationService.deleteAssignationsByDocumentId(_id); - } else if (status === 'loaded') { - await resetDocument(_id); } logger.log({ operationName: 'updateDocumentStatus', diff --git a/packages/generic/backend/src/modules/statistic/service/fetchSummary.ts b/packages/generic/backend/src/modules/statistic/service/fetchSummary.ts index 58617017d..c8fb11c60 100644 --- a/packages/generic/backend/src/modules/statistic/service/fetchSummary.ts +++ b/packages/generic/backend/src/modules/statistic/service/fetchSummary.ts @@ -3,8 +3,6 @@ import { documentService } from '../../../modules/document'; export { fetchSummary }; async function fetchSummary() { - const loadedDocumentsCount = await documentService.countLoadedDocuments(); - const nlpAnnotatingDocumentsCount = await documentService.countNlpAnnotatingDocuments(); const freeDocumentsCount = await documentService.countFreeDocuments(); const pendingDocumentsCount = await documentService.countPendingDocuments(); const savedDocumentsCount = await documentService.countSavedDocuments(); @@ -13,8 +11,6 @@ async function fetchSummary() { const rejectedDocumentsCount = await documentService.countRejectedDocuments(); return { - loadedDocuments: loadedDocumentsCount, - nlpAnnotatingDocuments: nlpAnnotatingDocumentsCount, freeDocuments: freeDocumentsCount, pendingDocuments: pendingDocumentsCount, savedDocuments: savedDocumentsCount, diff --git a/packages/generic/client/src/pages/Admin/Summary/SummaryBox/SummaryBox.tsx b/packages/generic/client/src/pages/Admin/Summary/SummaryBox/SummaryBox.tsx index bdfbde580..098116ffe 100644 --- a/packages/generic/client/src/pages/Admin/Summary/SummaryBox/SummaryBox.tsx +++ b/packages/generic/client/src/pages/Admin/Summary/SummaryBox/SummaryBox.tsx @@ -9,8 +9,6 @@ export type { summaryType }; const ROW_HEIGHT = 30; type summaryType = { - loadedDocuments: number; - nlpAnnotatingDocuments: number; freeDocuments: number; pendingDocuments: number; savedDocuments: number; @@ -40,14 +38,6 @@ function SummaryBox(props: { summary: summaryType; width: number }) { const { summary } = props; return [ - { - label: wordings.summaryPage.box.fields.loadedDocuments, - value: summary.loadedDocuments, - }, - { - label: wordings.summaryPage.box.fields.nlpAnnotatingDocuments, - value: summary.nlpAnnotatingDocuments, - }, { label: wordings.summaryPage.box.fields.freeDocuments, value: summary.freeDocuments, diff --git a/packages/generic/client/src/pages/Admin/Summary/SummaryDataFetcher.tsx b/packages/generic/client/src/pages/Admin/Summary/SummaryDataFetcher.tsx index 9f50158c9..c177bc317 100644 --- a/packages/generic/client/src/pages/Admin/Summary/SummaryDataFetcher.tsx +++ b/packages/generic/client/src/pages/Admin/Summary/SummaryDataFetcher.tsx @@ -32,8 +32,6 @@ function SummaryDataFetcher(props: { function buildFetchSummary() { return async () => { let summary = { - loadedDocuments: -1, - nlpAnnotatingDocuments: -1, freeDocuments: -1, pendingDocuments: -1, savedDocuments: -1, diff --git a/packages/generic/client/src/wordings/fr.ts b/packages/generic/client/src/wordings/fr.ts index 322606b05..366abc34d 100644 --- a/packages/generic/client/src/wordings/fr.ts +++ b/packages/generic/client/src/wordings/fr.ts @@ -407,8 +407,6 @@ const fr = { welcomeMessage: 'Bienvenue dans Label', box: { fields: { - loadedDocuments: 'Documents chargés', - nlpAnnotatingDocuments: 'Documents en annotation', freeDocuments: 'Documents en attente', pendingDocuments: 'Documents assignés', savedDocuments: 'Documents en relecture', diff --git a/packages/generic/core/src/api/apiSchema.ts b/packages/generic/core/src/api/apiSchema.ts index 13e54daa5..70bd25b5b 100644 --- a/packages/generic/core/src/api/apiSchema.ts +++ b/packages/generic/core/src/api/apiSchema.ts @@ -332,14 +332,6 @@ const apiSchema = { out: buildModel({ kind: 'object', content: { - loadedDocuments: buildModel({ - kind: 'primitive', - content: 'number', - } as const), - nlpAnnotatingDocuments: buildModel({ - kind: 'primitive', - content: 'number', - } as const), freeDocuments: buildModel({ kind: 'primitive', content: 'number', From adb7c6940e4106ea0417a4878a1a2c9eafda9a73 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 31 Jan 2025 10:01:34 +0100 Subject: [PATCH 03/13] test and lint --- .../backend/src/lib/preAssignator/preAssignator.spec.ts | 4 +--- .../document/service/documentService/updateDocumentStatus.ts | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts b/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts index afcb03615..562da2f9a 100644 --- a/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts +++ b/packages/generic/backend/src/lib/preAssignator/preAssignator.spec.ts @@ -13,9 +13,7 @@ describe('buildPreAssignator', () => { }); expect( preAssignator.preAssignDocument(documentNotFree), - ).rejects.toThrowError( - 'Document status must be loaded or nlpAnnotating before pre-assign it', - ); + ).rejects.toThrowError('Document status must be free before pre-assign it'); }); it('must find preAssignation and assign document', async () => { diff --git a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts b/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts index 7f37dedc8..e3dcdaeff 100644 --- a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts +++ b/packages/generic/backend/src/modules/document/service/documentService/updateDocumentStatus.ts @@ -2,7 +2,6 @@ import { errorHandlers } from 'sder-core'; import { documentType, idModule } from '@label/core'; import { assignationService } from '../../../assignation'; import { buildDocumentRepository } from '../../repository'; -import { resetDocument } from './resetDocument'; import { logger } from '../../../../utils'; export { updateDocumentStatus }; From a86bde6b4fadcdc5e8fbef8d68fccbcd2479cb50 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 31 Jan 2025 11:16:00 +0100 Subject: [PATCH 04/13] delete nlp references --- .env.example | 2 -- .../deploy_backend/defaults/main/defaults.yml | 9 ----- .../roles/deploy_backend/tasks/configmap.yml | 2 -- docker.env.example | 2 -- docs/cronJobs.md | 4 --- docs/documentStatuses.md | 2 -- docs/scripts.md | 13 ------- packages/generic/backend/src/app/envSchema.ts | 2 -- .../repository/buildDocumentRepository.ts | 6 ---- .../repository/buildFakeDocumentRepository.ts | 19 ---------- .../customDocumentRepositoryType.ts | 4 --- .../document/service/documentService/index.ts | 2 -- .../updateDocumentNlpVersions.spec.ts | 36 ------------------- .../updateDocumentNlpVersions.ts | 24 ------------- packages/generic/client/src/wordings/fr.ts | 2 -- 15 files changed, 129 deletions(-) delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.spec.ts delete mode 100644 packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.ts diff --git a/.env.example b/.env.example index dd63a9cbd..6965a9757 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,5 @@ LABEL_API_PORT=55430 DBSDER_API_URL=http://localhost:3008 DBSDER_API_KEY=3d8767ff-ed2a-47bd-91c2-f5ebac712f2c DBSDER_API_VERSION=v1 -NLP_PSEUDONYMISATION_API_URL=http://localhost:8081 -NLP_PSEUDONYMISATION_API_ENABLED=false JWT_PRIVATE_KEY=myPrivateKey RUN_MODE=LOCAL diff --git a/ansible/roles/deploy_backend/defaults/main/defaults.yml b/ansible/roles/deploy_backend/defaults/main/defaults.yml index dac95de8b..12b40f6d6 100644 --- a/ansible/roles/deploy_backend/defaults/main/defaults.yml +++ b/ansible/roles/deploy_backend/defaults/main/defaults.yml @@ -1,14 +1,5 @@ --- jobs: - - name: "nlp-annotation" - schedule: "*/5 6-19 * * *" - successful_jobs_history_limit: 7 - failed_jobs_history_limit: 7 - backoff_limit: 0 - restartPolicy: "Never" - parallelism: 1 - active_deadline_seconds: 18000 - command: "dist/scripts/annotateDocumentsWithoutAnnotationsWithNlp.js" - name: "tobetreated-document-import" schedule: "*/15 6-17 * * *" successful_jobs_history_limit: 7 diff --git a/ansible/roles/deploy_backend/tasks/configmap.yml b/ansible/roles/deploy_backend/tasks/configmap.yml index 4a8f2df6f..c25160995 100644 --- a/ansible/roles/deploy_backend/tasks/configmap.yml +++ b/ansible/roles/deploy_backend/tasks/configmap.yml @@ -17,8 +17,6 @@ APP_ID: "{{ label_back_app_id }}" KUBE_NAMESPACE: "{{ label_kube_namespace }}" ROOT_PATH: "{{ label_back_root_path }}" - NLP_PSEUDONYMISATION_API_URL: "{{ nlp_pseudonymisation_api_url }}" - NLP_PSEUDONYMISATION_API_ENABLED: "{{ nlp_pseudonymisation_api_enabled }}" DBSDER_API_URL: "{{ dbsder_api_url }}" DBSDER_API_VERSION: "{{ dbsder_api_version }}" LABEL_API_PORT: "{{ label_api_port }}" diff --git a/docker.env.example b/docker.env.example index 734e880ff..11e9633f1 100644 --- a/docker.env.example +++ b/docker.env.example @@ -5,7 +5,5 @@ LABEL_API_PORT=55430 DBSDER_API_URL=http://dbsder-api-dbsder-api-1:3000 DBSDER_API_KEY=3d8767ff-ed2a-47bd-91c2-f5ebac712f2c DBSDER_API_VERSION=v1 -NLP_PSEUDONYMISATION_API_URL=http://host.docker.internal:8081 -NLP_PSEUDONYMISATION_API_ENABLED=false JWT_PRIVATE_KEY=myPrivateKey RUN_MODE=LOCAL diff --git a/docs/cronJobs.md b/docs/cronJobs.md index e62db193f..2e42c7998 100644 --- a/docs/cronJobs.md +++ b/docs/cronJobs.md @@ -2,10 +2,6 @@ Here are all the cron jobs of Label : -## nlp-annotation - -Send Label documents to the nlp annotation service. - ## import-j-7 Import recent (7 days) documents from the source databases. diff --git a/docs/documentStatuses.md b/docs/documentStatuses.md index cf835f2aa..cb6956a06 100644 --- a/docs/documentStatuses.md +++ b/docs/documentStatuses.md @@ -2,8 +2,6 @@ A `document` is supposed to follow a specific flow once it enters the label database. Its status will evolve accordingly. -- `loaded`: the document has only been imported in LABEL. No treatment has been done on it. -- `nlpAnnotating`: the document is currently being annotated by the NLP annotator. - `free`: the document is ready to be annotated by a working user. There are already several `treatments` related to that document (one by the `NLP`, maybe one with the `supplementaryAnnotations` if decision is partially public) - `pending`: the document is proposed to a working user. An `assignation` and a corresponding empty `treatment` have been created. The document won't be proposed to another working user. - `saved`: the document is being annotated by a working user. diff --git a/docs/scripts.md b/docs/scripts.md index ea3e78bbd..09638cfcb 100644 --- a/docs/scripts.md +++ b/docs/scripts.md @@ -2,10 +2,6 @@ Find here the list of available scripts with a brief description. Find options at [`packages/courDeCassation/src/scripts`](https://github.com/Cour-de-cassation/label/tree/dev/packages/courDeCassation/src/scripts). -## annotateDocumentsWithoutAnnotationsWithNlp - -Send documents to the NLP API and retreive their annotations. - ## autoImportDocumentsFromSder Import all documents to be pseudonymized from SDER. @@ -58,10 +54,6 @@ Export treated documents (with the 4 days delay). Export important "publishable" documents. -## fillLossOfAllTreatedDocuments - -Calculate loss of the documents with the NLP API. - ## freePendingDocuments Free documents assignated to an annotator that is AFK after X minutes. @@ -94,11 +86,6 @@ List documents with problem reports. Purge db (for now only the users in statistics after 6 months). -## reAnnotateFreeDocuments - -If the NLP API was outdated or buggy, reannotate free documents. Warning: suspend nlp-annotation job during this operation to avoid side effects. -This script only prepare documents and set their status to loaded, the next nlp-annotation job will reannotate them. - ## renewCache Renew the cache. diff --git a/packages/generic/backend/src/app/envSchema.ts b/packages/generic/backend/src/app/envSchema.ts index c60c9227f..6b01c0698 100644 --- a/packages/generic/backend/src/app/envSchema.ts +++ b/packages/generic/backend/src/app/envSchema.ts @@ -8,7 +8,5 @@ export const envSchema = Joi.object({ DBSDER_API_URL: Joi.string().uri().required(), DBSDER_API_KEY: Joi.string().required(), DBSDER_API_VERSION: Joi.string().required(), - NLP_PSEUDONYMISATION_API_URL: Joi.string().uri().required(), - NLP_PSEUDONYMISATION_API_ENABLED: Joi.boolean().required(), JWT_PRIVATE_KEY: Joi.string().required(), }).unknown(); diff --git a/packages/generic/backend/src/modules/document/repository/buildDocumentRepository.ts b/packages/generic/backend/src/modules/document/repository/buildDocumentRepository.ts index c4c7d9fc9..a236ac55e 100644 --- a/packages/generic/backend/src/modules/document/repository/buildDocumentRepository.ts +++ b/packages/generic/backend/src/modules/document/repository/buildDocumentRepository.ts @@ -228,12 +228,6 @@ const buildDocumentRepository = buildRepositoryBuilder< .toArray(); }, - async updateNlpVersionsById(_id, nlpVersions) { - await collection.updateOne({ _id }, { $set: { nlpVersions } }); - const updatedDocument = await collection.findOne({ _id }); - return updatedDocument || undefined; - }, - async updateLossById(_id, loss) { await collection.updateOne({ _id }, { $set: { loss } }); const updatedDocument = await collection.findOne({ _id }); diff --git a/packages/generic/backend/src/modules/document/repository/buildFakeDocumentRepository.ts b/packages/generic/backend/src/modules/document/repository/buildFakeDocumentRepository.ts index a7e00a9f4..8da14ef5f 100644 --- a/packages/generic/backend/src/modules/document/repository/buildFakeDocumentRepository.ts +++ b/packages/generic/backend/src/modules/document/repository/buildFakeDocumentRepository.ts @@ -235,25 +235,6 @@ const buildFakeDocumentRepository = buildFakeRepositoryBuilder< return documents; }, - async updateNlpVersionsById(_id, nlpVersions) { - updateFakeCollection( - collection, - collection.map((document) => - idModule.lib.equalId(_id, document._id) - ? { - ...document, - nlpVersions, - } - : document, - ), - ); - const updatedDocument = collection.find((document) => - idModule.lib.equalId(_id, document._id), - ); - - return updatedDocument; - }, - async updateLossById(_id, loss) { updateFakeCollection( collection, diff --git a/packages/generic/backend/src/modules/document/repository/customDocumentRepositoryType.ts b/packages/generic/backend/src/modules/document/repository/customDocumentRepositoryType.ts index 8f7e2b035..235183017 100644 --- a/packages/generic/backend/src/modules/document/repository/customDocumentRepositoryType.ts +++ b/packages/generic/backend/src/modules/document/repository/customDocumentRepositoryType.ts @@ -82,10 +82,6 @@ type customDocumentRepositoryType = { _id: idType, loss: documentType['loss'], ) => Promise; - updateNlpVersionsById: ( - _id: idType, - nlpVersions: documentType['nlpVersions'], - ) => Promise; updateAdditionalTermsParsingFailed: ( _id: idType, additionalTermsParsingFailed: documentType['decisionMetadata']['additionalTermsParsingFailed'], diff --git a/packages/generic/backend/src/modules/document/service/documentService/index.ts b/packages/generic/backend/src/modules/document/service/documentService/index.ts index 0a4671580..247db97c5 100644 --- a/packages/generic/backend/src/modules/document/service/documentService/index.ts +++ b/packages/generic/backend/src/modules/document/service/documentService/index.ts @@ -43,7 +43,6 @@ import { updateDocumentComputedAdditionalTerms } from './updateDocumentComputedA import { updateDocumentStatus } from './updateDocumentStatus'; import { fetchAllImporters } from './fetchAllImporters'; import { updateDocumentAdditionalTermsParsingFailed } from './updateDocumentAdditionalTermsParsingFailed'; -import { updateDocumentNlpVersions } from './updateDocumentNlpVersions'; import { updateDocumentChecklist } from './updateDocumentChecklist'; export { buildDocumentService, documentService }; @@ -105,7 +104,6 @@ function buildDocumentService() { updateDocumentCategoriesToOmit, updateDocumentComputedAdditionalTerms, updateDocumentAdditionalTermsParsingFailed, - updateDocumentNlpVersions, updateDocumentChecklist, }; } diff --git a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.spec.ts b/packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.spec.ts deleted file mode 100644 index 40c1d9edd..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { documentModule } from '@label/core'; -import { buildDocumentRepository } from '../../repository'; -import { updateDocumentNlpVersions } from './updateDocumentNlpVersions'; -describe('updateDocumentNlpVersions', () => { - const documentRepository = buildDocumentRepository(); - - it('should update document nlpVersions', async () => { - const document = documentModule.generator.generate(); - await documentRepository.insert(document); - - const nlpVersionsMock = { - juriSpacyTokenizer: { - version: 'VERSION', - date: 'DATE', - }, - juritools: { - version: 'VERSION', - date: 'DATE', - }, - pseudonymisationApi: { - version: 'VERSION', - date: 'DATE', - }, - model: { - name: 'MODEL', - }, - }; - - const updatedDocument = await updateDocumentNlpVersions( - document._id, - nlpVersionsMock, - ); - - expect(updatedDocument).toEqual(nlpVersionsMock); - }); -}); diff --git a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.ts b/packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.ts deleted file mode 100644 index 228ecee80..000000000 --- a/packages/generic/backend/src/modules/document/service/documentService/updateDocumentNlpVersions.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { errorHandlers } from 'sder-core'; -import { documentType, idModule } from '@label/core'; -import { buildDocumentRepository } from '../../repository'; - -export { updateDocumentNlpVersions }; - -async function updateDocumentNlpVersions( - _id: documentType['_id'], - nlpVersions: documentType['nlpVersions'], -) { - const documentRepository = buildDocumentRepository(); - const updatedDocument = await documentRepository.updateNlpVersionsById( - _id, - nlpVersions, - ); - if (!updatedDocument) { - throw errorHandlers.notFoundErrorHandler.build( - `The document ${idModule.lib.convertToString( - _id, - )} was not found in the document collection`, - ); - } - return nlpVersions; -} diff --git a/packages/generic/client/src/wordings/fr.ts b/packages/generic/client/src/wordings/fr.ts index 366abc34d..f91ebaf4b 100644 --- a/packages/generic/client/src/wordings/fr.ts +++ b/packages/generic/client/src/wordings/fr.ts @@ -79,8 +79,6 @@ const fr = { default: 'N/A', }, documentStatus: { - loaded: "En attente d'annotation par le moteur NLP", - nlpAnnotating: "En cours d'annotation par le moteur NLP", free: 'Disponible pour être relu', pending: 'Assigné à un agent', saved: 'En cours de relecture par un agent', From a2cea413fc54361bb4d04530b12775fa6bd54be9 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Wed, 5 Feb 2025 14:58:27 +0100 Subject: [PATCH 05/13] remove loaded and nlpAnnotating references --- .../client/src/components/business/DocumentStatusIcon.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/generic/client/src/components/business/DocumentStatusIcon.tsx b/packages/generic/client/src/components/business/DocumentStatusIcon.tsx index da35ed09d..df70d7e1d 100644 --- a/packages/generic/client/src/components/business/DocumentStatusIcon.tsx +++ b/packages/generic/client/src/components/business/DocumentStatusIcon.tsx @@ -9,8 +9,6 @@ const documentStatusIconNameMapping: Record< documentType['status'], { iconName: iconNameType; colorName: 'alert' | 'primary' } > = { - loaded: { iconName: 'waiting', colorName: 'primary' }, - nlpAnnotating: { iconName: 'waiting', colorName: 'primary' }, free: { iconName: 'waiting', colorName: 'primary' }, pending: { iconName: 'assigned', colorName: 'primary' }, saved: { iconName: 'update', colorName: 'primary' }, From f72043b8f259fa50f5dda064db7560874c873a05 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Wed, 5 Feb 2025 15:51:34 +0100 Subject: [PATCH 06/13] remove nlp api url --- ansible/group_vars/all/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/ansible/group_vars/all/main.yml b/ansible/group_vars/all/main.yml index 9b2fab7c1..b6c866bfe 100644 --- a/ansible/group_vars/all/main.yml +++ b/ansible/group_vars/all/main.yml @@ -6,8 +6,6 @@ label_api_port: "55430" # pas encore utilisé, a utiliser dans le dockerfile du label_client_app_id: "label-client" label_back_app_id: "label-backend" label_back_root_path: "label/api" -nlp_pseudonymisation_api_url: "http://nlp-pseudonymisation-api-service.nlp.svc.cluster.local:8081" -nlp_pseudonymisation_api_enabled: "true" dbsder_api_url: "http://api-service.dbsder:3000" # url not tested dbsder_api_version: "v1" label_db_name: "labelDb" From eba0762ef584cd53bb3bfc5667f29299823fa58e Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Wed, 12 Feb 2025 16:40:49 +0100 Subject: [PATCH 07/13] import last NLP label treatment --- .../scripts/autoImportDocumentsFromSder.ts | 7 ++-- .../src/lib/connector/buildConnector.ts | 36 +++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/courDeCassation/src/scripts/autoImportDocumentsFromSder.ts b/packages/courDeCassation/src/scripts/autoImportDocumentsFromSder.ts index 5c2a03033..5122e8e3c 100644 --- a/packages/courDeCassation/src/scripts/autoImportDocumentsFromSder.ts +++ b/packages/courDeCassation/src/scripts/autoImportDocumentsFromSder.ts @@ -1,16 +1,17 @@ import { buildBackend } from '@label/backend'; import { sderConnector } from '../connector'; import { parametersHandler } from '../lib/parametersHandler'; +import { settingsType } from '@label/core'; (async () => { const { settings } = await parametersHandler.getParameters(); const backend = buildBackend(settings); - backend.runScript(() => autoImportDocumentsFromSder(), { + backend.runScript(() => autoImportDocumentsFromSder(settings), { shouldLoadDb: true, }); })(); -async function autoImportDocumentsFromSder() { - await sderConnector.importNewDocuments(); +async function autoImportDocumentsFromSder(settings: settingsType) { + await sderConnector.importNewDocuments(settings); } diff --git a/packages/generic/backend/src/lib/connector/buildConnector.ts b/packages/generic/backend/src/lib/connector/buildConnector.ts index 4c7eb76f7..a95748474 100644 --- a/packages/generic/backend/src/lib/connector/buildConnector.ts +++ b/packages/generic/backend/src/lib/connector/buildConnector.ts @@ -182,7 +182,7 @@ function buildConnector(connectorConfig: connectorConfigType) { } } - async function importNewDocuments() { + async function importNewDocuments(settings: settingsType) { logger.log({ operationName: 'importNewDocuments', msg: `Starting importNewDocuments...`, @@ -215,7 +215,39 @@ function buildConnector(connectorConfig: connectorConfigType) { 'recent', ); insertDocument(converted); - // Add labelTreatment import + + const lastNlpLabelTreatment = decision.labelTreatments + ?.filter((treatment) => treatment.source === 'NLP') + .sort((a, b) => b.order - a.order)[0]; + + if (!lastNlpLabelTreatment) { + throw new Error( + 'Could not import to label a document without NLP annotations', + ); + } + + const annotations: annotationType[] = lastNlpLabelTreatment.annotations.map( + (annotation) => { + return annotationModule.lib.buildAnnotation({ + category: annotation.category, + start: annotation.start, + text: annotation.text, + certaintyScore: annotation.certaintyScore, + entityId: annotation.entityId, + }); + }, + ); + + await treatmentService.createTreatment( + { + documentId: converted._id, + previousAnnotations: [], + nextAnnotations: annotations, + source: 'NLP', + }, + settings, + ); + await connectorConfig.updateDocumentLabelStatusToLoaded( converted.externalId, ); From 5992584dc6c049e0a65bd7c96e150b0c3a7f63e6 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Wed, 12 Feb 2025 17:16:35 +0100 Subject: [PATCH 08/13] remove storage --- INSTALL.md | 11 +- docs/reuserGuide.md | 14 +- docs/scripts.md | 12 - package.json | 1 - .../courDeCassation/src/scripts/clearDb.ts | 16 - .../src/scripts/clearDbExceptUsers.ts | 12 - .../src/scripts/clearDbOnlyProblemReports.ts | 20 - .../src/scripts/initializeTestDb.ts | 21 - .../storage-example/annotations/123452.json | 4 - .../storage-example/annotations/123456.json | 612 ------------------ .../storage-example/annotations/123457.json | 4 - .../storage-example/documents/123452.json | 14 - .../storage-example/documents/123456.json | 13 - .../storage-example/documents/123457.json | 13 - .../generic/backend/src/app/buildBackend.ts | 16 - .../generic/backend/src/app/scripts/index.ts | 4 - .../src/app/scripts/insertTestStatistics.ts | 42 -- .../src/app/scripts/insertTestUsers.ts | 24 - scripts/initializeTestDb.sh | 22 - 19 files changed, 12 insertions(+), 863 deletions(-) delete mode 100644 packages/courDeCassation/src/scripts/clearDb.ts delete mode 100644 packages/courDeCassation/src/scripts/clearDbExceptUsers.ts delete mode 100644 packages/courDeCassation/src/scripts/clearDbOnlyProblemReports.ts delete mode 100644 packages/courDeCassation/src/scripts/initializeTestDb.ts delete mode 100644 packages/courDeCassation/storage-example/annotations/123452.json delete mode 100644 packages/courDeCassation/storage-example/annotations/123456.json delete mode 100644 packages/courDeCassation/storage-example/annotations/123457.json delete mode 100644 packages/courDeCassation/storage-example/documents/123452.json delete mode 100644 packages/courDeCassation/storage-example/documents/123456.json delete mode 100644 packages/courDeCassation/storage-example/documents/123457.json delete mode 100644 packages/generic/backend/src/app/scripts/insertTestStatistics.ts delete mode 100644 packages/generic/backend/src/app/scripts/insertTestUsers.ts delete mode 100755 scripts/initializeTestDb.sh diff --git a/INSTALL.md b/INSTALL.md index 3271004fa..62c72f641 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -13,7 +13,7 @@ You can lauch the backend with or withour docker. To configure each of these met Copy and rename `docker.env.example` and `.env.example`. -Label depends on 2 other services from the Cour de cassation : dbsder-api and nlp-pseudonymisation-api. You can lauch these services locally to simulate operation close to production or you can disable theses services from env files. In this case these 2 services are emulated by Label with the storage folder. To do so, follow the `Add documents you want to annotate` step in the [reuser guide](docs/reuserGuide.md) or just rename the `storage-example` folder to `storage`. +Label depends on one other service from the Cour de cassation : [dbsder-api](https://github.com/cour-de-cassation/dbsder-api). This API is used to import and export decisions in label. ## Installation and lauch @@ -65,11 +65,12 @@ yarn start:backend:dev ### Database -You can init database with : +You can init/load/clean database with seeds scripts : -```sh -yarn init:db -``` +- clean the database : `node seeds/clean.js` +- load fake data in all collections : `node seeds/load.js` +- save your current database data on seeds : `node seeds/save.js` +- refresh date to a recent date : `node seeds/refreshDate.js ` This script is lauch with the `.env` configuration. diff --git a/docs/reuserGuide.md b/docs/reuserGuide.md index f049a8f6e..bde28781b 100644 --- a/docs/reuserGuide.md +++ b/docs/reuserGuide.md @@ -4,15 +4,13 @@ If you are reusing Label, these instructions will be usefull. Also have a look a ## Add documents you want to annotate -The `courDeCassation/storage-example` contains two folders: +We provide seeds to populate the database with test data. +To use seeds you can use the following commands from the project root : -- documents : the documents you want to annotate. Look at `courDeCassation/storage-example/documents/123452.json` for an example of the fields you are supposed to fill. The only required fields are: - - `dateDecision`: the date of the document - - `originalText`: the text of the document. Every paragraph has to be separated by \n - - `sourceId`: the unique ID of the document, which must also be its name ("{ID}.json") -- annotations: the initial annotations for a document. If you don't have an automatic annotator, copy/paste the `courDeCassation/storage-example/annotations/123452.json` content. - -The folder used by LABEL is `courDeCassation/storage`. If you want to reuse the `storage-example` folder as is, simply rename it to `storage`. +- clean the database : `node seeds/clean.js` +- load fake data in all collections : `node seeds/load.js` +- save your current database data on seeds : `node seeds/save.js` +- refresh date to a recent date : `node seeds/refreshDate.js ` ## Edit the annotation settings diff --git a/docs/scripts.md b/docs/scripts.md index 09638cfcb..d13bc2426 100644 --- a/docs/scripts.md +++ b/docs/scripts.md @@ -10,18 +10,6 @@ Import all documents to be pseudonymized from SDER. Cleaning script (clean duplicated documents and other). -## clearDb - -Clear Label database. - -## clearDbExceptUsers - -Delete all documents related data but keep users. - -## clearDbOnlyProblemReports - -Delete all problem reports. - ## deleteDocument Delete specific document from Label db. diff --git a/package.json b/package.json index 9550bf2b0..1618587dc 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "docker:start:db": "docker compose -f docker-compose-dev.yml up -d labelDb", "docker:stop:db": "docker compose -f docker-compose-dev.yml down labelDb", "fix": "lerna run fix", - "init:db": "scripts/initializeTestDb.sh", "lint": "lerna run lint", "start:backend": "lerna run --scope @label/cour-de-cassation start --stream", "start:backend:dev": "nodemon", diff --git a/packages/courDeCassation/src/scripts/clearDb.ts b/packages/courDeCassation/src/scripts/clearDb.ts deleted file mode 100644 index bb7ccfdc3..000000000 --- a/packages/courDeCassation/src/scripts/clearDb.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { parametersHandler } from '../lib/parametersHandler'; -import * as dotenv from 'dotenv'; - -(async () => { - if (process.env.RUN_MODE === 'LOCAL') { - dotenv.config(); - } - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - - await backend.runScript( - () => backend.scripts.clearDb.run({}), - backend.scripts.clearDb.option, - ); -})(); diff --git a/packages/courDeCassation/src/scripts/clearDbExceptUsers.ts b/packages/courDeCassation/src/scripts/clearDbExceptUsers.ts deleted file mode 100644 index 6c92a8ebd..000000000 --- a/packages/courDeCassation/src/scripts/clearDbExceptUsers.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { parametersHandler } from '../lib/parametersHandler'; - -(async () => { - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - - await backend.runScript( - () => backend.scripts.clearDb.run({ user: false }), - backend.scripts.clearDb.option, - ); -})(); diff --git a/packages/courDeCassation/src/scripts/clearDbOnlyProblemReports.ts b/packages/courDeCassation/src/scripts/clearDbOnlyProblemReports.ts deleted file mode 100644 index d6d585be5..000000000 --- a/packages/courDeCassation/src/scripts/clearDbOnlyProblemReports.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { parametersHandler } from '../lib/parametersHandler'; - -(async () => { - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - - await backend.runScript( - () => - backend.scripts.clearDb.run({ - annotation: false, - assignation: false, - document: false, - statistic: false, - treatment: false, - user: false, - }), - backend.scripts.clearDb.option, - ); -})(); diff --git a/packages/courDeCassation/src/scripts/initializeTestDb.ts b/packages/courDeCassation/src/scripts/initializeTestDb.ts deleted file mode 100644 index 339f0fa96..000000000 --- a/packages/courDeCassation/src/scripts/initializeTestDb.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { buildBackend } from '@label/backend'; -import { parametersHandler } from '../lib/parametersHandler'; -import * as dotenv from 'dotenv'; - -(async () => { - if (process.env.RUN_MODE === 'LOCAL') { - dotenv.config(); - } - const { settings } = await parametersHandler.getParameters(); - const backend = buildBackend(settings); - - await backend.runScript( - backend.scripts.insertTestUsers.run, - backend.scripts.insertTestUsers.option, - ); - - await backend.runScript( - backend.scripts.insertTestStatistics.run, - backend.scripts.insertTestStatistics.option, - ); -})(); diff --git a/packages/courDeCassation/storage-example/annotations/123452.json b/packages/courDeCassation/storage-example/annotations/123452.json deleted file mode 100644 index 47095c70e..000000000 --- a/packages/courDeCassation/storage-example/annotations/123452.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "entities": [], - "checklist": [] -} diff --git a/packages/courDeCassation/storage-example/annotations/123456.json b/packages/courDeCassation/storage-example/annotations/123456.json deleted file mode 100644 index f093f47aa..000000000 --- a/packages/courDeCassation/storage-example/annotations/123456.json +++ /dev/null @@ -1,612 +0,0 @@ -{ - "entities": [ - { - "category": "localite", - "start": 37, - "end": 46, - "text": "Dunkerque", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 812, - "end": 821, - "text": "Dunkerque", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 5680, - "end": 5689, - "text": "Dunkerque", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 88, - "end": 98, - "text": "Loon-Plage", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 128, - "end": 134, - "text": "Xavier", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 5312, - "end": 5318, - "text": "Xavier", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 135, - "end": 143, - "text": "Bertrand", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 5319, - "end": 5327, - "text": "Bertrand", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 263, - "end": 269, - "text": "Franck", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 270, - "end": 276, - "text": "Gonsse", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 552, - "end": 558, - "text": "Gonsse", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1090, - "end": 1096, - "text": "Gonsse", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 5282, - "end": 5288, - "text": "Gonsse", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 366, - "end": 373, - "text": "Nicolas", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 374, - "end": 381, - "text": "Sarkozy", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1407, - "end": 1415, - "text": "Philippe", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 2247, - "end": 2255, - "text": "Philippe", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 8135, - "end": 8143, - "text": "Philippe", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1416, - "end": 1422, - "text": "Poutou", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1494, - "end": 1501, - "text": "Olivier", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 5844, - "end": 5851, - "text": "Olivier", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1502, - "end": 1512, - "text": "Besancenot", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1597, - "end": 1604, - "text": "Arlette", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1605, - "end": 1614, - "text": "Laguiller", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1831, - "end": 1841, - "text": "Christophe", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1842, - "end": 1851, - "text": "Prudhomme", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 1864, - "end": 1881, - "text": "Seine-Saint-Denis", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 2317, - "end": 2334, - "text": "Seine-Saint-Denis", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1883, - "end": 1889, - "text": "Pascal", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1890, - "end": 1899, - "text": "Le Manach", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1923, - "end": 1927, - "text": "Eric", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1928, - "end": 1936, - "text": "Pecqueur", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1981, - "end": 1990, - "text": "Sébastien", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 1991, - "end": 1998, - "text": "Pointet", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 2059, - "end": 2065, - "text": "Cécile", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 2066, - "end": 2073, - "text": "Cukierman", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 2256, - "end": 2264, - "text": "Martinez", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 8739, - "end": 8747, - "text": "Martinez", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 2853, - "end": 2858, - "text": "Cyril", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 2859, - "end": 2868, - "text": "Chabanier", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 3359, - "end": 3363, - "text": "Yvan", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 3364, - "end": 3373, - "text": "Ricordeau", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personneMorale", - "start": 288, - "end": 292, - "text": "CFDT", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personneMorale", - "start": 3401, - "end": 3405, - "text": "CFDT", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personneMorale", - "start": 5383, - "end": 5387, - "text": "CFDT", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 3817, - "end": 3825, - "text": "Isabelle", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 3826, - "end": 3833, - "text": "Chauvin", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 4618, - "end": 4626, - "text": "François", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 4627, - "end": 4635, - "text": "Hommeril", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 5254, - "end": 5262, - "text": "Hommeril", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 5977, - "end": 5986, - "text": "Jean-Yves", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 5987, - "end": 5995, - "text": "Le Drian", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personneMorale", - "start": 6055, - "end": 6058, - "text": "Gad", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 6367, - "end": 6371, - "text": "Yves", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 6372, - "end": 6379, - "text": "Veyrier", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 7011, - "end": 7019, - "text": "Stéphane", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 7020, - "end": 7028, - "text": "Blanchon", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 7613, - "end": 7621, - "text": "Blanchon", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 7883, - "end": 7891, - "text": "Blanchon", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 9030, - "end": 9038, - "text": "Blanchon", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 7350, - "end": 7357, - "text": "Doumont", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 7631, - "end": 7638, - "text": "Doumont", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "localite", - "start": 8880, - "end": 8888, - "text": "Nilvange", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "professionnelMagistratGreffier", - "start": 6796, - "end": 6799, - "text": "Yon", - "source": "Cour de cassation example", - "score": 1 - }, - { - "category": "personnePhysique", - "start": 9358, - "end": 9361, - "text": "Yon", - "source": "Cour de cassation example", - "score": 1 - } - ], - "checklist": [ - { - "check_type": "different_categories", - "message": "L'annotation 'Yon' est présente dans différentes catégories: ['Magistrat/Greffier', 'Personne physique']", - "short_message": "Yon [professionnelMagistratGreffier] [personnePhysique] ?", - "entities": [ - { - "text": "Yon", - "start": 9358, - "category": "personnePhysique", - "source": "postprocess", - "score": 1.0, - "entityId": "personnePhysique_yon", - "end": 9361 - }, - { - "text": "Yon", - "start": 6796, - "category": "professionnelMagistratGreffier", - "source": "postprocess", - "score": 1.0, - "entityId": "professionnelMagistratGreffier_yon", - "end": 6799 - } - ], - "sentences": [ - { - "start": 0, - "end": 22 - } - ], - "metadata_text": [] - }, - { - "check_type": "different_categories", - "message": "L'annotation 'Xavier' est présente dans différentes catégories: ['Personne physique', 'Localité']", - "short_message": "Xavier [personnePhysique] [localite] ?", - "entities": [ - { - "category": "personnePhysique", - "start": 5312, - "end": 5318, - "text": "Xavier", - "source": "Cour de cassation example", - "score": 1, - "entityId": "personnePhysique_xavier" - }, - { - "category": "localite", - "start": 135, - "end": 143, - "text": "Bertrand", - "source": "Cour de cassation example", - "score": 1, - "entityId": "localite_xavier" - } - ], - "sentences": [ - { - "start": 0, - "end": 22 - } - ], - "metadata_text": [] - }, - { - "check_type": "juridoute", - "message": "L'annotation 'Colonel-Fabien' est-elle une personne physique ?", - "short_message": "Colonel-Fabien [personnePhysique] ?", - "entities": [ - { - "category": "personnePhysique", - "entityId": "personnePhysique_colonel-fabien", - "start": 2732, - "end": 2746, - "text": "Colonel-Fabien", - "certaintyScore": 1 - } - ], - "sentences": [ - { - "start": 2700, - "end": 2747 - } - ], - "metadata_text": [] - } - ] -} diff --git a/packages/courDeCassation/storage-example/annotations/123457.json b/packages/courDeCassation/storage-example/annotations/123457.json deleted file mode 100644 index 47095c70e..000000000 --- a/packages/courDeCassation/storage-example/annotations/123457.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "entities": [], - "checklist": [] -} diff --git a/packages/courDeCassation/storage-example/documents/123452.json b/packages/courDeCassation/storage-example/documents/123452.json deleted file mode 100644 index da001baf5..000000000 --- a/packages/courDeCassation/storage-example/documents/123452.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "chamberName": "", - "dateDecision": "07/05/2021", - "jurisdictionName": "Mer", - "originalText": "L’annonce a été faite sur le port de Dunkerque, au milieu des containers du terminal de Loon-Plage. Sur la photo, lundi 10 mai, Xavier Bertrand (ex-Les Républicains), en campagne pour sa réélection à la tête de la région des Hauts-de-France, et son nouvel allié, Franck Gonsse, le patron CFDT des dockers locaux. Une belle prise pour l’ancien ministre du travail de Nicolas Sarkozy : obtenir le renfort de personnalités provenant de la société civile offre la possibilité d’élargir sa base politique et de capter un potentiel gisement de voix.\nChez M. Gonsse, les motivations sont différentes : cumuler des casquettes de syndicaliste et d’élu territorial relève du « pragmatisme », explique-t-il. D’ailleurs, il est déjà conseiller délégué chargé des affaires maritimes et portuaires au conseil communautaire de Dunkerque. Une fonction qu’il a décrochée lors des municipales de 2020, en faisant acte de candidature parmi une coalition divers gauche. « Ça me permet d’avancer plus vite, affirme-t-il. Je n’ai plus besoin d’aller pleurer à la porte du politique, c’est du direct.Le cas de M. Gonsse est loin d’être isolé, mais il est difficile d’évaluer le nombre de syndicalistes qui briguent un mandat à l’occasion des élections des 20 et 27 juin. Si le phénomène n’est sans doute pas massif, il est récurrent : à chaque scrutin, des profils de ce type fleurissent. Même la présidentielle n’y échappe pas : Philippe Poutou, en lice pour le NPA en 2012 et 2017, était issu des rangs de la CGT ; Olivier Besancenot, le représentant de la LCR en 2002 et 2007, était encarté à SUD-PTT ; membre de FO, Arlette Laguiller a porté la bannière de Lutte ouvrière (LO) à six reprises…\nUne aura et un réseau\n\n»Pour les régionales de juin, la CGT fournit, à nouveau, plusieurs têtes de liste à des formations situées à la gauche de la gauche : Christophe Prudhomme pour LFI en Seine-Saint-Denis, Pascal Le Manach pour LO en Normandie ; Eric Pecqueur également pour LO dans les Hauts-de-France. Sébastien Pointet, de son côté, a rejoint l’attelage emmené par la communiste Cécile Cukierman en Auvergne-Rhône-Alpes pour en être le chef de file en Savoie. « Ces dernières années, on a même eu des militants qui ont concouru sous l’étiquette EELV ou PS », s’amuse Philippe Martinez, le secrétaire général de la centrale de Montreuil (Seine-Saint-Denis) : d’après lui, ceux qui, au sein de ses troupes, partent à l’assaut des urnes affichent des engagements politiques d’« une plus grande diversité » qu’il y a « trente ans ». Une allusion au fait que la CGT a, pendant des décennies, été perçue comme la « courroie de transmission » du PCF. A tel point que l’appareil de la confédération fut longtemps dominé par des figures du parti de la place du Colonel-Fabien.\nLe fait que des syndicalistes soient enrôlés par des formations politiques n’a rien d’étonnant, décrypte Cyril Chabanier, le président de la CFTC : « Ils ont des compétences recherchées et certains jouissent d’une aura certaine dans leur territoire, tout en s’appuyant sur un réseau qui peut être dense », souligne-t-il. Sans compter qu’il devient « de plus en plus compliqué de trouver des gens pour constituer des listes », complète-t-il. « Que certains militants syndicaux fassent le choix de se présenter à une élection, c’est logique, sinon le corps politique serait assez restreint », note, pour sa part, Yvan Ricordeau, secrétaire national de la CFDT.\nEnfin, l’activité d’élu est vue comme « le prolongement de l’engagement syndical », selon la formule de Patricia Téjas, une des responsables du comité régional de la CGT en Provence-Alpes-Côte d’Azur en lice pour les départementales sous les couleurs du PCF dans le Vaucluse. « Il s’agit d’entrer dans les institutions pour faire bouger les lignes sur le terrain et améliorer le sort des citoyens », renchérit Isabelle Chauvin, candidate LFI aux départementales dans les Bouches-du-Rhône et élue CGT du personnel dans un groupe d’enseignement privé.\nChaque confédération a ses règles\n\nMais de telles démarches soulèvent parfois des débats en interne car elles peuvent être vues comme une atteinte au principe d’indépendance du syndicalisme vis-à-vis des partis. Un principe inscrit dans la Charte d’Amiens, adoptée en 1906 par la CGT. Bien qu’il ait été transgressé maintes fois – à commencer par la CGT elle-même – , il demeure une boussole pour toutes les centrales de salariés, conduisant celles-ci à édicter des règles. « La contrainte que l’on impose à nos militants qui participent à une élection est de ne pas faire état de leur appartenance à notre organisation ni de leurs mandats syndicaux », indique François Hommeril, le président de la CFE-CGC. Dans certaines confédérations, il peut être demandé à ceux qui ont des responsabilités de les mettre entre parenthèses, le temps de la campagne, et de démissionner s’il y a un conflit d’intérêts en cas d’élection. A la CGT et à FO, les membres du bureau confédéral n’ont pas le droit de se présenter. L’UNSA, elle, semble être un peu plus permissive pour ses hauts dirigeants : une secrétaire nationale, Emilie Trigo, figure sur la liste socialiste d’Audrey Pulvar en Ile-de-France.\nCeux qui sortent des clous « peuvent faire l’objet de sanctions allant jusqu’à l’exclusion », enchaîne M. Hommeril. Dans le cas de M. Gonsse, le cédétiste rallié à Xavier Bertrand dans les Hauts-de-France, la direction nationale de la CFDT tient à ce que les choses soient claires : « S’il devient conseiller régional, il restituera son mandat syndical. Cela a été discuté avec lui en amont. » Mais l’intéressé ne l’entend pas de cette oreille : « en aucun cas » il ne renoncera à son rôle auprès des salariés des ports et docks de Dunkerque.\nA l’inverse, certains syndicalistes qui tentent l’aventure politique abandonnent d’eux-mêmes leurs fonctions et rendent même leur carte. Une décision qu’Olivier Le Bras a prise en 2015, quand il s’est lancé, avec succès, dans la course aux régionales en Bretagne, au côté du socialiste Jean-Yves Le Drian. Cet ancien représentant du personnel FO dans l’entreprise Gad confie qu’il ne voulait « pas exposer » sa confédération. En outre, poursuit-il, « c’est compliqué » d’être à la fois élu territorial et défenseur des intérêts des salariés.\n« Chacun a le droit à ses engagements politique, philosophique, religieux, sous réserve qu’ils ne les introduisent pas à FO », résume Yves Veyrier, le numéro un de la confédération. Une gageure quand on connaît le poids des courants politiques, notamment les trotskistes et les anarchistes, dans les diverses composantes de sa centrale.\n« Dans les années 1980, ça allait encore de soi de dire que les syndicats et la gauche, c’est la même chose, mais, au fil du temps, un fossé symbolique s’est creusé entre les champs syndical et partisan », contrebalance Karel Yon, sociologue et chargé de recherche au CNRS. Dans le même temps, les idées d’extrême droite se sont peu à peu propagées parmi les salariés et chez ceux qui les représentent.\n« Chasse aux sorcières »\n\nIl y a peu, Stéphane Blanchon était à la tête de la fédération UNSA santé et action sociale. Désormais tête de liste Rassemblement national (RN) dans la Drôme pour les régionales en Auvergne-Rhône-Alpes, il explique avoir sauté le pas, car il souhaitait passer « à une autre sorte d’action ». Sa candidature ainsi que celle d’un de ses collègues, Luc Doumont, aux départementales, ont provoqué l’ire du secrétaire général de l’UNSA : « On ne transige pas avec les valeurs, s’exclame Laurent Escure. Le RN est le seul parti qui a un problème avec un syndicalisme libre et démocratique. »\nPour lui, l’attitude de M. Blanchon et de M. Doumont est le résultat d’« un mélange de démarche individuelle camouflée et d’opportunisme ». « Aujourd’hui, le RN, c’est bankable pour se faire élire, dénonce-t-il. Ce que l’on ne mesure pas, c’est la profondeur de l’offensive. » Une réaction que M. Blanchon ne comprend pas : il critique une direction devenue « parano » et s’estime victime d’« une chasse aux sorcières ». Car la bascule vers le RN équivaut, bien souvent, à une exclusion. Sauf si les transfuges lâchent leurs fonctions, à l’image de Philippe Théveniaud : cet ancien président de la CFTC dans la Somme a abandonné tous ses mandats peu avant de révéler sa candidature aux régionales dans les Hauts-de-France sous l’étiquette RN.\nQuant à ceux qui ne veulent pas partir, les centrales s’appuient sur leur charte des valeurs pour les bannir. Mais les numéros un syndicaux ont rarement la main – la procédure relevant la plupart du temps des fédérations professionnelles ou des structures locales. « Ce n’est pas moi qui commande, je ne peux que donner mon avis, mais généralement, dans ces cas-là, ça se règle assez facilement », certifie M. Martinez.\nEn 2011, la fédération CGT des services publics avait cependant dû désaffilier le syndicat des agents territoriaux de la mairie de Nilvange (Moselle), qui soutenait son responsable, Fabien Engelmann, alors candidat aux cantonales sous l’étiquette Front national. Dans le cas de M. Blanchon, sa fédération lui a retiré son mandat, mais, « techniquement », il n’est toujours pas évincé de son syndicat, prétend-il : « Je ne vois pas ce que j’ai fait de si monstrueux. La charte des valeurs de l’UNSA, je n’en renie pas une ligne. »\nPour l’extrême droite, ces candidatures constituent une bonne opération. Si M. Yon rappelle l’« ambivalence » du parti de Marine Le Pen vis-à-vis des syndicats, il relève aussi que « le RN a tout intérêt à valoriser le fait qu’un syndicaliste de telle ou telle organisation les rejoint. Cela s’inscrit dans leur stratégie de dédiabolisation, qui veut que le RN soit le premier parti ouvrier – quand on ne compte pas les abstentionnistes ».", - "registerNumber": 123452, - "sourceId": 123452, - "sourceName": "jurinet", - "appeals": [], - "occultation": { - "motivationOccultation": null, - "additionalTerms": "Occulter le terme Dunkerque" - } -} diff --git a/packages/courDeCassation/storage-example/documents/123456.json b/packages/courDeCassation/storage-example/documents/123456.json deleted file mode 100644 index 0c0b7672a..000000000 --- a/packages/courDeCassation/storage-example/documents/123456.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "chamberName": "", - "dateDecision": "07/05/2021", - "jurisdictionName": "Politique", - "originalText": "L’annonce a été faite sur le port de Dunkerque, au milieu des containers du terminal de Loon-Plage. Sur la photo, lundi 10 mai, Xavier Bertrand (ex-Les Républicains), en campagne pour sa réélection à la tête de la région des Hauts-de-France, et son nouvel allié, Franck Gonsse, le patron CFDT des dockers locaux. Une belle prise pour l’ancien ministre du travail de Nicolas Sarkozy : obtenir le renfort de personnalités provenant de la société civile offre la possibilité d’élargir sa base politique et de capter un potentiel gisement de voix.\nChez M. Gonsse, les motivations sont différentes : cumuler des casquettes de syndicaliste et d’élu territorial relève du « pragmatisme », explique-t-il. D’ailleurs, il est déjà conseiller délégué chargé des affaires maritimes et portuaires au conseil communautaire de Dunkerque. Une fonction qu’il a décrochée lors des municipales de 2020, en faisant acte de candidature parmi une coalition divers gauche. « Ça me permet d’avancer plus vite, affirme-t-il. Je n’ai plus besoin d’aller pleurer à la porte du politique, c’est du direct.Le cas de M. Gonsse est loin d’être isolé, mais il est difficile d’évaluer le nombre de syndicalistes qui briguent un mandat à l’occasion des élections des 20 et 27 juin. Si le phénomène n’est sans doute pas massif, il est récurrent : à chaque scrutin, des profils de ce type fleurissent. Même la présidentielle n’y échappe pas : Philippe Poutou, en lice pour le NPA en 2012 et 2017, était issu des rangs de la CGT ; Olivier Besancenot, le représentant de la LCR en 2002 et 2007, était encarté à SUD-PTT ; membre de FO, Arlette Laguiller a porté la bannière de Lutte ouvrière (LO) à six reprises…\nUne aura et un réseau\n\n»Pour les régionales de juin, la CGT fournit, à nouveau, plusieurs têtes de liste à des formations situées à la gauche de la gauche : Christophe Prudhomme pour LFI en Seine-Saint-Denis, Pascal Le Manach pour LO en Normandie ; Eric Pecqueur également pour LO dans les Hauts-de-France. Sébastien Pointet, de son côté, a rejoint l’attelage emmené par la communiste Cécile Cukierman en Auvergne-Rhône-Alpes pour en être le chef de file en Savoie. « Ces dernières années, on a même eu des militants qui ont concouru sous l’étiquette EELV ou PS », s’amuse Philippe Martinez, le secrétaire général de la centrale de Montreuil (Seine-Saint-Denis) : d’après lui, ceux qui, au sein de ses troupes, partent à l’assaut des urnes affichent des engagements politiques d’« une plus grande diversité » qu’il y a « trente ans ». Une allusion au fait que la CGT a, pendant des décennies, été perçue comme la « courroie de transmission » du PCF. A tel point que l’appareil de la confédération fut longtemps dominé par des figures du parti de la place du Colonel-Fabien.\nLe fait que des syndicalistes soient enrôlés par des formations politiques n’a rien d’étonnant, décrypte Cyril Chabanier, le président de la CFTC : « Ils ont des compétences recherchées et certains jouissent d’une aura certaine dans leur territoire, tout en s’appuyant sur un réseau qui peut être dense », souligne-t-il. Sans compter qu’il devient « de plus en plus compliqué de trouver des gens pour constituer des listes », complète-t-il. « Que certains militants syndicaux fassent le choix de se présenter à une élection, c’est logique, sinon le corps politique serait assez restreint », note, pour sa part, Yvan Ricordeau, secrétaire national de la CFDT.\nEnfin, l’activité d’élu est vue comme « le prolongement de l’engagement syndical », selon la formule de Patricia Téjas, une des responsables du comité régional de la CGT en Provence-Alpes-Côte d’Azur en lice pour les départementales sous les couleurs du PCF dans le Vaucluse. « Il s’agit d’entrer dans les institutions pour faire bouger les lignes sur le terrain et améliorer le sort des citoyens », renchérit Isabelle Chauvin, candidate LFI aux départementales dans les Bouches-du-Rhône et élue CGT du personnel dans un groupe d’enseignement privé.\nChaque confédération a ses règles\n\nMais de telles démarches soulèvent parfois des débats en interne car elles peuvent être vues comme une atteinte au principe d’indépendance du syndicalisme vis-à-vis des partis. Un principe inscrit dans la Charte d’Amiens, adoptée en 1906 par la CGT. Bien qu’il ait été transgressé maintes fois – à commencer par la CGT elle-même – , il demeure une boussole pour toutes les centrales de salariés, conduisant celles-ci à édicter des règles. « La contrainte que l’on impose à nos militants qui participent à une élection est de ne pas faire état de leur appartenance à notre organisation ni de leurs mandats syndicaux », indique François Hommeril, le président de la CFE-CGC. Dans certaines confédérations, il peut être demandé à ceux qui ont des responsabilités de les mettre entre parenthèses, le temps de la campagne, et de démissionner s’il y a un conflit d’intérêts en cas d’élection. A la CGT et à FO, les membres du bureau confédéral n’ont pas le droit de se présenter. L’UNSA, elle, semble être un peu plus permissive pour ses hauts dirigeants : une secrétaire nationale, Emilie Trigo, figure sur la liste socialiste d’Audrey Pulvar en Ile-de-France.\nCeux qui sortent des clous « peuvent faire l’objet de sanctions allant jusqu’à l’exclusion », enchaîne M. Hommeril. Dans le cas de M. Gonsse, le cédétiste rallié à Xavier Bertrand dans les Hauts-de-France, la direction nationale de la CFDT tient à ce que les choses soient claires : « S’il devient conseiller régional, il restituera son mandat syndical. Cela a été discuté avec lui en amont. » Mais l’intéressé ne l’entend pas de cette oreille : « en aucun cas » il ne renoncera à son rôle auprès des salariés des ports et docks de Dunkerque.\nA l’inverse, certains syndicalistes qui tentent l’aventure politique abandonnent d’eux-mêmes leurs fonctions et rendent même leur carte. Une décision qu’Olivier Le Bras a prise en 2015, quand il s’est lancé, avec succès, dans la course aux régionales en Bretagne, au côté du socialiste Jean-Yves Le Drian. Cet ancien représentant du personnel FO dans l’entreprise Gad confie qu’il ne voulait « pas exposer » sa confédération. En outre, poursuit-il, « c’est compliqué » d’être à la fois élu territorial et défenseur des intérêts des salariés.\n« Chacun a le droit à ses engagements politique, philosophique, religieux, sous réserve qu’ils ne les introduisent pas à FO », résume Yves Veyrier, le numéro un de la confédération. Une gageure quand on connaît le poids des courants politiques, notamment les trotskistes et les anarchistes, dans les diverses composantes de sa centrale.\n« Dans les années 1980, ça allait encore de soi de dire que les syndicats et la gauche, c’est la même chose, mais, au fil du temps, un fossé symbolique s’est creusé entre les champs syndical et partisan », contrebalance Karel Yon, sociologue et chargé de recherche au CNRS. Dans le même temps, les idées d’extrême droite se sont peu à peu propagées parmi les salariés et chez ceux qui les représentent.\n« Chasse aux sorcières »\n\nIl y a peu, Stéphane Blanchon était à la tête de la fédération UNSA santé et action sociale. Désormais tête de liste Rassemblement national (RN) dans la Drôme pour les régionales en Auvergne-Rhône-Alpes, il explique avoir sauté le pas, car il souhaitait passer « à une autre sorte d’action ». Sa candidature ainsi que celle d’un de ses collègues, Luc Doumont, aux départementales, ont provoqué l’ire du secrétaire général de l’UNSA : « On ne transige pas avec les valeurs, s’exclame Laurent Escure. Le RN est le seul parti qui a un problème avec un syndicalisme libre et démocratique. »\nPour lui, l’attitude de M. Blanchon et de M. Doumont est le résultat d’« un mélange de démarche individuelle camouflée et d’opportunisme ». « Aujourd’hui, le RN, c’est bankable pour se faire élire, dénonce-t-il. Ce que l’on ne mesure pas, c’est la profondeur de l’offensive. » Une réaction que M. Blanchon ne comprend pas : il critique une direction devenue « parano » et s’estime victime d’« une chasse aux sorcières ». Car la bascule vers le RN équivaut, bien souvent, à une exclusion. Sauf si les transfuges lâchent leurs fonctions, à l’image de Philippe Théveniaud : cet ancien président de la CFTC dans la Somme a abandonné tous ses mandats peu avant de révéler sa candidature aux régionales dans les Hauts-de-France sous l’étiquette RN.\nQuant à ceux qui ne veulent pas partir, les centrales s’appuient sur leur charte des valeurs pour les bannir. Mais les numéros un syndicaux ont rarement la main – la procédure relevant la plupart du temps des fédérations professionnelles ou des structures locales. « Ce n’est pas moi qui commande, je ne peux que donner mon avis, mais généralement, dans ces cas-là, ça se règle assez facilement », certifie M. Martinez.\nEn 2011, la fédération CGT des services publics avait cependant dû désaffilier le syndicat des agents territoriaux de la mairie de Nilvange (Moselle), qui soutenait son responsable, Fabien Engelmann, alors candidat aux cantonales sous l’étiquette Front national. Dans le cas de M. Blanchon, sa fédération lui a retiré son mandat, mais, « techniquement », il n’est toujours pas évincé de son syndicat, prétend-il : « Je ne vois pas ce que j’ai fait de si monstrueux. La charte des valeurs de l’UNSA, je n’en renie pas une ligne. »\nPour l’extrême droite, ces candidatures constituent une bonne opération. Si M. Yon rappelle l’« ambivalence » du parti de Marine Le Pen vis-à-vis des syndicats, il relève aussi que « le RN a tout intérêt à valoriser le fait qu’un syndicaliste de telle ou telle organisation les rejoint. Cela s’inscrit dans leur stratégie de dédiabolisation, qui veut que le RN soit le premier parti ouvrier – quand on ne compte pas les abstentionnistes ».", - "registerNumber": 123456, - "sourceId": 123456, - "sourceName": "juritj", - "appeals": [], - "occultation": { - "motivationOccultation": null - } -} diff --git a/packages/courDeCassation/storage-example/documents/123457.json b/packages/courDeCassation/storage-example/documents/123457.json deleted file mode 100644 index 5ff9cf284..000000000 --- a/packages/courDeCassation/storage-example/documents/123457.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "chamberName": "Gryffondor", - "dateDecision": "10/06/2021", - "jurisdictionName": "The Daily Prophet", - "originalText": "Harry Potter à l'école des sorciers (Harry Potter and the Philosopher's Stone) est le premier roman de la série littéraire centrée sur le personnage de Harry Potter, créé par J. K. Rowling. Sorti le 26 juin 1997, il est initialement tiré à 500 exemplaires. En France, le roman a été publié le 9 octobre 1998.\nIl trouve son importance puisqu'il sert de base introductive aux six autres tomes de la série ainsi qu'à la pièce de théâtre Harry Potter et l'Enfant maudit. Il permet à l'auteur de mettre en place l'univers, de familiariser le lecteur avec ses personnages, les lieux, les objets magiques, les mœurs et tout le vocabulaire propre à son monde. Ce premier tome installe progressivement les nœuds de l'intrigue grâce à des indices dissimulés pour ne pas éveiller les soupçons du lecteur dès le début de l'histoire.\nLe livre, qui est le premier roman de Rowling à être publié, est écrit entre approximativement juin 1990 et 1995. En 1990, l'auteur prend un train de Manchester à Londres après une recherche d'appartements, et l'idée de Harry Potter lui vient soudainement. Elle imagine alors un garçon de petite taille, aux cheveux noirs et aux lunettes, apprenant qu'il est un sorcier et bien plus encore. Elle commence a écrire L'école des sorciers le soir même et rédigera l'intégralité du manuscrit sur une machine à écrire. La mère de Rowling meurt à l'âge de quarante-cinq ans, alors que l'auteur rédige le livre depuis environ six mois. Pour faire face à cette douleur, Rowling transfère sa propre angoisse à son héros, bien qu'il était prévu dès le début de l'écriture que Harry serait un orphelin. Rowling séjourne au Portugal pour prendre de la distance et y rédige son chapitre préféré de ce premier roman : « Le Miroir du Riséd ». Elle passe environ sept ans à mettre en place son univers sorcier, en commençant par établir les lois et les « limites » de la magie.\nAprès que son livre a été accepté par Bloomsbury, elle obtient une subvention de 4 000 livres du Scottish Arts Council, ce qui lui permet de planifier les suites. Bloomsbury passe une année à essayer de vendre le livre à un éditeur, dont la plupart estime que le livre était trop long pour des enfants.\n\nRésumé de l'intrigue\nAprès la mort de ses parents (Lily et James Potter), Harry Potter est recueilli par sa tante maternelle Pétunia et son oncle Vernon à l'âge d'un an. Ces derniers, animés depuis toujours d'une haine féroce envers les parents du garçon qu'ils qualifient de gens « bizarres », voire de « monstres , traitent froidement leur neveu et demeurent indifférents aux humiliations que leur fils Dudley lui fait subir. Harry ignore tout de l'histoire de ses parents, si ce n'est qu'ils ont été, semble-t-il, tués dans un accident de voiture. Cependant, le jour des onze ans de Harry, un demi-géant du nom de Rubeus Hagrid vient le chercher pour l'informer de son inscription à Poudlard, une école de sorcellerie où il est inscrit depuis sa naissance, et lui remettre sa lettre. Il lui révèle qu’il a toujours été un sorcier, tout comme l'étaient ses parents, tués en réalité par le plus puissant mage noir du monde de la sorcellerie : Voldemort (surnommé « Celui-Dont-On-Ne-Doit-Pas-Prononcer-Le-Nom », « Vous savez qui » ou « Tu sais qui »). Ce serait Harry lui-même, alors qu'il n'était encore qu'un bébé, qui aurait fait ricocher le sortilège que Voldemort lui destinait, neutralisant ses pouvoirs et le réduisant à l'état de créature insignifiante. Le fait d'avoir vécu son enfance chez son oncle et sa tante dépourvus de pouvoirs magiques lui aurait permis de grandir à l'abri de l'admiration qu'il suscite dans le monde des sorciers. Hagrid l'accompagne ensuite sur le chemin de Traverse pour acheter sa baguette magique et ses fournitures scolaires. Le demi-géant en profite pour récupérer sur ordre de Dumbledore un mystérieux paquet à Gringotts, la banque des sorciers.\nHarry fait la connaissance de Ron Weasley et Hermione Granger dans le Poudlard Express, le train les conduisant à l'école, et découvre rapidement l'hostilité que semblent lui vouer le jeune Drago Malefoy et le professeur de potions Severus Rogue. À leur arrivée à Poudlard, les élèves sont répartis dans différentes maisons après avoir enfilé le « choixpeau » qui analyse leur personnalité : Harry, Ron et Hermione sont tous les trois répartis dans la maison Gryffondor.\nUn peu plus tard dans l'année, les trois amis découvrent par hasard qu'un immense chien à trois têtes est hébergé au sein même du château et semble garder quelque chose sous une trappe, sans doute l'objet mystérieux que Hagrid a récupéré à la banque des sorciers juste avant la rentrée. Harry est persuadé que le professeur Rogue tente de faire diversion pour essayer de passer devant le chien à trois têtes et récupérer l'objet en question, qui semble concerner Dumbledore et l'un de ses amis, un certain Nicolas Flamel\nLe jour de Noël, Harry découvre parmi ses cadeaux une cape d'invisibilité ayant appartenu à son père James Potter. Il décide de s'en servir, et pour éviter Rogue et Rusard qui se trouvent sur son chemin dans les couloirs, se cache dans une salle de classe désaffectée où il découvre un miroir étrange, le miroir du Riséd, ayant le pouvoir de montrer le désir le plus cher de la personne qui observe son reflet26. Harry observe ainsi avec fascination ses parents disparus avec lesquels il peut interagir.\nHarry, Ron et Hermione comprennent que l'objet si précieux caché sous la trappe est une pierre philosophale créée par Nicolas Flamel, et qui aurait le pouvoir d'offrir l'immortalité. Ils sont persuadés que Voldemort, par le biais du professeur Rogue, cherche à s'en emparer. Pour récupérer la pierre en premier, Harry, Ron et Hermione passent sous la trappe gardée par le chien et franchissent une série d'obstacles conçus par les plus talentueux professeurs de Poudlard. Dans la pièce de la dernière énigme, ce n'est pas le professeur Rogue que retrouve Harry mais le professeur Quirrell, professeur de défense contre les forces du Mal, qui se tient devant le miroir du Riséd, placé là par Dumbledore.\nHarry est terrifié lorsque Quirrell déroule le turban violet qu'il porte sur la tête : le couvre-chef dissimule en réalité le visage de Voldemort, formé à l'arrière du crâne de Quirrell ; le mage noir avait « emprunté » le corps du professeur pour se rapprocher de la pierre cachée et pour lui transmettre plus aisément ses ordres. Harry parvient à récupérer la pierre grâce au miroir. Voldemort ordonne alors à Quirrell de tuer Harry mais Dumbledore s'interpose in extremis.", - "registerNumber": 123457, - "sourceId": 123457, - "sourceName": "jurinet", - "appeals": [], - "occultation": { - "motivationOccultation": null - } -} diff --git a/packages/generic/backend/src/app/buildBackend.ts b/packages/generic/backend/src/app/buildBackend.ts index 773550d94..e1afc7382 100644 --- a/packages/generic/backend/src/app/buildBackend.ts +++ b/packages/generic/backend/src/app/buildBackend.ts @@ -3,14 +3,11 @@ import { buildRunScript } from './buildRunScript'; import { buildRunServer } from './buildRunServer'; import { cleanDocuments, - clearDb, deleteDocument, displayDocumentLinks, displayMultipleAssignatedDocuments, dumpDocument, freePendingDocuments, - insertTestStatistics, - insertTestUsers, insertUser, listAllDocuments, listAllCaches, @@ -35,10 +32,6 @@ function buildBackend(settings: settingsType) { run: cleanDocuments, option: { shouldLoadDb: true, shouldExit: false }, }, - clearDb: { - run: clearDb, - option: { shouldLoadDb: true, shouldExit: false }, - }, deleteDocument: { run: deleteDocument, option: { shouldLoadDb: true, shouldExit: false }, @@ -59,15 +52,6 @@ function buildBackend(settings: settingsType) { run: freePendingDocuments, option: { shouldLoadDb: true, shouldExit: false }, }, - insertTestStatistics: { - run: insertTestStatistics, - option: { shouldLoadDb: true, shouldExit: false }, - }, - - insertTestUsers: { - run: insertTestUsers, - option: { shouldLoadDb: true, shouldExit: false }, - }, insertUser: { run: insertUser, option: { shouldLoadDb: true, shouldExit: false }, diff --git a/packages/generic/backend/src/app/scripts/index.ts b/packages/generic/backend/src/app/scripts/index.ts index 493328ae0..6189f3997 100644 --- a/packages/generic/backend/src/app/scripts/index.ts +++ b/packages/generic/backend/src/app/scripts/index.ts @@ -5,8 +5,6 @@ import { displayDocumentLinks } from './displayDocumentLinks'; import { displayMultipleAssignatedDocuments } from './displayMultipleAssignatedDocuments'; import { dumpDocument } from './dumpDocument'; import { freePendingDocuments } from './freePendingDocuments'; -import { insertTestStatistics } from './insertTestStatistics'; -import { insertTestUsers } from './insertTestUsers'; import { insertUser } from './insertUser'; import { listAllCaches } from './listAllCaches'; import { listAllDocuments } from './listAllDocuments'; @@ -24,8 +22,6 @@ export { displayMultipleAssignatedDocuments, dumpDocument, freePendingDocuments, - insertTestStatistics, - insertTestUsers, insertUser, listAllCaches, listAllDocuments, diff --git a/packages/generic/backend/src/app/scripts/insertTestStatistics.ts b/packages/generic/backend/src/app/scripts/insertTestStatistics.ts deleted file mode 100644 index 721193c41..000000000 --- a/packages/generic/backend/src/app/scripts/insertTestStatistics.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { dateBuilder, statisticModule } from '@label/core'; -import { buildStatisticRepository } from '../../modules/statistic'; -import { userService } from '../../modules/user'; - -export { insertTestStatistics }; - -async function insertTestStatistics() { - const statisticRepository = buildStatisticRepository(); - - const users = await userService.fetchWorkingUsers(); - - for (const user of users) { - for (let i = 0; i < 100; i++) { - await statisticRepository.insert( - statisticModule.generator.generate({ - treatmentsSummary: [{ userId: user._id, treatmentDuration: 10 }], - route: 'simple', - importer: 'recent', - treatmentDate: dateBuilder.daysAgo(i), - }), - ); - - await statisticRepository.insert( - statisticModule.generator.generate({ - treatmentsSummary: [{ userId: user._id, treatmentDuration: 20 }], - route: 'exhaustive', - importer: 'recent', - treatmentDate: dateBuilder.daysAgo(i), - }), - ); - - await statisticRepository.insert( - statisticModule.generator.generate({ - treatmentsSummary: [{ userId: user._id, treatmentDuration: 30 }], - route: 'confirmation', - importer: 'recent', - treatmentDate: dateBuilder.daysAgo(i), - }), - ); - } - } -} diff --git a/packages/generic/backend/src/app/scripts/insertTestUsers.ts b/packages/generic/backend/src/app/scripts/insertTestUsers.ts deleted file mode 100644 index d1895adcb..000000000 --- a/packages/generic/backend/src/app/scripts/insertTestUsers.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { userService } from '../../modules/user'; - -export { insertTestUsers }; - -async function insertTestUsers() { - await userService.signUpUser({ - email: 'test.annotator@label.fr', - name: 'Test Annotator', - password: 'annotator', - role: 'annotator', - }); - await userService.signUpUser({ - email: 'test.scrutator@label.fr', - name: 'Test Scrutator', - password: 'scrutator', - role: 'scrutator', - }); - await userService.signUpUser({ - email: 'test.admin@label.fr', - name: 'Test Admin', - password: 'admin', - role: 'admin', - }); -} diff --git a/scripts/initializeTestDb.sh b/scripts/initializeTestDb.sh deleted file mode 100755 index 8a36596d9..000000000 --- a/scripts/initializeTestDb.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -if [ -f .env ]; then - export $(grep -v '^#' .env | xargs) -fi - -cd packages/courDeCassation; - -echo "Reset the DB except for users" -sh scripts/runLocalScript.sh ./dist/scripts/clearDb.js; - -echo "Import the documents from SDER database" -sh scripts/runLocalScript.sh ./dist/scripts/importAllDocumentsFromSderSinceOrBetween.js --fromDaysAgo 2; - -echo "Annotate all the documents with the NLP engine" -sh scripts/runLocalScript.sh ./dist/scripts/annotateDocumentsWithoutAnnotationsWithNlp.js; - -echo "Insert mock values in DB" -sh scripts/runLocalScript.sh ./dist/scripts/initializeTestDb.js; - -echo "Create initial cache" -sh scripts/runLocalScript.sh ./dist/scripts/renewCache.js --beforeMinutes=5; From aef3489b2e9718ceb2cf3c6ac4f81e688f0f7131 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 14 Feb 2025 10:59:22 +0100 Subject: [PATCH 09/13] import checklist for all documents --- .../src/connector/mapper/mapCourtDecisionToDocument.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts b/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts index 9544c8d8a..ecd238efc 100644 --- a/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts +++ b/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts @@ -225,7 +225,10 @@ async function mapCourtDecisionToDocument( text: sderCourtDecision.originalText, zoning: zoning, nlpVersions: {} as documentType['nlpVersions'], - checklist: [], + checklist: + sderCourtDecision.labelTreatments + ?.filter((treatment) => treatment.source === 'NLP') + .sort((a, b) => b.order - a.order)[0].checklist ?? [], }); } From ed963de561350356015103238b4a15e7d82b26dc Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 14 Feb 2025 11:22:15 +0100 Subject: [PATCH 10/13] fix checklist import --- .../src/connector/mapper/mapCourtDecisionToDocument.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts b/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts index ecd238efc..299798b91 100644 --- a/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts +++ b/packages/courDeCassation/src/connector/mapper/mapCourtDecisionToDocument.ts @@ -228,7 +228,7 @@ async function mapCourtDecisionToDocument( checklist: sderCourtDecision.labelTreatments ?.filter((treatment) => treatment.source === 'NLP') - .sort((a, b) => b.order - a.order)[0].checklist ?? [], + .sort((a, b) => b.order - a.order)[0]?.checklist ?? [], }); } From 633848c1aa66da1b735c2aeac6abd1b7e5823131 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 14 Feb 2025 11:22:32 +0100 Subject: [PATCH 11/13] manage labelTreatment import --- .../src/connector/fetcher/sderFetcher.ts | 7 +- .../src/lib/connector/buildConnector.ts | 202 ++++++++++-------- 2 files changed, 110 insertions(+), 99 deletions(-) diff --git a/packages/courDeCassation/src/connector/fetcher/sderFetcher.ts b/packages/courDeCassation/src/connector/fetcher/sderFetcher.ts index 574d56e8c..e99c14253 100644 --- a/packages/courDeCassation/src/connector/fetcher/sderFetcher.ts +++ b/packages/courDeCassation/src/connector/fetcher/sderFetcher.ts @@ -19,11 +19,6 @@ const sderFetcher = { sourceName, ); - return courtDecisions?.filter((courtDecision) => { - if (!courtDecision.originalText) { - return false; - } - return true; - }); + return courtDecisions; }, }; diff --git a/packages/generic/backend/src/lib/connector/buildConnector.ts b/packages/generic/backend/src/lib/connector/buildConnector.ts index a95748474..ebdb807d3 100644 --- a/packages/generic/backend/src/lib/connector/buildConnector.ts +++ b/packages/generic/backend/src/lib/connector/buildConnector.ts @@ -2,13 +2,9 @@ import { annotationModule, annotationType, documentType, - idModule, settingsType, } from '@label/core'; -import { - buildDocumentRepository, - documentService, -} from '../../modules/document'; +import { buildDocumentRepository } from '../../modules/document'; import { logger } from '../../utils'; import { connectorConfigType } from './connectorConfigType'; import { treatmentService } from '../../modules/treatment'; @@ -18,6 +14,8 @@ import { Sources } from 'dbsder-api-types'; export { buildConnector }; function buildConnector(connectorConfig: connectorConfigType) { + const preAssignator = buildPreAssignator(); + return { importSpecificDocument, importNewDocuments, @@ -56,11 +54,22 @@ function buildConnector(connectorConfig: connectorConfigType) { return; } + if ( + !courtDecision.originalText || + !courtDecision.labelTreatments || + courtDecision.labelTreatments.length === 0 + ) { + logger.log({ + operationName: 'importSpecificDocument', + msg: + 'Court decision must have an original text and labelTreatments, skipping.', + }); + return; + } + logger.log({ operationName: 'importSpecificDocument', - msg: `Court decision found. labelStatus: ${ - courtDecision.labelStatus - }, ${!!courtDecision.pseudoText ? 'already' : 'never'} pseudonymised`, + msg: `Court decision found. labelStatus: ${courtDecision.labelStatus}`, }); const document = await connectorConfig.mapCourtDecisionToDocument( courtDecision, @@ -74,97 +83,87 @@ function buildConnector(connectorConfig: connectorConfigType) { if (lowPriority) { await insertDocument({ ...document, route: 'exhaustive' }); } else { - await insertDocument({ ...document, route: 'request', priority: 4 }); + await insertDocument({ + ...document, + route: 'request', + priority: 4, + status: 'toBeConfirmed', + }); } logger.log({ operationName: 'importSpecificDocument', msg: 'Insertion done', }); - // To update + // If keepLabelTreatments reimport last treatment, otherwise reimport last NLP treatment if (keepLabelTreatments) { - if (courtDecision.labelTreatments?.length == 0) { - logger.error({ - operationName: 'importSpecificDocument', - msg: - 'LabelTreatments not found in court decision, skiping labelTreatments reimport.', - }); - } else { - logger.log({ - operationName: 'importSpecificDocument', - msg: 'LabelTreatments found in court decision, importing.', - }); - - const annotations: annotationType[] = - courtDecision.labelTreatments == undefined - ? [] - : courtDecision.labelTreatments[ - courtDecision.labelTreatments.length - 1 - ].annotations.map((annotation) => { - return annotationModule.lib.buildAnnotation({ - category: annotation.category, - start: annotation.start, - text: annotation.text, - certaintyScore: 1, - entityId: annotation.entityId, - }); + const annotations: annotationType[] = + courtDecision.labelTreatments == undefined + ? [] + : courtDecision.labelTreatments[ + courtDecision.labelTreatments.length - 1 + ].annotations.map((annotation) => { + return annotationModule.lib.buildAnnotation({ + category: annotation.category, + start: annotation.start, + text: annotation.text, + certaintyScore: 1, + entityId: annotation.entityId, }); + }); - await treatmentService.createTreatment( - { - documentId: document._id, - previousAnnotations: [], - nextAnnotations: annotations, - source: 'reimportedTreatment', - }, - settings, - ); - - // on récupère la checklist du treatment NLP le plus récent - const reimportedChecklist = courtDecision.labelTreatments - ?.filter((treatment) => treatment.source === 'NLP') - .sort((a, b) => b.order - a.order)[0].checklist; + await treatmentService.createTreatment( + { + documentId: document._id, + previousAnnotations: [], + nextAnnotations: annotations, + source: 'reimportedTreatment', + }, + settings, + ); - if (reimportedChecklist) { - await documentService.updateDocumentChecklist( - document._id, - reimportedChecklist, - ); - logger.log({ - operationName: 'importSpecificDocument', - msg: 'Checklist reimported', - }); - } + logger.log({ + operationName: 'importSpecificDocument', + msg: 'Last labelTreatment reimported.', + }); + } else { + const lastNlpLabelTreatment = courtDecision.labelTreatments + ?.filter((treatment) => treatment.source === 'NLP') + .sort((a, b) => b.order - a.order)[0]; + if (!lastNlpLabelTreatment) { logger.log({ operationName: 'importSpecificDocument', - msg: 'LabelTreatments reimported, checking for pre-assignation.', + msg: 'Court decision must have an NLP, skipping.', }); - const preAssignator = buildPreAssignator(); - const isPreassignated = await preAssignator.preAssignDocument( - document, - ); - if (!isPreassignated) { - logger.log({ - operationName: 'importSpecificDocument', - msg: - 'No preAssignation found, setting documentStatus to next status.', - }); - if (lowPriority) { - await documentService.updateDocumentStatus( - idModule.lib.buildId(document._id), - 'free', - ); - } else { - await documentService.updateDocumentStatus( - idModule.lib.buildId(document._id), - 'toBeConfirmed', - ); - } - } + return; } + + const annotations: annotationType[] = lastNlpLabelTreatment.annotations.map( + (annotation) => { + return annotationModule.lib.buildAnnotation({ + category: annotation.category, + start: annotation.start, + text: annotation.text, + certaintyScore: annotation.certaintyScore, + entityId: annotation.entityId, + }); + }, + ); + + await treatmentService.createTreatment( + { + documentId: document._id, + previousAnnotations: [], + nextAnnotations: annotations, + source: 'NLP', + }, + settings, + ); } + await preAssignator.preAssignDocument(document); + logger.log({ operationName: 'importSpecificDocument', msg: 'Selected document has been inserted in label database.', @@ -209,21 +208,36 @@ function buildConnector(connectorConfig: connectorConfigType) { operationName: 'importNewDocuments', msg: `${newDecisionForSource.length} ${source} decisions to pseudonymise found.`, }); - for (const decision of newDecisionForSource) { - const converted = await connectorConfig.mapCourtDecisionToDocument( - decision, + for (const courtDecision of newDecisionForSource) { + if ( + !courtDecision.originalText || + !courtDecision.labelTreatments || + courtDecision.labelTreatments.length === 0 + ) { + logger.log({ + operationName: 'importNewDocuments', + msg: + 'Court decision must have an original text and labelTreatments, skipping.', + }); + return; + } + + const document = await connectorConfig.mapCourtDecisionToDocument( + courtDecision, 'recent', ); - insertDocument(converted); + insertDocument(document); - const lastNlpLabelTreatment = decision.labelTreatments + const lastNlpLabelTreatment = courtDecision.labelTreatments ?.filter((treatment) => treatment.source === 'NLP') .sort((a, b) => b.order - a.order)[0]; if (!lastNlpLabelTreatment) { - throw new Error( - 'Could not import to label a document without NLP annotations', - ); + logger.log({ + operationName: 'importNewDocuments', + msg: 'Court decision must have an NLP treatment, skipping.', + }); + return; } const annotations: annotationType[] = lastNlpLabelTreatment.annotations.map( @@ -240,7 +254,7 @@ function buildConnector(connectorConfig: connectorConfigType) { await treatmentService.createTreatment( { - documentId: converted._id, + documentId: document._id, previousAnnotations: [], nextAnnotations: annotations, source: 'NLP', @@ -248,15 +262,17 @@ function buildConnector(connectorConfig: connectorConfigType) { settings, ); + await preAssignator.preAssignDocument(document); + await connectorConfig.updateDocumentLabelStatusToLoaded( - converted.externalId, + document.externalId, ); } } } } -function insertDocument(document: documentType) { +async function insertDocument(document: documentType) { const documentRepository = buildDocumentRepository(); try { From 3fc752c348d2fac12c2000e810a32200fc682e21 Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 14 Feb 2025 12:08:13 +0100 Subject: [PATCH 12/13] do not send NLP treatments at export --- docs/documentStatuses.md | 2 +- .../src/lib/exporter/buildExporter.spec.ts | 66 +++++++++---------- .../backend/src/lib/exporter/buildExporter.ts | 6 +- .../src/modules/treatment/lib/concat.spec.ts | 47 ++----------- .../core/src/modules/treatment/lib/concat.ts | 15 +---- 5 files changed, 41 insertions(+), 95 deletions(-) diff --git a/docs/documentStatuses.md b/docs/documentStatuses.md index cb6956a06..6d27ec644 100644 --- a/docs/documentStatuses.md +++ b/docs/documentStatuses.md @@ -2,7 +2,7 @@ A `document` is supposed to follow a specific flow once it enters the label database. Its status will evolve accordingly. -- `free`: the document is ready to be annotated by a working user. There are already several `treatments` related to that document (one by the `NLP`, maybe one with the `supplementaryAnnotations` if decision is partially public) +- `free`: the document is ready to be annotated by a working user. There are already several `treatments` related to that document (one by the `NLP` and others from users) - `pending`: the document is proposed to a working user. An `assignation` and a corresponding empty `treatment` have been created. The document won't be proposed to another working user. - `saved`: the document is being annotated by a working user. - `toBeConfirmed`: the document needs to be proof-read a second time by an administrator diff --git a/packages/generic/backend/src/lib/exporter/buildExporter.spec.ts b/packages/generic/backend/src/lib/exporter/buildExporter.spec.ts index 4349c71ca..b612f48f5 100644 --- a/packages/generic/backend/src/lib/exporter/buildExporter.spec.ts +++ b/packages/generic/backend/src/lib/exporter/buildExporter.spec.ts @@ -22,29 +22,17 @@ describe('buildExporter', () => { describe('exportTreatedDocumentsSince', () => { it('should export all the ready document since the given days fetched by the exporter', async () => { const days = 4; - const checklist = [ - { - check_type: 'check', - message: 'message', - short_message: 'short message', - entities: [], - sentences: [], - metadata_text: [], - }, - ]; const documents = ([ { text: 'Benoit est ingénieur', status: 'done', updateDate: dateBuilder.daysAgo(5), - checklist: checklist, }, { status: 'pending' }, { text: 'Romain est designer', status: 'done', updateDate: dateBuilder.daysAgo(7), - checklist: checklist, }, { status: 'done', @@ -76,9 +64,9 @@ describe('buildExporter', () => { after: [ { category: 'firstName', - entityId: 'firstName_Romain', - start: 0, - text: 'Romain', + entityId: 'firstName_designer', + start: 11, + text: 'designer', certaintyScore: 1, }, ], @@ -88,6 +76,32 @@ describe('buildExporter', () => { lastUpdateDate: 1720776599000, source: 'NLP' as treatmentType['source'], }, + { + annotationsDiff: { + before: [ + { + category: 'firstName', + entityId: 'firstName_designer', + start: 11, + text: 'designer', + certaintyScore: 1, + }, + ], + after: [ + { + category: 'firstName', + entityId: 'firstName_Romain', + start: 0, + text: 'Romain', + certaintyScore: 1, + }, + ], + }, + documentId: documents[2]._id, + order: 2, + lastUpdateDate: 1720776699000, + source: 'annotator' as treatmentType['source'], + }, ].map(treatmentModule.generator.generate); await Promise.all(documents.map(documentRepository.insert)); await Promise.all(treatments.map(treatmentRepository.insert)); @@ -106,22 +120,6 @@ describe('buildExporter', () => { ['[FIRST_NAME 1] est ingénieur', '[FIRST_NAME 1] est designer'].sort(), ); expect(exportedLabelTreatments.sort()).toEqual([ - { - annotations: [ - { - category: 'firstName', - certaintyScore: 1, - entityId: 'firstName_Benoit', - start: 0, - text: 'Benoit', - }, - ], - order: 1, - source: 'NLP', - treatmentDate: '2024-07-12T09:28:27.000Z', - version: undefined, - checklist: checklist, - }, { annotations: [ { @@ -133,10 +131,8 @@ describe('buildExporter', () => { }, ], order: 1, - source: 'NLP', - treatmentDate: '2024-07-12T09:29:59.000Z', - version: undefined, - checklist: checklist, + source: 'LABEL_WORKING_USER_TREATMENT', + treatmentDate: '2024-07-12T09:31:39.000Z', }, ]); }); diff --git a/packages/generic/backend/src/lib/exporter/buildExporter.ts b/packages/generic/backend/src/lib/exporter/buildExporter.ts index eac6dc1ff..8299a31b2 100644 --- a/packages/generic/backend/src/lib/exporter/buildExporter.ts +++ b/packages/generic/backend/src/lib/exporter/buildExporter.ts @@ -194,11 +194,7 @@ function buildExporter( await exporterConfig.sendDocumentPseudonymisationAndTreatments({ externalId: document.externalId, pseudoText: anonymizer.anonymizeDocument(document).text, - labelTreatments: treatmentModule.lib.concat( - treatments, - document.nlpVersions, - document.checklist, - ), + labelTreatments: treatmentModule.lib.concat(treatments), }); logger.log({ operationName: 'exportDocument', diff --git a/packages/generic/core/src/modules/treatment/lib/concat.spec.ts b/packages/generic/core/src/modules/treatment/lib/concat.spec.ts index 985c33b6b..b3327f623 100644 --- a/packages/generic/core/src/modules/treatment/lib/concat.spec.ts +++ b/packages/generic/core/src/modules/treatment/lib/concat.spec.ts @@ -2,24 +2,6 @@ import { documentModule, treatmentModule, treatmentType } from '../../'; import { concat } from './concat'; describe('concat', () => { - const nlpVersion = { - juriSpacyTokenizer: { - version: `VERSION_${Math.random()}`, - date: `DATE_${Math.random()}`, - }, - juritools: { - version: `VERSION_${Math.random()}`, - date: `DATE_${Math.random()}`, - }, - pseudonymisationApi: { - version: `VERSION_${Math.random()}`, - date: `DATE_${Math.random()}`, - }, - model: { - name: `MODEL_${Math.random()}`, - }, - }; - it('should return a labelTreatment', () => { const document = documentModule.generator.generate(); const treatments: treatmentType[] = [ @@ -40,27 +22,26 @@ describe('concat', () => { { documentId: document._id, order: 3, source: 'admin' as treatmentType['source'], lastUpdateDate: 1720776507123 }, ].map(treatmentModule.generator.generate); - const labelTreatments = concat(treatments, nlpVersion); + const labelTreatments = concat(treatments); expect(labelTreatments).toEqual([ - { annotations: [], order: 1, source: 'NLP', treatmentDate: '2024-07-12T08:38:27.000Z', version: nlpVersion }, { annotations: [], - order: 2, + order: 1, source: 'LABEL_AUTO_TREATMENT', treatmentDate: '2024-07-12T09:29:27.000Z', version: undefined, }, { annotations: [], - order: 3, + order: 2, source: 'LABEL_WORKING_USER_TREATMENT', treatmentDate: '2024-07-12T09:28:27.700Z', version: undefined, }, { annotations: [], - order: 4, + order: 3, source: 'LABEL_WORKING_USER_TREATMENT', treatmentDate: '2024-07-12T09:28:27.123Z', version: undefined, @@ -107,16 +88,6 @@ describe('concat', () => { ]); }); it('should return a checklist in the NLP treatment', () => { - const checklist = [ - { - check_type: 'check', - message: 'message', - short_message: 'short message', - entities: [], - sentences: [], - metadata_text: [], - }, - ]; const document = documentModule.generator.generate(); const treatments: treatmentType[] = [ { @@ -129,20 +100,12 @@ describe('concat', () => { { documentId: document._id, order: 0, source: 'NLP' as treatmentType['source'], lastUpdateDate: 1720773507000 }, ].map(treatmentModule.generator.generate); - const labelTreatments = concat(treatments, nlpVersion, checklist); + const labelTreatments = concat(treatments); expect(labelTreatments).toEqual([ { annotations: [], order: 1, - source: 'NLP', - treatmentDate: '2024-07-12T08:38:27.000Z', - version: nlpVersion, - checklist: checklist, - }, - { - annotations: [], - order: 2, source: 'LABEL_WORKING_USER_TREATMENT', treatmentDate: '2024-07-12T09:28:27.700Z', version: undefined, diff --git a/packages/generic/core/src/modules/treatment/lib/concat.ts b/packages/generic/core/src/modules/treatment/lib/concat.ts index 5f12bffa8..64bed5f1f 100644 --- a/packages/generic/core/src/modules/treatment/lib/concat.ts +++ b/packages/generic/core/src/modules/treatment/lib/concat.ts @@ -1,15 +1,10 @@ import { treatmentType } from '..'; import { computeAnnotations } from './computeAnnotations'; -import { documentType } from '../../document/documentType'; import { LabelTreatment } from 'dbsder-api-types'; export { concat }; -function concat( - treatments: treatmentType[], - nlpVersions?: documentType['nlpVersions'], - checklist?: documentType['checklist'], -): LabelTreatment[] { +function concat(treatments: treatmentType[]): LabelTreatment[] { const labelTreatments: LabelTreatment[] = []; const sortedTreatments = treatments.sort((treatment1, treatment2) => treatment1.order - treatment2.order); @@ -18,20 +13,18 @@ function concat( const order = sortedTreatments.length; const currentTreatment = sortedTreatments[order - 1]; - if (currentTreatment.source != 'reimportedTreatment') { + if (currentTreatment.source != 'reimportedTreatment' && currentTreatment.source != 'NLP') { labelTreatments.unshift({ annotations: computeAnnotations(sortedTreatments), source: computeSource(currentTreatment.source), order, - version: currentTreatment.source === 'NLP' ? nlpVersions : undefined, - checklist: currentTreatment.source === 'NLP' ? checklist : undefined, treatmentDate: new Date(currentTreatment.lastUpdateDate).toISOString(), }); } sortedTreatments.pop(); } - // re-write order in case of reimportedTreatment + // re-write order in case of skipped treatments (NLP or reimported) labelTreatments.forEach((labelTreatment, index) => { labelTreatment.order = index + 1; }); @@ -40,8 +33,6 @@ function concat( function computeSource(source: treatmentType['source']) { switch (source) { - case 'NLP': - return 'NLP'; case 'annotator': case 'admin': return 'LABEL_WORKING_USER_TREATMENT'; From fbc4ee0b5d1067a938bd0f7363762f4d5908d1bd Mon Sep 17 00:00:00 2001 From: Antoine Jeanneney Date: Fri, 14 Feb 2025 12:11:34 +0100 Subject: [PATCH 13/13] delete unused sh scripts --- scripts/startLocal.sh | 7 ------- scripts/startLocalDev.sh | 7 ------- 2 files changed, 14 deletions(-) delete mode 100755 scripts/startLocal.sh delete mode 100644 scripts/startLocalDev.sh diff --git a/scripts/startLocal.sh b/scripts/startLocal.sh deleted file mode 100755 index a6a5d8df1..000000000 --- a/scripts/startLocal.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -DIR=`dirname "$0"` - -$DIR/initializeTestDb.sh - -cd packages/generic/client && yarn serve -s build -l 55432 && cd ../../.. & lerna run --scope @label/cour-de-cassation startLocal --stream diff --git a/scripts/startLocalDev.sh b/scripts/startLocalDev.sh deleted file mode 100644 index d427d3508..000000000 --- a/scripts/startLocalDev.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -DIR=`dirname "$0"` - -$DIR/initializeTestDb.sh - -lerna run --scope @label/cour-de-cassation startLocal --stream