0f3bc2c50a
createStreamableValue must be created and returned in the action itself; wrapping in { data } or a helper return caused production RSC serialization errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
71 lines
1.5 KiB
TypeScript
71 lines
1.5 KiB
TypeScript
"use server";
|
|
|
|
import { createStreamableValue } from "ai/rsc";
|
|
import { pumpAIStream } from "@/lib/ai/stream";
|
|
import {
|
|
formatLiuyaoTimingForPrompt,
|
|
getTimingInfoWithLongitude,
|
|
} from "@/lib/calc/timing";
|
|
import {
|
|
extractChangeDetails,
|
|
extractZhangMingRen,
|
|
readGuaMarkdown,
|
|
} from "@/lib/content/zhouyi";
|
|
import { LIUYAO_SYSTEM_PROMPT } from "@/lib/prompts";
|
|
|
|
export interface LiuyaoInput {
|
|
question: string;
|
|
calcDate: string;
|
|
calcTime: string;
|
|
locationName: string;
|
|
longitude: number;
|
|
guaMark: string;
|
|
guaTitle: string;
|
|
guaResult: string;
|
|
guaChange: string;
|
|
}
|
|
|
|
export async function getLiuyaoAnswer(input: LiuyaoInput) {
|
|
const { timing, trueSolarTime } = getTimingInfoWithLongitude(
|
|
input.calcDate,
|
|
input.calcTime,
|
|
input.longitude,
|
|
);
|
|
const timingText = formatLiuyaoTimingForPrompt(
|
|
timing,
|
|
trueSolarTime,
|
|
input.locationName,
|
|
input.longitude,
|
|
);
|
|
|
|
let guaDetailText = "";
|
|
try {
|
|
const guaDetail = await readGuaMarkdown(input.guaMark);
|
|
const explain = extractZhangMingRen(guaDetail) ?? "";
|
|
const changeList = extractChangeDetails(
|
|
guaDetail,
|
|
input.guaChange,
|
|
input.guaTitle,
|
|
);
|
|
guaDetailText = [explain, changeList.join("\n")].filter(Boolean).join("\n");
|
|
} catch {
|
|
guaDetailText = "";
|
|
}
|
|
|
|
const stream = createStreamableValue<string>();
|
|
pumpAIStream(
|
|
stream,
|
|
LIUYAO_SYSTEM_PROMPT,
|
|
`${timingText}
|
|
|
|
【卦象】
|
|
${input.guaTitle} ${input.guaResult} ${input.guaChange}
|
|
|
|
【问事】
|
|
${input.question}
|
|
|
|
${guaDetailText}`,
|
|
);
|
|
return stream.value;
|
|
}
|