【Gradio】Chatbots 如何用 Gradio 创建聊天机器人

Creating A Chatbot Fast

简介

聊天机器人是大型语言模型的一个流行应用。使用 gradio ,您可以轻松构建您的聊天机器人模型的演示,并与您的用户分享,或者使用直观的聊天机器人用户界面自己尝试。

本教程使用 gr.ChatInterface() ,这是一个高级抽象,允许您快速创建聊天机器人界面,通常只需一行代码。我们创建的聊天机器人界面将如下所示:

6b5ff36c5ef68fe2bc3a32c0dd2ab4d2.png

我们将从一些简单的例子开始,然后展示如何结合几个流行的 API 和库中的真实语言模型使用 gr.ChatInterface() ,包括 langchain 、 openai 和 Hugging Face。

先决条件:请确保您使用的是 Gradio 的最新版本

$ pip install --upgrade gradio

定义聊天功能 

在使用 gr.ChatInterface() 时,您应该首先定义您的聊天功能。您的聊天功能应该有两个参数: message 然后是 history (参数可以任意命名,但必须按此顺序)。

  • message :代表用户输入的 str 。

  • history :一个 list ,代表到那时为止的 list 。每个内部列表由两个 str 组成,代表一对: [user input, bot response] 。

您的函数应该返回一个字符串响应,这是机器人对特定用户输入 message 的响应。您的函数可以考虑消息的 history ,以及当前消息。

让我们看几个例子。

示例:一个回答是或否的聊天机器人 

让我们编写一个聊天功能,它可以随机回应 Yes 或 No 。

这是我们的聊天功能:

import random# 定义一个函数用于生成随机响应
def random_response(message, history):# 从列表["Yes", "No"]中随机选择一个元素并返回return random.choice(["Yes", "No"])

ef6c9d9e108b52a7253c3c35d421ae70.png

现在,我们可以将其插入 gr.ChatInterface() 并调用 .launch() 方法来创建网络界面:

3f592bffd084539c87e483541afefd97.png

import gradio as gr# 定义一个随机响应函数,这个函数从"Yes"和"No"中随机选择一个作为响应
def random_response(message, history):import random  # 导入random模块用于生成随机数return random.choice(["Yes", "No"])  # 随机选取“Yes”或“No”作为响应# 使用Gradio的ChatInterface模块创建一个聊天界面,这个界面会使用上面定义的random_response函数来响应用户的输入
gr.ChatInterface(random_response).launch()  # 启动聊天界面

910bd5700b204c9fa66b226e339923d3.png

另一个例子是使用用户的输入和历史记录 

当然,之前的例子非常简单,它甚至没有考虑用户输入或之前的历史记录!这里有另一个简单的例子,展示了如何结合用户的输入以及历史记录。

import random  # 导入random模块
import gradio as gr  # 导入gradio库,并简称为gr# 定义一个根据历史长度奇偶性交替同意或不同意的函数
def alternatingly_agree(message, history):# 如果历史记录的长度是偶数,则同意if len(history) % 2 == 0:return f"Yes, I do think that '{message}'"  # 同意用户的观点# 否则,表示不同意else:return "I don't think so"  # 不同意用户的观点# 使用Gradio的ChatInterface模块创建一个聊天界面,使用上面定义的alternatingly_agree函数来响应用户的输入
gr.ChatInterface(alternatingly_agree).launch()  # 启动聊天界面

da1967b6b55c46d4eb5b35e4d493ace1.png

 流媒体聊天机器人 

在您的聊天功能中,您可以使用 yield 生成一系列部分响应,每个响应都会替换前一个。这样,您最终将得到一个流式聊天机器人。就是这么简单!

import time  # 导入time模块,用于实现等待(延时)
import gradio as gr  # 导入gradio库,并简称为gr# 定义一个慢速回显函数,模拟逐字打印的效果
def slow_echo(message, history):# 遍历消息中的每一个字符for i in range(len(message)):time.sleep(0.3)  # 每输出一个字符后暂停0.3秒yield "You typed: " + message[: i+1]  # 逐渐展示已经输入的消息内容# 使用Gradio的ChatInterface模块创建一个聊天界面,使用上面定义的slow_echo函数来响应用户的输入
gr.ChatInterface(slow_echo).launch()  # 启动聊天界面

a3d8b4a3c73c6fd7a9258c0ffdab2d90.png

提示:当响应正在流式传输时,“提交”按钮会变成“停止”按钮,可以用来停止生成器函数。您可以使用`stop_btn`参数自定义“停止”按钮的外观和行为。

