65.9K
CodeProject 正在变化。 阅读更多。
Home

为 CodeProject.AI Server 添加新模块

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2022 年 5 月 17 日

CPOL

10分钟阅读

viewsIcon

19220

在本文中,我们将探讨 CodeProject.AI Server 的实际工作原理,以及如何轻松快速地为 CodeProject.AI Server 添加您自己的功能,让您专注于您的业务,而不是您的 MLOps。

引言

如果您乐于遵循庞杂的库、工具、解释器、包管理器以及其他有时会让编码过程变得像洗碗一样乏味的乐趣,那么为应用程序添加人工智能功能相对来说是相当直接的。

我们构建了CodeProject.AI Server,以隐藏开发者遇到的所有烦恼,并为他们提供一个简单的人工智能包,能够“做好事”,并且易于与现有应用程序集成。

如果 CodeProject.AI Server 不能满足您的需求,那么添加模块来填补这一空白非常简单。

聚合,而非添加

我们说“添加”,但“聚合”更为准确。市面上存在大量活跃开发和改进的优秀人工智能项目,我们希望让开发者能够轻松地将这些现有的、不断发展的人工智能模块或应用程序集成到CodeProject.AI生态系统中。这可能意味着集成一个控制台应用程序、一个 Python 模块或一个 .NET 项目。

对于开发,您只需要:

  1. 创建一个安装脚本(通常很简短),用于设置先决条件(下载模型、安装必要的库、创建必要的文件夹等)。
  2. 编写一个适配器,处理模块和CodeProject.AI服务器之间的通信。
  3. 提供一个 modulesettings.json 文件,描述该模块并向CodeProject.AI提供如何启动该模块的说明。

CodeProject.AI Server 架构(30 秒内解读)

CodeProject.AI Server 是一个基于 HTTP 的 REST API 服务器。它基本上就是一个 Web 服务器,您的应用程序会向其发送请求。这些请求会被放入一个队列,然后分析服务(又称模块)会拾取它们知道如何处理的队列中的请求。每个请求随后会被处理(执行基于请求的人工智能操作),并将结果发送回 API 服务器,API 服务器再将其发送回发起初始调用的应用程序。

您可以将 CodeProject.AI Server 想象成数据库服务器或您在后台运行的任何其他服务:它作为一个服务或守护进程运行,您向它发送命令,它会响应结果。您不必担心它是如何工作的细节,只需要专注于您的应用程序的核心业务。

CodeProject.AI Server API 服务器独立于调用应用程序运行。

例如,假设我们有三个分析模块:使用 Python 3.7 进行人脸识别,使用 .NET 进行对象检测,以及使用 Python 3.10 进行文本分析。

  1. 应用程序向 API 服务器发送请求。
  2. API 服务器将请求放入相应的队列。
  3. 后端模块轮询它们感兴趣的队列,获取请求并进行处理。
  4. 然后,后端模块将结果发送回 API 服务器。
  5. API 服务器随后将结果发送回调用应用程序。

每个后端模块都可以使用任何技术栈,并在安装的任何运行时下运行——Python、.NET、Go、C++——只要能在主机系统上运行即可。由模块安装程序负责确保主机系统已安装所需的所有组件,但 CodeProject.AI Server 在此方面提供了大量帮助。

为 CodeProject.AI Server 添加新模块

添加新模块有三个任务:

  1. 创建一个设置文件,指示服务器和安装程序您的模块需要什么。
  2. 通过安装脚本确保正确安装任何先决条件,如模型、库或解释器。
  3. 编写实际的模块并将其连接到 CodeProject.AI Server。

设置文件

这是一个简单的 JSON 文件,提供模块的名称、版本和描述等通用信息,以及使用的运行时、版本兼容性信息、GPU 使用指南和路由信息。路由信息允许服务器监听指定的 API 路由并将这些请求传递给您的模块。

安装脚本

安装脚本(和后安装脚本)提供了一个机会来下载模型、安装运行时、构建和安装库,以及执行任何必要的任务以确保模块能够运行。您将需要一个 Windows BAT 文件用于 Windows 安装程序,以及一个 bash 文件用于 Linux/macOS 安装程序。

最新版本的 CodeProject.AI Server 不需要安装脚本来安装 Python 或 .NET——这些工作由核心设置系统根据您的设置文件完成。如果设置系统检测到模块正在使用 .NET 或 Python,它将设置这些环境,对于 Python,它还会查找并在虚拟环境中安装 requirements 文件中的包。

其他运行时或支持服务应通过安装脚本添加。

编写模块

