依赖:

  1. streamlit 
  2. 智谱 glm-4-flash
  3. 延迟退休政策

效果:

效果图

项目结构:

retirement-planner
    ├── .env
    ├── .gitignore
    ├── app.py
    ├── calc_retirement.py
    ├── image.png
    ├── README.md
    ├── requirements.txt
    └── zhipuai.py

智谱 zhipuai.py

# zhipuai.py 
from openai import OpenAI
from dotenv import load_dotenv
import os

load_dotenv()

api_key = os.getenv("ZHIPUAI_API_KEY")
if not api_key:
    raise ValueError("API 密钥未找到,请检查环境变量")


def generate_text(messages: list):
    client = OpenAI(api_key=api_key, base_url="https://open.bigmodel.cn/api/paas/v4/")

    try:
        stream = client.chat.completions.create(
            model="glm-4-flash",
            messages=messages,
            top_p=0.7,
            temperature=0.9,
            stream=True,
        )
        for chunk in stream:
            if chunk.choices[0].delta.content is not None:
                yield chunk.choices[0].delta.content
    except Exception as e:
        raise RuntimeError(f"生成文本时出错: {e}")


if __name__ == "__main__":
    messages = [
        {"role": "system", "content": "你是一个聪明且富有创造力的小说作家"},
        {
            "role": "user",
            "content": "请你作为童话故事大王,写一篇短篇童话故事,故事的主题是要永远保持一颗善良的心,要能够激发儿童的学习兴趣和想象力,同时也能够帮助儿童更好地理解和接受故事中所蕴含的道理和价值观。",
        },
    ]

    try:
        for text in generate_text(messages):
            print(text, end="")
    except Exception as e:
        print(e)

计算退休信息 calc_retirement.py

# calc_retirement.py
from datetime import datetime
from dateutil.relativedelta import relativedelta
from math import ceil


def calc_retirement(yob: int, mob: int, type: str) -> dict:
    """计算退休日期

    Args:
        yob (int): 出生年
        mob (int): 出生月
        type (str): 性别和人员类型
            'male' - 男职工,60岁退休
            'female50' - 女职工,50岁退休
            'female55' - 女职工,55岁退休

    Returns:
        dict: 返回详细的退休信息,包括
                出生年月、性别和人员类型、
                原退休年龄、原退休时间、现在距离原退休时间的天数、
                改革后新的退休年龄、改革后新的退休时间、现在距离改革后新的退休时间的天数、
                以及延迟月数
    """
    # 解析出生年月
    birth_date = datetime(yob, mob, 1).date()

    # 定义原退休年龄
    orig_ret_age_map = {"male": 60, "female50": 50, "female55": 55}
    orig_ret_age = orig_ret_age_map.get(type)
    if orig_ret_age is None:
        raise ValueError(
            "无效的性别及人员类型。预期值为'male'、'female50'或'female55'。"
        )

    # 政策开始日期
    policy_start_date = datetime(2025, 1, 1).date()

    # 计算原退休日期
    orig_ret_time = birth_date + relativedelta(years=orig_ret_age)

    # 获取当前日期
    current_date = datetime.now().date()

    # 计算当前日期与原退休日期之间的天数差
    orig_ret_days_between = (orig_ret_time - current_date).days

    # 如果天数差小于0,表示已经到了退休年龄,直接返回当前信息
    if orig_ret_days_between < 0:
        return {
            "yob": yob,
            "mob": mob,
            "type": type,
            "orig_ret_age": orig_ret_age,
            "orig_ret_time": orig_ret_time,
            "orig_ret_days_between": orig_ret_days_between,
            "ret_age": orig_ret_age,
            "ret_time": orig_ret_time,
            "ret_days_between": orig_ret_days_between,
            "delay": 0,
        }

    # 计算从政策开始日期到原退休日期的月数差
    months_between = (
        (orig_ret_time.year - policy_start_date.year) * 12
        + orig_ret_time.month
        - policy_start_date.month
    ) + 1  # 增加1个月以确保计算的准确性

    # 定义延迟月数的计算逻辑
    delay_map = {
        60: lambda months: min(
            36, ceil(months / 4)
        ),  # 60岁退休,最多延迟36个月,每4个月延迟1个月
        55: lambda months: min(
            36, ceil(months / 4)
        ),  # 55岁退休,最多延迟36个月,每4个月延迟1个月
        50: lambda months: min(
            60, ceil(months / 2)
        ),  # 50岁退休,最多延迟60个月,每2个月延迟1个月
    }
    delay = delay_map[orig_ret_age](months_between)

    # 计算最终的退休日期
    ret_time = orig_ret_time + relativedelta(months=delay)
    ret_days_between = (ret_time - current_date).days

    # 计算新的退休年龄(精确到月)
    new_ret_age = orig_ret_age + (delay / 12)

    return {
        "yob": yob,  # 出生年
        "mob": mob,  # 出生月
        "type": type,  # 性别和人员类型,可能值为 'male'、'female50' 或 'female55'
        "orig_ret_age": orig_ret_age,  # 原退休年龄
        "orig_ret_time": orig_ret_time,  # 原退休日期
        "orig_ret_days_between": orig_ret_days_between,  # 当前日期到原退休日期之间的天数差
        "ret_age": round(new_ret_age, 2),  # 改革后新的退休年龄,保留两位小数
        "ret_time": ret_time,  # 改革后新的退休日期
        "ret_days_between": ret_days_between,  # 当前日期到改革后新的退休日期之间的天数差
        "delay": delay,  # 延迟的月数
    }


