【Gradio】Custom Components | Gradio组件关键概念 后端

Gradio组件关键概念

在本节中,我们将讨论Gradio中组件的一些重要概念。在开发自己的组件时,理解这些概念非常重要。否则,您的组件可能会与其他Gradio组件的行为大不相同!

✍️ 提示:如果你熟悉Gradio库的内部机制,例如每个组件的预处理(preprocess)和后处理(postprocess)方法,你可以跳过这一节。

交互式 vs 静态

Gradio中的每个组件都有一个静态变体,大多数也有一个交互式版本。当组件显示一个值,并且用户不能通过与之交互来更改该值时,使用静态版本。当用户能够通过与Gradio UI交互来更改值时,使用交互式版本。

让我们看一些例子:

# 导入gradio库
import gradio as gr# 创建一个Blocks界面
with gr.Blocks() as demo:# 创建一个可交互的文本框gr.Textbox(value="Hello", interactive=True)# 创建一个静态文本框gr.Textbox(value="Hello", interactive=False)# 启动demo界面
demo.launch()

这将显示两个文本框。唯一的区别:你将能够编辑顶部的Gradio组件的值,而底部的变体将无法编辑(即文本框将被禁用)。

也许更有趣的例子是Image组件:

# 导入gradio库
import gradio as gr# 创建一个Blocks界面
with gr.Blocks() as demo:# 创建一个可交互的图片组件gr.Image(interactive=True)# 创建一个静态图片组件gr.Image(interactive=False)# 启动demo界面
demo.launch()

组件的交互式版本要复杂得多 — 你可以上传图片或者从你的摄像头拍照 — 而静态版本只能用来显示图片。

并非每个组件都有一个明显的交互式版本。例如,gr.AnnotatedImage仅作为静态版本出现,因为没有方法可以交互式地更改注解或图片的值。

你需要记住的

如果组件被用作任何事件的输入,Gradio将使用该组件的交互式版本(如果可用);否则,将使用静态版本。

当你设计自定义组件时,你必须在Python类的构造函数中接受布尔值关键字interactive。在前端,你可能接受interactive属性,一个表示组件应该是静态还是交互式的布尔值。如果你在前端不使用这个属性,组件在交互式或静态模式下将看起来相同。

值以及它是如何被预处理/后处理的

组件最重要的属性是它的值。每个组件都有一个值。这个值通常由前端的用户设置(如果组件是交互式的)或显示给用户(如果它是静态的)。同时,当用户触发事件时,这个值也会发送到后端函数,或者在预测结束时由用户的函数返回。

所以这个值在很多地方被传递,但有时这个值的格式需要在前端和后端之间改变。看这个例子:

# 导入numpy和gradio库
import numpy as np
import gradio as gr# 定义一个将图片转换为sepia色调的函数
def sepia(input_img):sepia_filter = np.array([[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]])sepia_img = input_img.dot(sepia_filter.T)sepia_img /= sepia_img.max()return sepia_img# 创建一个接受并返回图片的Gradio应用
demo = gr.Interface(sepia, gr.Image(shape=(200, 200)), "image")
# 启动demo应用
demo.launch()

这将创建一个Gradio应用,该应用有一个Image组件作为输入和输出。在前端,Image组件实际上会将文件上传到服务器并发送文件路径,但这在发送给用户的函数之前被转换为numpy数组。反过来,当用户从他们的函数返回一个numpy数组时,numpy数组被转换为文件,这样它就可以被发送到前端并由Image组件显示。

提示:默认情况下, Image 组件会将 numpy 数组发送到 python 函数,因为这是机器学习工程师的常用选择,尽管 Image 组件也支持使用 type 参数的其他格式。阅读 Image 文档了解更多信息。

每个组件都做两次转换:

  • preprocess:将值从前端发送的格式转换为Python函数期望的格式。这通常涉及从一个Web友好的JSON结构转换为一个Python原生数据结构,如numpy数组或PIL图像。Audio、Image组件是preprocess方法的好例子。

  • postprocess:将Python函数返回的值转换为前端期望的格式。这通常涉及从一个Python原生数据结构,如PIL图像转换为一个JSON结构。

你需要记住的

每个组件必须实现preprocesspostprocess方法。在罕见的事件中,如果不需要发生任何转换,简单地返回值即可。Textbox和Number是这种情况的例子。