编写模块是其中有趣的部分。事实上,您通常不必编写新模块:市面上有数百个优秀的开源、独立的 AI 项目可以作为优秀的模块。您需要做的就是确保模块能在已安装的环境中运行(这在先决条件步骤中已处理),任何所需的模型都已下载并放置在正确的位置(同样,应该已完成),并且模块能够与 CodeProject.AI Server 进行通信。

我们将为许多语言提供一个简单的 SDK,以帮助您编写一个可以在模块和 CodeProject.AI Server 之间起到连接作用的“Shim”,并处理通信。

让我们添加一个模块

我们将添加 rembg 模块。这是一个简单有趣的 AI 模块,可以移除照片中主体的背景。它运行在 Python 3.9 或更高版本。

设置(安装程序)

rembg 模块包含以下内容:

  1. Python 代码
  2. Python 3.9 解释器
  3. 一些 Python 包
  4. AI 模型

为确保这些都在开发环境中就位,我们需要修改 /Installers/Dev 中的设置脚本。

对于 Windows (install.bat)

:: Background Remover :::::::::::::::::::::::::::::::::::::::::::::::::::::::::

call "%sdkScriptsDirPath%\utils.bat" GetFromServer "rembg-models.zip" "models" "Downloading Background Remover models..."

这个脚本非常简单:它只是从 CodeProject S3 存储桶下载模型并将文件移到相应位置。GetFromServer 函数包含在 SDK 脚本中,它接受一个文件名、一个用于将文件解压到的文件夹名(相对于当前模块)和一个消息。

对于 Linux 或 macOS

该脚本本质上与 Windows 版本相同。

# Background Remover :::::::::::::::::::::::::::::::::::::::::::::::::::::::::

getFromServer "rembg-models.zip" "models" "Downloading Background Remover models..."

模块的 API

我们应该从如何调用模块开始。它可以是任何我们想要的,所以让我们选择路由 /v1/image/removebackground。我们将传入一个图像和一个布尔值 use_alphamatting,它告诉代码是否使用 alpha 蒙版(对于模糊边缘效果更好)。

返回的数据包将包含一个名为 imageBase64 的项目,其中包含已移除背景的图像的 base64 编码版本。

模块的源代码

首先,我们在 modules 目录下创建一个文件夹,并将模块的代码复制过来。在这种情况下,我们将代码存储在 /src/modules/BackgroundRemover。为了方便起见,我们将为使用 Visual Studio 的用户创建一个 Python 项目(在 VS Code 中工作同样简单)。

rembg 模块有一个我们需要调用的主要方法,名为 remove。我们需要能够获取客户端请求该方法的输入数据,然后将该方法的结果返回给客户端。为此,我们将使用 src/SDK/Python/module_runner.py 模块。

我们还将创建一个名为 rembg_adapter.py 的适配器,用于 rembg,它将 rembg remove 方法与我们的 codeprojectAI.py 辅助模块连接起来。

# Import our general libraries
import sys
import time

# Import the CodeProject.AI SDK. This will add to the PATH var for
# future imports
sys.path.append("../../SDK/Python")
from request_data import RequestData
from module_runner import ModuleRunner
from common import JSON

# Import the method of the module we're wrapping
from PIL import Image

# Import the method of the module we're wrapping
from rembg.bg import remove

class rembg_adapter(ModuleRunner):

    def initialise(self) -> None:   
        """ Initialises the module """
        pass

    def process(self, data: RequestData) -> JSON:
        """ Processes a request from the client and returns the results"""
        try:
            img: Image             = data.get_image(0)
            use_alphamatting: bool = data.get_value("use_alphamatting", "false") == "true"

            # Make the call to the AI code we're wrapping, and time it
            start_time = time.perf_counter()
            (processed_img, inferenceTime) = remove(img, use_alphamatting)
            processMs = int((time.perf_counter() - start_time) * 1000)

            return { 
                "success":      True, 
                "imageBase64":  RequestData.encode_image(processed_img),
                "processMs" :   processMs,
                "inferenceMs" : inferenceTime
            }

        except Exception as ex:
            self.report_error(ex, __file__)
            return {"success": False, "error": "unable to process the image"}

    def shutdown(self) -> None:
        pass

if __name__ == "__main__":
    rembg_adapter().start_loop()

这是我们添加的唯一代码。rembg 模块已被原封不动地复制粘贴,并且我们正在重用 ModuleRunner 工作类。不需要添加其他任何东西(代码方面)。

modulesettings.json 文件

此文件位于 BackgroundRemover 文件夹中,它指示 API 服务器如何启动我们的新分析服务。

