【橘子大模型】使用streamlit來構建自己的聊天機器人(下)

一、簡介

我們之前完成了一個簡易的聊天機器人,但是還留下了一些問題沒有解決,比如如何開啟新的會話。如何切換session_id,如何把對話做成流式的輸出。這些我們就會在今天來完成。

二、關于新的會話和session_id

from dotenv import load_dotenv
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ElasticsearchChatMessageHistoryfrom streamlit import streamlit as st# load env file
load = load_dotenv("./.env")# 無密碼的elasticsearch配置
es_url = "http://localhost:9200"
# 存儲的索引,我們不用預先創建索引,因為說實話我也不知道字段,langchain會創建,并且自動映射字段
index_name = "chat_history"# init llm
llm = ChatOllama(base_url = "http://127.0.0.1:11434",model = "huihui_ai/deepseek-r1-abliterated:14b",temperature = 0.5,num_predict = 10000
)# 構建ElasticsearchChatMessageHistory
def get_session_history(session_id: str) :return  ElasticsearchChatMessageHistory(index=index_name,session_id=session_id,es_url=es_url,ensure_ascii=False)session_id = "levi"
st.title("你好,這里是橘子GPT,我是小橘")
st.write("請把您的問題輸入,小橘會認真回答的哦。")
# 添加一個輸入框,用戶自己輸入來替代默認的
session_id = st.text_input("請輸入一個session_id,否則我們將使用默認值levi",session_id)
# 添加一個按鈕,觸發按鈕開啟新的會話,并且刪除上下文記錄
isClickButton:bool = st.button("點擊按鈕,開啟新的對話")
# query input
user_prompt = st.chat_input("我是小橘,請輸入你的問題吧")if isClickButton:# 清除es中存儲的上下文記錄,這個是物理刪除delete_by_queryget_session_history(session_id).clear()# 清除當前會話的上下文st.session_state.chat_history = []# 如果沒有就創建,不要每次都建立新的
if 'chat_history' not in st.session_state:st.session_state.chat_history = []
# 遍歷里面的內容,取出來存進去的每一組role 和 content
for message in st.session_state.chat_history :# 通過取出來的信息,構建st.chat_message,不同的角色會有不同的ui樣式,這里就是做這個的with st.chat_message(message['role']):# 把內容展示出來st.markdown(message['content'])template = ChatPromptTemplate.from_messages([('human',"{prompt}"),('placeholder',"{history}")
])
chain = template | llm | StrOutputParser()
chain_with_history = RunnableWithMessageHistory(chain,get_session_history,input_messages_key="prompt",history_messages_key="history",
)if user_prompt :response = chain_with_history.invoke({"prompt": user_prompt},config={"configurable": {"session_id": session_id}})# 保存歷史,上面用來遍歷顯示,避免后面覆蓋前面的顯示st.session_state.chat_history.append({'role':'user','content':user_prompt})with st.chat_message('user'):st.markdown(user_prompt)# 保存歷史,上面用來遍歷顯示,避免后面覆蓋前面的顯示st.session_state.chat_history.append({'role':'assistant','content':response})with st.chat_message('assistant'):st.markdown(response)

這樣就實現了需求了,可以直接跑一下看看。

三、關于流式對話

流式對話其實說白了就是回復的時候一個字一個字的顯示,表現為流的樣子,而不是一次性返回一大堆。

