大模型WebUI:Gradio全解系列8——Additional Features:补充特性(上)

大模型WebUI:Gradio全解系列8——Additional Features:补充特性(上)

  • 前言
  • 本篇摘要
  • 8. Additional Features:补充特性
    • 8.1 队列
      • 8.1.1 使用方法
      • 8.1.2 配置队列演示
    • 8.2 输入输出流
      • 8.2.1 输出流
        • 1. 生成器yield
        • 2. 流媒体
      • 8.2.2 输入流
        • 1. 流事件
        • 2. 图像滤镜
      • 8.2.3 统一的输入输出流
      • 8.2.4 跟踪过去的输入或输出
    • 8.3 提示及进度条
      • 8.3.1 提示
      • 8.3.2 进度条
    • 8.4 批处理函数
      • 8.4.1 Interface与Blocks演示
      • 8.4.2 diffusers库与批处理
    • 参考文献

前言

本系列文章主要介绍WEB界面工具Gradio。Gradio是Hugging Face发布的简易webui开发框架,它基于FastAPI和svelte,便于部署人工智能模型,是当前热门的非常易于开发和展示机器学习大语言模型LLM及扩散模型DM的UI框架。本系列文章分为前置概念和实战演练两部分。前置概念先介绍Gradio的详细技术架构、历史、应用场景、与其他框架Gradio/NiceGui/StreamLit/Dash/PyWebIO的区别,然后详细介绍了大模型及数据的资源网站Hugging Face,包括三种资源models/datasets/spaces、六类开源库transformers/diffusers/datasets/PEFT/accelerate/optimum实战。实战演练部分先讲解了多种不同的安装、运行和部署方式,安装包括Linux/Win/Mac三类系统安装,运行包括普通方式和热重载方式,部署包括本地部署、HuggingFace托管、FastAPI挂载和Gradio-Lite浏览器集成;然后按照先整体再细节的逻辑,讲解Gradio的多种高级特性:三种Gradio Clients(python/javascript/curl)、Gradio Tools、Gradio的模块架构和环境变量等,方便读者对Gradio整体把握;最后深入细节,也是本系列文章的核心,先实践基础功能Interface、Blocks和Additional Features,再详解高级功能Chatbots、Data Science And Plots和Streaming。本系列文章注解详细,代码均可运行并附有大量运行截图,方便读者理解,Gradio一定会成为每个技术人员实现奇思妙想的最称手工具。

本系列文章目录如下:

  1. 《Gradio全解系列1——Gradio简介》
  2. 《Gradio全解系列1——Gradio的安装与运行》
  3. 《Gradio全解系列2——Gradio的3+1种部署方式实践》
  4. 《Gradio全解系列2——浏览器集成Gradio-Lite》
  5. 《Gradio全解系列3——Gradio Client:python客户端》
  6. 《Gradio全解系列3——Gradio Client:javascript客户端》
  7. 《Gradio全解系列3——Gradio Client:curl客户端》
  8. 《Gradio全解系列4——Gradio Tools:将Gradio用于LLM Agents》
  9. 《Gradio全解系列5——Gradio库的模块架构和环境变量》
  10. 《Gradio全解系列6——Interface:高级抽象界面类(上)》
  11. 《Gradio全解系列6——Interface:高级抽象界面类(下)》
  12. 《Gradio全解系列7——Blocks:底层区块类(上)》
  13. 《Gradio全解系列7——Blocks:底层区块类(下)》
  14. 《Gradio全解系列8——Additional Features:补充特性(上)》
  15. 《Gradio全解系列8——Additional Features:补充特性(下)》
  16. 《Gradio全解系列9——Chatbots:聊天机器人(上)》
  17. 《Gradio全解系列9——Chatbots:聊天机器人(下)》
  18. 《Gradio全解系列10——Data Science And Plots:数据科学与绘图》
  19. 《Gradio全解系列11——Streaming:数据流(上)》
  20. 《Gradio全解系列11——Streaming:数据流(下)》

本篇摘要

本篇介绍Gradio的其它附加功能,这些功能辅助Interface/Blocks实现更绚丽效果和更多功能。本章附加功能主要包括队列、输入输出流、提示及进度条、批处理函数、安全访问文件和资源清理,下面逐一讲述。

