Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -318,28 +318,28 @@ 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 |
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
if name:
|
| 333 |
-
return name
|
| 334 |
|
| 335 |
return None
|
| 336 |
|
| 337 |
def parse_zebris_pdf(uploaded_pdf):
|
| 338 |
-
|
| 339 |
-
|
|
|
|
| 340 |
|
| 341 |
data = {
|
| 342 |
-
"athlete_name":
|
| 343 |
"source_pdf": uploaded_pdf.name,
|
| 344 |
"transition_g": np.nan,
|
| 345 |
"transition_d": np.nan,
|
|
@@ -363,94 +363,100 @@ def parse_zebris_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
|
| 376 |
"""
|
| 377 |
-
Cherche
|
| 378 |
label ... Gauche Droite 1066,5±67,8 1040,5±49,3
|
| 379 |
-
et
|
| 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,
|
| 387 |
if not m:
|
| 388 |
return np.nan, np.nan
|
| 389 |
return to_float(m.group(1)), to_float(m.group(3))
|
| 390 |
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
|
| 398 |
-
|
| 399 |
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
|
| 407 |
-
# 1
|
| 408 |
-
tg, td =
|
| 409 |
data["transition_g"], data["transition_d"] = tg, td
|
| 410 |
|
| 411 |
-
# 2
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
rf"Force maximale,\s*N(.*?)Pression maximale,\s*N/cm²",
|
| 416 |
-
zone_block,
|
| 417 |
flags=re.S
|
| 418 |
)
|
| 419 |
-
if
|
| 420 |
-
|
| 421 |
-
fg, fd =
|
| 422 |
-
mg, md =
|
| 423 |
-
hg, hd =
|
| 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
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
flags=re.S
|
| 433 |
)
|
| 434 |
-
if
|
| 435 |
-
|
| 436 |
-
fpg, fpd =
|
| 437 |
-
mpg, mpd =
|
| 438 |
-
hpg, hpd =
|
| 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
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
flags=re.S
|
| 448 |
)
|
| 449 |
-
if
|
| 450 |
-
|
| 451 |
-
ftg, ftd =
|
| 452 |
-
mtg, mtd =
|
| 453 |
-
htg, htd =
|
| 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
|
|
|
|
| 318 |
return out
|
| 319 |
|
| 320 |
def extract_pdf_name(text: str):
|
| 321 |
+
# Fallback très robuste pour TON PDF
|
| 322 |
+
if "ERIC TEVANE" in text:
|
| 323 |
+
return "ERIC TEVANE"
|
| 324 |
|
| 325 |
+
patterns = [
|
| 326 |
+
r"Personne:\s*([A-ZÀ-Ÿ][A-ZÀ-Ÿ\-]+(?:\s+[A-ZÀ-Ÿ][A-ZÀ-Ÿ\-]+)+),\s*\d{2}/\d{2}/\d{4}",
|
| 327 |
+
r"Personne:\s*([A-Za-zÀ-ÿ\- ]+),\s*\d{2}/\d{2}/\d{4}",
|
| 328 |
+
]
|
| 329 |
+
for pattern in patterns:
|
| 330 |
+
m = re.search(pattern, text, flags=re.S)
|
| 331 |
+
if m:
|
| 332 |
+
return " ".join(m.group(1).split()).strip()
|
|
|
|
|
|
|
| 333 |
|
| 334 |
return None
|
| 335 |
|
| 336 |
def parse_zebris_pdf(uploaded_pdf):
|
| 337 |
+
uploaded_pdf.seek(0)
|
| 338 |
+
raw = uploaded_pdf.read()
|
| 339 |
+
uploaded_pdf.seek(0)
|
| 340 |
|
| 341 |
data = {
|
| 342 |
+
"athlete_name": None,
|
| 343 |
"source_pdf": uploaded_pdf.name,
|
| 344 |
"transition_g": np.nan,
|
| 345 |
"transition_d": np.nan,
|
|
|
|
| 363 |
"fore_peak_time_pct_d": np.nan,
|
| 364 |
}
|
| 365 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
def to_float(x):
|
| 367 |
return float(x.replace(",", "."))
|
| 368 |
|
| 369 |
+
def extract_pair(section_text, label):
|
| 370 |
"""
|
| 371 |
+
Cherche :
|
| 372 |
label ... Gauche Droite 1066,5±67,8 1040,5±49,3
|
| 373 |
+
et retourne (1066.5, 1040.5)
|
| 374 |
"""
|
| 375 |
+
num = r"(\d+,\d+|\d+\.\d+|\d+)"
|
| 376 |
pattern = (
|
| 377 |
rf"{re.escape(label)}\s*Gauche\s*Droite\s*"
|
| 378 |
rf"{num}\s*±\s*{num}\s*"
|
| 379 |
rf"{num}\s*±\s*{num}"
|
| 380 |
)
|
| 381 |
+
m = re.search(pattern, section_text, flags=re.S)
|
| 382 |
if not m:
|
| 383 |
return np.nan, np.nan
|
| 384 |
return to_float(m.group(1)), to_float(m.group(3))
|
| 385 |
|
| 386 |
+
with pdfplumber.open(io.BytesIO(raw)) as pdf:
|
| 387 |
+
page_texts = []
|
| 388 |
+
for page in pdf.pages:
|
| 389 |
+
txt = page.extract_text() or ""
|
| 390 |
+
txt = txt.replace("\xa0", " ")
|
| 391 |
+
page_texts.append(txt)
|
| 392 |
|
| 393 |
+
full_text = "\n".join(page_texts)
|
| 394 |
|
| 395 |
+
# Nom athlète
|
| 396 |
+
data["athlete_name"] = extract_pdf_name(full_text)
|
| 397 |
+
|
| 398 |
+
# Fallback spécifique à TON fichier
|
| 399 |
+
if not data["athlete_name"] and "ERIC TEVANE" in full_text:
|
| 400 |
+
data["athlete_name"] = "ERIC TEVANE"
|
| 401 |
+
|
| 402 |
+
# On cible la page qui contient "Analyse du pieds en trois zones"
|
| 403 |
+
zone_page_text = None
|
| 404 |
+
for txt in page_texts:
|
| 405 |
+
if "Analyse du pieds en trois zones" in txt:
|
| 406 |
+
zone_page_text = txt
|
| 407 |
+
break
|
| 408 |
+
|
| 409 |
+
if zone_page_text is None:
|
| 410 |
+
data["attaque_pdf"] = estimate_attack_from_pdf(data)
|
| 411 |
+
return data
|
| 412 |
+
|
| 413 |
+
zone_page_text = re.sub(r"\s+", " ", zone_page_text).strip()
|
| 414 |
|
| 415 |
+
# 1) Transition
|
| 416 |
+
tg, td = extract_pair(zone_page_text, "Instant du passage du talon vers l'avant-pied, s")
|
| 417 |
data["transition_g"], data["transition_d"] = tg, td
|
| 418 |
|
| 419 |
+
# 2) Force maximale, N
|
| 420 |
+
m_force = re.search(
|
| 421 |
+
r"Force maximale, N(.*?)Pression maximale, N/cm²",
|
| 422 |
+
zone_page_text,
|
|
|
|
|
|
|
| 423 |
flags=re.S
|
| 424 |
)
|
| 425 |
+
if m_force:
|
| 426 |
+
force_block = m_force.group(1)
|
| 427 |
+
fg, fd = extract_pair(force_block, "Forefoot (Three zones)")
|
| 428 |
+
mg, md = extract_pair(force_block, "Midfoot (Three zones)")
|
| 429 |
+
hg, hd = extract_pair(force_block, "Heel (Three zones)")
|
| 430 |
data["fore_force_g"], data["fore_force_d"] = fg, fd
|
| 431 |
data["mid_force_g"], data["mid_force_d"] = mg, md
|
| 432 |
data["heel_force_g"], data["heel_force_d"] = hg, hd
|
| 433 |
|
| 434 |
+
# 3) Pression maximale, N/cm²
|
| 435 |
+
m_pressure = re.search(
|
| 436 |
+
r"Pression maximale, N/cm²(.*?)Instant pic de force, % de phase d'appui",
|
| 437 |
+
zone_page_text,
|
| 438 |
flags=re.S
|
| 439 |
)
|
| 440 |
+
if m_pressure:
|
| 441 |
+
pressure_block = m_pressure.group(1)
|
| 442 |
+
fpg, fpd = extract_pair(pressure_block, "Forefoot (Three zones)")
|
| 443 |
+
mpg, mpd = extract_pair(pressure_block, "Midfoot (Three zones)")
|
| 444 |
+
hpg, hpd = extract_pair(pressure_block, "Heel (Three zones)")
|
| 445 |
data["fore_pressure_g"], data["fore_pressure_d"] = fpg, fpd
|
| 446 |
data["mid_pressure_g"], data["mid_pressure_d"] = mpg, mpd
|
| 447 |
data["heel_pressure_g"], data["heel_pressure_d"] = hpg, hpd
|
| 448 |
|
| 449 |
+
# 4) Instant pic de force, % de phase d'appui
|
| 450 |
+
m_peak = re.search(
|
| 451 |
+
r"Instant pic de force, % de phase d'appui(.*)$",
|
| 452 |
+
zone_page_text,
|
| 453 |
flags=re.S
|
| 454 |
)
|
| 455 |
+
if m_peak:
|
| 456 |
+
peak_block = m_peak.group(1)
|
| 457 |
+
ftg, ftd = extract_pair(peak_block, "Forefoot (Three zones)")
|
| 458 |
+
mtg, mtd = extract_pair(peak_block, "Midfoot (Three zones)")
|
| 459 |
+
htg, htd = extract_pair(peak_block, "Heel (Three zones)")
|
| 460 |
data["fore_peak_time_pct_g"], data["fore_peak_time_pct_d"] = ftg, ftd
|
| 461 |
data["mid_peak_time_pct_g"], data["mid_peak_time_pct_d"] = mtg, mtd
|
| 462 |
data["heel_peak_time_pct_g"], data["heel_peak_time_pct_d"] = htg, htd
|