skill-calorie 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/anomaly/common.d.ts +53 -0
- package/dist/analysis/anomaly/common.d.ts.map +1 -0
- package/dist/analysis/anomaly/common.js +69 -0
- package/dist/analysis/anomaly/common.js.map +1 -0
- package/dist/analysis/anomaly/diet.d.ts +8 -0
- package/dist/analysis/anomaly/diet.d.ts.map +1 -0
- package/dist/analysis/anomaly/diet.js +95 -0
- package/dist/analysis/anomaly/diet.js.map +1 -0
- package/dist/analysis/anomaly/exercise.d.ts +9 -0
- package/dist/analysis/anomaly/exercise.d.ts.map +1 -0
- package/dist/analysis/anomaly/exercise.js +116 -0
- package/dist/analysis/anomaly/exercise.js.map +1 -0
- package/dist/analysis/anomaly/index.d.ts +19 -0
- package/dist/analysis/anomaly/index.d.ts.map +1 -0
- package/dist/analysis/anomaly/index.js +51 -0
- package/dist/analysis/anomaly/index.js.map +1 -0
- package/dist/analysis/anomaly/overall.d.ts +13 -0
- package/dist/analysis/anomaly/overall.d.ts.map +1 -0
- package/dist/analysis/anomaly/overall.js +128 -0
- package/dist/analysis/anomaly/overall.js.map +1 -0
- package/dist/analysis/anomaly/overall2.d.ts +5 -0
- package/dist/analysis/anomaly/overall2.d.ts.map +1 -0
- package/dist/analysis/anomaly/overall2.js +94 -0
- package/dist/analysis/anomaly/overall2.js.map +1 -0
- package/dist/analysis/anomaly/weight.d.ts +8 -0
- package/dist/analysis/anomaly/weight.d.ts.map +1 -0
- package/dist/analysis/anomaly/weight.js +106 -0
- package/dist/analysis/anomaly/weight.js.map +1 -0
- package/dist/analysis/anomaly/weight2.d.ts +4 -0
- package/dist/analysis/anomaly/weight2.d.ts.map +1 -0
- package/dist/analysis/anomaly/weight2.js +59 -0
- package/dist/analysis/anomaly/weight2.js.map +1 -0
- package/dist/analysis/contraindications.d.ts +63 -0
- package/dist/analysis/contraindications.d.ts.map +1 -0
- package/dist/analysis/contraindications.js +121 -0
- package/dist/analysis/contraindications.js.map +1 -0
- package/dist/analysis/cross.d.ts +75 -0
- package/dist/analysis/cross.d.ts.map +1 -0
- package/dist/analysis/cross.js +283 -0
- package/dist/analysis/cross.js.map +1 -0
- package/dist/analysis/dashboard.d.ts +18 -0
- package/dist/analysis/dashboard.d.ts.map +1 -0
- package/dist/analysis/dashboard.js +48 -0
- package/dist/analysis/dashboard.js.map +1 -0
- package/dist/analysis/deficit.d.ts +44 -0
- package/dist/analysis/deficit.d.ts.map +1 -0
- package/dist/analysis/deficit.js +54 -0
- package/dist/analysis/deficit.js.map +1 -0
- package/dist/analysis/diet.d.ts +76 -0
- package/dist/analysis/diet.d.ts.map +1 -0
- package/dist/analysis/diet.js +164 -0
- package/dist/analysis/diet.js.map +1 -0
- package/dist/analysis/exercise.d.ts +98 -0
- package/dist/analysis/exercise.d.ts.map +1 -0
- package/dist/analysis/exercise.js +298 -0
- package/dist/analysis/exercise.js.map +1 -0
- package/dist/analysis/exerciseReview.d.ts +36 -0
- package/dist/analysis/exerciseReview.d.ts.map +1 -0
- package/dist/analysis/exerciseReview.js +50 -0
- package/dist/analysis/exerciseReview.js.map +1 -0
- package/dist/analysis/precision.d.ts +15 -0
- package/dist/analysis/precision.d.ts.map +1 -0
- package/dist/analysis/precision.js +38 -0
- package/dist/analysis/precision.js.map +1 -0
- package/dist/analysis/result.d.ts +15 -0
- package/dist/analysis/result.d.ts.map +1 -0
- package/dist/analysis/result.js +13 -0
- package/dist/analysis/result.js.map +1 -0
- package/dist/analysis/review.d.ts +118 -0
- package/dist/analysis/review.d.ts.map +1 -0
- package/dist/analysis/review.js +195 -0
- package/dist/analysis/review.js.map +1 -0
- package/dist/analysis/series.d.ts +42 -0
- package/dist/analysis/series.d.ts.map +1 -0
- package/dist/analysis/series.js +127 -0
- package/dist/analysis/series.js.map +1 -0
- package/dist/analysis/simulate.d.ts +43 -0
- package/dist/analysis/simulate.d.ts.map +1 -0
- package/dist/analysis/simulate.js +109 -0
- package/dist/analysis/simulate.js.map +1 -0
- package/dist/analysis/simulate2.d.ts +65 -0
- package/dist/analysis/simulate2.d.ts.map +1 -0
- package/dist/analysis/simulate2.js +173 -0
- package/dist/analysis/simulate2.js.map +1 -0
- package/dist/analysis/trend.d.ts +39 -0
- package/dist/analysis/trend.d.ts.map +1 -0
- package/dist/analysis/trend.js +48 -0
- package/dist/analysis/trend.js.map +1 -0
- package/dist/analysis/utils.d.ts +17 -0
- package/dist/analysis/utils.d.ts.map +1 -0
- package/dist/analysis/utils.js +52 -0
- package/dist/analysis/utils.js.map +1 -0
- package/dist/analysis/volatility.d.ts +43 -0
- package/dist/analysis/volatility.d.ts.map +1 -0
- package/dist/analysis/volatility.js +96 -0
- package/dist/analysis/volatility.js.map +1 -0
- package/dist/analysis/weight.d.ts +86 -0
- package/dist/analysis/weight.d.ts.map +1 -0
- package/dist/analysis/weight.js +219 -0
- package/dist/analysis/weight.js.map +1 -0
- package/dist/analysis/weightCompare.d.ts +63 -0
- package/dist/analysis/weightCompare.d.ts.map +1 -0
- package/dist/analysis/weightCompare.js +212 -0
- package/dist/analysis/weightCompare.js.map +1 -0
- package/dist/analysis/weightCompare2.d.ts +63 -0
- package/dist/analysis/weightCompare2.d.ts.map +1 -0
- package/dist/analysis/weightCompare2.js +211 -0
- package/dist/analysis/weightCompare2.js.map +1 -0
- package/dist/analysis/weightCompare3.d.ts +13 -0
- package/dist/analysis/weightCompare3.d.ts.map +1 -0
- package/dist/analysis/weightCompare3.js +199 -0
- package/dist/analysis/weightCompare3.js.map +1 -0
- package/dist/cli/cmd_read.d.ts +8 -0
- package/dist/cli/cmd_read.d.ts.map +1 -0
- package/dist/cli/cmd_read.js +719 -0
- package/dist/cli/cmd_read.js.map +1 -0
- package/dist/cli/keys.d.ts +333 -0
- package/dist/cli/keys.d.ts.map +1 -0
- package/dist/cli/keys.js +103 -0
- package/dist/cli/keys.js.map +1 -0
- package/dist/cli/write.d.ts +24 -0
- package/dist/cli/write.d.ts.map +1 -0
- package/dist/cli/write.js +832 -0
- package/dist/cli/write.js.map +1 -0
- package/dist/fetch/audit.d.ts +25 -0
- package/dist/fetch/audit.d.ts.map +1 -0
- package/dist/fetch/audit.js +46 -0
- package/dist/fetch/audit.js.map +1 -0
- package/dist/fetch/batch.d.ts +68 -0
- package/dist/fetch/batch.d.ts.map +1 -0
- package/dist/fetch/batch.js +183 -0
- package/dist/fetch/batch.js.map +1 -0
- package/dist/fetch/body.d.ts +89 -0
- package/dist/fetch/body.d.ts.map +1 -0
- package/dist/fetch/body.js +217 -0
- package/dist/fetch/body.js.map +1 -0
- package/dist/fetch/cli.d.ts +3 -0
- package/dist/fetch/cli.d.ts.map +1 -0
- package/dist/fetch/cli.js +195 -0
- package/dist/fetch/cli.js.map +1 -0
- package/dist/fetch/cross-skill.d.ts +29 -0
- package/dist/fetch/cross-skill.d.ts.map +1 -0
- package/dist/fetch/cross-skill.js +42 -0
- package/dist/fetch/cross-skill.js.map +1 -0
- package/dist/fetch/db.d.ts +5 -0
- package/dist/fetch/db.d.ts.map +1 -0
- package/dist/fetch/db.js +4 -0
- package/dist/fetch/db.js.map +1 -0
- package/dist/fetch/diet.d.ts +174 -0
- package/dist/fetch/diet.d.ts.map +1 -0
- package/dist/fetch/diet.js +239 -0
- package/dist/fetch/diet.js.map +1 -0
- package/dist/fetch/errors.d.ts +5 -0
- package/dist/fetch/errors.d.ts.map +1 -0
- package/dist/fetch/errors.js +8 -0
- package/dist/fetch/errors.js.map +1 -0
- package/dist/fetch/exercise.d.ts +72 -0
- package/dist/fetch/exercise.d.ts.map +1 -0
- package/dist/fetch/exercise.js +270 -0
- package/dist/fetch/exercise.js.map +1 -0
- package/dist/fetch/goal.d.ts +48 -0
- package/dist/fetch/goal.d.ts.map +1 -0
- package/dist/fetch/goal.js +73 -0
- package/dist/fetch/goal.js.map +1 -0
- package/dist/fetch/goalHistory.d.ts +24 -0
- package/dist/fetch/goalHistory.d.ts.map +1 -0
- package/dist/fetch/goalHistory.js +51 -0
- package/dist/fetch/goalHistory.js.map +1 -0
- package/dist/fetch/history.d.ts +28 -0
- package/dist/fetch/history.d.ts.map +1 -0
- package/dist/fetch/history.js +29 -0
- package/dist/fetch/history.js.map +1 -0
- package/dist/fetch/index.d.ts +23 -0
- package/dist/fetch/index.d.ts.map +1 -0
- package/dist/fetch/index.js +16 -0
- package/dist/fetch/index.js.map +1 -0
- package/dist/fetch/nutritionGoal.d.ts +115 -0
- package/dist/fetch/nutritionGoal.d.ts.map +1 -0
- package/dist/fetch/nutritionGoal.js +154 -0
- package/dist/fetch/nutritionGoal.js.map +1 -0
- package/dist/fetch/photos.d.ts +76 -0
- package/dist/fetch/photos.d.ts.map +1 -0
- package/dist/fetch/photos.js +193 -0
- package/dist/fetch/photos.js.map +1 -0
- package/dist/fetch/plan.d.ts +145 -0
- package/dist/fetch/plan.d.ts.map +1 -0
- package/dist/fetch/plan.js +258 -0
- package/dist/fetch/plan.js.map +1 -0
- package/dist/fetch/products.d.ts +62 -0
- package/dist/fetch/products.d.ts.map +1 -0
- package/dist/fetch/products.js +73 -0
- package/dist/fetch/products.js.map +1 -0
- package/dist/fetch/profile.d.ts +46 -0
- package/dist/fetch/profile.d.ts.map +1 -0
- package/dist/fetch/profile.js +105 -0
- package/dist/fetch/profile.js.map +1 -0
- package/dist/fetch/shapes.d.ts +41 -0
- package/dist/fetch/shapes.d.ts.map +1 -0
- package/dist/fetch/shapes.js +38 -0
- package/dist/fetch/shapes.js.map +1 -0
- package/dist/fetch/validate.d.ts +11 -0
- package/dist/fetch/validate.d.ts.map +1 -0
- package/dist/fetch/validate.js +64 -0
- package/dist/fetch/validate.js.map +1 -0
- package/dist/fetch/weight.d.ts +109 -0
- package/dist/fetch/weight.d.ts.map +1 -0
- package/dist/fetch/weight.js +210 -0
- package/dist/fetch/weight.js.map +1 -0
- package/dist/fetch/xunji-catalog.d.ts +17 -0
- package/dist/fetch/xunji-catalog.d.ts.map +1 -0
- package/dist/fetch/xunji-catalog.js +57 -0
- package/dist/fetch/xunji-catalog.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/kcal.d.ts +21 -0
- package/dist/kcal.d.ts.map +1 -0
- package/dist/kcal.js +27 -0
- package/dist/kcal.js.map +1 -0
- package/dist/migrate/migrate.d.ts +71 -0
- package/dist/migrate/migrate.d.ts.map +1 -0
- package/dist/migrate/migrate.js +450 -0
- package/dist/migrate/migrate.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +34 -0
- package/dist/paths.js.map +1 -0
- package/dist/render/analysisPlate.d.ts +49 -0
- package/dist/render/analysisPlate.d.ts.map +1 -0
- package/dist/render/analysisPlate.js +149 -0
- package/dist/render/analysisPlate.js.map +1 -0
- package/dist/render/bodyPlate.d.ts +55 -0
- package/dist/render/bodyPlate.d.ts.map +1 -0
- package/dist/render/bodyPlate.js +97 -0
- package/dist/render/bodyPlate.js.map +1 -0
- package/dist/render/diet.d.ts +47 -0
- package/dist/render/diet.d.ts.map +1 -0
- package/dist/render/diet.js +94 -0
- package/dist/render/diet.js.map +1 -0
- package/dist/render/envelope.d.ts +60 -0
- package/dist/render/envelope.d.ts.map +1 -0
- package/dist/render/envelope.js +111 -0
- package/dist/render/envelope.js.map +1 -0
- package/dist/render/errors.d.ts +10 -0
- package/dist/render/errors.d.ts.map +1 -0
- package/dist/render/errors.js +9 -0
- package/dist/render/errors.js.map +1 -0
- package/dist/render/exercise.d.ts +20 -0
- package/dist/render/exercise.d.ts.map +1 -0
- package/dist/render/exercise.js +32 -0
- package/dist/render/exercise.js.map +1 -0
- package/dist/render/goal.d.ts +24 -0
- package/dist/render/goal.d.ts.map +1 -0
- package/dist/render/goal.js +23 -0
- package/dist/render/goal.js.map +1 -0
- package/dist/render/goalExtra.d.ts +45 -0
- package/dist/render/goalExtra.d.ts.map +1 -0
- package/dist/render/goalExtra.js +94 -0
- package/dist/render/goalExtra.js.map +1 -0
- package/dist/render/goalPlate.d.ts +66 -0
- package/dist/render/goalPlate.d.ts.map +1 -0
- package/dist/render/goalPlate.js +110 -0
- package/dist/render/goalPlate.js.map +1 -0
- package/dist/render/health.d.ts +21 -0
- package/dist/render/health.d.ts.map +1 -0
- package/dist/render/health.js +41 -0
- package/dist/render/health.js.map +1 -0
- package/dist/render/help.d.ts +18 -0
- package/dist/render/help.d.ts.map +1 -0
- package/dist/render/help.js +58 -0
- package/dist/render/help.js.map +1 -0
- package/dist/render/home.d.ts +30 -0
- package/dist/render/home.d.ts.map +1 -0
- package/dist/render/home.js +73 -0
- package/dist/render/home.js.map +1 -0
- package/dist/render/html.d.ts +66 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +510 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/index.d.ts +47 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +26 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/insightPlate.d.ts +55 -0
- package/dist/render/insightPlate.d.ts.map +1 -0
- package/dist/render/insightPlate.js +97 -0
- package/dist/render/insightPlate.js.map +1 -0
- package/dist/render/library.d.ts +32 -0
- package/dist/render/library.d.ts.map +1 -0
- package/dist/render/library.js +54 -0
- package/dist/render/library.js.map +1 -0
- package/dist/render/photo.d.ts +101 -0
- package/dist/render/photo.d.ts.map +1 -0
- package/dist/render/photo.js +241 -0
- package/dist/render/photo.js.map +1 -0
- package/dist/render/planPlate.d.ts +40 -0
- package/dist/render/planPlate.d.ts.map +1 -0
- package/dist/render/planPlate.js +72 -0
- package/dist/render/planPlate.js.map +1 -0
- package/dist/render/profilePlate.d.ts +17 -0
- package/dist/render/profilePlate.d.ts.map +1 -0
- package/dist/render/profilePlate.js +18 -0
- package/dist/render/profilePlate.js.map +1 -0
- package/dist/render/ranking.d.ts +22 -0
- package/dist/render/ranking.d.ts.map +1 -0
- package/dist/render/ranking.js +63 -0
- package/dist/render/ranking.js.map +1 -0
- package/dist/render/receipt.d.ts +71 -0
- package/dist/render/receipt.d.ts.map +1 -0
- package/dist/render/receipt.js +65 -0
- package/dist/render/receipt.js.map +1 -0
- package/dist/render/weightPlate.d.ts +54 -0
- package/dist/render/weightPlate.d.ts.map +1 -0
- package/dist/render/weightPlate.js +110 -0
- package/dist/render/weightPlate.js.map +1 -0
- package/dist/schema.d.ts +25 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +281 -0
- package/dist/schema.js.map +1 -0
- package/dist/triggers/help-lookup.d.ts +28 -0
- package/dist/triggers/help-lookup.d.ts.map +1 -0
- package/dist/triggers/help-lookup.js +163 -0
- package/dist/triggers/help-lookup.js.map +1 -0
- package/dist/triggers/index.d.ts +24 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +78 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/triggers/scene-01-home.d.ts +4 -0
- package/dist/triggers/scene-01-home.d.ts.map +1 -0
- package/dist/triggers/scene-01-home.js +13 -0
- package/dist/triggers/scene-01-home.js.map +1 -0
- package/dist/triggers/scene-02-diet.d.ts +4 -0
- package/dist/triggers/scene-02-diet.d.ts.map +1 -0
- package/dist/triggers/scene-02-diet.js +74 -0
- package/dist/triggers/scene-02-diet.js.map +1 -0
- package/dist/triggers/scene-03-weight.d.ts +4 -0
- package/dist/triggers/scene-03-weight.d.ts.map +1 -0
- package/dist/triggers/scene-03-weight.js +62 -0
- package/dist/triggers/scene-03-weight.js.map +1 -0
- package/dist/triggers/scene-04-exercise.d.ts +4 -0
- package/dist/triggers/scene-04-exercise.d.ts.map +1 -0
- package/dist/triggers/scene-04-exercise.js +43 -0
- package/dist/triggers/scene-04-exercise.js.map +1 -0
- package/dist/triggers/scene-05-workout.d.ts +4 -0
- package/dist/triggers/scene-05-workout.d.ts.map +1 -0
- package/dist/triggers/scene-05-workout.js +36 -0
- package/dist/triggers/scene-05-workout.js.map +1 -0
- package/dist/triggers/scene-06-goal.d.ts +4 -0
- package/dist/triggers/scene-06-goal.d.ts.map +1 -0
- package/dist/triggers/scene-06-goal.js +29 -0
- package/dist/triggers/scene-06-goal.js.map +1 -0
- package/dist/triggers/scene-07-profile.d.ts +4 -0
- package/dist/triggers/scene-07-profile.d.ts.map +1 -0
- package/dist/triggers/scene-07-profile.js +8 -0
- package/dist/triggers/scene-07-profile.js.map +1 -0
- package/dist/triggers/scene-08-body.d.ts +4 -0
- package/dist/triggers/scene-08-body.d.ts.map +1 -0
- package/dist/triggers/scene-08-body.js +17 -0
- package/dist/triggers/scene-08-body.js.map +1 -0
- package/dist/triggers/scene-09-photo.d.ts +4 -0
- package/dist/triggers/scene-09-photo.d.ts.map +1 -0
- package/dist/triggers/scene-09-photo.js +14 -0
- package/dist/triggers/scene-09-photo.js.map +1 -0
- package/dist/triggers/scene-10-analysis.d.ts +4 -0
- package/dist/triggers/scene-10-analysis.d.ts.map +1 -0
- package/dist/triggers/scene-10-analysis.js +180 -0
- package/dist/triggers/scene-10-analysis.js.map +1 -0
- package/dist/triggers/types.d.ts +66 -0
- package/dist/triggers/types.d.ts.map +1 -0
- package/dist/triggers/types.js +3 -0
- package/dist/triggers/types.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export const CONTRA_PARTS = ['腰', '膝', '肩'];
|
|
2
|
+
export const SAFE_VARIANTS = ['支撑式', '俯卧', '仰卧', '高位'];
|
|
3
|
+
export function isSafeVariant(name) {
|
|
4
|
+
return SAFE_VARIANTS.some((v) => name.includes(v));
|
|
5
|
+
}
|
|
6
|
+
const LUMBAR = [
|
|
7
|
+
{ part: '腰', name: '髋铰链轴向压力', reason: '硬拉/罗马尼亚硬拉/早安式弯腰会让腰椎承受巨大轴向压力,突出节段受挤压加重', keywords: ['硬拉', '罗马尼亚', '早安', 'good morning', '臀桥'], severity: 'error' },
|
|
8
|
+
{ part: '腰', name: '俯身/弯腰划船类', reason: '俯身角度超过 45° 时腰部竖脊肌持续等长收缩 + 腰椎剪切力,T-bar 划船最危险', keywords: ['俯身', 't-bar', 'tbar', 't bar', '杠铃划船'], severity: 'warn' },
|
|
9
|
+
{ part: '腰', name: '腿举/倒蹬类', reason: '倒蹬器械在膝屈曲 + 髋屈曲时腰椎屈曲代偿,突出节段受压(用户已主动删除器械倒蹬)', keywords: ['倒蹬', '腿举', 'smith 机深蹲'], severity: 'error' },
|
|
10
|
+
{ part: '腰', name: '坐姿腿弯举', reason: '腘绳肌在屈膝时收缩牵拉坐骨结节,导致骨盆前倾 + 腰椎屈曲,加重突出', keywords: ['腿弯举', '坐姿腿弯举', '俯卧腿弯举'], severity: 'error' },
|
|
11
|
+
];
|
|
12
|
+
const KNEE = [
|
|
13
|
+
{ part: '膝', name: '大重量深蹲/全蹲', reason: '超过 90° 深度 + 大重量会让髌股关节压力激增,半月板承受剪切', keywords: ['深蹲', '全蹲', '高杠深蹲', '低杠深蹲', '前蹲'], severity: 'warn' },
|
|
14
|
+
{ part: '膝', name: '跳跃/冲击类', reason: '跳跃落地时膝关节承受 5-7 倍体重冲击,半月板/韧带风险高', keywords: ['跳箱', 'box jump', '跳跃', '冲刺跑'], severity: 'warn' },
|
|
15
|
+
{ part: '膝', name: '开链伸膝大重量', reason: '坐姿腿屈伸(开链)大重量时髌腱张力极高,易诱发髌腱炎', keywords: ['腿屈伸', 'leg extension'], severity: 'info' },
|
|
16
|
+
];
|
|
17
|
+
const SHOULDER = [
|
|
18
|
+
{ part: '肩', name: '颈后推举', reason: '颈后推举时肩关节外旋 + 极度外展,肩峰下撞击综合征风险极高', keywords: ['颈后推举', '颈后推', 'behind neck press'], severity: 'error' },
|
|
19
|
+
{ part: '肩', name: '大重量直立划船', reason: '直立划船到顶端时肩关节内旋 + 外展,肩峰撞击 + 肩袖肌群挤压', keywords: ['直立划船', 'upright row'], severity: 'warn' },
|
|
20
|
+
{ part: '肩', name: '过头推举大重量', reason: '过头推举超过头部时肱骨大结节与肩峰撞击,肩袖肌群受压', keywords: ['过头推举', 'overhead press', '推举过头'], severity: 'warn' },
|
|
21
|
+
{ part: '肩', name: '大幅度侧平举', reason: '侧平举超过 90° 时肩峰下空间消失,冈上肌撞击', keywords: ['侧平举', 'lateral raise'], severity: 'info' },
|
|
22
|
+
];
|
|
23
|
+
export const ALL_RULES = { '腰': LUMBAR, '膝': KNEE, '肩': SHOULDER };
|
|
24
|
+
export function rulesFor(part) {
|
|
25
|
+
return ALL_RULES[part] ?? [];
|
|
26
|
+
}
|
|
27
|
+
function matches(name, keyword) {
|
|
28
|
+
return name.toLowerCase().includes(keyword.toLowerCase());
|
|
29
|
+
}
|
|
30
|
+
export function matchOne(name, rule) {
|
|
31
|
+
return rule.keywords.some((kw) => matches(name, kw));
|
|
32
|
+
}
|
|
33
|
+
/** 单动作扫描:每部位一个 slot(无命中为空数组,顺序稳定)。 */
|
|
34
|
+
export function scanMovement(name, parts = [...CONTRA_PARTS]) {
|
|
35
|
+
return parts.map((part) => rulesFor(part).filter((r) => matchOne(name, r)));
|
|
36
|
+
}
|
|
37
|
+
const SEV_ORDER = { error: 3, warn: 2, info: 1 };
|
|
38
|
+
export function worstSeverity(rules) {
|
|
39
|
+
if (rules.length === 0)
|
|
40
|
+
return null;
|
|
41
|
+
return rules.reduce((a, b) => (SEV_ORDER[b.severity] > SEV_ORDER[a.severity] ? b : a)).severity;
|
|
42
|
+
}
|
|
43
|
+
export function scanAllMovements(movements, parts = [...CONTRA_PARTS]) {
|
|
44
|
+
const hits = [];
|
|
45
|
+
for (const m of movements) {
|
|
46
|
+
const name = m.name ?? '';
|
|
47
|
+
const safe = isSafeVariant(name);
|
|
48
|
+
for (const [i, part] of parts.entries()) {
|
|
49
|
+
void i;
|
|
50
|
+
for (const rule of scanMovement(name, parts)[parts.indexOf(part)]) {
|
|
51
|
+
hits.push({ movementName: name, part, ruleName: rule.name, severity: rule.severity, reason: rule.reason, usedIn: [], safeVariant: safe });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return hits;
|
|
56
|
+
}
|
|
57
|
+
export function scanPlan(db, part = 'all') {
|
|
58
|
+
const parts = part === 'all' ? [...CONTRA_PARTS] : [part];
|
|
59
|
+
const plansRaw = db.prepare('SELECT week_number AS wn, day_of_week AS dow, session_index AS si, session_label AS label, movements AS movs FROM workout_plans ORDER BY week_number, day_of_week, session_index').all();
|
|
60
|
+
const plans = plansRaw.map((r) => [r.wn, r.dow, r.si, r.label, r.movs]);
|
|
61
|
+
const hits = [];
|
|
62
|
+
const byMovement = new Map();
|
|
63
|
+
let movementCount = 0;
|
|
64
|
+
let safeSkipped = 0;
|
|
65
|
+
for (const p of plans) {
|
|
66
|
+
const movements = JSON.parse(p[4] || '[]');
|
|
67
|
+
const usage = 'W' + p[0] + 'D' + p[1] + '(' + p[3] + ')';
|
|
68
|
+
for (const m of movements) {
|
|
69
|
+
movementCount += 1;
|
|
70
|
+
const name = m.name ?? '';
|
|
71
|
+
const safe = isSafeVariant(name);
|
|
72
|
+
for (const [pi, ppart] of parts.entries()) {
|
|
73
|
+
void pi;
|
|
74
|
+
for (const rule of scanMovement(name, parts)[parts.indexOf(ppart)]) {
|
|
75
|
+
const hit = { movementName: name, part: ppart, ruleName: rule.name, severity: rule.severity, reason: rule.reason, usedIn: [usage], safeVariant: safe };
|
|
76
|
+
if (hit.safeVariant) {
|
|
77
|
+
safeSkipped += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
hits.push(hit);
|
|
81
|
+
if (!byMovement.has(name))
|
|
82
|
+
byMovement.set(name, []);
|
|
83
|
+
byMovement.get(name).push(hit);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const bySeverity = { error: 0, warn: 0, info: 0 };
|
|
89
|
+
for (const h of hits)
|
|
90
|
+
bySeverity[h.severity] += 1;
|
|
91
|
+
const byMovementSummary = {};
|
|
92
|
+
for (const [name, list] of byMovement) {
|
|
93
|
+
const usedIn = [...new Set(list.flatMap((h) => h.usedIn))].sort();
|
|
94
|
+
const rules = [...new Set(list.map((h) => h.ruleName))].sort();
|
|
95
|
+
const sevList = list.map((h) => ({ severity: h.severity }));
|
|
96
|
+
byMovementSummary[name] = {
|
|
97
|
+
count: list.length,
|
|
98
|
+
severity: (worstSeverity(sevList) ?? 'info'),
|
|
99
|
+
rules,
|
|
100
|
+
usedIn,
|
|
101
|
+
parts: [...new Set(list.map((h) => h.part))].sort(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const status = bySeverity.error > 0 ? 'fail' : bySeverity.warn > 0 ? 'warn' : 'ok';
|
|
105
|
+
const suggestions = [];
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
for (const hit of hits) {
|
|
108
|
+
if (seen.has(hit.movementName) || hit.safeVariant)
|
|
109
|
+
continue;
|
|
110
|
+
seen.add(hit.movementName);
|
|
111
|
+
suggestions.push({
|
|
112
|
+
movement: hit.movementName,
|
|
113
|
+
rule: hit.ruleName,
|
|
114
|
+
reason: hit.reason,
|
|
115
|
+
replace: '用含 ' + SAFE_VARIANTS.slice(0, 3).join('/') + ' 等关键字的安全变体',
|
|
116
|
+
safeExamples: SAFE_VARIANTS.slice(0, 4),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return { scannedSessions: plans.length, scannedMovements: movementCount, scannedParts: parts, safeSkipped, hits, byMovement: byMovementSummary, bySeverity, summaryStatus: status, suggestions };
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=contraindications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contraindications.js","sourceRoot":"","sources":["../../src/analysis/contraindications.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** T5 #24 · 跨表组合分析(对照老家 scripts/analysis/cross.py A1/A5)。
|
|
2
|
+
*
|
|
3
|
+
* analyzePair(series, pair, db?):11 配对(PAIRS 表原样);db 仅 exercise/waist
|
|
4
|
+
* 分层取证用(不传则 extra 记不可用,不断言空)。pair 非法即抛。
|
|
5
|
+
* 系列键为 DaySeries 驼峰(_strat 的 a/b 字段名做映射)。
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
8
|
+
import type { DaySeries } from './series.js';
|
|
9
|
+
export declare const PAIRS: Record<string, [string, string, string, string, string]>;
|
|
10
|
+
export type PairName = keyof typeof PAIRS;
|
|
11
|
+
export declare function pearson(pairs: Array<[number, number]>): number | null;
|
|
12
|
+
export declare function linearRegression(pairs: Array<[number, number]>): {
|
|
13
|
+
slope: number;
|
|
14
|
+
intercept: number;
|
|
15
|
+
n: number;
|
|
16
|
+
} | null;
|
|
17
|
+
export interface StratRow {
|
|
18
|
+
label: string;
|
|
19
|
+
days: number;
|
|
20
|
+
aDelta: number | null;
|
|
21
|
+
bAvg: number | null;
|
|
22
|
+
note: string;
|
|
23
|
+
}
|
|
24
|
+
export interface Strat {
|
|
25
|
+
rows: StratRow[];
|
|
26
|
+
extra: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface PairAnalysis {
|
|
29
|
+
pair: string;
|
|
30
|
+
labels: {
|
|
31
|
+
a: string;
|
|
32
|
+
b: string;
|
|
33
|
+
};
|
|
34
|
+
window: string;
|
|
35
|
+
start: string | null;
|
|
36
|
+
end: string | null;
|
|
37
|
+
days: number;
|
|
38
|
+
aAvg: number | null;
|
|
39
|
+
bAvg: number | null;
|
|
40
|
+
aDelta: number | null;
|
|
41
|
+
bDelta: number | null;
|
|
42
|
+
aCount: number;
|
|
43
|
+
bCount: number;
|
|
44
|
+
line: Array<{
|
|
45
|
+
date: string;
|
|
46
|
+
a: number | null;
|
|
47
|
+
b: number | null;
|
|
48
|
+
}>;
|
|
49
|
+
scatter: Array<{
|
|
50
|
+
x: number;
|
|
51
|
+
y: number;
|
|
52
|
+
}>;
|
|
53
|
+
overLimitDays: string[];
|
|
54
|
+
deficitBuckets: Array<{
|
|
55
|
+
label: string;
|
|
56
|
+
days: number;
|
|
57
|
+
}>;
|
|
58
|
+
correlation: {
|
|
59
|
+
r: number | null;
|
|
60
|
+
n: number;
|
|
61
|
+
};
|
|
62
|
+
regression: {
|
|
63
|
+
slope: number;
|
|
64
|
+
intercept: number;
|
|
65
|
+
n: number;
|
|
66
|
+
} | null;
|
|
67
|
+
lag: Array<{
|
|
68
|
+
lag: number;
|
|
69
|
+
r: number | null;
|
|
70
|
+
}>;
|
|
71
|
+
strat: Strat;
|
|
72
|
+
insight: string;
|
|
73
|
+
}
|
|
74
|
+
export declare function analyzePair(series: DaySeries[], pair: string, db?: DatabaseSync, window?: string): PairAnalysis;
|
|
75
|
+
//# sourceMappingURL=cross.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross.d.ts","sourceRoot":"","sources":["../../src/analysis/cross.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { FetchError } from '../fetch/errors.js';
|
|
2
|
+
const round = (n) => Math.round(n);
|
|
3
|
+
const round2 = (n) => Math.round(n * 100) / 100;
|
|
4
|
+
const round3 = (n) => Math.round(n * 1000) / 1000;
|
|
5
|
+
const round4 = (n) => Math.round(n * 10000) / 10000;
|
|
6
|
+
export const PAIRS = {
|
|
7
|
+
weight_calorie: ['weightKg', 'calories', '体重(kg)', '摄入(卡)', 'weekday'],
|
|
8
|
+
weight_exercise: ['weightKg', 'exerciseKcal', '体重(kg)', '运动消耗(卡)', 'exercise'],
|
|
9
|
+
weight_protein: ['weightKg', 'protein', '体重(kg)', '蛋白摄入(g)', 'protein'],
|
|
10
|
+
weight_deficit: ['weightKg', 'deficit', '体重(kg)', '热量缺口(卡)', 'deficit'],
|
|
11
|
+
calorie_exercise: ['calories', 'exerciseKcal', '摄入(卡)', '运动消耗(卡)', 'deficit_src'],
|
|
12
|
+
weight_bodyfat: ['weightKg', 'bodyFatPct', '体重(kg)', '体脂率(%)', 'divergence'],
|
|
13
|
+
weight_waist: ['weightKg', 'waistCm', '体重(kg)', '腰围(cm)', 'waist_divergence'],
|
|
14
|
+
water_weight: ['waterMl', 'weightKg', '饮水(ml)', '体重(kg)', 'water'],
|
|
15
|
+
protein_carbs: ['protein', 'carbs', '蛋白(g)', '碳水(g)', 'ratio'],
|
|
16
|
+
protein_fat: ['protein', 'fat', '蛋白(g)', '脂肪(g)', 'ratio'],
|
|
17
|
+
carbs_fat: ['carbs', 'fat', '碳水(g)', '脂肪(g)', 'ratio'],
|
|
18
|
+
};
|
|
19
|
+
export function pearson(pairs) {
|
|
20
|
+
const n = pairs.length;
|
|
21
|
+
if (n < 2)
|
|
22
|
+
return null;
|
|
23
|
+
let sx = 0, sy = 0, sxy = 0, sx2 = 0, sy2 = 0;
|
|
24
|
+
for (const [x, y] of pairs) {
|
|
25
|
+
sx += x;
|
|
26
|
+
sy += y;
|
|
27
|
+
sxy += x * y;
|
|
28
|
+
sx2 += x * x;
|
|
29
|
+
sy2 += y * y;
|
|
30
|
+
}
|
|
31
|
+
const denom = Math.sqrt((n * sx2 - sx * sx) * (n * sy2 - sy * sy));
|
|
32
|
+
if (denom === 0)
|
|
33
|
+
return null;
|
|
34
|
+
return round3(Math.max(-1, Math.min(1, (n * sxy - sx * sy) / denom)));
|
|
35
|
+
}
|
|
36
|
+
export function linearRegression(pairs) {
|
|
37
|
+
const n = pairs.length;
|
|
38
|
+
if (n < 2)
|
|
39
|
+
return null;
|
|
40
|
+
let sx = 0, sy = 0, sxy = 0, sx2 = 0;
|
|
41
|
+
for (const [x, y] of pairs) {
|
|
42
|
+
sx += x;
|
|
43
|
+
sy += y;
|
|
44
|
+
sxy += x * y;
|
|
45
|
+
sx2 += x * x;
|
|
46
|
+
}
|
|
47
|
+
const denom = n * sx2 - sx * sx;
|
|
48
|
+
if (denom === 0)
|
|
49
|
+
return null;
|
|
50
|
+
const slope = (n * sxy - sx * sy) / denom;
|
|
51
|
+
return { slope: round4(slope), intercept: round2((sy - slope * sx) / n), n };
|
|
52
|
+
}
|
|
53
|
+
function val(s, f) {
|
|
54
|
+
const v = s[f];
|
|
55
|
+
return typeof v === 'number' ? v : null;
|
|
56
|
+
}
|
|
57
|
+
function delta(vals) {
|
|
58
|
+
if (vals.length < 2)
|
|
59
|
+
return null;
|
|
60
|
+
return round2(vals[vals.length - 1] - vals[0]);
|
|
61
|
+
}
|
|
62
|
+
function weekdayOf(iso) {
|
|
63
|
+
return new Date(iso + 'T12:00:00Z').getUTCDay();
|
|
64
|
+
}
|
|
65
|
+
function strat(series, mode, a, b, db) {
|
|
66
|
+
const rows = [];
|
|
67
|
+
const extra = [];
|
|
68
|
+
const mk = (label, rowsIn) => {
|
|
69
|
+
const av = rowsIn.map((s) => val(s, a)).filter((v) => v !== null);
|
|
70
|
+
const bv = rowsIn.map((s) => val(s, b)).filter((v) => v !== null);
|
|
71
|
+
return { label, days: rowsIn.length, aDelta: delta(av), bAvg: bv.length > 0 ? round1(bv.reduce((x, y) => x + y, 0) / bv.length) : null, note: '' };
|
|
72
|
+
};
|
|
73
|
+
const round1 = (n) => Math.round(n * 10) / 10;
|
|
74
|
+
if (mode === 'weekday' || mode === 'exercise' || mode === 'protein' || mode === 'deficit' || mode === 'water') {
|
|
75
|
+
const cond = [];
|
|
76
|
+
const non = [];
|
|
77
|
+
for (const s of series) {
|
|
78
|
+
let isCond = false;
|
|
79
|
+
if (mode === 'weekday')
|
|
80
|
+
isCond = weekdayOf(s.date) >= 1 && weekdayOf(s.date) <= 5;
|
|
81
|
+
else if (mode === 'exercise')
|
|
82
|
+
isCond = (s.exerciseKcal ?? 0) > 0;
|
|
83
|
+
else if (mode === 'protein')
|
|
84
|
+
isCond = (s.protein ?? 0) >= ((s.calorieGoal ?? 0) / 10) * 0.4;
|
|
85
|
+
else if (mode === 'deficit')
|
|
86
|
+
isCond = (s.deficit ?? 0) > 0;
|
|
87
|
+
else if (mode === 'water')
|
|
88
|
+
isCond = (s.waterMl ?? 0) >= (s.waterGoal ?? 2000);
|
|
89
|
+
if (val(s, a) === null)
|
|
90
|
+
continue;
|
|
91
|
+
(isCond ? cond : non).push(s);
|
|
92
|
+
}
|
|
93
|
+
const labels = { weekday: ['工作日', '周末'], exercise: ['运动日', '休息日'], protein: ['蛋白达标日', '未达标日'], deficit: ['有缺口日', '无缺口日'], water: ['饮水达标日', '未达标日'] };
|
|
94
|
+
const [l0, l1] = labels[mode];
|
|
95
|
+
rows.push(mk(l0, cond), mk(l1, non));
|
|
96
|
+
const d1 = rows[0]?.aDelta ?? 0;
|
|
97
|
+
const d2 = rows[1]?.aDelta ?? 0;
|
|
98
|
+
if ((rows[0]?.days ?? 0) > 0 && (rows[1]?.days ?? 0) > 0 && Math.abs(d1 - d2) > 0.2) {
|
|
99
|
+
rows[0].note = 'Δ差异 ' + (d1 - d2 >= 0 ? '+' : '') + round2(d1 - d2).toFixed(2);
|
|
100
|
+
rows[1].note = 'Δ差异 ' + (d2 - d1 >= 0 ? '+' : '') + round2(d2 - d1).toFixed(2);
|
|
101
|
+
}
|
|
102
|
+
if (mode === 'exercise') {
|
|
103
|
+
if (db && series.length > 0) {
|
|
104
|
+
try {
|
|
105
|
+
const start = series[0].date;
|
|
106
|
+
const end = series[series.length - 1].date;
|
|
107
|
+
const st = db.prepare("SELECT SUM(calories_burned) AS v FROM exercise_log WHERE date BETWEEN ? AND ? AND category = '力量'").get(start, end);
|
|
108
|
+
const ca = db.prepare("SELECT SUM(calories_burned) AS v FROM exercise_log WHERE date BETWEEN ? AND ? AND category = '有氧'").get(start, end);
|
|
109
|
+
extra.push('力量消耗合计 ' + round(st.v ?? 0) + ' 卡 vs 有氧 ' + round(ca.v ?? 0) + ' 卡');
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
extra.push('力量/有氧分层不可用: ' + e.message);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else
|
|
116
|
+
extra.push('力量/有氧分层不可用: 缺 db');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (mode === 'deficit_src') {
|
|
120
|
+
const cal = series.map((s) => s.calories).filter((v) => v !== null && v !== undefined);
|
|
121
|
+
const ex = series.map((s) => s.exerciseKcal).filter((v) => v !== null && v !== undefined);
|
|
122
|
+
const tdee = series.length > 0 ? series[0].tdee : null;
|
|
123
|
+
const calAvg = cal.length > 0 ? round1(cal.reduce((x, y) => x + y, 0) / cal.length) : null;
|
|
124
|
+
const exAvg = ex.length > 0 ? round1(ex.reduce((x, y) => x + y, 0) / ex.length) : null;
|
|
125
|
+
rows.push({ label: '日均摄入', days: cal.length, aDelta: null, bAvg: calAvg, note: '' });
|
|
126
|
+
rows.push({ label: '日均运动', days: ex.length, aDelta: null, bAvg: exAvg, note: '' });
|
|
127
|
+
if (calAvg !== null && tdee !== null && tdee !== undefined) {
|
|
128
|
+
extra.push('缺口构成:(TDEE ' + tdee + ' + 运动 ' + (exAvg ?? 0) + ') − 摄入 ' + calAvg + ' = 日均缺口 ' + (tdee + (exAvg ?? 0) - calAvg >= 0 ? '+' : '') + round(tdee + (exAvg ?? 0) - calAvg) + ' 卡');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (mode === 'divergence') {
|
|
132
|
+
const wv = series.map((s) => s.weightKg).filter((v) => v !== null && v !== undefined);
|
|
133
|
+
const bv = series.map((s) => s.bodyFatPct).filter((v) => v !== null && v !== undefined);
|
|
134
|
+
const wDelta = delta(wv);
|
|
135
|
+
const bDelta = delta(bv);
|
|
136
|
+
extra.push(wDelta !== null && bDelta !== null ? '体重净变化 ' + (wDelta >= 0 ? '+' : '') + wDelta.toFixed(2) + ' kg;体脂净变化 ' + (bDelta >= 0 ? '+' : '') + bDelta.toFixed(2) + ' 个百分点' : '体重/体脂样本不足,无法背离检测');
|
|
137
|
+
if (wDelta !== null && bDelta !== null) {
|
|
138
|
+
extra.push(wDelta < -0.3 && bDelta > -0.5 ? '⚠️ 背离:体重降但体脂未同步降,警惕肌肉流失' : '体重与体脂同向变化,脂肪确实在减少');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (mode === 'waist_divergence') {
|
|
142
|
+
const wv = series.map((s) => s.weightKg).filter((v) => v !== null && v !== undefined);
|
|
143
|
+
const wDelta = delta(wv);
|
|
144
|
+
extra.push(wDelta !== null ? '体重净变化 ' + (wDelta >= 0 ? '+' : '') + wDelta.toFixed(2) + ' kg' : '体重样本不足');
|
|
145
|
+
const cols = [['chest_cm', '胸围'], ['waist_cm', '腰围'], ['abdomen_cm', '腹围'], ['hip_cm', '臀围'], ['shoulder_cm', '肩围'], ['left_thigh_cm', '左大腿'], ['right_thigh_cm', '右大腿'], ['left_calf_cm', '左小腿'], ['right_calf_cm', '右小腿'], ['left_arm_cm', '左上臂'], ['right_arm_cm', '右上臂'], ['left_forearm_cm', '左前臂'], ['right_forearm_cm', '右前臂']];
|
|
146
|
+
if (db && series.length > 0) {
|
|
147
|
+
try {
|
|
148
|
+
const start = series[0].date;
|
|
149
|
+
const end = series[series.length - 1].date;
|
|
150
|
+
const deltas = [];
|
|
151
|
+
for (const [col, label] of cols) {
|
|
152
|
+
const first = db.prepare('SELECT ' + col + ' AS v FROM body_measurements WHERE date BETWEEN ? AND ? AND ' + col + ' IS NOT NULL AND is_deprecated = 0 ORDER BY date, id LIMIT 1').get(start, end);
|
|
153
|
+
const last = db.prepare('SELECT ' + col + ' AS v FROM body_measurements WHERE date BETWEEN ? AND ? AND ' + col + ' IS NOT NULL AND is_deprecated = 0 ORDER BY date DESC, id DESC LIMIT 1').get(start, end);
|
|
154
|
+
if (first?.v !== null && first?.v !== undefined && last?.v !== null && last?.v !== undefined) {
|
|
155
|
+
deltas.push([label, round1(last.v - first.v)]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
deltas.sort((a, b) => Math.abs(b[1]) - Math.abs(a[1]));
|
|
159
|
+
extra.push('各部位变化 TOP:' + (deltas.length > 0 ? deltas.slice(0, 3).map(([n, d]) => n + ' ' + (d >= 0 ? '+' : '') + d.toFixed(1) + 'cm').join('、') : '窗口内无围度数据'));
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
extra.push('围度明细不可用: ' + e.message);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else
|
|
166
|
+
extra.push('围度明细不可用: 缺 db');
|
|
167
|
+
}
|
|
168
|
+
else if (mode === 'ratio') {
|
|
169
|
+
const ab = series.filter((s) => s.protein !== null || s.carbs !== null || s.fat !== null).map((s) => [s.protein ?? 0, s.carbs ?? 0, s.fat ?? 0]);
|
|
170
|
+
if (ab.length >= 4) {
|
|
171
|
+
const half = Math.floor(ab.length / 2);
|
|
172
|
+
const ratio = (rowsIn) => {
|
|
173
|
+
const p = rowsIn.reduce((a, r) => a + r[0], 0) || 1;
|
|
174
|
+
return '蛋白' + round(rowsIn.reduce((a, r) => a + r[0], 0) / p * 100) + '% 碳水' + round(rowsIn.reduce((a, r) => a + r[1], 0) / p * 100) + '% 脂肪' + round(rowsIn.reduce((a, r) => a + r[2], 0) / p * 100) + '%';
|
|
175
|
+
};
|
|
176
|
+
extra.push('前段占比:' + ratio(ab.slice(0, half)));
|
|
177
|
+
extra.push('后段占比:' + ratio(ab.slice(half)));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { rows, extra };
|
|
181
|
+
}
|
|
182
|
+
function insight(pair, r, lag, st, days) {
|
|
183
|
+
const bLabel = PAIRS[pair][3];
|
|
184
|
+
if (r === null)
|
|
185
|
+
return '数据不足,无法判断“' + bLabel + '”与目标指标的关联。';
|
|
186
|
+
const strength = Math.abs(r) >= 0.5 ? '强' : Math.abs(r) >= 0.3 ? '中' : '弱';
|
|
187
|
+
const direction = r > 0 ? '正相关' : '负相关';
|
|
188
|
+
let line = strength + direction + '(r=' + (r >= 0 ? '+' : '') + r.toFixed(2) + ')';
|
|
189
|
+
if (pair === 'weight_calorie' && lag.length > 0) {
|
|
190
|
+
const best = lag.reduce((a, b) => Math.abs(b.r ?? 0) > Math.abs(a.r ?? 0) ? b : a);
|
|
191
|
+
if (best.r !== null && Math.abs(best.r) > Math.abs(r)) {
|
|
192
|
+
line += ';滞后 ' + best.lag + ' 天相关性更强(r=' + (best.r >= 0 ? '+' : '') + best.r.toFixed(2) + ')';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const ext = st.extra.join('\n');
|
|
196
|
+
if (ext.includes('背离'))
|
|
197
|
+
line += ';⚠️ 体重与体脂/围度存在背离信号';
|
|
198
|
+
if (ext.includes('⚠️ 背离'))
|
|
199
|
+
line += ';⚠️ 体重降但体脂未同步降,警惕肌肉流失';
|
|
200
|
+
return '窗口内共 ' + days + ' 天,' + bLabel + '与目标指标呈' + line + '。';
|
|
201
|
+
}
|
|
202
|
+
export function analyzePair(series, pair, db, window = '30d') {
|
|
203
|
+
if (!(pair in PAIRS))
|
|
204
|
+
throw new FetchError('未知配对 ' + pair + ',可选: ' + Object.keys(PAIRS).join(', '));
|
|
205
|
+
const [fa, fb, la, lb, mode] = PAIRS[pair];
|
|
206
|
+
const line = series.filter((s) => val(s, fa) !== null || val(s, fb) !== null).map((s) => ({ date: s.date, a: val(s, fa), b: val(s, fb) }));
|
|
207
|
+
const alignedPairs = [];
|
|
208
|
+
for (const s of series) {
|
|
209
|
+
const a = val(s, fa);
|
|
210
|
+
const b = val(s, fb);
|
|
211
|
+
if (a !== null && b !== null)
|
|
212
|
+
alignedPairs.push([a, b]);
|
|
213
|
+
}
|
|
214
|
+
const r = pearson(alignedPairs);
|
|
215
|
+
const reg = linearRegression(alignedPairs);
|
|
216
|
+
const lag = [];
|
|
217
|
+
if (pair === 'weight_calorie' || pair === 'weight_exercise' || pair === 'weight_protein') {
|
|
218
|
+
for (const l of [1, 2, 3]) {
|
|
219
|
+
const pairs = [];
|
|
220
|
+
for (let i = l; i < series.length; i++) {
|
|
221
|
+
const a = val(series[i], fa);
|
|
222
|
+
const b = val(series[i - l], fb);
|
|
223
|
+
if (a !== null && b !== null)
|
|
224
|
+
pairs.push([a, b]);
|
|
225
|
+
}
|
|
226
|
+
lag.push({ lag: l, r: pearson(pairs) });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const st = strat(series, mode, fa, fb, db);
|
|
230
|
+
let overLimitDays = [];
|
|
231
|
+
if (pair === 'weight_calorie' && series.length > 0) {
|
|
232
|
+
const goal = series[0].calorieGoal ?? 1800;
|
|
233
|
+
overLimitDays = series.filter((s) => s.calories !== null && s.calories !== undefined && s.calories > goal * 1.3).map((s) => s.date);
|
|
234
|
+
}
|
|
235
|
+
const deficitBuckets = [];
|
|
236
|
+
if (pair === 'weight_deficit') {
|
|
237
|
+
const buckets = { '深缺口(>500卡)': 0, '标准缺口(100~500)': 0, '小幅盈余(-100~100)': 0, '盈余(<-100)': 0 };
|
|
238
|
+
for (const s of series) {
|
|
239
|
+
const d = s.deficit;
|
|
240
|
+
if (d === null || d === undefined)
|
|
241
|
+
continue;
|
|
242
|
+
if (d > 500)
|
|
243
|
+
buckets['深缺口(>500卡)'] = buckets['深缺口(>500卡)'] + 1;
|
|
244
|
+
else if (d > 100)
|
|
245
|
+
buckets['标准缺口(100~500)'] = buckets['标准缺口(100~500)'] + 1;
|
|
246
|
+
else if (d >= -100)
|
|
247
|
+
buckets['小幅盈余(-100~100)'] = buckets['小幅盈余(-100~100)'] + 1;
|
|
248
|
+
else
|
|
249
|
+
buckets['盈余(<-100)'] = buckets['盈余(<-100)'] + 1;
|
|
250
|
+
}
|
|
251
|
+
for (const [label, days] of Object.entries(buckets)) {
|
|
252
|
+
if (days > 0)
|
|
253
|
+
deficitBuckets.push({ label, days });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const av = series.map((s) => val(s, fa)).filter((v) => v !== null);
|
|
257
|
+
const bv = series.map((s) => val(s, fb)).filter((v) => v !== null);
|
|
258
|
+
const avg = (xs) => xs.length > 0 ? round2(xs.reduce((a, b) => a + b, 0) / xs.length) : null;
|
|
259
|
+
return {
|
|
260
|
+
pair,
|
|
261
|
+
labels: { a: la, b: lb },
|
|
262
|
+
window,
|
|
263
|
+
start: series.length > 0 ? series[0].date : null,
|
|
264
|
+
end: series.length > 0 ? series[series.length - 1].date : null,
|
|
265
|
+
days: series.length,
|
|
266
|
+
aAvg: avg(av),
|
|
267
|
+
bAvg: avg(bv),
|
|
268
|
+
aDelta: delta(av),
|
|
269
|
+
bDelta: delta(bv),
|
|
270
|
+
aCount: av.length,
|
|
271
|
+
bCount: bv.length,
|
|
272
|
+
line,
|
|
273
|
+
scatter: alignedPairs.map(([x, y]) => ({ x, y })),
|
|
274
|
+
overLimitDays,
|
|
275
|
+
deficitBuckets,
|
|
276
|
+
correlation: { r, n: alignedPairs.length },
|
|
277
|
+
regression: reg,
|
|
278
|
+
lag,
|
|
279
|
+
strat: st,
|
|
280
|
+
insight: insight(pair, r, lag, st, series.length),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=cross.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross.js","sourceRoot":"","sources":["../../src/analysis/cross.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** T5 #24 · 综合健康报告 4 维度(对照老家 scripts/analysis/dashboard.py)。
|
|
2
|
+
*
|
|
3
|
+
* weight/calorie/exercise/deficit 四维独立 try/except(单维失败记 error 不
|
|
4
|
+
* 掀整单);任一 error → 总 status warn。单日 dashboard 时 weight.changeKg
|
|
5
|
+
* 改取“今日首条 − 昨日首条”(老家 2026-07-31 fix,原同日首尾差误导)。
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
8
|
+
import type { AnalysisResult } from './result.js';
|
|
9
|
+
export interface HealthDashboard {
|
|
10
|
+
start: string;
|
|
11
|
+
end: string;
|
|
12
|
+
weight: unknown;
|
|
13
|
+
calorie: unknown;
|
|
14
|
+
exercise: unknown;
|
|
15
|
+
deficit: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare function healthDashboard(db: DatabaseSync, startDate: string, endDate?: string | null): AnalysisResult<HealthDashboard>;
|
|
18
|
+
//# sourceMappingURL=dashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/analysis/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAUD,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,CAAC,eAAe,CAAC,CAgC7H"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { dietCalorieTrend, dietDeficitAnalysis } from './diet.js';
|
|
2
|
+
import { exerciseTrend } from './exercise.js';
|
|
3
|
+
import { weightTrend } from './weight.js';
|
|
4
|
+
import { parseDate, shiftISODate } from './utils.js';
|
|
5
|
+
import { FetchError } from '../fetch/errors.js';
|
|
6
|
+
function safe(fn) {
|
|
7
|
+
try {
|
|
8
|
+
return fn();
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
return { status: 'error', data: null, message: e instanceof Error ? e.message : String(e) };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function healthDashboard(db, startDate, endDate) {
|
|
15
|
+
const start = parseDate(startDate);
|
|
16
|
+
if (!start)
|
|
17
|
+
throw new FetchError('起始日期非法: ' + String(startDate));
|
|
18
|
+
const end = parseDate(endDate ?? undefined) ?? start;
|
|
19
|
+
const dims = {
|
|
20
|
+
weight: safe(() => weightTrend(db, start, end)),
|
|
21
|
+
calorie: safe(() => dietCalorieTrend(db, start, end)),
|
|
22
|
+
exercise: safe(() => exerciseTrend(db, start, end)),
|
|
23
|
+
deficit: safe(() => dietDeficitAnalysis(db, start, end)),
|
|
24
|
+
};
|
|
25
|
+
const weight = dims['weight'];
|
|
26
|
+
if (start === end && weight.status === 'ok' && weight.data && weight.data.firstWeight !== null && weight.data.firstWeight !== undefined) {
|
|
27
|
+
const yesterday = shiftISODate(start, -1);
|
|
28
|
+
const yest = safe(() => weightTrend(db, yesterday, yesterday));
|
|
29
|
+
const ydata = yest.data;
|
|
30
|
+
if (yest.status === 'ok' && ydata && ydata.firstWeight !== null && ydata.firstWeight !== undefined) {
|
|
31
|
+
weight.data.changeKg = Math.round((weight.data.firstWeight - ydata.firstWeight) * 10) / 10;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const overall = Object.values(dims).some((d) => d.status === 'error') ? 'warn' : 'ok';
|
|
35
|
+
return {
|
|
36
|
+
status: overall,
|
|
37
|
+
data: {
|
|
38
|
+
start,
|
|
39
|
+
end,
|
|
40
|
+
weight: dims['weight'].data,
|
|
41
|
+
calorie: dims['calorie'].data,
|
|
42
|
+
exercise: dims['exercise'].data,
|
|
43
|
+
deficit: dims['deficit'].data,
|
|
44
|
+
},
|
|
45
|
+
message: '健康报告 ' + start + ' ~ ' + end,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/analysis/dashboard.ts"],"names":[],"mappings":"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"}
|