定制您的聊天机器人 

如果您熟悉 Gradio 的 Interface 类,那么 gr.ChatInterface 包含许多相同的参数,您可以使用这些参数来自定义您的聊天机器人的外观和感觉。例如,您可以:

  • 在您的聊天机器人上方添加标题和描述,使用 title 和 description 参数。

  • 使用 theme 和 css 参数分别添加主题或自定义 CSS。

  • 添加 examples 并且甚至启用 cache_examples ,这使得用户更容易尝试。

  • 您可以更改聊天机器人界面中出现的每个按钮的文本或禁用它们: submit_btn , retry_btn , undo_btn , clear_btn 。

如果您想自定义组成 ChatInterface 的 gr.Chatbot 或 gr.Textbox ,您也可以传入您自己的聊天机器人或文本框。以下是我们如何使用这些参数的示例:

b75008015a6d2d0809e73499f8d7ad62.png

import gradio as gr  # 导入gradio库# 定义一个总是回答"Yes"或提示用户提问的函数
def yes_man(message, history):# 如果消息以问号结尾,则回答"Yes"if message.endswith("?"):return "Yes"# 否则,提示用户提出问题else:return "Ask me anything!"# 使用Gradio的ChatInterface模块创建一个聊天界面
gr.ChatInterface(yes_man,  # 指定yes_man函数为回答逻辑chatbot=gr.Chatbot(height=300),  # 创建一个聊天机器人并设置其容器高度为300textbox=gr.Textbox(placeholder="Ask me a yes or no question", container=False, scale=7),  # 创建文本输入框并设置提示文本、不使用容器模式,并放大7倍title="Yes Man",  # 设置聊天界面标题description="Ask Yes Man any question",  # 设置聊天界面描述theme="soft",  # 设置界面主题为softexamples=["Hello", "Am I cool?", "Are tomatoes vegetables?"],  # 提供示例问题cache_examples=True,  # 启用缓存示例功能retry_btn=None,  # 不显示重试按钮undo_btn="Delete Previous",  # 设置撤销按钮文本为"Delete Previous"clear_btn="Clear",  # 设置清除按钮文本为"Clear"
).launch()  # 启动聊天界面

特别是,如果您想为聊天界面添加一个“占位符”,该占位符会在用户开始聊天之前显示,您可以使用 gr.Chatbot 的 placeholder 参数来实现,它接受 Markdown 或 HTML。

2bdc86ac53863f7b20084141b6432d3c.png

