DLAI-Gradio-笔记-全-

DLAI Gradio 笔记(全)

001:课程介绍与Gradio概述 🚀

在本节课中,我们将学习这门课程的整体目标,并了解Gradio这一工具如何帮助我们快速为生成式AI模型构建演示界面。

欢迎来到这门与Hugging Face合作开设的“使用Gradio构建生成式人工智能应用程序”课程。我来介绍本课程的讲师——一位名为“Polly”的鹦鹉。

感谢Andrew。很高兴来到这里。Gradio是一种快速便捷的方式,可以直接在Python中通过友好的Web界面来演示你的机器学习模型。在本课程中,我们将学习如何使用它为生成式AI应用程序构建用户界面。

当你构建完一个应用程序的机器学习或生成式AI部分后,你可能想快速构建一个演示程序展示给他人。也许是为了获取反馈并推动系统改进,或者仅仅是因为你觉得这个系统很酷,想要展示它。Gradio让你可以通过Python接口快速做到这一点,而无需编写任何前端、Web或JavaScript代码。

在本课程中,你将看到包括文本摘要、命名实体识别、图像描述、使用扩散模型的图像生成以及基于LLM的聊天机器人在内的多个示例。对于每一个应用,Polly都将展示,在你构建好其机器学习部分后,如何利用Gradio快速构建一个非常酷的演示,并让他人能够交互和体验你所构建的内容。

第一课我们将为简单的NLP任务构建一个应用程序,包括摘要和命名实体识别。

我们感谢许多人为这门短期课程付出的辛勤努力。来自Hugging Face团队的Omar Sanseviero、Pedro Cuenca、Philipp Schmid、Amy Roberts、Sylvain Gugger、Patrick von Platen和Suraj Patil,以及来自DeepLearning.AI的Eddy Shyu和Dina Boon。

接下来,让我们进入下一个视频,正式开始学习。


本节课中我们一起学习了本课程的目标和Gradio的基本概念。Gradio是一个强大的Python库,其核心价值在于允许开发者通过简单的代码快速为机器学习模型创建可交互的Web演示界面,而无需掌握前端开发技能。在接下来的课程中,我们将动手实践,利用Gradio为各种生成式AI应用构建用户界面。

002:构建两个NLP应用

在本节课中,我们将学习如何使用Gradio快速构建两个自然语言处理应用:一个用于文本摘要,另一个用于命名实体识别。我们将使用专门为这些任务设计的模型,并通过Gradio为它们创建用户友好的界面。

设置与概述

首先,我们需要设置API密钥,并定义一个辅助函数来调用文本摘要的API端点。这个API本质上调用了一个函数,如果你在本地运行,代码会类似这样。

我们首先从Hugging Face的transformers库中导入pipeline函数。对于文本摘要任务,我们选择distilbart-cnn-12-6模型,因为它是目前最先进的文本摘要模型之一。事实上,如果你使用transformers的pipeline函数进行文本摘要而不明确指定模型,它默认就会使用这个模型。

由于这个模型是专门为摘要任务构建的,任何输入到模型中的文本,它都会输出一个摘要。考虑到应用的速度和成本,与通用的大型语言模型相比,专用模型通常运行成本更低,并且能为用户提供更快的响应。

另一种提高效率和降低成本的方法是创建模型的“蒸馏”版本,它在保持相似性能的同时体积更小。我们使用的distilbart-cnn-12-6模型就是基于Facebook更大的bart-large-cnn模型蒸馏而来的。

在本课程中,我们通过API调用来运行这些模型。如果你在自己的机器上本地运行模型,你会使用类似下面的代码:

from transformers import pipeline

summarizer = pipeline("summarization", model="distilbart-cnn-12-6")

构建文本摘要应用

现在,让我们开始构建第一个应用。我们将首先导入Gradio库。

import gradio as gr

接下来,我们将定义一个名为summarize的函数。它接收一个输入字符串,调用我们之前定义的get_completion函数,并返回摘要。

def summarize(input_text):
    summary = get_completion(input_text, endpoint=summarization_endpoint)
    return summary

然后,我们使用Gradio的Interface函数来创建界面。传入我们刚刚定义的summarize函数,将输入和输出都设置为文本类型,最后调用launch来启动用户界面。

demo = gr.Interface(fn=summarize, inputs="text", outputs="text")
demo.launch()

让我们看看效果。界面创建成功后,我们可以复制一段关于埃菲尔铁塔的文本并粘贴进去,模型会生成一个摘要。

