Gradio 教程四:Building Generative AI Applications with Gradio

文章目录

    • 一、使用interface构建NLP应用
      • 1.1 构建文本摘要应用
        • 1.1.1 设置API密钥
        • 1.1.2 调用文本摘要API
        • 1.1.3 运行本地模型获取响应
        • 1.1.4 使用interface构建应用
      • 1.2 构建命名实体识别应用
        • 1.2.1 调用NER任务API
        • 1.2.2 使用interface构建应用
        • 1.2.3 加入额外函数,合并tokens
    • 二、构建图像标注应用
      • 2.1 设置API密钥,定义图像标注函数
      • 2.2 使用Interface构建应用
    • 三、构建文生图应用
      • 3.1 设置API密钥,定义文生图函数
      • 3.2 使用Interface构建文生图应用
      • 3.3 为文生图函数添加更多的控制参数
      • 3.4 使用Blocks构建更复杂的用户界面
    • 四、创建图像接龙游戏
      • 4.1 设置API密钥,定义主函数和辅助函数
      • 4.2 使用Blocks构建应用
    • 五、构建LLM聊天机器人
      • 5.1 设置API密钥
      • 5.2 构建LLM聊天机器人
      • 5.3 格式化聊天记录
      • 5.4 构建流式输出机器人

传送门:

  • 《Gradio官方教程一:Gradio生态系统、主要组件及Interface class简介》
  • 《Gradio 4.37.1官方教程二:Blocks》
  • 《Gradio 4.37.1官方教程三:Chatbot》
  • 《Gradio 教程四:Building Generative AI Applications with Gradio》

deeplearning.ai课程主页、gradio官方教程

一、使用interface构建NLP应用

  本章将使用gr.interface构建文本摘要和命名实体识别两个NLP任务的应用程序。

1.1 构建文本摘要应用

1.1.1 设置API密钥

  本课程将通过API调用Hugging Face上运行的模型获取响应,所以需要先设置API密钥用于请求响应时的授权。

  Hugging Face的"API keys" 称为“用户访问令牌”(User Access Tokens)。首先,访问 Access Tokens 页面创建自己的用户访问令牌。接下来,为了在本地机器上安全地保存访问令牌,可以将将访问令牌保存到环境变量中。

  • 在项目的根目录中创建一个 .env 文件
  • 打开 .env 文件,添加以下内容:HF_API_KEY="your API keys"后保存
  • 为了能够在Jupyter Notebook中加载和使用这个 .env 文件,需要安装 python-dotenv
  • 在代码中,可以使用 python-dotenv 库加载环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']

有关如何获取自己的访问令牌的更多信息,请访问User access tokens。

1.1.2 调用文本摘要API
import os
import io
from IPython.display import Image, display, HTML
from PIL import Image
import base64
import requests, json#Summarization endpoint
def get_completion(inputs, parameters=None,ENDPOINT_URL=os.environ['HF_API_SUMMARY_BASE']): headers = {"Authorization": f"Bearer {hf_api_key}","Content-Type": "application/json"}data = { "inputs": inputs }if parameters is not None:data.update({"parameters": parameters})response = requests.request("POST",ENDPOINT_URL, headers=headers,data=json.dumps(data))return json.loads(response.content.decode("utf-8"))

  此函数将的作用是通过HTTP请求将输入文本发送到Hugging Face 上的API端点(ENDPOINT_URL),服务器端的摘要模型处理文本并返回摘要结果。下面是详细解析:

  • 函数定义:
    • inputs: 要进行摘要的文本。
    • parameters: 可选参数,用于调整摘要生成的细节。
    • ENDPOINT_URL: API的URL地址,通过环境变量 HF_API_SUMMARY_BASE 获取。Hugging Face 上进行文本摘要任务时,默认使用DistillBartCNN模型。该模型是通过蒸馏FaceBook训练的的BartLargeCNN得到的,是专门为文本摘要设计的前沿模型。
  • 请求头和请求数据
    • headers 包含两个部分: Authorization: 使用 hf_api_key进行授权;Content-Type: 指定请求内容的类型为JSON格式。
    • data 是发送给API的请求数据,包含输入文本 inputs。如果有额外的参数 parameters,也会包含在 data
  • 发送请求:
    • 使用 requests 库发送一个POST请求到 ENDPOINT_URL
    • 请求头 headers 和请求数据 data 作为参数传递。后者 使用 json.dumps 函数转换为JSON格式。
  • 处理响应
    • response.content 包含API返回的响应内容。
    • decode("utf-8") 将响应内容解码为字符串。
    • json.loads 将字符串转换为Python字典格式并返回。

  在deeplearning.ai课程中,左侧有完整的jupyter代码,其中的环境变量中已经写入了HF_API_SUMMARY_BASE。在本地跑的时候,直接将ENDPOINT_URL的值设为DistillBartCNN模型的网站就行。

1.1.3 运行本地模型获取响应

你也可以在本地运行摘要模型来获取摘要结果:

from transformers import pipelineget_completion = pipeline("summarization", model="shleifer/distilbart-cnn-12-6")def summarize(input):output = get_completion(input)return output[0]['summary_text']
text = ('''The tower is 324 metres (1,063 ft) tall, about the same heightas an 81-storey building, and the tallest structure in Paris. Its base is square, measuring 125 metres (410 ft) on each side. During its construction, the Eiffel Tower surpassed the Washington Monument to become the tallest man-made structure in the world,a title it held for 41 years until the Chrysler Buildingin New York City was finished in 1930. It was the first structure to reach a height of 300 metres. Due to the addition of a broadcasting aerial at the top of the tower in 1957, it is now taller than the Chrysler Building by 5.2 metres (17 ft). Excluding transmitters, the Eiffel Tower is the second tallest free-standing structure in France after the Millau Viaduct.''')get_completion(text)
1.1.4 使用interface构建应用
import gradio as gr
def summarize(input):output = get_completion(input)return output[0]['summary_text']gr.close_all()
demo = gr.Interface(fn=summarize, inputs="text", outputs="text")
demo.launch()
#demo.launch(share=True, server_port=int(os.environ['PORT1']))

在这里插入图片描述

  接下来,你可以输入任何文本到输入框,点击提交按钮,输出框就会出现总结性文本了。
上述代码中,"text"表示默认格式的文本框组件,即gr.Textbox()。你可以设置其参数,来进行组件的自定义,比如使用title 设置界面的标题,使用description 设置界面的描述,在gr.Textbox组件中设置文本框标签和显示的行数。

import gradio as grdef summarize(input):output = get_completion(input)return output[0]['summary_text']gr.close_all()
demo = gr.Interface(fn=summarize, inputs=[gr.Textbox(label="Text to summarize", lines=6)],outputs=[gr.Textbox(label="Result", lines=3)],title="Text summarization with distilbart-cnn",description="Summarize any text using the `shleifer/distilbart-cnn-12-6` model under the hood!")
demo.launch(share=True, server_port=int(os.environ['PORT2']))

在这里插入图片描述

server_port=int(os.environ['PORT2'])表示使用 PORT2 环境变量指定的端口号来启动服务器。

1.2 构建命名实体识别应用

1.2.1 调用NER任务API
PI_URL = os.environ['HF_API_NER_BASE'] #NER endpoint
text = "My name is Andrew, I'm building DeepLearningAI and I live in California"
get_completion(text, parameters=None, ENDPOINT_URL= API_URL)
[{'entity': 'B-PER','score': 0.9990625,'index': 4,'word': 'Andrew','start': 11,'end': 17},{'entity': 'B-ORG','score': 0.9927856,'index': 10,'word': 'Deep','start': 32,'end': 36},{'entity': 'I-ORG','score': 0.99677867,'index': 11,'word': '##L','start': 36,'end': 37},{'entity': 'I-ORG','score': 0.9954496,'index': 12,'word': '##ear','start': 37,'end': 40},{'entity': 'I-ORG','score': 0.9959293,'index': 13,'word': '##ning','start': 40,'end': 44},{'entity': 'I-ORG','score': 0.8917463,'index': 14,'word': '##A','start': 44,'end': 45},{'entity': 'I-ORG','score': 0.5036118,'index': 15,'word': '##I','start': 45,'end': 46},{'entity': 'B-LOC','score': 0.99969244,'index': 20,'word': 'California','start': 61,'end': 71}]

  我们切换了新的API端点PI_URL来完成NER任务,这会调用dslim/bert-base-NER模型来获取响应。你也可以在本地运行模型来获取结果:

from transformers import pipelineget_completion = pipeline("ner", model="dslim/bert-base-NER")def ner(input):output = get_completion(input)return {"text": input, "entities": output}
1.2.2 使用interface构建应用

  上一步我们通过我们通过get_completion函数获取了完整的NER结果,但是这个显示方式不太友好。我们使用Gradio将其进行演示,可读性会强很多。

  在下面的代码中,我们使用了gr.HighlightedText组件,它会根据 ner 函数返回的结果自动高亮显示 entities 部分。entities 列表应该包含每个实体的详细信息,例如实体本身、起始位置、结束位置和标签。另外我们还使用examples参数,在界面下方添加示例,方便用户快速测试。

