import { z } from "zod"; export const consultationEntrypointSchema = z.enum([ "daily_starlanguage", "birth_time_rectification", ]); export type ConsultationEntrypoint = z.infer; 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; } } }