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

313 lines
51 KiB
Plaintext
Raw Normal View History

Ë
2025-11-28 11:44:37 +01:00
X)i ýãóHdZddlmZddlmZmZmZmZddlZGdd«Z y)
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-26 22:17:30 +01:00
é)Údatetime)ÚAnyÚDictÚOptionalÚTupleNcóÖeZdZdZdZ d(dededeedeefdZd „Zd
2025-11-24 19:37:28 +01:00
ed e fd Z
2025-11-26 22:17:30 +01:00
d)d
ee d e fdZ d)d
2025-11-24 19:37:28 +01:00
ee d e fdZ d e
ee ee ffdZdee dee dej d e fdZde d e fdZde d e fdZd e fdZd e fdZdeded efdZdededed efdZde d e fdZdeded e fd „Zd!ededed efd"„Zd e fd#„Z d*d
ed$e eefd
2025-11-21 12:15:42 +01:00
ee d%eed&ed e ee ff d'„Z y)+ÚContextGeneratorz&Generate context data for report pagescóJd|_d|_d|_d|_i|_y©N)Úpnoe_dfÚ
spirometry_dfÚseca_dfÚoxygenation_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_pathÚoxygenation_pathcó$tj|d¬«|_tj|«|_|rtj|«|_nd|_|rtj|d¬«|_nd|_|j«y)zLoad all required datasetsú;)Ú delimiterNi½)Úskiprows)ÚpdÚread_csvr r
2025-11-24 19:37:28 +01:00
Ú
read_excelrrÚ_preprocess_pnoe_data)rrrrrs rÚ load_datazContextGenerator.load_dataslô—{{ 9¸ÔŒ ÜŸ[™[¨ÓÔÙ ÜŸ=™=¨Ó3ˆDˆDŒLÙ ä"$§+¡+Ð.>ÈÔ"Mˆ à"&ˆ Ø ×$rcóú|jjD]2} tj|j|«|j|<Œ4|jd|jdz |jd<|jd|jdz |jd<|jd|jdzdz |jd <|jd|jd
2025-11-24 19:37:28 +01:00
zdz |jd <d }gd
¢}|D]Y}||jjvsŒ|j|j
2025-11-21 12:15:42 +01:00
|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)zCARBS(%)édÚCHOúFAT(%)ÚFATé
)
2025-11-24 19:37:28 +01:00
r#z VCO2(ml/min)r$zVT(l)r&z VE(l/min)r%r'r*r,é©ÚwindowÚ min_periodsÚ _smoothedN)r ÚcolumnsrÚ
2025-11-21 12:15:42 +01:00
to_numericÚ
2025-11-24 19:37:28 +01:00
ValueErrorÚ TypeErrorÚrollingÚmean)rÚcolÚ window_sizeÚcolumns_to_smooths rr z&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-24 19:37:28 +01:00
L‰L˜Ñ (¨4¯<©<¸Ñ+AÑ AÀCÑ 
ðˆ ò 
Ðó%ˆCØd—l‘l×—L‘L Ñ-°[ÈaÐ  ˜u IÐ%øô=¤ Ð
Úð
ús/E'Å'E:Å9E:Ú patient_nameÚreturnc
ó |jI|j|jdjj|dd¬«}|jsù|jd}t |j
dd««}t |j
dd««}|j
dd«d |j
dd«|j
dd«|j
dd«t|j
2025-11-24 19:37:28 +01:00
d
d««|j
2025-11-24 19:37:28 +01:00
d d«||j
2025-11-21 14:15:29 +01:00
d d«j«|||zd
z dz|d|d
z z
2025-11-24 19:37:28 +01:00
zdzdœ
|_ |jSd|jvr_d|jvrQ|jd}|jd}||zd
z dz|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)g3܀ϣ@r.)
ÚnameÚ
first_nameÚ last_nameÚageÚheightÚweightÚgenderÚfat_percentageÚ fat_mass_lbsÚ
lean_mass_lbsrOrQrRrS)
rÚstrÚcontainsÚemptyÚilocÚfloatÚgetÚintÚlowerr)rr<Ú patient_dataÚrowÚ weight_kgÚfat_pcts rÚextract_patient_infoz%ContextGenerator.extract_patient_infoWà <‰<Ñ Ÿ<™<Ø ˜(×  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×;Ø&-Ø$-°Ñ$7¸#Ñ$=ÀÑ$GØ%.°!°gÀ±mÑ2CÑ%DÀwÑ%Nñ %Ô!ð(× Ñ Ð ð˜×
*Ð/?À4×CTÑCTÑ/TØ×)¨(Ñ3ˆ×'Ð(8Ñ9ˆGØ09¸GÑ0CÀcÑ0IÈGÑ0SˆD× Ñ ˜nÑ ˜Q ¨3¡Ñ/°'Ñ
× Ñ ˜oÑ × Ñ Ð rÚmetric_overridescóv|i}i}dD]}|j«jdd«jdd«}|d|vrt||d«||d<n†|jj|jdj
j
«|k(}|js9|djd }tj|«r t|«||d<|d
|vrt||d
«||d
2025-11-26 22:17:30 +01:00
<ο|jj|jdj
j
«|k(}|jrŒG|d jd }tj|«sŒp t|«||d
<Œ„|S#ttf$rYŒ¿wxYw#ttf$rYŒ®wxYw) z$Calculate spirometry-related metrics)ÚFVCÚFEV1z FEV1/FVC%ú_pctÚ_bestÚ
ParametersÚBestrÚ_predz%Pred.)
r[ÚreplacerXr
ÚlocrTÚstriprVÚvaluesrÚnotnar5r6)rraÚmetricsÚparamÚ param_keyr]Úvalues rÚcalculate_spirometry_metricsz-ContextGenerator.calculate_spirometry_metricszð Ð  àˆÜ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-26 22:17:30 +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
2025-11-21 09:23:13 +01:00
|}|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
«\}} | |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Úiras €rú <genexpr>z:ContextGenerator.calculate_pnoe_metrics.<locals>.<genexpr>ås øèø€ÐG¹;°aaˆ~Ð!1Ô1¹;ùsƒr.ér„) rXr ÚmaxrÚidxmaxrnÚ_detect_thresholdsÚanyÚrangeÚ_calculate_hr_zonesÚupdate)
2025-11-26 22:17:30 +01:00
rrarrÚ peak_vt_idxÚ peak_vt_rowÚ fat_max_idxÚ fat_max_rowr€rfrr‡Ú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ð
2025-11-21 09:23:13 +01:00
N‰N˜ ˆrcóh|jd|jdkD}||j}d}t|«dkDru|D]p}t|jj|dd|jj|ddkD«sŒF|}|jj|}|d|d|ddœ}n|jd j «}|j «}|j
«} d}
tj| «r(|jj| } | d| d| ddœ}
||
2025-11-24 19:37:28 +01:00
fS)
z7Detect VT1 and VT2 thresholds (matching notebook logic)Ú CHO_smoothedrNrr|ÚSpeedúT(sec))Ú HeartRateršÚTimezVE(l/min)_smoothed) r ÚindexÚlenÚallrnÚdiffrrrq) rÚ conditionÚcrossover_indicesr€ÚidxÚvt1_idxÚvt1_rowÚve_slopeÚsecond_derivativeÚvt2_idxrÚvt2_rows rz#ContextGenerator._detect_thresholdsôsQð—LL Ñ0°4·<±<ÀÑ3OÑOˆ Ø% àˆÜ Ð Ó ! AÒ (ÜØ—LL×$ S *¨>Ñ—ll×& s ,¨^Ñð""Ÿl™l×.¨wÑ7Gà%,Ð-?Ñ%@Ø!(¨Ñ!1Ø '¨Ñ 1ñ
ð—<<Ð 4Ñ5×<ˆØ$ŸM™M›OÐØàˆÜ
8‰8 Ø—ll×& /ˆ$Ð%7Ñ  Ñ ÑˆCð Cˆrr€rr”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
}
t|
dz«dt|
dz«d|d<t|
2025-11-24 19:37:28 +01:00
dz«dt|
dz«d|d<t|
2025-11-24 19:37:28 +01:00
dz«dt|
dz«d|d <t|
dz«dt|
2025-11-24 19:37:28 +01:00
dz«d|d
<t|
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î?)rZr) rr€rr”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 ðˆ ð
2025-11-26 22:17:30 +01:00
˜4×,¨UÑ3ˆFÜ$'¨°©
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
2025-11-24 19:37:28 +01:00
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
Ó$6Ð#7°q¼¸VÀd¹]Ó9KÐ8LÈCÐ!PˆE Ü$'¨°©
2025-11-24 19:37:28 +01:00
Ó$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\} }
|
2025-11-24 19:37:28 +01:00
sŒ |
2025-11-21 12:15:42 +01:00
jd
d «j«}d|vrc|jd«}t|«dk(sŒM t|d«t|djdd ««}}||cxkr|kr
2025-11-21 09:23:13 +01:00
nnd| }n0Œd|vsŒ• t|jdd ««}||k\rd| }nŒ¾|jdj«}|j |d¬«j «}|dk}||j }d}d}t|«dkDr7|d} |jj| }
2025-11-21 12:15:42 +01:00
t|
2025-11-21 13:23:38 +01:00
d«}|jd«rú|røtdd «D cgc]} |jd
2025-11-21 12:15:42 +01:00
| d d «Œ} } t| d«D\} }
|
2025-11-21 09:23:13 +01:00
sŒ |
2025-11-21 12:15:42 +01:00
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/rNr|r‰r„rEr­éú+zZone zVO2 Breath_smoothedé´úZone 4é­úZone 3)Úvo2_pulse_drop_bpmÚvo2_pulse_drop_zoneÚvo2_breath_drop_bpmÚvo2_breath_drop_zone)r r7r8rnrZrYÚ enumeratermroÚsplitr5)rÚvo2_pulse_sloper0Úvo2_pulse_slope_smoothedÚ
2025-11-21 09:23:13 +01:00
mask_pulseÚdrop_indices_pulserÅÚdrop_idxÚdrop_rowr‡rÚzone_strÚ
2025-11-21 12:15:42 +01:00
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_points4s>ðŸ,™,Ð';Ñ<×CˆÜ˜DŸL™LÓ)¨QÑ/ˆØ#2×#:Ñ#:Ø $;ó$
2025-11-26 22:17:30 +01:00
ç
2025-11-24 19:37:28 +01:00
‰$
2025-11-26 22:17:30 +01:00
Ñ2ˆ
Ø
2025-11-21 12:15:42 +01:00
ÑàØÜ Ð "  )¨!Ñ,ˆ—||×Ñ1ˆHÜ!$ XÐ.@Ñ%AÓ!BÐ à×Ñ  Ô,Ñ1CÜGLÈQÐPQÄ{ÓSÁ{À!˜×)¨D°°°4¨.¸=À{ÐSÜ#,¨U°AÖ#6KAØ%-×%5Ñ%5°e¸RÓ%@×%FÑ%FÓ%H˜
2025-11-21 13:23:38 +01:00
Ø ,Ø$.×$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×$<Ñ$<Ø %=ó%
2025-11-26 22:17:30 +01:00
ç
2025-11-21 13:23:38 +01:00
‰$
2025-11-24 19:37:28 +01:00
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˜
2025-11-21 14:15:29 +01:00
Ø ,Ø$.×$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¸
2025-11-21 12:15:42 +01:00
ð
2025-11-21 14:15:29 +01:00
ùò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
2025-11-26 22:17:30 +01:00
«}
2025-11-21 14:15:29 +01:00
|dkDr|
2025-11-21 12:15:42 +01:00
|z dznd} |jd d«}
2025-11-24 19:37:28 +01:00
d |vr|jd d
«nd
2025-11-26 22:17:30 +01:00
}|dd|ddt
2025-11-21 12:15:42 +01:00
|«dd|
2025-11-26 22:17:30 +01:00
xsdd| xsddd|
2025-11-21 12:15:42 +01:00
xsdd|
dd|dddœS)z,Calculate fat metabolism metrics for page 11rr}rr~r´rMr)Nr™r|ÚInclineg.2fz Kcals/minz.0fz% of Max Heart Rateú bpmz*Optimal 10-12Kcals/minuter®é3zbpm at a speed of ú.1fzmph and incline of rg)r}Úfat_max_heart_rateÚ fat_max_bpmÚfat_max_optimalÚ
crossover_bpmÚcrossover_heart_rateÚfat_metabolism_note)r rrnrYrrZ)rr“r”r}r~Úfat_max_heart_rate_pctÚ
crossover_idxr¤Úcrossover_heart_rate_pctÚ
crossover_rowÚ
2025-11-26 22:17:30 +01:00
fat_max_speedÚfat_max_inclines rÚ!_calculate_fat_metabolism_metricsz2ContextGenerator._calculate_fat_metabolism_metrics˜à—ll ;ˆ Ø—ll×& 3ˆ à$׸<ˆ
2025-11-21 14:15:29 +01:00
Ø!×% l°AÓ6ˆ
2025-11-21 12:15:42 +01:00
ØÑØ@FÈÂ
 *¨vÑ"5¸Ò";ÐPQÐðˆ