#gr.close_all()   # 关闭所有的Gradio演示
demo = gr.Interface(fn=ner,inputs=[gr.Textbox(label="Text to find entities", lines=2)],outputs=[gr.HighlightedText(label="Text with entities")],title="NER with dslim/bert-base-NER",description="Find entities using the `dslim/bert-base-NER` model under the hood!",allow_flagging="never",#Here we introduce a new tag, examples, easy to use examples for your applicationexamples=["My name is Andrew and I live in California", "My name is Poli and work at HuggingFace"])
demo.launch(share=True, server_port=int(os.environ['PORT3']))

在这里插入图片描述
  可以看到,一些实体单词被分割成多个tokens,实体标签以字母 B 开头,表示开始标记(beginning token),I 表示中间标记(intermediate token)。为了得到一个更友好的显示界面,可以构造一个合并函数将分割的tokens合并为一个完整的实体单词。

1.2.3 加入额外函数,合并tokens
def merge_tokens(tokens):merged_tokens = []												# 初始化一个空列表,用于存储合并后的标记for token in tokens:											# 遍历输入的所有标记if merged_tokens and token['entity'].startswith('I-') and merged_tokens[-1]['entity'].endswith(token['entity'][2:]):  # 判断是否合并# If current token continues the entity of the last one, merge themlast_token = merged_tokens[-1]last_token['word'] += token['word'].replace('##', '')  # 去掉当前token的前缀# ,添加到上一个token后面last_token['end'] = token['end']					   # 更新合并后标记的结束位置last_token['score'] = (last_token['score'] + token['score']) / 2else:# 如果当前标记不能与上一个合并后的标记合并,将其直接添加到 merged_tokens 列表中merged_tokens.append(token)  						  return merged_tokensdef ner(input):output = get_completion(input, parameters=None, ENDPOINT_URL=API_URL)merged_tokens = merge_tokens(output)return {"text": input, "entities": merged_tokens}gr.close_all()
demo = gr.Interface(fn=ner,inputs=[gr.Textbox(label="Text to find entities", lines=2)],outputs=[gr.HighlightedText(label="Text with entities")],title="NER with dslim/bert-base-NER",description="Find entities using the `dslim/bert-base-NER` model under the hood!",allow_flagging="never",examples=["My name is Andrew, I'm building DeeplearningAI and I live in California", "My name is Poli, I live in Vienna and work at HuggingFace"])demo.launch(share=True, server_port=int(os.environ['PORT4']))

在这里插入图片描述

二、构建图像标注应用

2.1 设置API密钥,定义图像标注函数

import os
import io
import IPython.display
from PIL import Image
import base64 
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
import requests, json#Image-to-text endpoint
def get_completion(inputs, parameters=None, ENDPOINT_URL=os.environ['HF_API_ITT_BASE']):headers = {"Authorization": f"Bearer {hf_api_key}","Content-Type": "application/json"}data = { "inputs": inputs }if parameters is not None:data.update({"parameters": parameters})response = requests.request("POST",ENDPOINT_URL,headers=headers,data=json.dumps(data))return json.loads(response.content.decode("utf-8"))

  此处的ENDPOINT_URL会调用Salesforce/blip-image-captioning-base模型,当输入一张图片后,会返回这张图片对应的文本描述。 https://free-images.com上有很多免费的图片,比如输入以下图片,模型生成的描述是“戴着圣诞帽和围巾的狗”。

image_url = "https://free-images.com/sm/9596/dog_animal_greyhound_983023.jpg"
display(IPython.display.Image(url=image_url))
get_completion(image_url)

2.2 使用Interface构建应用

import gradio as gr def image_to_base64_str(pil_image):byte_arr = io.BytesIO()pil_image.save(byte_arr, format='PNG')byte_arr = byte_arr.getvalue()return str(base64.b64encode(byte_arr).decode('utf-8'))def captioner(image):base64_image = image_to_base64_str(image)result = get_completion(base64_image)return result[0]['generated_text']gr.close_all()
demo = gr.Interface(fn=captioner,inputs=[gr.Image(label="Upload image", type="pil")],outputs=[gr.Textbox(label="Caption")],title="Image Captioning with BLIP",description="Caption any image using the BLIP model",allow_flagging="never",examples=["christmas_dog.jpeg", "bird_flight.jpeg", "cow.jpeg"])demo.launch(share=True, server_port=int(os.environ['PORT1']))
  • imageToBase64函数:将图像转换为Base64格式,这是API所需的格式;
  • captioner函数:接收图像并生成标注结果。

在这里插入图片描述

三、构建文生图应用

3.1 设置API密钥,定义文生图函数

import os
import io
import IPython.display
from PIL import Image
import base64 
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
# Helper function
import requests, json#Text-to-image endpoint
def get_completion(inputs, parameters=None, ENDPOINT_URL=os.environ['HF_API_TTI_BASE']):headers = {"Authorization": f"Bearer {hf_api_key}","Content-Type": "application/json"}   data = { "inputs": inputs }if parameters is not None:data.update({"parameters": parameters})response = requests.request("POST",ENDPOINT_URL,headers=headers,data=json.dumps(data))return json.loads(response.content.decode("utf-8"))

上述代码会调用diffusers库的runwayml/stable-diffusion-v1-5模型,我们可以测试一下这个模型的效果:

prompt = "a dog in a park"result = get_completion(prompt)
IPython.display.HTML(f'<img src="data:image/png;base64,{result}" />')

3.2 使用Interface构建文生图应用

import gradio as gr #定义一个辅助函数,将PIL image转为API需要的base64格式
def base64_to_pil(img_base64):base64_decoded = base64.b64decode(img_base64)byte_stream = io.BytesIO(base64_decoded)pil_image = Image.open(byte_stream)return pil_imagedef generate(prompt):output = get_completion(prompt)result_image = base64_to_pil(output)return result_imagegr.close_all()
demo = gr.Interface(fn=generate,inputs=[gr.Textbox(label="Your prompt")],outputs=[gr.Image(label="Result")],title="Image Generation with Stable Diffusion",description="Generate any image with Stable Diffusion",allow_flagging="never",examples=["the spirit of a tamagotchi wandering in the city of Vienna","a mecha robot in a favela"])demo.launch(share=True, server_port=int(os.environ['PORT1']))

在这里插入图片描述

3.3 为文生图函数添加更多的控制参数

  我们可以在generate函数中添加更多的控制参数,例如添加负面提示、采样步数、提示词的控制程度(值越高,生成的图片越符合提示词;越低,生成的图片越多样化)、图像宽度和高度等选项。

import gradio as gr #定义一个辅助函数,将PIL image转为API需要的base64格式
def base64_to_pil(img_base64):base64_decoded = base64.b64decode(img_base64)byte_stream = io.BytesIO(base64_decoded)pil_image = Image.open(byte_stream)return pil_imagedef generate(prompt, negative_prompt, steps, guidance, width, height):params = {"negative_prompt": negative_prompt,"num_inference_steps": steps,"guidance_scale": guidance,"width": width,"height": height}output = get_completion(prompt, params)pil_image = base64_to_pil(output)return pil_image

下面采用滑块组件gr.Slider,这样可以更方便地调整这些参数的数值。

gr.close_all()
demo = gr.Interface(fn=generate,inputs=[gr.Textbox(label="Your prompt"),gr.Textbox(label="Negative prompt"),gr.Slider(label="Inference Steps", minimum=1, maximum=100, value=25,info="In how many steps will the denoiser denoise the image?"),gr.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7, info="Controls how much the text prompt influences the result"),gr.Slider(label="Width", minimum=64, maximum=512, step=64, value=512),gr.Slider(label="Height", minimum=64, maximum=512, step=64, value=512),],outputs=[gr.Image(label="Result")],title="Image Generation with Stable Diffusion",description="Generate any image with Stable Diffusion",allow_flagging="never")demo.launch(share=True, server_port=int(os.environ['PORT2']))

  从gr.Interface的参数可以看到,inputs是一个输入组件的列表,每个组件和generate函数的参数一一对应。
