safetygates 0.1.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.
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/package.json +30 -0
- package/src/index.d.ts +99 -0
- package/src/index.js +228 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CycleCore Technologies LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# SafetyGates SDK for Node.js
|
|
2
|
+
|
|
3
|
+
Official Node.js client for [SafetyGates](https://cyclecore.ai/safetygates) content moderation API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install safetygates
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
const SafetyGates = require('safetygates');
|
|
15
|
+
|
|
16
|
+
const client = new SafetyGates('sg_live_your_api_key');
|
|
17
|
+
|
|
18
|
+
// Classify text
|
|
19
|
+
const result = await client.classify('you suck at this game', ['toxic', 'harassment']);
|
|
20
|
+
console.log(result.results.toxic.label); // true
|
|
21
|
+
console.log(result.results.toxic.confidence); // 0.92
|
|
22
|
+
|
|
23
|
+
// Convenience methods
|
|
24
|
+
if (await client.isToxic('some message')) {
|
|
25
|
+
console.log('Message blocked');
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Get Your API Key
|
|
30
|
+
|
|
31
|
+
Sign up for free at [sg-api.cyclecore.ai/signup](https://sg-api.cyclecore.ai/signup)
|
|
32
|
+
|
|
33
|
+
- **Free tier:** 1,000 requests/day
|
|
34
|
+
- **No credit card required**
|
|
35
|
+
|
|
36
|
+
## API Reference
|
|
37
|
+
|
|
38
|
+
### Constructor
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
const client = new SafetyGates(apiKey, options);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Parameter | Type | Description |
|
|
45
|
+
|-----------|------|-------------|
|
|
46
|
+
| `apiKey` | string | Your API key (required) |
|
|
47
|
+
| `options.baseUrl` | string | API URL (default: `https://sg-api.cyclecore.ai`) |
|
|
48
|
+
| `options.timeout` | number | Request timeout in ms (default: 10000) |
|
|
49
|
+
|
|
50
|
+
### classify(text, gates)
|
|
51
|
+
|
|
52
|
+
Classify a single text.
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const result = await client.classify('hello world', ['toxic', 'spam']);
|
|
56
|
+
|
|
57
|
+
// Result:
|
|
58
|
+
{
|
|
59
|
+
results: {
|
|
60
|
+
toxic: { label: false, confidence: 0.12 },
|
|
61
|
+
spam: { label: false, confidence: 0.08 }
|
|
62
|
+
},
|
|
63
|
+
latency_us: 1234.5
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### classifyBatch(texts, gates)
|
|
68
|
+
|
|
69
|
+
Classify multiple texts (up to 10,000).
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const result = await client.classifyBatch(
|
|
73
|
+
['hello', 'you suck', 'nice game'],
|
|
74
|
+
['toxic']
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Result:
|
|
78
|
+
{
|
|
79
|
+
results: [
|
|
80
|
+
{ toxic: { label: false, confidence: 0.1 } },
|
|
81
|
+
{ toxic: { label: true, confidence: 0.94 } },
|
|
82
|
+
{ toxic: { label: false, confidence: 0.05 } }
|
|
83
|
+
],
|
|
84
|
+
total_latency_us: 3456.7,
|
|
85
|
+
items_per_second: 867.5
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### isToxic(text, threshold?)
|
|
90
|
+
|
|
91
|
+
Convenience method to check toxicity.
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
if (await client.isToxic(message)) {
|
|
95
|
+
// Block message
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// With custom threshold
|
|
99
|
+
if (await client.isToxic(message, 0.8)) {
|
|
100
|
+
// Only block if >80% confident
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### isSpam(text, threshold?)
|
|
105
|
+
|
|
106
|
+
Convenience method to check spam.
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
if (await client.isSpam(message)) {
|
|
110
|
+
// Block spam
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### listGates()
|
|
115
|
+
|
|
116
|
+
Get available classification gates.
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
const { gates } = await client.listGates();
|
|
120
|
+
// [{ id: 'toxic', category: 'moderation', ... }, ...]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Available Gates
|
|
124
|
+
|
|
125
|
+
| Gate | Language | Description |
|
|
126
|
+
|------|----------|-------------|
|
|
127
|
+
| `toxic` | English | Toxic/abusive content |
|
|
128
|
+
| `spam` | English | Spam/promotional |
|
|
129
|
+
| `hate` | English | Hate speech |
|
|
130
|
+
| `nsfw` | English | Adult content |
|
|
131
|
+
| `harassment` | English | Harassment/bullying |
|
|
132
|
+
| `toxic_es` | Spanish | Toxic content |
|
|
133
|
+
| `spam_es` | Spanish | Spam |
|
|
134
|
+
| `hate_es` | Spanish | Hate speech |
|
|
135
|
+
| `toxic_pt` | Portuguese | Toxic content |
|
|
136
|
+
| `toxic_fr` | French | Toxic content |
|
|
137
|
+
|
|
138
|
+
Use the `GATES` constant for autocomplete:
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
const { GATES } = require('safetygates');
|
|
142
|
+
client.classify(text, [GATES.TOXIC, GATES.SPAM]);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Error Handling
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
const { SafetyGatesError } = require('safetygates');
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
await client.classify('test', ['invalid_gate']);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
if (err instanceof SafetyGatesError) {
|
|
154
|
+
console.log(err.statusCode); // 400
|
|
155
|
+
console.log(err.detail); // { detail: "Unknown gates: ['invalid_gate']" }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Discord Bot Example
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
const SafetyGates = require('safetygates');
|
|
164
|
+
const { Client, GatewayIntentBits } = require('discord.js');
|
|
165
|
+
|
|
166
|
+
const sg = new SafetyGates(process.env.SAFETYGATES_KEY);
|
|
167
|
+
const discord = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });
|
|
168
|
+
|
|
169
|
+
discord.on('messageCreate', async (message) => {
|
|
170
|
+
if (message.author.bot) return;
|
|
171
|
+
|
|
172
|
+
if (await sg.isToxic(message.content, 0.7)) {
|
|
173
|
+
await message.delete();
|
|
174
|
+
await message.channel.send(`${message.author}, please keep it civil.`);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
discord.login(process.env.DISCORD_TOKEN);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## TypeScript
|
|
182
|
+
|
|
183
|
+
Full TypeScript support included:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import SafetyGates, { ClassifyResult, GATES } from 'safetygates';
|
|
187
|
+
|
|
188
|
+
const client = new SafetyGates('sg_live_xxx');
|
|
189
|
+
const result: ClassifyResult = await client.classify('test', [GATES.TOXIC]);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Links
|
|
193
|
+
|
|
194
|
+
- [Documentation](https://sg-api.cyclecore.ai/docs)
|
|
195
|
+
- [Get API Key](https://sg-api.cyclecore.ai/signup)
|
|
196
|
+
- [CycleCore](https://cyclecore.ai)
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "safetygates",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official SDK for SafetyGates content moderation API",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "node test/test.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"content-moderation",
|
|
12
|
+
"safety",
|
|
13
|
+
"toxic",
|
|
14
|
+
"spam",
|
|
15
|
+
"hate-speech",
|
|
16
|
+
"moderation",
|
|
17
|
+
"discord",
|
|
18
|
+
"gaming",
|
|
19
|
+
"chat"
|
|
20
|
+
],
|
|
21
|
+
"author": "CycleCore Technologies <hi@cyclecore.ai>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"homepage": "https://cyclecore.ai/safetygates",
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=16.0.0"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"src/"
|
|
29
|
+
]
|
|
30
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SafetyGates SDK TypeScript Definitions
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026 CycleCore Technologies LLC
|
|
5
|
+
* Licensed under the MIT License
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface GateResult {
|
|
9
|
+
label: boolean;
|
|
10
|
+
confidence: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ClassifyResult {
|
|
14
|
+
results: Record<string, GateResult>;
|
|
15
|
+
latency_us: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BatchClassifyResult {
|
|
19
|
+
results: Array<Record<string, GateResult>>;
|
|
20
|
+
total_latency_us: number;
|
|
21
|
+
items_per_second: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface GateInfo {
|
|
25
|
+
id: string;
|
|
26
|
+
category: string;
|
|
27
|
+
description: string;
|
|
28
|
+
threshold: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface GatesListResult {
|
|
32
|
+
gates: GateInfo[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface HealthResult {
|
|
36
|
+
status: string;
|
|
37
|
+
gates_loaded: number;
|
|
38
|
+
available_gates: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SafetyGatesOptions {
|
|
42
|
+
baseUrl?: string;
|
|
43
|
+
timeout?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export declare const GATES: {
|
|
47
|
+
TOXIC: 'toxic';
|
|
48
|
+
SPAM: 'spam';
|
|
49
|
+
HATE: 'hate';
|
|
50
|
+
NSFW: 'nsfw';
|
|
51
|
+
HARASSMENT: 'harassment';
|
|
52
|
+
TOXIC_ES: 'toxic_es';
|
|
53
|
+
SPAM_ES: 'spam_es';
|
|
54
|
+
HATE_ES: 'hate_es';
|
|
55
|
+
TOXIC_PT: 'toxic_pt';
|
|
56
|
+
TOXIC_FR: 'toxic_fr';
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export declare class SafetyGatesError extends Error {
|
|
60
|
+
statusCode: number;
|
|
61
|
+
detail: any;
|
|
62
|
+
constructor(message: string, statusCode: number, detail: any);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export declare class SafetyGates {
|
|
66
|
+
constructor(apiKey: string, options?: SafetyGatesOptions);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Classify a single text
|
|
70
|
+
*/
|
|
71
|
+
classify(text: string, gates?: string[]): Promise<ClassifyResult>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Classify multiple texts in batch
|
|
75
|
+
*/
|
|
76
|
+
classifyBatch(texts: string[], gates?: string[]): Promise<BatchClassifyResult>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if text is toxic (convenience method)
|
|
80
|
+
*/
|
|
81
|
+
isToxic(text: string, threshold?: number): Promise<boolean>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if text is spam (convenience method)
|
|
85
|
+
*/
|
|
86
|
+
isSpam(text: string, threshold?: number): Promise<boolean>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get available gates
|
|
90
|
+
*/
|
|
91
|
+
listGates(): Promise<GatesListResult>;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Health check
|
|
95
|
+
*/
|
|
96
|
+
health(): Promise<HealthResult>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default SafetyGates;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SafetyGates SDK for Node.js
|
|
3
|
+
* Official client library for the SafetyGates content moderation API
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2026 CycleCore Technologies LLC
|
|
6
|
+
* Licensed under the MIT License
|
|
7
|
+
* https://cyclecore.ai/safetygates
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const SafetyGates = require('safetygates');
|
|
13
|
+
* const client = new SafetyGates('sg_live_xxx');
|
|
14
|
+
* const result = await client.classify('hello world', ['toxic']);
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const https = require('https');
|
|
18
|
+
const http = require('http');
|
|
19
|
+
|
|
20
|
+
const DEFAULT_BASE_URL = 'https://sg-api.cyclecore.ai';
|
|
21
|
+
const DEFAULT_TIMEOUT = 10000;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Available classification gates
|
|
25
|
+
*/
|
|
26
|
+
const GATES = {
|
|
27
|
+
// English
|
|
28
|
+
TOXIC: 'toxic',
|
|
29
|
+
SPAM: 'spam',
|
|
30
|
+
HATE: 'hate',
|
|
31
|
+
NSFW: 'nsfw',
|
|
32
|
+
HARASSMENT: 'harassment',
|
|
33
|
+
// Spanish
|
|
34
|
+
TOXIC_ES: 'toxic_es',
|
|
35
|
+
SPAM_ES: 'spam_es',
|
|
36
|
+
HATE_ES: 'hate_es',
|
|
37
|
+
// Portuguese
|
|
38
|
+
TOXIC_PT: 'toxic_pt',
|
|
39
|
+
// French
|
|
40
|
+
TOXIC_FR: 'toxic_fr',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class SafetyGatesError extends Error {
|
|
44
|
+
constructor(message, statusCode, detail) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = 'SafetyGatesError';
|
|
47
|
+
this.statusCode = statusCode;
|
|
48
|
+
this.detail = detail;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class SafetyGates {
|
|
53
|
+
/**
|
|
54
|
+
* Create a SafetyGates client
|
|
55
|
+
* @param {string} apiKey - Your API key (starts with sg_live_ or sg_test_)
|
|
56
|
+
* @param {Object} options - Configuration options
|
|
57
|
+
* @param {string} options.baseUrl - API base URL (default: https://sg-api.cyclecore.ai)
|
|
58
|
+
* @param {number} options.timeout - Request timeout in ms (default: 10000)
|
|
59
|
+
*/
|
|
60
|
+
constructor(apiKey, options = {}) {
|
|
61
|
+
if (!apiKey) {
|
|
62
|
+
throw new Error('API key is required. Get one at https://sg-api.cyclecore.ai/signup');
|
|
63
|
+
}
|
|
64
|
+
this.apiKey = apiKey;
|
|
65
|
+
this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;
|
|
66
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Make HTTP request to API
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
_request(method, path, body = null) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const url = new URL(path, this.baseUrl);
|
|
76
|
+
const isHttps = url.protocol === 'https:';
|
|
77
|
+
const lib = isHttps ? https : http;
|
|
78
|
+
|
|
79
|
+
const options = {
|
|
80
|
+
hostname: url.hostname,
|
|
81
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
82
|
+
path: url.pathname,
|
|
83
|
+
method,
|
|
84
|
+
headers: {
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
'X-API-Key': this.apiKey,
|
|
87
|
+
'User-Agent': 'safetygates-node/1.0.0',
|
|
88
|
+
},
|
|
89
|
+
timeout: this.timeout,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const req = lib.request(options, (res) => {
|
|
93
|
+
let data = '';
|
|
94
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
95
|
+
res.on('end', () => {
|
|
96
|
+
try {
|
|
97
|
+
const json = JSON.parse(data);
|
|
98
|
+
if (res.statusCode >= 400) {
|
|
99
|
+
reject(new SafetyGatesError(
|
|
100
|
+
json.detail || 'API error',
|
|
101
|
+
res.statusCode,
|
|
102
|
+
json
|
|
103
|
+
));
|
|
104
|
+
} else {
|
|
105
|
+
resolve(json);
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
reject(new SafetyGatesError('Invalid JSON response', res.statusCode, data));
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
req.on('error', (e) => {
|
|
114
|
+
reject(new SafetyGatesError(`Request failed: ${e.message}`, 0, null));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
req.on('timeout', () => {
|
|
118
|
+
req.destroy();
|
|
119
|
+
reject(new SafetyGatesError('Request timeout', 0, null));
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (body) {
|
|
123
|
+
req.write(JSON.stringify(body));
|
|
124
|
+
}
|
|
125
|
+
req.end();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Classify a single text
|
|
131
|
+
* @param {string} text - Text to classify
|
|
132
|
+
* @param {string[]} gates - Gates to check (default: ['toxic'])
|
|
133
|
+
* @returns {Promise<ClassifyResult>}
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* const result = await client.classify('you suck', ['toxic', 'harassment']);
|
|
137
|
+
* console.log(result.results.toxic.label); // true
|
|
138
|
+
* console.log(result.results.toxic.confidence); // 0.92
|
|
139
|
+
*/
|
|
140
|
+
async classify(text, gates = ['toxic']) {
|
|
141
|
+
if (!text || typeof text !== 'string') {
|
|
142
|
+
throw new Error('Text must be a non-empty string');
|
|
143
|
+
}
|
|
144
|
+
if (!Array.isArray(gates) || gates.length === 0) {
|
|
145
|
+
throw new Error('Gates must be a non-empty array');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return this._request('POST', '/v1/classify', { text, gates });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Classify multiple texts in batch
|
|
153
|
+
* @param {string[]} texts - Array of texts to classify (max 10,000)
|
|
154
|
+
* @param {string[]} gates - Gates to check (default: ['toxic'])
|
|
155
|
+
* @returns {Promise<BatchClassifyResult>}
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* const result = await client.classifyBatch(
|
|
159
|
+
* ['hello', 'you suck', 'nice game'],
|
|
160
|
+
* ['toxic']
|
|
161
|
+
* );
|
|
162
|
+
* result.results.forEach((r, i) => {
|
|
163
|
+
* console.log(`Text ${i}: toxic=${r.toxic.label}`);
|
|
164
|
+
* });
|
|
165
|
+
*/
|
|
166
|
+
async classifyBatch(texts, gates = ['toxic']) {
|
|
167
|
+
if (!Array.isArray(texts) || texts.length === 0) {
|
|
168
|
+
throw new Error('Texts must be a non-empty array');
|
|
169
|
+
}
|
|
170
|
+
if (texts.length > 10000) {
|
|
171
|
+
throw new Error('Batch size cannot exceed 10,000');
|
|
172
|
+
}
|
|
173
|
+
if (!Array.isArray(gates) || gates.length === 0) {
|
|
174
|
+
throw new Error('Gates must be a non-empty array');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return this._request('POST', '/v1/classify/batch', { texts, gates });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if text is toxic (convenience method)
|
|
182
|
+
* @param {string} text - Text to check
|
|
183
|
+
* @param {number} threshold - Confidence threshold (default: 0.5)
|
|
184
|
+
* @returns {Promise<boolean>}
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* if (await client.isToxic('you suck')) {
|
|
188
|
+
* console.log('Blocked toxic message');
|
|
189
|
+
* }
|
|
190
|
+
*/
|
|
191
|
+
async isToxic(text, threshold = 0.5) {
|
|
192
|
+
const result = await this.classify(text, ['toxic']);
|
|
193
|
+
return result.results.toxic.confidence >= threshold;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Check if text is spam (convenience method)
|
|
198
|
+
* @param {string} text - Text to check
|
|
199
|
+
* @param {number} threshold - Confidence threshold (default: 0.5)
|
|
200
|
+
* @returns {Promise<boolean>}
|
|
201
|
+
*/
|
|
202
|
+
async isSpam(text, threshold = 0.5) {
|
|
203
|
+
const result = await this.classify(text, ['spam']);
|
|
204
|
+
return result.results.spam.confidence >= threshold;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get available gates
|
|
209
|
+
* @returns {Promise<GatesListResult>}
|
|
210
|
+
*/
|
|
211
|
+
async listGates() {
|
|
212
|
+
return this._request('GET', '/v1/gates');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Health check
|
|
217
|
+
* @returns {Promise<HealthResult>}
|
|
218
|
+
*/
|
|
219
|
+
async health() {
|
|
220
|
+
return this._request('GET', '/health');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Export class and constants
|
|
225
|
+
module.exports = SafetyGates;
|
|
226
|
+
module.exports.SafetyGates = SafetyGates;
|
|
227
|
+
module.exports.SafetyGatesError = SafetyGatesError;
|
|
228
|
+
module.exports.GATES = GATES;
|