Gradio 搭建人工智能交互界面v1

Gradio 搭建人工智能交互界面v1

  • 0 Gradio 简介
  • 1 gradio.Interface() 搭建界面
  • 2 使用 gradio.Chatbot() 来助力聊天!
  • 3 接入本地知识库进行回答
    • 3.1 绑定已封装的函数
  • 4 丰富前端界面
    • 4.1 gradio.File() 上传文件
    • 4.2 gradio.Slider() 配置滑动条
    • 4.3 gradio.Dropdown() 建立下拉列表
    • 4.4 gradio.Accordion() 可折叠组件
    • 4.5 gradio.Markdown() 编写 Markdown 模块
    • 4.6 gradio.Row() 和 gradio.Column() 调整布局

Gradio 搭建人工智能交互界面

我们对知识库和LLM已经有了基本的理解,现在是将它们巧妙地融合并打造成一个富有视觉效果的界面的时候了。这样的界面不仅对操作更加便捷,还能便于与他人分享。
Gradio 是一种快速便捷的方法,可以直接在 Python 中通过友好的 Web 界面演示机器学习模型。在本课程中,我们将学习_如何使用它为生成式人工智能应用程序构建用户界面_。在构建了应用程序的机器学习或生成式人工智能后,如果你想构建一个demo给其他人看,也许是为了获得反馈并推动系统的改进,或者只是因为你觉得这个系统很酷,所以想演示一下:Gradio 可以让您通过 Python 接口程序快速实现这一目标,而无需编写任何前端、网页或 JavaScript 代码。 加载 HF API 密钥和相关 Python 库

0 Gradio 简介

Gradio 可以包装几乎任何 Python 函数为易于使用的用户界面。
常用的基础模块构成如下:

  • 应用界面:gradio.Interface(简易场景), gradio.Blocks(定制化场景)
  • 输入输出:gradio.Image(图像), gradio.Textbox(文本框), gradio.DataFrame(数据框), gradio.Dropdown(下拉选项), gradio.Number(数字), gradio.Markdown(Markdown), gradio.Files(文件)
  • 控制组件:gradio.Button(按钮)
  • 布局组件:gradio.Tab(标签页), gradio.Row(行布局), gradio.Column(列布局)