gr.ChatInterface(yes_man,chatbot=gr.Chatbot(placeholder="<strong>Your Personal Yes-Man</strong><br>Ask Me Anything"),
...

占位符在聊天机器人中垂直和水平居中显示。

将多模态功能添加到您的聊天机器人 

您可能希望为您的聊天机器人添加多模态功能。例如,您可能希望用户能够轻松地上传图片或文件到您的聊天机器人并对其提问。您可以通过向 gr.ChatInterface 类传递一个参数( multimodal=True )来使您的聊天机器人“多模态”。

import gradio as gr  # 导入gradio库,用于创建交互式界面
import time  # 导入time模块,虽然在这个例子中未直接使用,但可用于其他功能如延迟# 定义一个函数,用于计算用户上传的文件数量
def count_files(message, history):num_files = len(message["files"])  # 计算上传文件的数量return f"You uploaded {num_files} files"  # 返回一个字符串,包含上传的文件数量# 创建一个Gradio聊天界面
demo = gr.ChatInterface(fn=count_files,  # 指定处理消息的函数是count_filesexamples=[{"text": "Hello", "files": []}],  # 提供一个示例输入,没有附带文件title="Echo Bot",  # 设置界面的标题为"Echo Bot"multimodal=True  # 开启多模态支持,允许文本和文件同时作为输入
)# 启动Gradio界面
demo.launch()

db3910960a9f658a8e3b65dbeb9433cb.png

当 multimodal=True 时, fn 的签名会略有变化。你的函数的第一个参数应该接受一个由提交的文本和上传的文件组成的字典,看起来像这样: {"text": "user input", "file": ["file_path1", "file_path2", ...]} 。同样,你提供的任何示例也应该是这种形式的字典。你的函数仍然应该返回一个单一的 str 消息。

3499769a5a1d86b71b3d429e21564f0c.png

小贴士:如果您想自定义多模态聊天机器人的文本框的 UI/UX,您应该将 gr.MultimodalTextbox 的实例传递给 ChatInterface 的 textbox 参数,而不是 gr.Textbox 的实例。

附加输入 

您可能希望为您的聊天机器人添加额外的参数,并通过聊天机器人用户界面将它们暴露给用户。例如,假设您想添加一个系统提示的文本框,或者添加一个设置聊天机器人回应中的令牌数量的滑块。 ChatInterface 类支持一个 additional_inputs 参数,可用于添加额外的输入组件。

additional_inputs 参数接受一个组件或一组组件。您可以直接传递组件实例,或使用它们的字符串快捷方式(例如 "textbox" 而不是 gr.Textbox() )。如果您传入组件实例,并且它们尚未被渲染,那么这些组件将出现在聊天机器人(和任何示例)下方的 gr.Accordion() 中。您可以使用 additional_inputs_accordion_name 参数设置此手风琴的标签。

这是一个完整的例子:

3e629fbf8285dcc809d9ee0f53a1a849.png

import gradio as gr  # 导入gradio库,用于创建交云式界面
import time  # 导入time模块,用于在循环中添加延迟效果# 定义一个echo函数,模拟逐字输出消息的效果
def echo(message, history, system_prompt, tokens):# 格式化字符串,包含系统提示和用户消息response = f"System prompt: {system_prompt}\n Message: {message}."# 通过最小值函数确定输出字符的最大长度,避免超出用户设置的token数for i in range(min(len(response), int(tokens))):time.sleep(0.05)  # 在每个字符输出之间添加短暂延迟,增加逐字显示效果yield response[: i + 1]  # 逐步输出字符串,达到“打字机”效果# 使用Gradio的ChatInterface构建一个支持多输入的聊天界面
demo = gr.ChatInterface(echo,  # 将echo函数设为回调函数# 通过additional_inputs参数添加额外的输入控件additional_inputs=[gr.Textbox("You are helpful AI.", label="System Prompt"),  # 添加一个文本输入框,用于输入系统提示gr.Slider(10, 100),  # 添加一个滑动条,范围从10到100,用于控制输出的最大字符数(tokens)],
)if __name__ == "__main__":demo.queue().launch()  # 在主程序中启动Gradio界面,在队列模式下运行

a3cb632ef659d61e409f55566ca5fd0e.png

如果您传递到additional_inputs中的组件已经在父级gr.Blocks()中渲染过了,那么它们将不会在手风琴accordion中重新渲染。这在决定如何布局输入组件方面提供了灵活性。在下面的例子中,我们将gr.Textbox()放置在聊天机器人界面的顶部,同时将滑块保持在下方

import gradio as gr  # 导入gradio库,用于创建交互式Web应用
import time  # 导入time模块,用于实现延迟效果# 定义一个函数,用来逐字输出响应消息
def echo(message, history, system_prompt, tokens):# 格式化响应消息,包含系统提示和用户消息response = f"System prompt: {system_prompt}\n Message: {message}."# 根据response的长度和tokens确定循环的次数,逐个字符输出for i in range(min(len(response), int(tokens))):time.sleep(0.05)  # 每输出一个字符后暂停0.05秒,模拟打字效果yield response[:i+1]  # 逐渐输出,每次迭代输出一个字符多于上一次# 使用gr.Blocks创建一个可视化布局
with gr.Blocks() as demo:# 创建一个文本输入框,用于输入系统提示system_prompt = gr.Textbox("You are helpful AI.", label="System Prompt")# 创建一个滑动条,用于选择tokens的数量,但不直接在界面中渲染显示slider = gr.Slider(10, 100, render=False)# 创建一个聊天界面,将echo函数作为处理函数,并通过additional_inputs添加上面创建的输入控件gr.ChatInterface(echo, additional_inputs=[system_prompt, slider])# 启动Gradio应用
demo.launch()

1ffdfd84509858adf79877764c87a626.png

如果您需要创建更加定制化的内容,那么最好使用低级别的 gr.Blocks() API 来构建聊天机器人的用户界面。我们在这里有一个专门的指南。https://www.gradio.app/guides/creating-a-custom-chatbot-with-blocks

使用您的聊天机器人通过 API 

一旦您构建了 Gradio 聊天机器人并将其托管在 Hugging Face Spaces 或其他地方,那么您可以在 /chat 端点使用简单的 API 查询它。该端点只期望用户的消息(如果您使用 additional_inputs 参数设置了任何附加输入,也可能包括这些输入),并将返回响应,同时内部跟踪到目前为止发送的消息。

要使用端点,您应该使用 Gradio Python 客户端或 Gradio JS 客户端。

 一个 langchain 例子 

现在,让我们实际使用 gr.ChatInterface 与一些真正的大型语言模型。我们将开始使用 langchain 在 openai 之上构建一个通用的流式聊天机器人应用程序,只需 19 行代码。对于这个例子,你将需要一个 OpenAI 密钥(继续阅读免费的开源等价物!)

cfe0a8934a4fc5e151e7328d594a6d9d.png

from langchain.chat_models import ChatOpenAI  # 从langchain库中导入ChatOpenAI聊天模型
from langchain.schema import AIMessage, HumanMessage  # 从langchain库中导入消息模式
import openai  # 导入openai库,用于访问OpenAI的API
import gradio as gr  # 导入gradio库,用于创建交互式Web应用
import os  # 导入os模块,用于设置环境变量# 设置环境变量,这里留空了OPENAI_BASE_URL。通常,您不需要更改API的基本URL
os.environ["OPENAI_BASE_URL"] = ""
# 设置环境变量,这里的API密钥使用了一个示例值,你需要替换为你自己的OpenAI API密钥
os.environ["OPENAI_API_KEY"] = "dummy"  # 替换为你的密钥# 初始化ChatOpenAI实例,设置模型为'gpt-4',温度为1.0。这表示使用GPT-4模型,温度参数控制生成文本的创造性
llm = ChatOpenAI(temperature=1.0, model='gpt-4')# 定义预测函数,它接受用户的消息和历史对话记录,返回GPT模型的回复
def predict(message, history):history_langchain_format = []  # 创建一个空列表,用于存储历史对话记录for human, ai in history:  # 遍历历史记录中的人机对话# 将人类和AI的消息转换为Langchain的消息格式,并添加到列表中history_langchain_format.append(HumanMessage(content=human))history_langchain_format.append(AIMessage(content=ai))# 将当前用户的消息也转换为相应格式,并加入到历史记录中history_langchain_format.append(HumanMessage(content=message))# 使用Langchain模型llm处理转换后的历史记录,获取模型的回应gpt_response = llm(history_langchain_format)return gpt_response.content  # 返回GPT模型的回应内容# 使用Gradio的ChatInterface创建聊天界面,指定predict函数用于响应用户输入
gr.ChatInterface(predict).launch()  # 启动Gradio应用,可以在Web浏览器中与之交互

使用 openai  的流媒体示例

当然,我们也可以直接使用 openai 库。这里有一个类似的例子,但这次是带有流式结果的:

from openai import OpenAI  # 从openai模块导入OpenAI类,用于实例化客户端
import gradio as gr  # 导入gradio库,用于创建交互式Web界面
import osapi_key = "dummy"  # 将api_key变量设置为你的API密钥
# 设置环境变量
os.environ["OPENAI_BASE_URL"] = ''
# os.environ["OPENAI_API_KEY"] = "your-api-key"
client = OpenAI(api_key=api_key)  # 使用你的API密钥实例化OpenAI客户端# 定义predict函数,它接受用户的消息和聊天历史作为输入
def predict(message, history):history_openai_format = []  # 创建一个空列表用于存储处理过的历史记录for human, assistant in history:  # 遍历历史对话# 将每条历史消息按照OpenAI所需的格式添加到列表中history_openai_format.append({"role": "user", "content": human })history_openai_format.append({"role": "assistant", "content":assistant})# 将最新的用户消息也以相同的格式添加到列表history_openai_format.append({"role": "user", "content": message})# 使用客户端请求GPT-3.5-turbo模型的回复,传入处理过的历史消息和其他参数response = client.chat.completions.create(model='gpt-4',messages= history_openai_format,temperature=1.0,stream=True)partial_message = ""  # 初始化用于收集模型响应的字符串for chunk in response:  # 遍历响应中的每个部分if chunk.choices[0].delta.content is not None:  # 如果响应部分有内容partial_message += chunk.choices[0].delta.content  # 将其添加到累积的响应字符串yield partial_message  # 使用yield返回累积的响应字符串,实现流式响应gr.ChatInterface(predict).launch()  # 使用Gradio的ChatInterface调用predict函数,并启动Web界面

9d722f68caf6975d0ce25f5e5f1e090c.png

示例使用本地开源LLM与 Hugging Face 

当然,在许多情况下,您可能希望在本地运行聊天机器人。这里有一个使用 Hugging Face 的 Together's RedePajama 模型的等效示例(这需要您拥有支持 CUDA 的 GPU)。

import gradio as gr  # 导入gradio库来创建图形化的聊天界面
import torch  # 导入PyTorch库
from transformers import AutoModelForCausalLM, AutoTokenizer, StoppingCriteria, StoppingCriteriaList, TextIteratorStreamer
from threading import Thread  # 用于创建后台线程来生成模型的输出# 加载模型和分词器
tokenizer = AutoTokenizer.from_pretrained("togethercomputer/RedPajama-INCITE-Chat-3B-v1")
model = AutoModelForCausalLM.from_pretrained("togethercomputer/RedPajama-INCITE-Chat-3B-v1", torch_dtype=torch.float16)
model = model.to('cuda:0')  # 把模型移动到GPU上以加速计算class StopOnTokens(StoppingCriteria):  # 定义一个停止准则,按照特定的词或标志来停止生成def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:stop_ids = [29, 0]  # 设置停止IDfor stop_id in stop_ids:if input_ids[0][-1] == stop_id:return Truereturn Falsedef predict(message, history):  # 定义预测函数,接受消息和历史记录history_transformer_format = history + [[message, ""]]stop = StopOnTokens()# 组装历史消息和当前消息messages = "".join(["".join(["\n<human>:"+item[0], "\n<bot>:"+item[1]])for item in history_transformer_format])# 对消息进行编码,并移动到相应的设备上model_inputs = tokenizer([messages], return_tensors="pt").to("cuda")# 设置文本生成参数streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)generate_kwargs = dict(model_inputs,streamer=streamer,max_new_tokens=1024,do_sample=True,top_p=0.95,top_k=1000,temperature=1.0,num_beams=1,stopping_criteria=StoppingCriteriaList([stop]))t = Thread(target=model.generate, kwargs=generate_kwargs)  # 在后台线程中生成回复t.start()partial_message = ""for new_token in streamer:  # 从生成器中逐个获取新的标记if new_token != '<':  # 如果新标记不是特定的字符partial_message += new_token  # 添加到部分消息中yield partial_message  # 实时更新生成的消息gr.ChatInterface(predict).launch()  # 启动Gradio界面

有了这些例子,你应该很快就能创建自己的 Gradio 聊天机器人演示了!要构建更多定制的聊天机器人应用程序,请查看使用低级别 gr.Blocks() API 的专用指南https://www.gradio.app/guides/creating-a-custom-chatbot-with-blocks 。

2e31e9bcfb7522773a15604ba18ebd8a.png

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

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

相关文章

SpringMVC系列四: Rest-优雅的url请求风格

Rest请求 &#x1f49e;Rest基本介绍&#x1f49e;Rest风格的url-完成增删改查需求说明代码实现HiddenHttpMethodFilter机制注意事项和细节 &#x1f49e;课后作业 上一讲, 我们学习的是SpringMVC系列三: Postman(接口测试工具) 现在打开springmvc项目 &#x1f49e;Rest基本介…

基于Spark3.3.4版本,实现Standalone 模式高可用集群部署

目录 一、环境描述 二、部署Spark 节点 2.1 下载资源包 2.2 解压 2.3 配置 2.3.1 配置环境变量 2.3.2 修改workers配置文件 2.3.3 修改spark.env.sh文件 2.3.4 修改spark-defaults.conf 2.4 分发 2.5 启动服务 2.5.1 启动zookeeper 2.5.2 启动hdfs 2.5.3 启动spar…

归并排序 (递归实+非递归)

前言 归并排序是一种逻辑很简单&#xff0c;但是实现有点难度的排序&#xff0c;尤其是非递归&#xff0c;对于区间的把握更是需要一点逻辑的推导&#xff0c;但是没有关系&#xff0c;轻松拿捏 归并排序gif 归并排序单趟实现 1&#xff0c;创建tmp数组&#xff0c; 2&#xff…

javaWeb项目-在线考试系统详细功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Java简介 Java语…

「Qt Widget中文示例指南」如何实现一个滑动条(一)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 滑动条示例展示了如…

轻轻松松上手的LangChain学习说明书

本文为笔者学习LangChain时对官方文档以及一系列资料进行一些总结&#xff5e;覆盖对Langchain的核心六大模块的理解与核心使用方法&#xff0c;全文篇幅较长&#xff0c;共计50000字&#xff0c;可先码住辅助用于学习Langchain。 一、Langchain是什么&#xff1f; 如今各类AI…

昇思25天学习打卡营第1天|快速入门

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) 本节通过MindSpore的API来快速实现一个简单的深度学习模型。若想要深入了解MindSpore的使用方法&#xff0c;请参阅各节最后提供的参考链接。 import mindspore from mindspore import nn from …

