feat: complete Day 21-24 knowledge base features

- Day 21-22: fix CORS and file upload issues
- Day 23-24: implement @knowledge base search and conversation integration
- Backend: integrate Dify RAG into conversation system
- Frontend: load knowledge base list and @ reference feature
This commit is contained in:
AI Clinical Dev Team
2025-10-11 17:08:12 +08:00
parent 239c7ea85e
commit 60014b57b5
5 changed files with 218 additions and 18 deletions

View File

@@ -8,12 +8,6 @@ import { agentRoutes } from './routes/agents.js';
import { conversationRoutes } from './routes/conversations.js';
import knowledgeBaseRoutes from './routes/knowledgeBases.js';
console.log('\n' + '='.repeat(60));
console.log('🔧 正在加载修复后的服务器配置...');
console.log('📅 修复版本: 2025-10-11 - CORS完整配置');
console.log('='.repeat(60) + '\n');
console.log('🚨🚨🚨 测试日志: 文件已加载 🚨🚨🚨');
// 全局处理BigInt序列化
(BigInt.prototype as any).toJSON = function() {
@@ -54,10 +48,6 @@ await fastify.register(multipart, {
});
console.log('✅ 文件上传插件已配置: 最大文件大小 10MB');
// 添加请求日志钩子(用于调试)
fastify.addHook('onRequest', async (request, _reply) => {
console.log(`📥 ${request.method} ${request.url} - Origin: ${request.headers.origin || 'none'}`);
});
// 健康检查路由
fastify.get('/health', async () => {

View File

@@ -2,6 +2,7 @@ import { prisma } from '../config/database.js';
import { LLMFactory } from '../adapters/LLMFactory.js';
import { Message, ModelType, StreamChunk } from '../adapters/types.js';
import { agentService } from './agentService.js';
import * as knowledgeBaseService from './knowledgeBaseService.js';
interface CreateConversationData {
userId: string;
@@ -217,8 +218,44 @@ export class ConversationService {
// 获取知识库上下文(如果有@知识库)
let knowledgeBaseContext = '';
if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
// TODO: 调用Dify RAG获取知识库上下文
knowledgeBaseContext = '相关文献内容...';
const knowledgeResults: string[] = [];
// 对每个知识库进行检索
for (const kbId of knowledgeBaseIds) {
try {
const searchResult = await knowledgeBaseService.searchKnowledgeBase(
userId,
kbId,
content,
3 // 每个知识库返回3个最相关的段落
);
// 格式化检索结果
if (searchResult.records && searchResult.records.length > 0) {
const kbInfo = await prisma.knowledgeBase.findUnique({
where: { id: kbId },
select: { name: true },
});
knowledgeResults.push(
`【知识库:${kbInfo?.name || '未命名'}\n` +
searchResult.records
.map((record: any, index: number) => {
const score = (record.score * 100).toFixed(1);
return `${index + 1}. [相关度${score}%] ${record.segment.content}`;
})
.join('\n\n')
);
}
} catch (error) {
console.error(`Failed to search knowledge base ${kbId}:`, error);
// 检索失败不阻止对话,继续处理
}
}
if (knowledgeResults.length > 0) {
knowledgeBaseContext = knowledgeResults.join('\n\n---\n\n');
}
}
// 组装上下文
@@ -299,8 +336,44 @@ export class ConversationService {
// 获取知识库上下文(如果有@知识库)
let knowledgeBaseContext = '';
if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
// TODO: 调用Dify RAG获取知识库上下文
knowledgeBaseContext = '相关文献内容...';
const knowledgeResults: string[] = [];
// 对每个知识库进行检索
for (const kbId of knowledgeBaseIds) {
try {
const searchResult = await knowledgeBaseService.searchKnowledgeBase(
userId,
kbId,
content,
3 // 每个知识库返回3个最相关的段落
);
// 格式化检索结果
if (searchResult.records && searchResult.records.length > 0) {
const kbInfo = await prisma.knowledgeBase.findUnique({
where: { id: kbId },
select: { name: true },
});
knowledgeResults.push(
`【知识库:${kbInfo?.name || '未命名'}\n` +
searchResult.records
.map((record: any, index: number) => {
const score = (record.score * 100).toFixed(1);
return `${index + 1}. [相关度${score}%] ${record.segment.content}`;
})
.join('\n\n')
);
}
} catch (error) {
console.error(`Failed to search knowledge base ${kbId}:`, error);
// 检索失败不阻止对话,继续处理
}
}
if (knowledgeResults.length > 0) {
knowledgeBaseContext = knowledgeResults.join('\n\n---\n\n');
}
}
// 组装上下文