Files
bio-performx/app/services/__pycache__/context_generator.cpython-312.pyc
T

304 lines
40 KiB
Plaintext
Raw Normal View History

Ë
2025-11-21 09:23:13 +01:00
U‰i§ãóDdZddlmZddlmZmZmZddlZGdd«Zy)
Context Generator Service
This service processes all data files and generates context dictionaries for each page
of the medical report. It performs analysis on Pnoe, Spirometry, and SECA data.
2025-11-21 09:23:13 +01:00
é)Údatetime)ÚDictÚOptionalÚTupleNc óeZdZdZdZ d+dededeefdZdZd ed
e fd Z
2025-11-21 09:23:13 +01:00
d+d ee d
e fd
Z d+d ee d
e fdZ d
e
ee ee ffdZdee dee dej d
e fdZde d
e fdZde d
2025-11-21 09:23:13 +01:00
e fdZd
e fdZd
e fdZdedededed
ef
dZdeded
e
eeffd „Zd
efd!„Zd"ed
e
ej eeffd#„Zd$ed%ed
e
ej eeffd&„Zd+d'ee
2025-11-21 09:23:13 +01:00
eefd
e fd(„Z d+d ed)e eefd ee d
2025-11-21 09:23:13 +01:00
e ee ffd*„Zy),ÚContextGeneratorz&Generate context data for report pagescó<d|_d|_d|_i|_y©N)Úpnoe_dfÚ
spirometry_dfÚseca_dfÚ patient_info)Úselfs úW/home/oluwasanmi/Documents/Work/MKD/report_generation/app/services/context_generator.pyÚ__init__zContextGenerator.__init__s ؈Œ ØÔ؈Œ ؈ÕóNÚ pnoe_pathÚspirometry_pathÚ seca_pathcóØtj|d¬«|_tj|«|_|rtj|«|_nd|_|j
2025-11-21 09:23:13 +01:00
«y)zLoad all required datasetsú;)Ú delimiterN)ÚpdÚread_csvr r Ú
read_excelr
2025-11-21 09:23:13 +01:00
Ú_preprocess_pnoe_data)rrrrs rÚ load_datazContextGenerator.load_datasMô—{{ 9¸ÔŒ ÜŸ[™[¨ÓÔÙ ÜŸ=™=¨Ó3ˆDˆDŒLØ ×$rcóú|jjD]2} tj|j|«|j|<Œ4|jd|jdz |jd<|jd|jdz |jd<|jd|jdzdz |jd <|jd|jd
zdz |jd <d }gd
¢}|D]Y}||jjvsŒ|j|j
|d¬«j«|j|d<Œ[y#tt
f$rYŒbwxYw)z&Apply preprocessing steps to Pnoe dataú VO2(ml/min)úHR(bpm)ú VO2 PulseúBF(bpm)ú
VO2 Breathú EE(kcal/min)úCARBS(%)édÚCHOúFAT(%)ÚFATé
)
rú VCO2(ml/min)r úVT(l)r"ú VE(l/min)r!r#r'r)é©ÚwindowÚ min_periodsÚ _smoothedN)r ÚcolumnsrÚ
to_numericÚ
ValueErrorÚ TypeErrorÚrollingÚmean)rÚcolÚ window_sizeÚcolumns_to_smooths rrz&ContextGenerator._preprocess_pnoe_data&soð—<<×'ˆ
Ü$&§M¡M°$·,±,¸sÑ2CÓ$D ˜SÒ
L‰L˜Ñ '¨$¯,©,°yÑ*AÑ 

L‰L˜Ñ '¨$¯,©,°yÑ*AÑ 

