feat(admin): 数据源页转 RAG 运维台 + 支付/模型菜单重组 + 概览升级为仪表盘
后端: - 新增 POST /admin/kb/search:管理端跨租户检索,支持 mode 指定单路 (vector/fulltext/graph/hybrid),不走 scopedKB(否则会被强制锁到调用者 自己的 space,跨租户排障就没法做了) - KB 清单补 space_id(检索键是 <space_id>/<name>,缺它前端拼不出 key) 前端: - 数据源&RAG 页补「检索试验台」:同一 query 并排跑生产链路 + 四路诊断, 召回不准时能直接定位是向量/分词/图谱哪一环挂了 - 支付拆成「配置 / 订单与对账」两个子页,挂到运维 > 支付 下; 导航支持二级菜单(NavParent 命中子路由自动展开) - SettingsPage → ModelConfigPage「模型配置」,模型参数与计费规则合一 - 概览 → 仪表盘:并入计费与用量(UsagePage → UsageSection), 去掉系统健康拓扑(与服务状态页重复,同一份 /admin/status 数据) - 全局隐藏滚动条(保留滚动) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -434,6 +434,8 @@ export async function guardrailEvents(limit = 100): Promise<GuardrailEvent[]> {
|
||||
export interface DatasourceKB {
|
||||
id: string;
|
||||
name: string;
|
||||
/** 检索作用域键前半段:三库里的库名是 "<space_id>/<name>",检索试验台按此定位。 */
|
||||
space_id: string;
|
||||
kind: string;
|
||||
tenant_id: string;
|
||||
tenant_name: string;
|
||||
@@ -442,6 +444,30 @@ export interface DatasourceKB {
|
||||
total_words: number;
|
||||
}
|
||||
|
||||
/** 检索命中:text=命中片段,score=该路的相似度/融合分(不同 mode 分数体系不同,勿跨路比较)。 */
|
||||
export interface KbHit {
|
||||
text: string;
|
||||
score: number;
|
||||
}
|
||||
|
||||
/** 检索模式:单路用于逐路定位是哪一路没召回;hybrid=纯 RRF 融合(不 rerank);""=生产链路(混合+rerank)。 */
|
||||
export type SearchMode = "" | "vector" | "fulltext" | "graph" | "hybrid";
|
||||
|
||||
// adminKbSearch 检索试验台:按完整作用域键跨租户检索任意知识库。
|
||||
// kb 传 `${space_id}/${name}`(来自 adminDatasources)。
|
||||
export async function adminKbSearch(kb: string, q: string, topK = 5, mode: SearchMode = ""): Promise<KbHit[]> {
|
||||
const res = guard(
|
||||
await fetch(`${ADMIN}/kb/search`, {
|
||||
method: "POST",
|
||||
headers: authHeaders(true),
|
||||
body: JSON.stringify({ kb, q, topK, mode }),
|
||||
}),
|
||||
);
|
||||
const d = (await res.json().catch(() => ({}))) as { hits?: KbHit[]; error?: string };
|
||||
if (!res.ok) throw new Error(d.error ?? `search failed: ${res.status}`);
|
||||
return d.hits ?? [];
|
||||
}
|
||||
|
||||
export async function adminDatasources(): Promise<{ counts: { users: number; kbs: number; docs: number }; datasources: DatasourceKB[] }> {
|
||||
const res = guard(await fetch(`${ADMIN}/datasources`, { headers: authHeaders() }));
|
||||
const d = (await res.json().catch(() => ({}))) as { counts?: { users: number; kbs: number; docs: number }; datasources?: DatasourceKB[]; error?: string };
|
||||
|
||||
Reference in New Issue
Block a user