输入家庭成员的生日和喜好,提前七天发送提醒,还能推荐适合的生日礼物。

24 阅读9分钟

智能生日管家系统

  1. 项目概述

实际应用场景

在现代快节奏的生活中,人们常常因为工作繁忙而忘记家人生日等重要日期。同时,为不同的人挑选合适的生日礼物也是一项挑战。本系统旨在解决这些痛点,成为您的贴心生日管家。

痛点分析

  • 遗忘风险:工作忙碌导致忘记重要生日日期
  • 礼物选择困难:不了解收礼人当前喜好,难以挑选合适礼物
  • 时间管理不当:总是临时准备,缺乏充足时间
  • 重复购买:可能重复送类似的礼物
  • 预算控制困难:难以合理分配礼物预算
  1. 核心逻辑

系统架构

数据采集层 → 智能分析层 → 提醒服务层 → 推荐引擎层 ↓ ↓ ↓ ↓ 生日信息 喜好分析 定时提醒 礼物推荐

关键算法

  1. 时间预测算法:提前7天精准提醒

  2. 喜好学习算法:基于历史数据优化推荐

  3. 预算分配算法:智能分配年度礼物预算

  4. 相似度匹配:找到最匹配的礼物类型

  5. 代码实现

项目结构

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

如果你觉得这个工具好用,欢迎关注我!