作为组件作者,你控制前端显示的数据格式以及使用你的组件的人将接收的数据格式。想想一个Python开发者会觉得直观的人体工程学数据结构,并控制从一个Web友好的JSON数据结构(反之亦然)的转换,通过preprocesspostprocess

组件的“examples版本”

Gradio应用支持提供示例输入 — 这些在帮助用户开始使用你的Gradio应用时非常有用。在gr.Interface中,你可以使用examples关键字提供示例,在Blocks中,你可以使用特殊的gr.Examples组件提供示例。

在这个屏幕截图的底部,我们展示了一个小型的猎豹示例图片,当点击时,将在输入Image组件中填充相同的图片:

953d24c1b3797e190e52cb04b86215c6.png

要启用示例视图,您必须在 frontend 目录的顶部拥有以下两个文件:

  • Example.svelte:这对应于你的组件的“示例版本”

  • Index.svelte:这对应于“常规版本”

在后端,你通常不需要做任何事情。用户提供的示例值会使用前面描述的相同的.postprocess()方法进行处理。如果你想以不同的方式处理数据(例如,如果.postprocess()方法计算成本很高),那么你可以为你的自定义组件编写你自己的.process_example()方法,这将被使用。

Example.svelte文件和process_example()方法将在专门的前端https://www.gradio.app/guides/frontend和后端https://www.gradio.app/guides/backend指南中更深入地介绍。

你需要记住的

如果你期望你的组件被用作输入,定义一个“示例”视图很重要。

如果你不这样做,Gradio将使用一个默认的,但它不会像它可以的那样信息丰富!

结论

现在你知道了关于Gradio组件最重要的几点,你就可以开始设计和构建你自己的了!

配置您的自定义组件

自定义组件工作流程专注于约定优于配置,以减少您作为开发人员在开发自定义组件时需要做出的决策数量。话虽如此,您仍然可以配置自定义组件包和目录的某些方面。本指南将介绍如何操作。

 包名称 

默认情况下,所有自定义组件包都称为 gradio_<component-name> ,其中 component-name 是组件的 python 类的小写名称。

作为一个例子,让我们演示一下如何将一个组件的名称从 gradio_mytextbox 更改为 supertextbox 

  1. 修改 pyproject.toml 文件中的 name 。

[project]
name = "supertextbox"
  1. 将 pyproject.toml 中所有的 gradio_<component-name> 更改为 <component-name>

[tool.hatch.build]
artifacts = ["/backend/supertextbox/templates", "*.pyi"][tool.hatch.build.targets.wheel]
packages = ["/backend/supertextbox"]
  1. 将 backend/ 中的 gradio_<component-name> 目录重命名为 <component-name>

mv backend/gradio_mytextbox backend/supertextbox

✍️ 提示:记得更改`demo/app.py`中的导入语句!

顶级 Python 导出 

默认情况下,只有自定义组件的 python 类是顶级导出。这意味着当用户输入 from gradio_<component-name> import ... 时,唯一可用的类是自定义组件类。要添加更多类作为顶级导出,请修改 __all__ 属性在 __init__.py

from .mytextbox import MyTextbox
from .mytextbox import AdditionalClass, additional_function__all__ = ['MyTextbox', 'AdditionalClass', 'additional_function']

Python 依赖项 

您可以通过修改 dependencies 键在 pyproject.toml 中来添加 python 依赖项

dependencies = ["gradio", "numpy", "PIL"]

✍️ 提示:添加依赖项时记得运行 `gradio cc install`!

JavaScript 依赖项 

你可以通过修改 frontend/package.json 中的 "dependencies" 键来添加 JavaScript 依赖项

"dependencies": {"@gradio/atoms": "0.2.0-beta.4","@gradio/statustracker": "0.3.0-beta.6","@gradio/utils": "0.2.0-beta.4","your-npm-package": "<version>"
}

目录结构 

默认情况下,CLI 会将 Python 代码放在 backend 中,将 JavaScript 代码放在 frontend 中。不建议更改此结构,因为这使得潜在的贡献者能够轻松查看您的源代码并知道一切所在。然而,如果你确实想要更改,这就是你需要做的:

  1. 将 Python 代码放在你选择的子目录中。记得修改 pyproject.toml 中的 [tool.hatch.build] [tool.hatch.build.targets.wheel] 以匹配!

  2. 将 JavaScript 代码放置在您选择的子目录中。

  3. 在组件 python 类上添加 FRONTEND_DIR 属性。它必须是从定义类的文件到 JavaScript 目录位置的相对路径。