在这里插入图片描述

3.4 使用Blocks构建更复杂的用户界面

  gr.Interface()在构建应用界面时则提供了简单的自动化配置,而Gradle Blocks有更大的灵活性,比如自定义界面的布局、自定义事件监听器、处理更复杂的数据流(比如顺序执行多个组件,一个组件的输出可以作为下一个组件的输入)等等,Automatic1111的stable diffusion Web UI就是用Gradio的Blocks构建的。

  在默认情况下,Block 中的组件是垂直排列的,我们可以使用with语句定义多个gr.Row()gr.Column()对组件进行重新排列。另外在使用gr.Interface()时, 'Clear''Submit'按钮会自动添加,无需手动定义;使用gr.Blocks()时,你需要显式地定义'Submit'按钮(gr.Button())。

with gr.Blocks() as demo:gr.Markdown("# Image Generation with Stable Diffusion")prompt = gr.Textbox(label="Your prompt")with gr.Row():with gr.Column():negative_prompt = gr.Textbox(label="Negative prompt")steps = gr.Slider(label="Inference Steps", minimum=1, maximum=100, value=25,info="In many steps will the denoiser denoise the image?")guidance = gr.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7,info="Controls how much the text prompt influences the result")width = gr.Slider(label="Width", minimum=64, maximum=512, step=64, value=512)height = gr.Slider(label="Height", minimum=64, maximum=512, step=64, value=512)btn = gr.Button("Submit")with gr.Column():output = gr.Image(label="Result")btn.click(fn=generate, inputs=[prompt,negative_prompt,steps,guidance,width,height], outputs=[output])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT3']))
  • with gr.Blocks() as demo:使用with语句创建了一个名为demo的Blocks应用程序,所有组件和事件都将在这个上下文中被定义。
  • with gr.Column():通过此语句,将界面分为了两列,每一列的内容都可以自定义。
  • btn.click():定义按钮点击事件。click()是事件监听器,定义了应用程序中的数据流。
    在上面的示例中,当按钮被点击时,数据流被触发——调用generate函数,左侧组件中的内容内容作为输入,函数返回的结果会显示在右侧output文本框中。与Interface类似,事件监听器可以接受多个输入或输出。

