Skip to main content

Librairie outils IA Lexia par Lexfluent

Project description

Libraire python Lexfluent GeDAIA

Création/Révision Auteur date
Création Jacques MASSA 2 décembre 2024
Modification jacques MASSA 10 mars 2025
Modification jacques MASSA 06 février 2026
Modification jacques MASSA 05 mars 2026
Modification jacques MASSA 21 mai 2026
Modification jacques MASSA 22 juin 2026

Présentation

La librairie pyLexfluent propose toutes les fonctionnalités IA dans les domaines juridique et document.

  • Classification : Entraînement et inférence
  • Extraction de données : ODP, CNI, IBAN, Document juridique, Certificat d'Urbanisme, Extrait Acte de naissance, Extrait Acte de Décés,Extrait Acte de Mariage
  • Augmentation des données : Finance

Crédits

Built with Transformers
Built with gtp-oss20B
Built with Llama
Built with PaddleOcr

Nouveautés

0.2.1 :

Ajout de l'agent extracteur , InspectorRequest  et InpectorResult : Nouveau pattern de l'agent IA 
Ajout de la librairie PaddleOCR pour l'extraction de formulaires et tableaux depuis doccuments numérisés
Requiert un serveur d'inférence Paddle . 
Requiert l'exécution de la commande : 

Plus d'information: Documentation PadleOCR

Nouveaux extracteurs
- Gestion des programmes immobiliers :
    + Urbanisme : Attestation non retrait et/ou non recours, Dépôt/Transfert permis
    + Juridique : 
        - Constats d'affichage par un huissier,
        - Attestation acte de vente,
- Finance : 
    + Courrier proposition acte de prêts
Exemple de code
Document à analyser

Demande attestation non retrait/non recours permis de construire ou d'aménager :

FORMULAIRE DE DEMANDE D'ATTESTATION DE RECOURS/NON RECOURS

Demandeur de l'attestation

Civilité : nMadame: ___ Monsieur : ☐ Maître : □ Société:☒ NOM /Prénom : AAA AAAAAAAAAA dresse : 1 avenue de l'Europe 99999 AAAAAAX Téléphone :
$ underline{text{99 99 99 99 99}} $ Courriel :
$ underline{text{pxxxxxx.xxxxxx@xxxxxx-xxxxxxxxxx.fr}} $

ATTESTATION DE RECOURS/NON RECOURS

Délivrée en application de l'article R. 600-7 du code de l'urbanisme

Le greffier en chef du tribunal administratif de Besançon atteste que la décision désignée ci-après : N° de l'autorisation d'occupation ou d'utilisation du sol (exemple pour un permis de construire : PC 075 XXX XX XXXXX) PC 999 999 99 J0019 N° de la délibération : Auteur de la décision (maire, préfet) : mairie des AAAAAA Date de la décision :
$ underline{text{6 janvier}} $ Bénéficiaire de l'autorisation : AAA AAAAAAAAAA construction d'un immeuble collectif de 8 logements avec parking en sous sol route de AAAAAAAA 99999 LES RAAAAAA

Nature et lieu de l'opération : (éléments ci-dessus à compléter par le demandeur)

☒ n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.

□ a fait l'objet d'un recours contentieux enregistré au tribunal administratif de Besançon en date du ___

00/04/2025 À Besançon, le Le greffier en chef

\"Image\"

TRADITATIF DE SANSON