大部分功能模块都可以通过以下三个参数进行初始化:

  • fn:包装的函数
  • inputs:输入组件类型,(例如:“text”、"image)
  • ouputs:输出组件类型,(例如:“text”、"image

1 gradio.Interface() 搭建界面

# 导入所需的库
import gradio as gr  # 用于创建 Web 界面
import os  # 用于与操作系统交互,如读取环境变量

# 定义一个函数来根据输入生成文本
def generate(input, temperature):
    """
    该函数用于根据输入生成文本。

    参数:
    input: 输入内容。
    temperature: LLM 的温度系数。

    返回:
    output: 生成的文本。
    """
    # 使用预定义的 client 对象的 predict 方法,从输入生成文本
    # slider 的值限制生成的token的数量
    output = llm.predict(input, temperature=temperature)
    return output  # 返回生成的文本

# 创建一个 Web 界面
# 输入:一个文本框和一个滑块
# 输出:一个文本框显示生成的文本
demo = gr.Interface(
    fn=generate, 
    inputs=[
        gr.Textbox(label="Prompt"),  # 文本输入框
        gr.Slider(label="Temperature", value=0,  maximum=1, minimum=0)  # 滑块用于选择模型的 temperature
    ], 
    outputs=[gr.Textbox(label="Completion")],  # 显示生成文本的文本框
    title="Chat Robot",  # 界面标题
    description="Local Knowledge Base Q&A with llm",  # 界面描述
    # allow_flagging="never", 
)

# 关闭可能已经启动的任何先前的 gradio 实例
gr.close_all()

# 启动 Web 界面
# 使用环境变量 PORT1 作为服务器的端口号
# demo.launch(share=True, server_port=int(os.environ['PORT1']))
demo.launch() # 直接启动页面

上述代码进行运行:
然后输出一下URL:将下面的 URL 复制,在浏览器打开:

Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.

功能介绍:

  • fn=generate: 这是用于处理输入的函数,即文本生成函数 generate。
  • inputs=[ gr.Textbox(label=“Prompt”), gr.Slider(label=“Temperature”, value=0, maximum=1, minimum=0) ]: 这定义了模型的输入。
    使用 gr.Textbox 部件来以文本框的形式显示输入的内容描述,label 参数设置了输入部件的标签为 prompt。
    使用 gr.Slider 部件以滑动条的形式来显示输入的内容描述,label 参数设置了输入部件的标签为 temperature。
  • outputs=[gr.Textbox(label=“Caption”)]: 这定义了输出部分。使用 gr.Textbox 部件来显示生成的内容描述,label 参数设置了输出部件的标签。
  • title=“Chat Robot”: 这是界面的标题,将显示在界面的顶部。
  • description="Local Knowledge Base Q&A with llm ": 这是界面的描述,提供有关界面功能的更多信息。
  • allow_flagging=“never”: 这设置了不允许标记内容,确保不会显示标记不恰当内容的选项。

通过 demo.launch() 启动整个可视化前端界面。
我们可以对demo.launch 中的参数进行配置:demo.launch(share=True, server_port=8080))

  • share=True 表示生成外部可访问的链接
  • server_port=8080 表示运行的端口

看文件提示,每次生成的 外部访问链接,如果没有付费的话,每次只能存活72小时,72小时之后,就会中断;如果想要长期使用,可能需要付费。

这样,外部的用户也可以通过生成的链接直接访问我们的界面
现在我们已经搭建了一个非常简单的 Gradio 界面,它有一个文本框输入和一个输出。我们已经可以非常简单地向 LLM 提问。但我们还是不能对话,因为如果你再问一个后续问题,它就无法理解或保留上下文。
因此,基本上我们要做的是,向模型发送我们之前的问题、它自己的回答以及后续问题。但建立所有这些都有点麻烦。这就是 Gradio 聊天机器人组件的作用所在,因为它允许我们简化向模型发送对话历史记录的过程。

因此,我们要解决这个问题。为此,我们将引入一个新的 Gradio 组件–Gradio Chatbot

2 使用 gradio.Chatbot() 来助力聊天!

让我们开始使用 Gradio Chatbot 组件。这里实例化了一个带有文本框 prompt 和提交按钮的 Gradle ChatBot 组件,是一个非常简单的用户界面。但我们现在还不是在和 LLM 聊天。

我们必须格式化聊天 prompt。此处正在定义这个格式化聊天 prompt 函数。 在这里,我们要做的就是使其包含聊天历史记录,这样 LLM 就能知道上下文。 但这还不够。我们还需要告诉它,哪些信息来自用户,哪些信息来自 LLM 本身,也就是我们正在调用的助手。 因此,我们设置了格式聊天 prompt 功能,在聊天记录的每一轮中,都包含一条用户信息和一条助手信息,以便我们的模型能准确回答后续问题。 现在,我们要将格式化的 prompt 传递给我们的 API。

相比 Interface,Blocks 提供了一个低级别的 API,用于设计具有更灵活布局和数据流的网络应用。Blocks 允许控制组件在页面上出现的位置,处理复杂的数据流(例如,输出可以作为其他函数的输入),并根据用户交互更新组件的属性可见性。可以定制更多组件

# 定义一个函数,用于格式化聊天 prompt。
def format_chat_prompt(message, chat_history):
    """
    该函数用于格式化聊天 prompt。

    参数:
    message: 当前的用户消息。
    chat_history: 聊天历史记录。

    返回:
    prompt: 格式化后的 prompt。
    """
    # 初始化一个空字符串,用于存放格式化后的聊天 prompt。
    prompt = ""
    # 遍历聊天历史记录。
    for turn in chat_history:
        # 从聊天记录中提取用户和机器人的消息。
        user_message, bot_message = turn
        # 更新 prompt,加入用户和机器人的消息。
        prompt = f"{prompt}\nUser: {user_message}\nAssistant: {bot_message}"
    # 将当前的用户消息也加入到 prompt中,并预留一个位置给机器人的回复。
    prompt = f"{prompt}\nUser: {message}\nAssistant:"
    # 返回格式化后的 prompt。
    return prompt

# 定义一个函数,用于生成机器人的回复。
def respond(message, chat_history):
    """
    该函数用于生成机器人的回复。

    参数:
    message: 当前的用户消息。
    chat_history: 聊天历史记录。

    返回:
    "": 空字符串表示没有内容需要显示在界面上,可以替换为真正的机器人回复。
    chat_history: 更新后的聊天历史记录
    """
    # 调用上面的函数,将用户的消息和聊天历史记录格式化为一个 prompt。
    formatted_prompt = format_chat_prompt(message, chat_history)
    # 使用llm对象的predict方法生成机器人的回复(注意:llm对象在此代码中并未定义)。
    bot_message = llm.predict(formatted_prompt,
                                max_new_tokens=1024,
                                stop_sequences=["\nUser:", ""])
    # 将用户的消息和机器人的回复加入到聊天历史记录中。
    chat_history.append((message, bot_message))
    # 返回一个空字符串和更新后的聊天历史记录(这里的空字符串可以替换为真正的机器人回复,如果需要显示在界面上)。
    return "", chat_history

# 下面的代码是设置Gradio界面的部分。

# 使用Gradio的Blocks功能定义一个代码块。
with gr.Blocks() as demo:
    # 创建一个Gradio聊天机器人组件,设置其高度为240。
    chatbot = gr.Chatbot(height=240) 
    # 创建一个文本框组件,用于输入  prompt。
    msg = gr.Textbox(label="Prompt")
    # 创建一个提交按钮。
    btn = gr.Button("Submit")
    # 创建一个清除按钮,用于清除文本框和聊天机器人组件的内容。
    clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")

    # 设置按钮的点击事件。当点击时,调用上面定义的respond函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。
    btn.click(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])
    # 设置文本框的提交事件(即按下Enter键时)。功能与上面的按钮点击事件相同。
    msg.submit(respond, inputs=[msg, chatbot], outputs=[msg, chatbot]) 