另外还有两个常用的控制参数:

  • scale:设置列的相对宽度。gr.Column()scale参数可以设置列的相对宽度(默认为1),比如有两列,scale值分别为41,那么第一列占4/5的宽度。
  • gr.Accordion():折叠面板,可以显示/隐藏应用程序的选项。通过设置open参数可以设置折叠组件的默认状态(open=True默认显示,open=False默认折叠)
with gr.Blocks() as demo:gr.Markdown("# Image Generation with Stable Diffusion")with gr.Row():with gr.Column(scale=4):prompt = gr.Textbox(label="Your prompt") #Give prompt some real estatewith gr.Column(scale=1, min_width=50):btn = gr.Button("Submit") #Submit button side by side!with gr.Accordion("Advanced options", open=False): #Let's hide the advanced options!negative_prompt = gr.Textbox(label="Negative prompt")with gr.Row():with gr.Column():steps = gr.Slider(label="Inference Steps", minimum=1, maximum=100, value=25,info="In many steps will the denoiser denoise the image?")guidance = gr.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7,info="Controls how much the text prompt influences the result")with gr.Column():width = gr.Slider(label="Width", minimum=64, maximum=512, step=64, value=512)height = gr.Slider(label="Height", minimum=64, maximum=512, step=64, value=512)output = gr.Image(label="Result") #Move the output up toobtn.click(fn=generate, inputs=[prompt,negative_prompt,steps,guidance,width,height], outputs=[output])gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT4']))

在这里插入图片描述

所有可选的滑块都被折叠隐藏,点击箭头就可以打开显示。

四、创建图像接龙游戏

  在前面的课程中,我们学到了如何使用Gradio来构建NLP应用、图像标注应用和文生成图应用,现在,将这些知识结合起来,创建一个有趣的图像接龙游戏——上传一张图像,生成其描述,再用这个描述生成一张新图像。

4.1 设置API密钥,定义主函数和辅助函数

import os
import io
from IPython.display import Image, display, HTML
from PIL import Image
import base64 from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
#### Helper function
import requests, json#Here we are going to call multiple endpoints!
def get_completion(inputs, parameters=None, ENDPOINT_URL=""):headers = {"Authorization": f"Bearer {hf_api_key}","Content-Type": "application/json"}   data = { "inputs": inputs }if parameters is not None:data.update({"parameters": parameters})response = requests.request("POST",ENDPOINT_URL,headers=headers,data=json.dumps(data))return json.loads(response.content.decode("utf-8"))
#Bringing the functions from lessons 3 and 4!
def image_to_base64_str(pil_image):byte_arr = io.BytesIO()pil_image.save(byte_arr, format='PNG')byte_arr = byte_arr.getvalue()return str(base64.b64encode(byte_arr).decode('utf-8'))def base64_to_pil(img_base64):base64_decoded = base64.b64decode(img_base64)byte_stream = io.BytesIO(base64_decoded)pil_image = Image.open(byte_stream)return pil_imagedef captioner(image):base64_image = image_to_base64_str(image)result = get_completion(base64_image, None, ITT_ENDPOINT)return result[0]['generated_text']def generate(prompt):output = get_completion(prompt, None, TTI_ENDPOINT)result_image = base64_to_pil(output)return result_image

4.2 使用Blocks构建应用

先进行图像标注,再进行文生图。

#text-to-image
TTI_ENDPOINT = os.environ['HF_API_TTI_BASE']
#image-to-text
ITT_ENDPOINT = os.environ['HF_API_ITT_BASE']
import gradio as gr 
with gr.Blocks() as demo:gr.Markdown("# Describe-and-Generate game 🖍️")image_upload = gr.Image(label="Your first image",type="pil")btn_caption = gr.Button("Generate caption")caption = gr.Textbox(label="Generated caption")btn_caption.click(fn=captioner, inputs=[image_upload], outputs=[caption])gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT1']))
with gr.Blocks() as demo:gr.Markdown("# Describe-and-Generate game 🖍️")image_upload = gr.Image(label="Your first image",type="pil")btn_caption = gr.Button("Generate caption")caption = gr.Textbox(label="Generated caption")btn_image = gr.Button("Generate image")image_output = gr.Image(label="Generated Image")btn_caption.click(fn=captioner, inputs=[image_upload], outputs=[caption])btn_image.click(fn=generate, inputs=[caption], outputs=[image_output])gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT2']))

也可以一次性完成这个任务:

def caption_and_generate(image):caption = captioner(image)image = generate(caption)return [caption, image]with gr.Blocks() as demo:gr.Markdown("# Describe-and-Generate game 🖍️")image_upload = gr.Image(label="Your first image",type="pil")btn_all = gr.Button("Caption and generate")caption = gr.Textbox(label="Generated caption")image_output = gr.Image(label="Generated Image")btn_all.click(fn=caption_and_generate, inputs=[image_upload], outputs=[caption, image_output])gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT3']))

在这里插入图片描述

  你以进行多次循环,将生成的图像再次输入生成新的描述和图像,观察结果是否一致或主题是否保持。

  另外,这段代码使用一个按钮完成两个过程,点击按钮即可同时生成描述和图像。也可以考虑在一个界面中使用两个按钮分别生成描述和图像,这样用户可以在中间检查描述。

