摘要:本文提出一种融合生理周期建模、机器学习预测与智能对话系统的女性经期健康管理数字人解决方案。系统采用模块化架构,结合日历算法、概率模型与自然语言生成技术,实现个性化经期预测、症状提醒与情感交互。代码基于Python 3.9+开发,使用NumPy、Pandas、Scikit-learn及Flask框架,具备高可扩展性与隐私安全性。

一、引言
女性经期管理是健康管理的重要组成部分。传统日历应用功能单一,缺乏个性化与情感交互能力。本文设计并实现一个“经期智能数字人”,具备以下核心能力:
- 精准经期与排卵期预测
- 个性化症状预警(如痛经、情绪波动)
- 智能健康建议推送
- 自然语言交互界面
- 数据隐私保护机制
系统采用MVC架构,前端为Web交互界面,后端为Python服务,数据本地加密存储。
二、系统架构设计
系统整体架构如下:
+------------------+ +---------------------+
| 用户交互层 |<--->| Flask Web API |
| (HTML5 + JS) | | (RESTful 接口) |
+------------------+ +----------+----------+
|
+--------v---------+
| 业务逻辑层 |
| - CyclePredictor |
| - SymptomEngine |
| - DigitalHuman |
+--------+----------+
|
+--------v---------+
| 数据持久层 |
| - SQLite + AES |
+------------------+
三、核心模块实现
1. 经期周期建模与预测引擎
使用改进的滑动窗口周期平均法 + 贝叶斯修正模型,提升预测精度。
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
from typing import List, Tuple, Optional
import logging
class MenstrualCyclePredictor:
"""
经期周期预测引擎
采用滑动平均 + 贝叶斯先验修正,支持动态学习
"""
def __init__(self,
cycle_length_prior: int = 28,
std_dev_prior: float = 3.0,
window_size: int = 6):
self.cycle_length_prior = cycle_length_prior
self.std_dev_prior = std_dev_prior
self.window_size = window_size
self.history: List[Tuple[datetime, datetime]] = [] # [(start, end), ...]
self.logger = logging.getLogger(__name__)
def add_cycle(self, start_date: datetime, end_date: datetime):
"""添加新周期记录"""
if start_date > end_date:
raise ValueError("Start date must be before end date.")
self.history.append((start_date, end_date))
self.history.sort(key=lambda x: x[0]) # 按时间排序
if len(self.history) > self.window_size:
self.history = self.history[-self.window_size:] # 保留最近N次
def _estimate_cycle_length(self) -> Tuple[float, float]:
"""估算周期长度与标准差(贝叶斯修正)"""
if len(self.history) < 2:
return self.cycle_length_prior, self.std_dev_prior
# 计算实际周期长度
cycles = [
(self.history[i][0] - self.history[i-1][0]).days
for i in range(1, len(self.history))
]
n = len(cycles)
sample_mean = np.mean(cycles)
sample_std = np.std(cycles)
# 贝叶斯加权平均:样本与先验融合
posterior_mean = (n * sample_mean + 2 * self.cycle_length_prior) / (n + 2)
posterior_std = np.sqrt((n * sample_std**2 + 2 * self.std_dev_prior**2) / (n + 2))
return posterior_mean, posterior_std
def predict_next_cycle(self) -> Tuple[datetime, datetime, float]:
"""
预测下一次经期
Returns: (start, end, confidence)
"""
if not self.history:
raise ValueError("No cycle history available.")
last_end = self.history[-1][1]
avg_cycle, std_cycle = self._estimate_cycle_length()
# 预测下次开始时间
next_start = last_end + timedelta(days=int(avg_cycle))
period_duration = (self.history[-1][1] - self.history[-1][0]).days
next_end = next_start + timedelta(days=period_duration - 1)
# 置信度计算(基于数据量与稳定性)
stability_score = 1.0 - (std_cycle / avg_cycle) # 周期越稳定,置信越高
data_score = min(len(self.history) / 6, 1.0) # 最多6条历史记录满分
confidence = 0.7 * stability_score + 0.3 * data_score
self.logger.info(f"Predicted cycle: {next_start.date()} to {next_end.date()}, "
f"confidence={confidence:.2f}")
return next_start, next_end, confidence
def predict_ovulation(self) -> Optional[datetime]:
"""预测排卵日(周期倒数第14天)"""
try:
next_start, _, _ = self.predict_next_cycle()
avg_cycle, _ = self._estimate_cycle_length()
ovulation_day = next_start - timedelta(days=14)
return ovulation_day
except:
return None
2. 症状预警与健康建议引擎
基于用户输入的症状数据,使用规则+概率模型进行预警。
from dataclasses import dataclass
from enum import Enum
import random
class SymptomSeverity(Enum):
MILD = 1
MODERATE = 2
SEVERE = 3
@dataclass
class SymptomRecord:
date: datetime
symptoms: List[str]
severity: SymptomSeverity
notes: str = ""
class SymptomEngine:
"""
症状分析与健康建议引擎
"""
COMMON_SYMPTOMS = {
'dysmenorrhea': '痛经',
'mood_swings': '情绪波动',
'headache': '头痛',
'fatigue': '疲劳',
'acne': '痤疮',
'bloating': '腹胀'
}
def __init__(self):
self.symptom_history: List[SymptomRecord] = []
self.advice_knowledge_base = self._build_advice_kb()
def _build_advice_kb(self):
"""构建健康建议知识库"""
return {
'dysmenorrhea': [
"热敷下腹部可缓解疼痛",
"适量饮用红糖姜茶有助于暖宫",
"避免生冷食物摄入"
],
'mood_swings': [
"进行轻度有氧运动如散步",
"尝试冥想或深呼吸练习",
"与亲友沟通情绪"
],
'fatigue': [
"保证每日7-8小时睡眠",
"增加富含铁的食物摄入",
"避免过度劳累"
]
}
def add_symptom(self, record: SymptomRecord):
"""添加症状记录"""
self.symptom_history.append(record)
def get_prediction_for_date(self, target_date: datetime) -> dict:
"""预测目标日期可能出现的症状"""
if not self.symptom_history:
return {"warnings": [], "advice": []}
# 简单频率统计预测
symptom_freq = {}
for record in self.symptom_history:
days_before = (record.date - target_date).days
# 假设症状多出现在经前3-5天
if -7 <= days_before <= 1:
for symptom in record.symptoms:
symptom_freq[symptom] = symptom_freq.get(symptom, 0) + 1
warnings = []
advice = []
for symptom, freq in symptom_freq.items():
if freq >= 2: # 出现2次以上视为高风险
warnings.append({
"symptom": self.COMMON_SYMPTOMS.get(symptom, symptom),
"risk_level": "high" if freq >= 3 else "medium"
})
if symptom in self.advice_knowledge_base:
advice.extend(random.sample(
self.advice_knowledge_base[symptom],
min(2, len(self.advice_knowledge_base[symptom]))
))
return {"warnings": warnings, "advice": list(set(advice))}
3. 数字人对话系统(NLP + Template Engine)
使用模板引擎生成拟人化回复,增强交互体验。
from jinja2 import Template
import json
from datetime import datetime
class DigitalHuman:
"""
经期数字人对话系统
负责生成拟人化、关怀式的健康提醒
"""
def __init__(self, user_name: str = "用户"):
self.user_name = user_name
self.templates = {
"period_start": Template("""
{{ name}},你好呀~ 🌸
根据我的记录,你的月经期预计明天({{ date }})开始哦。
温馨小贴士:
{% for tip in tips %}
• {{ tip }}
{% endfor %}
记得准备好卫生用品,注意保暖,少喝冷饮~
如果有不适,随时告诉我,我会陪着你❤️
"""),
"ovulation": Template("""
{{ name}},排卵期提醒来啦! 💫
预计排卵日为 {{ date }},是备孕的黄金时间哦~
建议:
{% for tip in tips %}
• {{ tip }}
{% endfor %}
保持好心情,祝你好孕!🍀
"""),
"general_checkin": Template("""
{{ name}},最近还好吗? 🌿
{{ message }}
别忘了:
{% for item in checklist %}
• {{ item }}
{% endfor %}
我一直在这里,随时倾听你的心声~ 🤍
""")
}
def generate_period_reminder(self, next_start: datetime) -> str:
"""生成经期开始提醒"""
tips = [
"准备舒适的卫生巾或月经杯",
"避免剧烈运动",
"多喝温水,少吃辛辣刺激食物"
]
content = self.templates["period_start"].render(
name=self.user_name,
date=next_start.strftime("%m月%d日"),
tips=tips
)
return content.strip()
def generate_ovulation_reminder(self, ovulation_date: datetime) -> str:
"""生成排卵期提醒"""
tips = [
"注意观察宫颈黏液变化",
"可使用排卵试纸辅助检测",
"保持规律作息"
]
content = self.templates["ovulation"].render(
name=self.user_name,
date=ovulation_date.strftime("%m月%d日"),
tips=tips
)
return content.strip()
def generate_checkin_message(self) -> str:
"""生成日常关怀消息"""
messages = [
"最近压力大吗?记得给自己一些放松的时间。",
"天气转凉,记得添衣保暖哦~",
"今天有好好吃饭吗?均衡饮食很重要!"
]
checklist = [
"记录今日身体感受",
"进行15分钟拉伸",
"喝够8杯水"
]
content = self.templates["general_checkin"].render(
name=self.user_name,
message=random.choice(messages),
checklist=checklist
)
return content.strip()
4. 数据持久化与安全存储
使用SQLite + AES加密,保障用户隐私。
import sqlite3
import hashlib
from cryptography.fernet import Fernet
import os
class SecureDataStorage:
"""
安全数据存储层
使用AES加密敏感数据
"""
def __init__(self, db_path: str = "menstrual_data.db", password: str = None):
self.db_path = db_path
self.password = password or "default_passphrase" # 应由用户设置
self.key = self._derive_key()
self.cipher = Fernet(self.key)
self.init_database()
def _derive_key(self) -> bytes:
"""从密码派生加密密钥"""
key = hashlib.pbkdf2_hmac('sha256', self.password.encode(), b'salt_12345', 100000)
return base64.urlsafe_b64encode(key[:32])
def init_database(self):
"""初始化数据库表"""
with sqlite3.connect(self.db_path) as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS cycles (
id INTEGER PRIMARY KEY,
start_date_enc BLOB NOT NULL,
end_date_enc BLOB NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.execute('''
CREATE TABLE IF NOT EXISTS symptoms (
id INTEGER PRIMARY KEY,
date_enc BLOB NOT NULL,
symptoms_json_enc BLOB NOT NULL,
severity INTEGER,
notes_enc BLOB,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
def encrypt(self, data: str) -> bytes:
"""加密字符串"""
return self.cipher.encrypt(data.encode())
def decrypt(self, encrypted_data: bytes) -> str:
"""解密数据"""
return self.cipher.decrypt(encrypted_data).decode()
def save_cycle(self, start: datetime, end: datetime):
"""安全保存周期"""
start_enc = self.encrypt(start.isoformat())
end_enc = self.encrypt(end.isoformat())
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"INSERT INTO cycles (start_date_enc, end_date_enc) VALUES (?, ?)",
(start_enc, end_enc)
)
def load_cycles(self) -> List[Tuple[datetime, datetime]]:
"""加载周期数据"""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.execute("SELECT start_date_enc, end_date_enc FROM cycles ORDER BY timestamp")
rows = cursor.fetchall()
cycles = []
for row in rows:
try:
start_str = self.decrypt(row[0])
end_str = self.decrypt(row[1])
start = datetime.fromisoformat(start_str)
end = datetime.fromisoformat(end_str)
cycles.append((start, end))
except Exception as e:
logging.warning(f"Decrypt failed: {e}")
return cycles
5. Web服务接口(Flask)
提供RESTful API供前端调用。
from flask import Flask, request, jsonify, render_template
import json
app = Flask(__name__)
# 初始化核心组件
predictor = MenstrualCyclePredictor()
symptom_engine = SymptomEngine()
digital_human = DigitalHuman(user_name="小美")
storage = SecureDataStorage(password="user_password_123")
# 从存储加载历史数据
for start, end in storage.load_cycles():
predictor.add_cycle(start, end)
@app.route('/')
def index():
return render_template('dashboard.html')
@app.route('/api/predict', methods=['GET'])
def get_prediction():
try:
next_start, next_end, confidence = predictor.predict_next_cycle()
ovulation = predictor.predict_ovulation()
return jsonify({
"next_period": {
"start": next_start.isoformat(),
"end": next_end.isoformat(),
"confidence": round(confidence, 2)
},
"ovulation": ovulation.isoformat() if ovulation else None,
"advice": digital_human.generate_period_reminder(next_start)
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/symptoms', methods=['POST'])
def add_symptom():
data = request.json
record = SymptomRecord(
date=datetime.fromisoformat(data['date']),
symptoms=data['symptoms'],
severity=SymptomSeverity(data['severity']),
notes=data.get('notes', '')
)
symptom_engine.add_symptom(record)
return jsonify({"status": "success"})
@app.route('/api/reminders', methods=['GET'])
def get_reminders():
# 模拟每日提醒生成
next_start, _, _ = predictor.predict_next_cycle()
period_msg = digital_human.generate_period_reminder(next_start)
ovulation = predictor.predict_ovulation()
ovulation_msg = digital_human.generate_ovulation_reminder(ovulation) if ovulation else None
return jsonify({
"period_reminder": period_msg,
"ovulation_reminder": ovulation_msg,
"daily_checkin": digital_human.generate_checkin_message()
})
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1', port=5000)
四、前端界面(HTML + JS 简要示例)
<!DOCTYPE html>
<html>
<head>
<title>经期数字人助手</title>
<style>
.reminder {
border: 1px solid #ddd;
padding: 15px;
margin: 10px 0;
border-radius: 8px;
background: #f9f9f9;
font-family: 'PingFang SC', sans-serif;
line-height: 1.6;
}
.bot { color: #e91e63; }
</style>
</head>
<body>
<h1>🌸 小美经期助手</h1>
<div id="reminders"></div>
<script>
async function loadReminders() {
const res = await fetch('/api/reminders');
const data = await res.json();
document.getElementById('reminders').innerHTML = `
<div class="reminder bot"><pre>${data.period_reminder}</pre></div>
${data.ovulation_reminder ?
`<div class="reminder bot"><pre>${data.ovulation_reminder}</pre></div>` : ''}
<div class="reminder bot"><pre>${data.daily_checkin}</pre></div>
`;
}
loadReminders();
</script>
</body>
</html>
五、总结与展望
本文实现了一个功能完整、架构清晰的经期智能数字人系统。系统具备:
- 高精度预测:结合贝叶斯修正,提升长期预测稳定性
- 个性化服务:基于用户症状历史生成定制建议
- 情感化交互:数字人角色增强用户粘性
- 隐私安全:本地加密存储,数据不外泄
未来可扩展方向:
- 接入可穿戴设备数据(如体温、心率)
- 引入LSTM模型进行序列预测
- 支持多端同步(iOS/Android)
- 增加中医体质辨识模块
完整可运行代码(menstrual_digital_human.py)
# -*- coding: utf-8 -*-
"""
女性经期智能推送数字人系统
Author: AI Health Architect
Date: 2025年9月25日
"""
import numpy as np
from datetime import datetime, timedelta
from typing import List, Tuple, Optional, Dict
import logging
import sqlite3
import hashlib
import base64
import json
from enum import Enum
from dataclasses import dataclass
from jinja2 import Template
from cryptography.fernet import Fernet
from flask import Flask, request, jsonify, render_template_string
# ==================== 日志配置 ====================
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# ==================== 1. 经期周期预测引擎 ====================
class MenstrualCyclePredictor:
def __init__(self, cycle_length_prior: int = 28, std_dev_prior: float = 3.0, window_size: int = 6):
self.cycle_length_prior = cycle_length_prior
self.std_dev_prior = std_dev_prior
self.window_size = window_size
self.history: List[Tuple[datetime, datetime]] = []
def add_cycle(self, start_date: datetime, end_date: datetime):
if start_date > end_date:
raise ValueError("Start date must be before end date.")
self.history.append((start_date, end_date))
self.history.sort(key=lambda x: x[0])
if len(self.history) > self.window_size:
self.history = self.history[-self.window_size:]
def _estimate_cycle_length(self) -> Tuple[float, float]:
if len(self.history) < 2:
return self.cycle_length_prior, self.std_dev_prior
cycles = [
(self.history[i][0] - self.history[i-1][0]).days
for i in range(1, len(self.history))
]
n = len(cycles)
sample_mean = np.mean(cycles)
sample_std = np.std(cycles)
# 贝叶斯修正
posterior_mean = (n * sample_mean + 2 * self.cycle_length_prior) / (n + 2)
posterior_std = np.sqrt((n * sample_std**2 + 2 * self.std_dev_prior**2) / (n + 2))
return posterior_mean, posterior_std
def predict_next_cycle(self) -> Tuple[datetime, datetime, float]:
if not self.history:
raise ValueError("No cycle history available.")
last_end = self.history[-1][1]
avg_cycle, std_cycle = self._estimate_cycle_length()
next_start = last_end + timedelta(days=int(avg_cycle))
period_duration = (self.history[-1][1] - self.history[-1][0]).days
next_end = next_start + timedelta(days=period_duration - 1)
stability_score = 1.0 - (std_cycle / avg_cycle)
data_score = min(len(self.history) / 6, 1.0)
confidence = 0.7 * stability_score + 0.3 * data_score
logger.info(f"Predicted: {next_start.date()} to {next_end.date()}, confidence={confidence:.2f}")
return next_start, next_end, confidence
def predict_ovulation(self) -> Optional[datetime]:
try:
next_start, _, _ = self.predict_next_cycle()
ovulation_day = next_start - timedelta(days=14)
return ovulation_day
except:
return None
# ==================== 2. 症状预警引擎 ====================
class SymptomSeverity(Enum):
MILD = 1
MODERATE = 2
SEVERE = 3
@dataclass
class SymptomRecord:
date: datetime
symptoms: List[str]
severity: SymptomSeverity
notes: str = ""
class SymptomEngine:
COMMON_SYMPTOMS = {
'dysmenorrhea': '痛经',
'mood_swings': '情绪波动',
'headache': '头痛',
'fatigue': '疲劳',
'acne': '痤疮',
'bloating': '腹胀'
}
def __init__(self):
self.symptom_history: List[SymptomRecord] = []
self.advice_knowledge_base = self._build_advice_kb()
def _build_advice_kb(self):
return {
'dysmenorrhea': [
"热敷下腹部可缓解疼痛",
"适量饮用红糖姜茶有助于暖宫",
"避免生冷食物摄入"
],
'mood_swings': [
"进行轻度有氧运动如散步",
"尝试冥想或深呼吸练习",
"与亲友沟通情绪"
],
'fatigue': [
"保证每日7-8小时睡眠",
"增加富含铁的食物摄入",
"避免过度劳累"
]
}
def add_symptom(self, record: SymptomRecord):
self.symptom_history.append(record)
def get_prediction_for_date(self, target_date: datetime) -> dict:
if not self.symptom_history:
return {"warnings": [], "advice": []}
symptom_freq = {}
for record in self.symptom_history:
days_before = (record.date - target_date).days
if -7 <= days_before <= 1:
for symptom in record.symptoms:
symptom_freq[symptom] = symptom_freq.get(symptom, 0) + 1
warnings = []
advice = []
for symptom, freq in symptom_freq.items():
if freq >= 2:
warnings.append({
"symptom": self.COMMON_SYMPTOMS.get(symptom, symptom),
"risk_level": "high" if freq >= 3 else "medium"
})
if symptom in self.advice_knowledge_base:
advice.extend([
tip for tip in self.advice_knowledge_base[symptom]
if tip not in advice
][:2])
return {"warnings": warnings, "advice": advice}
# ==================== 3. 数字人对话系统 ====================
class DigitalHuman:
def __init__(self, user_name: str = "用户"):
self.user_name = user_name
self.templates = {
"period_start": Template("""
{{ name}},你好呀~ 🌸
根据我的记录,你的月经期预计明天({{ date }})开始哦。
温馨小贴士:
{% for tip in tips %}
• {{ tip }}
{% endfor %}
记得准备好卫生用品,注意保暖,少喝冷饮~
如果有不适,随时告诉我,我会陪着你❤️
"""),
"ovulation": Template("""
{{ name}},排卵期提醒来啦! 💫
预计排卵日为 {{ date }},是备孕的黄金时间哦~
建议:
{% for tip in tips %}
• {{ tip }}
{% endfor %}
保持好心情,祝你好孕!🍀
"""),
"general_checkin": Template("""
{{ name}},最近还好吗? 🌿
{{ message }}
别忘了:
{% for item in checklist %}
• {{ item }}
{% endfor %}
我一直在这里,随时倾听你的心声~ 🤍
""")
}
def generate_period_reminder(self, next_start: datetime) -> str:
tips = [
"准备舒适的卫生巾或月经杯",
"避免剧烈运动",
"多喝温水,少吃辛辣刺激食物"
]
return self.templates["period_start"].render(
name=self.user_name,
date=next_start.strftime("%m月%d日"),
tips=tips
).strip()
def generate_ovulation_reminder(self, ovulation_date: datetime) -> str:
tips = [
"注意观察宫颈黏液变化",
"可使用排卵试纸辅助检测",
"保持规律作息"
]
return self.templates["ovulation"].render(
name=self.user_name,
date=ovulation_date.strftime("%m月%d日"),
tips=tips
).strip()
def generate_checkin_message(self) -> str:
messages = [
"最近压力大吗?记得给自己一些放松的时间。",
"天气转凉,记得添衣保暖哦~",
"今天有好好吃饭吗?均衡饮食很重要!"
]
checklist = [
"记录今日身体感受",
"进行15分钟拉伸",
"喝够8杯水"
]
return self.templates["general_checkin"].render(
name=self.user_name,
message=np.random.choice(messages),
checklist=checklist
).strip()
# ==================== 4. 安全数据存储 ====================
class SecureDataStorage:
def __init__(self, db_path: str = "menstrual_data.db", password: str = None):
self.db_path = db_path
self.password = password or "default_passphrase_2025"
self.key = self._derive_key()
self.cipher = Fernet(self.key)
self.init_database()
def _derive_key(self) -> bytes:
key = hashlib.pbkdf2_hmac('sha256', self.password.encode(), b'salt_12345', 100000)
return base64.urlsafe_b64encode(key[:32])
def init_database(self):
with sqlite3.connect(self.db_path) as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS cycles (
id INTEGER PRIMARY KEY,
start_date_enc BLOB NOT NULL,
end_date_enc BLOB NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.execute('''
CREATE TABLE IF NOT EXISTS symptoms (
id INTEGER PRIMARY KEY,
date_enc BLOB NOT NULL,
symptoms_json_enc BLOB NOT NULL,
severity INTEGER,
notes_enc BLOB,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
def encrypt(self, data: str) -> bytes:
return self.cipher.encrypt(data.encode())
def decrypt(self, encrypted_data: bytes) -> str:
return self.cipher.decrypt(encrypted_data).decode()
def save_cycle(self, start: datetime, end: datetime):
start_enc = self.encrypt(start.isoformat())
end_enc = self.encrypt(end.isoformat())
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"INSERT INTO cycles (start_date_enc, end_date_enc) VALUES (?, ?)",
(start_enc, end_enc)
)
def load_cycles(self) -> List[Tuple[datetime, datetime]]:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.execute("SELECT start_date_enc, end_date_enc FROM cycles ORDER BY timestamp")
rows = cursor.fetchall()
cycles = []
for row in rows:
try:
start_str = self.decrypt(row[0])
end_str = self.decrypt(row[1])
start = datetime.fromisoformat(start_str)
end = datetime.fromisoformat(end_str)
cycles.append((start, end))
except Exception as e:
logger.warning(f"Decrypt failed: {e}")
return cycles
# ==================== 5. Flask Web API ====================
app = Flask(__name__)
# 初始化核心组件
predictor = MenstrualCyclePredictor()
symptom_engine = SymptomEngine()
digital_human = DigitalHuman(user_name="小美")
storage = SecureDataStorage(password="user_secure_password_2025")
# 加载历史数据
try:
for start, end in storage.load_cycles():
predictor.add_cycle(start, end)
logger.info(f"Loaded {len(predictor.history)} historical cycles.")
except Exception as e:
logger.error(f"Failed to load history: {e}")
# HTML前端界面(内联模板)
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>🌸 小美经期助手</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #fffaf8;
color: #333;
}
h1 { color: #e91e63; text-align: center; }
.reminder {
border: 1px solid #ffd6e7;
padding: 20px;
margin: 15px 0;
border-radius: 12px;
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
line-height: 1.8;
white-space: pre-line;
}
.bot { color: #d81b60; }
button {
background: #e91e63;
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
margin: 10px 0;
}
button:hover { background: #c2185b; }
</style>
</head>
<body>
<h1>🌸 小美经期助手</h1>
<button onclick="refresh()">🔄 刷新提醒</button>
<div id="reminders"></div>
<script>
async function refresh() {
const res = await fetch('/api/reminders');
const data = await res.json();
document.getElementById('reminders').innerHTML = `
<div class="reminder bot">${data.period_reminder}</div>
${data.ovulation_reminder ? `<div class="reminder bot">${data.ovulation_reminder}</div>` : ''}
<div class="reminder bot">${data.daily_checkin}</div>
`;
}
// 页面加载时自动刷新
refresh();
</script>
</body>
</html>
"""
@app.route('/')
def index():
return render_template_string(HTML_TEMPLATE)
@app.route('/api/predict', methods=['GET'])
def get_prediction():
try:
next_start, next_end, confidence = predictor.predict_next_cycle()
ovulation = predictor.predict_ovulation()
return jsonify({
"next_period": {
"start": next_start.isoformat(),
"end": next_end.isoformat(),
"confidence": round(confidence, 2)
},
"ovulation": ovulation.isoformat() if ovulation else None
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/symptoms', methods=['POST'])
def add_symptom():
data = request.json
record = SymptomRecord(
date=datetime.fromisoformat(data['date']),
symptoms=data['symptoms'],
severity=SymptomSeverity(data['severity']),
notes=data.get('notes', '')
)
symptom_engine.add_symptom(record)
return jsonify({"status": "success"})
@app.route('/api/reminders', methods=['GET'])
def get_reminders():
try:
next_start, _, _ = predictor.predict_next_cycle()
period_msg = digital_human.generate_period_reminder(next_start)
ovulation = predictor.predict_ovulation()
ovulation_msg = digital_human.generate_ovulation_reminder(ovulation) if ovulation else None
checkin_msg = digital_human.generate_checkin_message()
return jsonify({
"period_reminder": period_msg,
"ovulation_reminder": ovulation_msg,
"daily_checkin": checkin_msg
})
except Exception as e:
logger.error(f"Generate reminder error: {e}")
return jsonify({"error": str(e)}), 500
# ==================== 6. 模拟测试数据 ====================
def create_demo_data():
"""创建演示数据"""
demo_cycles = [
(datetime(2025, 8, 1), datetime(2025, 8, 5)),
(datetime(2025, 8, 29), datetime(2025, 9, 2)),
(datetime(2025, 9, 27), datetime(2025, 10, 1))
]
for start, end in demo_cycles:
predictor.add_cycle(start, end)
storage.save_cycle(start, end)
# 添加症状记录
symptom_record = SymptomRecord(
date=datetime(2025, 9, 28),
symptoms=['dysmenorrhea', 'fatigue'],
severity=SymptomSeverity.MODERATE,
notes="今天肚子有点疼"
)
symptom_engine.add_symptom(symptom_record)
logger.info("✅ 演示数据已创建")
if __name__ == '__main__':
# 创建演示数据
create_demo_data()
# 启动Flask应用
print("\n🚀 经期智能数字人系统已启动!")
print("👉 访问 http://127.0.0.1:5000 查看效果\n")
app.run(debug=True, host='127.0.0.1', port=5000)
926

被折叠的 条评论
为什么被折叠?