{
  "Modules": {

   "BackgroundRemoval": {

      "Name": "Background Remover",
      "Version": "1.6.2",

      // Publishing info
      "Description": "Automatically removes the background from a picture", 
      "Platforms": [ "windows", /*"linux",*/ "linux-arm64", "macos", "macos-arm64" ], // issues with numpy on linux
      "License": "SSPL",
      "LicenseUrl": "https://mongodb.ac.cn/licensing/server-side-public-license",

      // Launch instructions
      "AutoStart": false,
      "FilePath": "rembg_adapter.py",
      "Runtime": "python3.9",
      "RuntimeLocation": "Local",       // Can be Local or Shared

      "EnvironmentVariables": {
        "U2NET_HOME": "%CURRENT_MODULE_PATH%/models" // where to store the models
      },

      "RouteMaps": [
          // ... (explained below)
      ]
    }
  }
}

EnvironmentVariables 部分定义了将用于设置模块可能需要的环境变量的键值对。在这种情况下,是指向 AI 模型文件的路径。这是 rembg 模块特有的、由其定义的值。

CURRENT_MODULES_PATH 是一个宏,将展开为包含模块的目录的位置。在这种情况下,是 /src/AnalysisLayer

FilePath 是要执行的文件路径,相对于当前模块的目录。

AutoStart 设置该模块是否在服务器启动时启动。

Runtime 定义了将启动文件的运行时。我们目前支持 dotnet (.NET)、python3.6Python 3.12,或者仅 python(如果您使用系统的默认 Python 版本)。如果省略,CodeProject.AI Server 将尝试根据 FilePath 进行猜测。

Platforms 数组包含该服务可以运行的每个平台的条目。目前支持 Windows、Linux、macOS 和 Docker。

该文件还在 RouteMaps 部分定义了该模块的 API 路由。

{
  "Modules": {
    "ModulesConfig": {
      "BackgroundRemoval": {
         "Name": "Background Removal",
         "Description": "Removes backgrounds from images.",

         ...

         "RouteMaps": [
           {
             "Path": "image/removebackground",
             "Command": "removebackground",
             "Description": "Removes the background from images.",
             "Inputs": [ ... ],
             "Outputs": [...]
           }
         ]
       }
     }
   }
}

Path 是 API 路径,在此情况下为 localhost:5000/v1/image/removebackground。请记住,这是我们(任意)选择的 API。它可以是任何未被占用的路径。

Command 是 API 控制器中将被调用的方法,在此情况下为 removebackgroundQueue 是 API 服务器中将管理此服务请求的队列名称。

在我们编写的适配器 Python 模块中,我们有以下代码:

QUEUE_NAME = "removebackground_queue"

路由图中的 Queue 应该与此名称匹配。

DescriptionInputsOutputs 在此阶段纯粹是文档。

调用我们新模块的客户端

可以使用一个简单的 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 = 'https://: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 文件,实现了这一功能,提供了收集信息并显示结果的用户界面。

安装和测试

此时,我们已经有了模块、安装脚本和测试客户端。让我们来运行一下。

  1. 确保您已下载最新的 CodeProject.AI Server 仓库。其中已包含我们上面讨论过的所有代码。

  2. 运行 /src 中的设置脚本。这将确保安装和设置 Python 3.9,并且安装了所需的 Python 模块。

  3. 通过在 Visual Studio 或 VS Code 中启动新的调试会话来启动服务器。

  4. 在调试模式下,CodeProject.AI Server Dashboard 会在运行时自动启动。服务器启动后,仪表板将显示所有后端模块的状态,包括我们刚刚添加的背景移除模块。请注意,在下面的图像中,为了演示目的,我们故意禁用了一些模块的自动启动。

  5. 在浏览器中打开 index.html 文件,选择一个文件,然后点击提交按钮。结果应该会显示出来。

    Background Remover test.html page

What Next?

这取决于您。我们已经演示了一个非常简单的人工智能模块,可以移除图像背景。主要工作是:

  1. 确保您在服务器上拥有可用资源(例如模型),以便下载。
  2. 更新安装脚本,以便下载和放置您的资源,并确保您已安装必要的运行时和库。
  3. 放置您的模块代码并编写一个适配器,使其能够与 CodeProject.AI Server 通信。
  4. 编写一个 modulesettings 文件来描述您模块的 API。
  5. 测试!这永远是有趣的部分。

您可以添加的可能性几乎是无限的。我们的目标是让您作为开发者能够轻松地添加您自己的人工智能模块,并从中受益于他人添加的模块。混合搭配,尝试不同的训练模块集,调整设置,看看能取得什么成果。

这是关于学习,也是关于乐趣。放手去做吧。

© . All rights reserved.