Ø—<%ˆCà × Ñ   nÐ!4Ñ—,,×" Ð#6Ñ!$
Ùð
2025-11-24 19:37:28 +01:00
ˆ
2025-11-21 14:15:29 +01:00
Ø#'Ð Ø Ð  ŸL™L×,¨]Ñ;ˆMÜ 
2025-11-21 12:15:42 +01:00
Ð.@Ñ 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
2025-11-21 14:15:29 +01:00
œS|d z}||d|k}t |«dkDr%|j
d d}|dkDr ||z
2025-11-21 12:15:42 +01:00
|z d
2025-11-21 14:20:15 +01:00
znd}nd}|dz} |jj|df}
2025-11-21 14:15:29 +01:00
||d| k} t | «dkDr%| j
2025-11-24 19:37:28 +01:00
d d} |
2025-11-21 12:15:42 +01:00
dkDr |
2025-11-21 12:49:36 +01:00
| z
|
2025-11-21 12:15:42 +01:00
z d
znd}
2025-11-21 12:49:36 +01:00
nd}
2025-11-21 12:15:42 +01:00
|dz}|jj|df}||d|k}t |«dkDr%|j
2025-11-21 12:49:36 +01:00
d d}|dkDr ||z
2025-11-26 22:17:30 +01:00
|z d
znd}nd}dt
2025-11-21 12:49:36 +01:00
|«ddt
|
«ddt
|«dd
2025-11-26 22:17:30 +01:00
œS)z&Calculate recovery metrics for page 11r|rrz
(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é–úBF(bpm)_smoothedéLrg)r rrnÚcopyrŸrWrZ)rÚpeak_idxÚpeak_hrÚ peak_timeÚ recovery_dfÚ one_min_timeÚ one_min_rowÚ
2025-11-24 19:37:28 +01:00
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ñ
2025-11-21 12:49:36 +01:00
ð
ð! 2~ˆ Ø! +¨hÑ"7¸<Ñ"GÑHˆ Ü ˆ ˜ Ø$×)¨"Ñ-Ð.@ÑAˆJà<CÀaºK'˜&¨'Ñ1°CÒ7ÈQñ
2025-11-24 19:37:28 +01:00
$&Ð ð! 3ˆ Ø—L‘L×$ XÐ/FÐ%FÑGˆ Ø! +¨hÑ"7¸<Ñ"GÑHˆ Ü ˆ ˜ Ø&×+¨BÑ/Ð0GÑHˆLàBKÈaÂ-)˜*¨iÑ7¸=ÐUVñ
2025-11-21 12:15:42 +01:00
&(Ð ™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ñ

ð
rc
2025-11-26 22:17:30 +01:00
óâ|jjd«}|dj«}|jj dd«}|jj dd«j «}d|cxkrdkrnnd}n$d |cxkrd
2025-11-21 12:15:42 +01:00
krnnd }nd |cxkrd
2025-11-26 22:17:30 +01:00
krnnd}nd}|dk(r ddddddddœ}n
ddddddddœ}t
|«d||d|d|d|d|d|d|ddœ S) z0Calculate resting heart rate metrics for page 11ér|rMrPÚfemaleéé#ú26-35é$é-ú36-45é.é7ú46-55z82bpm +z75-81bpmz71-74bpmz66-70bpmz62-65bpmz55-61bpmz44-54bpm)ÚpoorÚ below_avgÚaverageÚ above_avgÚgoodÚ excellentÚathleter®rrrr r!r"r#) Úresting_heart_rateÚ hr_age_rangeÚhr_poorÚ hr_below_avgÚ
hr_averageÚ hr_above_avgÚhr_goodÚ hr_excellentÚ
hr_athlete)r Úheadr8rrYr[rZ)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Ø  Ñ% # %   Ñ% # 

