Migrate AI Hint feed generation

Bring dynamic hint generation into the account service while preserving the legacy key.osglab.com deployment for existing clients.
This commit is contained in:
Rocky
2026-08-21 15:17:15 +08:00
parent d0abe27623
commit 454ba8ddc5
40 changed files with 2838 additions and 10 deletions
+40
View File
@@ -27,6 +27,8 @@ describe("内容管理", () => {
const editor = await screen.findByLabelText("zh JSON");
expect(editor).toHaveProperty("readOnly", true);
expect(screen.queryByRole("button", { name: "保存并立即发布" })).toBeNull();
expect(screen.queryByRole("button", { name: "立即生成" })).toBeNull();
expect(screen.queryByRole("button", { name: "保存生成设置" })).toBeNull();
});
it("SUPER_ADMIN 可启停官方 Skill", async () => {
@@ -70,6 +72,24 @@ describe("内容管理", () => {
expect(input.getAttribute("maxlength")).toBe("6000");
});
});
it("SUPER_ADMIN 可手动触发双语 Hint 原子生成", async () => {
mockSession("SUPER_ADMIN");
mockContent();
vi.spyOn(window, "confirm").mockReturnValue(true);
const regenerate = vi.spyOn(adminApi, "regenerateHintFeed").mockResolvedValue({
generationId: "00000000-0000-0000-0000-000000000001",
generatedAt: "2026-08-21T06:00:00Z",
zh: { version: 3, cardCount: 20 },
en: { version: 3, cardCount: 25 },
});
window.location.hash = "#/content";
render(<App />);
await userEvent.click(await screen.findByRole("button", { name: "立即生成" }));
await waitFor(() => expect(regenerate).toHaveBeenCalledOnce());
});
});
function mockSession(role: AdminRole) {
@@ -89,6 +109,26 @@ function mockContent() {
version: 2,
cards: [],
});
vi.spyOn(adminApi, "hintFeedSettings").mockResolvedValue({
enabled: true,
topHubApiKeyConfigured: false,
generationIntervalHours: 12,
holidayCountriesZh: "CN",
holidayCountriesEn: "US,GB",
weatherCitiesZh: "北京:39.90,116.40",
weatherCitiesEn: "London:51.51,-0.13",
googleTrendsGeos: "US,GB",
});
vi.spyOn(adminApi, "hintFeedStatus").mockResolvedValue({
enabled: true,
outcome: "SUCCEEDED",
intervalHours: 12,
topHubApiKeyConfigured: false,
zhVersion: 2,
zhCardCount: 20,
enVersion: 2,
enCardCount: 25,
});
}
function catalog(): OfficialSkillCatalog {