项目训练营第一天

项目训练营第一天 springboot后端环境搭建 1、首先需要找文章下载好tomcat、JDK、maven、mysql、IDEA。&#xff08;软件下载及环境变量配置略&#xff09; 2、在下载好的IDEA中&#xff0c;选择新建spring initial项目&#xff0c;选定java web&#xff0c;即可新建一个spri…

win11 之下载安装 allure

1. 下载 https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/2.25.0/allure-commandline-2.25.0.zip 2. 配置系统变量 path 下添加解压后的bin目录 3. 验证是否安装成功 输入 allure

Mac 安装HomeBrew(亲测成功)

1、终端安装命令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"执行后&#xff0c;没有安装git&#xff0c;会先安装&#xff0c;安装后再执行一下命令。 2、根据中文选择源安装 3、相关命令 查看版本号&a…

python flask使用flask_migrate管理数据库迁移

&#x1f308;所属专栏&#xff1a;【Flask】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…

一篇文章了解常用排序算法

排序 文章目录 排序直接(插入)排序InsertSort思想实现方法&#xff1a; 希尔排序ShellSort&#xff08;可过OJ)思想预排序gap的作用整体代码 选择排序SelectSort思想完整代码 堆排序HeapSort(可过OJ)思想大根堆向下调整 完整代码 冒泡排序BubbleSort快速排序&#xff08;快排&a…

