当科技遇上神器:用Streamlit定制AI可视化问答界面

Streamlit是一个开源的Python库,利用Streamlit可以快速构建机器学习应用的用户界面。

本文主要探讨如何使用Streamlit构建大模型+外部知识检索的AI问答可视化界面。

我们先构建了外部知识检索接口,然后让大模型根据检索返回的结果作为上下文来回答问题。

Streamlit-使用说明

下面简单介绍下Streamlit的安装和一些用到的组件。

  1. Streamlit安装
pip install streamlit
  1. Streamlit启动
streamlit run xxx.py --server.port 8888

说明:

  • 如果不指定端口,默认使用8501,如果启动多个streamlit,端口依次升序,8502,8503,…。
  • 设置server.port可指定端口。
  • streamlit启动后将会给出两个链接,Local URL和Network URL。
  1. 相关组件
import streamlit as st
  • st.header

streamlit.header(body)

body:字符串,要显示的文本。

  • st.markdown

st.markdown(body, unsafe_allow_html=False)

body:要显示的markdown文本,字符串。

unsafe_allow_html: 是否允许出现html标签,布尔值,默认:false,表示所有的html标签都将转义。 注意,这是一个临时特性,在将来可能取消。

  • st.write

st.write(*args, **kwargs)

*args:一个或多个要显示的对象参数。

unsafe_allow_html :是否允许不安全的HTML标签,布尔类型,默认值:false。

  • st.button

st.button(label, key=None)

label:按钮标题字符串。

key:按钮组件的键,可选。如果未设置的话,streamlit将自动生成一个唯一键。

  • st.radio

st.radio(label, options, index=0, format_func=<class 'str'>, key=None)

label:单选框文本,字符串。

options:选项列表,可以是以下类型:
list
tuple
numpy.ndarray
pandas.Series

index:选中项的序号,整数。

format_func:选项文本的显示格式化函数。

key:组件ID,当未设置时,streamlit会自动生成。

  • st.sidebar

st.slider(label, min_value=None, max_value=None, value=None, step=None, format=None, key=None)

label:说明文本,字符串。

min_value:允许的最小值,默认值:0或0.0。

max_value:允许的最大值,默认值:0或0.0。

value:当前值,默认值为min_value。

step:步长,默认值为1或0.01。

format:数字显示格式字符串

key:组件ID。

  • st.empty

st.empty()

填充占位符。

  • st.columns

插入并排排列的容器。

st.columns(spec, *, gap="small")

spec: 控制要插入的列数和宽度。

gap: 列之间的间隙大小。

AI问答可视化代码

这里只涉及到构建AI问答界面的代码,不涉及到外部知识检索。

  1. 导入packages
import streamlit as st
import requests
import json
import sys,osimport torch
import torch.nn as nn
from dataclasses import dataclass, asdict
from typing import List, Optional, Callable
import copy
import warnings
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation.utils import GenerationConfig
from peft import PeftModel
from chatglm.modeling_chatglm import ChatGLMForConditionalGeneration
  1. 外部知识检索
def get_reference(user_query,use_top_k=True,top_k=10,use_similar_score=True,threshold=0.7):"""外部知识检索的方式,使用top_k或者similar_score控制检索返回值。"""# 设置检索接口SERVICE_ADD = ''ref_list = []user_query = user_query.strip()input_data = {}if use_top_k:input_data['query'] = user_queryinput_data['topk'] = top_kresult = requests.post(SERVICE_ADD, json=input_data)res_json = json.loads(result.text)for i in range(len(res_json['answer'])):ref = res_json['answer'][i]ref_list.append(ref)elif use_similar_score:input_data['query'] = user_queryinput_data['topk'] = top_kresult = requests.post(SERVICE_ADD, json=input_data)res_json = json.loads(result.text)for i in range(len(res_json['answer'])):maxscore = res_json['answer'][i]['prob']if maxscore > threshold:  ref = res_json['answer'][i]ref_list.append(ref)return ref_list
  1. 参数设置
