我将为您创建一个完整的宠物健康管理程序,用于分析宠物的喂食和运动数据,判断是否超重并提供科学的喂养建议。
项目结构
pet_health_manager/ ├── main.py # 主程序入口 ├── pet_data_manager.py # 数据管理模块 ├── health_analyzer.py # 健康分析模块 ├── nutrition_planner.py # 营养规划模块 ├── utils.py # 工具函数 ├── config.py # 配置文件 ├── data/ # 数据存储目录 │ ├── pets.json # 宠物基本信息 │ └── records.csv # 日常记录数据 ├── README.md # 使用说明 └── requirements.txt # 依赖包列表
- requirements.txt
pandas==2.0.3 numpy==1.24.3 matplotlib==3.7.2 seaborn==0.12.2 openpyxl==3.1.2 datetime json os random
- config.py
""" 配置文件 - 定义宠物健康管理的默认参数和标准 """
宠物类型配置
PET_TYPES = { 'dog': { 'small': {'weight_range': (1, 10), 'activity_level': 'medium'}, 'medium': {'weight_range': (10, 25), 'activity_level': 'high'}, 'large': {'weight_range': (25, 45), 'activity_level': 'high'} }, 'cat': { 'small': {'weight_range': (2, 4), 'activity_level': 'medium'}, 'medium': {'weight_range': (4, 6), 'activity_level': 'low'}, 'large': {'weight_range': (6, 10), 'activity_level': 'low'} } }
标准热量需求 (kcal/天)
BASE_CALORIES = { 'dog': { 'small': 300, 'medium': 500, 'large': 800 }, 'cat': { 'small': 200, 'medium': 250, 'large': 300 } }
活动系数
ACTIVITY_FACTORS = { 'low': 0.8, # 低活动量 'medium': 1.0, # 中等活动量 'high': 1.2 # 高活动量 }
超重判断阈值 (BMI)
OVERWEIGHT_THRESHOLDS = { 'dog': 0.9, # BMI超过标准90%为超重 'cat': 0.85 # 猫的标准更严格 }
体重指数计算公式系数
BMI_COEFFICIENTS = { 'dog': {'a': 1.2, 'b': 1.0}, 'cat': {'a': 1.0, 'b': 1.0} }
数据存储路径
DATA_PATHS = { 'pets_file': 'data/pets.json', 'records_file': 'data/records.csv' }
- utils.py
""" 工具函数模块 - 包含数据处理和计算的辅助函数 """
import json import pandas as pd import numpy as np from datetime import datetime, timedelta import os from typing import Dict, List, Tuple, Optional
def ensure_data_directory(): """确保数据目录存在""" os.makedirs('data', exist_ok=True)
def load_pet_data() -> Dict: """ 加载宠物基本信息数据
Returns:
宠物数据字典
"""
ensure_data_directory()
pets_file = 'data/pets.json'
if os.path.exists(pets_file):
try:
with open(pets_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"加载宠物数据失败: {e}")
return {}
else:
# 返回示例数据
sample_data = {
"1": {
"name": "旺财",
"type": "dog",
"breed": "金毛",
"birth_date": "2020-05-15",
"gender": "male",
"ideal_weight": 28.5,
"notes": "活泼好动,喜欢跑步"
},
"2": {
"name": "咪咪",
"type": "cat",
"breed": "英短",
"birth_date": "2019-08-20",
"gender": "female",
"ideal_weight": 4.2,
"notes": "比较懒,不爱运动"
}
}
save_pet_data(sample_data)
return sample_data
def save_pet_data(data: Dict) -> bool: """ 保存宠物基本信息数据
Args:
data: 宠物数据字典
Returns:
保存是否成功
"""
ensure_data_directory()
pets_file = 'data/pets.json'
try:
with open(pets_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
return True
except Exception as e:
print(f"保存宠物数据失败: {e}")
return False
def load_records_data() -> pd.DataFrame: """ 加载日常记录数据
Returns:
记录数据的DataFrame
"""
ensure_data_directory()
records_file = 'data/records.csv'
if os.path.exists(records_file):
try:
return pd.read_csv(records_file, parse_dates=['date'])
except Exception as e:
print(f"加载记录数据失败: {e}")
return pd.DataFrame()
else:
# 创建空的DataFrame结构
columns = ['pet_id', 'date', 'food_amount', 'food_type',
'exercise_duration', 'exercise_type', 'weight', 'notes']
df = pd.DataFrame(columns=columns)
df['date'] = pd.to_datetime(df['date'])
save_records_data(df)
return df
def save_records_data(df: pd.DataFrame) -> bool: """ 保存日常记录数据
Args:
df: 记录数据的DataFrame
Returns:
保存是否成功
"""
ensure_data_directory()
records_file = 'data/records.csv'
try:
df.to_csv(records_file, index=False, encoding='utf-8')
return True
except Exception as e:
print(f"保存记录数据失败: {e}")
return False
def calculate_age(birth_date_str: str) -> int: """ 计算宠物年龄(以月为单位)
Args:
birth_date_str: 出生日期字符串 (YYYY-MM-DD)
Returns:
年龄(月)
"""
try:
birth_date = datetime.strptime(birth_date_str, '%Y-%m-%d')
today = datetime.now()
age_months = (today.year - birth_date.year) * 12 + (today.month - birth_date.month)
return max(0, age_months)
except Exception as e:
print(f"计算年龄失败: {e}")
return 0
def calculate_bmi(pet_type: str, weight: float, ideal_weight: float) -> float: """ 计算宠物体重指数 (BMI)
Args:
pet_type: 宠物类型
weight: 当前体重
ideal_weight: 理想体重
Returns:
BMI值
"""
if ideal_weight <= 0:
return 0
# 简化的BMI计算,实际应用中可能需要更复杂的公式
bmi = weight / ideal_weight
return bmi
def get_date_range(days: int = 7) -> Tuple[datetime, datetime]: """ 获取日期范围
Args:
days: 天数
Returns:
开始日期和结束日期
"""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
return start_date, end_date
def validate_input_data(data: Dict) -> bool: """ 验证输入数据的有效性
Args:
data: 输入数据字典
Returns:
数据是否有效
"""
required_fields = ['pet_id', 'date', 'food_amount', 'exercise_duration', 'weight']
for field in required_fields:
if field not in data or data[field] is None:
return False
# 验证数值范围
if data['food_amount'] <= 0 or data['exercise_duration'] < 0 or data['weight'] <= 0:
return False
return True
4. pet_data_manager.py
""" 宠物数据管理模块 - 负责宠物信息和记录的增删改查 """
import pandas as pd from typing import Dict, List, Optional from datetime import datetime, timedelta from utils import * from config import DATA_PATHS
class PetDataManager: """宠物数据管理器"""
def __init__(self):
self.pets_data = load_pet_data()
self.records_df = load_records_data()
def add_pet(self, pet_info: Dict) -> bool:
"""
添加新宠物
Args:
pet_info: 宠物信息字典
Returns:
添加是否成功
"""
try:
# 生成唯一ID
pet_id = str(max([int(id) for id in self.pets_data.keys()] + [0]) + 1)
# 验证必需字段
required_fields = ['name', 'type', 'breed', 'birth_date', 'gender', 'ideal_weight']
for field in required_fields:
if field not in pet_info:
raise ValueError(f"缺少必需字段: {field}")
# 添加创建时间
pet_info['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
pet_info['age_months'] = calculate_age(pet_info['birth_date'])
self.pets_data[pet_id] = pet_info
return save_pet_data(self.pets_data)
except Exception as e:
print(f"添加宠物失败: {e}")
return False
def update_pet(self, pet_id: str, pet_info: Dict) -> bool:
"""
更新宠物信息
Args:
pet_id: 宠物ID
pet_info: 新的宠物信息
Returns:
更新是否成功
"""
try:
if pet_id not in self.pets_data:
raise ValueError(f"宠物ID {pet_id} 不存在")
# 更新年龄
if 'birth_date' in pet_info:
pet_info['age_months'] = calculate_age(pet_info['birth_date'])
self.pets_data[pet_id].update(pet_info)
return save_pet_data(self.pets_data)
except Exception as e:
print(f"更新宠物信息失败: {e}")
return False
def delete_pet(self, pet_id: str) -> bool:
"""
删除宠物
Args:
pet_id: 宠物ID
Returns:
删除是否成功
"""
try:
if pet_id not in self.pets_data:
raise ValueError(f"宠物ID {pet_id} 不存在")
del self.pets_data[pet_id]
return save_pet_data(self.pets_data)
except Exception as e:
print(f"删除宠物失败: {e}")
return False
def get_pet_info(self, pet_id: str) -> Optional[Dict]:
"""
获取宠物信息
Args:
pet_id: 宠物ID
Returns:
宠物信息字典
"""
return self.pets_data.get(pet_id)
def list_all_pets(self) -> Dict:
"""
获取所有宠物列表
Returns:
所有宠物信息
"""
return self.pets_data
def add_record(self, record: Dict) -> bool:
"""
添加日常记录
Args:
record: 记录信息字典
Returns:
添加是否成功
"""
try:
# 验证数据
if not validate_input_data(record):
raise ValueError("输入数据无效")
# 确保日期格式正确
if isinstance(record['date'], str):
record['date'] = pd.to_datetime(record['date'])
# 创建新的记录行
new_record = pd.DataFrame([record])
# 合并到现有数据
if self.records_df.empty:
self.records_df = new_record
else:
self.records_df = pd.concat([self.records_df, new_record], ignore_index=True)
return save_records_data(self.records_df)
except Exception as e:
print(f"添加记录失败: {e}")
return False
def get_pet_records(self, pet_id: str, days: int = 30) -> pd.DataFrame:
"""
获取指定宠物的记录
Args:
pet_id: 宠物ID
days: 获取最近多少天的记录
Returns:
记录DataFrame
"""
if self.records_df.empty:
return pd.DataFrame()
# 筛选指定宠物的记录
pet_records = self.records_df[self.records_df['pet_id'] == pet_id].copy()
if pet_records.empty:
return pd.DataFrame()
# 筛选日期范围
start_date, end_date = get_date_range(days)
pet_records = pet_records[
(pet_records['date'] >= start_date) &
(pet_records['date'] <= end_date)
]
# 按日期排序
pet_records = pet_records.sort_values('date', ascending=False)
return pet_records
def get_latest_weight(self, pet_id: str) -> Optional[float]:
"""
获取宠物最新体重
Args:
pet_id: 宠物ID
Returns:
最新体重,如果没有记录则返回None
"""
records = self.get_pet_records(pet_id, days=365) # 查找一年的记录
if records.empty:
return None
latest_record = records.iloc[0]
return latest_record['weight']
def get_average_food_intake(self, pet_id: str, days: int = 7) -> float:
"""
获取平均食物摄入量
Args:
pet_id: 宠物ID
days: 天数
Returns:
平均每天食物摄入量
"""
records = self.get_pet_records(pet_id, days)
if records.empty:
return 0.0
return records['food_amount'].mean()
def get_average_exercise(self, pet_id: str, days: int = 7) -> float:
"""
获取平均运动量
Args:
pet_id: 宠物ID
days: 天数
Returns:
平均每天运动时间(分钟)
"""
records = self.get_pet_records(pet_id, days)
if records.empty:
return 0.0
return records['exercise_duration'].mean()
5. health_analyzer.py
""" 健康分析模块 - 分析宠物健康状况,判断是否超重 """
import pandas as pd import numpy as np from typing import Dict, Tuple, List from datetime import datetime, timedelta from utils import * from config import *
class HealthAnalyzer: """宠物健康分析器"""
def __init__(self, data_manager: PetDataManager):
self.data_manager = data_manager
def analyze_weight_status(self, pet_id: str) -> Dict:
"""
分析宠物体重状态
Args:
pet_id: 宠物ID
Returns:
分析结果字典
"""
pet_info = self.data_manager.get_pet_info(pet_id)
if not pet_info:
return {"error": "宠物信息不存在"}
current_weight = self.data_manager.get_latest_weight(pet_id)
if current_weight is None:
return {"error": "没有体重记录"}
ideal_weight = pet_info['ideal_weight']
pet_type = pet_info['type']
# 计算BMI
bmi = calculate_bmi(pet_type, current_weight, ideal_weight)
# 判断是否超重
threshold = OVERWEIGHT_THRESHOLDS.get(pet_type, 0.9)
is_overweight = bmi > threshold
# 计算体重偏差百分比
weight_diff_percent = ((current_weight - ideal_weight) / ideal_weight) * 100
# 健康状态评级
if abs(weight_diff_percent) <= 5:
status = "理想"
status_color = "green"
elif weight_diff_percent > 5:
status = "超重"
status_color = "red"
else:
status = "偏瘦"
status_color = "orange"
analysis_result = {
"pet_name": pet_info['name'],
"pet_type": pet_type,
"current_weight": round(current_weight, 2),
"ideal_weight": ideal_weight,
"weight_difference": round(current_weight - ideal_weight, 2),
"weight_diff_percent": round(weight_diff_percent, 1),
"bmi": round(bmi, 3),
"threshold": threshold,
"is_overweight": is_overweight,
"status": status,
"status_color": status_color,
"analysis_date": datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
return analysis_result
def analyze_food_intake(self, pet_id: str, days: int = 7) -> Dict:
"""
分析食物摄入情况
Args:
pet_id: 宠物ID
days: 分析天数
Returns:
食物摄入分析结果
"""
pet_info = self.data_manager.get_pet_info(pet_id)
if not pet_info:
return {"error": "宠物信息不存在"}
average_food = self.data_manager.get_average_food_intake(pet_id, days)
if average_food == 0:
return {"error": "没有足够的食物摄入记录"}
# 计算推荐食物量
recommended_food = self.calculate_recommended_food(pet_id)
# 分析摄入情况
food_ratio = average_food / recommended_food if recommended_food > 0 else 0
if food_ratio < 0.8:
food_status = "摄入不足"
food_advice = "适当增加食物分量"
elif food_ratio > 1.2:
food_status = "摄入过量"
food_advice = "适当减少食物分量"
else:
food_status = "摄入正常"
food_advice = "保持当前饮食量"
analysis_result = {
"average_daily_food": round(average_food, 1),
"recommended_food": round(recommended_food, 1),
"food_ratio": round(food_ratio, 2),
"food_status": food_status,
"advice": food_advice,
"analysis_days": days
}
return analysis_result
def analyze_exercise(self, pet_id: str, days: int = 7) -> Dict:
"""
分析运动情况
Args:
pet_id: 宠物ID
days: 分析天数
Returns:
运动分析结果
"""
pet_info = self.data_manager.get_pet_info(pet_id)
if not pet_info:
return {"error": "宠物信息不存在"}
average_exercise = self.data_manager.get_average_exercise(pet_id, days)
if average_exercise == 0:
return {"error": "没有足够的运动记录"}
# 根据宠物类型和年龄推荐运动量
recommended_exercise = self.calculate_recommended_exercise(pet_id)
# 分析运动情况
exercise_ratio = average_exercise / recommended_exercise if recommended_exercise > 0 else 0
if exercise_ratio < 0.7:
exercise_status = "运动不足"
exercise_advice = "增加日常运动量,多散步或游戏"
elif exercise_ratio > 1.3:
exercise_status = "运动充足"
exercise_advice = "运动量合适,继续保持"
else:
exercise_status = "运动适中"
exercise_advice = "运动量基本合适"
analysis_result = {
"average_daily_exercise": round(average_exercise, 1),
"recommended_exercise": round(recommended_exercise, 1),
"exercise_ratio": round(exercise_ratio, 2),
"exercise_status": exercise_status,
"advice": exercise_advice,
"analysis_days": days
}
return analysis_result
def calculate_recommended_food(self, pet_id: str) -> float:
"""
计算推荐食物量
Args:
pet_id: 宠物ID
Returns:
推荐每日食物量(克)
"""
pet_info = self.data_manager.get_pet_info(pet_id)
if not pet_info:
return 0
pet_type = pet_info['type']
breed = pet_info['breed']
age_months = pet_info.get('age_months', 12)
# 确定体型分类
weight = pet_info['ideal_weight']
size_category = self._determine_size_category(pet_type, weight)
# 获取基础热量需求
base_calories = BASE_CALORIES.get(pet_type, {}).get(size_category, 300)
# 根据年龄调整
if age_months < 12: # 幼年期
age_factor = 1.5 if pet_type == 'dog' else 2.0
elif age_months < 84: # 成年期
age_factor = 1.0
else: # 老年期
age_factor = 0.8
# 根据活动水平调整(简化处理)
activity_factor = ACTIVITY_FACTORS.get('medium', 1.0)
# 计算总热量需求
total_calories = base_calories * age_factor * activity_factor
# 转换为食物重量(假设食物热量密度为4 kcal/g)
food_amount = total_calories / 4
return food_amount
def calculate_recommended_exercise(self, pet_id: str) -> float:
"""
计算推荐运动量
Args:
pet_id: 宠物ID
Returns:
推荐每日运动时间(分钟)
"""
pet_info = self.data_manager.get_pet_info(pet_id)
if not pet_info:
return 0
pet_type = pet_info['type']
age_months = pet_info.get('age_months', 12)
# 基础运动量
if pet_type == 'dog':
if age_months < 12: # 幼犬
base_exercise = 30
elif age_months < 84: # 成犬
base_exercise = 60
else: # 老犬
base_exercise = 40
else: # 猫
if age_months < 12: # 幼猫
base_exercise = 20
elif age_months < 120: # 成猫
base_exercise = 30
else: # 老猫
base_exercise = 20
return base_exercise
def _determine_size_category(self, pet_type: str, weight: float) -> str:
"""
确定宠物体型分类
Args:
pet_type: 宠物类型
weight: 体重
Returns:
体型分类
"""
type_config = PET_TYPES.get(pet_type, {})
for category, info in type_config.items():
weight_range = in
关注我,有更多实用程序等着你!