【Langchain+Streamlit】旅游聊天机器人

news2024/11/21 1:31:29

【Langchain+Streamlit】打造一个旅游问答AI-CSDN博客

项目线上地址,无需openai秘钥可直接体验:http://101.33.225.241:8502/

github地址:GitHub - jerry1900/langchain_chatbot: langchain+streamlit打造的一个有memory的旅游聊天机器人,可以和你聊旅游相关的事儿

        上节课,我们介绍了一个用streamlit和langchain打造的问答机器人,但是这个机器人有一个问题就是它只能一问一答,而且这个机器人是没有记忆的,你问他连续的问题他就傻帽了,所以,今天我们介绍一下如何打造一个类似chatGPT界面,有上下文感知、可以和你连续聊天的机器人,当然,我们也限定这个机器人只能聊旅游相关的问题。

1. 工程结构介绍

        之后我们做的项目越来越大,不可能所有代码都堆到一个主文件里,所以要设计良好的工程代码结构,这个是本项目的工程结构:

        .streamlit里面的secrets.toml是存放key和其他一些常用配置参数的文件。

        .venv是虚拟环境。

        chain.py里有两个函数,一个build_chain,一个generate_response。

        chat.py是主体程序。

        template.py是存放prompt模板的地方。

        其他两个文件不用管。

        完整的代码,去github上去拉。

2. 引入必要的包

        我们先用streamlit打造一个聊天界面,之前我们已经有了一些streamlit的基础,这里我们就讲的稍微稍微快一点:

import io
import streamlit as st
from PIL import Image

from langchain.memory import ConversationBufferMemory

from chain import generate_response,build_chain


st.title('🤖AI小万的旅游聊天机器人😜')

with st.sidebar:

    # 设置一个可点击打开的展开区域
    with st.expander("🤓国内可访问的openai账号"):
        st.write("""
            1. 如果使用默认地址,可以使用openai官网账号(需科学上网🥵).
            2. 如果你没有openai官网账号,可以联系博主免费试用国内openai节点账号🥳.
        """)

        # 本地图片无法直接加载,需先将图片读取加载为bytes流,然后才能正常在streamlit中显示
        image_path = r"C:\Users\Administrator\langchain_chatbot\wechat.jpg"
        image = Image.open(image_path)
        image_bytes = io.BytesIO()
        image.save(image_bytes, format='JPEG')
        st.image(image_bytes, caption='AI小万老师的微信', use_column_width=True)

  3. 进行聊天记录和memory的初始化,打印聊天记录

        先引入必要的包,注意要引入ConversationBufferMemory,因为我们要在初始化的时候先初始化一个memory,同时我们要初始化一个messages,这些都要放到session里。

# 初始化聊天记录
if "messages" not in st.session_state:
    st.session_state.messages = []
    st.session_state.memory = ConversationBufferMemory(memory_key='chat_history')

       streamlit有一个特性:用户只能使用互动组件(interactive widgets)触发回调,并且每次操作互动组件时,都会触发重新运行(rerun)。rerun(重新运行)是streamlit的一个特色,指的是将应用代码从头到尾重新运行一遍。

# 展示聊天记录
for message in st.session_state.messages:
    if message["role"] == "user":
        with st.chat_message(message["role"], avatar='☺️'):
            st.markdown(message["content"])
    else:
        with st.chat_message(message["role"], avatar='🤖'):
            st.markdown(message["content"])

        因此,我们要把session里的messages里的消息遍历一遍打印出来,这样确保你刚才添加的最新的消息 也在页面上显示出来,我们继续。

4. 进行用户输入、回答生成和回答展示

if prompt := st.chat_input('我们来聊一点旅游相关的事儿吧'):
    with st.chat_message('user', avatar='☺️'):
        st.markdown(prompt)

    st.session_state.messages.append({'role': 'user', 'content': prompt})

    chain = build_chain(st.session_state.memory)

    answer = generate_response(chain, prompt)

    response = answer['text']

    with st.chat_message('assistant', avatar='🤖'):
        st.markdown(response)
    st.session_state.messages.append({'role': 'assistant', 'content': response})

        下面这行代码,先检查prompt是否为空,如果为空则给他一个st的输入:

if prompt := st.chat_input('聊点和旅游相关的事儿吧,么么哒'):

        然后设置用户的输入和头像,然后把用户的输出用markdown语法显示出来(我没有试用write可不可以,你可以自己试一下):

with st.chat_message('user', avatar='☺️'):
        st.markdown(prompt)

    st.session_state.messages.append({'role': 'user', 'content': prompt})

       然后这里用了两个我们自己构造的函数,一个是build_chain,这里记住要把session里的memory传入进来,这个动作帮助我们构造的模型保持上下文的记忆:

chain = build_chain(st.session_state.memory)

       然后我们调用generate_response方法来获得模型的回答:

answer = generate_response(chain, prompt)

  5. build_chain方法

        这个方法的入参是一个在前文中构造好的memory,其他的方法我们在之前的课中都介绍过,大家可以自己去翻看:

