feat(admin-brand): add question expansion service and related functionality
- Implemented QuestionExpansionService for generating and materializing questions based on combinations and AI distillation. - Added question metadata classification logic to infer intent and layer of questions. - Created API handlers for question expansion operations including combination preview, AI distillation, metadata classification, and materialization. - Introduced database migrations to support new question-related fields and constraints in brand_questions and brand_keywords tables. - Added caching mechanism for AI distillation results to improve performance. - Defined JSON schemas for question distillation responses to ensure data integrity.
This commit is contained in:
@@ -72,6 +72,8 @@ import type {
|
||||
ListDesktopPublishTasksParams,
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
MaterializeQuestionsRequest,
|
||||
MaterializeQuestionsResult,
|
||||
MediaPlatform,
|
||||
MonitoringCitationSummaryResponse,
|
||||
MonitoringCollectNowResponse,
|
||||
@@ -89,6 +91,9 @@ import type {
|
||||
PublishKolPromptRequest,
|
||||
PublishRecord,
|
||||
Question,
|
||||
QuestionCandidateResult,
|
||||
QuestionCombinationRequest,
|
||||
QuestionDistillRequest,
|
||||
QuestionRequest,
|
||||
QuotaSummary,
|
||||
RecentArticle,
|
||||
@@ -122,6 +127,8 @@ import type {
|
||||
UpdateQuestionRequest,
|
||||
UserInfo,
|
||||
WorkspaceOverview,
|
||||
ClassifyQuestionsRequest,
|
||||
ClassifiedQuestion,
|
||||
} from '@geo/shared-types'
|
||||
|
||||
import {
|
||||
@@ -1036,6 +1043,30 @@ export const brandsApi = {
|
||||
params: keywordId ? { keyword_id: keywordId } : undefined,
|
||||
})
|
||||
},
|
||||
previewQuestionCombination(brandId: number, payload: QuestionCombinationRequest) {
|
||||
return apiClient.post<QuestionCandidateResult, QuestionCombinationRequest>(
|
||||
`/api/tenant/brands/${brandId}/questions/combination-preview`,
|
||||
payload,
|
||||
)
|
||||
},
|
||||
distillQuestions(brandId: number, payload: QuestionDistillRequest) {
|
||||
return apiClient.post<QuestionCandidateResult, QuestionDistillRequest>(
|
||||
`/api/tenant/brands/${brandId}/questions/ai-distill`,
|
||||
payload,
|
||||
)
|
||||
},
|
||||
classifyQuestions(brandId: number, payload: ClassifyQuestionsRequest) {
|
||||
return apiClient.post<ClassifiedQuestion[], ClassifyQuestionsRequest>(
|
||||
`/api/tenant/brands/${brandId}/questions/classify-metadata`,
|
||||
payload,
|
||||
)
|
||||
},
|
||||
materializeQuestions(brandId: number, payload: MaterializeQuestionsRequest) {
|
||||
return apiClient.post<MaterializeQuestionsResult, MaterializeQuestionsRequest>(
|
||||
`/api/tenant/brands/${brandId}/questions/materialize`,
|
||||
payload,
|
||||
)
|
||||
},
|
||||
createQuestion(brandId: number, payload: QuestionRequest) {
|
||||
return apiClient.post<Question, QuestionRequest>(
|
||||
`/api/tenant/brands/${brandId}/questions`,
|
||||
|
||||
@@ -67,7 +67,13 @@ const errorMessageMap: Record<string, string> = {
|
||||
brand_limit_reached: '品牌公司数量已达当前套餐上限',
|
||||
keyword_exists: '关键词已存在',
|
||||
keyword_limit_reached: '关键词数量已达当前套餐上限',
|
||||
question_limit_reached: '当前关键词下的问题数量已达上限',
|
||||
question_exists: '该品牌下已存在相同问题',
|
||||
no_valid_questions: '没有可保存的问题,请调整候选后重试',
|
||||
invalid_enum: '请求枚举值不合法',
|
||||
llm_timeout: 'AI 扩展超时,AI 点已退还',
|
||||
llm_invalid_output: 'AI 输出无法解析,AI 点已退还',
|
||||
materialize_failed: '保存问题失败,请稍后重试',
|
||||
question_limit_reached: '当前账号问题数量已达上限',
|
||||
knowledge_text_name_too_long: '文本名称不能超过 20 个字',
|
||||
brand_not_found: '品牌不存在或已删除',
|
||||
keyword_not_found: '关键词不存在或已删除',
|
||||
|
||||
Reference in New Issue
Block a user