那么你想向 CodeProject.AI 添加新模块
CodeProject.AI 允许开发人员轻松地将新的 AI 功能添加到现有系统中,而无需与工具和库进行斗争。
如果您乐于遵循一个缠绕扭曲的迷宫,即无穷无尽的库、工具、解释器、包管理器以及所有其他有趣的玩意儿,这些玩意儿有时会让编码的乐趣如同洗碗一样,那么为应用程序添加 AI 功能相对来说是比较直接的。
CodeProject.AI 通过提供一个框架来管理这些痛点,让这一切变得更容易,这样您就可以专注于您的代码,而不是工具。
聚合,而非添加
我们说“添加”,但“聚合”更准确。有大量的 AI 项目正在积极开发和改进中,我们希望允许开发人员将这些现有的、不断发展的 AI 模块或应用程序尽可能轻松地集成到 CodeProject.AI 生态系统中。这可能意味着集成一个控制台应用程序、一个 Python 模块或一个 .NET 项目。
对于开发,您只需要做:
- 查找或编写您想要包含的代码。这可能是在线找到的项目、您自己编写想包含的项目,或者您可以从一个新项目开始。
- 编写一个适配器,该适配器负责您编写或包含在模块中的 AI 代码与 CodeProject.AI 服务器本身之间的通信。
- 提供一个
modulesettings.json
文件,该文件描述了模块,并向 CodeProject.AI 提供有关如何启动模块的指令。 - 创建一个安装脚本(通常很短)来设置先决条件(下载模型,安装必要的运行时)。
- (可选但推荐)创建一个简单的
explore.html
文件来测试您的模块,并与 CodeProject.AI Explorer 集成。 - (可选但推荐)创建一个打包器,以便您的模块可以被打包并包含在主 CodeProject.AI 注册表中。
我只想写代码!
如果您想直奔主题,直接开始编写模块,请阅读 添加您自己的 Python 模块 或 添加您自己的 .NET 模块。
CodeProject.AI 架构(30 秒内了解)
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 服务器启动并监控分析模块。
-
有一组分析模块,它们从 CodeProject.AI 服务器的队列中获取请求并进行处理。每个模块包含:
- 一个适配器,用于在模块和 CodeProject.AI 服务器之间进行通信;
- 模块本身。
-
有许多运行时(例如 Python 或 .NET),模块在这些运行时下运行。多个模块可以共享一个给定的运行时:我们(还没有)沙箱化。
每个模块的适配器通常与模块在相同的运行时(甚至经常在相同的进程)中运行,但这并非必需。您可以轻松编写一个简单的 Python 脚本作为适配器,从 .NET 模块发送和接收数据。
设置:模型和运行时
设置脚本应负责下载所需的 AI 模型以及安装任何必要的运行时。默认情况下,我们目前确保 Python 3.7 和 3.9,以及 .NET 7 已安装并可供所有人使用。
对于 Python 模块,设置脚本通常还会确保安装任何 Python 包。
应提供一个 Windows BAT 文件和一个 Linux/macOS bash 文件用于设置,具体取决于您支持的平台。
选择要添加的代码
在考虑哪些模块适合包含在 CodeProject.AI 中时,请考虑以下几点:
- 代码是否自包含?模块需要的附带信息越少越好。
- 模块是否提供简单易调用的 API?例如,Python 模块可以提供一个您调用的函数,或者 Go 应用程序可以提供一个简单的控制台应用程序体验,允许从命令行调用它。
- 模块能否离线运行?需要互联网连接的模块在所有环境中可能无法正常工作,或者可能不被某些需要确保其数据保留在自己环境中的用户接受。
- 如果模块更新了,集成更新后的代码有多难?对原始代码的修改越少,以后更新模块就越容易。如果可能,请将代码更改限制在您的适配器中。
编写适配器
模块的适配器有一个任务:在 CodeProject.AI 和模块之间传递通信。
一个例子可能是用 Python 编写的模块。您有一个 my_module.py 文件,其中包含您的 AI 推理代码,并且该模块中可能有一个 predict
方法。适配器将:
- 通过查询环境变量或检查 modulesettings.json 文件中的值来设置模块。
- 处理请求(在本例中,调用 my_module.py 文件中的
predict
方法)并返回结果。
如果可能,应避免修改模块代码。适配器将模块与 CodeProject.AI 隔离开来,因此如果模块更新了,可以轻松集成更新,适配器(希望)仍然可以工作。如果不行,调整适配器以适应更改的 API、数据格式或方法签名应该是一个快速而简单的修复。
modulesettings.json 文件
CodeProject.AI 服务器在启动时将加载模块目录中的 modulesettings.json
文件及其变体。这些文件由 NET 配置系统按以下顺序读取:
- modulesettings.json - 通用和默认配置值。
- modulesettings.<production|development>.json - 生产或开发值。
- modulesettings.<platform>.json - 特定于运行时操作系统(platform)的值。目前支持:
windows
、linux
、docker
、macos
和macos-arm
。 - modulesettings.<platform>.<production|development>.json - 特定于平台和环境的值。
每个文件中的设置将覆盖任何先前加载的设置,允许您在每个变体中仅指定您需要为给定场景调整的设置。
modulesettings.json schema
modulesettings.json
文件在 Modules
部分定义了模块的通用元数据。这些元数据包括有关以下信息:
- 模块的名称和描述;
- 是否应在启动时运行;
- 模块应如何启动。a. 指定一个
runtime
和一个filePath
。然后将使用给定的运行时启动 filepath 中指定的模块。目前支持的运行时包括dotnet
、python37
、python38
和python39
。添加更多 Python 运行时非常简单。b. 或者,指定一个要运行的完整命令以启动模块。 - 模块可以运行的平台列表。目前支持的有
windows
、linux
、docker
、macos
和macos-arm
。 - 模块将处理的队列名称。这可以是模块希望使用的任何名称。
- CodeProject.AI 服务器将为此模块公开的端点(
RouteMaps
)。例如,端点可以是 GET 调用image/detect_animals
,它将映射到 *GET: localhost:32168/v1/image/detect_animal*。此端点的输入和输出也包含在此处,但仅用于文档目的。
一个例子是
{
"Modules": {
"PortraitFilter": {
"Name": "Portrait Filter",
"Version": "1.0.0",
"PublishingInfo" : {
"Description": "Provides a depth-of-field (bokeh) effect on images. Great for selfies.",
"Category": "Image Processing"
},
"LaunchSettings": {
"AutoStart": true,
"FilePath": "PortraitFilter.exe",
"Runtime": "dotnet"
},
"EnvironmentVariables": {
},
"GpuOptions" : {
"InstallGPU": true,
"EnableGPU": true
},
"InstallOptions" : {
"Platforms": [ "windows" ], // errors with Microsoft.ML.OnnxRuntime.NativeMethods in macOS, and System.Drawing issues in Linux
"ModuleReleases": [ // Which server version is compatible with each version of this module.
{ "ModuleVersion": "1.0", "ServerVersionRange": [ "2.5.0", "" ], "ReleaseDate": "2022-06-01" }
]
},
"RouteMaps": [
{
"Name": "Portrait Filter",
"Route": "image/portraitfilter",
"Method": "POST",
"Command": "filter",
"Description": "Blurs the background behind the main subjects in an image.",
"Inputs": [
{
"Name": "image",
"Type": "File",
"Description": "The image to be filtered."
},
{
"Name": "strength",
"Type": "Float",
"Description": "How much to blur the background (0.0 - 1.0).",
"MinValue": 0.0,
"MaxValue": 1.0,
"DefaultValue": 0.5
}
],
"Outputs": [
{
"Name": "success",
"Type": "Boolean",
"Description": "True if successful."
},
{
"Name": "filtered_image",
"Type": "Base64ImageData",
"Description": "The base64 encoded image that has had its background blurred."
}
]
}
]
}
}
}