84 lines
3.3 KiB
Python
84 lines
3.3 KiB
Python
"""temporal_context 文本组装(辰正设计 §8.1)。
|
||
|
||
纯函数:把 ``TemporalSnapshot`` + ``ModulationFactors`` 渲染为注入对话 prompt 的
|
||
中文时态上下文块。降级原则:任何字段缺失都跳过该行,不抛异常。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from app.modules.time_sense.modulation import ModulationFactors
|
||
from app.modules.time_sense.snapshot import TemporalSnapshot
|
||
|
||
|
||
def render_temporal_context(snapshot: TemporalSnapshot, factors: ModulationFactors) -> str: # noqa: ARG001
|
||
"""渲染 §8.1 格式的 temporal_context 文本块。
|
||
|
||
``factors`` 为 service 层统一传入的调制因子;v1 仅用 snapshot 字段,
|
||
参数预留给 v2(如 festival_joy / late_night_fragility 的影响话术)。
|
||
"""
|
||
lines: list[str] = []
|
||
|
||
# 第一行:时辰·时段(本地时间、时区、周几)
|
||
shichen = snapshot.shichen
|
||
period = snapshot.day_period
|
||
local_hm = snapshot.local_time[11:16]
|
||
tz_short = _tz_offset_short(snapshot.local_time)
|
||
weekday_cn = "一二三四五六日"[snapshot.weekday]
|
||
lines.append(f"现在是{shichen}·{period}({local_hm},UTC{tz_short}),周{weekday_cn}。")
|
||
|
||
# 第二行:农历 + 距下一节气
|
||
lunar_part = ""
|
||
if snapshot.lunar is not None:
|
||
lunar_part = (
|
||
f"农历{snapshot.lunar.year_ganzhi}年{snapshot.lunar.month}月{snapshot.lunar.day}日,"
|
||
)
|
||
term_part = ""
|
||
if snapshot.solar_term is not None:
|
||
days_to_next = getattr(snapshot.solar_term, "days_to_next", None)
|
||
next_name = getattr(snapshot.solar_term, "next_name", None)
|
||
if days_to_next is not None and next_name:
|
||
term_part = f"距{next_name}还有 {days_to_next} 天。"
|
||
if lunar_part or term_part:
|
||
lines.append(lunar_part + term_part)
|
||
|
||
# 第三行:认识时长
|
||
acq = snapshot.acquaintance
|
||
if acq.natural_language:
|
||
lines.append(f"已经认识 {acq.natural_language}。")
|
||
|
||
# 第四行:离线/重逢
|
||
offline = snapshot.offline
|
||
if offline.band == "reunion_impact":
|
||
days = int(offline.minutes // 1440)
|
||
lines.append(f"用户上次说话是 {days} 天前——久别重逢。")
|
||
elif offline.band == "long_absence":
|
||
days = int(offline.minutes // 1440)
|
||
lines.append(f"用户上次说话是 {days} 天前。")
|
||
|
||
# 第五行:纪念日
|
||
active = snapshot.active_milestones
|
||
next_ms = snapshot.next_milestone
|
||
if active:
|
||
names = "、".join(m.name for m in active)
|
||
lines.append(f"今日命中:{names}。")
|
||
else:
|
||
lines.append("今日命中:无纪念日。")
|
||
if next_ms is not None:
|
||
lines.append(f"下一个特殊日子:{next_ms.name},还有 {next_ms.days_until} 天。")
|
||
|
||
return "\n".join(lines)
|
||
|
||
|
||
def _tz_offset_short(local_time_iso: str) -> str:
|
||
"""从本地 ISO 时间(如 ``2026-07-04T02:00:00+08:00``)提取 UTC 偏移。
|
||
|
||
返回 ``+8`` / ``-5`` / ``+0`` 形式,用于 ``UTC{tz_short}`` 显示——
|
||
即用户本地时区相对 UTC 的偏移(非家时区差)。
|
||
"""
|
||
# isoformat() 偏移形如 +HH:MM / -HH:MM(末 6 字符);Z 或无偏移按 UTC
|
||
if local_time_iso.endswith("Z") or len(local_time_iso) < 6:
|
||
return "+0"
|
||
tail = local_time_iso[-6:]
|
||
sign = tail[0] if tail[0] in "+-" else "+"
|
||
return f"{sign}{int(tail[1:3])}"
|