# 设置清除按钮
def on_btn_click():del st.session_state.messages# 设置参数
def set_config():# 设置基本参数base_config = {"model_name":"","use_ref":"","use_topk":"","top_k":"","use_similar_score":"","max_similar_score":""}# 设置模型参数model_config = {'top_k':'','top_p':'','temperature':'','max_length':'','do_sample':""}# 左边栏设置with st.sidebar:model_name = st.radio("模型选择:",["baichuan2-13B-chat", "qwen-14B-chat","chatglm-6B","chatglm3-6B"],index="0",)base_config['model_name'] = model_nameset_ref = st.radio("是否使用外部知识库:",["是","否"],index="0",)base_config['use_ref'] = set_refif set_ref=="是":set_topk_score = st.radio('设置选择参考文献的方式:',['use_topk','use_similar_score'],index='0',)if set_topk_score=='use_topk':set_topk = st.slider('Top_K', 1, 10, 5,step=1)base_config['top_k'] = set_topkbase_config['use_topk'] = Truebase_config['use_similar_score'] = Falseset_score = st.empty()elif set_topk_score=='use_similar_score':set_score = st.slider("Max_Similar_Score",0.00,1.00,0.70,step=0.01)base_config['max_similar_score'] = set_scorebase_config['use_similar_score'] = Truebase_config['use_topk'] = Falseset_topk = st.empty()else:set_topk_score = st.empty()set_topk = st.empty()set_score = st.empty()sample = st.radio("Do Sample", ('True', 'False'))max_length = st.slider("Max Length", min_value=64, max_value=2048, value=1024)top_p = st.slider('Top P', 0.0, 1.0, 0.7, step=0.01)temperature = st.slider('Temperature', 0.0, 2.0, 0.05, step=0.01)st.button("Clear Chat History", on_click=on_btn_click)# 设置模型参数model_config['top_p']=top_pmodel_config['do_sample']=samplemodel_config['max_length']=max_lengthmodel_config['temperature']=temperaturereturn base_config,model_config
  1. 设置模型输入格式
# 设置不同模型的输入格式
def set_input_format(model_name):# ["baichuan2-13B-chat", "baichuan2-7B-chat", "qwen-14B-chat",'chatglm-6B','chatglm3-6B']if model_name=="baichuan2-13B-chat" or model_name=='baichuan2-7B-chat':input_format = "<reserved_106>{{query}}<reserved_107>"elif model_name=="qwen-14B-chat":input_format = """<|im_start|>system 你是一个乐于助人的助手。<|im_end|><|im_start|>user{{query}}<|im_end|><|im_start|>assistant"""elif model_name=="chatglm-6B":input_format = """{{query}}"""elif model_name=="chatglm3-6B":input_format = """<|system|>You are ChatGLM3, a large language model trained by Zhipu.AI. Follow the user's instructions carefully. Respond using markdown.<|user|>{{query}}<|assistant|>"""return input_format
  1. 加载模型
# 加载模型和分词器
@st.cache_resource
def load_model(model_name):if model_name=="baichuan2-13B-chat":model = AutoModelForCausalLM.from_pretrained("baichuan-inc/Baichuan2-13B-Chat",trust_remote_code=True)lora_path = ""tokenizer = AutoTokenizer.from_pretrained("baichuan-inc/Baichuan2-13B-Chat",trust_remote_code=True)model.to("cuda:0")elif model_name=="qwen-14B-chat":model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-14B-Chat",trust_remote_code=True)lora_path = ""tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-14B-Chat",trust_remote_code=True)model.to("cuda:1")elif model_name=="chatglm-6B":model = ChatGLMForConditionalGeneration.from_pretrained('THUDM/chatglm-6b',trust_remote_code=True)lora_path = ""tokenizer = AutoTokenizer.from_pretrained('THUDM/chatglm-6b',trust_remote_code=True)model.to("cuda:2")elif model_name=="chatglm3-6B":model = AutoModelForCausalLM.from_pretrained('THUDM/chatglm3-6b',trust_remote_code=True)lora_path = ""tokenizer = AutoTokenizer.from_pretrained('THUDM/chatglm3-6b',trust_remote_code=True)model.to("cuda:3")# 加载lora包model = PeftModel.from_pretrained(model,lora_path)return model,tokenizer
  1. 推理参数设置

