【基于langchain + streamlit 完整的与文档对话RAG】

news2024/11/27 4:13:39

本地部署文档问答webdemo

  • 支持 pdf
  • 支持 txt
  • 支持 doc/docx
  • 支持 源文档索引

你的点赞收藏是我持续分享优质内容的动力哦~

废话不多说直接看效果

在这里插入图片描述

准备

  • 首先创建一个新环境(选择性)
conda create -n chatwithdocs python=3.11
conda activate chatwithdocs
  • 新建一个requirements.txt文件
streamlit
python-docx
PyPDF2
faiss-gpu
langchain
langchain-core
langchain-community
  • 然后安装相应的包
pip install -r requirements.txt -U

代码

创建一个app.py文件, 把下边的复制进去
注意:替换你自己的api-keybase-url

import streamlit as st
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_openai import ChatOpenAI
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
from langchain.chains import ConversationalRetrievalChain
import docx
from PyPDF2 import PdfReader

import os
os.environ['OPENAI_API_KEY']='xxx'
# os.environ['OPENAI_BASE_URL']='xxx' # 看你的情况

st.set_page_config(page_title="Chat with Documents", page_icon=":robot:", layout="wide")

st.markdown(
    """<style>
.chat-message {
    padding: 1.5rem; border-radius: 0.5rem; margin-bottom: 1rem; display: flex
}
.chat-message.user {
    background-color: #2b313e
}
.chat-message.bot {
    background-color: #475063
}
.chat-message .avatar {
  width: 20%;
}
.chat-message .avatar img {
  max-width: 78px;
  max-height: 78px;
  border-radius: 50%;
  object-fit: cover;
}
.chat-message .message {
  width: 80%;
  padding: 0 1.5rem;
  color: #fff;
}
.stDeployButton {
            visibility: hidden;
        }
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}

.block-container {
    padding: 2rem 4rem 2rem 4rem;
}

.st-emotion-cache-16txtl3 {
    padding: 3rem 1.5rem;
}
</style>
# """,
    unsafe_allow_html=True,
)

bot_template = """
<div class="chat-message bot">
    <div class="avatar">
        <img src="https://cdn.icon-icons.com/icons2/1371/PNG/512/robot02_90810.png" style="max-height: 78px; max-width: 78px; border-radius: 50%; object-fit: cover;">
    </div>
    <div class="message">{{MSG}}</div>
</div>
"""

user_template = """
<div class="chat-message user">
    <div class="avatar">
        <img src="https://www.shareicon.net/data/512x512/2015/09/18/103160_man_512x512.png" >
    </div>    
    <div class="message">{{MSG}}</div>
</div>
"""


def get_pdf_text(pdf_docs):

    docs = []
    for document in pdf_docs:
        if document.type == "application/pdf":
            pdf_reader = PdfReader(document)
            for idx, page in enumerate(pdf_reader.pages):
                docs.append(
                    Document(
                        page_content=page.extract_text(),
                        metadata={"source": f"{document.name} on page {idx}"},
                    )
                )
        elif (
            document.type
            == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        ):
            doc = docx.Document(document)
            for idx, paragraph in enumerate(doc.paragraphs):
                docs.append(
                    Document(
                        page_content=paragraph.text,
                        metadata={"source": f"{document.name} in paragraph {idx}"},
                    )
                )
        elif document.type == "text/plain":
            text = document.getvalue().decode("utf-8")
            docs.append(Document(page_content=text, metadata={"source": document.name}))

    return docs


def get_text_chunks(docs):
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=0)

    docs_chunks = text_splitter.split_documents(docs)
    return docs_chunks


def get_vectorstore(docs_chunks):
    embeddings = OpenAIEmbeddings()
    vectorstore = FAISS.from_documents(docs_chunks, embedding=embeddings)
    return vectorstore


def get_conversation_chain(vectorstore):
    llm = ChatOpenAI()
    conversation_chain = ConversationalRetrievalChain.from_llm(
        llm=llm,
        retriever=vectorstore.as_retriever(),
        return_source_documents=True,
    )
    return conversation_chain


def handle_userinput_pdf(user_question):
    chat_history = st.session_state.chat_history
    response = st.session_state.conversation(
        {"question": user_question, "chat_history": chat_history}
    )
    st.session_state.chat_history.append(("user", user_question))
    st.session_state.chat_history.append(("assistant", response["answer"]))

    st.write(
        user_template.replace("{{MSG}}", user_question),
        unsafe_allow_html=True,
    )

    sources = response["source_documents"]
    source_names = set([i.metadata["source"] for i in sources])
    src = "\n\n".join(source_names)
    src = f"\n\n> source : {src}"
    message = st.session_state.chat_history[-1]
    st.write(bot_template.replace("{{MSG}}", message[1] + src), unsafe_allow_html=True)