# 关闭所有已经存在的 Gradio 实例。
gr.close_all()
# 启动新的 Gradio 应用,设置分享功能为 True,并使用环境变量 PORT1 指定服务器端口。
# demo.launch(share=True, server_port=int(os.environ['PORT1']))
demo.launch()
Closing server running on port: 7860
Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.

现在,我们的问答机器人可以回答后续问题了。 我们可以看到,我们向它发送了上下文。我们向它发送了信息,然后要求它完成。一旦我们进入另一个迭代循环,我们就会向它发送我们的整个上下文,然后要求它完成。这很酷。但是,如果我们一直这样迭代下去,那么模型在一次对话中所能接受的信息量就会达到极限,因为我们总是给它越来越多的之前对话的内容。

这里,我们创建了一个简单但功能强大的用户界面,用于与LLM聊天。如果需要进一步Gradio 所能提供的最佳功能,我们可以创建一个包含更多功能的用户界面。

3 接入本地知识库进行回答

3.1 绑定已封装的函数

现在我们可以将本地知识库的内容接入进来,让 llm 运用本地数据库进行回答。

我们之前已经学习过如何运用 LLM 对本地知识库进行问答,现在让我们将这个功能加入到我们的前端界面中。 回忆一下,我们学习了两种运用本地知识库进行问答的方式:

  • Chat_QA_chain_self:记忆历史记录的问答
  • QA_chain_self:直接进行问答,即没有历史记录

我们需要创建两个按钮,分别与对应的函数相绑定。
初始化按钮:

db_with_his_btn = gr.Button("Chat db with history")
db_wo_his_btn = gr.Button("Chat db without history")

将按钮与函数进行绑定,并且配置相应的输入和输出:

# 设置按钮的点击事件。当点击时,调用上面定义的 Chat_QA_chain_self 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。
db_with_his_btn.click(Chat_QA_chain_self.answer, inputs=[msg, chatbot,  llm, embeddings, history_len, top_k, temperature], outputs=[msg, chatbot])
# 设置按钮的点击事件。当点击时,调用上面定义的 QA_chain_self 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。
db_wo_his_btn.click(QA_chain_self.answer, inputs=[msg, chatbot, llm, embeddings, top_k, temperature], outputs=[msg, chatbot])

4 丰富前端界面

4.1 gradio.File() 上传文件

这里我们是直接运用前面章节生成好的向量数据库。
当用户想要在前端页面上传自己的文件生成新的数据库时,gradio.File 可以很方便的完成这部分功能
File 用于创建一个文件组件,允许用户上传通用文件(用作输入)或显示通用文件(用作输出)

  • 作为输入时,File 模块文件按照** file_count 以 tempfile._TemporaryFileWrapper** 或 List[tempfile._TemporaryFileWrapper] 的格式传递给绑定的函数,或者按照 type 的值转化为 bytes/List[bytes]。
  • 作为输出时,File 模块希望函数返回一个文件的路径/包含文件路径的列表(str / List[str])。