def llm_chat(model_name,model,tokenizer,model_config,query):response = ''top_k = model_config['top_k']top_p = model_config['top_p']max_length = model_config['max_length']do_sample = model_config['do_sample']temperature = model_config['temperature']if model_name=="baichuan2-13B-chat" or model_name=='baichuan-7B-chat':messages = []messages.append({"role": "user", "content": query})response = model.chat(tokenizer, messages)elif model_name=="qwen-14B-chat":response, history = model.chat(tokenizer, query, history=None, top_p=top_p, max_new_tokens=max_length, do_sample=do_sample, temperature=temperature)elif model_name=="chatglm-6B":response, history = model.chat(tokenizer, query, history=None, top_p=top_p, max_length=max_length, do_sample=do_sample, temperature=temperature)elif model_name=="chatglm3-6B":response, history= model.chat(tokenizer, query, top_p=top_p, max_length=max_length, do_sample=do_sample, temperature=temperature)return response
  1. 主程序
if __name__=="__main__":#对话的图标user_avator = "🧑‍💻"robot_avator = "🤖"if "messages" not in st.session_state:st.session_state.messages = []torch.cuda.empty_cache()base_config,model_config = set_config()model_name = base_config['model_name']use_ref = base_config['use_ref']model,tokenizer = load_model(model_name=model_name)input_format = set_input_format(model_name=model_name)header_text = f'Large Language Model :{model_name}'st.header(header_text)if use_ref=="是":col1, col2 = st.columns([5, 3])  with col1:for message in st.session_state.messages:with st.chat_message(message["role"], avatar=message.get("avatar")):st.markdown(message["content"])if user_query := st.chat_input("请输入内容..."):with col1:  with st.chat_message("user", avatar=user_avator):st.markdown(user_query)st.session_state.messages.append({"role": "user", "content": user_query, "avatar": user_avator})with st.chat_message("robot", avatar=robot_avator):message_placeholder = st.empty()use_top_k = base_config['use_topk']if use_top_k:top_k = base_config['top_k']use_similar_score = base_config['use_similar_score']ref_list = get_reference(user_query,use_top_k=use_top_k,top_k=top_k,use_similar_score=use_similar_score) else:use_top_k = base_config['use_topk']use_similar_score = base_config['use_similar_score']threshold = base_config['max_similar_score']ref_list = get_reference(user_query,use_top_k=use_top_k,use_similar_score=use_similar_score,threshold=threshold)if ref_list:context = ""for ref in ref_list:context = context+ref['para']+"\n"context = context.strip('\n')query = f'''上下文:【{context} 】只能根据提供的上下文信息,合理回答下面的问题,不允许编造内容,不允许回答无关内容。问题:【{user_query}】'''else:query = user_queryquery = input_format.replace("{{query}}",query)print('输入:',query)max_len = model_config['max_length']if len(query)>max_len:cur_response = f'字数超过{max_len},请调整max_length。'else:cur_response = llm_chat(model_name,model,tokenizer,model_config,query)fs.write(f'输入:{query}')fs.write('\n')fs.write(f'输出:{cur_response}')fs.write('\n')sys.stdout.flush()if len(query)<max_len:if ref_list:cur_response = f"""大模型将根据外部知识库回答您的问题:{cur_response}"""else:cur_response = f"""大模型将根据预训练时的知识回答您的问题,存在编造事实的可能性。因此以下输出仅供参考:{cur_response}"""message_placeholder.markdown(cur_response)st.session_state.messages.append({"role": "robot", "content": cur_response, "avatar": robot_avator})with col2:ref_list = get_reference(user_query)if ref_list:for ref in ref_list:ques = ref['ques']answer = ref['para']score = ref['prob']question = f'{ques}--->score: {score}'with st.expander(question):st.write(answer)else:for message in st.session_state.messages:with st.chat_message(message["role"], avatar=message.get("avatar")):st.markdown(message["content"])if user_query := st.chat_input("请输入内容..."):with st.chat_message("user", avatar=user_avator):st.markdown(user_query)st.session_state.messages.append({"role": "user", "content": user_query, "avatar": user_avator})with st.chat_message("robot", avatar=robot_avator):message_placeholder = st.empty()query = input_format.replace("{{query}}",user_query)max_len = model_config['max_length']if len(query)>max_len:cur_response = f'字数超过{max_len},请调整max_length。'else:cur_response = llm_chat(model_name,model,tokenizer,model_config,query)fs.write(f'输入:{query}')fs.write('\n')fs.write(f'输出:{cur_response}')fs.write('\n')sys.stdout.flush()cur_response = f"""大模型将根据预训练时的知识回答您的问题,存在编造事实的可能性。因此以下输出仅供参考:{cur_response}"""message_placeholder.markdown(cur_response)st.session_state.messages.append({"role": "robot", "content": cur_response, "avatar": robot_avator})
  1. 可视化界面展示

