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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -59
app.py CHANGED
@@ -317,13 +317,59 @@ def find_float_after_label(text: str, label: str, max_numbers: int = 2, window:
317
  pass
318
  return out
319
 
320
- def extract_pdf_name(text: str):
321
- if not text:
 
 
 
 
 
 
 
322
  return None
323
 
324
- # Fallback spécifique si le texte contient bien le nom
325
- if "ERIC TEVANE" in text.upper():
326
- return "ERIC TEVANE"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
 
328
  patterns = [
329
  r"Personne:\s*([A-Za-zÀ-ÿ\- ]+),\s*\d{2}/\d{2}/\d{4}",
@@ -339,7 +385,12 @@ def extract_pdf_name(text: str):
339
 
340
  return None
341
 
 
342
  def parse_zebris_pdf(uploaded_pdf):
 
 
 
 
343
  source_pdf = uploaded_pdf.name
344
 
345
  data = {
@@ -368,64 +419,90 @@ def parse_zebris_pdf(uploaded_pdf):
368
  "attaque_pdf": "indéterminée",
369
  }
370
 
371
- # -------------------------------------------------
372
- # 1) Fallback robuste sur le nom du fichier
373
- # ex: 19850515_ERIC_TEVANE_124522_Analyse...
374
- # -------------------------------------------------
375
- filename_upper = source_pdf.upper()
376
-
377
- m = re.search(r"\d{8}_([A-Z]+)_([A-Z]+)_", filename_upper)
378
- if m:
379
- first_name = m.group(1).strip()
380
- last_name = m.group(2).strip()
381
- data["athlete_name"] = f"{first_name} {last_name}"
382
-
383
- # -------------------------------------------------
384
- # 2) Cas spécifique du PDF ERIC TEVANE
385
- # car l'extraction texte pdfplumber est corrompue
386
- # -------------------------------------------------
387
- if "ERIC_TEVANE" in filename_upper or "TEVANE_ERIC" in filename_upper:
388
- data["athlete_name"] = "ERIC TEVANE"
389
-
390
- data["transition_g"] = 0.01
391
- data["transition_d"] = 0.02
392
-
393
- data["fore_force_g"] = 1066.5
394
- data["fore_force_d"] = 1040.5
395
- data["mid_force_g"] = 342.7
396
- data["mid_force_d"] = 306.2
397
- data["heel_force_g"] = 141.9
398
- data["heel_force_d"] = 181.6
399
-
400
- data["fore_pressure_g"] = 20.4
401
- data["fore_pressure_d"] = 20.6
402
- data["mid_pressure_g"] = 16.6
403
- data["mid_pressure_d"] = 15.2
404
- data["heel_pressure_g"] = 6.1
405
- data["heel_pressure_d"] = 6.5
406
-
407
- data["fore_peak_time_pct_g"] = 50.4
408
- data["fore_peak_time_pct_d"] = 50.0
409
- data["mid_peak_time_pct_g"] = 30.9
410
- data["mid_peak_time_pct_d"] = 23.6
411
- data["heel_peak_time_pct_g"] = 12.2
412
- data["heel_peak_time_pct_d"] = 12.2
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  data["attaque_pdf"] = estimate_attack_from_pdf(data)
415
  return data
416
 
417
- # -------------------------------------------------
418
- # 3) Sinon, tentative standard sur le texte PDF
419
- # -------------------------------------------------
420
- try:
421
- text = extract_text_from_pdf(uploaded_pdf)
422
- except Exception:
423
- return data
 
 
 
 
 
424
 
425
- if not data["athlete_name"]:
426
- extracted_name = extract_pdf_name(text)
427
- if extracted_name:
428
- data["athlete_name"] = extracted_name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
 
430
  data["attaque_pdf"] = estimate_attack_from_pdf(data)
431
  return data
@@ -1214,7 +1291,6 @@ if uploaded_pdfs:
1214
  for pdf in uploaded_pdfs:
1215
  try:
1216
  pdfs_data.append(parse_zebris_pdf(pdf))
1217
- st.write("PDF parsé :", pdfs_data[-1])
1218
  except Exception as e:
1219
  st.warning(f"{pdf.name} : erreur lecture PDF ({e})")
1220
 
 
317
  pass
318
  return out
319
 
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
 
374
  patterns = [
375
  r"Personne:\s*([A-Za-zÀ-ÿ\- ]+),\s*\d{2}/\d{2}/\d{4}",
 
385
 
386
  return None
387
 
388
+
389
  def parse_zebris_pdf(uploaded_pdf):
390
+ uploaded_pdf.seek(0)
391
+ raw = uploaded_pdf.read()
392
+ uploaded_pdf.seek(0)
393
+
394
  source_pdf = uploaded_pdf.name
395
 
396
  data = {
 
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
+
451
+ if zone_page_text is None:
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
474
+ # 3 mid force
475
+ # 4 heel force
476
+ # 5 fore pressure
477
+ # 6 mid pressure
478
+ # 7 heel pressure
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]
497
+ data["heel_force_g"], data["heel_force_d"] = values[4]
498
+
499
+ data["fore_pressure_g"], data["fore_pressure_d"] = values[5]
500
+ data["mid_pressure_g"], data["mid_pressure_d"] = values[6]
501
+ data["heel_pressure_g"], data["heel_pressure_d"] = values[7]
502
+
503
+ data["fore_peak_time_pct_g"], data["fore_peak_time_pct_d"] = values[8]
504
+ data["mid_peak_time_pct_g"], data["mid_peak_time_pct_d"] = values[9]
505
+ data["heel_peak_time_pct_g"], data["heel_peak_time_pct_d"] = values[10]
506
 
507
  data["attaque_pdf"] = estimate_attack_from_pdf(data)
508
  return data
 
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