**file_count **允许用户上传文件的数量,返回类型将根据 “multiple” 或 “directory” 的情况为每个文件返回一个列表。

  • “single”,允许用户上传一个文件。
  • “multiple”,允许用户上传多个文件。
  • “directory”,允许用户上传所选目录中的所有文件。

file_types: 要上传的文件扩展名或文件类型的列表(例如[‘image’,‘.json’,‘.mp4’])。字符串表示支持上传的文件类型,格式后缀表示支持上传的文件格式。

  • “file”: 允许上传任何文件
  • “image”: 仅允许上传图像文件
  • “audio”: 仅允许上传音频文件
  • “video”: 仅允许上传视频文件
  • “text”: 仅允许上传文本文件
  • “.pdf”: 仅允许上传 pdf 文件
  • “.md”: 仅允许上传 txt 文件

注意:当 file_count 为 “directory” 时,会忽略 “file_types” 的参数配置。

gr.File(label='请选择知识库目录',file_count='directory',
                file_types=['.txt', '.md', '.docx', '.pdf'])

4.2 gradio.Slider() 配置滑动条

对于本项目来说,存在很多可以配置的参数,比如 LLM 的温度系数(temperature),这个参数的取值范围为 0-1,控制着 LLM 生成内容的稳定性。

温度基本上就是希望模型的变化程度。因此,如果将温度设为零,模型就会倾向于始终对相同的输入做出相同的反应。所以同样的问题,同样的答案。温度越高,信息的变化就越多。但如果温度过高,它就会开始给出无意义的答案。

我们想通过前端来进行参数的配置,但同时希望将参数限制在一个区间内,这时 gr.text 无法满足我们的需求。gradio.Slider 是可以胜任这个任务的组件。

gradio.Slider 允许用户通过滑动滑块在指定的范围内选择一个值:

  • minimum:滑块的最小值,默认为 0。
  • maximum:滑块的最大值,默认为 100。
  • value: 滑块的默认值,即作为可调用对象时的默认值。
  • step:滑块的步长,即每次滑动的增量,默认为None。
  • label:组件在界面中显示的名称,默认为None。
  • interactive: 滑块是否可调节。如果未提供,则根据组件是用作输入还是输出进行推断。
temperature = gr.Slider(0,
        1,
        value=0.00,
        step=0.01,
        label="llm temperature",
        interactive=True)

我们可以将其他类似的参数采用相同的构建方式,如:

  • 向量检索的数量(top_k):从向量数据库返回的最相关文档的数量,LLM 会根据返回的文档生成回答。
  • 聊天历史的长度(history_len):使聊天历史保持一定的长度,防止过大消耗过多的 token。

4.3 gradio.Dropdown() 建立下拉列表

刚刚我们介绍了 gradio 对于连续值的选择方法,现在我们来介绍下对于离散值的选择方法。
我们可以切换不同的模型,尝试不同模型的效果。我们用 gradio.Dropdown 来建立一个下拉列表,让用户从提供的模型中选择一个模型

  • choices:可供选择的选项列表。
  • value:默认选中的值。如果为 None,则没有默认选中值。如果为可调用对象,则在应用程序加载时调用该函数以设置组件的初始值。
  • type:组件返回的值的类型。"value(返回选择的字符串),“index”(返回选择的索引)。
  • multiselect:是否可以选择多个选项。
  • max_choices:可选择的最大选项数。如果为None,则不限制数量。
  • interactive: 滑块是否可调节。如果未提供,则根据组件是用作输入还是输出进行推断。
llm = gr.Dropdown(
    llm_model_list,
    label="large language model",
    value=init_llm,
    interactive=True)

同样,我们可以对生成 Embedding 的模型进行对应的配置。

将组件作为输入绑定在对应的函数中,即可完成对应参数的切换。

4.4 gradio.Accordion() 可折叠组件

对于 llm 和 Embedding 来说,通常我们选择一次后就不会再做调整,一直将整个组件展示在界面中显得占位置,我们可以用 gradio.Accordion 组件来将其折叠

  • open:控制默认展开折叠组件。