Unity URP 仿原神角色渲染过程记录

想学一下NPR渲染&#xff0c;话不多说&#xff0c;先搞一只芙再说&#xff0c;边做边学 一、资源整理 终于是把东西全都集齐了 1、纹理设置 首先要把将Diffuse和Lightmap的压缩改成"无"或"高质量"。 法线贴图的纹理类型改成"法线贴图"。 除颜…

HarmonyOS 角落里的知识 —— 状态管理

一、前言 在探索 HarmonyOS 的过程中&#xff0c;我们发现了许多有趣且实用的功能和特性。有些总是在不经意间或者触类旁通的找到。或者是某些开发痛点。其中&#xff0c;状态管理是ArkUI开发非常核心的一个东西&#xff0c;我们进行了大量的使用和测试遇到了许多奇奇怪怪的问…

Android平台下VR头显如何低延迟播放4K以上超高分辨率RTSP|RTMP流

技术背景 VR头显需要更高的分辨率以提供更清晰的视觉体验、满足沉浸感的要求、适应透镜放大效应以及适应更广泛的可视角度&#xff0c;超高分辨率的优势如下&#xff1a; 提供更清晰的视觉体验&#xff1a;VR头显的分辨率直接决定了用户所看到的图像的清晰度。更高的分辨率意…