L‰L˜Ñ (¨4¯<©<¸
Ñ+CÑ CÀcÑ 
ð
2025-11-21 09:23:13 +01:00
L‰L˜Ñ (¨4¯<©<¸Ñ+AÑ AÀCÑ 
ðˆ ò 
Ðó%ˆCØd—l‘l×—L‘L Ñ-°[ÈaÐ  ˜u IÐ%øô=¤ Ð
Úð
ús/E'Å'E:Å9E:Ú patient_nameÚreturncón|jh|j|jdjj|dd¬«}|js|jd}t |j
dd««}t |j
dd««}|j
dd«d |j
dd«|j
dd«|j
dd«t|j
d
2025-11-21 09:23:13 +01:00
d««|j
d d«||j
2025-11-21 09:23:13 +01:00
d d«j«|||zd
z |d|d
z z
z||zd
z dz|d|d
2025-11-21 09:23:13 +01:00
z z
zdz|d|d
z z
zdzdœ
|_ |jSd|jvr§d|jvr™|jd}|jd}||zd
z |jd<|d|d
z z
z|jd<||zd
z dz|jd<|d|d
z z
zdz|jd<|d|d
z z
zdz|jd<|jS)zJExtract patient information from SECA dataset or use provided patient_infoÚLastNameF)ÚcaseÚnarÚWeightÚ Adult_FMPÚ FirstNameÚÚ ÚAgeÚHeightÚGenderr&r.g3܀ϣ@)
ÚnameÚ
first_nameÚ last_nameÚageÚheightÚweightÚgenderÚfat_percentageÚ fat_mass_kgÚfat_free_mass_kgÚ fat_mass_lbsÚfat_free_mass_lbsÚ
2025-11-21 09:23:13 +01:00
lean_mass_lbsrOrQrRrSrTrUrV)
r
ÚstrÚcontainsÚemptyÚilocÚfloatÚgetÚintÚlowerr)rr<Ú patient_dataÚrowÚ weight_kgÚfat_pcts rÚextract_patient_infoz%ContextGenerator.extract_patient_infoPsuà <‰<Ñ Ÿ<™<Ø ˜(×  u°ðñˆLð
 ×"×Ñ*Ü! #§'¡'¨(°AÓ"6Ó7 Ü §¡¨ °QÓ 7Ó8ð #Ÿw™w {°BÓ8¸¸#¿'¹'À*ÈbÓ:QÐ9RÐSØ"%§'¡'¨+°rÓ":Ø!$§¡¨°RÓ!8ܘsŸw™w u¨aÓ1Ø!$§¡¨°2Ó!6Ð 7Ø!Ÿg™g Ó3×;Ø&-Ø#,¨wÑ#6¸Ñ#<Ø(1°Q¸À3¹Ñ5FÑ(GØ$-°Ñ$7¸#Ñ$=ÀÑ$GØ)2°a¸'ÀC¹-Ñ6GÑ)HÈ7Ñ)Rà%.°!°gÀ±mÑ2CÑ%DÀwÑ%Nñ%Ô!ð<× Ñ Ð ð˜×
*Ð/?À4×CTÑCTÑ/TØ×)¨(Ñ3ˆ×'Ð(8Ñ9ˆGØ/8¸7Ñ/BÀSÑ/HˆD× Ñ ˜ ,Ø4=ÀÀWÈsÁ]ÑARÑ4SˆD× Ñ Ð 1Ø09¸GÑ0CÀcÑ0IÈGÑ0SˆD× Ñ ˜nÑ ˜Q ¨3¡Ñ/°'Ñ
× Ñ Ð
˜Q ¨3¡Ñ/°'Ñ
× Ñ ˜oÑ × Ñ Ð rÚmetric_overridescóv|i}i}dD]}|j«jdd«jdd«}|d|vrt||d«||d<n†|jj|jdj
2025-11-21 09:23:13 +01:00
j
«|k(}|js9|djd }tj|«r t|«||d<|d
|vrt||d
«||d
<ο|jj|jdj
j
«|k(}|jrŒG|d jd }tj|«sŒp t|«||d
2025-11-21 09:23:13 +01:00
<Œ„|S#ttf$rYŒ¿wxYw#ttf$rYŒ®wxYw) z$Calculate spirometry-related metrics)ÚFVCÚFEV1z FEV1/FVC%ú_pctÚ_bestÚ
ParametersÚBestrÚ_predz%Pred.)
r^Úreplacer[r ÚlocrWÚstriprYÚvaluesrÚnotnar5r6)rrdÚmetricsÚparamÚ param_keyr`Úvalues rÚcalculate_spirometry_metricsz-ContextGenerator.calculate_spirometry_metrics}ð Ð  àˆÜ1ˆEØŸ
×-¨c°3ÓÀVÓLˆ˜"Ð&6Ñ6Ü/4Ø {°%Ð%8Ñ0˜9˜+ ×(××& 4×8×@ÀEÑð—y’yØ ™K×.¨qÑ1—xx ð!Ü;@À»<˜G y Ð$7ј"Ð&6Ñ6Ü/4Ø {°%Ð%8Ñ0˜9˜+ ×(××& 4×8×@ÀEÑð—y”yØ ™M×Ñ3—x‘x ð!Ü;@À»<˜G y Ð$7Ó8ð?2ðDˆøô%!+¬IÐ ð!ûô !+¬IÐ ð!ús$ÃFÅ:F%ÆF"Æ!F"Æ%F8Æ7F8cóxiŠi}dvrtd«|d<n |jdj«|d<dvrtd«|d<n|d|jdz |d<dvrftd«|d<dvrtd«|d<n…|jdj «}|jj
2025-11-21 09:23:13 +01:00
|}|d|d<nF|jdj «}|jj
|}|d|d<|d|d<d ‰vrftd «|d <d
vrtd
«|d
<n…|jd j «}|jj
|}|d|d
<nF|jd j «}|jj
|}|d |d <|d|d
<d vr ‰d |d <n|j
«\}}||d <d
vr ‰d
2025-11-21 09:23:13 +01:00
|d
<n|j
2025-11-21 09:23:13 +01:00
«\}} | |d
<tˆfdtdd«D««r&tdd«D]}
d|
d} | vsŒ| || <Œ|S|jd j «}|jj
|}|j|d |d
|«} |j| «|S)z"Calculate all Pnoe-derived metricsÚvo2_maxzVO2(ml/min)_smoothedÚvo2_max_per_kgrOÚpeak_vtÚ
peak_vt_hrzVT(l)_smoothedúHR(bpm)_smoothedÚ
fat_max_valueÚ
fat_max_hrÚ FAT_smoothedÚvt1Úvt2c3ó.K|] }d|dvŒy­w)ÚzoneÚ_bpmN©)Ú.0Úirds €rú <genexpr>z:ContextGenerator.calculate_pnoe_metrics.<locals>.<genexpr>ès øèø€ÐG¹;°aaˆ~Ð!1Ô1¹;ùsƒr.ér†r‡) r[r ÚmaxrÚidxmaxrqÚ_detect_thresholdsÚanyÚrangeÚ_calculate_hr_zonesÚupdate)
rrdruÚ peak_vt_idxÚ peak_vt_rowÚ fat_max_idxÚ fat_max_rowrƒrir„Úzone_keyÚzoness
` rÚcalculate_pnoe_metricsz'ContextGenerator.calculate_pnoe_metrics©s1ø€à Ð  àˆð Ð (Ü!&Ð'7¸ Ñ'BÓ!CˆG à!%§¡Ð.DÑ!E×!IÑ!IÓ!KˆG à Ð /Ü(-Ð.>Ð?OÑ.PÓ(Qˆ %à(/° Ñ(:¸T×=NÑ=NÈxÑ=XÑ(Xˆ  Ð (Ü!&Ð'7¸ Ñ'BÓ!CˆG àÐ/Ü(-Ð.>¸|Ñ.LÓ(M˜ Ò"Ÿl™lÐ+;Ñ<×E Ø"Ÿl™l×.¨{Ñ; Ø(3Ð4FÑ(G˜ ÒŸ,™,Ð'7Ñ8×AˆŸ,™,×*¨;Ñ7ˆKØ!,Ð-=Ñ!>ˆG Ø$/Ð0BÑ$CˆG  Ð .Ü',Ð-=¸oÑ-NÓ'OˆG Ð/Ü(-Ð.>¸|Ñ.LÓ(M˜ Ò"Ÿl™l¨>Ñ:×C Ø"Ÿl™l×.¨{Ñ; Ø(3Ð4FÑ(G˜ ÒŸ,™, ~Ñ?ˆKØŸ,™,×*¨;Ñ7ˆKØ'2°>Ñ'BˆG $Ø$/Ð0BÑ$CˆG  Ð -¨eÑ4ˆGEŠNà×.‰FˆCØ ˆGE‰Nà Ð -¨eÑ4ˆGEŠNà×.‰FˆAˆsØ ˆGE‰Nô ÓG¼5ÀÀA¼;Ó ˜1˜a[Ø! !  D˜>ØÐ/Ø(8¸Ñ(BG˜HÒˆðŸ,™, ~Ñ?ˆKØŸ,™,×*¨;Ñ7ˆKØ×˜ ¨¡° óˆEð
N‰N˜ ˆrcóØ|jd|jdkD}||j}d}t|«dkDr-|d}|jj|}|d|d|ddœ}|jd j «}|j «}|j «}d} t
j|«r(|jj|}
|
d|
d|
2025-11-21 09:23:13 +01:00
ddœ} || fS)
zDetect VT1 and VT2 thresholdsÚ CHO_smoothedrNrrÚSpeedúT(sec))Ú HeartRaterÚTimezVE(l/min)_smoothed)r ÚindexÚlenrqÚdiffrŽrrt) rÚ conditionÚcrossover_indicesrƒÚvt1_idxÚvt1_rowÚve_slopeÚsecond_derivativeÚvt2_idxr„Úvt2_rows rrz#ContextGenerator._detect_thresholds÷sà—LL Ñ0°4·<±<ÀÑ3OÑOˆ Ø% àˆÜ Ð Ó ! AÒ Ñ*ˆ—ll×& /ˆ$Ð%7Ñ  Ñ Ñˆ —<<Ð 4Ñ5×<ˆØ$ŸM™M›OÐØàˆÜ
2025-11-21 09:23:13 +01:00
8‰8 Ø—ll×& /ˆ$Ð%7Ñ  Ñ ÑˆCð Cˆxˆrr„r—cóÎi}|r®|r¬|ddz
}|d}|d}|ddz
}|ddz} t|«dt|«d|d<t|«dt|d«d|d<t|«dt|«d|d <t|«dt| «d|d
<t| «d |d <|Sd
|jdz
}
2025-11-21 09:23:13 +01:00
t|
dz«dt|
2025-11-21 09:23:13 +01:00
dz«d|d<t|
dz«dt|
2025-11-21 09:23:13 +01:00
dz«d|d<t|
dz«dt|
dz«d|d <t|
dz«dt|
dz«d|d
<t|
2025-11-21 09:23:13 +01:00
dz«d |d <|S)z.Calculate heart rate zones based on thresholdsrér*ÚbpmÚ zone1_bpmÚ zone2_bpmÚ zone3_bpmÚ zone4_bpmz+bpmÚ zone5_bpméÜrMgš™™™™™á?gÍÌÌÌÌÌä?gè?ç333333ë?gffffffî?)r]r) rr„r—r™Ú zone_1_startÚ zone_2_startÚ zone_3_startÚ zone_4_startÚ zone_5_startÚmax_hrs rrz$ContextGenerator._calculate_hr_zonesðˆÙ &Ð'9Ñ:¸?ˆ&Ð'9Ñ:ˆ˜+ˆ˜{Ñ+¨bÑ0ˆLؘ+¨bÑ0ˆLä$'¨ Ó$5Ð#6°a¼¸LÓ8IÐ7JÈ#Ð!NˆE Ü$'¨ Ó$5Ð#6°a¼¸ Ñ<LÓ8MÐ7NÈcÐ!RˆE Ü$'¨ Ó$5Ð#6°a¼¸LÓ8IÐ7JÈ#Ð!NˆE Ü$'¨ Ó$5Ð#6°a¼¸LÓ8IÐ7JÈ#Ð!NˆE Ü$'¨ Ó$5Ð#6°dÐ!;ˆE ðˆ ð
˜4×,¨UÑ3ˆFÜ$'¨°©
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
Ó$6Ð#7°tÐ!<ˆE ؈ rÚ pnoe_metricscóx|jdj«}tdt|j«dz«}|j |d¬«j «}|dk}||j }d}d}t|«dkDr7|d} |jj| }
t|
d«}|jd«rú|røtdd «D cgc]} |jd
| d d «Œ} } t| d«D\} }
|
sŒ |
jd
d «j«}d|vrc|jd«}t|«dk(sŒM t|d«t|djdd ««}}||cxkr|kr
nnd| }n0Œd|vsŒ• t|jdd ««}||k\rd| }nŒ¾|jdj«}|j |d¬«j «}|dk}||j }d}d}t|«dkDr7|d} |jj| }
t|
d«}|jd«rú|røtdd «D cgc]} |jd
| d d «Œ} } t| d«D\} }
|
sŒ |
jd
d «j«}d|vrc|jd«}t|«dk(sŒM t|d«t|djdd ««}}||cxkr|kr
nnd| }n0Œd|vsŒ• t|jdd ««}||k\rd| }nŒ¾|xsd|xsd|xsd|xsddœScc} w#t$rYŒƒwxYw#t$rYŒ“wxYwcc} w#t$rYŒ wxYw#t$rYŒwxYw)z.Calculate VO2 Pulse and VO2 Breath drop pointszVO2 Pulse_smoothedr.ér/rNrr†r‡rEéú+zZone zVO2 Breath_smoothedé´zZone 4é­zZone 3)Úvo2_pulse_drop_bpmÚvo2_pulse_drop_zoneÚvo2_breath_drop_bpmÚvo2_breath_drop_zone)r rr7r8rqr]r\rÚ enumeraterprrÚsplitr5)rÚvo2_pulse_sloper0Úvo2_pulse_slope_smoothedÚ
mask_pulseÚdrop_indices_pulserÄÚdrop_idxÚdrop_rowrŠr™Úzone_strÚ
zone_cleanÚpartsÚstartÚendÚvo2_breath_slopeÚvo2_breath_slope_smoothedÚ mask_breathÚdrop_indices_breathrÆs rÚ_calculate_vo2_drop_pointsz+ContextGenerator._calculate_vo2_drop_points/s>ðŸ,™,Ð';Ñ<×CˆÜ˜DŸL™LÓ)¨QÑ/ˆØ#2×#:Ñ#:Ø $;ó$
ç
‰$
Ñ2ˆ
Ø
ÑàØÜ Ð "  )¨!Ñ,ˆ—||×Ñ1ˆHÜ!$ XÐ.@Ñ%AÓ!BÐ à×Ñ  Ô,Ñ1CÜGLÈQÐPQÄ{ÓSÁ{À!˜×)¨D°°°4¨.¸=À{ÐSÜ#,¨U°AÖ#6KAØ%-×%5Ñ%5°e¸RÓ%@×%FÑ%FÓ%H˜
Ø ,Ø$.×$4Ñ$4°SÓ$9˜" 5z¨Qð !)ä(+¨E°!©H«
Ü(+¨E°!©H×,<Ñ,<¸SÀ"Ó,EÓ(Fð,/ (-Ð0BÔ'IÀcÕ'IØ@EÀaÀS¸kÐ(;Ù(-øð! %Ü(+¨J×,>Ñ,>¸sÀBÓ,GÓ(H Ø#5¸Ò#>Ø<AÀ!À¸+Ð$7Ù$)ð$?ð)$7ð6 Ÿ<™<Ð(=Ñ>ר$4×$<Ñ$<Ø %=ó%
ç
‰$
0°1Ñ4ˆ Ø)¨+Ñ6×àØÜ Ð #  *¨1Ñ-ˆ—||×Ñ1ˆHÜ"% hÐ/AÑ&BÓ"CÐ à×Ñ  Ô,Ñ1DÜGLÈQÐPQÄ{ÓSÁ{À!˜×)¨D°°°4¨.¸=À{ÐSÜ#,¨U°AÖ#6KAØ%-×%5Ñ%5°e¸RÓ%@×%FÑ%FÓ%H˜
Ø ,Ø$.×$4Ñ$4°SÓ$9˜" 5z¨Qð !)ä(+¨E°!©H«
Ü(+¨E°!©H×,<Ñ,<¸SÀ"Ó,EÓ(Fð,/ (-Ð0CÔ'JÀsÕ'JØAFÀqÀc¸{Ð(<Ù(-øð! %Ü(+¨J×,>Ñ,>¸sÀBÓ,GÓ(H Ø#6¸%Ò#?Ø=BÀ1À#¸;Ð$8Ù$)ð$@ð)$7ð6#5Ò";¸Ø#6Ò#B¸(Ø#6Ò#=¸#Ø$8Ò$D¸
ð
ùòQTøô(2ò!)Ú$(ð!)ûô$.ò%Ú $ð%üò*Tøô(2ò!)Ú$(ð!)ûô$.ò%Ú $ð%úsTÃM2Å?M7Æ%NÉ1NË*?NÌ2%N,Í7 NÎNÎ NÎNÎ N)Î(N)Î, N9Î8N9c óì|jdj«}|jj|}|jdd«}|jdd«}d|jdz
}|dkDr||z dznd}d}|jj
D]=} |jj| d f|jj| dfkDsŒ;| }nd}
d} |6|jj|} t
| d
«}
|dkDr|
|z dznd} |jd d«}
d |vr|jd d
«nd
}|dd|ddt
|«dd|
xsdd| xsddd|
xsdd|
dd|dddœS)z,Calculate fat metabolism metrics for page 11rr€rrrMr&NrœrrÚInclineg.2fz Kcals/minz.0fz% of Max Heart Rateú bpmz*Optimal 10-12Kcals/minuter¯é3zbpm at a speed of ú.1fzmph and incline of rj)r€Úfat_max_heart_rateÚ fat_max_bpmÚfat_max_optimalÚ
crossover_bpmÚcrossover_heart_rateÚfat_metabolism_note)r rqr\rr])rrr—r€rÚfat_max_heart_rate_pctÚ
crossover_idxÚidxrãÚcrossover_heart_rate_pctÚ
crossover_rowÚ
fat_max_speedÚfat_max_inclines rÚ!_calculate_fat_metabolism_metricsz2ContextGenerator._calculate_fat_metabolism_metrics“à—ll ;ˆ Ø—ll×& 3ˆ à$׸<ˆ
Ø!×% l°AÓ6ˆ
ØÑØ@FÈÂ
 *¨vÑ"5¸Ò";ÐPQÐðˆ