8. Additional Features:补充特性

本篇介绍Gradio的其它附加功能,这些功能辅助Interface/Blocks实现更绚丽效果和更多功能。本章附加功能主要包括队列、输入输出流、提示及进度条、批处理函数、安全访问文件和资源清理,下面逐一讲述。

8.1 队列

每个Gradio程序提供了一个内置的队列系统,可以处理数千个并发用户。由于许多事件监听器可能涉及繁重的处理任务,Gradio 会自动为每个事件监听器创建一个队列来处理后端的事件,因此每个事件监听器都会自动拥有一个队列来处理传入的事件。

8.1.1 使用方法

如果函数推理时间较长(比如目标检测),或者应用程序处理流量过大,则需要使用queue方法进行排队。queue方法使用websockets,可以防止网络超时,通过启用队列,可以控制用户在队列中的位置。

队列使用方式如下:

demo = gr.Interface(...).queue()
demo.launch()
#或
with gr.Blocks() as demo:
    #...
demo.queue()
demo.launch()

以Blocks为例,演示如下:

with gr.Blocks() as demo:
    button = gr.Button(label="Generate Image")
    button.click(fn=image_generator, inputs=gr.Textbox(), outputs=gr.Image())
demo.queue(max_size=10)
demo.launch()

8.1.2 配置队列演示

每个事件监听器默认都有自己的队列,一次处理一个请求,但可以通过事件监听器的两个参数进行配置:

  • concurrency_limit:设置事件监听器的最大并发执行数。默认情况下限制为 1,除非在 Blocks.queue() 中的参数default_concurrency_limit另行配置。你也可以将其设置为None以表示无限制(即无限数量的并发执行);
  • concurrency_id:允许事件监听器通过分配相同的ID来共享队列。当使用共享队列管理多个事件监听器时,使用concurrency_id指定队列,例如如果你的设置中只有2个GPU,但多个函数需要访问GPU访问,此时可以为所有这些函数创建一个共享队列。

两个参数的设置示例如下:

import gradio as gr

with gr.Blocks() as demo:
    prompt = gr.Textbox()
    image = gr.Image()
    generate_btn_1 = gr.Button("Generate Image via model 1")
    generate_btn_2 = gr.Button("Generate Image via model 2")
    generate_btn_3 = gr.Button("Generate Image via model 3")
    generate_btn_1.click(image_gen_1, prompt, image, concurrency_limit=2, concurrency_id="gpu_queue")
    generate_btn_2.click(image_gen_2, prompt, image, concurrency_id="gpu_queue")
    generate_btn_3.click(image_gen_3, prompt, image, concurrency_id="gpu_queue")

在这个例子中,所有三个事件监听器共享一个标识为 “gpu_queue” 的队列。该队列最多可以同时处理 2 个并发请求,额外的请求将被排队,直到有可用的槽位。这些配置易于Gradio管理队列行为。注意事项:

  1. 要确保事件监听器的并发无限制,可以将 concurrency_limit设置为None,这在用户函数调用外部 API(该API自行处理请求的速率限制)时非常有用。
  2. 所有队列的默认并发限制可以使用Blocks.queue()中的default_concurrency_limit参数全局设置。

8.2 输入输出流

对于图像、音频、视频等文件,需要用流进行操作,本节通过讲述输出流、输入流、统一的输入输出流以及跟踪流等,让大家掌握如何处理多媒体文件。

8.2.1 输出流

在某些情况下,我们需要流式输出一系列结果,而不是一次性显示单个输出。例如,某个图像生成模型希望显示每一步生成的图像,直到最终图像生成;或者某个聊天机器人,它逐词流式输出响应,而不是一次性返回所有内容。在这种情况下,可以向Gradio提供一个生成器函数。

1. 生成器yield

在Python中创建生成器非常简单:通常yield语句会放在某种循环中,该函数不是返回单个值,而是生成一系列值。可以像提供常规函数一样向Gradio提供生成器。

例如,以下是一个模拟的图像生成模型,它在输出图像之前生成若干步噪声,使用gr.Interface类进行演示:

import gradio as gr
import numpy as np
import time