if __name__ == "__main__":
    # 示例测试
    print(calc_retirement(1970, 1, "female55"))

入口文件 app.py

# app.py
import streamlit as st
from zhipuai import generate_text
from calc_retirement import calc_retirement
from datetime import datetime

# 设置页面配置
st.set_page_config(page_title="悠享退休", layout="centered")

st.title("悠享退休")
policy_url = "https://www.mohrss.gov.cn/SYrlzyhshbzb/ztzl/zt202409/qwfb/202409/t20240913_525781.html"

st.caption(
    f"说明:按照[《关于实施渐进式延迟法定退休年龄的决定》附表对照关系]({policy_url}),"
    f"您通过法定退休年龄计算器,选择出生年月、性别及人员类型,即可计算出对应的改革后法定退休年龄、改革后退休时间、延迟月数"
)

col1, col2, col3 = st.columns([1, 1, 2])

with col1:
    yob = st.number_input(
        "出生年份", min_value=1900, max_value=datetime.now().year, value=1987
    )

with col2:
    mob = st.number_input("出生月份", min_value=1, max_value=12, value=5)


# 计算当前岁数
def calculate_age(yob: int, mob: int) -> float:
    birth_date = datetime(yob, mob, 1)
    current_date = datetime.now()
    age_years = current_date.year - birth_date.year
    age_months = current_date.month - birth_date.month

    # 如果当前月份小于出生月份,岁数减一
    if age_months < 0:
        age_years -= 1
        age_months += 12

    age = age_years + (age_months / 12.0)
    return round(age)


current_age = calculate_age(yob, mob)


with col3:
    gender = st.selectbox(
        "类型",
        options=["male", "female50", "female55"],
        format_func=lambda x: {
            "male": "男职工",
            "female50": "原法定退休年龄50周岁女职工",
            "female55": "原法定退休年龄55周岁女职工",
        }[x],
    )

result = calc_retirement(yob, mob, gender)
print(result)

st.markdown("---")

col1, col2 = st.columns(2)


def format_age(age: float) -> str:
    years = int(age)
    months = int(round((age - years) * 12))
    return f"{years}岁" if months == 0 else f"{years}岁{months}个月"


def format_date(date: datetime) -> str:
    return date.strftime("%Y年%m月")


with col1:
    st.header("原始退休信息")
    st.write(f"**原退休年龄:** {format_age(result['orig_ret_age'])}")
    st.write(f"**原退休时间:** {format_date(result['orig_ret_time'])}")

with col2:
    st.header("改革后退休信息")
    st.write(f"**退休年龄:** {format_age(result['ret_age'])}")
    st.write(f"**退休时间:** {format_date(result['ret_time'])}")
    st.write(f"**延迟月数:** {result['delay']}个月")
    if result["ret_days_between"] > 0:
        st.write(f"**距离退休还有:** {result['ret_days_between']} 天")
    else:
        st.write(f"**已退休:** {abs(result['ret_days_between'])} 天")

st.markdown("---")

# 显示调侃
st.header("调侃一下")

current_time = datetime.now().strftime("%Y年%m月")

messages = [
    {
        "role": "system",
        "content": (
            f"现在是{current_time},你是一位善于使用辛辣嘲讽的年轻人。"
            "请根据退休年龄计算器得出的退休信息,以尖酸刻薄的语气,"
            "生成一段挑剔、难听、尖酸、符合逻辑的吐槽或调侃,直接回复不要解释:"
        ),
    }
]

gender_str = "男士" if result["type"] == "male" else "女士"

if result["delay"] > 0:
    user_content = (
        f"幸灾乐祸地调侃:这位延迟退休的{current_age}岁{gender_str},"
        f"和所有同龄人一样受到国家新出台的延迟退休政策影响,需要调整原退休时间,"
        f"比原计划{format_date(result['orig_ret_time'])}退休,多上{result['delay']}个月班,"
        f"原退休年龄{format_age(result['orig_ret_age'])},现在要等到{format_age(result['ret_age'])}才能退休,"
        f"距离退休还有 {result['ret_days_between']} 天。"
    )
elif result["delay"] == 0 and result["ret_days_between"] == 0:
    user_content = (
        f"阴阳怪气地谈论:国家新出台的延迟退休政策对这位{gender_str}没有影响,不需要调整原退休时间,"
        f"今天就是这位{current_age}岁{gender_str}退休的日子,庆祝一下吧!"
    )
elif result["delay"] == 0 and result["ret_days_between"] > 0:
    user_content = (
        f"阴阳怪气地谈论:国家新出台的延迟退休政策对这位{current_age}岁{gender_str}没有影响,不需要调整原退休时间,"
        f"距离退休还有 {result['ret_days_between']} 天,庆祝一下吧!"
    )
else:
    user_content = (
        f"直接吐槽:这位已经退休的{current_age}岁{gender_str},"
        f"国家新出台的延迟退休政策与这位{gender_str}毫无关系,"
        f"早已经退休还来计算退休时间。吐槽内容中包含“已经退休 {abs(result['ret_days_between'])} 天”。"
    )

messages.append({"role": "user", "content": user_content})

output_area = st.empty()

try:
    generated_text = ""

    for chunk in generate_text(messages):
        generated_text += chunk
        output_area.write(generated_text)

except TypeError as e:
    output_area.write(f"生成文本时出现错误,请稍后再试。错误信息:{e}")

requirements.txt  和 .env

# requirements.txt 
streamlit
openai
python-dotenv
# .env
ZHIPUAI_API_KEY=xxx.xxx

 

使用:

安装依赖pip install -r requirements.txt.env 添加 api key,执行streamlit run app.py