def show_history():
    chat_history = st.session_state.chat_history

    for i, message in enumerate(chat_history):
        if i % 2 == 0:
            st.write(
                user_template.replace("{{MSG}}", message[1]),
                unsafe_allow_html=True,
            )
        else:
            st.write(
                bot_template.replace("{{MSG}}", message[1]), unsafe_allow_html=True
            )


def main():
    st.header("Chat with Documents")

    # 初始化会话状态
    if "conversation" not in st.session_state:
        st.session_state.conversation = None
    if "chat_history" not in st.session_state:
        st.session_state.chat_history = []

    with st.sidebar:
        st.title("文档管理")
        pdf_docs = st.file_uploader(
            "选择文件",
            type=["pdf", "txt", "doc", "docx"],
            accept_multiple_files=True,
        )
        if st.button(
            "处理文档",
            on_click=lambda: setattr(st.session_state, "last_action", "pdf"),
            use_container_width=True,
        ):
            if pdf_docs:
                with st.spinner("Processing"):
                    docs = get_pdf_text(pdf_docs)
                    docs_chunks = get_text_chunks(docs)
                    vectorstore = get_vectorstore(docs_chunks)
                    st.session_state.conversation = get_conversation_chain(vectorstore)
            else:
                st.warning("记得上传文件哦~~")

        def clear_history():
            st.session_state.chat_history = []

        if st.session_state.chat_history:
            st.button("清空对话", on_click=clear_history, use_container_width=True)

    with st.container():
        user_question = st.chat_input("输入点什么~")

    with st.container(height=400):
        show_history()
        if user_question:
            if st.session_state.conversation is not None:
                handle_userinput_pdf(user_question)
            else:
                st.warning("记得上传文件哦~~")


if __name__ == "__main__":
    main()

启动

  • 自动在浏览器打开
streamlit run app.py

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1511426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Promise其实也不难

难点图解&#xff1a;then&#xff08;&#xff09;方法 ES6学习网站&#xff1a;ES6 入门教程 解决&#xff1a;回调地狱&#xff08;回调函数中嵌套回调&#xff09; 两个特点&#xff1a; &#xff08;1&#xff09;对象的状态不受外界影响。Promise对象代表一个异步操作&…

Linux常见指令总结

ls&#xff1a;显示当前目录下文件列表 常用的命令行参数&#xff1a; -l 显示更多的文件属性 -a 显示所有的文件/目录&#xff08;包括隐藏的&#xff09; -d 只显示目录 ps&#xff1a;参数可以叠加使用。 例如&#xff1a;ls -la 显示所有文件…

力扣刷题Days16(js)-67二进制求和

目录 1,题目 2&#xff0c;代码 2.1转换进制数 2.2模拟加法 3&#xff0c;学习与总结 Math.floor() 模拟加法思路回顾 重点复习巩固 模拟加法的思路和学习位运算&#xff1b; 今天没精力了&#xff0c;先休息 1,题目 给你两个二进制字符串 a 和 b &#xff0c;以二进制…

2m高分辨率土地利用分类矢量数据/植被类型分布数据

土地利用数据是在根据影像光谱特征&#xff0c;结合野外实测资料&#xff0c;同时参照有关地理图件&#xff0c;对地物的几何形状&#xff0c;颜色特征、纹理特征和空间分布情况进行分析&#xff0c;建立统一解译标志的基础之上&#xff0c;依据多源卫星遥感信息&#xff0c;结…

【Echarts】曲线图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

前端精准测试调用链路分析

精准测试在评估需求的测试范围时&#xff0c;需要评估一下代码的影响范围&#xff0c;这个范围有两部分&#xff1a;一是需求直接修改的代码&#xff1b;二是修改代码影响到的功能模块。代码影响到的功能一般是通过调用链路分析来实现的&#xff0c;java和kotlin代码可以由java…

小白必看,靠这几步写一份简单的产品说明书!

我们都知道&#xff0c;无论是新产品发布&#xff0c;还是老产品的推广&#xff0c;产品说明书都扮演着至关重要的角色。产品说明书可以帮助用户正确、高效地使用产品&#xff0c;也是传递企业发展理念、展示企业形象的有效途径。但作为一个小白&#xff0c;怎样才能写一份简单…

