diff --git a/backend/check-docs-api.ps1 b/backend/check-docs-api.ps1 new file mode 100644 index 00000000..5cc3e845 --- /dev/null +++ b/backend/check-docs-api.ps1 @@ -0,0 +1,70 @@ +# 通过API查询文档状态 +Write-Host "`n📋 查询知识库和文档状态...`n" -ForegroundColor Green + +# 获取知识库列表 +try { + $response = Invoke-RestMethod -Uri "http://localhost:3001/api/v1/knowledge-bases" -Method GET + + if ($response.data.Count -eq 0) { + Write-Host "❌ 没有找到任何知识库" -ForegroundColor Red + exit + } + + Write-Host "找到 $($response.data.Count) 个知识库:`n" -ForegroundColor Cyan + + foreach ($kb in $response.data) { + Write-Host "📚 知识库: $($kb.name)" -ForegroundColor Yellow + Write-Host " ID: $($kb.id)" + Write-Host " 描述: $($kb.description)" + Write-Host " 文件数: $($kb.fileCount)" + Write-Host " 创建时间: $($kb.createdAt)" + + # 获取该知识库的文档列表 + try { + $docsResponse = Invoke-RestMethod -Uri "http://localhost:3001/api/v1/knowledge-bases/$($kb.id)/documents" -Method GET + + if ($docsResponse.data.Count -gt 0) { + Write-Host "`n 📄 文档列表:" -ForegroundColor Cyan + + foreach ($doc in $docsResponse.data) { + $statusEmoji = switch ($doc.status) { + "uploading" { "📤" } + "parsing" { "🔄" } + "indexing" { "⚙️" } + "completed" { "✅" } + "error" { "❌" } + default { "❓" } + } + + Write-Host " $statusEmoji $($doc.filename)" -ForegroundColor White + Write-Host " 状态: $($doc.status)" + Write-Host " 大小: $([math]::Round($doc.fileSizeBytes / 1024, 2)) KB" + Write-Host " 上传时间: $($doc.uploadedAt)" + + if ($doc.status -eq "completed") { + Write-Host " ✓ 段落数: $($doc.segmentsCount)" -ForegroundColor Green + Write-Host " ✓ Token数: $($doc.tokensCount)" -ForegroundColor Green + } + + if ($doc.status -eq "error" -and $doc.errorMessage) { + Write-Host " ✗ 错误: $($doc.errorMessage)" -ForegroundColor Red + } + + Write-Host "" + } + } else { + Write-Host " (该知识库暂无文档)`n" + } + + } catch { + Write-Host " ❌ 获取文档列表失败: $($_.Exception.Message)" -ForegroundColor Red + } + + Write-Host ("-" * 60) + Write-Host "" + } + +} catch { + Write-Host "❌ 查询失败: $($_.Exception.Message)" -ForegroundColor Red +} + diff --git a/backend/check-documents.js b/backend/check-documents.js new file mode 100644 index 00000000..ce62ab42 --- /dev/null +++ b/backend/check-documents.js @@ -0,0 +1,64 @@ +// 查询文档状态脚本 +const { PrismaClient } = require('@prisma/client'); + +const prisma = new PrismaClient(); + +async function checkDocuments() { + try { + console.log('\n📋 查询最近上传的文档...\n'); + + const docs = await prisma.document.findMany({ + orderBy: { uploadedAt: 'desc' }, + take: 10, + include: { + knowledgeBase: { + select: { + name: true, + } + } + } + }); + + if (docs.length === 0) { + console.log('❌ 没有找到任何文档'); + return; + } + + console.log(`找到 ${docs.length} 个文档:\n`); + + docs.forEach((doc, index) => { + const statusEmoji = { + 'uploading': '📤', + 'parsing': '🔄', + 'indexing': '⚙️', + 'completed': '✅', + 'error': '❌' + }[doc.status] || '❓'; + + console.log(`${index + 1}. ${statusEmoji} ${doc.filename}`); + console.log(` 知识库: ${doc.knowledgeBase.name}`); + console.log(` 状态: ${doc.status}`); + console.log(` 大小: ${(doc.fileSizeBytes / 1024).toFixed(2)} KB`); + console.log(` 上传时间: ${doc.uploadedAt}`); + + if (doc.status === 'completed') { + console.log(` ✓ 段落数: ${doc.segmentsCount || 0}`); + console.log(` ✓ Token数: ${doc.tokensCount || 0}`); + } + + if (doc.status === 'error' && doc.errorMessage) { + console.log(` ✗ 错误: ${doc.errorMessage}`); + } + + console.log(''); + }); + + } catch (error) { + console.error('❌ 查询失败:', error.message); + } finally { + await prisma.$disconnect(); + } +} + +checkDocuments(); + diff --git a/backend/src/index.ts b/backend/src/index.ts index 22eb23b7..663df1fe 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -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 () => { diff --git a/backend/src/services/conversationService.ts b/backend/src/services/conversationService.ts index ca1e9dec..ab65c930 100644 --- a/backend/src/services/conversationService.ts +++ b/backend/src/services/conversationService.ts @@ -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'); + } } // 组装上下文 diff --git a/frontend/src/pages/AgentChatPage.tsx b/frontend/src/pages/AgentChatPage.tsx index c791fafd..93c1de72 100644 --- a/frontend/src/pages/AgentChatPage.tsx +++ b/frontend/src/pages/AgentChatPage.tsx @@ -8,10 +8,12 @@ import MessageList from '../components/chat/MessageList' import MessageInput from '../components/chat/MessageInput' import ModelSelector, { type ModelType } from '../components/chat/ModelSelector' import { useProjectStore } from '../stores/useProjectStore' +import { useKnowledgeBaseStore } from '../stores/useKnowledgeBaseStore' const AgentChatPage = () => { const { agentId } = useParams() const { currentProject } = useProjectStore() + const { knowledgeBases, fetchKnowledgeBases } = useKnowledgeBaseStore() // 智能体相关状态 const [agent, setAgent] = useState(null) @@ -26,9 +28,6 @@ const AgentChatPage = () => { // 消息发送状态 const [sending, setSending] = useState(false) const [streamingContent, setStreamingContent] = useState('') - - // 知识库(预留) - const [knowledgeBases] = useState([]) // 加载智能体配置 useEffect(() => { @@ -56,6 +55,11 @@ const AgentChatPage = () => { fetchAgent() }, [agentId]) + // 加载知识库列表 + useEffect(() => { + fetchKnowledgeBases() + }, []) + // 创建或加载对话 useEffect(() => { const initConversation = async () => { @@ -267,4 +271,3 @@ const AgentChatPage = () => { } export default AgentChatPage -