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
+25
View File
@@ -4,6 +4,9 @@ import type {
AdminOperatorProvisioning,
AdminSecuritySummary,
AdminHintPack,
HintFeedGenerationResponse,
HintFeedGenerationStatus,
HintFeedSettings,
AdminLoginResponse,
AuditQuery,
AuditLogEntry,
@@ -25,6 +28,7 @@ import type {
UsersQuery,
UserSummary,
UpdateHintPackRequest,
UpdateHintFeedSettingsRequest,
UpdateOfficialSkillRequest,
} from "./types";
@@ -82,6 +86,9 @@ function safeMessage(status: number, code?: string): string {
CONTENT_SKILL_NOT_FOUND: "未找到该官方 Skill",
CONTENT_SKILL_CONFLICT: "该官方 Skill ID 已存在",
CONTENT_HINT_PACK_NOT_FOUND: "该语言的 Hint pack 尚未发布",
HINT_FEED_GENERATION_IN_PROGRESS: "Hint 提示包正在生成,请稍后刷新",
HINT_FEED_SETTINGS_INVALID: "Hint 自动生成配置不符合要求",
HINT_FEED_GENERATION_FAILED: "Hint 提示包生成失败,旧版本仍保持可用",
RATE_LIMITED: "操作过于频繁,请稍后再试",
};
if (code && messages[code]) return messages[code];
@@ -228,6 +235,24 @@ export const adminApi = {
body: JSON.stringify(payload),
}),
hintFeedSettings: () =>
request<HintFeedSettings>("/content/hints/generation/settings"),
updateHintFeedSettings: (payload: UpdateHintFeedSettingsRequest) =>
request<HintFeedSettings>("/content/hints/generation/settings", {
method: "PUT",
body: JSON.stringify(payload),
}),
hintFeedStatus: () =>
request<HintFeedGenerationStatus>("/content/hints/generation/status"),
regenerateHintFeed: () =>
request<HintFeedGenerationResponse>("/content/hints/generation/regenerate", {
method: "POST",
signal: AbortSignal.timeout(130_000),
}),
users: (value: string | UsersQuery = "", legacyCursor?: string) => {
const params =
typeof value === "string"
+41 -1
View File
@@ -16,7 +16,9 @@ export type AdminAuditAction =
| "CONTENT_SKILL_UPDATED"
| "CONTENT_SKILL_ENABLED"
| "CONTENT_SKILL_DISABLED"
| "CONTENT_HINT_PACK_PUBLISHED";
| "CONTENT_HINT_PACK_PUBLISHED"
| "CONTENT_HINT_FEED_SETTINGS_UPDATED"
| "CONTENT_HINT_FEED_GENERATED";
export interface SkillLocalization {
name: string;
@@ -82,6 +84,44 @@ export interface UpdateHintPackRequest {
cards: AIHintCard[];
}
export interface HintFeedSettings {
enabled: boolean;
topHubApiKeyConfigured: boolean;
generationIntervalHours: number;
holidayCountriesZh: string;
holidayCountriesEn: string;
weatherCitiesZh: string;
weatherCitiesEn: string;
googleTrendsGeos: string;
}
export type UpdateHintFeedSettingsRequest = Omit<
HintFeedSettings,
"enabled" | "topHubApiKeyConfigured"
>;
export interface HintFeedGenerationStatus {
enabled: boolean;
outcome: "IDLE" | "RUNNING" | "SUCCEEDED" | "FAILED";
intervalHours: number;
lastStartedAt?: string;
lastCompletedAt?: string;
lastErrorCode?: string;
nextScheduledAt?: string;
topHubApiKeyConfigured: boolean;
zhVersion?: number;
zhCardCount?: number;
enVersion?: number;
enCardCount?: number;
}
export interface HintFeedGenerationResponse {
generationId: string;
generatedAt: string;
zh: { version: number; cardCount: number };
en: { version: number; cardCount: number };
}
export interface CursorPageQuery {
cursor?: string;
limit?: number;