Ce formulaire doit obligatoirement être adressé au tribunal (accompagné obligatoirement d'une copie de la décision d'urbanisme faisant l'objet de la demande) exclusivement par courriel, et uniquement à l'adresse mail suivante : (greffe.ta-besancon@juradm.fr). Toute demande incomplète et formulée sur une autre adresse électronique, quelle qu'elle soit, par courrier postal ou déposée à l'accueil du greffe, ne sera pas traitée.

Résultat

import argparse
import json
import time
import logging
import asyncio
from pathlib import Path
import sys
import os

from threading import Thread

from lxf.extractors.metier.immobilier.urbanisme.urbanisme_extractors import urbanisme_extract_attestations_recours_retrait_permis



# System call
os.system("")

# Class of different styles
class print_color():
    BLACK = '\033[30m'
    RED = '\033[31m'
    GREEN = '\033[32m'
    YELLOW = '\033[33m'
    BLUE = '\033[34m'
    MAGENTA = '\033[35m'
    CYAN = '\033[36m'
    WHITE = '\033[37m'
    UNDERLINE = '\033[4m'
    RESET = '\033[0m'
from lxf.domain.inspector_request import InspectorRequest, InspectorResult
import lxf.settings as settings
settings.set_logging_level(logging.INFO)
settings.enable_tqdm=False
###################################################################

logger = logging.getLogger('test_pim')
fh = logging.FileHandler('./logs/pylexfluent.log')
fh.setLevel(settings.get_logging_level())
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.setLevel(settings.get_logging_level())
logger.addHandler(fh)
#################################################################


async def do_test_pim(file_path:str) :
    result = await urbanisme_extract_attestations_recours_retrait_permis(file_path,
                                base_url="http://XXXX:8000/v1",
                                paddle_server="https://ocr.lexfluent.com/v1")
    if result !=None: 
        print(print_color.BLUE+f"Resultat:\n{result.model_dump_json(indent=4)}")
    else :
        print("Aucune donnée n'a pu etre extraite !")    

if __name__ == "__main__":
    sys.stdout.reconfigure(line_buffering=True) 
    parser = argparse.ArgumentParser(description="Exemple d'usage")
    parser.add_argument("--file","-F",nargs=1,required=False,type=str,help="Fichier à traiter, exemple: --file 'data/PIM/Attestation/non_retrait/ATT NR MAIRIE + TA PCM01_26143778.pdf'")
    parser.add_argument("--dossier","-D",nargs=1,required=False,type=str,help="Dossier contenant des Fichiers à traiter, exemple: --dossier data/PIM/Attestation/non_retrait")
    args = parser.parse_args()
    files:list[str]=[]
    if args.file !=None:
        filename:str=args.file[0]
        if os.path.exists(filename) is False:
            print(print_color.RED+f"Fichier {filename} introuvable !")
            print(print_color.BLACK+"")
            exit(-2)  
        files.append(filename)      
    elif args.dossier !=None :
        folder:str=args.dossier[0]
        if os.path.exists(folder) is False:
            print(print_color.RED+f"Dossier {folder} introuvable !")
            print(print_color.BLACK+"")
            exit(-2)    
        for file in Path(folder).rglob("*.pdf"):
            files.append(f"{file}")
            
    else : 
        print(print_color.RED+"Aucun fichier ou dossier défini") 
        print(print_color.BLACK+"")
        exit(-1)
    threads:list[Thread]=[]
    for file in files :
        print(print_color.CYAN+f"Traitement du fichier : {file}")
        filename=file
        thread = Thread(target=asyncio.run,args=[do_test_pim(file)])         
        thread.start()
        threads.append(thread)
        # attendre avant le prochain traitement
        time.sleep(2)
    for t in threads : 
        try:
            t.join()
            print("thread terminé")
        except RuntimeError as err:
            print(print_color.RED+f"Erreur pendant l'attente du thread : {err}")

Sortie :

{
    "document": "ATT NT TA_26127988.pdf",
    "source": [
        " ## FORMULAIRE DE DEMANDE D'ATTESTATION DE RECOURS/NON RECOURS\n\n### Demandeur de l'attestation\n\nCivilité :\n\nMadame: ___\n\nMonsieur : ☐\n\nMaître : □\n\nSociété:☒\n\nNOM /Prénom : AAA AAAAAAAAAA\n\nAdresse : 1 avenue de l'Europe 99999 AAAAAAX\n\nTéléphone :  $ underline{text{99 99 99 99 99}} $\n\nCourriel :  $ underline{text{pxxxxxx.xxxxxx@xxxxxx-xxxxxxxxxx.fr}} $\n\n# ATTESTATION DE RECOURS/NON RECOURS\n\n# Délivrée en application de l'article R. 600-7 du code de l'urbanisme\n\nLe greffier en chef du tribunal administratif de Besançon atteste que la décision désignée ci-après :\n\nN° de l'autorisation d'occupation ou d'utilisation du sol (exemple pour un permis de construire : PC 075 XXX XX XXXXX) PC 999 999 99 J0019\n\nN° de la délibération :\n\nAuteur de la décision (maire, préfet) : mairie des Rousses\n\nDate de la décision :  $ underline{text{6 janvier}} $\n\nBénéficiaire de l'autorisation : AAA AAAAAAAAAA\n\nconstruction d'un immeuble collectif de 8 logements avec parking en sous sol route de AAAAAAAA\n\n99999 LES RAAAAAA\n\nNature et lieu de l'opération :\n\n(éléments ci-dessus à compléter par le demandeur)\n\n☒ n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.\n\n□ a fait l'objet d'un recours contentieux enregistré au tribunal administratif de Besançon en date du ___\n\n00/04/2025\n\nÀ Besançon, le\n\nLe greffier en chef\n\n<div style=\"text-align: center;\"><img src=\"imgs/img_in_image_box_856_1432_934_1504.jpg\" alt=\"Image\" width=\"6%\" />\n\nTRADITATIF DE SANSON\n\n</div>\n\n\nCe formulaire doit obligatoirement être adressé au tribunal (accompagné obligatoirement d'une copie de la décision d'urbanisme faisant l'objet de la demande) exclusivement par courriel, et uniquement à l'adresse mail suivante : (greffe.ta-besancon@juradm.fr). Toute demande incomplète et formulée sur une autre adresse électronique, quelle qu'elle soit, par courrier postal ou déposée à l'accueil du greffe, ne sera pas traitée."
    ],
    "logs": [],
    "content": {
        "source": [
            "PC 999 999 99 J0019",
            "n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.",
            "Date de la décision : 6 janvier",
            "Le greffier en chef du tribunal administratif de Besançon",
            "Auteur de la décision (maire, préfet) : mairie des AAAAAAA"
        ],
        "permis": [
            {
                "decision": "NON RECOURS",
                "detail": "n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.",
                "validation_decision": "Le greffier en chef du tribunal administratif de Besançon a déclaré explicitement qu'il n'y avait pas de recours, ce qui constitue une attestation de non recours.",
                "le_maire": "",
                "la_ville": "AAAAAAA",
                "tribunal": "Tribunal administratif de Besançon",
                "le_greffier": "greffier en chef du tribunal administratif de Besançon",
                "date_decision": "6 janvier",
                "permis_trouve": true,
                "numero_brut": "PC 999 999 99 J0019",
                "numero_normalise": "PC99999999J0019",
                "date_obtention": null
            }
        ]
    }
}

0.1.97 :

Ajout de l'extraction des données des offres de prêts du Crédit Agricole

0.1.96 :

Ajout de la protection contre l'injection de prompt et de jailbreak dans les agents IA (Interviewer)

Prérequis :

Vous devez avoir un token Hugginface en variable d'environnement :

```
export HF_TOKEN = XXXXXXXXXXXXXXXXXXXXXXXXXXX
echo $HF_TOKEN
```

Le Token doit avoir l'accès à : meta-llama/Prompt-Guard-86M

Pb d'import de tensorflow_hub du au retrait de pkg_resources de setuptools>=82.0.0 . 
Pour contourner ce problème, il faut forcer setuptools<81 

Identification de la menace

Une large partie de nos agents IA ont pour mission d'analyser, inspecter, questionner le contenu de documents provenant de PDF ou autres formats. A l'instart des virus pour nos programmes, ces documents peuvent eux-mêmes contenir des "menaces" sous la forme d'injection de prompt ou de jailbreak :

  • Les Injections de Prompt (Prompt Injections) sont des entrées qui exploitent la concaténation de données non fiables (provenant de tiers ou d'utilisateurs) dans la fenêtre de contexte d'un modèle, afin d'amener ce dernier à exécuter des instructions non souhaitées.

  • Les Jailbreaks (ou débridages) sont des instructions malveillantes conçues pour passer outre les fonctionnalités de sûreté et de sécurité intégrées à un modèle.

Afin de lutter contre ces nouvelles menaces, nous avons mis en place plusieurs protections.

0.1.92 :

IBAN DetectStructure

    Fix Valeur par défaut du rois_filter = FALSE

0.1.91 :

IBAN Analyzer

Fix bug liste des logs non initialisée 

0.1.90 :

Interviewer AI

Fix bug valeur par défaut de AI_TIMEOUT(180) et AI_RETRIES (1)

0.1.89 :

#### Reconnaissance des proposition de prêts.
Chaque requête AI dispose d'un timeout(180s par défaut)  pour s'exécuter, et d'un nombre de tentatives(1 tentative par défaut)  pour rééssayer.
Exemple :
```
	    result = await try_safe_execute_async(logger,
                                      odp_proposal_extractor.extract_data,
                                      file_path=file_path, 
                                      base_url=base_url, 
                                      default_model_instruct=model_instruct, 
                                      openapi_compatibility=openapi_compatibility,
                                      ai_timeout=120, 
                                      ai_max_retries=2)
```
#### Loging.
Rassemblement des logs dans un seul et même fichier : pylexfluent.log 

Installations Prérequises

"pip install setuptools",
"pip install wheel",
"pip install scikit-learn",
"pip install matplotlib",
"pip install tqdm",
"pip install pytesseract ",
"pip install pillow>=10.1.0",
"pip install jax==0.4.38",
"pip install jaxlib==0.4.38",
"pip install mediapipe",
"pip install opencv-python", 
"pip install pandas",
"pip install tensorrt",
"pip install tensorrt-lean",
"pip install tensorrt-dispatch",
"pip install tensorflow",
"pip install tf-keras",
"pip install tensorflow-hub",
"pip install torch",
"pip install torchvision",
"pip install torchaudio",
"pip install sentence-transformers",
"pip install spacy[cuda12x]",
"pip install ocrmypdf",
"pip install pdf2image",
"pip install pdfplumber",
"pip install langchain-community",
"pip install langchain-ollama",
"pip install langchain-openai",
"pip install pymongo",
"pip install openpyxl",
"pip install easyocr",
"pip install docling[all]"
python -m spacy download fr_core_news_lg

Il y peut y avoir un conflit de version avec cuDNN requis par TensforFlow et Torch Dans ce cas il faut supprimer nvidia-cuDNN-cu12 apporté par PIP

pip uninstall nvidia-cudnn-cu12

Prerequis système

Update et installations requises

    apt-get update 
    apt-get upgrade
    apt install software-properties-common -y
    apt-get install poppler-utils -y
    add-apt-repository ppa:alex-p/tesseract-ocr5
    apt-get install libc6 -y
    apt-get install poppler-utils -y
    apt-get install tesseract-ocr -y
    apt-get install tesseract-ocr-fra -y
    apt-get install tesseract-ocr-eng -y
    apt-get install tesseract-ocr-ita -y
    apt-get install tesseract-ocr-spa -y
    apt-get install tesseract-ocr-deu -y
    apt-get install tesseract-ocr-cos -y
    apt-get install tesseract-ocr-lat -y
    apt-get install automake libtool -y
    apt-get install libleptonica-dev -y
    apt-get install ffmpeg libsm6 libxext6  -y
    apt-get install ocrmypdf -y    

JBIG2

Installing the JBIG2 encoder Most Linux distributions do not include a JBIG2 encoder since JBIG2 encoding was patented for a long time. All known JBIG2 US patents have expired as of 2017, but it is possible that unknown patents exist.

JBIG2 encoding is recommended for OCRmyPDF and is used to losslessly create smaller PDFs. If JBIG2 encoding is not available, lower quality CCITT encoding will be used for monochrome images.

JBIG2 decoding is not patented and is performed automatically by most PDF viewers. It is widely supported and has been part of the PDF specification since 2001.

JBIG encoding is automatically provided by these OCRmyPDF packages: - Docker image (both Ubuntu and Alpine) - Snap package - ArchLinux AUR package - Alpine Linux package - Homebrew on macOS

For all other platforms, you would need to build the JBIG2 encoder from source:

git clone https://github.com/agl/jbig2enc
cd jbig2enc
./autogen.sh
./configure && make
[sudo] make install

Dependencies include libtoolize and libleptonica, which on Ubuntu systems are packaged as libtool and libleptonica-dev. On Fedora (35) they are packaged as libtool and leptonica-devel. For this to work, please make sure to install autotools, automake, libtool, pkg-config and leptonica first if not already installed. Other dependencies might be required depending on your system.

[sudo] apt install autotools-dev automake libtool libleptonica-dev pkg-config

Téléchargement modèles

SPACY

GPU issue

Si problème : Successful NUMA node read from SysFS had negative value (-1)

for a in /sys/bus/pci/devices/*; do echo 0 |  tee -a $a/numa_node; done

Exemples d'utilisation

Classification

Code

import logging
import sys

from lxf.services.measure_time import measure_time_async
from lxf.services.try_safe import try_safe_execute_asyncio



from lxf.ai.classification.classifier import get_classification
from lxf.domain.predictions import  Predictions

import lxf.settings as settings 
from lxf.settings import set_looging_level, get_logging_level
set_logging_level(logging.DEBUG)
###################################################################

logger = logging.getLogger('test classifier')
fh = logging.FileHandler('./logs/test_classifier.log')
fh.setLevel(get_logging_level())
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.setLevel(get_logging_level())
logger.addHandler(fh)
#################################################################

@measure_time_async
async def do_test(file_name) -> Predictions :
    """
    """
    return await get_classification(file_name=file_name,max_pages=10)


if __name__ == "__main__":
    sys.stdout.reconfigure(line_buffering=True) 
    pdf_path = "data/ODP.pdf"
    iban_pdf="data/RIBB.pdf"
    result = try_safe_execute_asyncio(logger=logger,func=do_test,file_name=iban_pdf) #asyncio.run(do_test(iban_pdf))
    print(result)    
    result = try_safe_execute_asyncio(logger=logger,func=do_test,file_name=pdf_path) #asyncio.run(do_test(pdf_path))
    print(result)

Code

import logging
import asyncio
import os
import sys



import lxf.settings as settings
from lxf.setting import set_logging_level, get_logging_level
set_logging_level(logging.DEBUG)
settings.enable_tqdm=False

from lxf.domain.loan import Pret
from lxf.extractors.finance import odp_extractor
from lxf.extractors.finance import iban_extractor

from lxf.services.try_safe import  try_safe_execute_async



###################################################################

logger = logging.getLogger('test_finance')
fh = logging.FileHandler('./logs/test_finance.log')
fh.setLevel(get_logging_level())
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.setLevel(get_logging_level())
logger.addHandler(fh)
#################################################################

async def do_test_odp(file_path:str)->Pret:
    result = await try_safe_execute_async(logger,odp_extractor.extract_data,file_path=file_path)
    return result
    
async def do_test_iban(file_path:str)->str :
    """
    """
    result = await try_safe_execute_async(logger,iban_extractor.extract_data,file_path=file_path)
    return result

if __name__ == "__main__":
    sys.stdout.reconfigure(line_buffering=True) 
    pdf_path = "data/ODP.pdf"
    # pret:Pret=  asyncio.run(do_test_odp(file_path=pdf_path))
    # if pret!=None:
    #     print(pret.emprunteurs)
    iban_pdf="data/rib pm.pdf"
    txt = asyncio.run(do_test_iban(file_path=iban_pdf))
    print(txt)
    

Project details


Release history Release notifications | RSS feed

This version

0.2.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pylexfluent-0.2.1.tar.gz (159.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pylexfluent-0.2.1-py3-none-any.whl (192.4 kB view details)

Uploaded Python 3

File details

Details for the file pylexfluent-0.2.1.tar.gz.

File metadata

  • Download URL: pylexfluent-0.2.1.tar.gz
  • Upload date:
  • Size: 159.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.12.3 Linux/6.8.0-124-generic

File hashes

Hashes for pylexfluent-0.2.1.tar.gz
Algorithm Hash digest
SHA256 ba02b88850b2b616dc5835a8d31f5fd3a8b3fc290425a89d8bc8158e78e3a71b
MD5 75aab8f383dc73c48e9d47b6b803f962
BLAKE2b-256 33d90ec3bed1fe7bbe7fd341031fcc8da50b1ca24508c3c31def00f94e4fc46c

See more details on using hashes here.

File details

Details for the file pylexfluent-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: pylexfluent-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 192.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.12.3 Linux/6.8.0-124-generic

File hashes

Hashes for pylexfluent-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9ca90165d58bfc14f4455c8f73910a494753e1fde1bac19708c6e1bdd13aced3
MD5 f514940bcd971d32d2ead82ee70b2258
BLAKE2b-256 fa79acb987a550a2146a8ed65067cfc82999630b074735690eb49df0308b88a4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page