Files
Jyotisha/frontend/src/lib/consultation-entrypoint.ts
T
Jesse_Chen 9958e00abc fix(web): keep unrectified birth data usable without inventing a minute
Rectification stays optional. Reported minutes can consult and generate reports; date-plus-period uses a declared window instead of a midpoint or 00:00. Updates BUG-341.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-21 15:29:58 +08:00

96 lines
4.0 KiB
TypeScript
Raw 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.
import { z } from "zod";
export const consultationEntrypointSchema = z.enum([
"daily_starlanguage",
"birth_time_rectification",
]);
export type ConsultationEntrypoint = z.infer<typeof consultationEntrypointSchema>;
export const GENERAL_NO_MINUTE_DAILY_FORTUNE_QUESTION =
"请帮我看一下今天的运势,重点告诉我适合推进什么、需要注意什么。";
type ConsultationQuestionInput = {
readonly visibleQuestion: string;
readonly entrypoint: ConsultationEntrypoint | undefined;
readonly currentDate: string;
readonly consultationMode?: "verified_chart" | "unverified_birth_time" | "declared_birth_window" | "general_no_birth_time";
};
export type ResolvedConsultationQuestion =
| { readonly kind: "plain"; readonly modelQuestion: string }
| { readonly kind: "expanded"; readonly modelQuestion: string };
function compactQuestion(question: string) {
return question.normalize("NFKC").replace(/\s+/gu, " ").trim();
}
export function isGeneralDailyFortuneQuestion(question: string): boolean {
const text = compactQuestion(question);
if (!text) return false;
if (text === GENERAL_NO_MINUTE_DAILY_FORTUNE_QUESTION) return true;
if (text === "深入看今日" || text === "从今日问起" || text === "查看今日运势") return true;
return /^(?:请帮我看一下)?今天的运势/.test(text) || /^今日运势/.test(text);
}
export function isRectificationHandoffQuestion(question: string): boolean {
const text = compactQuestion(question);
return /^(?:先完成)?(?:出生时间校正|生时校正|生时矫正)(?:\s*[(]生时(?:校正|矫正)[)])?$/.test(text);
}
export function shouldLoadGeneralDailyPanchanga(input: Readonly<{
consultationMode?: ConsultationQuestionInput["consultationMode"];
entrypoint?: ConsultationEntrypoint;
visibleQuestion: string;
}>): boolean {
if (input.consultationMode !== "general_no_birth_time"
&& input.consultationMode !== "declared_birth_window") return false;
return input.entrypoint === "daily_starlanguage"
|| isGeneralDailyFortuneQuestion(input.visibleQuestion);
}
function publicDailyExpansion(currentDate: string): ResolvedConsultationQuestion {
return {
kind: "expanded",
modelQuestion: [
`请依据服务器提供的 ${currentDate} 公共 Panchanga 日历摘要,回答今天的整体趋势。`,
"重点说明适合推进什么、需要注意什么,并给出一个立即可执行的行动建议。",
"这不是个人命盘结论,不包含个人上升点、宫位、大运或本命过境叠加;不要把公共日历趋势写成确定预测。",
].join("\n"),
};
}
export function resolveConsultationQuestion(
input: ConsultationQuestionInput,
): ResolvedConsultationQuestion {
if (shouldLoadGeneralDailyPanchanga(input)) {
return publicDailyExpansion(input.currentDate);
}
switch (input.entrypoint) {
case undefined:
return { kind: "plain", modelQuestion: input.visibleQuestion };
case "daily_starlanguage":
return {
kind: "expanded",
modelQuestion: [
`请结合已校验的星盘资料,深入解读 ${input.currentDate} 的今日主题。`,
"请说明今日趋势、适合推进的事、需要避开的事,以及一个可以立即执行的行动建议。",
"这是探索性日提示,不是确定预测;精确事件日期只能标为候选触发,不能包装成必然结论。",
].join("\n"),
};
case "birth_time_rectification":
return {
kind: "expanded",
modelQuestion: [
"请基于已校验的出生资料继续进行生时校正辅助。",
"先判断现有证据与候选结果,再说明最有区分度的下一步;需要补充信息时优先给用户可点击、容易回答的选项。",
"候选时间必须标为待验证,不能声称是出生记录中的确定分钟,也不能在没有新证据时循环重启相同流程。",
].join("\n"),
};
default: {
const exhaustive: never = input.entrypoint;
return exhaustive;
}
}
}