def fake_diffusion(steps):
    rng = np.random.default_rng()
    for i in range(steps):
        time.sleep(1)
        image = rng.random(size=(600, 600, 3))
        yield image
    image = np.ones((1000,1000,3), np.uint8)
    image[:] = [255, 124, 0]
    yield image

demo = gr.Interface(fake_diffusion,
                    inputs=gr.Slider(1, 10, 3, step=1),
                    outputs="image")

demo.launch()

运行截图如下:
在这里插入图片描述
请注意,我们在迭代器中添加了 time.sleep(1),它在步骤之间创建一个人为的暂停,这样就能够观察到迭代器的每一步。但在真实的图像生成模型中,这可能是不必要的。

Gradio同样可以处理输入流,例如,每当用户在文本框中输入一个字母时,图像生成模型都会重新运行。这在关于构建响应式界面的中有更详细的介绍,请参考Interface章节中关于实时Interface的讲解。

2. 流媒体

Gradio可以直接从生成器函数中流式输出音频和视频,这让用户几乎在函数生成音频或视频的同时就能听到或看到。实现流式媒体只需执行以下操作:

  1. 在 gr.Audio 或 gr.Video 输出组件中设置 streaming=True,图像自动转换为 base64 格式;
  2. 编写一个 Python 生成器,生成下一个音频或视频的“chunk”块;
  3. 设置 autoplay=True,以便媒体自动开始播放。

对于音频,下一个“块”可以是 .mp3 或 .wav 文件,也可以是音频的字节序列。对于视频,下一个“块”必须是 .mp4 文件或使用 h.264 编解码器且扩展名为 .ts 的文件。为了确保流畅播放,请确保每个块的长度一致且大于 1 秒。

我们将通过一些简单的示例来说明这些要点,以音频为例:

import gradio as gr
from time import sleep

def keep_repeating(audio_file):
    for _ in range(10):
        sleep(0.5)
        yield audio_file

gr.Interface(keep_repeating,
             gr.Audio(sources=["microphone"], type="filepath"),
             gr.Audio(streaming=True, autoplay=True)
).launch()

运行后点击submit,输出与输入同步播放,截图如下:
在这里插入图片描述
同样也可以视频为例,只需将gr.Audio替换为gr.Video即可:gr.Video(sources=["webcam"], format="mp4"),设置也一样,不再重复。关于流的端到端演示请参考后续的数据流章节。

8.2.2 输入流

在上一小节中,我们介绍了如何从事件处理程序中流式输出一系列结果。Gradio还可以将用户摄像头中的图像或麦克风中的音频块流式输入到事件处理程序中,这可以用于创建实时对象检测应用程序或使用Gradio构建对话式聊天应用。

1. 流事件

目前,gr.Image 和 gr.Audio 组件支持通过 stream 事件实现输入流。比如创建一个最简单的流式应用程序,直接返回未修改的网络摄像头流:

import gradio as gr

with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            input_img = gr.Image(label="Input", sources="webcam")
        with gr.Column():
            output_img = gr.Image(label="Output")
        input_img.stream(lambda s: s, input_img, output_img, time_limit=15, stream_every=0.1, concurrency_limit=30)

if __name__ == "__main__":
    demo.launch()

运行截图如下:
在这里插入图片描述
可以自己运行看一下效果。当用户开始录制时,stream 事件会被触发。底层逻辑是网络摄像头每 0.1 秒拍摄一张照片并将其发送到服务器,然后服务器会返回该图像。

stream 事件有两个独特的关键字参数:

  • time_limit:这是 Gradio 服务器处理事件的时间限制。多媒体流本质上是无限制的,因此设置时间限制非常重要,以防止一个用户长期占用 Gradio 队列。时间限制仅计算处理流所花费的时间,不包括在队列中等待的时间。输入图像底部显示的橙色条表示剩余时间。当时间限制到期时,用户将自动重新加入队列。
  • stream_every:这是流捕获输入并将其发送到服务器的频率(以秒为单位)。对于图像检测或处理等演示,设置较小的值可以实现“real-time”实时效果。对于语音转录等演示,较高的值更有用,因为可以使转录算法可以更好地理解上下文。
2. 图像滤镜

本节创建一个图像滤镜演示,用户可以选择多种应用于网络摄像头输入流的滤镜,滤镜种类包括边缘检测滤镜、卡通滤镜,或者简单地垂直翻转流滤镜。代码如下:

import gradio as gr
import numpy as np
import cv2

def transform_cv2(frame, transform):
    if transform == "cartoon":
        # prepare color
        img_color = cv2.pyrDown(cv2.pyrDown(frame))
        for _ in range(6):
            img_color = cv2.bilateralFilter(img_color, 9, 9, 7)
        img_color = cv2.pyrUp(cv2.pyrUp(img_color))

        # prepare edges
        img_edges = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
        img_edges = cv2.adaptiveThreshold(
            cv2.medianBlur(img_edges, 7),
            255,
            cv2.ADAPTIVE_THRESH_MEAN_C,
            cv2.THRESH_BINARY,
            9,
            2,
        )
        img_edges = cv2.cvtColor(img_edges, cv2.COLOR_GRAY2RGB)
        # combine color and edges
        img = cv2.bitwise_and(img_color, img_edges)
        return img
    elif transform == "edges":
        # perform edge detection
        img = cv2.cvtColor(cv2.Canny(frame, 100, 200), cv2.COLOR_GRAY2BGR)
        return img
    else:
        return np.flipud(frame)

with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            transform = gr.Dropdown(choices=["cartoon", "edges", "flip"],
                                    value="flip", label="Transformation")
            input_img = gr.Image(sources=["webcam"], type="numpy")
        with gr.Column():
            output_img = gr.Image(streaming=True)
        dep = input_img.stream(transform_cv2, [input_img, transform], [output_img],
                                time_limit=30, stream_every=0.1, concurrency_limit=30)

demo.launch()

运行后选择边缘检测滤镜,截图如下:
在这里插入图片描述
需要注意的是:

  1. 当更改滤镜值时,它会立即在输出流中生效。这是流事件与其他 Gradio 事件的一个重要区别:在处理流的过程中,可以更改流相关的输入值并立即生效。
  2. 我们将图像输出组件的 streaming 参数设置为True,这样可以让服务器自动将输出图像转换为 base64 格式,这是一种适合流高效传输的格式。

8.2.3 统一的输入输出流

对于一些图像流式传输演示(如上面的示例),我们不需要分别显示输入和输出组件,只显示修改后的输出流,应用程序看起来会更简洁。

我们可以通过将输入图像组件指定为流事件的输出来实现这一点,省略重复代码,另外加入一些CSS格式,核心代码如下:

css=""".my-group {max-width: 500px !important; max-height: 500px !important;}
            .my-column {display: flex !important; justify-content: center !important; align-items: center !important};"""

with gr.Blocks(css=css) as demo:
    with gr.Column(elem_classes=["my-column"]):
        with gr.Group(elem_classes=["my-group"]):
            transform = gr.Dropdown(choices=["cartoon", "edges", "flip"],
                                    value="flip", label="Transformation")
            input_img = gr.Image(sources=["webcam"], type="numpy", streaming=True)
    input_img.stream(transform_cv2, [input_img, transform], [input_img], time_limit=30, stream_every=0.1)

demo.launch()

运行截图如下:
在这里插入图片描述

8.2.4 跟踪过去的输入或输出

通常流式函数应该是无状态的,它应该接受当前输入并返回相应的输出。然而在某些情况下,可能希望跟踪过去的输入或输出。例如可能希望在缓冲区保留前 k 个输入,以提高音频转录演示的准确性。可以使用 Gradio 的 gr.State()组件来实现这一点,示例如下:

def transcribe_handler(current_audio, state, transcript):
    next_text = transcribe(current_audio, history=state)
    state.append(current_audio)
    # 保留前3个输入
    state = state[-3:]
    return state, transcript + next_text

with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            mic = gr.Audio(sources="microphone")
            state = gr.State(value=[])
        with gr.Column():
            transcript = gr.Textbox(label="Transcript")
    mic.stream(transcribe_handler, [mic, state, transcript], [state, transcript],
               time_limit=10, stream_every=1)

demo.launch()

8.3 提示及进度条

当程序运行出现状况时,如何告知用户,以及让用户知道等待时间,这就用到提示和进度条。

8.3.1 提示