自定义用户界面

目前的界面只显示“输入”和“输出”标签,我们可以通过使用gr.Textbox组件来自定义这些标签。

demo = gr.Interface(
    fn=summarize,
    inputs=gr.Textbox(label="待摘要文本"),
    outputs=gr.Textbox(label="摘要结果")
)
demo.launch()

为了让用户知道可以输入多行文本,我们可以调整文本框的高度。使用lines参数可以实现这一点。

inputs=gr.Textbox(label="待摘要文本", lines=6),
outputs=gr.Textbox(label="摘要结果", lines=3)

我们还可以为应用添加标题和描述。

demo = gr.Interface(
    fn=summarize,
    inputs=gr.Textbox(label="待摘要文本", lines=6),
    outputs=gr.Textbox(label="摘要结果", lines=3),
    title="使用DistilBART-CNN进行文本摘要",
    description="输入一段长文本,模型将自动生成摘要。"
)
demo.launch()

如果你想与朋友在线分享这个应用,可以在launch方法中设置share=True来生成一个公共链接。

demo.launch(share=True)

构建命名实体识别应用

上一节我们构建了文本摘要应用,本节中我们来看看如何构建第二个应用:命名实体识别。这个模型将接收一段文本,并将特定的单词标记为人物、机构或地点等实体。

我们将使用一个基于BERT的命名实体识别模型。BERT是一个通用语言模型,可以执行多种NLP任务,但我们使用的这个版本经过了专门微调,在命名实体识别任务上具有最先进的性能。它能识别四种类型的实体:位置、组织、人物和其他。

以下是调用该模型API的示例:

ner_text = “Andrew is building a course for the Andrew Ng deep learning community.”
entities = get_completion(ner_text, endpoint=ner_endpoint)

模型的原始输出是一个字典列表,每个字典包含一个实体的信息。虽然这对下游软件应用有用,但对人类用户来说不够友好。我们可以使用Gradio让输出更直观。

创建NER应用界面

首先,我们定义一个函数供Gradio应用调用。这个函数将调用模型并返回原始文本以及模型识别出的实体列表。

def ner(input_text):
    entities = get_completion(input_text, endpoint=ner_endpoint)
    return input_text, entities

接下来,我们构建Gradio界面。这次,输出将使用gr.HighlightedText组件,它可以高亮显示文本中的实体。

demo = gr.Interface(
    fn=ner,
    inputs=gr.Textbox(label="输入文本", lines=3),
    outputs=gr.HighlightedText(label="识别出的实体"),
    title="命名实体识别",
    description="输入文本,模型将识别其中的人物、地点、组织等实体。",
    allow_flagging="never",
    examples=[
        ["Polly works for Hugging Face in Vienna."],
        ["My name is Andrew and I live in California."]
    ]
)
demo.launch()

在界面中,我们添加了examples参数,为用户提供示例输入,帮助他们快速了解应用功能。同时,我们通过allow_flagging=“never”隐藏了默认的“标记”按钮。

处理与合并分词

运行应用后,你可能会发现模型将一些单词(如“Hugging Face”)拆分成了多个“分词”。分词是语言中常见的短字符序列,长单词通常由多个分词组成,这样做是为了提高模型效率。

模型输出的实体标签以“B-”表示开始分词,“I-”表示中间分词。对于面向用户的应用,我们可能希望将属于同一实体的分词合并显示为一个完整的单词。

以下是合并分词的函数示例:

def merge_tokens(tokens):
    merged = []
    for token in tokens:
        if token[‘entity’].startswith(‘I-’) and merged:
            # 合并到前一个token
            merged[-1][‘word’] += token[‘word’].replace(‘##’, ‘’)
            # 可选:平均分数
            merged[-1][‘score’] = (merged[-1][‘score’] + token[‘score’]) / 2
        else:
            # 添加新token,并清理‘##’字符
            new_token = {‘word’: token[‘word’].replace(‘##’, ‘’), ‘entity’: token[‘entity’], ‘score’: token[‘score’]}
            merged.append(new_token)
    return merged

将这个函数集成到ner函数中,可以使输出对用户更加友好。

总结与清理

本节课中,我们一起学习了如何使用Gradio构建两个自然语言处理应用。我们首先构建了一个文本摘要应用,并学习了如何自定义其界面。接着,我们构建了一个命名实体识别应用,并解决了分词合并的问题,以提升用户体验。

在构建了多个应用后,你可能需要关闭所有打开的Gradio端口以释放资源。可以使用以下代码:

gr.close_all()

在下一节课中,我们将超越文本输入,构建一个图像描述应用,它可以接收一张图片并输出描述该图片的文字。

003:构建图像描述应用 📸

在本节课中,我们将学习如何使用开源的图像到文本模型,构建一个图像描述(Image Captioning)应用。我们将设置API密钥,调用预训练模型,并通过Gradio创建一个直观的交互界面。

概述

上一节我们介绍了Gradio的基本用法。本节中,我们将利用Hugging Face上的Salesforce Blip模型,创建一个能够为上传的图片自动生成文字描述的应用。核心流程是:用户上传图片,应用调用模型API,返回对图片内容的描述文本。

设置API与辅助函数

首先,我们需要设置访问Hugging Face模型API所需的密钥。

import os
os.environ[‘HF_API_KEY’] = ‘your_huggingface_api_key_here’

接下来,我们定义一个辅助函数 get_completion 来调用图像描述模型的API端点。这个端点对应的是Salesforce Blip图像描述模型。

import requests

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-gradio/img/16a006e618fc43b1e8a2d38184a69788_4.png)

def get_completion(inputs, parameters=None, ENDPOINT_URL=‘https://api-inference.huggingface.co/models/Salesforce/blip-image-captioning-base’):
    headers = {
        “Authorization”: f”Bearer {os.environ[‘HF_API_KEY’]}”
    }
    data = {“inputs”: inputs}
    if parameters is not None:
        data.update({“parameters”: parameters})
    response = requests.post(ENDPOINT_URL, headers=headers, json=data)
    return response.json()

该模型接收一张图片作为输入,并输出对该图片的描述。它是在数百万张图片及其对应文字描述的数据集上训练而成的。训练目标是让模型学会在看到新图片时,能够预测出准确的描述。

测试模型函数

现在,让我们用一个示例图片URL来测试这个函数。

image_url = “https://example.com/dog_in_santa_hat.jpg”
result = get_completion(image_url)
print(result)

测试结果显示,模型为图片生成的描述是:“a dog wearing a Santa hat and scarf”。这表明模型工作正常。

构建Gradio应用界面

了解了模型的工作原理后,我们来看看如何用Gradio为它构建一个用户界面。首先导入Gradio库。

import gradio as gr

我们将创建两个主要函数:

  1. captioner 函数:接收图片,调用 get_completion 函数,并返回生成的描述文本。
  2. image_to_base64 辅助函数:将图片转换为Base64格式,这是API调用所需的格式。如果你在本地运行模型则不需要此步骤,但通过API调用时必须进行转换。

以下是应用的核心代码结构:

import base64
import requests
from PIL import Image
from io import BytesIO

def image_to_base64(image):
    buffered = BytesIO()
    image.save(buffered, format=“JPEG”)
    img_str = base64.b64encode(buffered.getvalue()).decode()
    return img_str

def captioner(image):
    # 将图片转换为Base64字符串
    image_b64 = image_to_base64(image)
    # 调用模型API
    result = get_completion(image_b64)
    # 返回描述文本
    return result[0][‘generated_text’]

与上一课的Gradio应用结构类似,我们定义输入、输出、标题、描述和示例。

# 定义Gradio界面
demo = gr.Interface(
    fn=captioner,
    inputs=gr.Image(type=“pil”, label=“上传图片”),
    outputs=gr.Textbox(label=“图片描述”),
    title=“🖼️ 图像描述示例 (使用Blip模型)”,
    description=“上传一张图片,AI将尝试描述图片中的内容。”,
    examples=[
        [“example_images/dog_santa.jpg”],
        [“example_images/bird_flying.jpg”],
        [“example_images/cows_field.jpg”]
    ]
)

demo.launch()

这里,inputs 字段使用了新的 gr.Image 组件,它会在界面上呈现为一个图片上传区域。

运行与测试应用

运行上述代码后,Gradio应用界面将会启动。界面包含一个图片上传区域和一个用于显示描述的文字框。

以下是使用应用的一些建议:

  • 你可以上传宠物、家人或身边有趣事物的照片,看看模型如何描述它们。
  • 也可以直接点击界面提供的示例图片进行测试。

例如,使用之前测试过的小狗图片,应用会生成相同的描述:“a dog wearing a Santa hat and scarf”。
再尝试示例中的小鸟图片,模型描述为:“There is a bird that is flying in the yard.”,描述准确。
对于奶牛图片,模型描述为:“There are two cows standing in a field with a lake in the background.”,描述较为完整。

总结

本节课中,我们一起学习了如何利用开源的Blip图像描述模型和Gradio库,构建一个交互式的图像描述应用。我们掌握了设置API、编写模型调用函数、处理图片格式转换以及设计Gradio界面的完整流程。这个应用能够接收用户上传的图片,并返回AI生成的文字描述。

在下一节课中,我们将更进一步,学习如何使用生成式模型来创造全新的图像。

004:构建图像生成应用 🖼️

在本节课中,我们将学习如何使用开源的文本到图像模型构建一个图像生成应用。该应用接收一段文字描述,并据此生成相应的图像。我们将从基础应用开始,逐步引入更复杂的参数控制,并最终使用Gradio Blocks构建一个布局更清晰、功能更强大的用户界面。

概述:从文本到图像

上一节我们介绍了如何使用Gradio构建图像描述应用。本节中,我们将构建一个功能相反的应用:一个文本到图像的生成器。我们将使用一个名为Stable Diffusion的开源扩散模型,通过API连接到服务器上的模型来生成图像。

首先,我们需要设置API密钥以连接到模型服务。

import os
os.environ[‘API_KEY‘] = ‘your_api_key_here‘

核心生成函数

与上节课的“图像到文本”端点不同,本节课我们使用“文本到图像”端点。模型训练的目标是相反的:它学习将一段文字描述与对应的图像关联起来,从而能够根据新的描述生成图像。

以下是调用API的核心函数 generate_completion

import requests

def generate_completion(prompt, api_url, headers):
    """
    向文本到图像API端点发送请求并获取生成的图像。
    """
    payload = {
        "inputs": prompt
    }
    response = requests.post(api_url, headers=headers, json=payload)
    # 假设API返回图像的字节数据或URL
    image_data = response.content
    return image_data

我们可以测试这个函数。输入一段描述,例如“一只在公园里的卡通狗”,函数会返回一张生成的图像。这表明我们的基础生成逻辑是有效的。

构建基础Gradio应用

现在,让我们将这个生成函数封装到一个Gradio应用中。这与之前构建的应用结构相似,但输入和输出组件互换了位置。

以下是构建基础应用的代码:

import gradio as gr

def generate_image(prompt):
    # 此处应调用上述的 generate_completion 函数
    # 为简化示例,我们假设它返回一个图像文件路径或PIL图像对象
    image = generate_completion(prompt, API_URL, HEADERS)
    return image

# 创建Gradio界面
demo = gr.Interface(
    fn=generate_image,        # 处理函数
    inputs=gr.Textbox(label="输入图像描述"), # 输入组件:文本框
    outputs=gr.Image(label="生成的图像"),    # 输出组件:图像显示
    title="文本到图像生成器",
    description="输入一段描述,模型将为你生成对应的图像。"
)

demo.launch()

在这个界面中,用户在文本框中输入描述,点击提交后,右侧会显示生成的图像。例如,输入“一个电子宠物的灵魂漫步在维也纳城中”,模型会生成一幅符合该意境的图像。每次运行都会生成略有不同的新图像,增加了趣味性。

引入高级参数

Stable Diffusion模型功能强大,支持更多参数来精细控制图像生成效果。为了让用户能使用这些参数,我们需要升级应用界面。

以下是新增的几个关键参数:

  • 负向提示词:引导模型避免生成包含某些元素的图像。
  • 推理步数:控制生成过程的精细度,步数越多,质量可能越高,但耗时也越长。
  • 引导尺度:控制生成结果与提示词的贴合程度。
  • 图像宽高:设置生成图像的尺寸。

我们首先创建一个包含这些参数的新界面:

def generate_image_advanced(prompt, negative_prompt, steps, guidance_scale, width, height):
    # 构建包含所有参数的请求
    payload = {
        "inputs": prompt,
        "parameters": {
            "negative_prompt": negative_prompt,
            "num_inference_steps": int(steps),
            "guidance_scale": guidance_scale,
            "width": int(width),
            "height": int(height)
        }
    }
    # ... 发送请求并返回图像
    return image

# 定义输入组件
prompt_input = gr.Textbox(label="正向提示词")
negative_input = gr.Textbox(label="负向提示词", placeholder="输入你不想在图像中出现的内容")
steps_slider = gr.Slider(minimum=1, maximum=100, value=20, label="推理步数")
guidance_slider = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, label="引导尺度")
width_slider = gr.Slider(minimum=256, maximum=1024, value=512, step=64, label="宽度")
height_slider = gr.Slider(minimum=256, maximum=1024, value=512, step=64, label="高度")

# 创建界面
demo_advanced = gr.Interface(
    fn=generate_image_advanced,
    inputs=[prompt_input, negative_input, steps_slider, guidance_slider, width_slider, height_slider],
    outputs=gr.Image(),
    title="高级图像生成器"
)

测试这个应用,例如输入“动漫风格,公园里的一只狗”,并在负向提示词中输入“低质量”,同时增加推理步数,可以得到质量更优、更符合预期的图像。

使用Gradio Blocks优化布局

随着参数增多,基础界面变得拥挤。为了创建更灵活、美观的布局,我们将引入 Gradio Blocks。与 gr.Interface 这种快速但布局固定的方式不同,Blocks允许你像搭积木一样自定义UI结构。

以下是使用Blocks重构后的应用代码:

import gradio as gr

def generate_image_advanced(prompt, negative_prompt, steps, guidance_scale, width, height):
    # 生成逻辑保持不变
    # ...
    return image

# 开始构建Blocks
with gr.Blocks() as demo:
    # 1. 标题
    gr.Markdown(“# 🎨 高级图像生成工作室”)

    # 2. 主要输入行:提示词和提交按钮并列
    with gr.Row():
        with gr.Column(scale=4, min_width=300):
            prompt_input = gr.Textbox(label=“描述你的画面”, placeholder=“例如:一只穿着宇航服的猫”)
        with gr.Column(scale=1, min_width=100):
            submit_btn = gr.Button(“生成”, variant=“primary”)

    # 3. 可折叠的“高级选项”区域
    with gr.Accordion(“🛠️ 高级选项”, open=False):
        negative_input = gr.Textbox(label=“负向提示词”, placeholder=“希望避免的内容,如:模糊、畸形”)
        with gr.Row():
            with gr.Column():
                steps_slider = gr.Slider(1, 100, value=20, label=“推理步数”)
                guidance_slider = gr.Slider(1.0, 20.0, value=7.5, label=“引导尺度”)
            with gr.Column():
                width_slider = gr.Slider(256, 1024, value=512, step=64, label=“图像宽度”)
                height_slider = gr.Slider(256, 1024, value=512, step=64, label=“图像高度”)

    # 4. 输出图像区域
    output_image = gr.Image(label=“生成结果”, height=400)

    # 5. 明确绑定按钮点击事件
    submit_btn.click(
        fn=generate_image_advanced,
        inputs=[prompt_input, negative_input, steps_slider, guidance_slider, width_slider, height_slider],
        outputs=output_image
    )

# 启动应用
demo.launch()

在这个布局中:

  • 使用 gr.Row()gr.Column(scale=...) 进行灵活排版。
  • 使用 gr.Accordion() 将高级参数收纳起来,保持界面简洁。
  • 使用 gr.Button().click() 显式地将按钮与生成函数绑定。
  • 通过 min_width 等参数确保元素在不同屏幕尺寸下的可用性。

这种结构使得应用界面层次清晰:主要提示词输入和生成按钮突出显示,高级选项可按需展开,生成结果占据视觉中心。

总结

本节课中,我们一起学习了如何构建一个文本到图像的生成式AI应用。

  1. 我们首先连接了Stable Diffusion模型的API,实现了核心的图像生成功能。
  2. 接着,我们使用 gr.Interface 快速构建了一个基础应用原型。
  3. 然后,我们为模型引入了负向提示词、推理步数等高级参数,增强了用户对生成结果的控制力。
  4. 最后,为了管理复杂的输入控件,我们深入学习了 Gradio Blocks,通过自定义行、列、折叠面板等组件,构建了一个布局优雅、用户体验更佳的高级应用界面。

使用Gradio Blocks虽然需要编写更多布局代码,但它赋予了开发者极大的UI设计自由度,是构建复杂、专业级应用的强大工具。你可以尝试调整示例中的Blocks结构,创造出独一无二的界面。

在下一节课中,我们将把“图像描述”和“图像生成”两个模型结合起来,制作一个有趣的竞猜游戏应用。

005:构建一个图像描述与生成的游戏

在本节课中,我们将综合之前学到的“文本生成图像”和“图像生成文本”知识,构建一个有趣的、可以交互的应用程序。

概述

在前几节课中,我们学习了如何为NOP应用构建Gradio应用、如何构建图像描述应用以及如何构建文本到图像应用。本节中,我们将整合这些知识,构建一个有趣的游戏。这个游戏将从图像描述开始,然后根据生成的描述,再创造出一张新的图像。

准备工作

首先,我们进行常规的导入操作。在我们的辅助函数中,你会看到这里有一个端点URL和两个端点变量,因为本节课我们将使用两个API:文本到图像API和图像到文本API。

以下是需要导入的函数和库:

import gradio as gr
# 假设以下函数已在之前的课程中定义
from utils import image_to_base64, base64_to_image, captioner, generate

我们从前面的课程中引入了以下核心函数:

  • image_to_base64:将图像转换为Base64字符串。
  • base64_to_image:将Base64字符串转换回图像。
  • captioner:接收一张图像并生成描述。
  • generate:接收一段文本并生成图像。

构建分步式应用

首先,让我们构建一个分两步走的图像描述应用。这个应用的流程是:上传图像 -> 生成描述 -> 根据描述生成新图像。

以下是该应用的核心逻辑:

# 定义处理函数
def caption_image(input_img):
    # 调用描述生成函数
    caption = captioner(input_img)
    return caption

def generate_from_caption(input_caption):
    # 调用图像生成函数
    generated_img = generate(input_caption)
    return generated_img

# 构建Gradio界面
with gr.Blocks() as demo_step:
    gr.Markdown("## 分步式图像描述与生成游戏")
    with gr.Row():
        image_input = gr.Image(label="上传图像", type="filepath")
        caption_output = gr.Textbox(label="生成的描述")
        image_output = gr.Image(label="生成的图像")

    btn_caption = gr.Button("生成描述")
    btn_image = gr.Button("生成图像")

    # 连接按钮与函数
    btn_caption.click(fn=caption_image, inputs=image_input, outputs=caption_output)
    btn_image.click(fn=generate_from_caption, inputs=caption_output, outputs=image_output)

在这个界面中,我们有两个按钮。btn_caption按钮会调用captioner函数,其输入是上传的图像,输出是生成的描述。btn_image按钮则会接收上一个函数输出的描述,将其输入到generate函数中,最终输出一张新图像。

你可以这样使用它:

  1. 上传一张图片。
  2. 点击“生成描述”按钮,获得对图片的文字描述。
  3. 点击“生成图像”按钮,系统会根据上一步生成的描述,创造出一张全新的图片。

这就形成了一个有趣的“传话游戏”:上传一张图片,模型描述它,然后根据这个描述再生成一张新图片。你甚至可以将新生成的图片再次上传,生成新的描述,如此循环,观察结果会如何变化。

构建流线型应用

分步式应用虽然清晰,但可能需要点击多次。接下来,我们看看如何构建一个更流线型的版本,将所有步骤合并到一个函数中。

以下是流线型应用的核心逻辑:

# 定义一个函数,同时完成描述和生成
def caption_and_generate(input_img):
    # 第一步:生成描述
    caption = captioner(input_img)
    # 第二步:根据描述生成图像
    generated_img = generate(caption)
    # 返回描述和图像
    return caption, generated_img

# 构建Gradio界面
with gr.Blocks() as demo_streamlined:
    gr.Markdown("## 流线型图像描述与生成游戏")
    with gr.Row():
        image_input = gr.Image(label="上传图像", type="filepath")
    with gr.Row():
        caption_output = gr.Textbox(label="生成的描述")
        image_output = gr.Image(label="生成的图像")

    btn_all = gr.Button("描述并生成图像")

    # 连接按钮与函数
    btn_all.click(fn=caption_and_generate, inputs=image_input, outputs=[caption_output, image_output])

在这个版本中,我们只有一个按钮btn_all。点击后,它会调用caption_and_generate函数。这个函数内部依次执行描述生成和图像生成两个任务,并一次性返回描述文本和生成的新图像。

例如,上传一张办公室里的羊驼钥匙扣图片,点击一次按钮,你就能立刻得到对它的描述(如“一只戴着红色领结的小玩具羊驼”)以及根据该描述生成的新羊驼图片。

总结

本节课中,我们一起学习了如何将文本到图像和图像到文本两个功能结合起来。我们构建了两种风格的Gradio应用:一种是分步式,允许用户分步查看和操作;另一种是流线型,将所有过程整合到一次点击中。这两种方式各有优劣,你可以根据实际需求选择。恭喜你,你已经成功构建了第一个结合了多种生成式AI功能的交互式游戏应用。

在下一节课中,你将学习如何构建一个由先进大语言模型驱动的聊天机器人。

006:构建开源LLM聊天机器人应用 🚀

概述

在本节课中,我们将学习如何使用Gradio构建一个能与开源大语言模型(LLM)聊天的应用程序。我们将以目前性能最佳的开源模型之一——Falcon 40B Instruct为例,创建一个具备对话记忆和上下文理解能力的聊天机器人界面。


从简单问答到对话式交互

上一节我们介绍了如何通过Gradio界面与LLM进行简单的单轮问答。本节中,我们来看看如何构建一个能处理多轮对话、理解上下文的聊天机器人。

简单问答界面的局限性

我们首先创建一个基础的Gradio界面,包含一个文本框用于输入问题,并调用Falcon模型生成回答。

import gradio as gr
from text_generation import Client

client = Client("https://api-inference.huggingface.co/models/tiiuae/falcon-40b-instruct")
token = "YOUR_HF_TOKEN"

def generate(prompt):
    completion = client.generate(prompt, max_new_tokens=256).generated_text
    return completion

iface = gr.Interface(fn=generate, inputs="text", outputs="text")
iface.launch()

运行此代码后,我们可以向模型提问,例如“Has math been invented or discovered?”,模型会生成一个最多256个token的回答。然而,这种交互方式存在明显缺陷:如果我们提出后续问题,模型无法理解上下文,因为它只接收当前输入,没有对话历史记忆。


引入Gradio Chatbot组件

为了解决上下文缺失的问题,我们需要引入Gradio的Chatbot组件。这个组件能帮助我们管理对话历史,并将其正确地格式化后发送给模型。

以下是创建基础聊天机器人界面的步骤:

import gradio as gr

with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox()
    clear = gr.Button("Clear")

    def respond(message, chat_history):
        # 此处暂时使用预设回复进行演示
        bot_message = random.choice(["How are you?", "I love you", "I'm very hungry"])
        chat_history.append((message, bot_message))
        return "", chat_history

    msg.submit(respond, [msg, chatbot], [msg, chatbot])
    clear.click(lambda: None, None, chatbot, queue=False)

demo.launch()

在这个示例中,我们创建了一个包含聊天记录显示框、文本输入框和清除按钮的界面。respond函数暂时返回随机预设回复,以展示Chatbot组件如何工作:它将用户消息和机器人回复成对地添加到chat_history列表中。


连接LLM与格式化对话提示

现在,我们将预设回复替换为真实的Falcon模型生成内容。但仅仅发送当前用户消息是不够的,模型仍然无法理解对话历史。

我们需要定义一个函数来格式化对话提示,确保模型能区分用户消息和它自己的回复(助手消息)。

def format_chat_prompt(message, chat_history):
    prompt = ""
    for turn in chat_history:
        user_message, bot_message = turn
        prompt = f"{prompt}User: {user_message}\nAssistant: {bot_message}\n"
    prompt = f"{prompt}User: {message}\nAssistant:"
    return prompt

def respond(message, chat_history):
    formatted_prompt = format_chat_prompt(message, chat_history)
    bot_message = client.generate(formatted_prompt, max_new_tokens=256).generated_text
    chat_history.append((message, bot_message))
    return "", chat_history

format_chat_prompt函数遍历整个chat_history,将每一轮对话都格式化为“User: ...\nAssistant: ...\n”的结构。最后,附加上当前的新用户消息和“Assistant:”提示,引导模型开始生成回复。这样,模型在生成回答时就能看到完整的对话上下文。


处理长对话与停止序列

随着对话轮次增加,我们发送给模型的提示会越来越长,最终可能超过模型的最大上下文长度限制。此外,模型有时可能会错误地开始生成“User:”部分的内容(即模仿用户提问)。

为了解决这些问题,我们可以采取以下措施:

  1. 合理设置max_new_tokens参数,控制单次生成的长度。
  2. 使用stop_sequences参数,例如设置为["\nUser:"]。当模型在生成过程中遇到“\nUser:”这个序列时,它会立即停止,从而防止它冒充用户。
def respond(message, chat_history):
    formatted_prompt = format_chat_prompt(message, chat_history)
    bot_message = client.generate(
        formatted_prompt,
        max_new_tokens=1024, # 根据硬件和API限制调整
        stop_sequences=["\nUser:"]
    ).generated_text
    chat_history.append((message, bot_message))
    return "", chat_history

构建功能完整的进阶UI

为了获得最佳体验,我们可以构建一个包含更多控制选项的进阶界面。

以下是构建进阶UI的核心要素:

  1. 系统指令:通过系统消息设定AI助手的角色和行为基调(例如,“你是一个乐于助人的助手”)。
  2. 温度参数:控制模型输出的随机性。temperature=0时输出确定性最强,temperature值越高输出越多样。
  3. 流式响应:让模型逐词生成回复,实现实时显示效果,无需等待整个回答完成。
def format_chat_prompt(message, chat_history, system_message=""):
    prompt = f"System: {system_message}\n"
    for turn in chat_history:
        user_message, bot_message = turn
        prompt = f"{prompt}User: {user_message}\nAssistant: {bot_message}\n"
    prompt = f"{prompt}User: {message}\nAssistant:"
    return prompt

def respond(message, chat_history, system_message, temperature):
    formatted_prompt = format_chat_prompt(message, chat_history, system_message)
    # 使用支持流式生成的方法
    stream = client.generate_stream(formatted_prompt, max_new_tokens=1024, temperature=temperature, stop_sequences=["\nUser:"])

    partial_message = ""
    for token in stream:
        partial_message += token
        # 逐词更新聊天记录
        yield chat_history + [(message, partial_message)]

with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox(label="Your Message")
    with gr.Accordion("Advanced Options", open=False):
        system_msg = gr.Textbox(label="System Instruction", value="You are a helpful assistant.", lines=2)
        temperature = gr.Slider(label="Temperature", minimum=0.0, maximum=1.0, value=0.7, step=0.1)
    clear = gr.Button("Clear")

    msg.submit(respond, [msg, chatbot, system_msg, temperature], chatbot)
    clear.click(lambda: None, None, chatbot, queue=False)

demo.queue().launch()

在这个进阶示例中:

  • format_chat_prompt函数在对话历史前加入了系统指令。
  • respond函数使用generate_stream来获取流式响应,并通过yield逐步更新界面上的聊天记录。
  • 界面使用gr.Accordion将高级选项(系统指令和温度滑块)收纳起来,保持界面整洁。
  • demo.queue()用于处理流式响应所需的请求队列。

总结

本节课中我们一起学习了如何使用Gradio构建一个功能强大的开源LLM聊天机器人应用。我们从简单的问答界面出发,逐步解决了上下文记忆问题,引入了Chatbot组件和提示格式化函数。最后,我们构建了一个包含系统指令、温度控制和流式响应等高级功能的完整应用。

你可以在此基础上继续探索,例如:调整UI布局、尝试不同的系统指令让模型扮演特定角色(如用法语回答的生物学家),或者集成其他开源模型。请记住,虽然LLM功能强大,但在实际应用中,对于法律、医疗等专业领域,仍需谨慎对待其输出内容,并建立相应的保障措施。

007:HuggingFace总结与展望 🚀

在本节课中,我们将总结使用Gradio与HuggingFace构建AI应用的核心要点,并了解如何将你的项目分享给全世界。

课程概述

上一节我们介绍了如何将模型集成到Gradio应用中。本节中,我们将对HuggingFace生态进行总结,并探索项目部署与社区参与的途径。

旅程的起点

我希望这仅仅是你使用Gradio旅程的开始。

探索与社区

你可以探索它的全部功能,并加入其充满活力的开源社区。

以下是深入学习的两个关键方向:

  • 探索功能:深入研究Gradio的文档,尝试其高级组件和布局选项。
  • 加入社区:在GitHub或Discord上参与Gradio社区的讨论,获取帮助并分享想法。

部署与分享

当你有了想要与世界分享的应用程序时,HuggingFace提供了一个名为Spaces的平台,你可以在上面部署它们。

部署应用的基本流程如下:

  1. 在HuggingFace网站上创建账户。
  2. 点击“新建”并选择“Space”。
  3. 按照指引,上传你的Gradio应用代码(通常是一个包含app.py的仓库)。
  4. Spaces会自动构建并公开你的应用。

总结与展望

本节课中我们一起学习了Gradio与HuggingFace生态的结合,并了解了通过Spaces平台部署和分享AI应用的方法。我十分期待看到你构建出的作品。😊

posted @ 2026-03-26 08:11  绝不原创的飞龙  阅读(1)  评论(0)    收藏  举报