Files
smt/docs/ALGORITHM.md
T

8.5 KiB
Raw Blame History

戒烟算法与 AI 策略说明

1. 核心理念

采用渐进式递减策略,而非突然戒断:

  • 科学研究表明,逐步减少比冷火鸡戒断成功率更高
  • 通过延长抽烟间隔,让身体逐渐适应尼古丁减少
  • AI 分析个人模式,提供个性化的递减计划

2. 默认递减算法 (staircase_delay_v1)

2.1 算法概述

下次建议时间 = 上次抽烟时间 + 基础间隔 + 奖励间隔

2.2 参数说明

参数 来源 默认值 说明
base_interval profile.baseline_interval_minutes 60 分钟 用户初始平均抽烟间隔(为空/0 时默认 60)
resisted_7d 近7天忍住次数 0 level=0,num=0 的记录数
bonus_interval 计算得出 0 奖励延长时间

2.3 奖励机制

每累计 5 次忍住,基础间隔 +5 分钟,最多 +60 分钟

bonus_interval = min(floor(resisted_7d / 5) * 5, 60)
final_interval = clamp(base_interval + bonus_interval, 5, 240)

示例

  • 用户基础间隔 48 分钟,近 7 天忍住 12 次
  • bonus = floor(12/5) * 5 = 10 分钟
  • 最终间隔 = 48 + 10 = 58 分钟

2.4 睡眠规避

若计算出的时间落在睡眠区间,顺延到下一次起床时间(可能是当天也可能是次日):

if suggested_time in [sleep_time, wake_up_time]:
    suggested_time = next_day_wake_up_time

2.5 边界与兜底

  • 若没有历史记录,则以“当前时间”作为 last_smoke_at 参与计算。
  • 若生成未来日期计划(如明天),默认建议不早于该日起床时间;未配置作息时按 07:00 处理。

2.6 算法流程图

获取上次抽烟时间 (last_smoke_at, 若无记录则取当前时间)
        ↓
获取用户基础间隔 (base_interval_minutes)
        ↓
统计近7天忍住次数 (resisted_7d)
        ↓
计算奖励间隔: bonus = min(floor(resisted_7d / 5) * 5, 60)
        ↓
计算建议时间: suggested = last_smoke_at + base + bonus (并限制在 5~240 分钟区间)
        ↓
检查是否在睡眠时间?
    ├── 是 → 顺延到起床时间
    └── 否 → 返回建议时间

3. AI 增强算法

3.1 AI 时间节点规划

当用户解锁 AI 功能后,系统会:

  1. 收集近 3 天数据

    • 每次抽烟的时间点
    • 每次忍住的时间点
    • 抽烟原因/场景标签
  2. 分析抽烟模式

    • 高峰时段识别(如下午 2-4 点)
    • 触发场景识别(如压力、无聊、社交)
    • 间隔规律分析
  3. 生成个性化时间节点

    • 避开高峰时段的前半小时
    • 在用户通常能忍住的时段设置节点
    • 逐日递增间隔

3.2 AI 建议内容

AI 会生成以下内容(实际接口格式):

{
  "not_before_at": "2026-01-05T10:18:00+08:00",
  "suggested_at": "2026-01-05T10:28:00+08:00",
  "time_nodes": ["09:30", "12:30", "15:30", "19:00", "22:00"],
  "advice": "昨天你的吸烟量比限额少了2支,这是一个巨大的胜利!数据显示你的烟瘾在下午2点左右达到顶峰——今天试着那个时候去散散步。"
}

3.3 AI Prompt 设计

你是一位专业的戒烟辅导教练。基于用户的抽烟数据,提供个性化的戒烟建议。

用户档案:
- 日均吸烟量:{baseline_cigs_per_day} 支
- 烟龄:{smoking_years} 年
- 抽烟动机:{smoke_motivations}
- 戒烟动力:{quit_motivations}
- 作息:{wake_up_time} - {sleep_time}

近3天数据:
{recent_logs}

请分析:
1. 用户的抽烟规律和高峰时段
2. 主要的触发场景
3. 成功忍住的模式

然后生成:
1. 一段鼓励性的分析总结(2-3句话)
2. 明天的建议抽烟时间节点(比今天少1支)
3. 2-3条实用的应对建议

4. 阶段划分

4.1 三阶段戒烟计划

阶段 时间 目标 策略
记录期 Day 1-7 建立基线 正常抽烟,但每次都记录
减量期 Day 8-21 减少 50% 每周目标递减,AI 指导
巩固期 Day 22-30 维持/归零 强化抵抗,心理建设

4.2 阶段进度计算