def build_chain(memory):
    llm = OpenAI(
        temperature=0,
        # openai_api_key=os.getenv("OPENAI_API_KEY"),
        openai_api_key=st.secrets['api']['key'],
        # base_url=os.getenv("OPENAI_BASE_URL")
        base_url=st.secrets['api']['base_url']
    )

    prompt = PromptTemplate.from_template(BASIC_TEMPLATE)


    conversation = LLMChain(
        llm=llm,
        prompt=prompt,
        verbose=True,
        memory=memory,

    )

    return conversation

6.generate_response方法

      这个更简单,不多说了:

def generate_response(chain,input_text):

    response = chain.invoke(input_text)
    return  response

7. template单独设置

        我看别的项目,都是把template单独建一个文件,然后引入,这样代码结构比较清晰,我也有样学样了:

from template import BASIC_TEMPLATE

        这里是template里BASIC_TEMPLATE的具体内容:

BASIC_TEMPLATE="""
你是一个万贺创造的旅游问答机器人,你只回答用户关于旅游和地理方面的问题。
如果用户的问题中没有出现地名或者没有出现如下词语则可以判定为与旅游无关:‘玩、旅游、好看、有趣、风景’

    
案例:
1. 用户问题:今天天气如何? 你的回答:抱歉,我只负责回答和旅游、地理相关的问题。
2. 用户问题:你是谁?你的回答:我是万贺创造的旅游问答机器人,我只负责回答和旅游、地理相关的问题。
3. 用户问题:今天股市表现如何?你的回答:抱歉我只负责回答和旅游、地理相关的问题

注意:
1. 价格也是旅游相关的问题,如果你不清楚的话直接回答不知道

过去的聊天记录:
{chat_history}

用户的问题: 
{question}

你的回答:
"""

8. 完整代码

        chat.py

import io
import streamlit as st
from PIL import Image

from langchain.memory import ConversationBufferMemory

from chain import generate_response,build_chain


st.title('🤖AI小万的旅游聊天机器人😜')

with st.sidebar:

    # 设置一个可点击打开的展开区域
    with st.expander("🤓国内可访问的openai账号"):
        st.write("""
            1. 如果使用默认地址,可以使用openai官网账号(需科学上网🥵).
            2. 如果你没有openai官网账号,可以联系博主免费试用国内openai节点账号🥳.
        """)

        # 本地图片无法直接加载,需先将图片读取加载为bytes流,然后才能正常在streamlit中显示
        image_path = r"C:\Users\Administrator\langchain_chatbot\wechat.jpg"
        image = Image.open(image_path)
        image_bytes = io.BytesIO()
        image.save(image_bytes, format='JPEG')
        st.image(image_bytes, caption='AI小万老师的微信', use_column_width=True)


# 初始化聊天记录
if "messages" not in st.session_state:
    st.session_state.messages = []
    st.session_state.memory = ConversationBufferMemory(memory_key='chat_history')




# 展示聊天记录
for message in st.session_state.messages:
    if message["role"] == "user":
        with st.chat_message(message["role"], avatar='☺️'):
            st.markdown(message["content"])
    else:
        with st.chat_message(message["role"], avatar='🤖'):
            st.markdown(message["content"])


# 用于用户输入
if prompt := st.chat_input('我们来聊一点旅游相关的事儿吧'):
    with st.chat_message('user', avatar='☺️'):
        st.markdown(prompt)

    st.session_state.messages.append({'role': 'user', 'content': prompt})

    chain = build_chain(st.session_state.memory)

    answer = generate_response(chain, prompt)

    response = answer['text']

    with st.chat_message('assistant', avatar='🤖'):
        st.markdown(response)
    st.session_state.messages.append({'role': 'assistant', 'content': response})

        chain.py

  

import os

import streamlit as st

from langchain_openai import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

from template import BASIC_TEMPLATE

def build_chain(memory):
    llm = OpenAI(
        temperature=0,
        # openai_api_key=os.getenv("OPENAI_API_KEY"),
        openai_api_key=st.secrets['api']['key'],
        # base_url=os.getenv("OPENAI_BASE_URL")
        base_url=st.secrets['api']['base_url']
    )

    prompt = PromptTemplate.from_template(BASIC_TEMPLATE)


    conversation = LLMChain(
        llm=llm,
        prompt=prompt,
        verbose=True,
        memory=memory,

    )

    return conversation

def generate_response(chain,input_text):

    response = chain.invoke(input_text)
    return  response

        

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

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

相关文章

Linux 命令基础

Shell概述 Linux操作系统的Shell作为操作系统的外壳,为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。 Shell是用户和Linux内核之间的接口程序,如果把硬件想象成一个球体的中心,内核围绕在硬件的外层管理着…

【JS逆向九】逆向某混淆网站源码,模拟 加密,解密,密钥生成

