Files

142 lines
4.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
import json
from datetime import datetime
from typing import Optional, List
from functools import lru_cache
from openai import OpenAI
from cnlunar import Lunar
from app.config.setting import settings
class CalendarService:
"""万年历服务 - 使用 cnlunar 获取农历信息DeepSeek 生成宜忌"""
# 内存缓存,存储日期对应的宜忌数据
_yi_ji_cache: dict = {}
@classmethod
def get_calendar_info(cls, year: Optional[int] = None, month: Optional[int] = None, day: Optional[int] = None) -> dict:
"""
获取万年历信息
参数:
- year: 年份,默认今年
- month: 月份,默认本月
- day: 日期,默认今天
返回:
- dict: 万年历信息
"""
# 获取日期
if year and month and day:
solar_date = datetime(year, month, day)
else:
solar_date = datetime.now()
# 使用 cnlunar 获取农历信息
lunar = Lunar(solar_date)
# 获取农历月份和日期
lunar_month = lunar.lunarMonthCn # 如:腊月
lunar_day = lunar.lunarDayCn # 如:十二
# 获取天干地支年份
gan_zhi_year = lunar.year8Char # 如:甲辰
# 使用 DeepSeek 生成宜忌(带缓存)
yi_list, ji_list = cls._get_yi_ji_cached(solar_date, lunar)
return {
"lunar": f"{lunar_month} {lunar_day}",
"year": f"{gan_zhi_year}",
"solar": solar_date.strftime("%Y.%m.%d"),
"yi": yi_list,
"ji": ji_list,
}
@classmethod
def _get_yi_ji_cached(cls, solar_date: datetime, lunar: Lunar) -> tuple[List[str], List[str]]:
"""
获取宜忌数据(带缓存)
同一天的数据只调用一次 API后续直接返回缓存
"""
# 用日期字符串作为缓存 key
cache_key = solar_date.strftime("%Y-%m-%d")
# 如果缓存中有数据,直接返回
if cache_key in cls._yi_ji_cache:
return cls._yi_ji_cache[cache_key]
# 缓存中没有,调用 API 获取
yi_list, ji_list = cls._get_yi_ji_from_deepseek(solar_date, lunar)
# 存入缓存
cls._yi_ji_cache[cache_key] = (yi_list, ji_list)
# 限制缓存大小,最多保留 30 天的数据
if len(cls._yi_ji_cache) > 30:
# 删除最早的一条
oldest_key = next(iter(cls._yi_ji_cache))
del cls._yi_ji_cache[oldest_key]
return yi_list, ji_list
@classmethod
def _get_yi_ji_from_deepseek(cls, solar_date: datetime, lunar: Lunar) -> tuple[List[str], List[str]]:
"""
调用 DeepSeek API 生成宜忌数据
参数:
- solar_date: 公历日期
- lunar: 农历对象
返回:
- tuple: (宜列表, 忌列表)
"""
try:
# 从配置文件读取 API 配置
client = OpenAI(
api_key=settings.DEEPSEEK_API_KEY,
base_url=settings.DEEPSEEK_BASE_URL
)
# 构建提示词
prompt = f"""请根据以下日期信息,生成中国传统黄历的宜忌数据。
日期信息:
- 公历:{solar_date.strftime("%Y年%m月%d")}
- 农历:{lunar.lunarMonthCn}{lunar.lunarDayCn}
- 天干地支:{lunar.year8Char}{lunar.month8Char}{lunar.day8Char}
请严格按照以下 JSON 格式返回,不要有其他内容:
{{"yi": ["宜做的事1", "宜做的事2", "宜做的事3", "宜做的事4"], "ji": ["忌做的事1", "忌做的事2", "忌做的事3", "忌做的事4"]}}
要求:
1. 宜和忌各返回4-6个项目
2. 使用传统黄历术语,如:祭祀、祈福、嫁娶、出行、开市、动土、安葬等
3. 只返回 JSON不要有任何解释"""
response = client.chat.completions.create(
model=settings.DEEPSEEK_MODEL,
messages=[
{"role": "system", "content": "你是一个精通中国传统黄历的专家,请根据日期生成准确的宜忌信息。"},
{"role": "user", "content": prompt}
],
temperature=0.7,
max_tokens=200
)
# 解析返回的 JSON
result_text = response.choices[0].message.content.strip()
result = json.loads(result_text)
return result.get("yi", []), result.get("ji", [])
except Exception as e:
# 如果 API 调用失败,返回默认值
print(f"DeepSeek API 调用失败: {e}")
return ["祭祀", "祈福", "出行", "开市"], ["动土", "安葬", "破土", "作灶"]