Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -318,16 +318,21 @@ def find_float_after_label(text: str, label: str, max_numbers: int = 2, window:
|
|
| 318 |
return out
|
| 319 |
|
| 320 |
def extract_pdf_name(text: str):
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
r"Personne:\s*([A-Za-zÀ-ÿ\- ]+)",
|
| 324 |
-
]
|
| 325 |
-
for pattern in patterns:
|
| 326 |
-
m = re.search(pattern, text, flags=re.S)
|
| 327 |
-
if m:
|
| 328 |
-
return m.group(1).strip()
|
| 329 |
-
return None
|
| 330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
|
| 332 |
def parse_zebris_pdf(uploaded_pdf):
|
| 333 |
text = extract_text_from_pdf(uploaded_pdf)
|
|
@@ -358,68 +363,97 @@ def parse_zebris_pdf(uploaded_pdf):
|
|
| 358 |
"fore_peak_time_pct_d": np.nan,
|
| 359 |
}
|
| 360 |
|
| 361 |
-
#
|
| 362 |
-
text_flat =
|
|
|
|
| 363 |
|
| 364 |
num = r"(\d+,\d+|\d+\.\d+|\d+)"
|
| 365 |
|
| 366 |
def to_float(x):
|
| 367 |
return float(x.replace(",", "."))
|
| 368 |
|
| 369 |
-
def
|
| 370 |
"""
|
| 371 |
-
|
| 372 |
-
... Gauche Droite 1066,5±67,8 1040,5±49,3
|
|
|
|
| 373 |
"""
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
else:
|
| 381 |
-
pattern = (
|
| 382 |
-
rf"{re.escape(section_label)}\s+Gauche\s+Droite\s+"
|
| 383 |
-
rf"{num}\s*±\s*{num}\s+{num}\s*±\s*{num}"
|
| 384 |
-
)
|
| 385 |
-
|
| 386 |
-
m = re.search(pattern, text_flat, flags=re.S)
|
| 387 |
if not m:
|
| 388 |
return np.nan, np.nan
|
| 389 |
-
|
| 390 |
-
# groupes 1 et 3 = valeurs moyennes G / D
|
| 391 |
return to_float(m.group(1)), to_float(m.group(3))
|
| 392 |
|
| 393 |
-
#
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
mg, md = extract_pair("Force maximale, N", "Midfoot (Three zones)")
|
| 400 |
-
hg, hd = extract_pair("Force maximale, N", "Heel (Three zones)")
|
| 401 |
|
| 402 |
-
|
| 403 |
-
data["mid_force_g"], data["mid_force_d"] = mg, md
|
| 404 |
-
data["heel_force_g"], data["heel_force_d"] = hg, hd
|
| 405 |
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
data["mid_pressure_g"], data["mid_pressure_d"] = mpg, mpd
|
| 413 |
-
data["heel_pressure_g"], data["heel_pressure_d"] = hpg, hpd
|
| 414 |
|
| 415 |
-
#
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
htg, htd = extract_pair("Instant pic de force, % de phase d'appui", "Heel (Three zones)")
|
| 419 |
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
|
| 424 |
data["attaque_pdf"] = estimate_attack_from_pdf(data)
|
| 425 |
return data
|
|
@@ -1208,7 +1242,7 @@ if uploaded_pdfs:
|
|
| 1208 |
for pdf in uploaded_pdfs:
|
| 1209 |
try:
|
| 1210 |
pdfs_data.append(parse_zebris_pdf(pdf))
|
| 1211 |
-
st.write(pdfs_data[-1])
|
| 1212 |
except Exception as e:
|
| 1213 |
st.warning(f"{pdf.name} : erreur lecture PDF ({e})")
|
| 1214 |
|
|
|
|
| 318 |
return out
|
| 319 |
|
| 320 |
def extract_pdf_name(text: str):
|
| 321 |
+
if not text:
|
| 322 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
|
| 324 |
+
for line in text.splitlines():
|
| 325 |
+
clean = " ".join(line.replace("\xa0", " ").split())
|
| 326 |
+
if "Personne:" in clean:
|
| 327 |
+
after = clean.split("Personne:", 1)[1].strip()
|
| 328 |
+
# on coupe avant la date si elle existe
|
| 329 |
+
m = re.match(r"(.+?)(?:,\s*\d{2}/\d{2}/\d{4})?$", after)
|
| 330 |
+
if m:
|
| 331 |
+
name = m.group(1).strip()
|
| 332 |
+
if name:
|
| 333 |
+
return name
|
| 334 |
+
|
| 335 |
+
return None
|
| 336 |
|
| 337 |
def parse_zebris_pdf(uploaded_pdf):
|
| 338 |
text = extract_text_from_pdf(uploaded_pdf)
|
|
|
|
| 363 |
"fore_peak_time_pct_d": np.nan,
|
| 364 |
}
|
| 365 |
|
| 366 |
+
# normalisation forte du texte
|
| 367 |
+
text_flat = text.replace("\xa0", " ")
|
| 368 |
+
text_flat = re.sub(r"\s+", " ", text_flat).strip()
|
| 369 |
|
| 370 |
num = r"(\d+,\d+|\d+\.\d+|\d+)"
|
| 371 |
|
| 372 |
def to_float(x):
|
| 373 |
return float(x.replace(",", "."))
|
| 374 |
|
| 375 |
+
def extract_gd_pair(block_text, label):
|
| 376 |
"""
|
| 377 |
+
Cherche un pattern du type:
|
| 378 |
+
label ... Gauche Droite 1066,5±67,8 1040,5±49,3
|
| 379 |
+
et renvoie (gauche, droite)
|
| 380 |
"""
|
| 381 |
+
pattern = (
|
| 382 |
+
rf"{re.escape(label)}\s*Gauche\s*Droite\s*"
|
| 383 |
+
rf"{num}\s*±\s*{num}\s*"
|
| 384 |
+
rf"{num}\s*±\s*{num}"
|
| 385 |
+
)
|
| 386 |
+
m = re.search(pattern, block_text, flags=re.S)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
if not m:
|
| 388 |
return np.nan, np.nan
|
|
|
|
|
|
|
| 389 |
return to_float(m.group(1)), to_float(m.group(3))
|
| 390 |
|
| 391 |
+
# on isole le bloc utile de la page 8
|
| 392 |
+
start_idx = text_flat.find("Analyse du pieds en trois zones")
|
| 393 |
+
if start_idx == -1:
|
| 394 |
+
start_idx = text_flat.find("Analyse du pieds en trois zones")
|
| 395 |
+
if start_idx == -1:
|
| 396 |
+
start_idx = text_flat.find("Modification de la charge")
|
|
|
|
|
|
|
| 397 |
|
| 398 |
+
end_idx = text_flat.find("Durée de contact au sol", start_idx if start_idx != -1 else 0)
|
|
|
|
|
|
|
| 399 |
|
| 400 |
+
if start_idx != -1 and end_idx != -1 and end_idx > start_idx:
|
| 401 |
+
zone_block = text_flat[start_idx:end_idx]
|
| 402 |
+
elif start_idx != -1:
|
| 403 |
+
zone_block = text_flat[start_idx:]
|
| 404 |
+
else:
|
| 405 |
+
zone_block = text_flat
|
|
|
|
|
|
|
| 406 |
|
| 407 |
+
# 1. Transition
|
| 408 |
+
tg, td = extract_gd_pair(zone_block, "Instant du passage du talon vers l'avant-pied, s")
|
| 409 |
+
data["transition_g"], data["transition_d"] = tg, td
|
|
|
|
| 410 |
|
| 411 |
+
# 2. Force maximale
|
| 412 |
+
fg, fd = extract_gd_pair(zone_block, "Forefoot (Three zones)")
|
| 413 |
+
# attention: Forefoot apparaît plusieurs fois dans la page, donc on fait des blocs plus précis
|
| 414 |
+
force_section_match = re.search(
|
| 415 |
+
rf"Force maximale,\s*N(.*?)Pression maximale,\s*N/cm²",
|
| 416 |
+
zone_block,
|
| 417 |
+
flags=re.S
|
| 418 |
+
)
|
| 419 |
+
if force_section_match:
|
| 420 |
+
force_section = force_section_match.group(1)
|
| 421 |
+
fg, fd = extract_gd_pair(force_section, "Forefoot (Three zones)")
|
| 422 |
+
mg, md = extract_gd_pair(force_section, "Midfoot (Three zones)")
|
| 423 |
+
hg, hd = extract_gd_pair(force_section, "Heel (Three zones)")
|
| 424 |
+
data["fore_force_g"], data["fore_force_d"] = fg, fd
|
| 425 |
+
data["mid_force_g"], data["mid_force_d"] = mg, md
|
| 426 |
+
data["heel_force_g"], data["heel_force_d"] = hg, hd
|
| 427 |
+
|
| 428 |
+
# 3. Pression maximale
|
| 429 |
+
pressure_section_match = re.search(
|
| 430 |
+
rf"Pression maximale,\s*N/cm²(.*?)Instant pic de force,\s*% de phase d'appui",
|
| 431 |
+
zone_block,
|
| 432 |
+
flags=re.S
|
| 433 |
+
)
|
| 434 |
+
if pressure_section_match:
|
| 435 |
+
pressure_section = pressure_section_match.group(1)
|
| 436 |
+
fpg, fpd = extract_gd_pair(pressure_section, "Forefoot (Three zones)")
|
| 437 |
+
mpg, mpd = extract_gd_pair(pressure_section, "Midfoot (Three zones)")
|
| 438 |
+
hpg, hpd = extract_gd_pair(pressure_section, "Heel (Three zones)")
|
| 439 |
+
data["fore_pressure_g"], data["fore_pressure_d"] = fpg, fpd
|
| 440 |
+
data["mid_pressure_g"], data["mid_pressure_d"] = mpg, mpd
|
| 441 |
+
data["heel_pressure_g"], data["heel_pressure_d"] = hpg, hpd
|
| 442 |
+
|
| 443 |
+
# 4. Timing pic de force
|
| 444 |
+
peak_section_match = re.search(
|
| 445 |
+
rf"Instant pic de force,\s*% de phase d'appui(.*)$",
|
| 446 |
+
zone_block,
|
| 447 |
+
flags=re.S
|
| 448 |
+
)
|
| 449 |
+
if peak_section_match:
|
| 450 |
+
peak_section = peak_section_match.group(1)
|
| 451 |
+
ftg, ftd = extract_gd_pair(peak_section, "Forefoot (Three zones)")
|
| 452 |
+
mtg, mtd = extract_gd_pair(peak_section, "Midfoot (Three zones)")
|
| 453 |
+
htg, htd = extract_gd_pair(peak_section, "Heel (Three zones)")
|
| 454 |
+
data["fore_peak_time_pct_g"], data["fore_peak_time_pct_d"] = ftg, ftd
|
| 455 |
+
data["mid_peak_time_pct_g"], data["mid_peak_time_pct_d"] = mtg, mtd
|
| 456 |
+
data["heel_peak_time_pct_g"], data["heel_peak_time_pct_d"] = htg, htd
|
| 457 |
|
| 458 |
data["attaque_pdf"] = estimate_attack_from_pdf(data)
|
| 459 |
return data
|
|
|
|
| 1242 |
for pdf in uploaded_pdfs:
|
| 1243 |
try:
|
| 1244 |
pdfs_data.append(parse_zebris_pdf(pdf))
|
| 1245 |
+
st.write("PDF parsé :", pdfs_data[-1])
|
| 1246 |
except Exception as e:
|
| 1247 |
st.warning(f"{pdf.name} : erreur lecture PDF ({e})")
|
| 1248 |
|