from dotenv import load_dotenv
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ElasticsearchChatMessageHistoryfrom streamlit import streamlit as st# load env file
load = load_dotenv("./.env")# 無密碼的elasticsearch配置
es_url = "http://localhost:9200"
# 存儲的索引,我們不用預先創建索引,因為說實話我也不知道字段,langchain會創建,并且自動映射字段
index_name = "chat_history"
# streamlit code
session_id = "levi"# init llm
llm = ChatOllama(base_url = "http://127.0.0.1:11434",model = "huihui_ai/deepseek-r1-abliterated:14b",temperature = 0.5,num_predict = 10000
)
# 構建ElasticsearchChatMessageHistory
def get_session_history(session_id: str) :return ElasticsearchChatMessageHistory(index=index_name,session_id=session_id,es_url=es_url,ensure_ascii=False)st.title("你好,這里是橘子GPT,我是小橘")
st.write("請把您的問題輸入,小橘會認真回答的哦。")
# 設置一個輸入框,用戶輸入的內容來替代默認的session_id。
session_id = st.text_input("請輸入一個session_id,否則我們將使用默認值levi",session_id)
# 添加一個按鈕,點擊按鈕的時候清空歷史會話
isClickButton:bool = st.button("點擊按鈕,開啟新的對話")
if isClickButton:# 注意這一行會去調用es客戶端delete_by_query物理刪除es中的上下文數據,最好自己定制,不要直接用get_session_history(session_id).clear()# 清除當前窗口的上下文記錄st.session_state.chat_history = []# query input
user_prompt = st.chat_input("我是小橘,請輸入你的問題吧")# 構建langchain執行
def invoke_history_by_stream(chain,prompt,session_id):chain_with_history = RunnableWithMessageHistory(chain,get_session_history,input_messages_key = prompt,history_messages_key="history",)# 以stream流的方式執行responseStream = chain_with_history.stream({"prompt": prompt},config={"configurable": {"session_id": session_id}})# 遍歷返回,逐個回復for response in responseStream:yield response# 如果沒有就創建,不要每次都建立新的
if 'chat_history' not in st.session_state:st.session_state.chat_history = []
# 遍歷里面的內容,取出來存進去的每一組role 和 content
for message in st.session_state.chat_history :# 通過取出來的信息,構建st.chat_message,不同的角色會有不同的ui樣式,這里就是做這個的with st.chat_message(message['role']):# 把內容展示出來st.markdown(message['content'])template = ChatPromptTemplate.from_messages([('human',"{prompt}"),('placeholder',"{history}")
])
chain = template | llm | StrOutputParser()# 如果感知到輸入
if user_prompt :# 保存歷史,上面用來遍歷顯示,避免后面覆蓋前面的顯示st.session_state.chat_history.append({'role':'user','content':user_prompt})with st.chat_message('user'):st.markdown(user_prompt)with st.chat_message('assistant'):# 以流式的方式渲染答案streamResp = st.write_stream(invoke_history_by_stream(chain,user_prompt,session_id))# 保存歷史,上面用來遍歷顯示,避免后面覆蓋前面的顯示st.session_state.chat_history.append({'role': 'assistant', 'content': streamResp})

這就是流的代碼,可以執行一下。

四、優化一版

我們再來優化一下樣式。這個可以有可以不做,最好交給前端來做,streamlit的ui太生硬了。加了幾個模板占位的替換。

from dotenv import load_dotenv
from langchain_community.chat_message_histories import ElasticsearchChatMessageHistory
from langchain_ollama import ChatOllama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.prompts import MessagesPlaceholder, ChatPromptTemplatefrom streamlit import streamlit as stload = load_dotenv("./.env")
es_url = "http://localhost:9200"
index_name = "chat_history"
def get_session_history(session_id: str) :return ElasticsearchChatMessageHistory(index=index_name,session_id=session_id,es_url=es_url,ensure_ascii=False)
# init llm
llm = ChatOllama(base_url = "http://127.0.0.1:11434",model = "huihui_ai/deepseek-r1-abliterated:14b",temperature = 0.5,num_predict = 10000
)user_id = "levi"with st.sidebar:st.image("./orange.png", width=150)user_id = st.text_input("輸入你的id", user_id)role = st.radio("你想獲得什么級別的回答呢?", ["初學者", "專家", "大佬"], index=0)if st.button("清空歷史上下文,開啟新的對話"):st.session_state.chat_history = []get_session_history(user_id).clear()st.markdown("""<div style='display: flex; height: 70vh; justify-content: center; align-items: center;'><h2>請問你需要什么幫助呢?</h2></div>""",unsafe_allow_html=True
)if 'chat_history' not in st.session_state:st.session_state.chat_history = []for message in st.session_state.chat_history:with st.chat_message(message['role']):st.markdown(message['content'])template = ChatPromptTemplate.from_messages([MessagesPlaceholder(variable_name="history"),('system', f"你作為一個 {role} 級別的人來回答這個問題"),('human', "{prompt}")
])chain = template | llm | StrOutputParser()def invoke_history(chain, session_id, prompt):history = RunnableWithMessageHistory(chain, get_session_history,input_messages_key="prompt",history_messages_key="history")for response in history.stream({"prompt": prompt},config={"configurable": {"session_id": session_id}}):yield responseprompt = st.chat_input("輸入你的問題,小橘會為你回答。")if prompt:st.session_state.chat_history.append({'role': 'user', "content": prompt})with st.chat_message('user'):st.markdown(prompt)with st.chat_message('assistant'):streamResponse = st.write_stream(invoke_history(chain, user_id, prompt))st.session_state.chat_history.append({'role': 'assistant', "content": streamResponse})

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76028.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76028.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76028.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php-cgi參數注入攻擊經歷淺談