提示组件分为三类:gr.Error()、 gr.Warning() 和gr.Info() 。我们希望向用户显示提示错误信息,为此可以在函数中抛出 gr.Error(“自定义消息”) ,这时函数停止执行并向用户显示错误信息。

我们还可以通过在函数中单独使用 gr.Warning(“自定义消息”) 或 gr.Info(“自定义消息”) 来立即显示模态框,同时继续执行函数。gr.Info() 和 gr.Warning() 之间的唯一区别是提示框的颜色。演示如下:

import gradio as gr
from functools import partial

with gr.Blocks() as demo:
    with gr.Row():
        duration = gr.Number(label="Duration", info="Set to -1 for infinite", value=10, minimum=-1)
    with gr.Row():
        error = gr.Button("Error")
        info = gr.Button("Info")
        warning = gr.Button("Warning")

    def display_message(type, msg, duration):
        duration = None if duration < 0 else duration
        if type == "error":
            raise gr.Error(msg, duration=duration)
        elif type == "info":
            gr.Info(msg, duration=duration)
        elif type == "warning":
            gr.Warning(msg,  duration=duration)

    error.click(partial(display_message, "error", "ERROR 💥"),  [duration])
    info.click(partial(display_message, "info", "INFO ℹ️"), [duration])
    warning.click(partial(display_message, "warning", "WARNING ⚠️"), [duration])

运行结果如下:
在这里插入图片描述
提示:请注意gr.Error()是一个必须引发的异常,而gr.Warning()gr.Info()可以让函数继续运行。

8.3.2 进度条

Gradio 支持创建自定义进度条,可以自定义和控制进度更新,以便向用户展示。要启用此功能,只需在方法中添加一个参数,该参数的默认值为 gr.Progress 实例;然后通过直接调用此实例并传入一个介于 0 和 1 之间的浮点数来更新进度,或者使用 Progress 实例的 tqdm() 方法来跟踪可迭代对象的进度,演示如下:

import gradio as gr
import time

def slowly_reverse(word, progress=gr.Progress()):
    progress(0, desc="Starting")
    time.sleep(1)
    progress(0.05)
    new_string = ""
    for letter in progress.tqdm(word, desc="Reversing"):
        time.sleep(0.25)
        new_string = letter + new_string  
    return new_string

demo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())
demo.launch()

运行截图如下:
在这里插入图片描述
如果使用 tqdm 库,甚至可以通过将gr.Progress()的参数track_tqdm设置为True,自动从任意函数中已存在的 tqdm.tqdm 报告进度更新!

8.4 批处理函数

Gradio 支持传入批处理函数,批处理函数是指接收输入列表并返回预测列表的函数。使用批处理函数的优势在于:如果启用了队列,Gradio服务器将传入的请求进行自动批处理和并行处理,从而可能加快演示执行速度。

8.4.1 Interface与Blocks演示

例如,下面演示是一个批处理函数,它接收两个输入列表(一个单词列表和一个整数列表),并返回一个修剪后的单词列表作为输出:

import gradio as gr
import time

def trim_words(words, lens):
    trimmed_words = []
    time.sleep(5)
    for w, l in zip(words, lens):
        trimmed_words.append(w[:int(l)])
    return [trimmed_words]

以下是 Gradio 代码示例(注意 batch=True 和 max_batch_size=16),使用gr.Interface:

gr.Interface(fn=image_classifier, inputs="image", outputs="label")
demo = gr.Interface(
    fn=trim_words, 
    inputs=["textbox", "number"], 
    outputs=["label"],
    batch=True, 
    max_batch_size=16
)

demo.launch()

运行界面如下:
在这里插入图片描述
使用gr.Blocks:

with gr.Blocks() as demo:
    with gr.Row():
        word = gr.Textbox(label="word")
        leng = gr.Number(label="leng")
        output = gr.Textbox(label="Output")
    with gr.Row():
        run = gr.Button()

    event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)

demo.launch()

在这里插入图片描述
在上面的示例中,可以并行处理 16 个请求(总推理时间为 5 秒),而不是每个请求单独处理(总推理时间为 80 秒)。

8.4.2 diffusers库与批处理

Hugging Face 的库 transformers 和 diffusers 中许多模型与 Gradio 的批处理模式可以非常自然地配合使用,比如下面是一个使用 diffusers 批量生成图像的示例演示:

import torch
from diffusers import DiffusionPipeline  # type: ignore
import gradio as gr

generator = DiffusionPipeline.from_pretrained("CompVis/ldm-text2im-large-256")
# move to GPU if available
if torch.cuda.is_available():
    generator = generator.to("cuda")

def generate(prompts):
  images = generator(list(prompts)).images  # type: ignore
  return [images]

demo = gr.Interface(generate,
             "textbox",
             "image",
             batch=True,
             max_batch_size=4  # Set the batch size based on your CPU/GPU memory
)

if __name__ == "__main__":
    demo.launch()

此处由于版本问题和引入库torch,可能出现错误提示,我们主要从代码理解批处理的使用方法即可,是否运行成功不必强求。

参考文献

  1. Gradio - guides - Additional Features

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

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

相关文章

leetcode 2658. 网格图中鱼的最大数目

题目如下 数据范围 使用并查集来做这道题。 其实按照题目的意思就是让我们求每一个联通的水域可以捞到的最大权值。 我们可以从前往后遍历这个二维数组只需要判断前一个水域和上一个水域是否和当前的(i, j)联通如果有则合并水域&#xff0c;同时用一个weight数组保存每一个联…

【go每日一题】golang异常、错误 {源码、实践、总结}

错误与异常在golang中区分 Go 的错误处理设计与其他语言的异常不同。Go 中的 error 就是一个普通的值对象&#xff0c;而其他语言如 Java 中的 Exception 将会造成程序控制流的终止和其他行为&#xff0c;Exception 与普通的值不同。虽然 Go 也有类似的异常机制 —— panic&am…

大模型 Fine-Tuning 技术解析

引言 在大型语言模型&#xff08;LLMs, Large Language Models&#xff09;的发展历程中&#xff0c;预训练模型和微调&#xff08;Fine-tuning&#xff09;技术起到了至关重要的作用。这些技术使得模型不仅能够学习到丰富的语言特征&#xff0c;还能根据具体任务进行优化调整…

LabVIEW开发中常见硬件通讯接口快速识别

在 LabVIEW 开发中&#xff0c;与硬件进行通讯是实现数据采集与控制的重要环节。准确判断通讯接口类型和协议&#xff0c;可以提高开发效率&#xff0c;减少调试时间。本文结合 LabVIEW 的实际应用&#xff0c;详细介绍如何识别和判断常见硬件通讯接口的定义&#xff0c;并提供…

抖音短视频矩阵系统源码开发全流程解析

在项目开发过程中&#xff0c;调整配置文件至关重要&#xff0c;这些文件包括数据库连接、API密钥及全局参数等。通过正确配置这些信息&#xff0c;可确保应用程序的稳定性和安全性。灵活调整配置以适应具体需求有助于短视频矩阵系统项目的顺利推进。 在开发环境中&#xff0c…

Unity功能模块一对话系统(4)实现个性文本标签

本期我们将了解如何在TMPro中自定义我们的标签样式&#xff0c;并实现两种有趣的效果。 一.需求描述 1.定义<float>格式的标签&#xff0c;实现标签处延迟打印功能 2.定义<r" "></r>格式的标签&#xff0c;实现标签区间内文本片段的注释显示功能…

深度学习实战自动驾驶目标识别

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对BDD100K自动驾驶目标数据集进行训练和优化&#xff0c;该数据集包含丰富的自动驾…

广西大数据局:数聚政府、利企惠民(广西数字政府建设内容、管理机制、应用场景)

2023年数字政府评估大会上&#xff0c;广西大数据局党委书记、主任周飞发表了题为“数聚政府、利企惠民”的主旨演讲。主要介绍了广西壮族自治区“数字政府的建设内容、数字政府的管理机制以及数字政府有哪些应用场景来实现惠企利民”。 篇幅限制&#xff0c;部分内容如下&…

AI 助力游戏开发中的常用算法实现

在当今的游戏开发领域&#xff0c;人工智能&#xff08;AI&#xff09;技术的应用已经成为推动行业发展的关键力量。AI不仅能够提升游戏的智能化水平&#xff0c;还能够增强玩家的沉浸感和游戏体验。随着技术的进步&#xff0c;AI在游戏设计、开发和测试中的应用越来越广泛&…

