feat: complete heaven readings and screener publication
This commit is contained in:
@@ -6,11 +6,17 @@ from datetime import date
|
||||
from typing import Any
|
||||
|
||||
from backend.bootstrap.config import normalize_date
|
||||
from backend.features.heaven.agent import HeavenAgentError, interpret_heaven
|
||||
from backend.features.heaven.agent import (
|
||||
HEAVEN_PROMPT_VERSIONS,
|
||||
HeavenAgentError,
|
||||
interpret_heaven,
|
||||
)
|
||||
from backend.features.heaven.engine import (
|
||||
build_five_phase_field,
|
||||
hexagram_from_lines,
|
||||
)
|
||||
from backend.features.heaven.knowledge import prepare_heaven_context
|
||||
from backend.features.heaven.six_yao import build_six_yao_chart
|
||||
from backend.features.market import MarketServiceMixin
|
||||
|
||||
|
||||
@@ -75,9 +81,11 @@ class HeavenReadingMixin:
|
||||
return subject, detail
|
||||
hexagram = context.get("hexagram") or {}
|
||||
transformed = hexagram.get("transformed") or {}
|
||||
question = str(context.get("question") or "").strip()
|
||||
question_detail = f" · {question[:48]}" if question else ""
|
||||
return (
|
||||
f"{display_date} 观心",
|
||||
f"{hexagram.get('name') or '--'} → {transformed.get('name') or '--'}",
|
||||
f"{hexagram.get('name') or '--'} → {transformed.get('name') or '--'}{question_detail}",
|
||||
)
|
||||
|
||||
def heaven_interpret(self, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
@@ -85,6 +93,8 @@ class HeavenReadingMixin:
|
||||
if mode not in {"trend", "fortune", "heart"}:
|
||||
raise ValueError("问天解读模式不正确。")
|
||||
trade_date = normalize_date(str(payload.get("trade_date") or date.today().isoformat()))
|
||||
prompt_version = HEAVEN_PROMPT_VERSIONS[mode]
|
||||
stale_fortune: dict[str, Any] | None = None
|
||||
if mode == "fortune":
|
||||
existing = self.database.latest_heaven_reading(
|
||||
self.current_user_id, "fortune", trade_date
|
||||
@@ -94,7 +104,9 @@ class HeavenReadingMixin:
|
||||
self.current_user_id, int(existing["id"])
|
||||
)
|
||||
existing = None
|
||||
if existing:
|
||||
if existing and self.database.heaven_reading_interpretation_version(
|
||||
self.current_user_id, int(existing["id"])
|
||||
) == prompt_version:
|
||||
return {
|
||||
"answer": existing["answer"],
|
||||
"mode": mode,
|
||||
@@ -103,6 +115,7 @@ class HeavenReadingMixin:
|
||||
"reading": existing,
|
||||
"reused": True,
|
||||
}
|
||||
stale_fortune = existing
|
||||
if mode in {"trend", "fortune"}:
|
||||
setup = self.heaven_setup(
|
||||
trade_date,
|
||||
@@ -141,38 +154,44 @@ class HeavenReadingMixin:
|
||||
setup["field"],
|
||||
public=False,
|
||||
)
|
||||
fortune_field = json.loads(json.dumps(setup["field"], ensure_ascii=False))
|
||||
catalog = fortune_field.pop("sector_catalog", [])
|
||||
dominant_elements = {
|
||||
item.get("element") for item in fortune_field.get("balance", [])[:2]
|
||||
}
|
||||
fortune_field["industry_affinity"] = [
|
||||
{
|
||||
"element": group.get("element"),
|
||||
"examples": [
|
||||
item.get("name")
|
||||
for item in group.get("industries", [])[:8]
|
||||
if item.get("name")
|
||||
],
|
||||
}
|
||||
for group in catalog
|
||||
if group.get("element") in dominant_elements
|
||||
]
|
||||
context = {
|
||||
"calendar_date": setup["calendar_date"],
|
||||
"five_phase_field": fortune_field,
|
||||
"five_phase_field": setup["field"],
|
||||
"personal_profile": personal_profile,
|
||||
}
|
||||
context_date = setup["calendar_date"]
|
||||
if mode == "trend":
|
||||
context_date = setup["trade_date"]
|
||||
else:
|
||||
question = str(payload.get("question") or "").strip()
|
||||
if len(question) > 300:
|
||||
raise ValueError("观心问题不能超过300个字符。")
|
||||
question_preset = str(payload.get("question_preset") or "unthemed").strip()
|
||||
if question_preset not in {"trade", "mind", "unthemed", "custom"}:
|
||||
question_preset = "custom"
|
||||
if not question:
|
||||
question = "不设具体问题,只观此刻一念。"
|
||||
question_preset = "unthemed"
|
||||
raw_lines = payload.get("lines")
|
||||
hexagram = self.heaven_hexagram(raw_lines)
|
||||
context = {
|
||||
"hexagram": self.heaven_hexagram(payload.get("lines")),
|
||||
"ritual": "用户已完成30秒静心、六次三枚铜钱起卦,并在心中察看第一念。问题未输入。",
|
||||
"question": question,
|
||||
"question_preset": question_preset,
|
||||
"hexagram": hexagram,
|
||||
"six_yao": build_six_yao_chart(
|
||||
[int(value) for value in raw_lines],
|
||||
str(payload.get("cast_at") or ""),
|
||||
),
|
||||
"ritual": {
|
||||
"breathing": "用户已完成1秒准备与五轮吸3秒、顿2秒、呼4秒的静心呼吸。",
|
||||
"casting": "用户以三枚铜钱自初爻至上爻投掷六次。",
|
||||
"reflection": "用户已在看见卦象后察看第一念。",
|
||||
},
|
||||
}
|
||||
context_date = trade_date
|
||||
result, compiler = self._call_heaven_agent(mode, context)
|
||||
agent_context = prepare_heaven_context(mode, context)
|
||||
agent_context["interpretation_version"] = prompt_version
|
||||
result, compiler = self._call_heaven_agent(mode, agent_context)
|
||||
subject, subject_detail = self._heaven_reading_identity(
|
||||
mode, context_date, context
|
||||
)
|
||||
@@ -181,6 +200,10 @@ class HeavenReadingMixin:
|
||||
if mode == "fortune"
|
||||
else f"{mode}:{context_date}:{secrets.token_urlsafe(12)}"
|
||||
)
|
||||
if stale_fortune:
|
||||
self.database.delete_heaven_reading(
|
||||
self.current_user_id, int(stale_fortune["id"])
|
||||
)
|
||||
reading = self.database.save_heaven_reading(
|
||||
self.current_user_id,
|
||||
mode,
|
||||
@@ -188,14 +211,14 @@ class HeavenReadingMixin:
|
||||
subject,
|
||||
subject_detail,
|
||||
str(result.get("answer") or ""),
|
||||
context,
|
||||
agent_context,
|
||||
dedupe_key,
|
||||
)
|
||||
return {
|
||||
**result,
|
||||
"mode": mode,
|
||||
"compiler": compiler,
|
||||
"notice": "智能解读已自动切换可用服务。" if compiler == "fallback" else "",
|
||||
"notice": "当前智能服务繁忙,已自动切换备用服务。" if compiler == "fallback" else "",
|
||||
"reading": reading,
|
||||
"reused": False,
|
||||
}
|
||||
@@ -205,9 +228,10 @@ class HeavenReadingMixin:
|
||||
return bool(reading and str(reading.get("answer") or "").rstrip().endswith("……"))
|
||||
|
||||
def _call_heaven_agent(self, mode: str, context: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
||||
prompt_version = HEAVEN_PROMPT_VERSIONS[mode]
|
||||
result = self.llm_gateway.call(
|
||||
f"heaven_{mode}",
|
||||
f"heaven-{mode}-v1",
|
||||
prompt_version,
|
||||
lambda profile: interpret_heaven(
|
||||
mode,
|
||||
context,
|
||||
|
||||
Reference in New Issue
Block a user