总结

Streamlit工具使用非常方便,说明文档清晰。

这个可视化界面集成了多个大模型+外部知识检索,同时可以在线调整模型参数,使用方便。

完整代码:https://github.com/hjandlm/Streamlit_LLM_QA

参考

[1] https://docs.streamlit.io/
[2] http://cw.hubwiz.com/card/c/streamlit-manual/
[3] https://github.com/hiyouga/LLaMA-Factory/tree/9093cb1a2e16d1a7fde5abdd15c2527033e33143

在这里插入图片描述

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

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

相关文章

【AUTOSAR】【以太网】DoIp

AUTOSAR专栏——总目录_嵌入式知行合一的博客-CSDN博客文章浏览阅读217次。本文主要汇总该专栏文章,以方便各位读者阅读。https://xianfan.blog.csdn.net/article/details/132072415 目录 一、概述 二、功能描述 2.1 Do

DNS 域名解析协议

作用 将域名转化位IP地址 域名 用’ . ’ 隔开的字符串&#xff0c;如&#xff1a;www.badu.com,就是为了赋予IP特殊含义。 一级域名 .com &#xff1a;公用 .cn&#xff1a;中国 .gov&#xff1a;政府 .us&#xff1a;美国 .org&#xff1a;组织 .net&#xff1a;网站 对应一级…

HTML脚本、字符实体、URL

HTML脚本&#xff1a; JavaScript 使 HTML 页面具有更强的动态和交互性。 <script> 标签用于定义客户端脚本&#xff0c;比如 JavaScript。<script> 元素既可包含脚本语句&#xff0c;也可通过 src 属性指向外部脚本文件。 JavaScript 最常用于图片操作、表单验…

Vue路由导航(replace、push、forward、back、go)

Vue路由导航&#xff08;replace、push、forward、back、go&#xff09; 先了解栈结构&#xff0c;再学习以下内容 栈的数据结构&#xff1a;先进后出&#xff0c;后进先出。原理&#xff1a;push将元素压入栈内&#xff0c;pop将元素弹出&#xff0c;栈有分别有栈底指针和栈顶…

C++11 initializer_list 轻量级初始化列表的使用场景(让自定义类可以用初始化列表的形式来实例化对象)

initializer_list 是 C11 中的一个特性&#xff0c;它允许你使用花括号 {} 中的值列表来初始化容器或数组。通常用于初始化标准库容器&#xff0c;比如 std::vector、std::set、std::map 以及数组。 场景一&#xff1a;用初始化列表初始化容器 std::vector<int> arr {…

Java中Deque栈对象的增删查(所有方法详解)

1、Deque栈的增删查方法总结 2、方法增删查 栈顶添加&#xff1a;push、offFirst栈尾添加&#xff1a;add、offer、offerLast栈顶删除&#xff1a;remove、pop、poll、pollFirst栈尾删除&#xff1a;pollLast栈顶查看&#xff1a;peek、peekFirst栈尾查看&#xff1a;peekLast…

搭载基于RK3229的Android5.1修改开机默认桌面Launcher

