FIX-01: TrajectoryRecorderMiddleware 注册到 create_middleware_chain() (@650优先级) FIX-02: industryStore 接入 ButlerPanel 行业专长展示 + 自动拉取 FIX-03: 桌面端知识库搜索 saas-knowledge mixin + VikingPanel SaaS KB UI FIX-04: webhook 迁移标注 deprecated + 添加 down migration 注释 FIX-05: Admin Knowledge 添加结构化数据 Tab (CRUD + 行浏览) FIX-06: PersistentMemoryStore 精化 dead_code 标注 (完整迁移留后续) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
209 lines
6.3 KiB
TypeScript
209 lines
6.3 KiB
TypeScript
import request, { withSignal } from './request'
|
|
|
|
// === Types ===
|
|
|
|
export interface CategoryResponse {
|
|
id: string
|
|
name: string
|
|
description: string | null
|
|
parent_id: string | null
|
|
icon: string | null
|
|
sort_order: number
|
|
item_count: number
|
|
children: CategoryResponse[]
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface KnowledgeItem {
|
|
id: string
|
|
category_id: string
|
|
title: string
|
|
content: string
|
|
keywords: string[]
|
|
related_questions: string[]
|
|
priority: number
|
|
status: string
|
|
version: number
|
|
source: string
|
|
tags: string[]
|
|
created_by: string
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface SearchResult {
|
|
chunk_id: string
|
|
item_id: string
|
|
item_title: string
|
|
category_name: string
|
|
content: string
|
|
score: number
|
|
keywords: string[]
|
|
}
|
|
|
|
export interface AnalyticsOverview {
|
|
total_items: number
|
|
active_items: number
|
|
total_categories: number
|
|
weekly_new_items: number
|
|
total_references: number
|
|
avg_reference_per_item: number
|
|
hit_rate: number
|
|
injection_rate: number
|
|
positive_feedback_rate: number
|
|
stale_items_count: number
|
|
}
|
|
|
|
export interface ListItemsResponse {
|
|
items: KnowledgeItem[]
|
|
total: number
|
|
page: number
|
|
page_size: number
|
|
}
|
|
|
|
// === Structured Data Sources ===
|
|
|
|
export interface StructuredSource {
|
|
id: string
|
|
account_id: string
|
|
name: string
|
|
source_type: string
|
|
row_count: number
|
|
columns: string[]
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface StructuredRow {
|
|
id: string
|
|
source_id: string
|
|
row_data: Record<string, unknown>
|
|
created_at: string
|
|
}
|
|
|
|
export interface StructuredQueryResult {
|
|
row_id: string
|
|
source_name: string
|
|
row_data: Record<string, unknown>
|
|
score: number
|
|
}
|
|
|
|
// === Service ===
|
|
|
|
export const knowledgeService = {
|
|
// 分类
|
|
listCategories: (signal?: AbortSignal) =>
|
|
request.get<CategoryResponse[]>('/knowledge/categories', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
createCategory: (data: { name: string; description?: string; parent_id?: string; icon?: string }) =>
|
|
request.post('/knowledge/categories', data).then((r) => r.data),
|
|
|
|
deleteCategory: (id: string) =>
|
|
request.delete(`/knowledge/categories/${id}`).then((r) => r.data),
|
|
|
|
updateCategory: (id: string, data: { name?: string; description?: string; parent_id?: string; icon?: string }) =>
|
|
request.put(`/knowledge/categories/${id}`, data).then((r) => r.data),
|
|
|
|
reorderCategories: (items: Array<{ id: string; sort_order: number }>) =>
|
|
request.patch('/knowledge/categories/reorder', { items }).then((r) => r.data),
|
|
|
|
getCategoryItems: (id: string, params?: { page?: number; page_size?: number; status?: string }, signal?: AbortSignal) =>
|
|
request.get<ListItemsResponse>(`/knowledge/categories/${id}/items`, withSignal({ params }, signal))
|
|
.then((r) => r.data),
|
|
|
|
// 条目
|
|
listItems: (params: { page?: number; page_size?: number; category_id?: string; status?: string; keyword?: string }, signal?: AbortSignal) =>
|
|
request.get<ListItemsResponse>('/knowledge/items', withSignal({ params }, signal))
|
|
.then((r) => r.data),
|
|
|
|
getItem: (id: string, signal?: AbortSignal) =>
|
|
request.get<KnowledgeItem>(`/knowledge/items/${id}`, withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
createItem: (data: {
|
|
category_id: string
|
|
title: string
|
|
content: string
|
|
keywords?: string[]
|
|
related_questions?: string[]
|
|
priority?: number
|
|
tags?: string[]
|
|
}) => request.post('/knowledge/items', data).then((r) => r.data),
|
|
|
|
updateItem: (id: string, data: Record<string, unknown>) =>
|
|
request.put(`/knowledge/items/${id}`, data).then((r) => r.data),
|
|
|
|
deleteItem: (id: string) =>
|
|
request.delete(`/knowledge/items/${id}`).then((r) => r.data),
|
|
|
|
batchCreate: (items: Array<{
|
|
category_id: string
|
|
title: string
|
|
content: string
|
|
keywords?: string[]
|
|
tags?: string[]
|
|
}>) => request.post('/knowledge/items/batch', items).then((r) => r.data),
|
|
|
|
// 搜索
|
|
search: (data: { query: string; category_id?: string; limit?: number }) =>
|
|
request.post<SearchResult[]>('/knowledge/search', data).then((r) => r.data),
|
|
|
|
// 分析
|
|
getOverview: (signal?: AbortSignal) =>
|
|
request.get<AnalyticsOverview>('/knowledge/analytics/overview', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
getTrends: (signal?: AbortSignal) =>
|
|
request.get('/knowledge/analytics/trends', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
getTopItems: (signal?: AbortSignal) =>
|
|
request.get('/knowledge/analytics/top-items', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
getQuality: (signal?: AbortSignal) =>
|
|
request.get('/knowledge/analytics/quality', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
getGaps: (signal?: AbortSignal) =>
|
|
request.get('/knowledge/analytics/gaps', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
// 版本
|
|
getVersions: (itemId: string, signal?: AbortSignal) =>
|
|
request.get(`/knowledge/items/${itemId}/versions`, withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
rollbackVersion: (itemId: string, version: number) =>
|
|
request.post(`/knowledge/items/${itemId}/rollback/${version}`).then((r) => r.data),
|
|
|
|
// 推荐搜索
|
|
recommend: (data: { query: string; category_id?: string; limit?: number }) =>
|
|
request.post<SearchResult[]>('/knowledge/recommend', data).then((r) => r.data),
|
|
|
|
// 导入
|
|
importItems: (data: { category_id: string; files: Array<{ content: string; title?: string; keywords?: string[]; tags?: string[] }> }) =>
|
|
request.post('/knowledge/items/import', data).then((r) => r.data),
|
|
|
|
// === Structured Data Sources ===
|
|
listStructuredSources: (signal?: AbortSignal) =>
|
|
request.get<StructuredSource[]>('/structured/sources', withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
getStructuredSource: (id: string, signal?: AbortSignal) =>
|
|
request.get<StructuredSource>(`/structured/sources/${id}`, withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
deleteStructuredSource: (id: string) =>
|
|
request.delete(`/structured/sources/${id}`).then((r) => r.data),
|
|
|
|
listStructuredRows: (sourceId: string, signal?: AbortSignal) =>
|
|
request.get<StructuredRow[]>(`/structured/sources/${sourceId}/rows`, withSignal({}, signal))
|
|
.then((r) => r.data),
|
|
|
|
queryStructured: (data: { source_id?: string; query?: string; limit?: number }) =>
|
|
request.post<StructuredQueryResult[]>('/structured/query', data).then((r) => r.data),
|
|
}
|