起因&#xff1a; 阿里云服務器再次警告出現挖礦程序。上一次服務器被攻擊后&#xff0c;怕有惡意程序殘留&#xff0c;第一時間重裝了系統&#xff0c;也沒有詳查攻擊入口。不過事后還是做了一些防范&#xff0c;這臺留作公網訪問的服務器上并未保留業務數據&#xff0c;只作…

自動駕駛中的實時挑戰:如何優化車輛動力學模型

自動駕駛中的實時優化:自行車模型與雙軌模型的計算復雜度權衡 在自動駕駛領域,車輛動力學建模是實現精準控制和路徑規劃的關鍵。自行車模型和雙軌模型作為兩種主流的建模方法,在實時性需求下如何平衡計算復雜度與精確度,是工程師們必須面對的挑戰。本文將深入探討這兩種模…

Hybrid 架構的概念,以及如何優化Hybrid 通信方案,提升頁面加載速度和渲染性能

1. 什么是 Hybrid 架構&#xff1f; Hybrid&#xff08;混合&#xff09;架構是指 結合 Web 技術和 Native&#xff08;原生&#xff09;技術 的移動應用開發模式&#xff0c;通常由以下部分組成&#xff1a; Web 部分&#xff1a;使用 HTML、CSS、JavaScript&#xff08;或前…

關于類模板STL中vector容器的運用和智能指針的實現

代碼題&#xff1a;使用vector實現一個簡單的本地注冊登錄系統 注冊&#xff1a;將賬號密碼存入vector里面&#xff0c;注意防重復判斷 登錄&#xff1a;判斷登錄的賬號密碼是否正確 #include <iostream> #include <cstring> #include <cstdlib> #in…

OpenCV 從入門到精通(day_04)

1. 繪制圖像輪廓 1.1 什么是輪廓 輪廓是一系列相連的點組成的曲線&#xff0c;代表了物體的基本外形。相對于邊緣&#xff0c;輪廓是連續的&#xff0c;邊緣不一定連續&#xff0c;如下圖所示。其實邊緣主要是作為圖像的特征使用&#xff0c;比如可以用邊緣特征可以區分臉和手…

Python錯誤分析與調試

在Python編程的過程中&#xff0c;我們難免會遇到各種各樣的錯誤&#xff0c;而有效地分析和調試這些錯誤&#xff0c;能讓我們的代碼快速恢復正常運行&#xff0c;今天就來和大家聊聊Python中錯誤分析與調試的相關內容。 錯誤分析 Python中的錯誤大致可以分為語法錯誤和邏…

Browser-use:基于 Python 的智能瀏覽器自動化 AI 工具調研與實戰

Browser-use&#xff1a;基于 Python 的智能瀏覽器自動化 AI 工具調研與實戰 一、概述 Browser-use 是一個旨在將 AI “智能體”&#xff08;Agents&#xff09;與真實瀏覽器進行交互的 Python 庫&#xff0c;可以輕松實現瀏覽器自動化。在配合 LLM&#xff08;如 GPT 系列&a…

網絡空間安全(51)郵件函數漏洞

前言 郵件函數漏洞&#xff0c;特別是在PHP環境中使用mail()函數時&#xff0c;是一個重要的安全問題。 一、概述 在PHP中&#xff0c;mail()函數是一個用于發送電子郵件的內置函數。其函數原型為&#xff1a; bool mail ( string $to , string $subject , string $message [, …

LLaMA-Factory 數據集成從入門到精通

一、框架概述 LLaMA-Factory 框架通過Alpaca/Sharegpt雙格式體系實現多任務適配&#xff0c;其中Alpaca專注結構化指令微調&#xff08;含SFT/DPO/預訓練&#xff09;&#xff0c;Sharegpt支持多角色對話及多模態數據集成。核心配置依托 dataset_info.json 實現數據源映射、格…

如何根據設計稿進行移動端適配:全面詳解

