Files
memind/health-intent-rules.mjs
T
john f96fdcb3b9 feat(health): add P0 health channel kernel and encrypted health zone.
Lock health recording behind confirm-only state machines, reject public publishes for the health category, and ship the 14-day experiment Page Data templates with tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 18:04:26 +08:00

115 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const HEALTH_RULE_INTENTS = Object.freeze({
BLOOD_PRESSURE: 'blood_pressure',
WEIGHT: 'weight',
HEART_RATE: 'heart_rate',
SPO2: 'spo2',
TEMPERATURE: 'temperature',
SLEEP: 'sleep',
SYMPTOM: 'symptom',
ASSESS: 'assess',
ARCHIVE: 'archive',
});
const BP_PAIR = /(\d{2,3})\s*[/]\s*(\d{2,3})/;
export function matchHealthIdleRules(text) {
const raw = String(text ?? '').trim();
if (!raw) return { matched: false, confidence: 0 };
const bp = raw.match(BP_PAIR);
if (bp || /血压/.test(raw) && /\d{2,3}/.test(raw)) {
const systolic = bp ? Number(bp[1]) : null;
const diastolic = bp ? Number(bp[2]) : null;
return {
matched: true,
intent: HEALTH_RULE_INTENTS.BLOOD_PRESSURE,
confidence: bp ? 0.95 : 0.8,
extracted: { systolic, diastolic },
};
}
const weight = raw.match(/体重\s*(\d{2,3}(?:\.\d)?)/);
if (weight) {
return {
matched: true,
intent: HEALTH_RULE_INTENTS.WEIGHT,
confidence: 0.9,
extracted: { weight: Number(weight[1]) },
};
}
const hr = raw.match(/(?:心率|脉搏)\s*(\d{2,3})/);
if (hr) {
return {
matched: true,
intent: HEALTH_RULE_INTENTS.HEART_RATE,
confidence: 0.9,
extracted: { hr: Number(hr[1]) },
};
}
const spo2 = raw.match(/(?:血氧|SpO2|spo2)\s*(\d{2,3})/i);
if (spo2) {
return {
matched: true,
intent: HEALTH_RULE_INTENTS.SPO2,
confidence: 0.9,
extracted: { spo2: Number(spo2[1]) },
};
}
const temp = raw.match(/(?:体温|发烧)\s*(3\d(?:\.\d)?)/);
if (temp) {
return {
matched: true,
intent: HEALTH_RULE_INTENTS.TEMPERATURE,
confidence: 0.9,
extracted: { temperature: Number(temp[1]) },
};
}
if (/睡了|睡眠/.test(raw) && /\d/.test(raw)) {
return { matched: true, intent: HEALTH_RULE_INTENTS.SLEEP, confidence: 0.75, extracted: {} };
}
if (/头晕|胸闷|乏力|心慌|头痛|气短/.test(raw)) {
return { matched: true, intent: HEALTH_RULE_INTENTS.SYMPTOM, confidence: 0.8, extracted: {} };
}
if (/(?:最近怎么样|有没有异常|健康评估)|(?:身体|血压|健康).{0,12}(?:怎么样|帮我看看)|帮我看看.{0,12}(?:身体|血压|健康)/.test(raw)) {
return { matched: true, intent: HEALTH_RULE_INTENTS.ASSESS, confidence: 0.85, extracted: {} };
}
if (/我的档案|历史记录|报告/.test(raw)) {
return { matched: true, intent: HEALTH_RULE_INTENTS.ARCHIVE, confidence: 0.8, extracted: {} };
}
return { matched: false, confidence: 0 };
}
export function shouldForceActionChoice(ruleResult, llm = null) {
if (ruleResult?.matched && ruleResult.confidence >= 0.75) return false;
const confidence = Number(llm?.confidence ?? 0);
const gap = Number(llm?.top1 ?? 0) - Number(llm?.top2 ?? 0);
if (confidence < 0.75 || gap < 0.15) return true;
return false;
}
export function shouldRedirectOrdinaryChatToHealth(text) {
const hit = matchHealthIdleRules(text);
if (!hit.matched) return false;
return [
HEALTH_RULE_INTENTS.BLOOD_PRESSURE,
HEALTH_RULE_INTENTS.WEIGHT,
HEALTH_RULE_INTENTS.HEART_RATE,
HEALTH_RULE_INTENTS.SPO2,
HEALTH_RULE_INTENTS.TEMPERATURE,
HEALTH_RULE_INTENTS.SLEEP,
HEALTH_RULE_INTENTS.SYMPTOM,
HEALTH_RULE_INTENTS.ASSESS,
].includes(hit.intent);
}
export const HEALTH_REDIRECT_COPY =
'你想记录健康数据吗?健康数据需要在健康助手通道里录入,这样才能保证记录准确并纳入你的健康基线分析。';