本系统是一个基于GraphRAG(图检索增强生成)技术的智能知识库应用,能够将上传的PDF文档自动转换为结构化的知识图谱,并支持基于图谱的智能问答。系统采用Streamlit框架构建,提供直观的用户界面,支持多文档处理、知识可视化和交互式问答功能。
- PDF文档上传与内容提取
- 实体关系抽取与知识图谱构建
- 交互式知识图谱可视化
- 基于知识库的智能问答
- 支持测试模式(无需API Key)和正常模式
+-------------------+ +-------------------+ +-------------------+
| | | | | |
| 用户界面层 | | 业务逻辑层 | | 数据存储层 |
| (Streamlit) | | (GraphRAG引擎) | | |
| | | | | |
+--------+----------+ +--------+----------+ +--------+----------+
| | |
v v v
+--------+----------+ +--------+----------+ +--------+----------+
| PDF上传与解析 | | 文本分块与向量化 | | Chroma向量存储 |
| | | | | |
+--------+----------+ +--------+----------+ +--------+----------+
| | |
v v v
+--------+----------+ +--------+----------+ +--------+----------+
| 实体关系抽取 | | 知识图谱构建 | | 图数据存储 |
| | | | | |
+--------+----------+ +--------+----------+ +--------+----------+
| | |
v v v
+--------+----------+ +--------+----------+
| 智能问答引擎 | | DeepSeek API/测试 |
| | | 问答实现 |
+-------------------+ +-------------------+
- Streamlit框架:提供响应式Web界面,支持侧边栏导航、文件上传、数据可视化
- 侧边栏菜单:包含文档上传、知识图谱、智能问答三个主要功能模块切换
- 交互式组件:文件上传器、按钮、输入框、状态指示器等
- PDF处理模块:负责PDF文档的解析和文本提取
- 文本分块模块:使用RecursiveCharacterTextSplitter将文本分割为适当大小的片段
- 实体关系抽取:基于TF-IDF的关键词提取和简单关系构建
- 知识图谱构建:使用NetworkX创建和管理实体关系图
- 向量检索:使用HuggingFaceEmbeddings和Chroma向量数据库进行语义检索
- 问答引擎:支持DeepSeek API、阿里百炼API和测试模式三种问答方式
- Chroma向量数据库:存储文档向量表示,用于相似度搜索
- 文件系统存储:保存上传的PDF文件和临时生成的HTML知识图谱
- 会话状态管理:使用Streamlit的session_state管理用户会话数据
- 确保已安装Python 3.8或更高版本
- 安装项目依赖
pip install -r requirements.txt在项目根目录下执行以下命令启动Streamlit应用:
streamlit run app.py或使用指定端口启动:
streamlit run app.py --server.port 8501启动成功后,可通过以下方式访问应用:
- 浏览器访问:http://localhost:8501
- 或者通过命令行输出中提供的URL访问
系统使用PyPDF2库解析PDF文档,提取文本内容,并保存到本地文件系统的data/uploads目录。文档处理流程包括:
def process_pdfs(uploaded_files):
"""处理上传的PDF文件,提取文本内容"""
chunks = []
# 创建上传目录
os.makedirs("data/uploads", exist_ok=True)
for uploaded_file in uploaded_files:
# 保存上传的文件
file_path = os.path.join("data/uploads", uploaded_file.name)
with open(file_path, "wb") as f:
f.write(uploaded_file.getbuffer())
# 提取PDF文本
text = extract_text_from_pdf(file_path)
# 文本分块
chunked_texts = split_text(text)
chunks.extend(chunked_texts)
return chunks使用递归字符分割器将长文本分割为重叠的片段,然后使用多语言BERT模型进行向量化:
def create_text_splitter():
"""创建文本分割器"""
return RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
length_function=len
)
def create_vector_store(texts):
"""创建向量存储"""
try:
# 配置HuggingFace模型国内镜像
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
# 创建嵌入模型
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder="./model_cache"
)
# 创建向量存储
vector_store = Chroma.from_texts(
texts=texts,
embedding=embeddings,
persist_directory="./chroma_db"
)
return vector_store
except Exception as e:
st.error(f"创建向量存储时出错: {e}")
return None系统使用基于TF-IDF的关键词提取方法识别实体,并基于实体共现关系构建知识图谱:
def extract_entities_relations(texts):
"""从文本中提取实体和关系"""
# 创建知识图谱
G = nx.Graph()
# 从文本中提取实体(这里使用简化的关键词提取方法)
# 实际项目中可以使用更复杂的NLP技术
# 提取关键词作为实体
all_text = " ".join(texts)
words = re.findall(r'\b\w{3,}\b', all_text.lower())
stop_words = set(stopwords.words('english') + stopwords.words('chinese'))
words = [word for word in words if word not in stop_words]
# 计算词频
word_freq = Counter(words)
entities = [word for word, freq in word_freq.most_common(50)]
# 添加实体节点
for entity in entities:
G.add_node(entity)
# 添加关系边(基于共现)
# 这里使用简化的共现关系构建
for text in texts:
text_words = set(re.findall(r'\b\w{3,}\b', text.lower()))
text_entities = [e for e in entities if e in text_words]
# 添加实体之间的连接
for i in range(len(text_entities)):
for j in range(i+1, len(text_entities)):
if not G.has_edge(text_entities[i], text_entities[j]):
G.add_edge(text_entities[i], text_entities[j])
return G使用pyvis库创建交互式知识图谱可视化,支持节点拖拽、缩放等操作:
def visualize_graph(graph):
"""可视化知识图谱"""
# 创建网络可视化
nt = Network(height="600px", width="100%", bgcolor="#ffffff", font_color="black")
# 添加节点和边
for node in graph.nodes():
nt.add_node(node, label=node, size=15)
for edge in graph.edges():
nt.add_edge(edge[0], edge[1])
# 设置物理布局
nt.barnes_hut(gravity=-80000, central_gravity=0.3, spring_length=250, spring_strength=0.001)
nt.show_buttons(filter_=['physics'])
# 保存为HTML文件并显示
with tempfile.TemporaryDirectory() as tmpdirname:
html_file = os.path.join(tmpdirname, "knowledge_graph.html")
nt.save_graph(html_file)
with open(html_file, "r", encoding="utf-8") as f:
html_content = f.read()
st.components.v1.html(html_content, height=600, width=None)系统支持两种问答模式:使用DeepSeek API的正常模式和基于检索的测试模式:
def create_qa_chain(vector_store):
"""创建问答链"""
# 检查是否设置了DeepSeek API Key
deepseek_api_key = os.environ.get("DEEPSEEK_API_KEY")
if deepseek_api_key:
try:
# 配置DeepSeek模型
llm = DeepSeek(api_key=deepseek_api_key)
# 创建检索QA链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vector_store.as_retriever()
)
return qa_chain
except Exception as e:
st.error(f"创建QA链时出错: {e}")
return create_test_qa_chain(vector_store)
else:
# 返回测试模式的QA链
return create_test_qa_chain(vector_store)
def create_test_qa_chain(vector_store):
"""创建测试模式的QA链"""
# 定义一个简单的基于检索的问答实现
class TestQAChain:
def __init__(self, vector_store):
self.vector_store = vector_store
def run(self, query):
# 检索相关文档
docs = self.vector_store.similarity_search(query, k=3)
# 构建简单的回答
response = f"基于检索到的信息,以下是关于 '{query}' 的回答:\n\n"
for i, doc in enumerate(docs, 1):
response += f"相关信息 {i}:\n{doc.page_content[:200]}...\n\n"
response += "\n注意:这是测试模式下的回答,基于检索的文档片段生成。设置DeepSeek API Key以获取更智能的回答。"
return response
return TestQAChain(vector_store)系统采用侧边栏导航菜单,提供三个主要功能选项:文档上传、知识图谱和智能问答。使用会话状态管理当前页面,确保导航流畅:
# 侧边栏菜单 - 优化交互
with st.sidebar:
st.title("📑 功能菜单")
# 初始化会话状态中的菜单选项
if "current_page" not in st.session_state:
st.session_state.current_page = "📄 文档上传"
# 主要功能导航菜单
st.session_state.current_page = st.radio(
"选择功能:",
["📄 文档上传", "📊 知识图谱", "💬 智能问答"],
index=["📄 文档上传", "📊 知识图谱", "💬 智能问答"].index(st.session_state.current_page),
format_func=lambda x: x.split(' ')[1],
key="main_menu"
)文档上传页面支持多文件上传,显示文件列表和大小信息,并提供进度反馈:
if st.session_state.current_page == "📄 文档上传":
st.header("📁 文档上传与处理")
# 文件上传器
uploaded_files = st.file_uploader(
"选择PDF文件",
type="pdf",
accept_multiple_files=True,
help="支持上传多个PDF文件,每个文件将被自动处理"
)
if uploaded_files:
# 显示文件列表
st.markdown("### 已选择文件:")
for i, file in enumerate(uploaded_files, 1):
st.markdown(f"{i}. **{file.name}** ({file.size / 1024:.1f} KB)")
# 处理按钮
if st.button("🔄 开始处理文档", type="primary", use_container_width=True):
# 处理文档并提供反馈知识图谱页面显示基于文档构建的实体关系图,提供交互式可视化体验:
elif st.session_state.current_page == "📊 知识图谱":
st.header("📊 知识图谱可视化")
if len(st.session_state.graph.nodes()) > 0:
st.info(f"知识图谱包含 **{len(st.session_state.graph.nodes())} 个实体** 和 **{len(st.session_state.graph.edges())} 个关系**")
if st.button("🔍 显示知识图谱", type="primary", use_container_width=True):
with st.spinner("正在生成交互式知识图谱..."):
visualize_graph(st.session_state.graph)
else:
st.warning("⚠️ 请先上传并处理文档以构建知识图谱")智能问答页面支持用户提问,提供示例问题,并显示当前运行模式:
elif st.session_state.current_page == "💬 智能问答":
st.header("💬 基于知识库的智能问答")
if st.session_state.qa_chain:
# 显示模式提示
if not deepseek_api_key:
st.info("💡 当前运行在测试模式,将返回基于检索的模拟回答")
else:
st.success("✅ 当前运行在正常模式,将返回AI生成的回答")
# 提问区域
user_query = st.text_input("请输入您的问题:", placeholder="例如: 文档中提到了哪些重要概念?")
if user_query:
if st.button("🚀 提交问题", type="primary"):
# 生成回答
# 示例问题
st.markdown("### 💡 示例问题")
# 示例问题按钮系统主要依赖以下Python库:
- streamlit - Web应用框架
- pypdf2 - PDF文档解析
- networkx - 图数据结构和算法
- pyvis - 交互式图可视化
- chromadb - 向量数据库
- langchain - 大语言模型应用框架
- sentence-transformers - 文本嵌入模型
- nltk - 自然语言处理工具包
- deepseek - DeepSeek API客户端
完整依赖列表请查看requirements.txt文件。
系统使用以下环境变量:
DEEPSEEK_API_KEY- DeepSeek API密钥(可选)ALI_BAILIAN_ACCESS_ID- 阿里百炼Access ID(可选)ALI_BAILIAN_ACCESS_KEY- 阿里百炼Access Key(可选)HF_ENDPOINT- HuggingFace模型镜像地址,默认为https://hf-mirror.com
我们提供了一个便捷的环境变量设置脚本,可以帮助您快速配置API密钥:
# 设置环境变量
python set_env_vars.py
# 设置环境变量并直接运行应用
python set_env_vars.py --run-app使用前,请确保您已在ali_bailian_config.json文件中正确配置了API凭证。
streamlit_app/
├── app.py # 主应用程序
├── app_backup.py # 代码备份
├── app_backup_*.py # 带时间戳的代码备份
├── data/
│ └── uploads/ # 上传文件存储目录
├── chroma_db/ # Chroma向量数据库
├── lib/ # 前端库文件
│ ├── bindings/
│ ├── tom-select/
│ └── vis-9.1.2/ # Vis.js图可视化库
├── model_cache/ # HuggingFace模型缓存
├── requirements.txt # 依赖项列表
├── test_*.py # 测试脚本
└── README.md # 本说明文档
在项目根目录下执行以下命令启动应用:
streamlit run app.py应用启动后,可以通过浏览器访问http://localhost:8501。
- 在侧边栏选择"文档上传"功能
- 点击"浏览文件"按钮选择一个或多个PDF文件
- 确认文件列表显示正确
- 点击"开始处理文档"按钮
- 等待处理完成(会显示处理进度和统计信息)
- 处理完文档后,点击侧边栏的"知识图谱"选项
- 或在文档处理成功后直接点击"查看知识图谱"按钮
- 点击"显示知识图谱"按钮生成交互式图谱
- 使用鼠标拖拽节点、滚轮缩放等方式交互探索图谱
- 处理完文档后,点击侧边栏的"智能问答"选项
- 或在文档处理成功后直接点击"开始问答"按钮
- 在输入框中输入您的问题,或点击示例问题按钮
- 点击"提交问题"按钮获取回答
- 系统会根据是否设置了API Key返回相应模式的回答
系统支持三种运行模式:测试模式、DeepSeek API模式和阿里百炼API模式。
- 在侧边栏的"大模型配置"部分
- 从下拉菜单选择"DeepSeek"
- 输入您的DeepSeek API Key
- 点击其他区域保存设置
- 系统会显示"DeepSeek API Key已设置"的成功提示
- 在侧边栏的"大模型配置"部分
- 从下拉菜单选择"阿里百炼"
- 输入您的阿里百炼Access ID和Access Key
- 点击其他区域保存设置
- 系统会显示"阿里百炼API凭证已设置"的成功提示
- 在侧边栏的"大模型配置"部分
- 从下拉菜单选择"测试模式"
- 无需输入API密钥,系统将使用模拟问答功能
如果遇到NLTK的punkt或stopwords数据集下载失败,可以尝试手动下载并放置在适当的位置。系统已实现异常处理,即使下载失败也能继续运行。
处理大文件时可能会遇到内存错误,建议:
- 减小文件大小或拆分大文件
- 增加chunk_size参数值,减少分块数量
- 确保系统有足够的内存资源
知识图谱节点和关系数量过多时生成会比较缓慢,可以:
- 减少提取的实体数量
- 调整词频阈值
- 优化共现关系计算逻辑
- 改进实体关系抽取:使用更先进的NLP技术如命名实体识别(NER)和关系抽取模型
- 优化知识图谱可视化:支持节点分类、关系类型展示、更丰富的交互功能
- 增强问答能力:集成更多LLM模型,支持更复杂的问答场景
- 添加文档搜索功能:支持关键词搜索和过滤
- 实现历史记录管理:保存和恢复用户会话状态
- 优化性能:提高大文档处理速度,优化向量检索效率
- 添加更多文档格式支持:扩展支持Word、Excel、PPT等格式
- 支持更多大模型:集成更多开源和商业大模型选项
- 优化阿里百炼大模型调用:添加更多模型参数配置和错误处理机制
本项目采用MIT许可证。详情请参阅LICENSE文件。
如有问题或建议,请联系项目维护者。