Files

58 lines
4.4 KiB
JavaScript
Raw Permalink Normal View History

const fs = require('node:fs')
const path = require('node:path')
const assert = require('node:assert/strict')
const root = path.resolve(__dirname, '../..')
const ids = ['16c3e59c-4bb6-41cf-ae0a-6d0941b3d032', '20b9280e-ed73-4700-8fa5-944d6ae6dd5f', 'bb86b44a-576b-4bf8-a6bf-8f1baca3a845', 'badd084b-f229-4005-8fb3-196fbe139fe0', '5d28a7e5-e00e-44a7-a0e1-c72342cdcf68', '3ae9257d-928a-4886-8101-7cfd0ed8c27c']
let token
async function api(route, method = 'GET', body) {
const response = await fetch(`http://127.0.0.1:18080/api/v1${route}`, { method,
headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}`, 'X-Tenant-ID': '10059' } : {}) },
body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(30000) })
const result = await response.json()
assert.ok(response.ok && result.success !== false, `${method} ${route}: HTTP ${response.status}`)
return result
}
async function main() {
const credentials = JSON.parse(fs.readFileSync(path.join(root, 'acceptance/super-admin-login.json'), 'utf8'))
const login = await api('/auth/login', 'POST', { username: credentials.username, password: credentials.password })
token = (login.data || login).token
const selected = process.argv.includes('--product-only') ? ids.slice(0, 1) : ids
const before = []
for (const id of selected) before.push((await api(`/knowledge-bases/${id}`)).data)
if (!process.argv.includes('--apply')) {
console.log(JSON.stringify(before.map(kb => ({ name: kb.name, enabled: !!kb.extract_config?.enabled, initialized: !!(kb.embedding_model_id && kb.summary_model_id) }))))
return
}
fs.writeFileSync(path.join(root, 'acceptance', `kb-graph-config-before-${Date.now()}.json`), JSON.stringify(before, null, 2), { mode: 0o600, flag: 'wx' })
for (const kb of before) {
assert.ok(kb.embedding_model_id && kb.summary_model_id, 'Models must be configured first')
const config = (await api(`/initialization/config/${kb.id}`)).data
const request = { ...config,
llmModelId: kb.summary_model_id, embeddingModelId: kb.embedding_model_id,
nodeExtract: {
enabled: true,
text: '基础概念是实践练习的先修条件。',
tags: ['先修条件', '包含', '适用于', '条件适用于', '禁用于', '慎用于', '不适用于', '不能用于', '关联', '导致', '不导致', '约束', '对比', '支持', '不支持', '抑制'],
nodes: [{ name: '基础概念', attributes: ['概念'] }, { name: '实践练习', attributes: ['方法'] }],
relations: [{ node1: '基础概念', node2: '实践练习', type: '先修条件', evidence: '基础概念是实践练习的先修条件。' }],
customInstructions: '按当前原文的实际主题提取有依据的实体和关系,不根据知识库名称预设领域。每条关系的 evidence 必须逐字引用连续原文,保留主体、时间、否定、条件、观点归属和不确定性。叙事和个人观点不能改写成通用因果;先修条件按前提指向后续目标;约束须保留完整动作。产品使用标签只适用于明确的产品使用说明,不同产品分节不得串用关系。不要把格式示例写入实际图谱,不要补造原文没有的关系;确实没有关系时如实返回,交由覆盖复核。',
},
}
await api(`/initialization/config/${kb.id}`, 'PUT', request)
await api(`/knowledge-bases/${kb.id}`, 'PUT', { name: kb.name, description: kb.description,
config: { chunking_config: kb.chunking_config, image_processing_config: kb.image_processing_config,
faq_config: kb.faq_config, auto_tag_config: kb.auto_tag_config, wiki_config: kb.wiki_config,
indexing_strategy: { ...kb.indexing_strategy, graph_enabled: true } } })
const after = (await api(`/knowledge-bases/${kb.id}`)).data
assert.equal(after.extract_config.enabled, true)
assert.equal(after.indexing_strategy.graph_enabled, true)
assert.equal(after.embedding_model_id, kb.embedding_model_id)
assert.equal(after.summary_model_id, kb.summary_model_id)
assert.equal(after.storage_backend_id, kb.storage_backend_id)
assert.deepEqual(after.wiki_config, kb.wiki_config)
assert.deepEqual(after.chunking_config, kb.chunking_config)
}
console.log(JSON.stringify({ configured: before.map(kb => kb.name), existing_indexes_preserved: true, graph_build_complete: false }))
}
main().catch(error => { console.error(error.message); process.exitCode = 1 })