目录
对于Windows(setup_dev_env_win.bat)
介绍
本文指的是 CodeProject.AI Server v1.5.0+版本
如果你乐于遵循曲折的迷宫,那么将 AI功能添加到应用程序是相当简单的,这是无穷无尽的库、工具、解释器、包管理器和所有其他有趣的东西,有时使编码和洗碗一样有趣。
我们构建 CodeProject.AI服务器是为了向开发人员隐藏所有烦人的事情,并给他们留下一个简单的AI包,该包可以做一些事情,并且易于与现有应用程序一起使用。
如果CodeProject.AI服务器没有满足您的需求,那么很容易添加可以填补空白的模块。
30秒内完成CodeProject.AI服务器架构
CodeProject.AI服务器是基于HTTP的REST API服务器。它基本上只是一个Web服务器,您的应用程序向其发送请求。这些请求被放置在队列中,分析服务(也称为模块)从它们知道如何服务的队列中挑选请求。然后处理每个请求(根据请求执行AI操作),并将结果发送回API服务器,而API服务器又将其发送回进行初始调用的应用程序。
假设我们有3个分析模块,使用Python 3.7的人脸识别、使用.NET的对象检测和使用Python 3.10的文本分析:
- 应用程序向API服务器发送请求
- API服务器将请求放在相应的队列中
- 后端模块轮询它们感兴趣的队列,获取请求并处理它
- 然后,后端模块将结果发送回API服务器
- 然后,API服务器将结果发送回调用应用程序
CodeProject.AI服务器API服务器独立于调用应用程序运行。
CodeProject.AI服务器想象成数据库服务器或您在后台运行的任何其他服务:它作为服务或守护程序运行,您发送命令并响应结果。您不会担心它如何开展业务的细节,您只需专注于应用程序的核心业务。
向服务器添加新模块CodeProject.AI
添加新模块有2个任务
- 确保正确安装任何先决条件,例如模型、库或解释器
- 编写实际模块并将其连接到CodeProject.AI服务器
添加先决条件
需要将模型、解释器、编译器和工具等先决条件添加到开发设置脚本中,以便允许处理代码的每个人都拥有适用于该模块的开发环境。如果选择将模块包含在Windows安装程序或Docker镜像中,则还需要更新这两个环境。
必需(用于开发)
- 开发环境设置脚本。/Installers/Dev 中是应运行的安装脚本,以便为构建、调试和测试设置开发环境。如果您需要下载和/或安装模型、程序或工具,请确保将命令添加到这些脚本中。
有两个脚本,一个用于Windows,一个用于Linux / macOS。脚本分为多个部分,包括常规设置、可重用函数和与每个给定模块相关的脚本块。
可选(适用于最终用户)
- Windows安装程序。如果您希望将新模块与现有模块一起安装在Windows上,则需要为需要放置的任何资产创建一个子安装程序。这并非易事,仅当您希望将工作作为主安装程序的一部分分发时才需要。
将来,模块的资产将简单地与清单文件压缩在一起,安装程序将自动检查并安装在正确的位置。
- Docker镜像如果您希望在Docker镜像中安装新模块,则需要更新主Docker镜像,以确保它包含所需的资产和工具。
这两者都不在本文的讨论范围之内。
编写模块
编写模块是有趣的部分。事实上,你通常不必编写一个新模块:有数百个优秀的开源、独立的人工智能项目可以制作出优秀的模块。您需要做的就是确保模块可以在已安装的环境中运行(在先决条件步骤中处理),下载所需的任何模型并将其放置在正确的位置(同样,应该已经完成),并且模块可以与CodeProject.AI服务器通信。
我们将为多种语言提供一个简单的SDK,这将有助于您编写适合模块和CodeProject.AI服务器之间的填充程序,并负责通信。
让我们添加一个模块
我们将添加 remgb 模块。这是一个简单但有趣的AI模块,可以拍摄任何包含主题的照片并从图像中删除背景。它在Python 3.9或更高版本下运行。
安装程序(安装程序)
REMBG模块包括以下内容
- Python代码
- Python 3.9解释器
- 一些Python包
- 人工智能模型
为了确保这些在开发环境中都到位,我们需要修改 /Installers/Dev 中的安装脚本。
对于Windows(setup_dev_env_win.bat)
:: Background Remover :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The name of the dir containing the Background Remover module
set moduleDir=BackgroundRemover
:: The full path of the background remover module
set modulePath=%analysisLayerPath%\%moduleDir%
:: The name of the dir containing the background remover models
set moduleAssetsDir=models
:: The name of the file in our S3 bucket containing the assets required for this module
set modelsAssetFilename=rembg-models.zip
:: Install python and the required dependencies
call :SetupPython 3.9
call :InstallPythonPackages 3.9 "%modulePath%\requirements.txt" "onnxruntime"
:: Download the AI models
call :Download "%storageUrl%" "%downloadPath%\" "%modelsAssetFilename%" "%moduleDir%" ^
"Downloading Background Remover models..."
:: Copy over the models to the working directory for this module.
if exist "%downloadPath%\%modulesDir%" (
robocopy /e "%downloadPath%\%moduleDir% " "%modulePath%\%moduleAssetsDir% "
)
代码应该是不言自明的:
1、设置将保存模块的目录和子目录的名称,以及要下载的资产的名称。
analysisLayerPath 是包含所有模块的“分析”文件夹的完整路径。在我们的例子中,这目前是/src/AnalysisLayer
2、安装Python 3.9,然后安装 Python.txt 文件中列出的Python包
:SetupPython是一个安装给定版本的Python的子例程。我们目前仅支持3.7和3.9,但会根据需要添加更多版本。添加另一个版本真正需要的只是提供64位python解释器的独立下载。
:InstallPythonPackages遍历提供的需求文件,并使用给定的python版本安装包。还有第二个参数(此处为“onnxruntime”)允许您提供软件包的名称,如果检测到该名称,可以假定表示已安装所有软件包,并且可以跳过此步骤。这在您需要重新运行安装时提供了优化。
3、下载模型
:Download source_base_url download_storage_path archive_filename extract_dir消息将从source_base_url下载archive_filename,将其存储在download_storage_path中,然后将其解压缩到名为extract_dir的目录中。它还将在下载开始时输出消息。archive_filename必须是Zip或GZip文件。
source_base_url包含包含所有下载内容的S3存储桶的URL。
download_storage_path将是/Installers/Dev/downloads。
在这种情况下,archive_filename将是“rembg-models.zip”
extract_dir是“BackgroundRemover”。
因此,我们将rembg-models.zip 中的模型从我们的S3存储桶下载,并将其存储在/Installers/Dev/downloads/BackgroundRemover 中。
我们将zip存储在 /downloads 目录中而不是直接解压缩到模块目录的原因是,我们可以轻松地重新运行安装脚本,而无需重新下载每个模块的每个资产。
4、将下载的模型复制到模块的工作目录。这里没有什么太花哨的。模型将被复制到 %modulePath%\%moduleAssetsDir%,该模型将扩展到 /src/AnalysisLayer/BackgroundRemover/models。
对于Linux
该脚本与Windows版本基本相同:
# Background Remover :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# The name of the dir containing the background remover module
moduleDir='BackgroundRemover'
# The name of the dir containing the background remover models
modulePath="${analysisLayerPath}/${moduleDir}"
# The name of the dir containing the background remover models
moduleAssetsDir='models'
# The name of the file in our S3 bucket containing the assets required for this module
modelsAssetFilename='rembg-models.zip'
setupPython 3.9
installPythonPackages 3.9 "${modulePath}/requirements.txt" "onnxruntime"
Download $storageUrl "${downloadPath}" $modelsAssetFilename "${moduleDir}" "Downloading models..."
if [ -d "${downloadPath}/${moduleDir}" ]; then
mv -f "${downloadPath}/${moduleDir}" "${modulePath}/${moduleAssetsDir}"
fi
请注意,在我们的脚本中,我们包含了一些小的添加,允许您在需要时强制重新下载,但这些只是详细信息,因此为了简单起见,我们没有在此处包含它们。
模块的接口
我们应该从如何调用模块开始。它可以是我们喜欢的任何内容,所以让我们选择路由/v1/image/removebackground。我们将传入一个图像和一个布尔“use_alphamatting”,它告诉代码是否使用alpha遮罩(更适合模糊边缘)。
返回包将包含单个项目“imageBase64”,其中包含已删除背景的图像的base64编码版本。
模块的源代码
首先,我们在模块目录下创建一个文件夹,并复制模块的代码。在本例中,我们将代码存储在/src/AnalysisLayer/BackgroundRemover 中。为了方便起见,我们将为那些使用Visual Studio的人创建一个Python项目(在VS Code中工作同样简单)。
rembg模块有一个我们需要调用的主方法,名为remove。我们需要能够从客户端对此方法的请求中获取数据,然后将此方法的结果传递回客户端。为此,我们将使用该AnalysisLayer/SDK/codeprojectAI.py模块来提供帮助。
我们还将为rembg创建一个适配器(我们称之为rembg_adapter.py),它将rembg remove方法与我们的codeprojectAI.py帮助程序模块连接起来。
# Import the CodeProject.AI helper
import sys
sys.path.append("../SDK/Python")
from CodeProjectAI import ModuleWrapper, LogMethod
# Import the rembg method we need to call
from rembg.bg import remove
# Import the packages that we need to pass around the data
import base64
from io import BytesIO
import json
import traceback
# Create a CodeProject.AI helper
ai_module = ModuleWrapper()
# The main method containing the loop that will process the queue
def remove_background(thread_name):
QUEUE_NAME = "removebackground_queue"
# Hack for debug mode
if ai_module.moduleId == "CodeProject.AI":
ai_module.moduleId = "BackgroundRemoval";
while True:
queue_entries: list = ai_module.get_command(QUEUE_NAME)
if len(queue_entries) > 0:
timer: tuple = ai_module.start_timer("Remove Background")
for queue_entry in queue_entries:
req_data: dict = json.JSONDecoder().decode(queue_entry)
req_id: str = req_data.get("reqid", "")
use_alphamatting: bool = ai_module.get_request_value(req_data, "use_alphamatting", "false") == "true"
output: any = {}
try:
img = ai_module.get_image_from_request(req_data, 0)
processed = remove(img, use_alphamatting)
buffered = BytesIO()
processed.save(buffered, format="PNG")
img_dataB64_bytes = base64.b64encode(buffered.getvalue())
img_dataB64 = img_dataB64_bytes.decode("ascii");
output = {"success": True, "imageBase64": img_dataB64}
except Exception:
err_trace = traceback.format_exc()
output = {"success": False, "error": "unable to process the image", "code": 500}
ai_module.log(LogMethod.Error | LogMethod.Cloud | LogMethod.Server,
{ "process": "removebackground",
"file": "rembg_adapter.py",
"method": "remove_background",
"message": err_trace,
"exception_type": "Exception"})
finally:
ai_module.end_timer(timer)
try:
ai_module.send_response(req_id, json.dumps(output))
except Exception:
print("An exception occured")
if __name__ == "__main__":
ai_module.log(LogMethod.Info | LogMethod.Server, {"message":"RemoveBackground module started."})
remove_background("main_removebackground")
这是我们添加的唯一代码。rembg模块已按原样复制和粘贴,我们正在重用codeprojectAI.py帮助程序类。无需添加任何其他内容(代码方面)。
modulesettings.json文件
此文件位于 BackgroundRemover 文件夹中,指示API服务器如何启动我们的新分析服务。
{
"Modules": {
"BackgroundRemoval": {
"Name": "Background Removal",
"Activate": true,
"Description": "Removes backgrounds from images.",
"FilePath": "BackgroundRemover\\rembg_adapter.py",
"Platforms": [ "windows", "linux", "macos", "docker" ],
"Runtime": "python39",
"EnvironmentVariables": {
"U2NET_HOME": "%MODULES_PATH%/BackgroundRemover/models" // where to store the models
},
"RouteMaps": [
// ... (explained below)
]
}
}
}
环境变量部分定义键/值对,这些键/值对将用于设置模块可能需要的环境变量。在本例中为AI模型文件的路径。这是特定于rembg模块并由其定义的值。
MODULES_PATH是一个宏,它将扩展到包含模块的目录的位置。在本例中为/src/AnalysisLayer。
模块配置部分包含有关启动模块的信息。名称和描述是不言自明的。FilePath是要执行的文件相对于MODULES_PATH目录的路径。激活设置是否在运行时启动此模块。
运行时定义将启动文件的运行时。我们目前支持dotnet(.NET),python37(python 3.7)和python39(Python 3.9)。如果省略,CodeProject.AI服务器将尝试根据文件路径进行猜测。
平台数组包含可以运行服务的每个平台的条目。目前支持Windows,Linux,macOS和Docker。
该文件还在“路由映射”部分下定义了模块的API路由
{
"Modules": {
"ModulesConfig": {
"BackgroundRemoval": {
"Name": "Background Removal",
"Description": "Removes backgrounds from images.",
...
"RouteMaps": [
{
"Path": "image/removebackground",
"Command": "removebackground",
"Queue": "removebackground_queue",
"Description": "Removes the background from images.",
"Inputs": [ ... ],
"Outputs": [...]
}
]
}
}
}
}
路径是API路径,在本例中为 localhost:5000/v1/image/removebackground。请记住,这是我们(任意)选择的API 。它可以是任何东西,只要它当前未被使用。
命令是API控制器中将调用的方法,在本例中为removebackground。队列是API服务器中将管理此服务请求的队列的名称。
在我们编写的适配器python模块中,我们有代码
QUEUE_NAME = "removebackground_queue"
路由映射中的队列应与此名称匹配。
描述、输入和输出在此阶段纯粹是文档。
将调用新模块的客户端
一个简单的JavaScript测试工具可用于演示新模块
// Assume we have a HTML INPUT type=file control with ID=fileChooser
var formData = new FormData();
formData.append('image', fileChooser.files[0]);
formData.append("use_alphamatting", 'false');
var url = 'http://localhost:5000/v1/image/removebackground';
fetch(url, { method: "POST", body: formData})
.then(response => {
if (response.ok) {
response.json().then(data => {
// img is an IMG tag that will display the result
img.src = "data:image/png;base64," + data.imageBase64;
})
}
})
该项目包含一个文件test.html用于实现此目的,提供用于收集信息和显示结果的UI。
安装和测试
此时,我们有一个模块,一个安装脚本和一个测试客户端。让我们试一试。
- 确保已下载最新的 CodeProject.AI服务器存储库。这已经包含了我们上面讨论的所有代码
- 运行开发安装脚本。这将确保安装和设置Python 3.9,并安装所需的Python模块。
- 通过在Visual Studio或VS Code中启动新的调试会话来启动服务器。
- 在调试中,CodeProject.AI服务器仪表板在运行时自动启动。服务器启动后,仪表板将显示所有后端模块的状态,包括我们刚刚添加的后台删除模块。请注意,在下图中,我们已出于演示目的禁用了旧对象检测模块。
- 在浏览器中启动index.html文件,选择一个文件并单击“提交”按钮。应显示结果。
接下来呢?
这取决于你。我们演示了一个非常简单的AI模块,它可以从图像中删除背景。主要工作是
- 确保您在服务器上有可用的资产(例如模型),以便可以下载它们
- 更新安装脚本,以便可以下载资产并将其移动到位,并确保已安装必要的运行时和库
- 放入模块的代码并编写适配器,以便它可以与CodeProject.AI服务器通信
- 编写描述模块API的模块设置文件
- 测试!总是有趣的部分。
您可以添加的内容的可能性几乎是无限的。我们的目标是使开发人员能够轻松添加自己的AI模块,从而从其他人添加的模块中获益。混合搭配,使用不同的训练模块集,尝试设置,看看你可以把它带到哪里。
https://www.codeproject.com/Articles/5332075/Adding-a-new-module-to-CodeProject-AI-Server