calmlens 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/lib/calmlens/assets.rb +48 -17
- data/lib/calmlens/cdn.rb +2 -2
- data/lib/calmlens/error_codes.rb +20 -0
- data/lib/calmlens/errors.rb +9 -0
- data/lib/calmlens/lenses.rb +1 -1
- data/lib/calmlens/option_keys.rb +10 -1
- data/lib/calmlens/project_configuration.rb +113 -0
- data/lib/calmlens/server_client.rb +10 -1
- data/lib/calmlens/session.rb +2 -3
- data/lib/calmlens/testing/classification.rb +1 -1
- data/lib/calmlens/testing/fake_api.rb +350 -45
- data/lib/calmlens/testing/mock_decision.rb +47 -6
- data/lib/calmlens/testing/test_inputs.rb +5 -5
- data/lib/calmlens/testing.rb +30 -9
- data/lib/calmlens/transform_schema.rb +0 -14
- data/lib/calmlens/transport.rb +3 -0
- data/lib/calmlens/upload_body.rb +85 -2
- data/lib/calmlens/version.rb +1 -1
- data/lib/calmlens.rb +1 -0
- data/sig/calmlens.rbs +29 -1
- data/sig/error_codes.rbs +10 -0
- data/sig/qualifiers.rbs +1 -0
- data/sig/types.rbs +173 -23
- metadata +3 -2
data/sig/types.rbs
CHANGED
|
@@ -102,7 +102,11 @@ module CalmLens
|
|
|
102
102
|
# Preview. The adaptive stream of audio or video: HLS with fragmented MP4 (CMAF) segments, served
|
|
103
103
|
# at the CDN's `hls` resource (`hls/index.m3u8`) and played by its `embed` resource. Renditions list
|
|
104
104
|
# video from the largest down, then audio.
|
|
105
|
-
type asset_hls = {
|
|
105
|
+
type asset_hls = {
|
|
106
|
+
"status" => String,
|
|
107
|
+
"reason" => String?,
|
|
108
|
+
"renditions" => Array[asset_hls_rendition]
|
|
109
|
+
}
|
|
106
110
|
type asset_rendered_kind = "image" | "pdf" | "video" | "audio"
|
|
107
111
|
# The asset's one displayable file, as the CDN's `rendered` resource serves it: an image, a PDF, or
|
|
108
112
|
# browser-safe video or audio. `peaks` is an audio waveform's normalised peaks.
|
|
@@ -193,13 +197,32 @@ module CalmLens
|
|
|
193
197
|
# What decided the automated status: the `policy`'s categories, the asset's `children`, a
|
|
194
198
|
# `hash-list` match, a `mandatory-rule` or `link-safety`.
|
|
195
199
|
type moderation_source = "policy" | "children" | "hash-list" | "mandatory-rule" | "link-safety"
|
|
200
|
+
# The policy that made a decision: its ID, its revision then and, for a policy from a preset, the
|
|
201
|
+
# preset release it used.
|
|
202
|
+
type decision_policy = {
|
|
203
|
+
"id" => String,
|
|
204
|
+
"revision" => Integer,
|
|
205
|
+
"preset" => { "id" => String, "version" => Integer }?
|
|
206
|
+
}
|
|
207
|
+
# A review the human review queue is waiting for: when the asset joined it (Unix milliseconds),
|
|
208
|
+
# why, and the categories that made the decision uncertain.
|
|
209
|
+
type asset_pending_review = {
|
|
210
|
+
"requestedAt" => Integer,
|
|
211
|
+
"reason" => "sampled" | "uncertain",
|
|
212
|
+
"uncertainCategories" => Array[String]
|
|
213
|
+
}
|
|
196
214
|
# Every field but `status`, `manualReviews`, `flaggedCategories`, `regions` and `timeline` is `nil`
|
|
197
|
-
# until moderation decides.
|
|
215
|
+
# until moderation decides; `pendingReview` is `nil` when no review is waiting.
|
|
198
216
|
type asset_moderation = {
|
|
199
217
|
"manualReviews" => Array[asset_review],
|
|
200
218
|
"status" => asset_moderation_status,
|
|
201
219
|
# The policy's original decision; a reviewer's decision can change `status` without changing it.
|
|
202
220
|
"automatedStatus" => asset_moderation_decision?,
|
|
221
|
+
# The policy that made the automated decision, as it was then.
|
|
222
|
+
"policy" => decision_policy?,
|
|
223
|
+
# The review the human review queue is waiting for, set with the automated decision that
|
|
224
|
+
# joined the queue; `nil` when no review is waiting.
|
|
225
|
+
"pendingReview" => asset_pending_review?,
|
|
203
226
|
"source" => moderation_source?,
|
|
204
227
|
# The mandatory rule that decided, when `source` is `mandatory-rule`; otherwise `nil`.
|
|
205
228
|
"rule" => String?,
|
|
@@ -249,6 +272,8 @@ module CalmLens
|
|
|
249
272
|
"id" => String,
|
|
250
273
|
"projectId" => String,
|
|
251
274
|
?"parentId" => String?,
|
|
275
|
+
# The pages of the parent document a child shows, from 1; empty when unknown or not a child.
|
|
276
|
+
?"parentPages" => Array[Integer],
|
|
252
277
|
?"folderId" => String?,
|
|
253
278
|
?"uploadPresetId" => String?,
|
|
254
279
|
"createdAt" => Integer,
|
|
@@ -276,6 +301,9 @@ module CalmLens
|
|
|
276
301
|
type likelihood = "very-unlikely" | "unlikely" | "possible" | "likely" | "very-likely"
|
|
277
302
|
# not-supported: this processing path cannot assess the signal; unavailable: assessment failed.
|
|
278
303
|
type not_evaluated_reason = "not-supported" | "unavailable"
|
|
304
|
+
# A processing feature's reason, which adds in-children: a document's or website's images are each
|
|
305
|
+
# a child asset with its own result (`assets.list_children`).
|
|
306
|
+
type feature_not_evaluated_reason = not_evaluated_reason | "in-children"
|
|
279
307
|
type classification_category = "sexual" | "violence" | "self-harm" | "harassment" | "hate" | "criminal-activity"
|
|
280
308
|
|
|
281
309
|
# `status: "evaluated"` carries `someScore`, `likelihood` and optionally `allScore`;
|
|
@@ -324,13 +352,13 @@ module CalmLens
|
|
|
324
352
|
type person_detection_result = {
|
|
325
353
|
"status" => "evaluated" | "not-evaluated",
|
|
326
354
|
?"people" => Array[detected_person],
|
|
327
|
-
?"reason" =>
|
|
355
|
+
?"reason" => feature_not_evaluated_reason
|
|
328
356
|
}
|
|
329
357
|
# `status: "evaluated"` carries `faces`; `"not-evaluated"` carries `reason`.
|
|
330
358
|
type face_detection_result = {
|
|
331
359
|
"status" => "evaluated" | "not-evaluated",
|
|
332
360
|
?"faces" => Array[detected_face],
|
|
333
|
-
?"reason" =>
|
|
361
|
+
?"reason" => feature_not_evaluated_reason
|
|
334
362
|
}
|
|
335
363
|
type detected_qr_code = { "value" => String, "box" => bounding_box }
|
|
336
364
|
# A web link found in a QR code or in the text OCR extracted.
|
|
@@ -340,7 +368,7 @@ module CalmLens
|
|
|
340
368
|
"status" => "evaluated" | "not-evaluated",
|
|
341
369
|
?"qrCodes" => Array[detected_qr_code],
|
|
342
370
|
?"links" => Array[detected_link],
|
|
343
|
-
?"reason" =>
|
|
371
|
+
?"reason" => feature_not_evaluated_reason
|
|
344
372
|
}
|
|
345
373
|
# Link safety (preview, LinkSafety.ts).
|
|
346
374
|
# What a link's destination is: `safe` when every reputation check passed, `adult` or `gambling`
|
|
@@ -404,16 +432,15 @@ module CalmLens
|
|
|
404
432
|
"status" => "evaluated" | "not-evaluated",
|
|
405
433
|
?"provenance" => "ai-generated" | "ai-edited" | "unknown",
|
|
406
434
|
?"signals" => Array[provenance_signal],
|
|
407
|
-
?"reason" =>
|
|
435
|
+
?"reason" => feature_not_evaluated_reason
|
|
408
436
|
}
|
|
409
437
|
# Where OCR found text in an image, and whether it is personal information.
|
|
410
438
|
type text_region = { "box" => bounding_box, "personalInformation" => bool }
|
|
411
|
-
# `status: "evaluated"` carries `textRegions`, where OCR found text
|
|
412
|
-
# these regions); `"not-evaluated"` carries `reason`. The text itself is `content.extractedText`.
|
|
439
|
+
# `status: "evaluated"` carries `textRegions`, where OCR found text; `"not-evaluated"` carries `reason`. The text itself is `content.extractedText`.
|
|
413
440
|
type ocr_result = {
|
|
414
441
|
"status" => "evaluated" | "not-evaluated",
|
|
415
442
|
?"textRegions" => Array[text_region],
|
|
416
|
-
?"reason" =>
|
|
443
|
+
?"reason" => feature_not_evaluated_reason
|
|
417
444
|
}
|
|
418
445
|
|
|
419
446
|
# How strongly each assessed category meets the policy and what the policy does with it.
|
|
@@ -424,7 +451,7 @@ module CalmLens
|
|
|
424
451
|
# What decided a category's action: its `default` action, a policy score `below-threshold`, or the
|
|
425
452
|
# `allowance` or `restriction` rules listed by `indexes` (at least one, the decisive rule first).
|
|
426
453
|
type category_policy_source = { "kind" => "default" | "below-threshold" } |
|
|
427
|
-
{ "kind" => "allowance" | "restriction", "indexes" => Array[Integer] }
|
|
454
|
+
{ "kind" => "allowance" | "restriction", "indexes" => Array[Integer], "conditionScore" => Float }
|
|
428
455
|
type category_policy_settings_snapshot = {
|
|
429
456
|
"action" => flagged_content_action,
|
|
430
457
|
"allowances" => Array[policy_rule_snapshot], "restrictions" => Array[policy_rule_snapshot]
|
|
@@ -517,11 +544,6 @@ module CalmLens
|
|
|
517
544
|
?anim: bool,
|
|
518
545
|
?background: String,
|
|
519
546
|
?blur: number,
|
|
520
|
-
?redact: {
|
|
521
|
-
?text: bool,
|
|
522
|
-
?personalInformation: bool,
|
|
523
|
-
?faces: bool
|
|
524
|
-
},
|
|
525
547
|
?border: {
|
|
526
548
|
?color: String,
|
|
527
549
|
?width: number
|
|
@@ -564,11 +586,6 @@ module CalmLens
|
|
|
564
586
|
?"anim" => bool,
|
|
565
587
|
?"background" => String,
|
|
566
588
|
?"blur" => number,
|
|
567
|
-
?"redact" => {
|
|
568
|
-
?"text" => bool,
|
|
569
|
-
?"personalInformation" => bool,
|
|
570
|
-
?"faces" => bool
|
|
571
|
-
},
|
|
572
589
|
?"border" => {
|
|
573
590
|
?"color" => String,
|
|
574
591
|
?"width" => number
|
|
@@ -609,12 +626,12 @@ module CalmLens
|
|
|
609
626
|
type transform_input = String | image_transform_options_input
|
|
610
627
|
|
|
611
628
|
type lens_type = "image" | "video" | "audio" | "document" | "website"
|
|
612
|
-
# ENSURE_LENS_BODY_SCHEMA: a lens definition, which the CDN serves once it is saved.
|
|
629
|
+
# ENSURE_LENS_BODY_SCHEMA: a lens definition, which the CDN serves once it is saved unless `active` is false.
|
|
613
630
|
type lens_definition = {
|
|
614
631
|
identifier: String,
|
|
615
632
|
name: String,
|
|
616
633
|
type: lens_type,
|
|
617
|
-
active: bool,
|
|
634
|
+
?active: bool,
|
|
618
635
|
?description: String?,
|
|
619
636
|
?transform: image_transform_options_input?
|
|
620
637
|
}
|
|
@@ -636,6 +653,81 @@ module CalmLens
|
|
|
636
653
|
"nextCursor" => String?
|
|
637
654
|
}
|
|
638
655
|
|
|
656
|
+
# ---- Configuration as data (UploadPreset.ts, ProjectConfiguration.ts) --------------------------
|
|
657
|
+
|
|
658
|
+
type upload_preset_access = "token" | "anyone"
|
|
659
|
+
# An upload preset's processing options, as the API returns them.
|
|
660
|
+
type upload_preset_processing_options = {
|
|
661
|
+
?"keepContentAfterProcessing" => bool?,
|
|
662
|
+
?"storeSensitiveMetadata" => bool?,
|
|
663
|
+
?"features" => {
|
|
664
|
+
?"ocr" => { "enabled" => bool }?,
|
|
665
|
+
?"personDetection" => { "enabled" => bool }?,
|
|
666
|
+
?"faceDetection" => { "enabled" => bool, ?"ageEstimation" => bool? }?,
|
|
667
|
+
?"linkDetection" => { "enabled" => bool }?,
|
|
668
|
+
?"streaming" => { "enabled" => bool }?
|
|
669
|
+
}?
|
|
670
|
+
}
|
|
671
|
+
# The rules for uploads made from browsers and apps. `key` is unique in its project; `revision`
|
|
672
|
+
# counts changes, starting at 1. Send it back with a change.
|
|
673
|
+
type upload_preset = {
|
|
674
|
+
"id" => String,
|
|
675
|
+
"projectId" => String,
|
|
676
|
+
?"createdByUserId" => String?,
|
|
677
|
+
"key" => String,
|
|
678
|
+
"revision" => Integer,
|
|
679
|
+
"name" => String,
|
|
680
|
+
"access" => upload_preset_access,
|
|
681
|
+
"enabled" => bool,
|
|
682
|
+
?"allowedContentTypes" => Array[String]?,
|
|
683
|
+
?"maxSizeInBytes" => Integer?,
|
|
684
|
+
?"folderId" => String?,
|
|
685
|
+
?"policyId" => String?,
|
|
686
|
+
"visibility" => asset_visibility,
|
|
687
|
+
?"processingOptions" => upload_preset_processing_options?,
|
|
688
|
+
"revealDecision" => bool,
|
|
689
|
+
?"dailyUploadLimit" => Integer?,
|
|
690
|
+
?"allowedOrigins" => Array[String]?,
|
|
691
|
+
"createdAt" => Integer,
|
|
692
|
+
"updatedAt" => Integer
|
|
693
|
+
}
|
|
694
|
+
type upload_preset_page = { "items" => Array[upload_preset], "hasMore" => bool, "nextCursor" => String? }
|
|
695
|
+
type ensure_upload_presets_response = { "uploadPresets" => Array[upload_preset] }
|
|
696
|
+
|
|
697
|
+
type remote_url_rule = { "mode" => "allow" | "deny", "domains" => Array[String] }
|
|
698
|
+
type human_review_settings = {
|
|
699
|
+
"allowedSamplePercent" => number,
|
|
700
|
+
"restrictedSamplePercent" => number,
|
|
701
|
+
"uncertaintyMarginPercent" => number,
|
|
702
|
+
"reviewMissingEvidence" => bool
|
|
703
|
+
}
|
|
704
|
+
type public_project_settings = {
|
|
705
|
+
"optOutJurisdictions" => Array[String],
|
|
706
|
+
"blockUnmoderatedAssets" => bool,
|
|
707
|
+
"storeSensitiveMetadata" => bool,
|
|
708
|
+
"streamingEnabled" => bool,
|
|
709
|
+
"aiMediaSearchEnabled" => bool,
|
|
710
|
+
"remoteUrlRule" => remote_url_rule?,
|
|
711
|
+
"websiteSubmissionsPerMinute" => Integer?,
|
|
712
|
+
"humanReview" => human_review_settings
|
|
713
|
+
}
|
|
714
|
+
# The project's settings, with defaults filled in. `revision` counts changes to the settings and
|
|
715
|
+
# metadata fields, starting at 1. Send it back with a change.
|
|
716
|
+
type project_settings_resource = { "projectId" => String, "revision" => Integer, "settings" => public_project_settings }
|
|
717
|
+
|
|
718
|
+
type metadata_field_type = "string" | "number" | "boolean" | "date" | "url"
|
|
719
|
+
type metadata_field_icon = "tag" | "hash" | "user" | "folder" | "layers" | "photo" | "link"
|
|
720
|
+
# A metadata field the portal shows and filters by. `color` is `#rrggbb`.
|
|
721
|
+
type metadata_field = {
|
|
722
|
+
"id" => String,
|
|
723
|
+
"title" => String,
|
|
724
|
+
?"description" => String,
|
|
725
|
+
"type" => metadata_field_type,
|
|
726
|
+
"icon" => metadata_field_icon,
|
|
727
|
+
"color" => String
|
|
728
|
+
}
|
|
729
|
+
type metadata_fields_resource = { "projectId" => String, "revision" => Integer, "fields" => Array[metadata_field] }
|
|
730
|
+
|
|
639
731
|
# ---- Folders (Folder.ts) --------------------------------------------------------------------
|
|
640
732
|
|
|
641
733
|
type folder = {
|
|
@@ -1067,7 +1159,7 @@ module CalmLens
|
|
|
1067
1159
|
identifier: String,
|
|
1068
1160
|
name: String,
|
|
1069
1161
|
type: lens_type,
|
|
1070
|
-
active: bool,
|
|
1162
|
+
?active: bool,
|
|
1071
1163
|
?description: String?,
|
|
1072
1164
|
?transform: image_transform_options_input?,
|
|
1073
1165
|
?request_options: request_options
|
|
@@ -1087,6 +1179,64 @@ module CalmLens
|
|
|
1087
1179
|
?request_options: request_options
|
|
1088
1180
|
}
|
|
1089
1181
|
|
|
1182
|
+
# `sort` is `createdAt` and `id`, `createdAt` (oldest first) by default.
|
|
1183
|
+
type list_upload_presets_options = { ?cursor: String, ?page_size: Integer, ?sort: sort, ?request_options: request_options }
|
|
1184
|
+
# One preset's whole definition, by `key`; fields left out take their defaults. Send the `revision`
|
|
1185
|
+
# you read (0 for a preset that must not exist yet) to refuse a change made since.
|
|
1186
|
+
type upload_preset_definition = {
|
|
1187
|
+
key: String,
|
|
1188
|
+
name: String,
|
|
1189
|
+
?revision: Integer,
|
|
1190
|
+
?access: upload_preset_access,
|
|
1191
|
+
?enabled: bool,
|
|
1192
|
+
?allowed_content_types: Array[String]?,
|
|
1193
|
+
?max_size_in_bytes: Integer?,
|
|
1194
|
+
?folder_id: String?,
|
|
1195
|
+
?policy_id: String?,
|
|
1196
|
+
?visibility: asset_visibility,
|
|
1197
|
+
?processing_options: processing_options_input?,
|
|
1198
|
+
?reveal_decision: bool,
|
|
1199
|
+
?daily_upload_limit: Integer?,
|
|
1200
|
+
?allowed_origins: Array[String]?
|
|
1201
|
+
}
|
|
1202
|
+
type ensure_upload_presets_options = { upload_presets: Array[upload_preset_definition], ?request_options: request_options }
|
|
1203
|
+
type upload_preset_id_options = { upload_preset_id: String, ?request_options: request_options }
|
|
1204
|
+
# The complete settings: those left out return to their defaults.
|
|
1205
|
+
type project_settings_input = {
|
|
1206
|
+
?opt_out_jurisdictions: Array[String],
|
|
1207
|
+
?block_unmoderated_assets: bool,
|
|
1208
|
+
?store_sensitive_metadata: bool,
|
|
1209
|
+
?streaming_enabled: bool,
|
|
1210
|
+
?ai_media_search_enabled: bool,
|
|
1211
|
+
?remote_url_rule: { mode: "allow" | "deny", domains: Array[String] }?,
|
|
1212
|
+
?website_submissions_per_minute: Integer?,
|
|
1213
|
+
?human_review: {
|
|
1214
|
+
?allowed_sample_percent: number,
|
|
1215
|
+
?restricted_sample_percent: number,
|
|
1216
|
+
?uncertainty_margin_percent: number,
|
|
1217
|
+
?review_missing_evidence: bool
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
# Send the `revision` you read to refuse settings changed since. `search_indexing_budget_units` is
|
|
1221
|
+
# needed when turning on `ai_media_search_enabled`.
|
|
1222
|
+
type update_project_settings_options = {
|
|
1223
|
+
?revision: Integer,
|
|
1224
|
+
settings: project_settings_input,
|
|
1225
|
+
?search_indexing_budget_units: number,
|
|
1226
|
+
?request_options: request_options
|
|
1227
|
+
}
|
|
1228
|
+
type metadata_field_input = {
|
|
1229
|
+
id: String,
|
|
1230
|
+
title: String,
|
|
1231
|
+
?description: String,
|
|
1232
|
+
type: metadata_field_type,
|
|
1233
|
+
icon: metadata_field_icon,
|
|
1234
|
+
color: String
|
|
1235
|
+
}
|
|
1236
|
+
# Fields to create or replace by ID; other fields are kept.
|
|
1237
|
+
type ensure_metadata_fields_options = { ?revision: Integer, fields: Array[metadata_field_input], ?request_options: request_options }
|
|
1238
|
+
type delete_metadata_field_options = { field_id: String, ?revision: Integer, ?request_options: request_options }
|
|
1239
|
+
|
|
1090
1240
|
type asset_url_options = {
|
|
1091
1241
|
# Exactly one of `asset_id` and `external_id`.
|
|
1092
1242
|
?asset_id: String,
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: calmlens
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- CalmLens
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-11-
|
|
11
|
+
date: 2026-11-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: 'Server-side client for the CalmLens API: moderation, uploads, events,
|
|
14
14
|
webhooks and CDN delivery.'
|
|
@@ -32,6 +32,7 @@ files:
|
|
|
32
32
|
- lib/calmlens/moderation_context.rb
|
|
33
33
|
- lib/calmlens/option_keys.rb
|
|
34
34
|
- lib/calmlens/policies.rb
|
|
35
|
+
- lib/calmlens/project_configuration.rb
|
|
35
36
|
- lib/calmlens/resource.rb
|
|
36
37
|
- lib/calmlens/response.rb
|
|
37
38
|
- lib/calmlens/server_client.rb
|