class SuperTextbox(Component):FRONTEND_DIR = "../../frontend/"

JavaScript 和 Python 目录必须位于同一个公共目录下!

 结论 

坚持默认设置将使其他人更容易理解和贡献您的自定义组件。毕竟,开源的美妙之处在于任何人都可以帮助改进您的代码!但如果您需要偏离默认设置,您知道该怎么做!

后端 🐍

本指南将涵盖实现自定义组件后端处理所需了解的所有内容。

应继承哪个类 

所有组件都继承自三个类别中的一个 Component 、 FormComponent 或 BlockContext 。你需要从其中一个继承,以便你的组件像所有其他 gradio 组件一样运作。当你从带有 gradio cc create --template 的模板开始时,你不需要担心选择哪一个,因为模板会使用正确的类别。为了完整性,以及在你需要从头开始制作自己的组件时,我们解释了每个类别的用途。

  • FormComponent :当你想要你的组件与其他 FormComponents 在相同的 Form 布局中被分组在一起时使用。 Slider 、 Textbox 和 Number 组件都是 FormComponents 。

  • BlockContext :当你想要在你的组件"内部"放置其他组件时使用。这启用了 with MyComponent() as component: 语法。

  • Component :在所有其他情况下使用。

    ✍️ 提示:如果你的组件支持流式输出,请继承 StreamingOutput 类。

    ✍️ 提示:如果你继承自 BlockContext ,你也需要将元类设置为 ComponentMeta 。请参见下面的示例。

from gradio.blocks import BlockContext  #从gradio库的blocks模块导入BlockContext类
from gradio.component_meta import ComponentMeta  # 从gradio库的component_meta模块导入ComponentMeta类@document()  #一个装饰器,可能用于生成文档,但在这里没有给出实际实现
class Row(BlockContext, metaclass=ComponentMeta):  # 定义一个名为Row的类,继承自BlockContext,并使用ComponentMeta作为元类pass  # 类体部分为空,是一个空类定义

df388f6b7e496d8fe94880c129458534.png

你需要实现的方法 

当你继承这些类中的任何一个时,必须实现以下方法。否则当你实例化你的组件时,Python 解释器会抛出错误!

  preprocess 和 postprocess 

在关键概念指南中解释。它们处理从前端发送的数据到 Python 函数期望的格式的转换。

def preprocess(self, x: Any) -> Any:"""Convert from the web-friendly (typically JSON) value in the frontend to the format expected by the python function."""return xdef postprocess(self, y):"""Convert from the data returned by the python function to the web-friendly (typically JSON) value expected by the frontend."""return y

process_example

接收原始的 Python 值,并返回应在应用程序中的示例预览中显示的修改后的值。如果没有提供,将使用 .postprocess() 方法代替。让我们看看来自 SimpleDropdown 组件的以下示例。

def process_example(self, input_data):  # 定义一个名为process_example的函数,接受两个参数:self和input_data# 列表解析:对于self.choices中的每一个元素c(c是一个由两个元素组成的列表或元组),如果c的第二个元素(c[1])与输入数据(input_data)相等,则取出c的第一个元素(c[0])并组成一个新的列表# next函数:从上述列表解析生成的列表中取出第一个元素;如果列表为空(即没有元素c满足c[1] == input_data),则返回Nonereturn next((c[0] for c in self.choices if c[1] == input_data), None)

8feeb5d1e7a5b13dd4d71f5a18f5d744.png

由于 self.choices 是对应于( display_name , value )的元组列表,这将把用户提供的值转换为显示值(或者如果值不在 self.choices 中,它将被转换为 None )。

api_info

preprocess 期望的值的 JSON-schema 表示。这通过 gradio 客户端支持 api 使用。如果你的组件指定了一个 data_model ,你不需要自己实现这个。以下部分的 data_model 。

def api_info(self) -> dict[str, list[str]]:"""A JSON-schema representation of the value that the `preprocess` expects and the `postprocess` returns."""pass

example_payload