逆向日期:2024.02.09 使用工具:Node.js 是否有混淆:源代码混淆 加密方法:AES标准库 文章全程已做去敏处理!!! 【需要做的可联系我】 可使用AES进行解密处理(直接解密即可&#xff0…

读千脑智能笔记09_大脑的错误信念

1. 人类智能的未来 1.1. 气候变化如此剧烈,在下一个百年里,一些城市很可能会不再适合人类居住,大面积的农业区或将变得更加贫瘠 1.1.1. 气候并非唯一需要关注的问题 1.1.2. 人类的一些技术,如核武器和基因编辑,为少…

win32编程系统BUG(Win32 API中的WM_SETTEXT消息)

由于频繁使用Win32 API中的WM_SETTEXT消息,导致内存占用直线上升。 暂未找到有效解决方案。

【SpringBoot】Redis集中管理Session和自定义用户参数解决登录状态及校验问题

🏡浩泽学编程:个人主页 🔥 推荐专栏:《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 🛸学无止境,不骄不躁,知行合一 文章目录 前言一、分布…

全网最快2024刘谦春晚魔术揭秘

早点关注我,精彩不错过! 来来来,我的手机快被私信爆炸了,一次性给大家说清楚。 原版 Woody Arogon的教学《Woodyland》 数学原理 约瑟夫问题与魔术(五)——魔术《自我匹配的奇迹》中的数学原理 魔术原理 约…

vim常用命令以及配置文件

layout: article title: “vim文本编译器” vim文本编辑器 有三种模式: 命令模式 文本模式, 末行模式 vim命令大全 - 知乎 (zhihu.com) 命令模式 插入 i: 切换到输入模式,在光标当前位置开始输入文本。 a: 进入插入模式,在光标下一个位置开始输入文…

小巨人大爆发:紧凑型大型语言模型效率之谜揭晓!

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

【数学建模】【2024年】【第40届】【MCM/ICM】【A题 七鳃鳗性别比与资源可用性】【解题思路】

我们通过将近半天的搜索数据,查到了美国五大湖中优势物种的食物网数据,以Eric伊利湖为例,共包含34各优势物种,相互之间的关系如下图所示: 一、题目 (一) 赛题原文 2024 MCM Problem A: Reso…

VBA技术资料MF117:测试显示器大小

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。我的教程一共九套,分为初级、中级、高级三大部分。是对VBA的系统讲解,从简单的入门,到…

数据结构(C语言)代码实现(八)——顺序栈实现数值转换行编辑程序括号分配汉诺塔

目录 参考资料 顺序栈的实现 头文件SqStack.h(顺序栈函数声明) 源文件SqStack.cpp(顺序栈函数实现) 顺序栈的三个应用 数值转换 行编辑程序 顺序栈的实现测试 栈与递归的实现(以汉诺塔为例) 参考资…

前端工程化面试题 | 02.精选前端工程化高频面试题

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

秒杀相关问题解决

秒杀 超卖问题 如下,我们先来复现问题,抢购秒杀券的代码逻辑也是很简单, 先判断优惠券是否开始了,是的化,判断库存是否充足,如果是的化,扣减库存,最后创建订单 如下是代码 Override Transactional public Result seckillVoucher(Long voucherId) {//1.查询优惠券SeckillVo…

备战蓝桥杯---动态规划之背包问题引入

先看一个背包问题的简单版: 如果我们暴力枚举可能会超时。 但我们想一想,我们其实不关心怎么放,我们关心的是放后剩下的体积。 用可行性描述即可。 于是我们令f[i][j]表示前i个物品能否放满体积为j的背包。 f[i][j]f[i-1][j]||f[i-1][j-v…

数据结构-->线性表-->单链表

链表的定义 链表:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 与顺序表不同的是,链表里的每节都是独立申请下来的空间,我们称之为“节点、结点”。 节点的组成主要由…

Electron+Vue实现仿网易云音乐实战

前言 这个项目是我跟着官方文档的那个Electron入门教程大致跑了一遍,了解了下Electron开发流程之后的实战项目,所以中间应该是会有很多写法不是很规范,安全性有可能也没考虑到,可实现的各种api也不是很了解,适合初学者。 必须感谢 https://github.com/Binaryify/NeteaseC…

小白水平理解面试经典题目LeetCode 71. Simplify Path【Stack类】

71. 简化路径 小白渣翻译 给定一个字符串 path ,它是 Unix 风格文件系统中文件或目录的绝对路径(以斜杠 ‘/’ 开头),将其转换为简化的规范路径。 在 Unix 风格的文件系统中,句点 ‘.’ 指的是当前目录,…

每日五道java面试题之java基础篇(二)

第一题. 为什么说 Java 语⾔“编译与解释并存”? ⾼级编程语⾔按照程序的执⾏⽅式分为编译型和解释型两种。 简单来说,编译型语⾔是指编译器针对特定的操作系统将源代码⼀次性翻译成可被该平台执⾏的机器码;解释型语⾔是指解释器对源程序逐…

vue全家桶之状态管理Pinia

一、Pinia和Vuex的对比 1.什么是Pinia呢? Pinia(发音为/piːnjʌ/,如英语中的“peenya”)是最接近pia(西班牙语中的菠萝)的词; Pinia开始于大概2019年,最初是作为一个实验为Vue重新…

基于Spark+Springboot的电商用户行为分析系统设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容:SpringBoot、Vue、SSM、HLM…