Ø—<%ˆCà × Ñ   nÐ!4Ñ—,,×" Ð#6Ñ!$
Ùð
ˆ
Ø#'Ð Ø Ð  ŸL™L×,¨]Ñ;ˆMÜ 
Ð.@Ñ AÓBˆMà28¸1²* Ñ'¨#Ò-À!ð
¨°Ó3ˆ
à/8¸KÑ/GˆKO‰O˜I  +ÈSð ð
!.¨cÐ2°)Ð<Ø%;¸CÐ$@Ð@SÐ"TÜ! *.¨dÐ;Ø -Ò 4°Ð5°SÐ9Ø'?Ò'EÀ2ÀcÐ&JÐJ]Ð$^Ø&3Ò&:°sÐ%;Ð;MÈmÐ\_ÐM`Ð`sðuDðEHðtIðIJð$Kñ
ð
rcó”|jdj«}|jj|df}|jj|df}|j|jd|kDj«}t |«dk(r dddddd d
œS|d z}||d|k}t |«dkDr%|j
d d}|dkDr ||z
|z d
znd}nd}|dz} |jj|df}
||d| k} t | «dkDr%| j
d d} |
dkDr |
| z
|
z d
znd}
nd}
2025-11-21 09:23:13 +01:00
|dz}|jj|df}||d|k}t |«dkDr%|j
d d}|dkDr ||z
|z d
znd}nd}dt
|«ddt
|
2025-11-21 09:23:13 +01:00
«ddt
|«dd
œS)z&Calculate recovery metrics for page 11rrz
(1 minute)z33%z
(2 minute)z65%z (2.5 minute)z76%)Úcardiac_recovery_timeÚcardiac_recovery_percentageÚmetabolic_recovery_timeÚmetabolic_recovery_percentageÚbreath_recovery_timeÚbreath_recovery_percentageé<éÿÿÿÿr&é!éxzVCO2(ml/min)_smoothedéAé–zBF(bpm)_smoothedéLrj)r rqÚcopyr¢rZr])rÚpeak_idxÚpeak_hrÚ peak_timeÚ recovery_dfÚ one_min_timeÚ one_min_rowÚ
one_min_hrÚcardiac_recovery_pctÚ two_min_timeÚ peak_vco2Ú two_min_rowÚ two_min_vco2Úmetabolic_recovery_pctÚtwo_five_min_timeÚpeak_bfÚtwo_five_min_rowÚtwo_five_min_bfÚbreath_recovery_pcts rÚ_calculate_recovery_metricsz,ContextGenerator._calculate_recovery_metricsÀs\ð—<<Ð 2Ñ3×<ˆØ—,,×" 8Ð-?Ð#?Ñ@ˆØ—LL×$ X¨xÐ%7Ñ8ˆ ð—ll 4§<¡<°Ñ#9¸IÑ#EÑF× ä ˆ{Ó ˜ à)5Ø/4Ø+7Ø16Ø(6Ø.3ñ
ð
ð! 2~ˆ Ø! +¨hÑ"7¸<Ñ"GÑHˆ Ü ˆ ˜ Ø$×)¨"Ñ-Ð.@ÑAˆJà<CÀaºK'˜&¨'Ñ1°CÒ7ÈQñ
2025-11-21 09:23:13 +01:00
$&Ð ð! 3ˆ Ø—L‘L×$ XÐ/FÐ%FÑGˆ Ø! +¨hÑ"7¸<Ñ"GÑHˆ Ü ˆ ˜ Ø&×+¨BÑ/Ð0GÑHˆLàBKÈaÂ-)˜*¨iÑ7¸=ÐUVñ
&(Ð ™OÐØ—,,×" 8Ð-?Ð#?Ñ@ˆØ& {°8Ñ'<Ð@QÑ'QÑÜ ÐÓ   3°BÑ7Ð8JÑKˆOàAHÈ1Â'˜+¨wÑ6¸Ò<ÐRSñ
ð#%Ð ð&2Ü.1Ð2FÓ.GÐ-HÈÐ+JØ'3Ü03Ð4JÓ0KÐ/LÈAÐ-NØ$2Ü-0Ð1DÓ-EÐ,FÀaÐ*Hñ

2025-11-21 09:23:13 +01:00
ð
rc
óâ|jjd«}|dj«}|jj dd«}|jj dd«j «}d|cxkrdkrnnd}n$d |cxkrd
krnnd }nd |cxkrd
krnnd}nd}|dk(r ddddddddœ}n
ddddddddœ}t
2025-11-21 09:23:13 +01:00
|«d||d|d|d|d|d|d|ddœ S) z0Calculate resting heart rate metrics for page 11érrMrPÚfemaleéé#z26-35é$é-z36-45é.é7z46-55z82bpm +z75-81bpmz71-74bpmz66-70bpmz62-65bpmz55-61bpmz44-54bpm)ÚpoorÚ below_avgÚaverageÚ above_avgÚgoodÚ excellentÚathleter¯rrrrrrr) Úresting_heart_rateÚ hr_age_rangeÚhr_poorÚ hr_below_avgÚ
hr_averageÚ hr_above_avgÚhr_goodÚ hr_excellentÚ
hr_athlete)r Úheadr8rr\r^r])rÚ
rest_phaseÚ
resting_hrrMrPÚ age_rangeÚ hr_rangess rÚ%_calculate_resting_heart_rate_metricsz6ContextGenerator._calculate_resting_heart_rate_metricss6ð—\\×& *ˆ
ØÐ 2Ñ
à×Ñ×# E¨2Ó.ˆØ×"×& Ó:×Bˆð Œ?˜‰IØ
3Œ_˜"‰IØ
3Œ_˜"‰Iàˆ  à‰Iðˆ&)¨£_Ð$5°SÐ"9Ø  Ñ% # %   Ñ% # 