您组件的一个示例有效负载,例如,可以传递到组件的 .preprocess() 方法中的东西。示例输入显示在使用您的自定义组件的 Gradio 应用程序的 View API 页面上。必须是可 JSON 序列化的。如果您的组件期望一个文件,最好使用一个公开可访问的 URL。

def example_payload(self) -> Any:"""The example inputs for this component for API usage. Must be JSON-serializable."""pass

example_value

您组件的一个示例值,例如,可以传递给组件的 .postprocess() 方法的东西。这在自定义组件开发中创建的默认应用程序中用作示例值。

def example_payload(self) -> Any:"""The example inputs for this component for API usage. Must be JSON-serializable."""pass

flag

将组件的值写入可以存储在 csv 或 json 文件中用于标记的格式。如果您的组件指定了 data_model ,则无需自己实现此功能。以下部分中的 data_model 。

def flag(self, x: Any | GradioDataModel, flag_dir: str | Path = "") -> str:pass

read_from_flag

从存储在 csv 或 json 文件中的格式转换到组件的 python value 。如果你的组件指定了一个 data_model ,你不需要自己实现这个。以下部分的 data_model 。

def read_from_flag(self,x: Any,
) -> GradioDataModel | Any:"""Convert the data from the csv or jsonl file into the component state."""return x

The data_model

data_model 是您定义组件值将如何存储在前端的预期数据格式。它指定了您的 preprocess 方法期望的数据格式以及 postprocess 方法返回的格式。为您的组件定义一个 data_model 不是必需的,但它极大地简化了创建自定义组件的过程。如果您定义了一个自定义组件,您只需要实现四个方法- preprocess 、 postprocess 、 example_payload 和 example_value !

您通过定义一个从 GradioModel 或 GradioRootModel 继承的 pydantic 模型来定义 data_model 。

这最好通过一个例子来解释。让我们看看核心的 Video 组件,它将视频数据存储为一个带有两个键 video 和 subtitles 的 JSON 对象,这两个键指向不同的文件。

from gradio.data_classes import FileData, GradioModel  # 从gradio.data_classes模块中导入FileData和GradioModel类class VideoData(GradioModel):  # 定义一个名为VideoData的类,继承自GradioModelvideo: FileData  # video是一个FileData类型的属性,代表视频文件subtitles: Optional[FileData] = None  # subtitles是一个可选的FileData类型的属性,代表字幕文件,默认值为Noneclass Video(Component):  # 定义一个名为Video的类,继承自Componentdata_model = VideoData  # data_model是一个类属性(或者说是静态属性),其值为VideoData,表示该类处理的数据模型是VideoData

通过添加这四行代码,您的组件将自动实现 API 使用所需的方法、标记方法和示例缓存方法!它还具有自记录代码的附加优势。任何阅读您组件代码的人都会确切知道它期望的数据。

小贴士:如果您的组件期望从前端上传文件,您必须使用 FileData 模型!相关内容将在下一节中解释。

提示:在此处阅读 pydantic 文档。https://docs.pydantic.dev/latest/concepts/models/#basic-model-usage 

GradioModel 和 GradioRootModel 之间的区别在于 RootModel 不会将数据序列化为字典。例如, Names 模型会将数据序列化为 {'names': ['freddy', 'pete']} ,而 NamesRoot 模型则会将其序列化为 ['freddy', 'pete'] 。

from typing import Listclass Names(GradioModel):names: List[str]class NamesRoot(GradioRootModel):root: List[str]

即使你的组件不期望一个“复杂”的 JSON 数据结构,定义一个 GradioRootModel 也是有益的,这样你就不必担心实现 API 和标记方法了。

小贴士:使用 Python typing 库中的类来为你的模型定义类型。例如 ` List ` 而不是 ` list `。

 处理文件 

如果您的组件期望上传的文件作为输入,或者将保存的文件返回到前端,您必须使用 FileData 来在您的 data_model 中对文件进行类型定义。

当您使用 FileData 时:

  • Gradio 知道它应该允许将这个文件提供给前端。Gradio 自动阻止请求在运行服务器的计算机上提供任意文件。

  • Gradio 会自动将文件放入缓存中,以便不会保存文件的重复副本。

  • 客户端库将自动知道在发送请求之前应该上传输入文件。它们还会自动下载文件。

如果您不使用 FileData ,您的组件将无法按预期工作!