五、构建LLM聊天机器人

5.1 设置API密钥

import os
import io
import IPython.display
from PIL import Image
import base64 
import requests 
requests.adapters.DEFAULT_TIMEOUT = 60from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
# Helper function
import requests, json
from text_generation import Client#FalcomLM-instruct endpoint on the text_generation library
client = Client(os.environ['HF_API_FALCOM_BASE'], headers={"Authorization": f"Basic {hf_api_key}"}, timeout=120)
prompt = "Has math been invented or discovered?"
client.generate(prompt, max_new_tokens=256).generated_text
'\nMath has been both invented and discovered. It is a human invention in the sense that it is a system of rules and concepts that we have created to help us understand the world around us. However, it is also a discovery in the sense that it is a fundamental aspect of the universe that we have uncovered through our observations and experiments.'

这里使用了falcon-40b-instruct模型进行测试。

5.2 构建LLM聊天机器人

在第一章中,我们学习了使用Interface构建应用界面:

#Back to Lesson 2, time flies!
import gradio as gr
def generate(input, slider):output = client.generate(input, max_new_tokens=slider).generated_textreturn outputdemo = gr.Interface(fn=generate, inputs=[gr.Textbox(label="Prompt"), gr.Slider(label="Max new tokens", value=20,  maximum=1024, minimum=1)], outputs=[gr.Textbox(label="Completion")])gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT1']))

在这里插入图片描述
gr.Chatbot()允许您保存用户与LLM之间的聊天记录,并在应用程序中显示对话。

  • 定义一个函数,该函数接受一个gr.Chatbot()对象作为输入。

  • 在这个函数中,将用户消息和LLM的响应作为一个元组(或列表)附加到gr.Chatbot()对象中。例如,使用chatbot_object.append((user_message, llm_message))

  • gr.Chatbot()对象包括在应用程序的输入和输出中,也就是更新对话框

import randomdef respond(message, chat_history):#No LLM here, just respond with a random pre-made messagebot_message = random.choice(["Tell me more about it", "Cool, but I'm not interested", "Hmmmm, ok then"]) chat_history.append((message, bot_message))return "", chat_historywith gr.Blocks() as demo:chatbot = gr.Chatbot(height=240) #just to fit the notebookmsg = gr.Textbox(label="Prompt")btn = gr.Button("Submit")clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")btn.click(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])msg.submit(respond, inputs=[msg, chatbot], outputs=[msg, chatbot]) #Press enter to submitgr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT2']))

在这里插入图片描述

5.3 格式化聊天记录

遍历gr.Chatbot()对象中的聊天记录,并将每一条记录格式化输出:

  • 迭代遍历: 使用for循环遍历chatbot对象(即聊天记录)。
  • 拆解元组: 每一条记录是一个包含用户消息和LLM响应的元组,您可以通过元组解包来分别获取用户消息和LLM的响应,例如:
for turn in chat_history:user_msg, bot_msg = turn...

下面是具体的代码:

def format_chat_prompt(message, chat_history):prompt = ""for turn in chat_history:						# 遍历聊天记录user_message, bot_message = turn			# 提取用户信息和机器人回复# 将每条记录格式化为字符串 "User: {user_message}\nAssistant: {bot_message}",并附加到 prompt 中prompt = f"{prompt}\nUser: {user_message}\nAssistant: {bot_message}"# 在循环结束后,将当前用户输入的消息 message 添加到 prompt 中,并以 Assistant: 结尾,为生成新的助手回复提供上下文。prompt = f"{prompt}\nUser: {message}\nAssistant:"return promptdef respond(message, chat_history):formatted_prompt = format_chat_prompt(message, chat_history)bot_message = client.generate(formatted_prompt,max_new_tokens=1024,stop_sequences=["\nUser:", "<|endoftext|>"]).generated_textchat_history.append((message, bot_message))return "", chat_historywith gr.Blocks() as demo:chatbot = gr.Chatbot(height=240) #just to fit the notebookmsg = gr.Textbox(label="Prompt")btn = gr.Button("Submit")clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")btn.click(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])msg.submit(respond, inputs=[msg, chatbot], outputs=[msg, chatbot]) #Press enter to submitgr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT3']))

  format_chat_prompt 函数将当前对话上下文整理为一个格式化的文本块,这个文本块可以作为提示输入到LLM中,以生成上下文相关的回复。通过包含之前的聊天记录,确保LLM能够理解整个对话的背景,从而生成更相关和连贯的回复。

5.4 构建流式输出机器人

