|
1 | 1 | import { generateText } from "ai"; |
| 2 | +import { unstable_cache } from "next/cache"; |
2 | 3 | import { getModel, requiresApiKey, type AIProvider } from "@/lib/ai/models"; |
3 | 4 | import { createGlmFlashModel } from "@/lib/ai/providers/glm"; |
4 | 5 |
|
@@ -85,10 +86,62 @@ export async function POST(req: Request) { |
85 | 86 | : `User asked: "${lastText}". Suggest 3 short follow-up questions (max 10 words each). Return a JSON array only, e.g. ["Q1","Q2","Q3"]`; |
86 | 87 | } |
87 | 88 |
|
88 | | - const { text } = await generateText({ |
89 | | - model, |
90 | | - prompt, |
91 | | - }); |
| 89 | + // 将核心请求提取为一个辅助函数以便于使用 Vercel Cache |
| 90 | + // 注意:unstable_cache 序列化函数只能接收可序列化的对象,因此仅传递必需的参数 |
| 91 | + const fetchSuggestionsWithCache = unstable_cache( |
| 92 | + async (cPrompt: string, cModelId: string) => { |
| 93 | + // 由于 model 不能序列化传入,在缓存函数内侧由于无法动态构建,所以此处传递标识再创建 |
| 94 | + const m = |
| 95 | + cModelId === "intern" |
| 96 | + ? getModel("intern") |
| 97 | + : cModelId === "glm" |
| 98 | + ? createGlmFlashModel() |
| 99 | + : // 无法传递用户动态 key,对于配置了 key 的情况不走此函数 |
| 100 | + getModel("intern"); |
| 101 | + |
| 102 | + const { text } = await generateText({ |
| 103 | + model: m, |
| 104 | + prompt: cPrompt, |
| 105 | + }); |
| 106 | + return text; |
| 107 | + }, |
| 108 | + // 使用明确具有区分度的 cache key |
| 109 | + [`suggestions-cache-${isWelcomeRequest ? "welcome" : "followup"}`], |
| 110 | + { |
| 111 | + revalidate: 60 * 60 * 24, // 对同一个页面的建议缓存 24 小时 |
| 112 | + tags: ["suggestions"], |
| 113 | + }, |
| 114 | + ); |
| 115 | + |
| 116 | + let text = ""; |
| 117 | + // 判断是否可以使用缓存(如果使用了自定义 apiKey,为了防止数据交叉,不采用公用缓存) |
| 118 | + if (provider !== "intern" && !process.env.ZHIPU_API_KEY) { |
| 119 | + const { text: directText } = await generateText({ |
| 120 | + model, |
| 121 | + prompt, |
| 122 | + }); |
| 123 | + text = directText; |
| 124 | + } else { |
| 125 | + // 确定内部用于缓存匹配的模型标识 |
| 126 | + const internalModelId = |
| 127 | + provider === "intern" |
| 128 | + ? process.env.ZHIPU_API_KEY |
| 129 | + ? "glm" |
| 130 | + : "intern" |
| 131 | + : "intern"; |
| 132 | + // 将缓存粒度关联到请求本身的内容上 |
| 133 | + const suggestionKey = isWelcomeRequest |
| 134 | + ? `welcome-${pageContext?.slug || "default"}` |
| 135 | + : `followup-${prompt}`; |
| 136 | + |
| 137 | + const cachedFn = unstable_cache( |
| 138 | + async (pPrompt: string, pModelId: string) => |
| 139 | + fetchSuggestionsWithCache(pPrompt, pModelId), |
| 140 | + [`suggestion-key-${suggestionKey}`], |
| 141 | + { revalidate: 3600 * 24 }, // 24小时 |
| 142 | + ); |
| 143 | + text = await cachedFn(prompt, internalModelId); |
| 144 | + } |
92 | 145 |
|
93 | 146 | let questions: unknown[] = []; |
94 | 147 | try { |
|
0 commit comments