为您的组件添加事件触发器 

您组件的事件触发器在 EVENTS 类属性中定义。这是一个包含事件名称字符串的列表。在此列表中添加一个事件,将自动为您的组件添加一个具有相同名称的方法!

您可以从 gradio.events 导入 Events 枚举,以访问核心 gradio 组件中常用的事件。

例如,以下代码将在 MyComponent 类中定义 text_submit 、 file_upload 和 change 方法

from gradio.events import Events
from gradio.components import FormComponentclass MyComponent(FormComponent):EVENTS = ["text_submit","file_upload",Events.change]

小贴士:别忘了也要在 JavaScript 代码中处理这些事件!

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

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

相关文章

达梦8 通过日志解释数据守护系统的关停顺序

关闭守护系统时&#xff0c;必须按照一定的顺序来关闭守护进程和数据库实例。特别是自动切换模式&#xff0c;如果退出守护进程或主备库的顺序不正确&#xff0c;可能会引起主备切换&#xff0c;甚至造成守护进程组分裂。 官方推荐通过在监视器执行stop group命令关闭守护系统…

ALOS 12.5m DEM下载

1、下载地址 阿拉斯加遥感数据下载地址&#xff1a;https://search.asf.alaska.edu/ &#xff1b; 数据详情描述见地址&#xff1a;https://asf.alaska.edu/datasets/daac/alos-palsar-radiometric-terrain-correction/ &#xff1b; 2、下载步骤 2.1、勾绘研究区 在网站中…

以太坊==windows电脑本地搭建一个虚拟的以太坊环境

提供不同的选择&#xff0c;适合不同需求和技术水平的开发者&#xff1a; Geth&#xff1a;适合需要与主网兼容或构建私有网络的开发者。Ganache&#xff1a;适合快速开发和测试智能合约的开发者&#xff0c;特别是初学者。Docker&#xff1a;适合需要快速、可重复搭建环境的开…

笔记-python reduce 函数

reduce() 函数在 python 2 是内置函数&#xff0c; 从python 3 开始移到了 functools 模块。 官方文档是这样介绍的 reduce(...) reduce(function, sequence[, initial]) -> valueApply a function of two arguments cumulatively to the items of a sequence, from left …

简易智能家居系统

文章目录 摘要一、系统设计要求及总体设计方案1.1 设计要求1.2 总体设计方案 二、终端结点的设计及实现2.1单片机最小系统2.2 LED灯的控制与工作状态的显示2.2.1 硬件设计2.2.2 软件设计 2.3 温度的测量与显示2.4 火灾的监测与报警2.5 串口的显示与控制 三、网络传输与控制3.1 …

拦截器Interceptor

概念&#xff1a;是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。Spring框架中提供的&#xff0c;用来动态拦截方法的执行。 作用&#xff1a;拦截请求&#xff0c;在指定的方法调用前后&#xff0c;根据业务需要执行预先设定的代码。

已解决javax.management.BadAttributeValueExpException异常的正确解决方法,亲测有效!!!

已解决javax.management.BadAttributeValueExpException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 出现问题的场景 报错原因 解决思路 解决方法 分析错误日志 检查属性值合法性 确认属性类型匹配 优化代码逻辑 增…

后端数据null前端统一显示成空

handleNullValues方法在封装请求接口返回数据时统一处理 // null 转 function handleNullValues(data) {// 使用递归处理多层嵌套的对象或数组function processItem(item) {if (Array.isArray(item)) {return item.map(processItem);} else if (typeof item object &&…

学会python——对目录的操作(python实例十)

目录 1、认识Python 2、环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3、遍历当前目录 3.1 代码构思 3.2 代码示例 3.3 运行结果 4、删除目录中的文件 4.1 代码构思 4.2 代码示例 4.3 运行结果 5、总计 1、认识Python Python 是一个高层次的结合了解释性…

C Tips: 举例说明在 Visual C++ 中忽略 C4996 编译警告的几种方法

C4996 编译警告非常常见&#xff0c;经常发生在程序调用了类似于strcpy这样的不够安全的函数时。例如以下代码在 Visual C 的默认工程设置中会引起 C4996 编译警告&#xff1a; void foo() {char filename[MAX_PATH];strcpy(filename, "D:\\Pub\\Test\\1.dat"); }编…

