Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ai-content-moderation plugin #11541

Merged
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c80f932
feat: content-moderation plugin
shreemaan-abhishek Aug 30, 2024
d29f928
fix lint
shreemaan-abhishek Aug 30, 2024
8ac0738
Merge branch 'master' of github.com:apache/apisix into content-modera…
shreemaan-abhishek Aug 30, 2024
7ffa489
change priority in lua file
shreemaan-abhishek Aug 30, 2024
5214d0d
change priority and plugins.t
shreemaan-abhishek Aug 30, 2024
2fe1ea2
lint fix
shreemaan-abhishek Aug 30, 2024
5cecf2a
upgrade luarocks version
shreemaan-abhishek Aug 30, 2024
cf08f04
add docs
shreemaan-abhishek Aug 30, 2024
460081e
format doc
shreemaan-abhishek Aug 30, 2024
d475eb0
add to config.json
shreemaan-abhishek Aug 30, 2024
6350d15
update doc
shreemaan-abhishek Sep 2, 2024
f713f87
cleanup
shreemaan-abhishek Sep 2, 2024
e16a823
support ai-model based moderation
shreemaan-abhishek Sep 2, 2024
b21b64b
support secrets
shreemaan-abhishek Sep 2, 2024
ee34e37
rename to ai-content-moderation
shreemaan-abhishek Sep 2, 2024
12529f0
modularise on basis of provider
shreemaan-abhishek Sep 2, 2024
57c59ab
rename
shreemaan-abhishek Sep 10, 2024
093d7a9
cleanup
shreemaan-abhishek Sep 10, 2024
7b52fa5
code review
shreemaan-abhishek Sep 11, 2024
6e3bee2
Merge branch 'master' of github.com:apache/apisix into content-modera…
shreemaan-abhishek Sep 17, 2024
6a2d575
fix method name
shreemaan-abhishek Sep 18, 2024
6bb399c
fix ci
shreemaan-abhishek Sep 18, 2024
1f4528d
code review
shreemaan-abhishek Sep 23, 2024
ef16068
fix doc
shreemaan-abhishek Sep 23, 2024
f6f3451
code review
shreemaan-abhishek Sep 25, 2024
f3672fa
add service provider related info
shreemaan-abhishek Sep 25, 2024
8447d6d
update with LLM proxy
shreemaan-abhishek Oct 3, 2024
0949327
suggestions
shreemaan-abhishek Oct 3, 2024
3a616e1
cleanup
shreemaan-abhishek Oct 3, 2024
4c1f2a6
cleanup lua
shreemaan-abhishek Oct 3, 2024
5b1be91
conf ssl_verify
shreemaan-abhishek Oct 9, 2024
a3e47b2
cleanup
shreemaan-abhishek Oct 9, 2024
81958e4
toxicity_level -> moderation_threshold
shreemaan-abhishek Oct 9, 2024
3da00a2
rm redundant file
shreemaan-abhishek Oct 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ install: runtime
$(ENV_INSTALL) -d $(ENV_INST_LUADIR)/apisix/plugins/ai-proxy/drivers
$(ENV_INSTALL) apisix/plugins/ai-proxy/drivers/*.lua $(ENV_INST_LUADIR)/apisix/plugins/ai-proxy/drivers

# ai-content-moderation plugin
$(ENV_INSTALL) -d $(ENV_INST_LUADIR)/apisix/plugins/ai
$(ENV_INSTALL) apisix/plugins/ai/*.lua $(ENV_INST_LUADIR)/apisix/plugins/ai

$(ENV_INSTALL) bin/apisix $(ENV_INST_BINDIR)/apisix


Expand Down
2 changes: 1 addition & 1 deletion apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ dependencies = {
"lua-resty-t1k = 1.1.5",
"brotli-ffi = 0.3-1",
"lua-ffi-zlib = 0.6-0",
"api7-lua-resty-aws == 2.0.1-1",
"api7-lua-resty-aws == 2.0.2-1",
}

build = {
Expand Down
1 change: 1 addition & 0 deletions apisix/cli/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ local _M = {
"body-transformer",
"ai-prompt-template",
"ai-prompt-decorator",
"ai-content-moderation",
"proxy-mirror",
"proxy-rewrite",
"workflow",
Expand Down
174 changes: 174 additions & 0 deletions apisix/plugins/ai-content-moderation.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core = require("apisix.core")
local aws_instance = require("resty.aws")()
local http = require("resty.http")
local fetch_secrets = require("apisix.secret").fetch_secrets

local next = next
local pairs = pairs
local unpack = unpack
local type = type
local ipairs = ipairs
local require = require
local HTTP_INTERNAL_SERVER_ERROR = ngx.HTTP_INTERNAL_SERVER_ERROR
local HTTP_BAD_REQUEST = ngx.HTTP_BAD_REQUEST


local aws_comprehend_schema = {
type = "object",
properties = {
access_key_id = { type = "string" },
secret_access_key = { type = "string" },
region = { type = "string" },
endpoint = {
type = "string",
pattern = [[^https?://]]
},
},
required = { "access_key_id", "secret_access_key", "region", }
}

local moderation_categories_pattern = "^(PROFANITY|HATE_SPEECH|INSULT|"..
"HARASSMENT_OR_ABUSE|SEXUAL|VIOLENCE_OR_THREAT)$"
local schema = {
type = "object",
properties = {
provider = {
type = "object",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type = "object",
type = "object",
maxProperties = 1,

To make sure next(conf.provider) always returns aws_comprehend

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

properties = {
aws_comprehend = aws_comprehend_schema
},
-- ensure only one provider can be configured while implementing support for
-- other providers
required = { "aws_comprehend" }
},
moderation_categories = {
type = "object",
patternProperties = {
[moderation_categories_pattern] = {
type = "number",
minimum = 0,
maximum = 1
}
},
additionalProperties = false
},
toxicity_level = {
bzp2010 marked this conversation as resolved.
Show resolved Hide resolved
type = "number",
minimum = 0,
maximum = 1,
default = 0.5
},
llm_provider = {
type = "string",
enum = { "openai" },
}
},
required = { "provider", "llm_provider" },
}


local _M = {
version = 0.1,
priority = 1040, -- TODO: might change
name = "ai-content-moderation",
schema = schema,
}


function _M.check_schema(conf)
return core.schema.check(schema, conf)
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two blank lines between functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

function _M.rewrite(conf, ctx)
conf = fetch_secrets(conf, true, conf, "")
if not conf then
return HTTP_INTERNAL_SERVER_ERROR, "failed to retrieve secrets from conf"
end

local body, err = core.request.get_json_request_body_table()
if not body then
return HTTP_BAD_REQUEST, err
end

local msgs = body.messages
if type(msgs) ~= "table" or #msgs < 1 then
return HTTP_BAD_REQUEST, "messages not found in request body"
end

local provider = conf.provider[next(conf.provider)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if conf.provider has multiple properties?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the schema should avoid this from happening.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current schema definition does not seem to be able to prevent multiple properties from being entered incorrectly. It is recommended that you consider adding a maxProperties = 1 constraint to the schema.


-- TODO support secret
local credentials = aws_instance:Credentials({
accessKeyId = provider.access_key_id,
secretAccessKey = provider.secret_access_key,
sessionToken = provider.session_token,
})

local default_endpoint = "https://comprehend." .. provider.region .. ".amazonaws.com"
local scheme, host, port = unpack(http:parse_uri(provider.endpoint or default_endpoint))
local endpoint = scheme .. "://" .. host
aws_instance.config.endpoint = endpoint
aws_instance.config.ssl_verify = false
bzp2010 marked this conversation as resolved.
Show resolved Hide resolved

local comprehend = aws_instance:Comprehend({
credentials = credentials,
endpoint = endpoint,
region = provider.region,
port = port,
})

local ai_module = require("apisix.plugins.ai." .. conf.llm_provider)
local create_request_text_segments = ai_module.create_request_text_segments

local text_segments = create_request_text_segments(msgs)
local res, err = comprehend:detectToxicContent({
LanguageCode = "en",
TextSegments = text_segments,
})

if not res then
core.log.error("failed to send request to ", provider, ": ", err)
return HTTP_INTERNAL_SERVER_ERROR, err
end

local results = res.body and res.body.ResultList
if type(results) ~= "table" or core.table.isempty(results) then
return HTTP_INTERNAL_SERVER_ERROR, "failed to get moderation results from response"
end

for _, result in ipairs(results) do
if conf.moderation_categories then
for _, item in pairs(result.Labels) do
if not conf.moderation_categories[item.Name] then
goto continue
end
if item.Score > conf.moderation_categories[item.Name] then
return HTTP_BAD_REQUEST, "request body exceeds " .. item.Name .. " threshold"
end
::continue::
end
end

if result.Toxicity > conf.toxicity_level then
return HTTP_BAD_REQUEST, "request body exceeds toxicity threshold"
end
end
end

return _M
33 changes: 33 additions & 0 deletions apisix/plugins/ai/openai.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core = require("apisix.core")
local ipairs = ipairs

local _M = {}


function _M.create_request_text_segments(msgs)
local text_segments = {}
for _, msg in ipairs(msgs) do
core.table.insert_tail(text_segments, {
Text = msg.content
})
end
return text_segments
end

return _M
1 change: 1 addition & 0 deletions conf/config.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ plugins: # plugin list (sorted by priority)
- body-transformer # priority: 1080
- ai-prompt-template # priority: 1071
- ai-prompt-decorator # priority: 1070
- ai-content-moderation # priority: 1040 TODO: compare priority with other ai plugins
- proxy-mirror # priority: 1010
- proxy-rewrite # priority: 1008
- workflow # priority: 1006
Expand Down
3 changes: 2 additions & 1 deletion docs/en/latest/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@
"plugins/ext-plugin-post-req",
"plugins/ext-plugin-post-resp",
"plugins/inspect",
"plugins/ocsp-stapling"
"plugins/ocsp-stapling",
"plugins/ai-content-moderation"
]
},
{
Expand Down
Loading
Loading