智能生日管家系统
- 项目概述
实际应用场景
在现代快节奏的生活中,人们常常因为工作繁忙而忘记家人生日等重要日期。同时,为不同的人挑选合适的生日礼物也是一项挑战。本系统旨在解决这些痛点,成为您的贴心生日管家。
痛点分析
- 遗忘风险:工作忙碌导致忘记重要生日日期
- 礼物选择困难:不了解收礼人当前喜好,难以挑选合适礼物
- 时间管理不当:总是临时准备,缺乏充足时间
- 重复购买:可能重复送类似的礼物
- 预算控制困难:难以合理分配礼物预算
- 核心逻辑
系统架构
数据采集层 → 智能分析层 → 提醒服务层 → 推荐引擎层 ↓ ↓ ↓ ↓ 生日信息 喜好分析 定时提醒 礼物推荐
关键算法
-
时间预测算法:提前7天精准提醒
-
喜好学习算法:基于历史数据优化推荐
-
预算分配算法:智能分配年度礼物预算
-
相似度匹配:找到最匹配的礼物类型
-
代码实现
项目结构
birthday_manager/ ├── main.py # 主程序入口 ├── data/ # 数据目录 │ ├── family_members.json │ ├── gift_history.json │ └── gift_categories.json ├── modules/ # 功能模块 │ ├── birthday_manager.py │ ├── reminder_system.py │ ├── gift_recommender.py │ ├── preference_analyzer.py │ └── notification_service.py ├── config.py # 配置文件 ├── scheduler.py # 定时任务调度 └── README.md
核心代码
main.py - 主程序
#!/usr/bin/env python3 """ 智能生日管家系统主程序 """
import sys import json from datetime import datetime, timedelta from modules.birthday_manager import BirthdayManager from modules.gift_recommender import GiftRecommender from modules.reminder_system import ReminderSystem from modules.preference_analyzer import PreferenceAnalyzer from notification_service import NotificationService from utils import setup_logging, load_config
class BirthdayButler: """智能生日管家"""
def __init__(self):
self.config = load_config()
self.logger = setup_logging()
self.birthday_manager = BirthdayManager()
self.gift_recommender = GiftRecommender()
self.reminder_system = ReminderSystem()
self.preference_analyzer = PreferenceAnalyzer()
self.notification_service = NotificationService()
def run(self, mode="interactive"):
"""
运行主程序
Args:
mode: 运行模式 (interactive/batch/daemon)
"""
try:
print("🎂 欢迎使用智能生日管家系统!")
print("=" * 50)
if mode == "interactive":
self._run_interactive_mode()
elif mode == "batch":
self._run_batch_mode()
elif mode == "daemon":
self._run_daemon_mode()
except KeyboardInterrupt:
print("\n\n👋 感谢使用,再见!")
except Exception as e:
self.logger.error(f"程序运行出错: {e}")
print(f"❌ 程序运行出错: {e}")
def _run_interactive_mode(self):
"""交互式模式"""
while True:
print("\n📋 请选择操作:")
print("1. 添加家庭成员")
print("2. 查看生日列表")
print("3. 手动触发提醒")
print("4. 获取礼物推荐")
print("5. 查看礼物历史")
print("6. 退出系统")
choice = input("\n请输入选择 (1-6): ").strip()
if choice == "1":
self._add_family_member()
elif choice == "2":
self._show_birthday_list()
elif choice == "3":
self._trigger_reminders()
elif choice == "4":
self._get_gift_recommendations()
elif choice == "5":
self._show_gift_history()
elif choice == "6":
break
else:
print("⚠️ 无效选择,请重新输入")
def _add_family_member(self):
"""添加家庭成员"""
print("\n👥 添加家庭成员")
name = input("姓名: ").strip()
birthday_str = input("生日 (YYYY-MM-DD): ").strip()
relationship = input("关系 (如:父亲、母亲、配偶): ").strip()
print("\n🎁 兴趣爱好 (可多选,用逗号分隔):")
print("可选: 阅读, 运动, 音乐, 美食, 旅行, 科技, 艺术, 园艺, 宠物, 摄影")
hobbies_input = input("兴趣爱好: ").strip()
hobbies = [h.strip() for h in hobbies_input.split(",")] if hobbies_input else []
budget_input = input("年度礼物预算 (元): ").strip()
annual_budget = float(budget_input) if budget_input else 1000.0
member_data = {
"name": name,
"birthday": birthday_str,
"relationship": relationship,
"hobbies": hobbies,
"annual_budget": annual_budget,
"gift_history": []
}
if self.birthday_manager.add_member(member_data):
print(f"✅ 成功添加 {name} 的信息!")
else:
print("❌ 添加失败,请检查输入格式")
def _show_birthday_list(self):
"""显示生日列表"""
members = self.birthday_manager.get_all_members()
if not members:
print("📝 暂无家庭成员信息")
return
print("\n🎂 家庭成员生日列表:")
print("-" * 60)
today = datetime.now()
for member in members:
next_birthday = self.birthday_manager.get_next_birthday(member["birthday"])
days_until = (next_birthday - today).days
status = "🎉 今天" if days_until == 0 else f"⏰ {days_until}天后"
print(f"{member['name']} ({member['relationship']})")
print(f" 生日: {member['birthday']} | {status}")
print(f" 兴趣: {', '.join(member['hobbies'])}")
print(f" 预算: ¥{member['annual_budget']}/年")
print("-" * 40)
def _trigger_reminders(self):
"""手动触发提醒"""
print("\n🔔 检查即将到来的生日...")
upcoming = self.reminder_system.check_upcoming_birthdays(days_ahead=7)
if not upcoming:
print("📅 未来7天内没有即将到来的生日")
return
print(f"发现 {len(upcoming)} 个即将到来的生日:")
for item in upcoming:
print(f"\n🎂 {item['name']} 的生日还有 {item['days_until']} 天")
print(f" 建议准备时间: {item['suggested_prep_days']} 天")
print(f" 推荐开始准备日期: {item['prep_start_date']}")
def _get_gift_recommendations(self):
"""获取礼物推荐"""
members = self.birthday_manager.get_all_members()
if not members:
print("📝 请先添加家庭成员信息")
return
print("\n👥 选择要推荐礼物的成员:")
for i, member in enumerate(members, 1):
print(f"{i}. {member['name']} ({member['relationship']})")
try:
choice = int(input("请选择 (输入数字): ")) - 1
if 0 <= choice < len(members):
selected_member = members[choice]
recommendations = self.gift_recommender.recommend_for_member(selected_member)
print(f"\n🎁 为 {selected_member['name']} 推荐的礼物:")
print("=" * 50)
for i, rec in enumerate(recommendations, 1):
print(f"\n{i}. {rec['name']}")
print(f" 类别: {rec['category']}")
print(f" 价格区间: ¥{rec['price_min']} - ¥{rec['price_max']}")
print(f" 推荐理由: {rec['reason']}")
print(f" 匹配度: {'⭐' * rec['match_score']}")
except (ValueError, IndexError):
print("⚠️ 无效选择")
def _show_gift_history(self):
"""显示礼物历史"""
history = self.gift_recommender.get_gift_history()
if not history:
print("📝 暂无礼物赠送历史")
return
print("\n📜 礼物赠送历史:")
print("-" * 60)
for record in history[-10:]: # 显示最近10条记录
print(f"🎁 {record['recipient']} - {record['gift_name']}")
print(f" 日期: {record['date']} | 价格: ¥{record['price']}")
print(f" 满意度: {'⭐' * record['satisfaction']}")
print("-" * 40)
def main(): """主函数""" butler = BirthdayButler()
# 解析命令行参数
mode = "interactive"
if len(sys.argv) > 1:
mode = sys.argv[1]
butler.run(mode)
if name == "main": main()
birthday_manager.py - 生日管理模块
""" 生日管理模块 负责管理家庭成员信息和生日日期 """
import json import os from datetime import datetime, date from typing import List, Dict, Optional from dataclasses import dataclass
@dataclass class FamilyMember: """家庭成员数据类""" id: int name: str birthday: str # YYYY-MM-DD格式 relationship: str hobbies: List[str] annual_budget: float created_at: str
class BirthdayManager: """生日管理器"""
def __init__(self, data_file="data/family_members.json"):
self.data_file = data_file
self.members = self._load_members()
self.next_id = max([m.id for m in self.members], default=0) + 1
def _load_members(self) -> List[FamilyMember]:
"""加载成员数据"""
try:
os.makedirs(os.path.dirname(self.data_file), exist_ok=True)
if os.path.exists(self.data_file):
with open(self.data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
return [FamilyMember(**item) for item in data]
else:
return []
except Exception as e:
print(f"加载成员数据出错: {e}")
return []
def _save_members(self):
"""保存成员数据"""
try:
os.makedirs(os.path.dirname(self.data_file), exist_ok=True)
data = [{
'id': m.id,
'name': m.name,
'birthday': m.birthday,
'relationship': m.relationship,
'hobbies': m.hobbies,
'annual_budget': m.annual_budget,
'created_at': m.created_at
} for m in self.members]
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存成员数据出错: {e}")
def add_member(self, member_data: Dict) -> bool:
"""
添加家庭成员
Args:
member_data: 成员信息字典
Returns:
bool: 是否添加成功
"""
try:
# 验证必填字段
required_fields = ['name', 'birthday', 'relationship']
for field in required_fields:
if field not in member_data or not member_data[field]:
return False
# 验证生日格式
datetime.strptime(member_data['birthday'], '%Y-%m-%d')
# 创建新成员
new_member = FamilyMember(
id=self.next_id,
name=member_data['name'],
birthday=member_data['birthday'],
relationship=member_data['relationship'],
hobbies=member_data.get('hobbies', []),
annual_budget=member_data.get('annual_budget', 1000.0),
created_at=datetime.now().isoformat()
)
self.members.append(new_member)
self.next_id += 1
self._save_members()
return True
except ValueError:
print("❌ 生日格式错误,请使用 YYYY-MM-DD 格式")
return False
except Exception as e:
print(f"添加成员失败: {e}")
return False
def get_all_members(self) -> List[FamilyMember]:
"""获取所有成员"""
return sorted(self.members, key=lambda m: m.birthday)
def get_member_by_id(self, member_id: int) -> Optional[FamilyMember]:
"""根据ID获取成员"""
for member in self.members:
if member.id == member_id:
return member
return None
def update_member(self, member_id: int, updates: Dict) -> bool:
"""更新成员信息"""
member = self.get_member_by_id(member_id)
if not member:
return False
for key, value in updates.items():
if hasattr(member, key):
setattr(member, key, value)
self._save_members()
return True
def delete_member(self, member_id: int) -> bool:
"""删除成员"""
member = self.get_member_by_id(member_id)
if member:
self.members.remove(member)
self._save_members()
return True
return False
def get_next_birthday(self, birthday_str: str) -> date:
"""
获取下一个生日日期
Args:
birthday_str: 生日字符串 (YYYY-MM-DD)
Returns:
date: 下一个生日日期
"""
birthday_month, birthday_day = map(int, birthday_str.split('-')[1:])
today = datetime.now().date()
current_year = today.year
# 今年的生日
try:
this_year_birthday = date(current_year, birthday_month, birthday_day)
except ValueError:
# 处理2月29日的情况
this_year_birthday = date(current_year, 3, 1)
# 如果今年生日已过,则计算明年生日
if this_year_birthday < today:
try:
next_year_birthday = date(current_year + 1, birthday_month, birthday_day)
except ValueError:
next_year_birthday = date(current_year + 1, 3, 1)
return next_year_birthday
else:
return this_year_birthday
def get_days_until_birthday(self, birthday_str: str) -> int:
"""计算距离生日的天数"""
next_birthday = self.get_next_birthday(birthday_str)
today = datetime.now().date()
return (next_birthday - today).days
def get_birthday_stats(self) -> Dict:
"""获取生日统计信息"""
if not self.members:
return {}
today = datetime.now().date()
upcoming_birthdays = []
for member in self.members:
days_until = self.get_days_until_birthday(member.birthday)
if days_until <= 30: # 未来30天内的生日
upcoming_birthdays.append({
'name': member.name,
'days_until': days_until,
'birthday': member.birthday
})
return {
'total_members': len(self.members),
'upcoming_birthdays': sorted(upcoming_birthdays, key=lambda x: x['days_until']),
'birthday_months': self._get_birthday_distribution()
}
def _get_birthday_distribution(self) -> Dict[int, int]:
"""获取生日月份分布"""
distribution = {}
for member in self.members:
month = int(member.birthday.split('-')[1])
distribution[month] = distribution.get(month, 0) + 1
return distribution
gift_recommender.py - 礼物推荐模块
""" 礼物推荐模块 基于用户喜好和历史数据推荐合适的生日礼物 """
import json import random import os from datetime import datetime from typing import List, Dict, Tuple from collections import defaultdict, Counter import math
class GiftRecommender: """礼物推荐器"""
def __init__(self):
self.gift_database = self._load_gift_database()
self.gift_history = self._load_gift_history()
def _load_gift_database(self) -> Dict:
"""加载礼物数据库"""
default_gifts = {
"阅读": [
{"name": "畅销书单精选", "price_min": 50, "price_max": 200, "category": "书籍"},
{"name": "Kindle电子书阅读器", "price_min": 800, "price_max": 1200, "category": "数码"},
{"name": "精美书签套装", "price_min": 30, "price_max": 80, "category": "文具"}
],
"运动": [
{"name": "专业运动跑鞋", "price_min": 300, "price_max": 800, "category": "运动装备"},
{"name": "智能手环", "price_min": 200, "price_max": 500, "category": "数码"},
{"name": "健身会员年卡", "price_min": 1000, "price_max": 2000, "category": "服务"}
],
"音乐": [
{"name": "高品质耳机", "price_min": 200, "price_max": 1000, "category": "音频设备"},
{"name": "黑胶唱片机", "price_min": 500, "price_max": 1500, "category": "音响设备"},
{"name": "音乐会门票", "price_min": 200, "price_max": 800, "category": "体验"}
],
"美食": [
{"name": "高档红酒", "price_min": 200, "price_max": 500, "category": "酒类"},
{"name": "米其林餐厅代金券", "price_min": 500, "price_max": 1000, "category": "餐饮"},
{"name": "烘焙课程体验", "price_min": 300, "price_max": 600, "category": "体验"}
],
"旅行": [
{"name": "旅行背包", "price_min": 200, "price_max": 600, "category": "旅行用品"},
{"name": "便携相机", "price_min": 800, "price_max": 2000, "category": "数码"},
{"name": "旅行保险套餐", "price_min": 100, "price_max": 300, "category": "服务"}
],
"科技": [
{"name": "最新智能手机", "price_min": 2000, "price_max": 5000, "category": "数码"},
{"name": "智能家居套装", "price_min": 500, "price_max": 1500, "category": "智能家居"},
{"name": "VR头戴设备", "price_min": 1000, "price_max": 2500, "category": "数码"}
],
"艺术": [
{"name": "绘画工具套装", "price_min": 100, "price_max": 400, "category": "艺术用品"},
{"name": "美术馆年卡", "price_min": 300, "price_max": 600, "category": "文化"},
{"name": "艺术品复制品", "price_min": 200, "price_max": 800, "category": "装饰"}
],
"园艺": [
{"name": "多肉植物套装", "price_min": 50, "price_max": 150, "category": "植物"},
{"name": "园艺工具套装", "price_min": 100, "price_max": 300, "category": "工具"},
{"name": "智能浇水器", "price_min": 200, "price_max": 500, "category": "智能设备"}
],
"宠物": [
{"name": "高端宠物食品", "price_min": 100, "price_max": 300, "category": "宠物用品"},
{"name": "宠物写真拍摄", "price_min": 500, "price_max": 1000, "category": "服务"},
{"name": "智能宠物玩具", "price_min": 80, "price_max": 200, "category": "宠物用品"}
],
"摄影": [
{"name": "专业三脚架", "price_min": 300, "price_max": 800, "category": "摄影器材"},
{"name": "滤镜套装", "price_min": 200, "price_max": 500, "category": "摄影配件"},
{"name": "摄影培训课程", "price_min": 1000, "price_max": 3000, "category": "教育"}
]
}
# 确保数据目录存在
os.makedirs('data', exist_ok=True)
try:
with open('data/gift_categories.json', 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
with open('data/gift_categories.json', 'w', encoding='utf-8') as f:
json.dump(default_gifts, f, ensure_ascii=False, indent=2)
return default_gifts
def _load_gift_history(self) -> List[Dict]:
"""加载礼物历史记录"""
try:
with open('data/gift_history.json', 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
return []
def _save_gift_history(self):
"""保存礼物历史记录"""
with open('data/gift_history.json', 'w', encoding='utf-8') as f:
json.dump(self.gift_history, f, ensure_ascii=False, indent=2)
def recommend_for_member(self, member: Dict, budget_limit: float = None) -> List[Dict]:
"""
为指定成员推荐礼物
Args:
member: 成员信息
budget_limit: 预算限制
Returns:
推荐礼物列表
"""
if not budget_limit:
budget_limit = member.get('annual_budget', 1000) / 2 # 默认使用年度预算的一半
recommendations = []
# 基于兴趣爱好的推荐
hobby_matches = self._get_hobby_based_recommendations(
member['hobbies'], budget_limit
)
recommendations.extend(hobby_matches)
# 基于历史偏好的推荐
history_matches = self._get_history_based_recommendations(
member['name'], budget_limit
)
recommendations.extend(history_matches)
# 基于预算的推荐
budget_matches = self._get_budget_friendly_recommendations(
budget_limit
)
recommendations.extend(budget_matches)
# 去重和评分
unique_recommendations = self._deduplicate_and_score(recommendations)
# 按评分排序并返回前5个
unique_recommendations.sort(key=lambd
如果你觉得这个工具好用,欢迎关注我!