pylexfluent 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/PKG-INFO +221 -6
  2. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/README.md +210 -1
  3. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/pyproject.toml +5 -3
  4. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/agents/interviewer.py +4 -2
  5. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/classification/classifier.py +1 -1
  6. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/classification/multiclass/jupiter_model.py +1 -1
  7. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/classification/tc_finance/accountings.py +1 -1
  8. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/cni_utilities/detection/cni_detection.py +1 -1
  9. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/cni_utilities/detection/rois.py +1 -1
  10. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/cni_utilities/recognize_zones.py +1 -1
  11. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/default_ocr.py +1 -31
  12. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/ocr_pdf.py +1 -1
  13. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/pdf_utilities.py +1 -1
  14. pylexfluent-0.2.2/src/lxf/ai/ocr/super_ocr.py +74 -0
  15. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/text_extractor.py +1 -1
  16. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/text_analysis/default_text_analysis.py +6 -4
  17. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/title_analysis/extract_titles_with_format.py +1 -1
  18. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/title_analysis/prepare_title_dataset.py +1 -1
  19. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/converters/converter.py +1 -1
  20. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/TrainingData.py +1 -1
  21. pylexfluent-0.2.2/src/lxf/domain/inspector_request.py +81 -0
  22. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/keyswordsandphrases.py +1 -1
  23. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/loan.py +12 -0
  24. pylexfluent-0.2.2/src/lxf/domain/pim.py +165 -0
  25. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/administratif/cni_extractor.py +1 -1
  26. pylexfluent-0.2.2/src/lxf/extractors/agent/agent_extractor.py +49 -0
  27. pylexfluent-0.2.2/src/lxf/extractors/agent/inspector.py +478 -0
  28. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/default/default_extractor.py +1 -1
  29. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/finance/iban_extractor.py +1 -1
  30. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/finance/ibans/iban_analyzer.py +1 -1
  31. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/finance/loans/loan_extracted_data.py +1 -1
  32. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/finance/loans/loan_extractor.py +2 -2
  33. pylexfluent-0.2.2/src/lxf/extractors/finance/loans/loan_proposal_extractor.py +603 -0
  34. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/finance/odp_extractor.py +1 -1
  35. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/finance/odp_proposal_extractor.py +22 -10
  36. {pylexfluent-0.2.0/src/lxf/extractors/administratif → pylexfluent-0.2.2/src/lxf/extractors/metier/immobilier}/urbanisme/cu_extractor.py +1 -1
  37. pylexfluent-0.2.2/src/lxf/extractors/metier/immobilier/urbanisme/permis_attestation_depot_transfert.py +219 -0
  38. pylexfluent-0.2.2/src/lxf/extractors/metier/immobilier/urbanisme/permis_attestations_extractor.py +294 -0
  39. pylexfluent-0.2.2/src/lxf/extractors/metier/immobilier/urbanisme/permis_constat_huissier_affichage.py +232 -0
  40. pylexfluent-0.2.2/src/lxf/extractors/metier/immobilier/urbanisme/urbanisme_extractors.py +151 -0
  41. pylexfluent-0.2.2/src/lxf/extractors/metier/notariat/notariat_extractor.py +62 -0
  42. pylexfluent-0.2.2/src/lxf/extractors/metier/notariat/vente/attestation_acte_vente.py +326 -0
  43. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/repositories/training_repository.py +1 -1
  44. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/services/keys_words.py +1 -1
  45. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/services/measure_time.py +1 -1
  46. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/services/pdf.py +1 -1
  47. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/services/try_safe.py +9 -1
  48. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/settings/__init__.py +0 -3
  49. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/utilities/tables_helper.py +1 -1
  50. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/utilities/text_comparator.py +1 -1
  51. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/utilities/text_utils.py +1 -1
  52. pylexfluent-0.2.0/src/lxf/extractors/finance/__pycache__/iban_extractor.cpython-312.pyc +0 -0
  53. pylexfluent-0.2.0/src/lxf/extractors/finance/__pycache__/odp_extractor.cpython-312.pyc +0 -0
  54. pylexfluent-0.2.0/src/lxf/extractors/finance/ibans/__pycache__/iban_analyzer.cpython-312.pyc +0 -0
  55. pylexfluent-0.2.0/src/lxf/extractors/finance/loans/__pycache__/loan_extractor.cpython-312.pyc +0 -0
  56. pylexfluent-0.2.0/src/lxf/extractors/finance/loans/loan_proposal_extractor.py +0 -900
  57. pylexfluent-0.2.0/src/lxf/extractors/metier/notariat/__init__.py +0 -1
  58. pylexfluent-0.2.0/src/lxf/settings/__pycache__/__init__.cpython-312.pyc +0 -0
  59. pylexfluent-0.2.0/src/lxf/utilities/__pycache__/text_comparator.cpython-312.pyc +0 -0
  60. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/LICENSE +0 -0
  61. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/__init__.py +0 -0
  62. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/agents/guard_rail.py +0 -0
  63. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/classification/multiclass/common.py +0 -0
  64. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/classification/multiclass/prediction.py +0 -0
  65. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/cni_ocr.py +0 -0
  66. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/ocr/iban_ocr.py +0 -0
  67. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/ai/title_analysis/correct_jsonl_prodigy.py +0 -0
  68. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/cni.py +0 -0
  69. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/cni_zones.py +0 -0
  70. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/entity.py +0 -0
  71. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/extracted_data.py +0 -0
  72. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/extractor_log.py +0 -0
  73. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/iban.py +0 -0
  74. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/inference_result.py +0 -0
  75. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/keyWord.py +0 -0
  76. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/keyphrase.py +0 -0
  77. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/loan_proposal.py +0 -0
  78. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/medicaments.py +0 -0
  79. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/predictions.py +0 -0
  80. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/repertoire.py +0 -0
  81. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/domain/tables.py +0 -0
  82. {pylexfluent-0.2.0 → pylexfluent-0.2.2}/src/lxf/extractors/metier/notariat/repertoire/repertoire_extractor.py +0 -0