001.VMware Workstation Pro虚拟平台安装

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

《数字图像处理-OpenCV/Python》第16章:图像的特征描述

《数字图像处理-OpenCV/Python》第16章&#xff1a;图像的特征描述 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第16章&#xff1a;图像的特征描述 特征通常是针对图像中的目标或…

快排(霍尔排序实现+前后指针实现)(递归+非递归)

前言 快排是很重要的排序&#xff0c;也是一种比较难以理解的排序&#xff0c;这里我们会用递归的方式和非递归的方式来解决&#xff0c;递归来解决是比较简单的&#xff0c;非递归来解决是有点难度的 快排也称之为霍尔排序&#xff0c;因为发明者是霍尔&#xff0c;本来是命名…

基于Spring Boot+VUE旧物置换网站

1前台首页功能模块 旧物置换网站&#xff0c;在系统首页可以查看首页、旧物信息、网站公告、个人中心、后台管理等内容&#xff0c;如图1所示。 图1系统功能界面图 用户注册&#xff0c;在用户注册页面通过填写用户名、密码、姓名、性别、头像、手机、邮箱等内容进行用户注册&…

FlinkCDC介绍及使用

CDC简介 什么是CDC&#xff1f; cdc是Change Data Capture(变更数据获取)的简称。核心思想是&#xff0c;监测并捕获数据库的 变动(包括数据或数据表的插入&#xff0c;更新以及删除等)&#xff0c;将这些变更按发生的顺序完整记录下来&#xff0c;写入到消息中间件以供其它服…