From 72f911a1cbc532e01e091690e3dca2a124a8787e Mon Sep 17 00:00:00 2001 From: digua Date: Sun, 14 Jun 2026 23:39:13 +0800 Subject: [PATCH] fix(analytics): invalidate language-preference cache when Jieba dict changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The language-preference endpoint calls createJiebaNlpProvider() which uses the on-disk zh-CN dict. If the result was cached before the dict was downloaded, the built-in fallback tokenization was served even after the dict became available, until a DB write invalidated the cache. Include the zh-CN dict file mtime/size as extraVersion in the cache version so the entry is recomputed whenever the dict is added, replaced, or deleted — consistent with the word-frequency fix. Co-Authored-By: Claude Sonnet 4.6 --- .../http-routes/src/routes/web/analytics.ts | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/http-routes/src/routes/web/analytics.ts b/packages/http-routes/src/routes/web/analytics.ts index 354a7a63..349c1ee4 100644 --- a/packages/http-routes/src/routes/web/analytics.ts +++ b/packages/http-routes/src/routes/web/analytics.ts @@ -1,3 +1,5 @@ +import * as fs from 'fs' +import * as path from 'path' import type { FastifyInstance } from 'fastify' import type { HttpRouteContext } from '../../context' import { createJiebaNlpProvider } from '@openchatlab/node-runtime' @@ -45,7 +47,7 @@ export function registerAnalyticsRoutes(server: FastifyInstance, ctx: HttpRouteC sessionId: string, params: Record, compute: () => T, - options?: { dailyInvalidate?: boolean } + options?: { dailyInvalidate?: boolean; extraVersion?: string } ): T => withAnalyticsCache(ctx, sessionId, `analytics.${name}`, params, compute, options) server.get<{ Params: { id: string } }>('/_web/sessions/:id/years', async (request) => { @@ -171,12 +173,25 @@ export function registerAnalyticsRoutes(server: FastifyInstance, ctx: HttpRouteC const id = request.params.id const filter = parseTimeFilter(request.query) const locale = request.query.locale || 'zh-CN' - return cached('language-preference', id, { ...filter, locale }, () => - getLanguagePreferenceAnalysis(adapter.ensureReadonly(id), { - locale, - timeFilter: filter, - nlpProvider: createJiebaNlpProvider(), - }) + const zhDictPath = path.join(ctx.pathProvider.getSystemDir(), 'nlp', 'zh-CN.dict') + let zhDictVersion: string + try { + const st = fs.statSync(zhDictPath) + zhDictVersion = `${Math.floor(st.mtimeMs)}:${st.size}` + } catch { + zhDictVersion = '-' + } + return cached( + 'language-preference', + id, + { ...filter, locale }, + () => + getLanguagePreferenceAnalysis(adapter.ensureReadonly(id), { + locale, + timeFilter: filter, + nlpProvider: createJiebaNlpProvider(), + }), + { extraVersion: `dict:${zhDictVersion}` } ) } )