is-it-spam 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/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # isSpamLLM
2
+
3
+ Simple LLM-based spam classifier. Works with any OpenAI-compatible API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install spam-classifier
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { createClassifier } from "spam-classifier";
15
+
16
+ // Set up once
17
+ const isSpam = createClassifier({
18
+ apiKey: process.env.OPENROUTER_API_KEY!,
19
+ });
20
+
21
+ // Use anywhere - returns true/false
22
+ if (await isSpam("Need a quote for your services")) {
23
+ // spam - ignore it
24
+ }
25
+
26
+ // Or get details
27
+ const result = await isSpam.details("Need a quote");
28
+ // { isSpam: false, confidence: 0.95, reason: "Customer requesting quote" }
29
+ ```
30
+
31
+ ## Options
32
+
33
+ | Option | Type | Default | Description |
34
+ |--------|------|---------|-------------|
35
+ | `apiKey` | string | **required** | API key |
36
+ | `model` | string | `"openai/gpt-4o-mini"` | Model to use |
37
+ | `baseUrl` | string | OpenRouter | API endpoint |
38
+ | `zdr` | boolean | `false` | Enable Zero Data Retention |
39
+
40
+ ## Providers
41
+
42
+ Works with any OpenAI-compatible API:
43
+
44
+ ```typescript
45
+ // OpenRouter (default)
46
+ const isSpam = createClassifier({ apiKey: process.env.OPENROUTER_API_KEY! });
47
+
48
+ // OpenAI directly
49
+ const isSpam = createClassifier({
50
+ apiKey: process.env.OPENAI_API_KEY!,
51
+ baseUrl: "https://api.openai.com/v1/chat/completions",
52
+ model: "gpt-4o-mini",
53
+ });
54
+
55
+ // Local LLM
56
+ const isSpam = createClassifier({
57
+ apiKey: "not-needed",
58
+ baseUrl: "http://localhost:11434/v1/chat/completions",
59
+ model: "llama3",
60
+ });
61
+ ```
62
+
63
+ ## Fail-Safe
64
+
65
+ Returns `false` (legitimate) if the API fails, so you never block real customers.
66
+
67
+ ## Cost
68
+
69
+ ~$0.0002 per classification. 10,000 submissions = ~$2.
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,42 @@
1
+ /**
2
+ * isSpamLLM
3
+ *
4
+ * Simple LLM-based spam classifier.
5
+ * Works with any OpenAI-compatible API.
6
+ */
7
+ export interface ClassifierOptions {
8
+ apiKey: string;
9
+ model?: string;
10
+ baseUrl?: string;
11
+ zdr?: boolean;
12
+ }
13
+ export interface ClassifyResult {
14
+ isSpam: boolean;
15
+ confidence?: number;
16
+ reason?: string;
17
+ }
18
+ type Classifier = ((content: string) => Promise<boolean>) & {
19
+ details: (content: string) => Promise<ClassifyResult>;
20
+ };
21
+ /**
22
+ * Create a spam classifier function.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Set up once
27
+ * const isSpam = createClassifier({
28
+ * apiKey: process.env.OPENROUTER_API_KEY!,
29
+ * });
30
+ *
31
+ * // Use anywhere
32
+ * if (await isSpam("Need a quote")) {
33
+ * // spam
34
+ * }
35
+ *
36
+ * // Or get details
37
+ * const result = await isSpam.details("Need a quote");
38
+ * // { isSpam: false, confidence: 0.95, reason: "..." }
39
+ * ```
40
+ */
41
+ export declare function createClassifier(options: ClassifierOptions): Classifier;
42
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ /**
2
+ * isSpamLLM
3
+ *
4
+ * Simple LLM-based spam classifier.
5
+ * Works with any OpenAI-compatible API.
6
+ */
7
+ const DEFAULT_BASE_URL = "https://openrouter.ai/api/v1/chat/completions";
8
+ const DEFAULT_MODEL = "openai/gpt-5.4-nano";
9
+ const SYSTEM_PROMPT = `You are a spam filter.
10
+ Determine if the input is spam or a legitimate message.
11
+
12
+ LEGITIMATE: genuine inquiries, customer questions, support requests, etc.
13
+ SPAM: web design pitches, SEO offers, lead gen, "grow your business", partnership requests, unsolicited sales pitches, etc.
14
+
15
+ Key indicator: Is this a sales pitch TO the recipient or a genuine message FROM someone?
16
+
17
+ Respond with JSON: {"is_spam": boolean, "confidence": number, "reason": string}`;
18
+ async function classify(content, options) {
19
+ const { apiKey, model = DEFAULT_MODEL, baseUrl = DEFAULT_BASE_URL, zdr = false, } = options;
20
+ const body = {
21
+ model,
22
+ messages: [
23
+ { role: "system", content: SYSTEM_PROMPT },
24
+ { role: "user", content: `Classify this:\n\n${content}` },
25
+ ],
26
+ response_format: {
27
+ type: "json_schema",
28
+ json_schema: {
29
+ name: "spam_classification",
30
+ strict: true,
31
+ schema: {
32
+ type: "object",
33
+ properties: {
34
+ is_spam: { type: "boolean" },
35
+ confidence: { type: "number" },
36
+ reason: { type: "string" },
37
+ },
38
+ required: ["is_spam", "confidence", "reason"],
39
+ additionalProperties: false,
40
+ },
41
+ },
42
+ },
43
+ temperature: 0,
44
+ max_tokens: 200,
45
+ };
46
+ if (zdr) {
47
+ body.provider = { zdr: true };
48
+ }
49
+ const response = await fetch(baseUrl, {
50
+ method: "POST",
51
+ headers: {
52
+ Authorization: `Bearer ${apiKey}`,
53
+ "Content-Type": "application/json",
54
+ },
55
+ body: JSON.stringify(body),
56
+ });
57
+ if (!response.ok) {
58
+ throw new Error(`API error: ${response.status}`);
59
+ }
60
+ const data = (await response.json());
61
+ const parsed = JSON.parse(data.choices[0].message.content);
62
+ return {
63
+ isSpam: parsed.is_spam,
64
+ confidence: parsed.confidence,
65
+ reason: parsed.reason,
66
+ };
67
+ }
68
+ /**
69
+ * Create a spam classifier function.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // Set up once
74
+ * const isSpam = createClassifier({
75
+ * apiKey: process.env.OPENROUTER_API_KEY!,
76
+ * });
77
+ *
78
+ * // Use anywhere
79
+ * if (await isSpam("Need a quote")) {
80
+ * // spam
81
+ * }
82
+ *
83
+ * // Or get details
84
+ * const result = await isSpam.details("Need a quote");
85
+ * // { isSpam: false, confidence: 0.95, reason: "..." }
86
+ * ```
87
+ */
88
+ export function createClassifier(options) {
89
+ const classifier = async (content) => {
90
+ try {
91
+ const result = await classify(content, options);
92
+ return result.isSpam;
93
+ }
94
+ catch {
95
+ return false; // Fail open
96
+ }
97
+ };
98
+ classifier.details = async (content) => {
99
+ try {
100
+ return await classify(content, options);
101
+ }
102
+ catch {
103
+ return { isSpam: false, confidence: 0, reason: "Classification failed" };
104
+ }
105
+ };
106
+ return classifier;
107
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "is-it-spam",
3
+ "version": "0.1.0",
4
+ "description": "LLM-based spam classifier. Works with any OpenAI-compatible API.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "test": "bun test"
20
+ },
21
+ "keywords": [
22
+ "spam",
23
+ "classifier",
24
+ "llm",
25
+ "form",
26
+ "openai",
27
+ "openrouter"
28
+ ],
29
+ "license": "MIT",
30
+ "devDependencies": {
31
+ "typescript": "^5.7.0"
32
+ }
33
+ }