Skip to content

Commit d59fa6f

Browse files
authored
Merge pull request #21 from Copyleaks/add-text-moderation
add text moderation
2 parents b5bca33 + 1a00ec7 commit d59fa6f

File tree

12 files changed

+341
-1
lines changed

12 files changed

+341
-1
lines changed

demo/demo.rb

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def self.run
3535

3636
# test_submit_url(loginResponse)
3737

38-
test_submit_file(loginResponse)
38+
# test_submit_file(loginResponse)
3939

4040
# test_submit_ocr_file(loginResponse)
4141

@@ -44,6 +44,9 @@ def self.run
4444
# test_ai_detection_source_code(loginResponse)
4545

4646
# test_writing_assistant(loginResponse)
47+
48+
test_text_moderation(loginResponse)
49+
4750
rescue StandardError => e
4851
puts '--------ERROR-------'
4952
puts
@@ -249,6 +252,36 @@ def self.test_writing_assistant(_authToken)
249252
logInfo('Writing Assistant - submit_text', res)
250253
end
251254

255+
def self.test_text_moderation(_authToken)
256+
scanId = DateTime.now.strftime('%Q').to_s
257+
text_moderation_request = Copyleaks::CopyleaksTextModerationRequestModel.new(
258+
text: "This is some text to scan.",
259+
sandbox: true,
260+
language: "en",
261+
labels: [
262+
{ id: "other-v1" },
263+
{ id: "adult-v1" },
264+
{ id: "toxic-v1" },
265+
{ id: "violent-v1" },
266+
{ id: "profanity-v1" },
267+
{ id: "self-harm-v1" },
268+
{ id: "harassment-v1" },
269+
{ id: "hate-speech-v1" },
270+
{ id: "drugs-v1" },
271+
{ id: "firearms-v1" },
272+
{ id: "cybersecurity-v1" }
273+
]
274+
)
275+
res = @copyleaks.text_moderation_client.submit_text(_authToken, scanId, text_moderation_request)
276+
277+
textModerationResponse = Copyleaks::CopyleaksTextModerationResponseModel.new(
278+
moderations: res['moderations'],
279+
legend: res['legend'],
280+
scanned_document: res['scannedDocument'])
281+
282+
logInfo('Text Moderation - submit_text', textModerationResponse)
283+
end
284+
252285
def self.logInfo(title, info = nil)
253286
puts '-------------' + title + '-------------'
254287
puts info.to_json unless info.nil?

lib/copyleaks/api.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
require 'date'
2727
require_relative 'ai_detection_client.rb'
2828
require_relative 'writing_assistant_client.rb'
29+
require_relative 'text_moderation_client.rb'
2930
require_relative 'utils/copyleaks_client.utils'
3031

3132
module Copyleaks
@@ -43,6 +44,7 @@ def initialize
4344
# Initialize clients
4445
@ai_detection_client = AIDetectionClient.new(@api_client)
4546
@writing_assistant_client = WritingAssistantClient.new(@api_client)
47+
@text_moderation_client = TextModerationClient.new(@api_client)
4648
end
4749

4850
# Login to Copyleaks authentication server.
@@ -456,5 +458,8 @@ def ai_detection_client
456458
def writing_assistant_client
457459
@writing_assistant_client
458460
end
461+
def text_moderation_client
462+
@text_moderation_client
463+
end
459464
end
460465
end

lib/copyleaks/models/index.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,13 @@
3131
require_relative 'delete_request_model.rb'
3232
require_relative 'start_request_model.rb'
3333

34+
require_relative 'textModeration/requests/CopyleaksTextModerationRequestModel.rb'
35+
require_relative 'textModeration/responses/submodules/ModerationsModel.rb'
36+
require_relative 'textModeration/responses/submodules/Text.rb'
37+
require_relative 'textModeration/responses/submodules/TextModerationChars.rb'
38+
require_relative 'textModeration/responses/submodules/TextModerationScannedDocument.rb'
39+
require_relative 'textModeration/responses/submodules/TextModerationsLegend.rb'
40+
require_relative 'textModeration/responses/CopyleaksTextModerationResponseModel.rb'
41+
3442
module Copyleaks
3543
end