@@ -1,15 +1,18 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pylexfluent
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Librairie outils IA Lexia par Lexfluent
5
- Home-page: https://dev.azure.com/LexFluent2020/RevolutionAI
5
+ License-File: LICENSE
6
6
  Author: Jacques MASSA
7
7
  Author-email: jacques.massa@lexfluent.com
8
- Requires-Python: >=3.12,<4.0
8
+ Requires-Python: >=3.11,<4.0
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
12
13
  Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
13
16
  Requires-Dist: docling[all]
14
17
  Requires-Dist: easyocr
15
18
  Requires-Dist: img2pdf (==0.6.0)
@@ -23,6 +26,8 @@ Requires-Dist: mediapipe
23
26
  Requires-Dist: ocrmypdf
24
27
  Requires-Dist: opencv-python
25
28
  Requires-Dist: openpyxl
29
+ Requires-Dist: paddleocr[doc-parser] (>=3.7.0,<4.0.0)
30
+ Requires-Dist: paddlepaddle (==3.2.2)
26
31
  Requires-Dist: pandas
27
32
  Requires-Dist: pdf2image
28
33
  Requires-Dist: pdfplumber
@@ -35,7 +40,7 @@ Requires-Dist: scikit-learn
35
40
  Requires-Dist: sentence-transformers
36
41
  Requires-Dist: sentencepiece
37
42
  Requires-Dist: setuptools (<81)
38
- Requires-Dist: spacy[cuda12x]
43
+ Requires-Dist: spacy[cuda12x] (>=3.7.2)
39
44
  Requires-Dist: tensorflow
40
45
  Requires-Dist: tensorflow-hub
41
46
  Requires-Dist: tensorrt
@@ -48,6 +53,7 @@ Requires-Dist: torchvision
48
53
  Requires-Dist: tqdm
49
54
  Requires-Dist: transformers
50
55
  Requires-Dist: wheel
56
+ Project-URL: Homepage, https://dev.azure.com/LexFluent2020/RevolutionAI
51
57
  Project-URL: Issues, https://dev.azure.com/LexFluent2020/RevolutionAI/_queries/query/180a1ed2-3494-42cc-8d8a-2e60217c2171/
52
58
  Description-Content-Type: text/markdown
53
59
 
@@ -60,6 +66,7 @@ Description-Content-Type: text/markdown
60
66
  |Modification | *jacques MASSA* | 06 février 2026|