ð
rrMrPcónd|cxkrdkrnnd}nNd|cxkrdkrnnd}n=d|cxkrdkrnnd }n,d
|cxkrd krnnd }nd
|cxkrdkrnnd}n
|dkDrd}nd}ddddddddœddddddddœddddd dd!dœd"d#d$dddd%dœd"d#d$dd dd&dœd"d'dd(d dd)dœd*œd+d,ddd-d.d/dœd+d0d1d2d-d3d4dœdd5d6d7d8d9d:dœd"d'd;d<d=d>d?dœd+d@dAd<dBdCdDdœdEdFddd-d.dGdœd*œdHœ}|j«jdI«rdJndK}|||}i}|j«D]\}\} }
|
€ | dL||<Œ| dM|
dN||<Œ |||dOœS)PzÜ
Calculate Resting Heart Rate reference table data.
Args:
age: Patient age
gender: Patient gender
Returns:
Dictionary containing age_range and ranges
ééú18-25rrrrrrrrré8ú56-65ú65+)éUN)éOr:)éJr;)éFr<)éBr=)é=r>)é(r?)ÚPoorú
Below AverageÚAverageú
2025-11-24 19:37:28 +01:00
Above AverageÚGoodÚ ExcellentÚAthlete)éSN)éMrH)éIrI)éErJ)rK))é*)r=)r)éTN)éNrM)r<rN)é0r?)é2)rIrM)r=rJ)é4)r6rrrr8r9)éRN)r<rR)é>r>)r7rS)r@r7)éKrR)éGrT)r>rU)rrS)é,r)rH)rU)éCrU)é?rW)é9rX)é/rY)éHrI)éDr[)é@r\)é:r])é1r^)rR)r[)rSr\)rYrS)rY)éPN)r<r`)rQr7)ÚmalerÚmrarzbpm +r­©r0ÚrangesÚ
2025-11-26 22:17:30 +01:00
raw_ranges)r[Ú
2025-11-21 14:15:29 +01:00
startswithÚitems) rrMrPr0Ú rhr_chartÚ
gender_keyrdÚformatted_rangesÚcategoryÚmin_valÚmax_vals rÚ_calculate_rhr_table_dataz*ContextGenerator._calculate_rhr_table_data:s]ð Œ?˜‰IØ
3Œ_˜"‰IØ
3Œ_˜"‰IØ
2025-11-26 22:17:30 +01:00
3Œ_˜"‰IØ
3Œ_˜"‰IØ
2ŠX؉Iàˆ 'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øñ]7ðt'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øð'Ø%-Ø'Ø%-Ø$Ø!)Øñ]7ñsq
ˆ ðf &Ÿ|™|~×8¸Ô=VÀ8ˆ
ؘ& 1ˆðÐØ,2¯L©L®NÑ (ˆHÑ(w ØˆØ07¨y¸Ð->Ð  Ò*à07¨y¸¸'¸À#Ð-FÐ  Ò-;ð ñ
ð
2025-11-21 12:49:36 +01:00
rÚrhrcó’|j||«}|d}|d\}}|||k\rydD]}||\}}||cxkr |ksŒ|cSŒy)z_Determine resting heart rate category based on value, age, and gender (matching notebook logic)rerA)rBrCrDrErFrGrG)rn) rrorMrPÚrhr_table_infordrlrmrks rÚ_determine_rhr_categoryz(ContextGenerator._determine_rhr_categoryÚsuà׸VÓØ  Ñ-ˆð" &™>ÑˆØ ˆ?˜s gš~Øó
ˆ &  ˆG˜' Óñ
ðrc óÌddl}|jd|jddzz |jd<|jdj«}|jj|}|j d«}|j d«}|r|siS|j |d d
z
2025-11-24 19:56:02 +01:00
«}|j |d «}|j |d «} |j |d d z
«}
|j |d «} |} |j |d «}
|
}| }|j |d d z«}d
|| fd||
fd| |fd|
|fd| |fg}gd¢}d}g}t
2025-11-24 19:37:28 +01:00
|«D]‡\}\}}}|jd |k\|jd |kz}|j|}t|«dt|«d}|jsú||ddkDd}|js}|j«}|j«}t||z
«dkr|dd}n
2025-11-26 22:17:30 +01:00
|dd|dd}||«\} }!||«\}"}#| |"k(r|!|#k(r
| d|!dd}$n|"d|#dd| d|!dd}$nd}d}$|dj«}%d |%dd!}&|d"j«d#z }'d$|'dd%}(|d&j«})d$t|)«d'||}*nd}d}$d}&d}(d(||}*|j||||$|&|(|*d)œ«ŒŠd*|iS)+zHCalculate detailed metrics for each heart rate zone based on actual datarNrr™g:Œ0âŽyE>Úfat_carb_ratior€rr|r-úZone 1úZone 2rÄúZone 5)zIdeal Range: 15-20 breathszIdeal Range: 20-25 breathszIdeal Range: 25-30 breathszIdeal Range: 30-35 breathszIdeal Range: 40+ breathscób|dkry|dz}d|z }t|«}t|dzdz«}||fS)z&Convert speed in mph to pace in min/kmr)rrgrPÂLÛ¿ù?rõr.)rZ)Ús_mphÚs_kmhÚp_minÚp_mÚp_ss rÚ
speed_to_pacez?ContextGenerator._calculate_zone_metrics.<locals>.speed_to_pace(sCà˜ŠzØØ˜G‘OˆEؘ‘JˆEÜe“*ˆu˜qy 'ˆ˜8ˆOrgš™™™™™¹?ràz mph
2% Inclineú02dz min/km Pacez
min/km Pacez -
2% Incliner(zAvg:
2025-11-24 19:37:28 +01:00
z
kcals/minuter*ézAvg: zg/min
Carb Utilizationrûz breaths
z-
)Ú zone_nameÚhr_bpmÚspeedÚpaceÚcaloriesÚcarbÚ breathingr)Úmathr rrnrYÚfloorrÉrZrVÚminrŠÚabsr8Úappend)+rr‰Úoptimal_fat_idxÚ optimal_rowr€rÚ
zone_1_endÚ
zone_2_endÚ
zone_3_endÚ
zone_4_endÚ
zone_5_endÚ
2025-11-21 13:23:38 +01:00
zones_listÚideal_breath_rangesr~Ú zone_datar‡rJÚmaskÚzone_dfÚ
hr_bpm_strÚ speed_seriesÚ min_speedÚ max_speedÚ speed_strÚ
min_pace_mÚ
min_pace_sÚ
2025-11-21 14:20:15 +01:00
max_pace_mÚ
2025-11-21 12:49:36 +01:00
max_pace_sÚpace_strÚavg_calsÚ calories_strÚ avg_carbs_gÚcarb_strÚ avg_breathsÚ
breath_strs+ rÚ_calculate_zone_metricsz(ContextGenerator._calculate_zone_metrics÷ãð*.¯©°nÑ)EØ L‰L˜Ñ (¨:Ñ *
ˆ П,™,Ð'7Ñ8×AˆØ—ll×& Ñ7ˆ ð×јuÓØ×јuÓá™#àˆIð—zz +Ð.@Ñ"AÀBÑ"FÓGˆ Ø—zz +Ð.@Ñ"AÓBˆ Ø—zz # kÑ"2Ó3ˆ Ø—zz # kÑ"2°RÑ"7Ó8ˆ Ø—zz # kÑ"2Ó3ˆ à!ˆ
2025-11-26 22:17:30 +01:00
Ø—ZZ  KÑ 0Ó1ˆ
Ø!ˆ
Ø!ˆ
Ø—Z‘Z  KÑ 0°2Ñ 5Ó6ˆ