def format_chat_prompt(message, chat_history, instruction):prompt = f"System:{instruction}"for turn in chat_history:user_message, bot_message = turnprompt = f"{prompt}\nUser: {user_message}\nAssistant: {bot_message}"prompt = f"{prompt}\nUser: {message}\nAssistant:"return prompt
def respond(message, chat_history, instruction, temperature=0.7):prompt = format_chat_prompt(message, chat_history, instruction)chat_history = chat_history + [[message, ""]]stream = client.generate_stream(prompt,max_new_tokens=1024,stop_sequences=["\nUser:", "<|endoftext|>"],temperature=temperature)#stop_sequences to not generate the user answeracc_text = ""#Streaming the tokensfor idx, response in enumerate(stream):text_token = response.token.textif response.details:returnif idx == 0 and text_token.startswith(" "):text_token = text_token[1:]acc_text += text_tokenlast_turn = list(chat_history.pop(-1))last_turn[-1] += acc_textchat_history = chat_history + [last_turn]yield "", chat_historyacc_text = ""
with gr.Blocks() as demo:chatbot = gr.Chatbot(height=24![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0cee694ef37146dda0e2856df00bb0a6.png)
0) #just to fit the notebookmsg = gr.Textbox(label="Prompt")with gr.Accordion(label="Advanced options",open=False):system = gr.Textbox(label="System message", lines=2, value="A conversation between a user and an LLM-based AI assistant. The assistant gives helpful and honest answers.")temperature = gr.Slider(label="temperature", minimum=0.1, maximum=1, value=0.7, step=0.1)btn = gr.Button("Submit")clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")btn.click(respond, inputs=[msg, chatbot, system], outputs=[msg, chatbot])msg.submit(respond, inputs=[msg, chatbot, system], outputs=[msg, chatbot]) #Press enter to submitgr.close_all()
demo.queue().launch(share=True, server_port=int(os.environ['PORT4']))    

在这里插入图片描述

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

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

相关文章

CPU/内存/综合性能评估工具汇总-3:unixbench

目录 一、概括二、UnixBench 一、概括 嵌入式开发中对要设计的产品、立项的项目进行设计时&#xff0c;往往需要对关键芯片进行性能评估&#xff0c;本文主要总结基于linux系统的产品在性能评估时的工具使用总结&#xff0c;在aarch64(arm64平台下测试)&#xff0c;板卡根文件…

Rhino 犀牛三维建模工具下载安装,Rhino 适用于机械设计广泛领域

Rhinoceros&#xff0c;这款软件小巧而强大&#xff0c;无论是机械设计、科学工业还是三维动画等多元化领域&#xff0c;它都能展现出其惊人的建模能力。 Rhinoceros所包含的NURBS建模功能&#xff0c;堪称业界翘楚。NURBS&#xff0c;即非均匀有理B样条&#xff0c;是计算机图…

【笔记】记录一次全新的Java项目部署过程

记录一次全新的Java项目部署过程 环境&#xff1a;CentOS7 一、初始环境准备 yum install wget -y yum install vim -y yum install net-tools -y mkdir /data mkdir /data/html mkdir /data/backend一、安装JDK 17 安装JDK17 # 下载rpm wget https://download.oracle.com…

数据驱动:Facebook的广告策略与商业模式

在现代数字经济中&#xff0c;数据已经成为新的石油&#xff0c;驱动着企业的增长和创新。Facebook&#xff0c;作为全球最大的社交媒体平台之一&#xff0c;充分利用其庞大的用户数据和先进的算法技术&#xff0c;建立了一个高度精确和高效的广告生态系统。这不仅推动了平台自…

带着味蕾去旅行,在“必吃”餐厅里认识一座城

时代不同了&#xff0c;旅游也变了。十多年前的旅游&#xff0c;是文艺青年的诗与远方&#xff0c;生活在别处的荷尔蒙之旅&#xff0c;宁浩拍了部电影叫《心花怒放》&#xff0c;那些年不管是大理、丽江、拉萨、成都&#xff0c;还是张家界&#xff0c;商家最喜欢用的宣传口号…

Oracle Database 23ai新特性:DB_DEVELOPER_ROLE角色

角色介绍 从 Oracle Database 23ai 开始&#xff0c;新角色“DB_DEVELOPER_ROLE”允许管理员快速分配开发人员为 Oracle 数据库设计、构建和部署应用程序所需的所有必要权限。&#xff08;包括构建数据模型所需的系统权限以及监视和调试应用程序所需的对象权限&#xff09;。通…

NSSCTF-Web题目23(RCE-空格绕过)

目录 [SWPUCTF 2022 新生赛]webdog1__start 1、题目 2、知识点 3、思路 [FSCTF 2023]webshell是啥捏 4、题目 5、知识点 6、思路 [SWPUCTF 2022 新生赛]webdog1__start 1、题目 2、知识点 RCE、空格绕过&#xff0c;嵌套eval 3、思路 出现这个页面&#xff0c;没有其…

【SSL 1056】最大子矩阵 (多维DP)

题目大意 已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵&#xff0c;你的任务是找到最大的非空&#xff08;大小至少是 1 ∗ 1 1*1 1∗1&#xff09;子矩阵。 比如&#xff0c;如下 4 ∗ 4 4*4 4∗4 子矩阵 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 的最大子矩阵是 …