lib/copyleaks/models/submissions/webhooks/HelperModels/BaseModels/StatusWebhook.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#=
1919
module Copyleaks
2020
class StatusWebhook < Webhook
21+
# @param [Integer] status - The current status of the scan.
2122
attr_reader :status
2223

2324
def initialize(status:, **args)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
require 'json'
2+
3+
module Copyleaks
4+
class CopyleaksTextModerationRequestModel
5+
attr_accessor :text, :sandbox, :language, :labels
6+
7+
# @param text [String] Text to produce Text Moderation report for.
8+
# @param sandbox [Boolean] Use sandbox mode to test your integration. Default: false.
9+
# @param language [String, nil] The language code. Optional; set to nil for auto-detect.
10+
# @param labels [Array<Object>] A list of label configurations (min 1, max 32 elements).
11+
def initialize(text: '', sandbox: false, language: nil, labels: [])
12+
13+
@text = text
14+
@sandbox = sandbox
15+
@language = language
16+
@labels = labels
17+
18+
raise ArgumentError, "String cannot be blank" if @text.nil?
19+
raise ArgumentError, "Labels must be a non-empty array." unless labels.is_a?(Array) && !labels.empty?
20+
raise ArgumentError, "Labels cannot have more than 32 elements." if labels.length > 32
21+
22+
end
23+
24+
def to_json(options = {})
25+
{
26+
text: @text,
27+
sandbox: @sandbox,
28+
language: @language,
29+
labels: @labels
30+
}.to_json(options)
31+
end
32+
33+
def self.from_json(json_string)
34+
data = JSON.parse(json_string, symbolize_names: true)
35+
new(
36+
text: data[:text],
37+
sandbox: data[:sandbox],
38+
language: data[:language],
39+
labels: data[:labels]
40+
)
41+
end
42+
end
43+
end
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
require 'json'
2+
module Copyleaks
3+
4+
class CopyleaksTextModerationResponseModel
5+
attr_accessor :moderations, :legend, :scanned_document
6+
7+
# @param moderations [ModerationsModel] Moderated text segments detected in the input text.
8+
# @param legend [Array<TextModerationsLegend>] An array that provides a lookup for the labels referenced by their numerical indices in the `text.chars.labels` array. Each object within this legend array defines a specific label that was used in the scan.
9+
# @param scanned_document [TextModerationScannedDocument] General information about the scanned document.
10+
def initialize(moderations: ModerationsModel.new, legend: [], scanned_document: TextModerationScannedDocument.new, **_ignored)
11+
@moderations = moderations
12+
@legend = legend
13+
@scanned_document = scanned_document
14+
end
15+
16+
17+
def to_json(options = {})
18+
{
19+
moderations: @moderations ? JSON.parse(@moderations.to_json) : nil,
20+
legend: @legend.map(&:to_json).map { |l| JSON.parse(l) },
21+
scannedDocument: @scanned_document ? JSON.parse(@scanned_document.to_json) : nil
22+
}.to_json(options)
23+
end
24+
25+
26+
def self.from_json(json_string)
27+
data = JSON.parse(json_string, symbolize_names: true)
28+
new(
29+
moderations: data[:moderations] ? ModerationsModel.from_json(data[:moderations].to_json) : nil,
30+
legend: data[:legend].map { |l| TextModerationsLegend.from_json(l.to_json) },
31+
scanned_document: data[:scannedDocument] ? TextModerationScannedDocument.from_json(data[:scannedDocument].to_json) : nil
32+
)
33+
end
34+
end
35+
36+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require 'json'
2+
module Copyleaks
3+
4+
class ModerationsModel
5+
attr_accessor :text
6+
7+
# @param text [Text] Moderated text segments corresponding to the submitted text. Each position in the inner arrays corresponds to a single segment in the textual version.
8+
def initialize(text: Text.new)
9+
@text = text
10+
end
11+
12+
def to_json(options = {})
13+
{
14+
text: @text ? JSON.parse(@text.to_json) : nil
15+
}.to_json(options)
16+
end
17+
18+
19+
def self.from_json(json_string)
20+
data = JSON.parse(json_string, symbolize_names: true)
21+
new(
22+
text: data[:text] ? Text.from_json(data[:text].to_json) : nil
23+
)
24+
end
25+
end
26+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require 'json'
2+
3+
module Copyleaks
4+
class Text
5+
attr_accessor :chars
6+
7+
# @param chars [TextModerationChars] An object that groups together several arrays detailing the properties of labelled segments.
8+
def initialize(chars: TextModerationChars.new)
9+
@chars = chars
10+
end
11+
12+
def to_json(options = {})
13+
{
14+
chars: @chars ? JSON.parse(@chars.to_json) : nil
15+
}.to_json(options)
16+
end
17+
18+
19+
def self.from_json(json_string)
20+
data = JSON.parse(json_string, symbolize_names: true)
21+
new(
22+
chars: data[:chars] ? TextModerationChars.from_json(data[:chars].to_json) : nil
23+
)
24+
end
25+
end
26+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require 'json'
2+
module Copyleaks
3+
4+
class TextModerationChars
5+
attr_accessor :labels, :starts, :lengths
6+
7+
# @param starts [Array<Integer>] Start character position of the labelled segment.
8+
# @param labels [Array<Integer>] Predicted label index for the corresponding segment. The index can be resolved to its ID using the supplied legend.
9+
# @param lengths [Array<Integer>] Labelled segment character length.
10+
def initialize( starts: [],labels: [], lengths: [])
11+
@starts = starts
12+
@labels = labels
13+
@lengths = lengths
14+
end
15+
16+
17+
def to_json(options = {})
18+
{
19+
labels: @labels,
20+
starts: @starts,
21+
lengths: @lengths
22+
}.to_json(options)
23+
end
24+
25+
def self.from_json(json_string)
26+
data = JSON.parse(json_string, symbolize_names: true)
27+
new(
28+
labels: data[:labels],
29+
starts: data[:starts],
30+
lengths: data[:lengths]
31+
)
32+
end
33+
end
34+
35+
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
require 'json'
2+
require 'date'
3+
module Copyleaks
4+
5+
class TextModerationScannedDocument
6+
attr_accessor :scan_id, :total_words, :total_excluded, :actual_credits, :expected_credits, :creation_time
7+
8+
# @param scan_id [String] The scan id given by the user.
9+
# @param total_words [Integer] Total number of words found in the scanned text.
10+
# @param total_excluded [Integer] Total excluded words from the text.
11+
# @param actual_credits [Integer] The cost of credits for this scan.
12+
# @param expected_credits [Integer] The amount of credits that was expected to be spent on the scan.
13+
# @param creation_time [Time] Creation time of the scan.
14+
def initialize(scan_id: '', total_words: 0, total_excluded: 0, actual_credits: 0, expected_credits: 0, creation_time: Time.utc.now)
15+
@scan_id = scan_id
16+
@total_words = total_words
17+
@total_excluded = total_excluded
18+
@actual_credits = actual_credits
19+
@expected_credits = expected_credits
20+
@creation_time = creation_time
21+
end
22+
23+
24+
def to_json(options = {})
25+
{
26+
scanId: @scan_id,
27+
totalWords: @total_words,
28+
totalExcluded: @total_excluded,
29+
actualCredits: @actual_credits,
30+
expectedCredits: @expected_credits,
31+
creationTime: @creation_time.iso8601
32+
}.to_json(options)
33+
end
34+
35+
def self.from_json(json_string)
36+
data = JSON.parse(json_string, symbolize_names: true)
37+
new(
38+
scan_id: data[:scanId],
39+
total_words: data[:totalWords],
40+
total_excluded: data[:totalExcluded],
41+
actual_credits: data[:actualCredits],
42+
expected_credits: data[:expectedCredits],
43+
creation_time: Time.parse(data[:creationTime])
44+
)
45+
end
46+
end
47+
end

0 commit comments

Comments
 (0)