微信扫码
与创始人交个朋友
我要投稿
昨天写了『OLLama 如何通过已有文档建立知识库进行问答?OLLama + LangChain给你助力』 ,关于图形界面下的OLLama知识库问答有个
streamlit
由于代码没跑起来,就没有写出来,今天把这部分内容补出来。最后还有一段关于离线安装ollama模型的方法,如果有需要可以到最后去参考一下。
构建一个类似于chatPDF
,但更简单的应用,用户可以上传PDF文件,基于已有的大模型,再加上提交的文档,进行简单提问。主要使用LangChain、OLLama和Streamlit,代码也并不多,提交文档,还是使用embedding,进行分割,向量转化,存储在chroma数据库。
在ollama官网安装相应版本的ollama,并在后台开启服务。在浏览器输入http://localhost:11434/
,提示Ollama is running
,表示后台服务开启。也可以手动开启ollama服务。在命令行输入ollama serve
,这个命令窗口不要关闭,后台一些信息都会在这里显示。
个人感觉,通过这个窗口的服务,比右下角图标服务,效率更高一点,支持gpu
好一点,仅个人感觉。右下角图标服务时,cpu跑满,有卡死状态,命令行运行服务时,cpu占用降下来,gpu占用提高。
拉取Mistral-7B,命令行输入:
ollama pull mistral
是否拉取成功,可以通过:
ollama list
进行查看:
检索增强生成 (RAG) 是一种使用来自私有或专有数据源的信息来辅助文本生成的技术。它将检索模型(设计用于搜索大型数据集或知识库)和生成模型(例如大型语言模型 (LLM),此类模型会使用检索到的信息生成可供阅读的文本回复)结合在一起。
流程用这张图来总结:
首先,它将文档拆分为更小的块以适应 LLM 的标记限制;其次,它使用Embeddings 对这些块进行矢量化并存储到 Chroma 中。该方法处理用户查询。用户可以提出一个问题,然后 Retrieval使用向量相似性搜索技术检索相关上下文(文档块)。通过用户的问题和检索到的上下文,我们可以编写一个提示,并请求 LLM 服务器进行预测。
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("./你不知道的JavaScript(上卷).pdf")
pages = loader.load_and_split()
print(pages)
(https://stackoverflow.com/questions/76431655/langchain-pypdfloader)
加载pdf文件后,后面还是进行分割,转矢量,存储到数据库,步骤和代码和昨天一样,只是数据源进行简单修改。可以对已有的pdf进行加载。
Streamlit 是一个用于创建数据应用的开源 Python 库。它允许开发人员使用 Python 语言来快速构建交互式的数据科学和机器学习应用,而无需编写大量的前端代码。通过 Streamlit,开发人员可以轻松地将数据处理、可视化、机器学习模型部署等功能集成到一个用户友好的 Web 应用中。
Streamlit 提供了简单易用的 API,可以通过简单的 Python 脚本来创建交互式组件,如滑动条、下拉菜单、复选框等,以及数据可视化组件,如图表、地图等。开发人员只需要编写一些 Python 代码,Streamlit 就会自动将其转换成一个 Web 应用,用户可以通过浏览器访问。
使用用stramlit进行上传pdf文件:
import streamlit as st
from PyPDF2 import PdfReader
uploaded_file = st.file_uploader("Upload your PDF")
if uploaded_file is not None:
reader = PdfReader(uploaded_file)
model_local = ChatOllama(model="mistral")
uploaded_file = st.file_uploader("Upload your PDF")
docs = []
if uploaded_file is not None:
reader = PdfReader(uploaded_file)
i = 1
for page in reader.pages:
docs.append(Document(page_content=page.extract_text(), metadata={'page':i}))
i += 1
加上streamlit的侧边栏
with st.sidebar:
st.title('?? PDF Chat App')
st.markdown('## About')
st.markdown('This app is an LLM-powered chatbot built using:')
st.markdown('- [Streamlit](https://streamlit.io/)')
st.markdown('- [LangChain](https://python.langchain.com/)')
st.markdown('- [OpenAI](https://platform.openai.com/docs/models) LLM model')
#add_vertical_space(5)
st.write('Made with 峰哥Python笔记')
streamlit代码运行时,需要在命令行输入streamlit run app.py
,类似这种格式运行代码。
class ChatPDF:
vector_store = None
retriever = None
chain = None
def __init__(self):
self.model = ChatOllama(model="mistral")
self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=100)
self.prompt = PromptTemplate.from_template(
"""
<s> [INST] You are an assistant for question-answering tasks. Use the following pieces of retrieved context
to answer the question. If you don't know the answer, just say that you don't know. Use three sentences
maximum and keep the answer concise. [/INST] </s>
[INST] Question: {question}
Context: {context}
Answer: [/INST]
"""
)
def ingest(self, pdf_file_path: str):
docs = PyPDFLoader(file_path=pdf_file_path).load()
chunks = self.text_splitter.split_documents(docs)
chunks = filter_complex_metadata(chunks)
vector_store = Chroma.from_documents(documents=chunks, embedding=FastEmbedEmbeddings())
self.retriever = vector_store.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={
"k": 3,
"score_threshold": 0.5,
},
)
self.chain = ({"context": self.retriever, "question": RunnablePassthrough()}
| self.prompt
| self.model
| StrOutputParser())
def ask(self, query: str):
if not self.chain:
return "Please, add a PDF document first."
return self.chain.invoke(query)
st.set_page_config(page_title="ChatPDF")
with st.sidebar:
st.title('?? PDF Chat App')
st.markdown('## About')
st.markdown('This app is an LLM-powered chatbot built using:')
st.markdown('- [Streamlit](https://streamlit.io/)')
st.markdown('- [LangChain](https://python.langchain.com/)')
st.markdown('- [OpenAI](https://platform.openai.com/docs/models) LLM model')
#add_vertical_space(5)
st.write('Made with 峰哥Python笔记')
def display_messages():
st.subheader("Chat")
for i, (msg, is_user) in enumerate(st.session_state["messages"]):
message(msg, is_user=is_user, key=str(i))
st.session_state["thinking_spinner"] = st.empty()
def process_input():
if st.session_state["user_input"] and len(st.session_state["user_input"].strip()) > 0:
user_text = st.session_state["user_input"].strip()
with st.session_state["thinking_spinner"], st.spinner(f"Thinking"):
agent_text = st.session_state["assistant"].ask(user_text)
st.session_state["messages"].append((user_text, True))
st.session_state["messages"].append((agent_text, False))
def read_and_save_file():
st.session_state["assistant"].clear()
st.session_state["messages"] = []
st.session_state["user_input"] = ""
for file in st.session_state["file_uploader"]:
with tempfile.NamedTemporaryFile(delete=False) as tf:
tf.write(file.getbuffer())
file_path = tf.name
with st.session_state["ingestion_spinner"], st.spinner(f"Ingesting {file.name}"):
st.session_state["assistant"].ingest(file_path)
os.remove(file_path)
def main():
if len(st.session_state) == 0:
st.session_state["messages"] = []
st.session_state["assistant"] = ChatPDF()
st.header("ChatPDF")
st.subheader("Upload a document")
st.file_uploader(
"Upload document",
type=["pdf"],
key="file_uploader",
on_change=read_and_save_file,
label_visibility="collapsed",
accept_multiple_files=True,
)
st.session_state["ingestion_spinner"] = st.empty()
display_messages()
st.text_input("Message", key="user_input", on_change=process_input)
if __name__ == "__main__":
main()
这段代码使用了 Streamlit 库来构建用户界面,并通过调用 ChatPDF
类的方法来处理上传的 PDF 文件和生成聊天消息。然后,用户可以在文本输入框中输入消息,程序将根据用户输入生成响应并显示在页面上。
st.set_page_config
设置页面配置,包括页面标题为 "ChatPDF"。st.sidebar
创建侧边栏,并在侧边栏中显示应用程序的标题和关于信息。display_messages
函数用于显示聊天消息,以及 process_input
函数用于处理用户输入和生成回复消息。read_and_save_file
函数用于读取和保存上传的 PDF 文件,并调用 ChatPDF
类中的 ingest
方法来处理文档。main
函数作为应用程序的主页面,其中包含了上传 PDF 文档的部分、显示聊天消息的部分以及用户输入消息的部分。在 Streamlit 中,st.session_state
是一个字典,用于存储应用程序的会话状态数据。会话状态数据是指与特定用户会话相关的数据,它在不同的请求之间保持不变,并且在整个用户会话期间持续存在。使用 st.session_state
可以在 Streamlit 应用程序的不同部分之间共享数据,并且可以跨多个用户请求保持数据的状态。这对于跟踪用户输入、存储应用程序的配置选项或者保存用户的会话状态非常有用。st.session_state["message"]
来管理用户输入的消息和返回的消息,st.session_state["assistant"]
一个处理ollama
的对象,包含了上传pdf,调用模型,分割,转成向量,存储到数据等操作。message
用来显示对话过程,把st.session_state["message"]
显示出来。
Streamlit 中的st.spinner(f"Thinking")
是一个小部件,用于在应用程序中显示加载状态或者进行长时间运行的任务时的进度指示。它可以让用户知道应用程序正在处理某些任务,并且可以提高用户体验,让用户感觉应用程序在运行中。
在后台回复『streamlit-chat』来获取相关的例子代码。
群里有人提问,如何使用huggingface
下载的.gguf
的模型,经过查询找到使用的方法:
下载mistrallite.Q4_K_M.gguf
这个文件到本地,可以是其他文件,需要ollama
支持的模型。
里面正确路径写好这个文件的位置
FROM ./mistrallite.Q4_K_M.gguf
通过Modelfile
创建新模型:
ollama create mistrallite -f Modelfile
-f 后面跟这个Modelfile文件,上面命令是通过这个Modelfile
,创建一个名为mistrallite
的模型,可以通过ollama run mistrallite
来运行这个模型,然后进行提问。
如果网络不通畅,可以试试此方法手动安装模型。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-05-28
2024-04-26
2024-08-21
2024-04-11
2024-07-09
2024-08-13
2024-07-18
2024-10-25
2024-07-01
2024-06-17