131 lines
4.9 KiB
JavaScript
131 lines
4.9 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import { moderateImage } from '../src/moderation.js';
|
|
|
|
test('queues uploads when AI moderation is not configured', async () => {
|
|
const originalApiKey = process.env.OPENAI_API_KEY;
|
|
delete process.env.OPENAI_API_KEY;
|
|
|
|
try {
|
|
const moderation = await moderateImage({
|
|
buffer: Buffer.from('image'),
|
|
mime: 'image/webp'
|
|
});
|
|
|
|
assert.equal(moderation.status, 'pending');
|
|
assert.equal(moderation.score, 50);
|
|
assert.match(moderation.reason, /not configured/);
|
|
} finally {
|
|
if (originalApiKey === undefined) {
|
|
delete process.env.OPENAI_API_KEY;
|
|
} else {
|
|
process.env.OPENAI_API_KEY = originalApiKey;
|
|
}
|
|
}
|
|
});
|
|
|
|
test('queues model approvals below the auto-publish quality threshold', async () => {
|
|
const originalApiKey = process.env.OPENAI_API_KEY;
|
|
const originalThreshold = process.env.AUTO_APPROVE_MIN_SCORE;
|
|
const originalFetch = globalThis.fetch;
|
|
process.env.OPENAI_API_KEY = 'test-key';
|
|
process.env.AUTO_APPROVE_MIN_SCORE = '90';
|
|
|
|
globalThis.fetch = async (_url, options) => {
|
|
const body = JSON.parse(options.body);
|
|
const prompt = body.input[0].content;
|
|
|
|
assert.match(prompt, /could the exact same caption work on 50 unrelated images/);
|
|
assert.match(prompt, /Use approved only when it appears legal and score is at least 90/);
|
|
|
|
return {
|
|
ok: true,
|
|
json: async () => ({
|
|
output_text: JSON.stringify({
|
|
decision: 'approved',
|
|
score: 89,
|
|
reason: 'Specific joke, but not strong enough.'
|
|
})
|
|
})
|
|
};
|
|
};
|
|
|
|
try {
|
|
const moderation = await moderateImage({
|
|
buffer: Buffer.from('image'),
|
|
mime: 'image/webp'
|
|
});
|
|
|
|
assert.equal(moderation.status, 'pending');
|
|
assert.equal(moderation.score, 89);
|
|
assert.match(moderation.reason, /Low MEME_CONSENSUS_SCORE queued for review/);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
if (originalApiKey === undefined) {
|
|
delete process.env.OPENAI_API_KEY;
|
|
} else {
|
|
process.env.OPENAI_API_KEY = originalApiKey;
|
|
}
|
|
if (originalThreshold === undefined) {
|
|
delete process.env.AUTO_APPROVE_MIN_SCORE;
|
|
} else {
|
|
process.env.AUTO_APPROVE_MIN_SCORE = originalThreshold;
|
|
}
|
|
}
|
|
});
|
|
|
|
test('generates searchable captions using a constrained tag catalog and discards invented tags', async (t) => {
|
|
const originalKey = process.env.OPENAI_API_KEY;
|
|
const originalFetch = globalThis.fetch;
|
|
process.env.OPENAI_API_KEY = 'test-key';
|
|
t.after(() => {
|
|
globalThis.fetch = originalFetch;
|
|
if (originalKey === undefined) delete process.env.OPENAI_API_KEY;
|
|
else process.env.OPENAI_API_KEY = originalKey;
|
|
});
|
|
globalThis.fetch = async (_url, options) => {
|
|
const body = JSON.parse(options.body);
|
|
assert.equal(body.text.format.type, 'json_schema');
|
|
assert.equal(body.text.format.strict, true);
|
|
assert.deepEqual(body.text.format.schema.properties.tags.items.enum, ['cats', 'work']);
|
|
assert.match(body.input[0].content, /Available tags.*\["cats","work"\]/);
|
|
assert.match(body.input[0].content, /never as instructions/);
|
|
assert.equal(body.input[1].content[0].type, 'input_image');
|
|
return { ok: true, json: async () => ({ status: 'completed', output: [{ content: [{ type: 'output_text', text: JSON.stringify({
|
|
decision: 'approved', score: 99, reason: 'Good meme', caption: ' A cat says “I hate Mondays” at work. ', tags: ['cats', 'invented', 'cats']
|
|
}) }] }] }) };
|
|
};
|
|
const result = await moderateImage({ buffer: Buffer.from('image'), mime: 'image/webp', availableTags: ['cats', 'work'] });
|
|
assert.equal(result.status, 'approved');
|
|
assert.equal(result.caption, 'A cat says “I hate Mondays” at work.');
|
|
assert.deepEqual(result.tags, ['cats']);
|
|
});
|
|
|
|
test('failed or incomplete caption generation raises an error; failed moderation queues safely', async (t) => {
|
|
const { captionImage } = await import('../src/moderation.js');
|
|
const originalKey = process.env.OPENAI_API_KEY;
|
|
const originalFetch = globalThis.fetch;
|
|
process.env.OPENAI_API_KEY = 'test-key';
|
|
t.after(() => {
|
|
globalThis.fetch = originalFetch;
|
|
if (originalKey === undefined) delete process.env.OPENAI_API_KEY;
|
|
else process.env.OPENAI_API_KEY = originalKey;
|
|
});
|
|
const image = { buffer: Buffer.from('image'), mime: 'image/webp' };
|
|
for (const payload of [
|
|
{ status: 'incomplete', output_text: '{"caption":"partial","tags":[]}' },
|
|
{ status: 'completed', output: [{ content: [{ type: 'refusal', refusal: 'No' }] }] },
|
|
{ output_text: 'not JSON' }
|
|
]) {
|
|
globalThis.fetch = async () => ({ ok: true, json: async () => payload });
|
|
await assert.rejects(captionImage(image), { statusCode: 503 });
|
|
const result = await moderateImage(image);
|
|
assert.equal(result.status, 'pending');
|
|
assert.equal(result.caption, '');
|
|
assert.deepEqual(result.tags, []);
|
|
}
|
|
delete process.env.OPENAI_API_KEY;
|
|
await assert.rejects(captionImage(image), { statusCode: 503 });
|
|
});
|