AI视频教程下载-与ChatGPT结合的UX用户体验/UI用户界面设计策略

Revolutionize UX_UI_ AI-Design Strategies with ChatGPT 提升你的设计工具包&#xff1a;使用ChatGPT、Figma和Miro的AI驱动UX/UI策略 50个创新UX提示 了解人工智能的基础知识。介绍ChatGPT及其底层技术。区分不同AI模型及其在设计中的应用。将AI工具融入设计工作流程的策略…

高纯PFA容量瓶PFA试剂瓶在半导体材料的应用

在半导体生产过程中&#xff0c;为避免金属污染对硅器件性能造成不利影响&#xff0c;碳化硅产业链不同阶段产品&#xff08;如衬底、外延、芯片、器件&#xff09;表面的痕量杂质元素浓度表征至关重要。 在实验人员使用质谱法高精度检测第三代半导体碳化硅材料的痕量杂质浓度…

高级IO操作

高级I/O操作与非阻塞I/O 在操作系统中&#xff0c;I/O&#xff08;输入/输出&#xff09;操作是所有实现的基础。本文将探讨阻塞I/O与非阻塞I/O的区别&#xff0c;以及如何使用有限状态机来实现非阻塞I/O&#xff0c;并介绍数据中继的概念。 阻塞I/O与非阻塞I/O 阻塞I/O 阻…

数据结构历年考研真题对应知识点(栈和队列的应用)

目录 3.3栈和队列的应用 3.3.2栈在表达式求值中的应用 【中缀表达式转后缀表达式的过程(2012、2014)】 【栈的深度分析(2009、2012)】 【用栈实现表达式求值的分析(2018)】 3.3.3栈在递归中的应用 【栈在函数调用中的作用和工作原理(2015、2017)】 3.3.5队列在计算机系…

docker搭建mongo副本集

1、mongo集群分类 MongoDB集群有4种类型&#xff0c;分别是主从复制、副本集、分片集群和混合集群。 MongoDB的主从复制是指在一个MongoDB集群中&#xff0c;一个节点&#xff08;主节点&#xff09;将数据写入并同步到其他节点&#xff08;从节点&#xff09;。主从复制提供…

L56---226.翻转二叉树(广搜)---Java版

1.题目描述 2.思路和知识点 &#xff08;1&#xff09;按照每层来划分&#xff0c; 第一层是2^0&#xff08; 1&#xff09; 第二层是2^1&#xff08;2&#xff0c;3&#xff09; 第三层是2^2 &#xff08;4&#xff0c;5&#xff0c;6&#xff0c;7&#xff09; 第n层是2^(n-…

如何实现外部编码器轴和虚轴电子齿轮比例随动(汇川AM400PLC)

1、如何添加虚轴可以参考下面文章链接: 如何添加虚轴(AM400PLC)-CSDN博客文章浏览阅读2次。EtherCAT运动控制总线启用的时候,选择EtherCAT总线任务周期。选择好后,选择点击添加。https://blog.csdn.net/m0_46143730/article/details/139898985?csdn_share_tail=%7B%22type…

如何解决代码中if…else-过多的问题,建议收藏

逻辑表达模式固定的 if…else 实现与示例 if (param.equals(value1)) { doAction1(someParams); } else if (param.equals(value2)) { doAction2(someParams); } else if (param.equals(value3)) { doAction3(someParams); } // … 可重构为 Map<?, Function<?>…

【会议征稿,CPS出版】第四届管理科学和软件工程国际学术会议(ICMSSE 2024,7月19-21)

第四届管理科学和软件工程国际学术会议(ICMSSE 2024)由ACM珠海分会&#xff0c;广州番禺职业技术学院主办&#xff1b;全国区块链行业产教融合共同体&#xff0c;AEIC学术交流中心承办&#xff0c;将于2024年7月19-21日于广州召开。 会议旨在为从事管理与软件工程领域的专家学…

Type-C连接器厂商对检测实验室的要求及重要性解析

Type-C连接器厂商对检测实验室的要求与重要性 Type-C连接器作为一种高速、全功能的接口标准&#xff0c;被广泛应用于各类电子产品中。作为Type-C连接器的制造商&#xff0c;对于产品的质量和性能要求是至关重要的。为了确保产品符合规范并满足市场需求&#xff0c;Type-C连接…