如何根據設計稿進行移動端適配&#xff1a;全面詳解 文章目錄 如何根據設計稿進行移動端適配&#xff1a;全面詳解1. **理解設計稿**1.1 設計稿的尺寸1.2 設計稿的單位 2. **移動端適配的核心技術**2.1 使用 viewport 元標簽2.1.1 代碼示例2.1.2 參數說明 2.2 使用相對單位2.2.…

07-Spring Boot 自動配置原理全解析

Spring Boot 自動配置原理全解析&#xff08;EnableAutoConfiguration 源碼追蹤&#xff09; Spring Boot 之所以能大幅簡化配置&#xff0c;核心就在于它的 自動配置機制&#xff0c;而這一機制背后主要依賴于 EnableAutoConfiguration 注解。本文將從使用、源碼、常見問題及…

前端如何檢測項目中新版本的發布?

前言 你是否也曾遇到過這種情況&#xff0c;每次發完版之后都還會有用戶反饋問題沒有被修復&#xff0c;一頓排查之后發現他用的還是舊的版本。 用戶&#xff1a;在 XX 頁面 XX 字段還是不展示 我&#xff1a;刷新下頁面 用戶&#xff1a;刷新了啊 我&#xff1a;強刷一下&…

Vue 項目使用 pdf.js 及 Elasticpdf 教程

摘要&#xff1a;本文章介紹如何在 Vue 中使用 pdf.js 及基于 pdf.js 的批注開發包 Elasticpdf。簡單 5 步可完成集成部署&#xff0c;包括數據的云端同步&#xff0c;示例代碼完善且簡單&#xff0c;文末有集成代碼分享。 1. 工具庫介紹與 Demo 1.1 代碼包結構 ElasticPDF基…

聊聊Spring AI的ChromaVectorStore

序 本文主要研究一下Spring AI的ChromaVectorStore 示例 pom.xml <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-chroma</artifactId></dependency>配置 spring:ai:vectorstore:…

整數編碼 - 華為OD統一考試(A卷、Java)

題目描述 實現一種整數編碼方法,使得待編碼的數字越小,編碼后所占用的字節數越小。 編碼規則如下: 編碼時7位一組,每個字節的低7位用于存儲待編碼數字的補碼。字節的最高位表示后續是否還有字節,置1表示后面還有更多的字節,置0表示當前字節為最后一個字節。采用小端序編…

Linux 遞歸查找并刪除目錄下的文件

在 Linux 中&#xff0c;可以使用 find 命令遞歸查找并刪除目錄下的文件 1、示例命令 find /path/to/directory -type f -name "filename_pattern" -exec rm -f {} 2、參數說明 /path/to/directory&#xff1a;要查找的目標目錄type f&#xff1a;表示查找文件&am…

【筆記】VS中C#類庫項目引用另一個類庫項目的方法

VS中C#類庫項目引用另一個類庫項目的方法 在 C# 開發中&#xff0c;有時我們需要在一個類庫項目中引用另一個類庫項目&#xff0c;但另一個項目可能尚未編譯成 DLL。在這種情況下&#xff0c;我們仍然可以通過 Visual Studio 提供的項目引用功能進行依賴管理。 &#x1f3af; …

第五講(下)| string類的模擬實現

string類的模擬實現 一、Member constants&#xff08;成員常數&#xff09;npos 二、Member functions&#xff08;成員函數&#xff09;constructor&#xff08;構造&#xff09;、destructor&#xff08;析構&#xff09;、c_str遍歷1 &#xff1a;Iterators遍歷2&#xff1…

洛谷題單3-P4956 [COCI 2017 2018 #6] Davor-python-流程圖重構

題目描述 在征服南極之后&#xff0c;Davor 開始了一項新的挑戰。下一步是在西伯利亞、格林蘭、挪威的北極圈遠征。 他將在 2018 年 12 月 31 日開始出發&#xff0c;在這之前需要一共籌集 n 元錢。 他打算在每個星期一籌集 x 元&#xff0c;星期二籌集 xk 元&#xff0c;……

【正點原子】如何設置 ATK-DLMP135 開發板 eth0 的開機默認 IP 地址

開機就想讓 eth0 乖乖用靜態 IP&#xff1f;別再被 DHCP 搶走地址了&#xff01; 三步教你徹底掌控 ATK-DLMP135 的網絡啟動配置&#xff0c;簡單粗暴&#xff0c;實測有效&#xff01; 正點原子STM32MP135開發板Linux核心板嵌入式ARM雙千兆以太網CAN 1. 刪除 dhcpcd 自動獲取…