61
67
  |Modification | *jacques MASSA* | 05 mars 2026|
62
68
  |Modification | *jacques MASSA* | 21 mai 2026|
69
+ |Modification | *jacques MASSA* | 22 juin 2026 |
63
70
  ---
64
71
 
65
72
  ## Présentation
@@ -74,9 +81,216 @@ La librairie pyLexfluent propose toutes les fonctionnalités IA dans les domaine
74
81
  Built with Transformers
75
82
  Built with gtp-oss20B
76
83
  Built with Llama
84
+ Built with PaddleOcr
85
+
86
+
77
87
 
78
88
 
79
89
  ## Nouveautés
90
+ #### 0.2.1 :
91
+ Ajout de l'agent extracteur , InspectorRequest et InpectorResult : Nouveau pattern de l'agent IA
92
+ Ajout de la librairie PaddleOCR pour l'extraction de formulaires et tableaux depuis doccuments numérisés
93
+ Requiert un serveur d'inférence Paddle .
94
+ Requiert l'exécution de la commande :
95
+ Plus d'information:
96
+ [ Documentation PadleOCR ]( https://www.paddleocr.ai/latest/en/version3.x/pipeline_usage/PaddleOCR-VL.html )
97
+
98
+ ##### Nouveaux extracteurs
99
+ - Gestion des programmes immobiliers :
100
+ + Urbanisme : Attestation non retrait et/ou non recours, Dépôt/Transfert permis
101
+ + Juridique :
102
+ - Constats d'affichage par un huissier,
103
+ - Attestation acte de vente,
104
+ - Finance :
105
+ + Courrier proposition acte de prêts
106
+ ##### Exemple de code
107
+ ###### Document à analyser
108
+ Demande attestation non retrait/non recours permis de construire ou d'aménager :
109
+
110
+
111
+ ## FORMULAIRE DE DEMANDE D'ATTESTATION DE RECOURS/NON RECOURS
112
+
113
+ ### Demandeur de l'attestation
114
+ Civilité :
115
+ nMadame: ___
116
+ Monsieur : ☐
117
+ Maître : □
118
+ Société:☒
119
+ NOM /Prénom : AAA AAAAAAAAAA
120
+ dresse : 1 avenue de l'Europe 99999 AAAAAAX
121
+ Téléphone :
122
+ $ underline{text{99 99 99 99 99}} $
123
+ Courriel :
124
+ $ underline{text{pxxxxxx.xxxxxx@xxxxxx-xxxxxxxxxx.fr}} $
125
+ # ATTESTATION DE RECOURS/NON RECOURS
126
+ # Délivrée en application de l'article R. 600-7 du code de l'urbanisme
127
+
128
+ Le greffier en chef du tribunal administratif de Besançon atteste que la décision désignée ci-après :
129
+ 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
130
+ N° de la délibération :
131
+ Auteur de la décision (maire, préfet) : mairie des AAAAAA
132
+ Date de la décision :
133
+ $ underline{text{6 janvier}} $
134
+ Bénéficiaire de l'autorisation : AAA AAAAAAAAAA
135
+ construction d'un immeuble collectif de 8 logements avec parking en sous sol route de AAAAAAAA
136
+ 99999 LES RAAAAAA
137
+
138
+ Nature et lieu de l'opération :
139
+ (éléments ci-dessus à compléter par le demandeur)
140
+
141
+ ☒ n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.
142
+
143
+ □ a fait l'objet d'un recours contentieux enregistré au tribunal administratif de Besançon en date du ___
144
+
145
+ 00/04/2025
146
+ À Besançon, le
147
+ Le greffier en chef
148
+ <div style=\"text-align: center;\"><img src=\"imgs/img_in_image_box_856_1432_934_1504.jpg\" alt=\"Image\" width=\"6%\" />
149
+
150
+ TRADITATIF DE SANSON
151
+ </div>
152
+ 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.
153
+
154
+ #### Résultat
155
+ ```
156
+ import argparse
157
+ import json
158
+ import time
159
+ import logging
160
+ import asyncio
161
+ from pathlib import Path
162
+ import sys
163
+ import os
164
+
165
+ from threading import Thread
166
+
167
+ from lxf.extractors.metier.immobilier.urbanisme.urbanisme_extractors import urbanisme_extract_attestations_recours_retrait_permis
168
+
169
+
170
+
171
+ # System call
172
+ os.system("")
173
+
174
+ # Class of different styles
175
+ class print_color():
176
+ BLACK = '\033[30m'
177
+ RED = '\033[31m'
178
+ GREEN = '\033[32m'
179
+ YELLOW = '\033[33m'
180
+ BLUE = '\033[34m'
181
+ MAGENTA = '\033[35m'
182
+ CYAN = '\033[36m'
183
+ WHITE = '\033[37m'
184
+ UNDERLINE = '\033[4m'
185
+ RESET = '\033[0m'
186
+ from lxf.domain.inspector_request import InspectorRequest, InspectorResult
187
+ import lxf.settings as settings
188
+ settings.set_logging_level(logging.INFO)
189
+ settings.enable_tqdm=False
190
+ ###################################################################
191
+
192
+ logger = logging.getLogger('test_pim')
193
+ fh = logging.FileHandler('./logs/pylexfluent.log')
194
+ fh.setLevel(settings.get_logging_level())
195
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
196
+ fh.setFormatter(formatter)
197
+ logger.setLevel(settings.get_logging_level())
198
+ logger.addHandler(fh)
199
+ #################################################################
200
+
201
+
202
+ async def do_test_pim(file_path:str) :
203
+ result = await urbanisme_extract_attestations_recours_retrait_permis(file_path,
204
+ base_url="http://XXXX:8000/v1",
205
+ paddle_server="https://ocr.lexfluent.com/v1")
206
+ if result !=None:
207
+ print(print_color.BLUE+f"Resultat:\n{result.model_dump_json(indent=4)}")
208
+ else :
209
+ print("Aucune donnée n'a pu etre extraite !")
210
+
211
+ if __name__ == "__main__":
212
+ sys.stdout.reconfigure(line_buffering=True)
213
+ parser = argparse.ArgumentParser(description="Exemple d'usage")
214
+ 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'")
215
+ parser.add_argument("--dossier","-D",nargs=1,required=False,type=str,help="Dossier contenant des Fichiers à traiter, exemple: --dossier data/PIM/Attestation/non_retrait")
216
+ args = parser.parse_args()
217
+ files:list[str]=[]
218
+ if args.file !=None:
219
+ filename:str=args.file[0]
220
+ if os.path.exists(filename) is False:
221
+ print(print_color.RED+f"Fichier {filename} introuvable !")
222
+ print(print_color.BLACK+"")
223
+ exit(-2)
224
+ files.append(filename)
225
+ elif args.dossier !=None :
226
+ folder:str=args.dossier[0]
227
+ if os.path.exists(folder) is False:
228
+ print(print_color.RED+f"Dossier {folder} introuvable !")
229
+ print(print_color.BLACK+"")
230
+ exit(-2)
231
+ for file in Path(folder).rglob("*.pdf"):
232
+ files.append(f"{file}")
233
+
234
+ else :
235
+ print(print_color.RED+"Aucun fichier ou dossier défini")
236
+ print(print_color.BLACK+"")
237
+ exit(-1)
238
+ threads:list[Thread]=[]
239
+ for file in files :
240
+ print(print_color.CYAN+f"Traitement du fichier : {file}")
241
+ filename=file
242
+ thread = Thread(target=asyncio.run,args=[do_test_pim(file)])
243
+ thread.start()
244
+ threads.append(thread)
245
+ # attendre avant le prochain traitement
246
+ time.sleep(2)
247
+ for t in threads :
248
+ try:
249
+ t.join()
250
+ print("thread terminé")
251
+ except RuntimeError as err:
252
+ print(print_color.RED+f"Erreur pendant l'attente du thread : {err}")
253
+
254
+ ```
255
+ Sortie :
256
+
257
+
258
+ ```
259
+ {
260
+ "document": "ATT NT TA_26127988.pdf",
261
+ "source": [
262
+ " ## 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."
263
+ ],
264
+ "logs": [],
265
+ "content": {
266
+ "source": [
267
+ "PC 999 999 99 J0019",
268
+ "n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.",
269
+ "Date de la décision : 6 janvier",
270
+ "Le greffier en chef du tribunal administratif de Besançon",
271
+ "Auteur de la décision (maire, préfet) : mairie des AAAAAAA"
272
+ ],
273
+ "permis": [
274
+ {
275
+ "decision": "NON RECOURS",
276
+ "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.",
277
+ "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.",
278
+ "le_maire": "",
279
+ "la_ville": "AAAAAAA",
280
+ "tribunal": "Tribunal administratif de Besançon",
281
+ "le_greffier": "greffier en chef du tribunal administratif de Besançon",
282
+ "date_decision": "6 janvier",
283
+ "permis_trouve": true,
284
+ "numero_brut": "PC 999 999 99 J0019",
285
+ "numero_normalise": "PC99999999J0019",
286
+ "date_obtention": null
287
+ }
288
+ ]
289
+ }
290
+ }
291
+
292
+ ```
293
+
80
294
  #### 0.1.97 :
81
295
  Ajout de l'extraction des données des offres de prêts du Crédit Agricole
82
296
  #### 0.1.96 :
@@ -231,7 +445,8 @@ Dependencies include libtoolize and libleptonica, which on Ubuntu systems are pa
231
445
  ## Téléchargement modèles
232
446
  ### SPACY
233
447
 
234
- ``` python -m spacy download fr_core_news_lg ```
448
+ ```
449
+ ```
235
450
 
236
451
 
237
452
 
@@ -7,6 +7,7 @@
7
7
  |Modification | *jacques MASSA* | 06 février 2026|
8
8
  |Modification | *jacques MASSA* | 05 mars 2026|
9
9
  |Modification | *jacques MASSA* | 21 mai 2026|
10
+ |Modification | *jacques MASSA* | 22 juin 2026 |
10
11
  ---
11
12
 
12
13
  ## Présentation
@@ -21,9 +22,216 @@ La librairie pyLexfluent propose toutes les fonctionnalités IA dans les domaine
21
22
  Built with Transformers
22
23
  Built with gtp-oss20B
23
24
  Built with Llama
25
+ Built with PaddleOcr
26
+
27
+
24
28
 
25
29
 
26
30
  ## Nouveautés
31
+ #### 0.2.1 :
32
+ Ajout de l'agent extracteur , InspectorRequest et InpectorResult : Nouveau pattern de l'agent IA
33
+ Ajout de la librairie PaddleOCR pour l'extraction de formulaires et tableaux depuis doccuments numérisés
34
+ Requiert un serveur d'inférence Paddle .
35
+ Requiert l'exécution de la commande :
36
+ Plus d'information:
37
+ [ Documentation PadleOCR ]( https://www.paddleocr.ai/latest/en/version3.x/pipeline_usage/PaddleOCR-VL.html )
38
+
39
+ ##### Nouveaux extracteurs
40
+ - Gestion des programmes immobiliers :
41
+ + Urbanisme : Attestation non retrait et/ou non recours, Dépôt/Transfert permis
42
+ + Juridique :
43
+ - Constats d'affichage par un huissier,
44
+ - Attestation acte de vente,
45
+ - Finance :
46
+ + Courrier proposition acte de prêts
47
+ ##### Exemple de code
48
+ ###### Document à analyser
49
+ Demande attestation non retrait/non recours permis de construire ou d'aménager :
50
+
51
+
52
+ ## FORMULAIRE DE DEMANDE D'ATTESTATION DE RECOURS/NON RECOURS
53
+
54
+ ### Demandeur de l'attestation
55
+ Civilité :
56
+ nMadame: ___
57
+ Monsieur : ☐
58
+ Maître : □
59
+ Société:☒
60
+ NOM /Prénom : AAA AAAAAAAAAA
61
+ dresse : 1 avenue de l'Europe 99999 AAAAAAX
62
+ Téléphone :
63
+ $ underline{text{99 99 99 99 99}} $
64
+ Courriel :
65
+ $ underline{text{pxxxxxx.xxxxxx@xxxxxx-xxxxxxxxxx.fr}} $
66
+ # ATTESTATION DE RECOURS/NON RECOURS
67
+ # Délivrée en application de l'article R. 600-7 du code de l'urbanisme
68
+
69
+ Le greffier en chef du tribunal administratif de Besançon atteste que la décision désignée ci-après :
70
+ 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
71
+ N° de la délibération :
72
+ Auteur de la décision (maire, préfet) : mairie des AAAAAA
73
+ Date de la décision :
74
+ $ underline{text{6 janvier}} $
75
+ Bénéficiaire de l'autorisation : AAA AAAAAAAAAA
76
+ construction d'un immeuble collectif de 8 logements avec parking en sous sol route de AAAAAAAA
77
+ 99999 LES RAAAAAA
78
+
79
+ Nature et lieu de l'opération :
80
+ (éléments ci-dessus à compléter par le demandeur)
81
+
82
+ ☒ n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.
83
+
84
+ □ a fait l'objet d'un recours contentieux enregistré au tribunal administratif de Besançon en date du ___
85
+
86
+ 00/04/2025
87
+ À Besançon, le
88
+ Le greffier en chef
89
+ <div style=\"text-align: center;\"><img src=\"imgs/img_in_image_box_856_1432_934_1504.jpg\" alt=\"Image\" width=\"6%\" />
90
+
91
+ TRADITATIF DE SANSON
92
+ </div>
93
+ 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.
94
+
95
+ #### Résultat
96
+ ```
97
+ import argparse
98
+ import json
99
+ import time
100
+ import logging
101
+ import asyncio
102
+ from pathlib import Path
103
+ import sys
104
+ import os
105
+
106
+ from threading import Thread
107
+
108
+ from lxf.extractors.metier.immobilier.urbanisme.urbanisme_extractors import urbanisme_extract_attestations_recours_retrait_permis
109
+
110
+
111
+
112
+ # System call
113
+ os.system("")
114
+
115
+ # Class of different styles
116
+ class print_color():
117
+ BLACK = '\033[30m'
118
+ RED = '\033[31m'
119
+ GREEN = '\033[32m'
120
+ YELLOW = '\033[33m'
121
+ BLUE = '\033[34m'
122
+ MAGENTA = '\033[35m'
123
+ CYAN = '\033[36m'
124
+ WHITE = '\033[37m'
125
+ UNDERLINE = '\033[4m'
126
+ RESET = '\033[0m'
127
+ from lxf.domain.inspector_request import InspectorRequest, InspectorResult
128
+ import lxf.settings as settings
129
+ settings.set_logging_level(logging.INFO)
130
+ settings.enable_tqdm=False
131
+ ###################################################################
132
+
133
+ logger = logging.getLogger('test_pim')
134
+ fh = logging.FileHandler('./logs/pylexfluent.log')
135
+ fh.setLevel(settings.get_logging_level())
136
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
137
+ fh.setFormatter(formatter)
138
+ logger.setLevel(settings.get_logging_level())
139
+ logger.addHandler(fh)
140
+ #################################################################
141
+
142
+
143
+ async def do_test_pim(file_path:str) :
144
+ result = await urbanisme_extract_attestations_recours_retrait_permis(file_path,
145
+ base_url="http://XXXX:8000/v1",
146
+ paddle_server="https://ocr.lexfluent.com/v1")
147
+ if result !=None:
148
+ print(print_color.BLUE+f"Resultat:\n{result.model_dump_json(indent=4)}")
149
+ else :
150
+ print("Aucune donnée n'a pu etre extraite !")
151
+
152
+ if __name__ == "__main__":
153
+ sys.stdout.reconfigure(line_buffering=True)
154
+ parser = argparse.ArgumentParser(description="Exemple d'usage")
155
+ 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'")
156
+ parser.add_argument("--dossier","-D",nargs=1,required=False,type=str,help="Dossier contenant des Fichiers à traiter, exemple: --dossier data/PIM/Attestation/non_retrait")
157
+ args = parser.parse_args()
158
+ files:list[str]=[]
159
+ if args.file !=None:
160
+ filename:str=args.file[0]
161
+ if os.path.exists(filename) is False:
162
+ print(print_color.RED+f"Fichier {filename} introuvable !")
163
+ print(print_color.BLACK+"")
164
+ exit(-2)
165
+ files.append(filename)
166
+ elif args.dossier !=None :
167
+ folder:str=args.dossier[0]
168
+ if os.path.exists(folder) is False:
169
+ print(print_color.RED+f"Dossier {folder} introuvable !")
170
+ print(print_color.BLACK+"")
171
+ exit(-2)
172
+ for file in Path(folder).rglob("*.pdf"):
173
+ files.append(f"{file}")
174
+
175
+ else :
176
+ print(print_color.RED+"Aucun fichier ou dossier défini")
177
+ print(print_color.BLACK+"")
178
+ exit(-1)
179
+ threads:list[Thread]=[]
180
+ for file in files :
181
+ print(print_color.CYAN+f"Traitement du fichier : {file}")
182
+ filename=file
183
+ thread = Thread(target=asyncio.run,args=[do_test_pim(file)])
184
+ thread.start()
185
+ threads.append(thread)
186
+ # attendre avant le prochain traitement
187
+ time.sleep(2)
188
+ for t in threads :
189
+ try:
190
+ t.join()
191
+ print("thread terminé")
192
+ except RuntimeError as err:
193
+ print(print_color.RED+f"Erreur pendant l'attente du thread : {err}")
194
+
195
+ ```
196
+ Sortie :
197
+
198
+
199
+ ```
200
+ {
201
+ "document": "ATT NT TA_26127988.pdf",
202
+ "source": [
203
+ " ## 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."
204
+ ],
205
+ "logs": [],
206
+ "content": {
207
+ "source": [
208
+ "PC 999 999 99 J0019",
209
+ "n'a pas fait l'objet, à ce jour et sous toutes réserves, d'un recours contentieux enregistré au tribunal administratif de Besançon.",
210
+ "Date de la décision : 6 janvier",
211
+ "Le greffier en chef du tribunal administratif de Besançon",
212
+ "Auteur de la décision (maire, préfet) : mairie des AAAAAAA"
213
+ ],
214
+ "permis": [
215
+ {
216
+ "decision": "NON RECOURS",
217
+ "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.",
218
+ "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.",
219
+ "le_maire": "",
220
+ "la_ville": "AAAAAAA",
221
+ "tribunal": "Tribunal administratif de Besançon",
222
+ "le_greffier": "greffier en chef du tribunal administratif de Besançon",
223
+ "date_decision": "6 janvier",
224
+ "permis_trouve": true,
225
+ "numero_brut": "PC 999 999 99 J0019",
226
+ "numero_normalise": "PC99999999J0019",
227
+ "date_obtention": null
228
+ }
229
+ ]
230
+ }
231
+ }
232
+
233
+ ```
234
+
27
235
  #### 0.1.97 :
28
236
  Ajout de l'extraction des données des offres de prêts du Crédit Agricole
29
237
  #### 0.1.96 :
@@ -178,7 +386,8 @@ Dependencies include libtoolize and libleptonica, which on Ubuntu systems are pa
178
386
  ## Téléchargement modèles
179
387
  ### SPACY
180
388
 
181
- ``` python -m spacy download fr_core_news_lg ```
389
+ ```
390
+ ```
182
391
 
183
392
 
184
393
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pylexfluent"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "Librairie outils IA Lexia par Lexfluent"
5
5
  authors = ["Jacques MASSA <jacques.massa@lexfluent.com>"]
6
6
  readme = "README.md"
@@ -33,7 +33,7 @@ homepage = "https://dev.azure.com/LexFluent2020/RevolutionAI"
33
33
  "Issues" = "https://dev.azure.com/LexFluent2020/RevolutionAI/_queries/query/180a1ed2-3494-42cc-8d8a-2e60217c2171/"
34
34
 
35
35
  [tool.poetry.dependencies]
36
- python = ">=3.12,<4.0"
36
+ python = ">=3.11,<4.0"
37
37
  setuptools = "<81"
38
38
  pytz = "*"
39
39
  wheel = "*"
@@ -59,7 +59,7 @@ torchaudio = "*"
59
59
  sentencepiece = "*"
60
60
  transformers = "*"
61
61
  sentence-transformers = "*"
62
- spacy = {extras = ["cuda12x"], version = "*"}
62
+ spacy = {extras = ["cuda12x"], version = ">=3.7.2"}
63
63
  ocrmypdf = "*"
64
64
  pdf2image = "*"
65
65
  img2pdf = "0.6.0"
@@ -72,6 +72,8 @@ openpyxl = "*"
72
72
  easyocr = "*"
73
73
  docling = {extras = ["all"], version = "*"}
74
74
  pymupdf= "*"
75
+ paddlepaddle = "3.2.2"
76
+ paddleocr = {extras = ["doc-parser"], version = "^3.7.0"}
75
77
 
76
78
  [build-system]
77
79
  requires = ["poetry-core"]
@@ -15,7 +15,7 @@ fh.setFormatter(formatter)
15
15
  logger.setLevel(SETLEVEL)
16
16
  logger.addHandler(fh)
17
17
 
18
- AI_TIMEOUT=180
18
+ AI_TIMEOUT=600
19
19
  AI_RETRIES=1
20
20
 
21
21
 
@@ -102,4 +102,6 @@ class Interviewer():
102
102
  logger.error(f"{libelle}: Aucune tentative n'a reussie.")
103
103
  return -10, "La requete a mis trop de temps. Aucune tentative n'a reussie."
104
104
  except Exception as ex:
105
- logger.critical(f"Connexion impossible à l'agent IA. Raison :{ex}")
105
+ error_message = f"Connexion impossible à l'agent IA. Raison :{ex}"
106
+ logger.critical(error_message)
107
+ return -20, error_message
@@ -7,7 +7,7 @@ from lxf.settings import get_logging_level
7
7
  ###################################################################
8
8
 
9
9
  logger = logging.getLogger('test classifier')
10
- fh = logging.FileHandler('./logs/test_classifier.log')
10
+ fh = logging.FileHandler('./logs/pylexfluent.log')
11
11
  fh.setLevel(get_logging_level())
12
12
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
13
13
  fh.setFormatter(formatter)
@@ -37,7 +37,7 @@ from lxf.services.measure_time import measure_time
37
37
 
38
38
  SETLEVEL = logging.ERROR
39
39
  logger = logging.getLogger('MulticlassClassificationJupiterModel')
40
- fh = logging.FileHandler('./logs/MulticlassClassificationJupiterModel.log')
40
+ fh = logging.FileHandler('./logs/pylexfluent.log')
41
41
  fh.setLevel(SETLEVEL)
42
42
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
43
43
  fh.setFormatter(formatter)
@@ -36,7 +36,7 @@ quarter_num = { 1: 'Trimestre 1',
36
36
 
37
37
  from lxf.settings import get_logging_level
38
38
  logger = logging.getLogger('ClassificationTCFinanceAccountigs')
39
- fh = logging.FileHandler('./logs/ClassificationTCFinanceAccountigs.log')
39
+ fh = logging.FileHandler('./logs/pylexfluent.log')
40
40
  fh.setLevel(get_logging_level())
41
41
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
42
42
  fh.setFormatter(formatter)
@@ -5,7 +5,7 @@ from typing import List, Tuple
5
5
  from lxf.settings import get_logging_level
6
6
 
7
7
  logger = logging.getLogger('cni detection')
8
- fh = logging.FileHandler('./logs/cni_detection.log')
8
+ fh = logging.FileHandler('./logs/pylexfluent.log')
9
9
  fh.setLevel(get_logging_level())
10
10
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
11
11
  fh.setFormatter(formatter)
@@ -5,7 +5,7 @@ import mediapipe as mp
5
5
 
6
6
  #logger
7
7
  logger = logging.getLogger('rois cni')
8
- fh = logging.FileHandler('./logs/cni_rois.log')
8
+ fh = logging.FileHandler('./logs/pylexfluent.log')
9
9
  fh.setLevel(get_logging_level())
10
10
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
11
11
  fh.setFormatter(formatter)
@@ -7,7 +7,7 @@ import re
7
7
  from lxf.settings import get_logging_level
8
8
 
9
9
  logger = logging.getLogger('cni recognize')
10
- fh = logging.FileHandler('./logs/cni_recognize.log')
10
+ fh = logging.FileHandler('./logs/pylexfluent.log')
11
11
  fh.setLevel(get_logging_level())
12
12
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
13
13
  fh.setFormatter(formatter)