pierreguillou commited on
Commit
a67b346
·
verified ·
1 Parent(s): d5b80db

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +4 -379
app.py CHANGED
@@ -11,8 +11,6 @@ import zipfile
11
  from pdf2image import convert_from_path
12
  import google.generativeai as genai
13
  import json
14
- from typing import Dict, Any, List, Union # Ajout des imports typing nécessaires
15
- import logging
16
 
17
  from docx import Document
18
  from docx.shared import Pt, RGBColor, Inches
@@ -20,6 +18,10 @@ from docx.enum.text import WD_ALIGN_PARAGRAPH
20
  from docx.enum.section import WD_SECTION
21
  from docx.oxml import OxmlElement
22
  from docx.oxml.ns import qn
 
 
 
 
23
 
24
  def authenticate(username, password):
25
  return username == os.getenv("HF_USERNAME") and password == os.getenv("HF_PASSWORD")
@@ -183,384 +185,7 @@ def extract_data_with_gemini(text_file_path: str, path_to_data_to_extract: str)
183
  except Exception as e:
184
  raise gr.Error(f"Error in Gemini processing: {str(e)}")
185
 
186
- class RapportGenerator:
187
- def __init__(self, json_file: str):
188
- self.doc = Document()
189
- self.logger = logging.getLogger(__name__)
190
- logging.basicConfig(level=logging.INFO)
191
- self.json_data = self.load_json(json_file)
192
- self._setup_document()
193
 