行业商机信息付费小程序系统开发方案

行业商机信息付费小程序系统&#xff0c;主要是整合优质行业资源&#xff0c;实时更新的商机信息。在当今信息爆炸的时代&#xff0c;精准、高效地获取行业商机信息对于企业和个人创业者而言至关重要。 一、使用场景 日常浏览&#xff1a;用户在工作间隙或闲暇时间&#xff0c…

LabVIEW 中 NI Vision 模块的IMAQ Create VI

IMAQ Create VI 是 LabVIEW 中 NI Vision 模块&#xff08;NI Vision Development Module&#xff09;的一个常用 VI&#xff0c;用于创建一个图像变量。该图像变量可以存储和操作图像数据&#xff0c;是图像处理任务的基础。 ​ 通过以上操作&#xff0c;IMAQ Create VI 是构建…

[AI] 深度学习的“黑箱”探索:从解释性到透明性

目录 1. 深度学习的“黑箱”问题&#xff1a;何为不可解释&#xff1f; 1.1 为什么“黑箱”问题存在&#xff1f; 2. 可解释性研究的现状 2.1 模型解释的方法 2.1.1 后置可解释性方法&#xff08;Post-hoc Explanations&#xff09; 2.1.2 内在可解释性方法&#xff08;I…

UnityRenderStreaming使用记录(四)

测试把UnityRenderStreaming部署在docker&#xff0c;剧透一下&#xff0c;嘎了…… 当然webserver运行的妥妥的 那么打包出的程序运行log Mono path[0] /home/unity/Broadcast/Broadcast_Data/Managed Mono config path /home/unity/Broadcast/Broadcast_Data/MonoBleedingE…

javaEE-文件操作和IO-文件

目录 一.什么是文件 1.文件就是硬盘(磁盘)上的文件。 2.计算机中存储数据的设备&#xff1a; 3.硬盘的物理特征 4.树型结构组织和⽬录 5.文件路径 文件路径有两种表示方式&#xff1a; 6.文件的分类 二、java中文件系统的操作 1.File类中的属性&#xff1a; 2.构造方…

SqlSession的线程安全问题源码分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 SqlSession 是线程安全的吗&#xff1f;为什么说是线程不安全的&#xff1f;事务管理问题 数据库连接的共享问题 一级缓存线程安全问题…

拆解 Web3:探寻去中心化网络的核心密码

近年来&#xff0c;Web3频繁出现在技术讨论中&#xff0c;被视为互联网发展的下一阶段。那么&#xff0c;Web3究竟是什么&#xff1f;它如何区别于传统互联网&#xff0c;又将为未来的网络带来哪些新的可能&#xff1f;本文将从科普的角度拆解Web3的核心密码&#xff0c;揭开它…

《Vue3实战教程》37:Vue3生产部署

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 生产部署​ 开发环境 vs. 生产环境​ 在开发过程中&#xff0c;Vue 提供了许多功能来提升开发体验&#xff1a; 对常见错误和隐患的警告对组件 props / 自定义事件的校验响应性调试钩子开发工具集成 然而&#xff…

Ruby自动化:用Watir库获取YouTube视频链接

引言 Watir&#xff08;Web Application Testing in Ruby&#xff09;是一个强大的工具&#xff0c;它允许开发者使用Ruby语言来自动化控制浏览器。Watir最初被设计用于自动化Web应用测试&#xff0c;但其功能远不止于此。通过Watir&#xff0c;我们可以模拟用户行为&#xff…

[CTF/网络安全] 攻防世界 warmup 解题详析

查看页面源代码&#xff0c;发现source.php 得到一串代码&#xff0c;进行代码审计&#xff1a; <?phpclass emmm{public static function checkFile(&$page){$whitelist ["source">"source.php","hint">"hint.php"];…

solr9.7 单机安装教程

1.环境要求:jdk11以上 2.下载wget https://dlcdn.apache.org/solr/solr/9.7.0/solr-9.7.0.tgz 3.解压 4.修改solr.in.sh配置 5.启动命令 bin/solr start 6.创建core bin/solr create -c <core名称> 注意:用solr ui界面创建&#xff0c;会提示找不到solrconfig.xml和m…