gradio.Accordion 默认是展开的,对于组件内容提供折叠按钮。对于不需要的组件我们可以配置 open=“False”, 将其设置为默认折叠的状态。

我们先初始化 gradio.Accordion 组件,再将需要折叠的内容用 with 包起来即可。

model_select = gr.Accordion("模型选择")
with model_select:
    llm = gr.Dropdown(...)
    embedding = gr.Dropdown(...)

4.5 gradio.Markdown() 编写 Markdown 模块

之前介绍的都是交互式组件,我们可以用 markdown 为我们的界面加一些说明,使整个界面看起来更加美观。同时可以增加一些辅助信息。

  • value:要在Markdown组件中显示的值。如果可调用,则每当加载应用程序以设置组件的初始值时,都会调用该函数。
  • rtl(bool):是否从右到左呈现文本。如果为True,则将渲染文本的方向设置为从右到左。默认值为False,它从左到右呈现文本。
  • latex_delimiters(list[dict[str,str|bool]]):将用于呈现 LaTeX 表达式的形式{“left”:打开分隔符(str)、“right”:关闭分隔符(str)、“display”:是否以换行符(bool)显示}形式的dict列表。如果未提供,则将latex_delimitters’设置为[{ “left”: “,“right”:”", “display”: False }]`,因此只有包含在 $ 分隔符中且在同一行中的表达式才会呈现为 latex。传入一个空列表以禁用 LaTeX 渲染。有关更多信息,请参阅KaTeX文档。
gr.Markdown("""

Chat Robot

Local Knowledge Base Q&A with llm
"""
)

4.6 gradio.Row() 和 gradio.Column() 调整布局

现在我们已经有了足够多的组件,是时候将他们按照一定的布局格式进行调整了。
gradio.Row()gradio.Column() 分别是新建一行和新建一列的组件。我们将界面划分成不同的行列区域,将所需组件摆放在对应位置即可。

gradio.Row() 的常用参数:

  • equal_height(bool): 是否将每个子元素的高度设置为相等。
  • variant(Literal[(‘default’, ‘panel’, ‘compact’)]): 行类型。“default”(无背景)、“panel”(灰色背景色和圆角)或“compact”(圆角和无内部间隙)。

gradio.Column() 的常用参数:

  • scale:与相邻列相比的相对宽度。例如,如果列 A 的 scale 为 2,而列 B 的 scale 为1,则 A 的宽度将是 B 的两倍。
  • min_width: Column 的最小像素宽度,如果没有足够的屏幕空间,则将换行。如果某个 scale 值导致列比 min_width 窄,则首先考虑 min_widght 参数。
  • variant: 同 gradio.Row()

例如,我们可以将所有的对话组件放在一行中。将所有参数配置放在一列, 并将 chatBot 和参数配置以 4:1 的比例进行布置。

with gr.Row():
    # 创建提交按钮。
    db_with_his_btn = gr.Button("Chat db with history")
    db_wo_his_btn = gr.Button("Chat db without history")
    llm_btn = gr.Button("Chat with llm")
with gr.Column(scale=4):
    chatbot = gr.Chatbot(height=480) 
    ...
with gr.Column(scale=1):
    ...
    model_argument = gr.Accordion("参数配置", open=False)
    with model_argument:
        ...
    model_select = gr.Accordion("模型选择")
    with model_select:
        ...

当项目部署时,可能同一时间有多个用户进行访问,这时我们可以将 demo.queue(concurrency_count=3) 进行配置,表示用三个线程来并行。

现在是时候将我们的界面分享给别人了
下面是 demo.launch() 的几种场景分享配置

  1. 如果你的运行环境是在容器中运行,需要指定与当初创建容器时的端口一致,才能将端口映射出来 假设容器端口是8080,
  • demo.launch(server_name=“0.0.0.0”, server_port=8080)
  1. 如果是外部环境,非容器内部,则任意端口均可。
  • demo.launch(server_name=“0.0.0.0”, server_port=“任意端口”)
  1. 若想分享给局域网之外的其他人,则设置 share=True,可免费分享3天;
  • demo.launch(share=True)

现在我们已经实现了 《llm 通过本地数据库进行回答》的基本功能和界面。快去进行自己的尝试吧。

你可能感兴趣的:(大模型,人工智能,交互)