mannnon commited on
Commit
3093069
·
verified ·
1 Parent(s): a98431a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -63
app.py CHANGED
@@ -320,54 +320,28 @@ def find_float_after_label(text: str, label: str, max_numbers: int = 2, window:
320
 
321
 
322
  def extract_name_from_filename(filename: str):
323
- """
324
- Ex:
325
- 19850515_ERIC_TEVANE_124522_Analyse de la marche FDM-T_Report (1).pdf
326
- -> ERIC TEVANE
327
- """
328
  if not filename:
329
  return None
330
 
331
  base = filename.rsplit("/", 1)[-1]
332
  base = base.rsplit(".", 1)[0]
333
 
334
- parts = base.split("_")
335
- name_parts = []
336
-
337
- # on saute le premier token s'il est purement numérique (date)
338
- started = False
339
- for p in parts:
340
- p_clean = p.strip()
341
- if not p_clean:
342
- continue
343
-
344
- if not started:
345
- if p_clean.isdigit():
346
- continue
347
- if re.fullmatch(r"[A-ZÀ-Ÿ\-]+", p_clean):
348
- started = True
349
- name_parts.append(p_clean)
350
- continue
351
-
352
- # quand on a commencé à lire le nom, on continue tant que c'est alpha MAJ
353
- if re.fullmatch(r"[A-ZÀ-Ÿ\-]+", p_clean):
354
- name_parts.append(p_clean)
355
- else:
356
- break
357
-
358
- if name_parts:
359
- return " ".join(name_parts)
360
 
361
  return None
362
 
363
 
364
  def extract_pdf_name(text: str, source_pdf: str = None):
365
- # 1) fallback robuste via nom de fichier
366
  name_from_file = extract_name_from_filename(source_pdf) if source_pdf else None
367
  if name_from_file:
368
  return name_from_file
369
 
370
- # 2) fallback texte si jamais le PDF est mieux extrait
371
  if not text:
372
  return None
373
 
@@ -381,7 +355,7 @@ def extract_pdf_name(text: str, source_pdf: str = None):
381
  if m:
382
  name = " ".join(m.group(1).split()).strip()
383
  if len(name) >= 4:
384
- return name
385
 
386
  return None
387
 
@@ -394,7 +368,7 @@ def parse_zebris_pdf(uploaded_pdf):
394
  source_pdf = uploaded_pdf.name
395
 
396
  data = {
397
- "athlete_name": None,
398
  "source_pdf": source_pdf,
399
  "transition_g": np.nan,
400
  "transition_d": np.nan,
@@ -419,32 +393,34 @@ def parse_zebris_pdf(uploaded_pdf):
419
  "attaque_pdf": "indéterminée",
420
  }
421
 
422
- # Nom athlète : priorité au nom de fichier, car le texte extrait est parfois corrompu
423
- data["athlete_name"] = extract_pdf_name("", source_pdf=source_pdf)
424
-
425
  def to_float(x):
426
- return float(x.replace(",", "."))
427
 
428
  with pdfplumber.open(io.BytesIO(raw)) as pdf:
429
  page_texts = []
430
  for page in pdf.pages:
431
  txt = page.extract_text() or ""
432
  txt = txt.replace("\xa0", " ")
 
433
  page_texts.append(txt)
434
 
435
- full_text = "\n".join(page_texts)
436
 
437
- # fallback si le nom de fichier n'a pas suffi
438
  if not data["athlete_name"]:
439
  data["athlete_name"] = extract_pdf_name(full_text, source_pdf=source_pdf)
440
 
441
- # ---------------------------------------------------
442
- # PAGE 8 : "Analyse du pieds en trois zones"
443
- # On parse les paires Gauche / Droite dans l'ordre.
444
- # ---------------------------------------------------
445
  zone_page_text = None
446
  for txt in page_texts:
447
- if "Analyse du pieds en trois zones" in txt:
 
 
 
 
 
448
  zone_page_text = txt
449
  break
450
 
@@ -452,22 +428,34 @@ def parse_zebris_pdf(uploaded_pdf):
452
  data["attaque_pdf"] = estimate_attack_from_pdf(data)
453
  return data
454
 
455
- # normalisation
456
  zone_page_text = zone_page_text.replace("\xa0", " ")
457
  zone_page_text = re.sub(r"\s+", " ", zone_page_text).strip()
458
 
459
- # Dans TON extraction pdfplumber, "Droite" est souvent corrompu en "oeitDr"
460
- # et l'écart-type sort avec un tiret/en dash, ex: 1066,5–67,8
461
- # On récupère seulement la valeur moyenne gauche puis droite.
 
 
 
462
  pair_pattern = re.compile(
463
- r"Gauche\s+(\d+,\d+|\d+\.\d+|\d+)\s*[–-]\s*(\d+,\d+|\d+\.\d+|\d+).*?"
464
- r"(?:Droite|oeitDr)\s+(\d+,\d+|\d+\.\d+|\d+)\s*[–-]\s*(\d+,\d+|\d+\.\d+|\d+)",
 
465
  flags=re.S
466
  )
467
 
468
  matches = pair_pattern.findall(zone_page_text)
469
 
470
- # Ordre attendu sur la page 8 Zebris :
 
 
 
 
 
 
 
 
 
471
  # 0 transition s
472
  # 1 transition %
473
  # 2 fore force
@@ -479,18 +467,8 @@ def parse_zebris_pdf(uploaded_pdf):
479
  # 8 fore peak time
480
  # 9 mid peak time
481
  # 10 heel peak time
482
- #
483
- # Sur ton PDF, cet ordre est bien visible dans la page "Analyse du pieds en trois zones". :contentReference[oaicite:1]{index=1}
484
-
485
- values = []
486
- for m in matches:
487
- g_mean = to_float(m[0])
488
- d_mean = to_float(m[2])
489
- values.append((g_mean, d_mean))
490
-
491
  if len(values) >= 11:
492
  data["transition_g"], data["transition_d"] = values[0]
493
- # values[1] = transition en %, non utilisé ici
494
 
495
  data["fore_force_g"], data["fore_force_d"] = values[2]
496
  data["mid_force_g"], data["mid_force_d"] = values[3]
@@ -1291,6 +1269,7 @@ if uploaded_pdfs:
1291
  for pdf in uploaded_pdfs:
1292
  try:
1293
  pdfs_data.append(parse_zebris_pdf(pdf))
 
1294
  except Exception as e:
1295
  st.warning(f"{pdf.name} : erreur lecture PDF ({e})")
1296
 
 
320
 
321
 
322
  def extract_name_from_filename(filename: str):
 
 
 
 
 
323
  if not filename:
324
  return None
325
 
326
  base = filename.rsplit("/", 1)[-1]
327
  base = base.rsplit(".", 1)[0]
328
 
329
+ # ex: 19850515_ERIC_TEVANE_124522_Analyse...
330
+ m = re.search(r"\d{8}_([A-Z]+)_([A-Z]+)_", base.upper())
331
+ if m:
332
+ first_name = m.group(1).strip()
333
+ last_name = m.group(2).strip()
334
+ return f"{first_name} {last_name}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
  return None
337
 
338
 
339
  def extract_pdf_name(text: str, source_pdf: str = None):
340
+ # priorité au nom du fichier
341
  name_from_file = extract_name_from_filename(source_pdf) if source_pdf else None
342
  if name_from_file:
343
  return name_from_file
344
 
 
345
  if not text:
346
  return None
347
 
 
355
  if m:
356
  name = " ".join(m.group(1).split()).strip()
357
  if len(name) >= 4:
358
+ return name.upper()
359
 
360
  return None
361
 
 
368
  source_pdf = uploaded_pdf.name
369
 
370
  data = {
371
+ "athlete_name": extract_name_from_filename(source_pdf),
372
  "source_pdf": source_pdf,
373
  "transition_g": np.nan,
374
  "transition_d": np.nan,
 
393
  "attaque_pdf": "indéterminée",
394
  }
395
 
 
 
 
396
  def to_float(x):
397
+ return float(x.replace(",", ".").replace(" ", ""))
398
 
399
  with pdfplumber.open(io.BytesIO(raw)) as pdf:
400
  page_texts = []
401
  for page in pdf.pages:
402
  txt = page.extract_text() or ""
403
  txt = txt.replace("\xa0", " ")
404
+ txt = re.sub(r"\s+", " ", txt).strip()
405
  page_texts.append(txt)
406
 
407
+ full_text = " ".join(page_texts)
408
 
409
+ # fallback si nom non récupéré via fichier
410
  if not data["athlete_name"]:
411
  data["athlete_name"] = extract_pdf_name(full_text, source_pdf=source_pdf)
412
 
413
+ # --------------------------------------------------
414
+ # Chercher la page utile Zebris
415
+ # --------------------------------------------------
 
416
  zone_page_text = None
417
  for txt in page_texts:
418
+ txt_lower = txt.lower()
419
+ if (
420
+ "force maximale" in txt_lower
421
+ and "pression maximale" in txt_lower
422
+ and "instant pic de force" in txt_lower
423
+ ):
424
  zone_page_text = txt
425
  break
426
 
 
428
  data["attaque_pdf"] = estimate_attack_from_pdf(data)
429
  return data
430
 
 
431
  zone_page_text = zone_page_text.replace("\xa0", " ")
432
  zone_page_text = re.sub(r"\s+", " ", zone_page_text).strip()
433
 
434
+ # --------------------------------------------------
435
+ # Regex paires Gauche / Droite
436
+ # Supporte :
437
+ # Gauche 1066,5±67,8 Droite 1040,5±49,3
438
+ # ou variantes OCR/pdfplumber dégradées
439
+ # --------------------------------------------------
440
  pair_pattern = re.compile(
441
+ r"Gauche\s+(\d+,\d+|\d+\.\d+|\d+)\s*(?:±|[–-])?\s*(\d+,\d+|\d+\.\d+|\d+)?"
442
+ r".{0,60}?"
443
+ r"(?:Droite|Droit|oeitDr)\s+(\d+,\d+|\d+\.\d+|\d+)\s*(?:±|[–-])?\s*(\d+,\d+|\d+\.\d+|\d+)?",
444
  flags=re.S
445
  )
446
 
447
  matches = pair_pattern.findall(zone_page_text)
448
 
449
+ values = []
450
+ for m in matches:
451
+ try:
452
+ g_mean = to_float(m[0])
453
+ d_mean = to_float(m[2])
454
+ values.append((g_mean, d_mean))
455
+ except Exception:
456
+ pass
457
+
458
+ # Ordre attendu Zebris :
459
  # 0 transition s
460
  # 1 transition %
461
  # 2 fore force
 
467
  # 8 fore peak time
468
  # 9 mid peak time
469
  # 10 heel peak time
 
 
 
 
 
 
 
 
 
470
  if len(values) >= 11:
471
  data["transition_g"], data["transition_d"] = values[0]
 
472
 
473
  data["fore_force_g"], data["fore_force_d"] = values[2]
474
  data["mid_force_g"], data["mid_force_d"] = values[3]
 
1269
  for pdf in uploaded_pdfs:
1270
  try:
1271
  pdfs_data.append(parse_zebris_pdf(pdf))
1272
+ st.write("PDF parsé :", pdfs_data[-1])
1273
  except Exception as e:
1274
  st.warning(f"{pdf.name} : erreur lecture PDF ({e})")
1275