组件丰富、支持2/3D数据可视化的编辑器平台软件?

数据可视化编辑器通常用于创建交互式的图表和模型&#xff0c;可以帮助用户以更直观的方式展示数据。一些在线平台软件提供了丰富的组件&#xff0c;支持2D和3D数据可视化&#xff1a; 1、Plotly - 提供了多种语言的库&#xff0c;支持在线创建交互式图表&#xff0c;包括2D和…

mac|Mysql WorkBench导入文件失败(修改编码)

⚠️&#xff1a;表格中有中文的不适用表格中有中文的不适用表格中有中文的不适用表格中有中文的不适用 我有一个excel表&#xff0c;想导入到mysql数据库中&#xff0c;但是Workbench的导入格式只支持csv&#xff0c;通过excel、wps将excel另存为csv文件进行导入 导入会因为编…

【软件测试】之自动化测试

&#x1f3c0;&#x1f3c0;&#x1f3c0;来都来了&#xff0c;不妨点个关注&#xff01; &#x1f3a7;&#x1f3a7;&#x1f3a7;博客主页&#xff1a;欢迎各位大佬! 文章目录 什么是自动化测试Selenium介绍什么是SeleniumSelenium的特点工作原理 SeleniumJava环境搭建下载…

第1章 信息系统综合知识

第1章 信息系统综合知识 本章主要介绍信息系统综合知识&#xff0c;介绍信息、信息系统的基本概念&#xff0c;概述两化融合和国家信息化战略&#xff0c;讲解电子政务、电子商务的典型应用&#xff0c;描述信息化整体总体规划以及IT战略的主要内容。 1.1 信息的定义和属性 …

【TB作品】矩阵键盘电话拨号,ATMEGA16单片机,Proteus仿真 atmega16矩阵键盘电话拨号

atmega16矩阵键盘电话拨号 c代码和仿真图&#xff1a; 使用ATmega16实现矩阵键盘电话拨号功能 项目背景 在电子设计和嵌入式系统开发中&#xff0c;矩阵键盘是常见的人机交互方式。它可以实现较多按键的输入&#xff0c;同时节省单片机的I/O资源。结合LCD显示和蜂鸣器&am…

Flume集群部署(手把手部署图文详细版)

前景概要&#xff1a; Kafka消息订阅系统在大数据业务中有着重要运用&#xff0c;尤其在实时业务中&#xff0c;kafka是必不可少的组件之一。 Flume是大数据组件中重要的数据采集工具&#xff0c;我们常利用Flume采集各种数据源的数据供其他组件分析使用。例如在实时业务中&…

Java房屋租赁管理系统附论文

作者介绍&#xff1a;计算机专业研究生&#xff0c;现企业打工人&#xff0c;从事Java全栈开发 主要内容&#xff1a;技术学习笔记、Java实战项目、项目问题解决记录、AI、简历模板、简历指导、技术交流、论文交流&#xff08;SCI论文两篇&#xff09; 上点关注下点赞 生活越过…

以智能化为舵手,引领现代计算机系统架构新航向

编者按&#xff1a;如今计算机系统承载的服务和算法逻辑日益复杂&#xff0c;理解、设计并改进计算机系统已成为核心挑战。面对系统复杂度和规模的指数级增长&#xff0c;以及新的大模型驱动场景下的分布式系统形态的涌现&#xff0c;人们亟需创新方法与技术来应对。在计算机系…

光明领鲜物流荣膺“2023中国冷链物流百强企业”荣誉称号

近日&#xff0c;以“全球链接跨界融合”为主题的2024第十六届全球食品冷链大会举行&#xff0c;光明乳业旗下光明领鲜物流受邀参加。 作为光明乳业全产业链中重要组成部分&#xff0c;光明领鲜物流始终保持高标准严要求&#xff0c;专注于冷链质量和服务持续完善&#xff0c;并…

Python基础语法(与C++对比)(持续更新ing)

代码块 Python在统一缩进体系内&#xff0c;为同一代码块C{...}内部的为同一代码块 注释 Python 单行注释&#xff1a;#... 多行注释&#xff1a;... C 单行注释&#xff1a;//... 多行注释: /*...*/ 数据类型 1. Python数据类型 Python中支持数字之间使用下划线 _ 分割…

DB2数据库日常维护

一、DB2系统结构 创建实例 db2icrt 实例名 删除实例 db2idrop 实例名 查询实例 db2ilist 实例名 启动实例 db2start 停止实例 db2stop 创建数据库 create database 库名 [on 存储路径] [using codeset 字符集] [TERRITORY 区域码] [pagesize 页大小] 删除数据库 drop database…

秋招力扣刷题——从前序与中序遍历序列构造二叉树

一、题目要求 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 二、解法思路 根据二叉树的遍历结构重构二叉树&#xff0c;至少两种遍历方式结合&…