【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),  # 创建一个聊天机器人并设置其容器高度为300
    textbox=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",  # 设置界面主题为soft
    examples=["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_files
    examples=[{"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 os


api_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]  # 设置停止ID
        for stop_id in stop_ids:
            if input_ids[0][-1] == stop_id:
                return True
        return False


def 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.mfbz.cn/a/722350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「51媒体」总台,地方卫视媒体邀约新闻报道采访怎么做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 总台对选题要求非常严格&#xff0c;在想做总台新闻报道之前&#xff0c;让我们先来了解下总台对新闻选题有哪些要求&#xff1a; 一、新闻价值 社会意义&#xff1a;新闻报道的首要任务…

【电源开发】输出电压纹波

输出电压纹波是什么 电压纹波指的是直流输出电压中一个交流部分 减小输出电压纹波的方法 调整输出端的电容值 提高开关电源的工作频率

R语言做图

目录 1. 图形参数 2. 低级图形 3. 部分高级图形 参考 1. 图形参数 图形参数用于设置图形中各种属性。 有些参数直接用在绘图函数内&#xff0c;如plot函数可以用 pch&#xff08;点样式&#xff09;、col&#xff08;颜色&#xff09;、cex&#xff08;文字符号大小倍数&…

Android SurfaceFlinger——概述(一)

一、基础介绍 SurfaceFlinger 是 Android 系统中的一个关键组件&#xff0c;负责管理屏幕显示的合成和渲染。 服务角色&#xff1a;SurfaceFlinger 作为一个系统服务独立运行&#xff0c;它不依赖于任何应用程序进程&#xff0c;而是由系统启动并持续运行。窗口管理&#xff1a…

用Flask定制指令上传Excel数据到数据库

用Flask定制指令上传Excel数据到数据库 假设现在有一张员工信息data.xlsx文件 使用SQLAlchemy创表 # ExcelModel.py from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.orm import DeclarativeBaseclass Base(DeclarativeBase):passclass Emp(…

《Windows API每日一练》4.6 矩形、区域和裁剪

在前面的4.3节中我们讲述了绘制矩形的API函数Rectangle和RoundRect。本节我们将介绍另外一组使用RECT矩形结构和区域的绘图函数。 本节必须掌握的知识点&#xff1a; 矩形 第28练&#xff1a;绘制随机矩形 矩形与区域的裁剪 第29练&#xff1a;区域裁剪 4.6.1 矩形 ■FillRe…

2025年计算机毕业设计题目参考-简单容易

2025年最新计算机毕业设计题目参考-第二批 以下可以参考 企业员工薪酬关系系统的设计 基于SpringBoot在线远程考试系统 SpringBootVue的乡政府管理系统 springboot青年公寓服务平台 springboot大学生就业需求分析系统 基于Spring Boot的疗养院管理系统 基于SpringBoot的房屋交…

堆优化版Dijkstra求最短路-java

主要通过堆优化Dijkstra算法解决最短路&#xff0c;可以跟朴素版的Dijkstra算法进行对比。 文章目录 前言 一、Dijkstra求最短路 二、算法思路 1.邻接表存储图 2.用小根堆优化Dijkstra 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入数据 3.代码运行…

高压线防外破警示灯在电力安全发挥的作用_鼎跃安全

高压输电线路往往跨越城市、乡村和野外&#xff0c;覆盖范围广泛。随着城乡建设和交通运输的快速发展&#xff0c;高压线路周围的活动频繁&#xff0c;外部破坏风险增加。车辆撞击电线杆、施工机械误碰线路以及人为破坏等事件时有发生&#xff0c;严重影响电力供应的稳定性和安…

人工智能--自然语言处理NLP概述

欢迎来到 Papicatch的博客 目录 &#x1f349;引言 &#x1f348;基本概念 &#x1f348;核心技术 &#x1f348;常用模型和方法 &#x1f348;应用领域 &#x1f348;挑战和未来发展 &#x1f349;案例分析 &#x1f348;机器翻译中的BERT模型 &#x1f348;情感分析在…

深入了解Java的ConcurrentHashMap类

深入了解Java的ConcurrentHashMap类 在多线程编程中&#xff0c;线程安全的数据结构至关重要。ConcurrentHashMap是Java提供的一种线程安全的哈希表实现&#xff0c;它在不使用显式同步的情况下允许并发的读取和写入操作。 ConcurrentHashMap属于java.util.concurrent包。它是…

19.Docker跨宿主机容器之间的通信macvlan

Docker跨宿主机容器之间的通信macvlan&#xff0c;类似桥接网络模式 macvlan通信类型&#xff0c;设置IP地址只能手动指定&#xff08;–ip&#xff09;一台一台设置IP地址 默认一个物理网卡&#xff0c;只有一个物理mac地址&#xff0c;虚拟多个mac地址&#xff08;让人感觉是…

【机器学习】第7章 集成学习(小重点,混之前章节出题但小题)

一、概念 1.集成学习&#xff0c;顾名思义&#xff0c;不是一个玩意&#xff0c;而是一堆玩意混合到一块。 &#xff08;1&#xff09;基本思想是先 生成一定数量基学习器&#xff0c;再采用集成策略 将这堆基学习器的预测结果组合起来&#xff0c;从而形成最终结论。 &#x…

C# 利用XejeN框架源码,编写一个在 Winform 界面上的语法高亮的编辑器,使用 Monaco 编辑器

析锦基于Monaco技术实现的Winform语法高亮编辑器 winform中&#xff0c;我们有时需要高亮显示基于某种语言的语法编辑器。 目前比较强大且UI现代化的&#xff0c;无疑是宇宙最强IDE的兄弟&#xff1a;VS Code。 类似 VS Code 的体验&#xff0c;可以考虑使用 Monaco Editor&a…

【机器学习】第6章 支持向量机(SVM)

一、概念 1.支持向量机&#xff08;support vector machine&#xff0c;SVM&#xff09;&#xff1a; &#xff08;1&#xff09;基于统计学理论的监督学习方法&#xff0c;但不属于生成式模型&#xff0c;而是判别式模型。 &#xff08;2&#xff09;支持向量机在各个领域内的…

【系统架构设计师】三、数据库系统(事务并发|封锁协议|数据库安全|商业智能|SQL语句)

目录 一、事务并发 1.1 事务概述 1.2 并发控制 1.3 封锁 1.3.1 X 封锁和 S 封锁 1.3.2 三级封锁协议 二、数据库安全 2.1 备份(转储)与恢复 2.2 备份分类 2.3 数据库故障 三、商业智能 3.1 数据仓库 3.2 数据仓库的结构-OLAP 3.3 数据挖掘 3.4 分布式数据库 四…

DS1302实时时钟芯片完整使用介绍(配合51单片机)

DS1302是一款由美国DALLAS Semiconductor公司&#xff08;现已被Maxim Integrated公司收购&#xff09;设计的高性能、低功耗的实时时钟集成电路。这款芯片因其简单易用的接口和丰富的功能&#xff0c;在嵌入式系统、消费电子、工业控制等多个领域得到广泛应用。 原理图 寄存器…

Vscode中的行尾序列CRLF/LF不兼容问题

最近开发的的时候&#xff0c;打开项目文件经常会出现爆红错误提示信息&#xff0c;显示如下图&#xff1a; 这东西太烦人了&#xff0c;毕竟谁都不希望在遍地都是爆红的代码里写东西&#xff0c;就像能解决这个问题&#xff0c;根据提示可以知道这是vscode中使用的prettier插件…

QT基础 - 布局管理器间隔控件

目录 一. QVBoxLayout 二. QHBoxLayout 三. QGridLayout 四. QFormLayout 五. Spacers 六.总结 一. QVBoxLayout QVBoxLayout 主要用于将控件在垂直方向上进行排列。 它具有以下特点&#xff1a; 可以方便地管理和组织控件&#xff0c;使其按照垂直顺序依次排列。能够自动…

数据治理平台报Invalid CORS request

文章目录 背景一、步骤1.修改治理conf配置文件 背景 问题描述&#xff1a;俩个域名&#xff08;都能进入同一个平台&#xff09;其中一个正常使用&#xff0c;另外一个无法进入 报错截图&#xff1a; *备注&#xff1a;本文主要从配置文件入手解决。 一、步骤 1.修改治理co…