1、找到ActivityManagerService.java 在..\rk3229_5.1_box\frameworks\base\services\core\java\com\android\server\am目录找到ActivityManagerService.java文件。在文件里找到startHomeActivityLocked函数里的setDefaultLauncher。 boolean startHomeActivityLocked(int use…

软件设计模式原则(一)迪米特法则

开一个小专题——详细总结一下软件设计模式原则&#xff0c;这部分在《软计》和《java设计模式》中算是很重要的知识点&#xff0c;值得展开详细讲解一下~首先介绍的是【迪米特法则】 一.定义 迪米特法则又称为最少知识原则&#xff0c;其定义为&#xff1a;一个软件实体应当尽…

微众银行备用金怎么取出来

在这个数字时代里&#xff0c;互联网金融产品以其便捷性和创新性逐渐成为我们日常生活中不可或缺的一部分。微众银行作为国内领先的互联网银行&#xff0c;其旗下的微众备用金产品凭借其灵活、便捷的特性&#xff0c;深受消费者喜爱。那么&#xff0c;微众备用金怎么借钱出来呢…

JavaScript中BOM与DOM

BOM window对象 所有的浏览器都支持window对象&#xff0c;他表示浏览器窗口&#xff0c; 所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。 全局变量是 window 对象的属性。全局函数是 window 对象的方法。 接下来要讲的HTML DOM 的 document 也是…

【设计模式】第24节:行为型模式之“模板方法模式”

一、简介 模板方法模式在一个方法中定义一个算法骨架&#xff0c;并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下&#xff0c;重新定义算法中的某些步骤。 模板模式有两大作用&#xff1a;复用和扩展。其中&#xff0c;复用指的是&#…

Tailwind CSS vs 现代CSS,Tailwind CSS 会像CSS-in-JS 一样亡?

本文是 关于Tailwind CSS 与 现代 CSS之间比较的文章。文章中作者详细比较了这两种CSS开发方法的优缺点。他指出&#xff0c;Tailwind CSS是一种基于类的CSS框架&#xff0c;提供了快速开发网站的便利性&#xff0c;但可能导致HTML代码的臃肿。另一方面&#xff0c;现代CSS方法…

蓝桥杯每日一题2023.10.31

题目描述 全球变暖 - 蓝桥云课 (lanqiao.cn) 题目分析 果然有关连通块类的问题使用dfs都较为好写~~ 我们可以通过判断连通块的代码来加上部分条件算出被完全淹没的岛屿个数 在岛屿中如果有为"#"的a[i][j]上下左右全部是"#"则说明此岛屿一定不会被完全…

MojoUserAgent库

Mojo::UserAgent 是 Perl 编程语言中的一个库&#xff0c;用于创建和管理 HTTP 请求。它提供了一个简单而强大的接口&#xff0c;用于发送 HTTP 请求并处理响应。 以下是一个使用 Mojo::UserAgent 的简单示例&#xff1a; use Mojo::UserAgent;创建一个 Mojo::UserAgent 对象…

[2016-2018]phpstudy的exp制作

[2016-2018]phpstudy的exp制作 用python的requests模块进行编写 修改请求数据包进行远程代码执行 import requests import base64 def remove_code_execute():try:url input("请输入要测试的网址:")cmd input("想要执行的命令:")cmd f"system({…

【Linux】Linux项目部署及更改访问端口号和jdk、tomcat、MySQL环境搭建的配置安装

目录 一、作用 二、配置 1、上传安装包 2、jdk 2.1、解压对应安装包 2.2、环境变量搭建 3、tomcat 3.1、解压对应安装包 3.2、启动 3.3、设置防火墙 3.4、设置开发端口 4、MySQL 三、后端部署 四、Linux部署项目 1、单体项目 五、修改端口访问 1、进入目录 2…

vue+elementUI 设置el-descriptions固定长度并对齐

问题描述 对于elementUI组件&#xff0c;el-descriptions 在以类似列表的形式排列的时候&#xff0c;上下无法对齐的问题。 问题解决 在el-descriptions 标签中&#xff0c;添加属性&#xff1a; :contentStyle"content_style" 控制其内容栏长度 <el-descripti…

thinkphp6 入门(11)-- 模板标签

新版框架默认只能支持PHP原生模板&#xff0c;如果需要使用thinkTemplate模板引擎&#xff0c;需要安装think-view扩展&#xff08;该扩展会自动安装think-template依赖库&#xff09;。 composer require topthink/think-view配置文件 安装完成后&#xff0c;在配置目录的vi…

stm32 ADC

目录 简介 stm32的adc 框图 ①电压输入范围 ②输入通道 ​编辑③ADC通道 ④ADC触发 ⑤ADC中断 ⑥ADC数据 ⑦ADC时钟 ADC的四种转换模式 hal库代码 标准库代码 简介 自然界的信号几乎都是模拟信号&#xff0c;比如光亮、温度、压力、声音&#xff0c;而为了方便存储、…

C++之回调函数使用和不使用using、typedef、function定义总结(二百五十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…