JSONObject在Android Main方法中无法实例化问题

目录 前言一、Main(非安卓环境)方法下运行二、安卓坏境下运行三、why? 前言 原生的json,即org.json.JSONObject; 在Android Studio中的Main方法里运行报错&#xff0c;但在安卓程序运行过程正常 一、Main(非安卓环境)方法下运行 static void test() {try {// 创建一个 JSON …

动态类型是什么?——跟老吕学Python编程

动态类型是什么&#xff1f;——跟老吕学Python编程 前言动态编程语言动态编程语言特点&#xff1a;动态编程语言的优点&#xff1a;动态编程语言的缺点&#xff1a; 静态编程语言静态编程语言特点&#xff1a;静态编程语言的优点&#xff1a;静态编程语言的缺点&#xff1a; 总…

【Vue3】什么是路由?Vue中的路由基本切换~

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Linux操作系统-07-Linux安装应用

一、使用rpm安装应用&#xff08;不推荐&#xff09; 先下载到本地&#xff0c;以.rpm文件名结尾&#xff0c;下载完成后&#xff0c;再安装 rpm -qa | grep mysql #查询当前系统是否有下载过mysql包 先上传mysql的rpm安装包到linux的opt目录 安装 rpm -ivh …

云游戏发行是什么?云游戏发行的演进历程

云游戏发行是一系列基于云游戏技术的游戏发行策略或行为&#xff0c;融合云试玩、云微端、可玩广告、跨端移植等技术&#xff0c;从而在传统游戏发行生态的基础上实现更为卓越的发行效果。 云游戏发行出现的原因 近年来&#xff0c;游戏市场出现负增长。其原因一方面在于游戏版…

删除数据表

oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 删除数据表属于数据库对象的操作 drop table 表名称; 删除 emp30 表 SQL> drop table emp30;表已删除。 上面这个语句运行后&#xff0c;就会把数据表 emp30 删除 在…

AV1:编码块划分

​AV1是AOM于2018年发布的一代视频编码标准&#xff0c;相比于VP9其编码效率提升30%&#xff0c;相对于H.26X系列标准&#xff0c;AV1完全免去专利费可以自由使用。 AV1和其他视频编码标准类似&#xff0c;也采用基于块的编码架构。当编码器读进一帧图像&#xff0c;首先将其划…

Vue 3中的provide和inject:跨组件通信的新方式

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【linux】冯诺依曼体系与操作系统的理解

本篇文章是进程的预备知识&#xff0c;但也不仅仅是进程的预备知识&#xff0c; 也可以更好地帮助我们理解整个计算机体系。 目录 冯诺依曼体系结构&#xff1a;进一步理解操作系统&#xff1a; 冯诺依曼体系结构&#xff1a; 关于这张图先进行一下必要的解释&#xff1a; 输…

【清晰易懂】@Mapper注解和BaseMapper爱恨情仇

此问题的提出在于自己没有弄明白一个问题&#xff0c;就是Mapper注解有时候可以不加&#xff0c;有时候又需要加。 先说结论&#xff1a;Mapper注解和BaseMapper类在项目中起着相同的作用&#xff0c;都是为了实现数据库基本简单的CRUD&#xff0c;省去在xml文件中再去写&#…

java八股文复习----java集合,CAS---2024/03/12

1.java常见的集合类 2.List&#xff0c;Set,Map的区别 3.上述三个集合有哪些常用的方法 4.List,Set,Map哪几个是线程安全的&#xff1f; 5.ArrayList和LinkedList的区别 6.ArrayList和Vector的区别 7.ArrayList的扩容机制 8.HashMap集合 8.1数据结构 8.2哈希冲突的解决办法有哪…

Conmi遇到的坑——禅道的PCDN

好家伙&#xff0c;悄悄在后台吃了七十多G流量&#xff0c;我把你当兄弟宣传&#xff0c;你把我当PCDN吸。 还纳闷今天创建个VUE项目怎么提示D盘没空间&#xff0c;明明留了几十G&#xff0c;好家伙&#xff0c;一下子全吸干了。 删了两个&#xff0c;还有一个&#xff08;已…

吴恩达深度学习笔记:神经网络的编程基础2.5-2.8

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第二周&#xff1a;神经网络的编程基础 (Basics of Neural Network programming)2.5 导数&#xff08;Derivatives&#xff09; 第一门课&#xff1a;神经网络和深度学习 (Neural Networks an…