ð
rraÚ height_cmÚ age_yearsÚsexcóvd|zd|zzd|zz
}|j«jd«r|dzS|dz
S)a:Calculate predicted RMR using Mifflin St Jeor equation
Args:
weight_kg: Weight in kilograms
height_cm: Height in centimeters
age_years: Age in years
sex: 'male' or 'female'
Returns:
Predicted RMR in kcal/day
g$@g@gmg d@)r^Ú
startswith)rrar/r0r1Úbases rÚ_mifflin_st_jeorz!ContextGenerator._mifflin_st_jeor5sIð Ñ"2Ñ2°S¸9±_ÑDˆØ 9‰9;× !  ˜# à˜% rÚmeasured_kcal_dayÚpredicted_kcal_daycóp||z }|dkrd}||fS|dkrd}||fS|dkrd}||fS|dkrd}||fSd }||fS)
aClassify metabolic rate relative to prediction
2025-11-21 09:23:13 +01:00
Args:
measured_kcal_day: Measured RMR in kcal/day
predicted_kcal_day: Predicted RMR in kcal/day
2025-11-21 09:23:13 +01:00
Returns:
Tuple of (classification label, ratio)
gffffffæ?z very slowgÍÌÌÌÌÌì?Úslowgš™™™™™ñ?rgÍÌÌÌÌÌô?Úfastz very fastrˆ)rr7r8ÚratioÚlabels rÚ_classify_metabolismz%ContextGenerator._classify_metabolismGs†ð"Ð$6Ñ6ˆà 4Š<؈eˆ|ÐðTŠ\؈Eðeˆ|ÐðdŠ]؈Eð eˆ|Ðð dŠ]؈Eðeˆ|Ðð ˆEàeˆ|Ðrcó¼|jdj«j«}||dkr td«t t d|z ««}|dkrd}|S)zDerive number of samples that represent about 2 minutes
Returns:
Number of samples in a 2-minute window
rzInvalid time step in T(sec)g^@r.)r Úmedianr5r]Úround)rÚdtÚsampless rÚ_find_sampling_windowz&ContextGenerator._find_sampling_window`s_ð \‰\˜
#×
2025-11-21 09:23:13 +01:00
*×
2025-11-21 09:23:13 +01:00