// utils/stage.js
function calculateStage(startDate) {
  const daysSinceStart = daysBetween(startDate, new Date())
  
  if (daysSinceStart <= 7) {
    return {
      stage: 1,
      name: '记录期',
      progress: daysSinceStart / 7,
      daysLeft: 7 - daysSinceStart
    }
  } else if (daysSinceStart <= 21) {
    return {
      stage: 2,
      name: '减量期',
      progress: (daysSinceStart - 7) / 14,
      daysLeft: 21 - daysSinceStart
    }
  } else {
    return {
      stage: 3,
      name: '巩固期',
      progress: Math.min((daysSinceStart - 21) / 9, 1),
      daysLeft: Math.max(30 - daysSinceStart, 0)
    }
  }
}

4.3 每日目标计算

// utils/target.js
function calculateDailyTarget(baseline, stage, dayInStage) {
  if (stage === 1) {
    return baseline
  }
  
  if (stage === 2) {
    const reduction = (dayInStage / 14) * 0.5
    return Math.max(Math.round(baseline * (1 - reduction)), 1)
  }
  
  if (stage === 3) {
    const targetRate = 0.25 - (dayInStage / 9) * 0.25
    return Math.max(Math.round(baseline * targetRate), 0)
  }
  
  return baseline
}

5. 健康恢复计算(后端统一)

接口:GET /api/v1/smoke/stats?range=week|month|year(详见 docs/smoke/API.md

基于医学研究的恢复时间线:

时间点 恢复指标 计算方式
20分钟 心率血压恢复正常 固定
8小时 血氧水平恢复 固定
24小时 心脏病风险开始下降 固定
48小时 嗅觉味觉开始恢复 固定
2周 肺功能提升 15% 线性计算
1月 肺功能提升 30% 线性计算
3月 肺功能提升 50% 线性计算
1年 心脏病风险降低 50% 线性计算
// utils/health.js
function calculateLungRecovery(smokeFreeMinutes) {
  const days = smokeFreeMinutes / (24 * 60)
  
  if (days < 14) {
    return (days / 14) * 15
  } else if (days < 30) {
    return 15 + ((days - 14) / 16) * 15
  } else if (days < 90) {
    return 30 + ((days - 30) / 60) * 20
  } else {
    return Math.min(50 + ((days - 90) / 275) * 50, 100)
  }
}

6. 省钱计算(后端统一)

接口:GET /api/v1/smoke/stats?range=week|month|year(详见 docs/smoke/API.md

// utils/money.js
function calculateMoneySaved(packPriceCent, cigsPerPack, baselineCigsPerDay, actualCigsTotal, days) {
  const expectedTotal = baselineCigsPerDay * days
  const savedCigs = expectedTotal - actualCigsTotal
  const savedPacks = savedCigs / cigsPerPack
  return Math.round(savedPacks * packPriceCent)
}

7. 激励语生成(后端统一)

接口:GET /api/v1/smoke/motivation(详见 docs/smoke/API.md

根据用户状态生成不同的激励语:

// utils/motivation.js
function getMotivationMessage(context) {
  const { 
    minutesSinceLast, 
    todayCount, 
    dailyTarget,
    resistedToday,
    quitMotivations 
  } = context
  
  if (resistedToday > 0 && minutesSinceLast < 30) {
    return '太棒了!你刚刚成功抵抗了一次烟瘾'
  }
  
  if (todayCount < dailyTarget * 0.5) {
    return '今天的表现非常出色,继续保持!'
  }
  
  if (todayCount === dailyTarget - 1) {
    return '还剩最后一支配额,考虑把它留到睡前?'
  }
  
  if (todayCount > dailyTarget) {
    return `没关系,明天是新的一天。记住你为什么要戒烟:${quitMotivations[0]}`
  }
  
  return '保持连胜纪录!'
}

8. 数据分析指标

8.1 关键指标

指标 计算方式 用途
日均吸烟量 周期内总量 / 天数 趋势对比
周同比变化 (本周 - 上周) / 上周 进度评估
忍住成功率 忍住次数 / (忍住+抽烟次数) 意志力评估
平均间隔 总时长 / 抽烟次数 递减效果
最长无烟时长 最大间隔记录 成就激励
较昨日减少 昨日支数 - 今日支数(可为负) 若为负,表示今天超出昨日

8.2 周报数据结构

// 周报数据结构
const weeklyReport = {
  period: { start: '2026-01-01', end: '2026-01-07' },
  totalCigs: 35,
  dailyAverage: 5,
  comparedToLastWeek: -20,   // 百分比变化
  resistedCount: 12,
  longestGap: 180,           // 分钟
  peakHours: ['14:00', '21:00'],
  topTriggers: ['压力大', '无聊'],
  achievements: ['连续7天记录', '单日忍住5次'],
  nextWeekTarget: 4
}