194
- def load_json(self, json_file: str) -> Dict:
195
- """Charge le fichier JSON"""
196
- try:
197
- with open(json_file, 'r', encoding='utf-8') as f:
198
- return json.load(f)
199
- except Exception as e:
200
- self.logger.error(f"Erreur lors de la lecture du JSON: {str(e)}")
201
- raise
202
-
203
- def _setup_document(self):
204
- """Configure le document"""
205
- sections = self.doc.sections
206
- for section in sections:
207
- section.bottom_margin = Inches(1)
208
- self._create_page_number()
209
-
210
- def _create_page_number(self):
211
- """Crée le numéro de page dans le pied de page"""
212
- section = self.doc.sections[0]
213
- footer = section.footer
214
- paragraph = footer.paragraphs[0]
215
- paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
216
-
217
- run = paragraph.add_run()
218
- self._create_element(run, 'PAGE')
219
- run = paragraph.add_run(" / ")
220
- run = paragraph.add_run()
221
- self._create_element(run, 'NUMPAGES')
222
-
223
- def _create_element(self, run, text):
224
- """Crée un élément de champ Word"""
225
- fldChar1 = OxmlElement('w:fldChar')
226
- fldChar1.set(qn('w:fldCharType'), 'begin')
227
- run._r.append(fldChar1)
228
-
229
- instrText = OxmlElement('w:instrText')
230
- instrText.text = text
231
- run._r.append(instrText)
232
-
233
- fldChar2 = OxmlElement('w:fldChar')
234
- fldChar2.set(qn('w:fldCharType'), 'end')
235
- run._r.append(fldChar2)
236
-
237
- def _add_title(self, text: str, level: int = 1):
238
- """Ajoute un titre avec style et taille appropriés"""
239
- heading = self.doc.add_heading(level=level)
240
- heading.alignment = WD_ALIGN_PARAGRAPH.LEFT
241
- run = heading.add_run(text.strip()) # Ajout de strip()
242
- font_sizes = {0: 18, 1: 16, 2: 14, 3: 12}
243
- run.font.size = Pt(font_sizes.get(level, 12))
244
-
245
- def _format_key(self, key: str) -> str:
246
- """Formate la clé en supprimant les suffixes _DEMANDEUR et _DEFENDEUR"""
247
- key = key.replace("_", " ").title()
248
- key = key.replace(" Demandeur", "")
249
- key = key.replace(" Defendeur", "")
250
- return key
251
-
252
- def _get_safe_value(self, data: Dict, key: str, default: str = '') -> str:
253
- """Récupère une valeur en toute sécurité du dictionnaire"""
254
- if isinstance(data, dict):
255
- return str(data.get(key, default))
256
- return default
257
-
258
- def _format_person_info(self, data: Dict, is_lawyer: bool = False) -> Dict[str, str]:
259
- """Formate les informations d'une personne"""
260
- info = {}
261
-
262
- if not isinstance(data, dict):
263
- return info
264
-
265
- if is_lawyer:
266
- # Informations de l'avocat
267
- civilite = self._get_safe_value(data, 'CIVILITE_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'CIVILITE_AVOCAT_DEFENDEUR')
268
- prenom = self._get_safe_value(data, 'PRENOM_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'PRENOM_AVOCAT_DEFENDEUR')
269
- nom = self._get_safe_value(data, 'NOM_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'NOM_AVOCAT_DEFENDEUR')
270
-
271
- info['Nom'] = f"{civilite} {prenom} {nom}".strip()
272
- info['Barreau'] = self._get_safe_value(data, 'BARREAU_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'BARREAU_AVOCAT_DEFENDEUR')
273
- info['Bureau d\'avocats'] = self._get_safe_value(data, 'BUREAU_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'BUREAU_AVOCAT_DEFENDEUR')
274
-
275
- adresse = data.get('ADRESSE_AVOCAT_DEMANDEUR', {}) if isinstance(data.get('ADRESSE_AVOCAT_DEMANDEUR'), dict) else {}
276
- if not adresse:
277
- adresse = data.get('ADRESSE_AVOCAT_DEFENDEUR', {}) if isinstance(data.get('ADRESSE_AVOCAT_DEFENDEUR'), dict) else {}
278
-
279
- info['Adresse Complete'] = self._get_safe_value(adresse, 'ADRESSE_COMPLETE_AVOCAT_DEMANDEUR') or self._get_safe_value(adresse, 'ADRESSE_COMPLETE_AVOCAT_DEFENDEUR')
280
- info['Email'] = self._get_safe_value(data, 'EMAIL_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'EMAIL_AVOCAT_DEFENDEUR')
281
- info['Telephone'] = self._get_safe_value(data, 'TELEPHONE_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'TELEPHONE_AVOCAT_DEFENDEUR')
282
- else:
283
- # Informations de la partie
284
- civilite = self._get_safe_value(data, 'CIVILITE_DEMANDEUR') or self._get_safe_value(data, 'CIVILITE_DEFENDEUR')
285
- prenom = self._get_safe_value(data, 'PRENOM_DEMANDEUR') or self._get_safe_value(data, 'PRENOM_DEFENDEUR')
286
- nom = self._get_safe_value(data, 'NOM_DEMANDEUR') or self._get_safe_value(data, 'NOM_DEFENDEUR')
287
-
288
- info['Nom'] = f"{civilite} {prenom} {nom}".strip()
289
- info['Organisme'] = self._get_safe_value(data, 'ORGANISME_DEMANDEUR') or self._get_safe_value(data, 'ORGANISME_DEFENDEUR')
290
-
291
- adresse = data.get('ADRESSE_DEMANDEUR', {}) if isinstance(data.get('ADRESSE_DEMANDEUR'), dict) else {}
292
- if not adresse:
293
- adresse = data.get('ADRESSE_DEFENDEUR', {}) if isinstance(data.get('ADRESSE_DEFENDEUR'), dict) else {}
294
-
295
- info['Adresse Complete'] = self._get_safe_value(adresse, 'ADRESSE_COMPLETE_DEMANDEUR') or self._get_safe_value(adresse, 'ADRESSE_COMPLETE_DEFENDEUR')
296
- info['Email'] = self._get_safe_value(data, 'EMAIL_DEMANDEUR') or self._get_safe_value(data, 'EMAIL_DEFENDEUR')
297
- info['Telephone'] = self._get_safe_value(data, 'TELEPHONE_DEMANDEUR') or self._get_safe_value(data, 'TELEPHONE_DEFENDEUR')
298
-
299
- return {k: v for k, v in info.items() if v and v != "Non spécifié"}
300
-
301
- def _process_special_fields(self, key: str, value: Any) -> bool:
302
- """Traite les champs spéciaux (HISTORIQUE et MISSION)"""
303
- if key in ["HISTORIQUE", "MISSION"]:
304
- self._add_title(key.upper().strip(), 1)
305
-
306
- # Vérifier si la valeur est une liste
307
- if isinstance(value, list):
308
- for item in value:
309
- p = self.doc.add_paragraph()
310
- p.add_run(str(item).strip())
311
- else:
312
- # Si c'est une chaîne simple ou autre type
313
- p = self.doc.add_paragraph()
314
- p.add_run(str(value).strip())
315
-
316
- # Ajouter un espace après HISTORIQUE seulement
317
- if key == "HISTORIQUE":
318
- self.doc.add_paragraph()
319
-
320
- return True
321
- return False
322
-
323
- def _process_parties(self, title: str, items: Union[str, List], level: int):
324
- """Traite les parties (demandeurs/défendeurs)"""
325
- self._add_title(title, level)
326
-
327
- # Si aucune partie n'est spécifiée
328
- if isinstance(items, str) and items == "Non spécifié":
329
- p = self.doc.add_paragraph(style='List Bullet')
330
- p.add_run("Non spécifié")
331
- return
332
-
333
- # Traitement de chaque partie
334
- if isinstance(items, list):
335
- for idx, item in enumerate(items, 1):
336
- if not isinstance(item, dict):
337
- continue
338
-
339
- # Sous-titre pour chaque partie
340
- partie_title = f"{title.rstrip('S')} {idx}"
341
- self._add_title(partie_title, level + 1)
342
-
343
- # Formatage du nom complet
344
- civilite = self._get_safe_value(item, f'CIVILITE_{title.rstrip("S")}', '')
345
- prenom = self._get_safe_value(item, f'PRENOM_{title.rstrip("S")}', '')
346
- nom = self._get_safe_value(item, f'NOM_{title.rstrip("S")}', '')
347
- nom_complet = f"{civilite} {prenom} {nom}".strip()
348
-
349
- # Ajout du nom
350
- if nom_complet and nom_complet != "Non spécifié":
351
- p = self.doc.add_paragraph(style='List Bullet')
352
- p.add_run("Nom: ").bold = True
353
- p.add_run(nom_complet)
354
-
355
- # Récupération de l'adresse
356
- adresse = item.get(f'ADRESSE_{title.rstrip("S")}', {})
357
- if isinstance(adresse, dict):
358
- adresse_complete = adresse.get(f'ADRESSE_COMPLETE_{title.rstrip("S")}', '')
359
- if adresse_complete and adresse_complete != "Non spécifié":
360
- p = self.doc.add_paragraph(style='List Bullet')
361
- p.add_run("Adresse Complete: ").bold = True
362
- p.add_run(adresse_complete)
363
-
364
- # Ajout du téléphone
365
- telephone = self._get_safe_value(item, f'TELEPHONE_{title.rstrip("S")}', '')
366
- if telephone and telephone != "Non spécifié":
367
- p = self.doc.add_paragraph(style='List Bullet')
368
- p.add_run("Téléphone: ").bold = True
369
- p.add_run(telephone)
370
-
371
- # Ajout de l'email
372
- email = self._get_safe_value(item, f'EMAIL_{title.rstrip("S")}', '')
373
- if email and email != "Non spécifié":
374
- p = self.doc.add_paragraph(style='List Bullet')
375
- p.add_run("Email: ").bold = True
376
- p.add_run(email)
377
-
378
- # Traitement des avocats
379
- avocat_key = f'AVOCAT_{title.rstrip("S")}'
380
- avocats = item.get(avocat_key, [])
381
-
382
- if isinstance(avocats, list) and avocats and avocats != "Non spécifié":
383
- for avocat_idx, avocat in enumerate(avocats, 1):
384
- if isinstance(avocat, dict):
385
- # Sous-titre pour chaque avocat
386
- self._add_title(f"Avocat {avocat_idx}", level + 2)
387
-
388
- # Nom de l'avocat
389
- civilite_avocat = self._get_safe_value(avocat, f'CIVILITE_AVOCAT_{title.rstrip("S")}', '')
390
- prenom_avocat = self._get_safe_value(avocat, f'PRENOM_AVOCAT_{title.rstrip("S")}', '')
391
- nom_avocat = self._get_safe_value(avocat, f'NOM_AVOCAT_{title.rstrip("S")}', '')
392
- nom_complet_avocat = f"{civilite_avocat} {prenom_avocat} {nom_avocat}".strip()
393
-
394
- if nom_complet_avocat and nom_complet_avocat != "Non spécifié":
395
- p = self.doc.add_paragraph(style='List Bullet')
396
- p.add_run("Nom: ").bold = True
397
- p.add_run(nom_complet_avocat)
398
-
399
- # Barreau
400
- barreau = self._get_safe_value(avocat, f'BARREAU_AVOCAT_{title.rstrip("S")}', '')
401
- if barreau and barreau != "Non spécifié":
402
- p = self.doc.add_paragraph(style='List Bullet')
403
- p.add_run("Barreau: ").bold = True
404
- p.add_run(barreau)
405
-
406
- # Bureau d'avocats
407
- bureau = self._get_safe_value(avocat, f'BUREAU_AVOCAT_{title.rstrip("S")}', '')
408
- if bureau and bureau != "Non spécifié":
409
- p = self.doc.add_paragraph(style='List Bullet')
410
- p.add_run("Bureau d'avocats: ").bold = True
411
- p.add_run(bureau)
412
-
413
- # Adresse de l'avocat
414
- adresse_avocat = avocat.get(f'ADRESSE_AVOCAT_{title.rstrip("S")}', {})
415
- if isinstance(adresse_avocat, dict):
416
- adresse_complete_avocat = adresse_avocat.get(f'ADRESSE_COMPLETE_AVOCAT_{title.rstrip("S")}', '')
417
- if adresse_complete_avocat and adresse_complete_avocat != "Non spécifié":
418
- p = self.doc.add_paragraph(style='List Bullet')
419
- p.add_run("Adresse Complete: ").bold = True
420
- p.add_run(adresse_complete_avocat)
421
-
422
- # Téléphone de l'avocat
423
- tel_avocat = self._get_safe_value(avocat, f'TELEPHONE_AVOCAT_{title.rstrip("S")}', '')
424
- if tel_avocat and tel_avocat != "Non spécifié":
425
- p = self.doc.add_paragraph(style='List Bullet')
426
- p.add_run("Téléphone: ").bold = True
427
- p.add_run(tel_avocat)
428
-
429
- # Email de l'avocat
430
- email_avocat = self._get_safe_value(avocat, f'EMAIL_AVOCAT_{title.rstrip("S")}', '')
431
- if email_avocat and email_avocat != "Non spécifié":
432
- p = self.doc.add_paragraph(style='List Bullet')
433
- p.add_run("Email: ").bold = True
434
- p.add_run(email_avocat)
435
-
436
- # Ajouter un espace entre chaque partie
437
- if idx < len(items):
438
- self.doc.add_paragraph()
439
-
440
- def _add_table_of_contents(self):
441
- """Ajoute une table des matières au document"""
442
- paragraph = self.doc.add_paragraph()
443
- run = paragraph.add_run("TABLE DES MATIÈRES")
444
- run.bold = True
445
- run.font.size = Pt(14)
446
-
447
- self.doc.add_paragraph()
448
- paragraph = self.doc.add_paragraph()
449
-
450
- # Ajouter le champ TOC
451
- run = paragraph.add_run()
452
- fldChar1 = OxmlElement('w:fldChar')
453
- fldChar1.set(qn('w:fldCharType'), 'begin')
454
- run._r.append(fldChar1)
455
-
456
- instrText = OxmlElement('w:instrText')
457
- instrText.set(qn('xml:space'), 'preserve')
458
- instrText.text = 'TOC \\o "1-3" \\h \\z \\u'
459
- run._r.append(instrText)
460
-
461
- fldChar2 = OxmlElement('w:fldChar')
462
- fldChar2.set(qn('w:fldCharType'), 'separate')
463
- run._r.append(fldChar2)
464
-
465
- # Ajouter un espace pour la mise à jour
466
- run = paragraph.add_run()
467
-
468
- fldChar4 = OxmlElement('w:fldChar')
469
- fldChar4.set(qn('w:fldCharType'), 'end')
470
- run._r.append(fldChar4)
471
-
472
- self.doc.add_page_break()
473
-
474
- def _format_person_info_simple(self, data: Dict, prefix: str) -> str:
475
- """Formate les informations d'une personne (magistrat ou greffier)"""
476
- prenom = data.get(f'PRENOM_{prefix}', '').strip()
477
- nom = data.get(f'NOM_{prefix}', '').strip()
478
- titre = data.get(f'TITRE_{prefix}', '').strip()
479
- return f"{prenom} {nom}, {titre}".strip()
480
-
481
- def _format_monetary_value(self, data: Dict, prefix: str) -> str:
482
- """Formate les valeurs monétaires"""
483
- valeur = str(data.get(f'VALEUR_{prefix}', 0)).strip()
484
- monnaie = data.get(f'MONNAIE_{prefix}', '€').strip()
485
- return f"{valeur} {monnaie}".strip()
486
-
487
- def generate_report(self):
488
- """Génère le rapport complet"""
489
- try:
490
- # Titre principal
491
- title = self.doc.add_heading("Données extraites d'une ordonnance de référé", 0)
492
- title.alignment = WD_ALIGN_PARAGRAPH.CENTER
493
-
494
- # Informations générales
495
- self._add_title("INFORMATIONS GÉNÉRALES", 1)
496
- if isinstance(self.json_data.get("INFORMATIONS_GENERALES"), dict):
497
- info_gen = self.json_data["INFORMATIONS_GENERALES"]
498
-
499
- # Liste des champs à traiter
500
- fields_to_process = [
501
- # Champs simples
502
- ("DATE_ORDONNANCE_REFERE", "Date Ordonnance Refere"),
503
- ("VILLE_TRIBUNAL", "Ville Tribunal"),
504
- ("NUMERO_RG", "Numero RG"),
505
-
506
- # Champs complexes avec formatage spécial
507
- ("MAGISTRAT_ORDONNANCE_REFERE", "Magistrat Ordonnance Refere",
508
- lambda x: self._format_person_info_simple(x, "MAGISTRAT_ORDONNANCE_REFERE")),
509
-
510
- ("GREFFIER_ORDONNANCE_REFERE", "Greffier Ordonnance Refere",
511
- lambda x: self._format_person_info_simple(x, "GREFFIER_ORDONNANCE_REFERE")),
512
-
513
- ("CONSIGNATION", "Consignation",
514
- lambda x: self._format_monetary_value(x, "CONSIGNATION")),
515
-
516
- ("SOMME_A_CONSIGER", "Somme A Consiger",
517
- lambda x: self._format_monetary_value(x, "SOMME_A_CONSIGER"))
518
- ]
519
-
520
- # Traitement de chaque champ
521
- for field in fields_to_process:
522
- key = field[0]
523
- display_name = field[1]
524
-
525
- if key in info_gen:
526
- p = self.doc.add_paragraph(style='List Bullet')
527
- p.add_run(f"{display_name}: ").bold = True
528
-
529
- # Si c'est un champ avec formatage spécial (longueur du tuple = 3)
530
- if len(field) == 3:
531
- formatter = field[2]
532
- value = formatter(info_gen[key])
533
- else:
534
- value = str(info_gen[key])
535
-
536
- p.add_run(value)
537
-
538
- # Traitement des demandeurs
539
- if "DEMANDEURS" in self.json_data:
540
- self._process_parties("DEMANDEURS", self.json_data["DEMANDEURS"], 1)
541
-
542
- # Traitement des défendeurs
543
- if "DEFENDEURS" in self.json_data:
544
- self._process_parties("DEFENDEURS", self.json_data["DEFENDEURS"], 1)
545
-
546
- # Historique
547
- if "HISTORIQUE" in self.json_data:
548
- self._process_special_fields("HISTORIQUE", self.json_data["HISTORIQUE"])
549
-
550
- # Mission
551
- if "MISSION" in self.json_data:
552
- self._process_special_fields("MISSION", self.json_data["MISSION"])
553
-
554
- # Sauvegarde du document
555
- output_file = "rapport_extraction.docx"
556
- self.doc.save(output_file)
557
- self.logger.info(f"Rapport généré avec succès: {output_file}")
558
-
559
- return output_file
560
-
561
- except Exception as e:
562
- self.logger.error(f"Erreur lors de la génération du rapport: {str(e)}")
563
- raise
564
 
565
  # Main Processing Function
566
  def process_pdf(pdf_file):
 
11
  from pdf2image import convert_from_path
12
  import google.generativeai as genai
13
  import json
 
 
14
 
15
  from docx import Document
16
  from docx.shared import Pt, RGBColor, Inches
 
18
  from docx.enum.section import WD_SECTION
19
  from docx.oxml import OxmlElement
20
  from docx.oxml.ns import qn
21
+ from typing import Dict, Any, List, Union # Ajout des imports typing nécessaires
22
+ import logging
23
+
24
+ from helpers.utils import report-generator
25
 
26
  def authenticate(username, password):
27
  return username == os.getenv("HF_USERNAME") and password == os.getenv("HF_PASSWORD")
 
185
  except Exception as e:
186
  raise gr.Error(f"Error in Gemini processing: {str(e)}")
187
 
 
 
 
 
 
 
 
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  # Main Processing Function
191
  def process_pdf(pdf_file):