openvibers/openvibe.meme Commits

AI text may describe people: openvibe-sdk 0.78.0 (replaces #26) (#35)

OP OpenVibers committed 12 days ago · a26831985f · 6 files, +33 −50

Changes

ddiff --git a/STATUS.json b/STATUS.json
iindex 90ce76f..54dc5f9 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -9,11 +9,11 @@
"port": "5120",
"domain": "openvibe.meme",
"contracts": "openvibe-contracts v0.234.0",
-- "sdk": "openvibe-sdk v0.74.0",
++ "sdk": "openvibe-sdk v0.78.0",
"shared": "openvibe-shared v4.67.0",
"packages": [
"openvibe-contracts v0.234.0",
-- "openvibe-sdk v0.74.0",
++ "openvibe-sdk v0.78.0",
"openvibe-shared v4.67.0"
],
"summary": "OpenVibe.Meme is the open meme database, rebuilt with AI. The importer reads only public Chat and Live APIs and proposes a candidate when a recurring phrase appears in at least two uses on two different days; the candidate is born hidden with a verbatim citation for every use and stays hidden until a staff person publishes it. Every citation is re-verified daily, a 404 marks it gone and an entry whose origin is gone is hidden. People vote once a week for meme of the week, and a caption is plain text over a template, never a rendered image. Every public entry is one Search Fabric document queued in the service's outbox.",
ddiff --git a/package-lock.json b/package-lock.json
iindex 66c1fee..7785b09 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -16,7 +16,7 @@
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.234.0",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.78.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.67.0",
"pg": "^8.23.0"
},
@@@ -1166,9 +1166,9 @@
}
},
"node_modules/openvibe-sdk": {
-- "version": "0.74.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
-- "integrity": "sha512-DO9KVPnUriY/I4lX6ZEJtXaUvRDbJyqnqJxvlpl+zkNGFILpmuBXVJogNOCfK071Qci1gg7C4Iw1Xrseklcajg==",
++ "version": "0.78.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.78.0",
++ "integrity": "sha512-xOUpk7+K1gB3qhaXE0a+GpHkJZOJd+HKr7+EqfQwZqQxXr7fumMHt6/y2y0A1ersqHjZtx3WMvMc49bfBrBv2g==",
"license": "MIT",
"bin": {
"openvibe-download": "bin/openvibe-download.js"
ddiff --git a/package.json b/package.json
iindex d371782..60f58bf 100644
---- a/package.json
++++ b/package.json
@@@ -27,7 +27,7 @@
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.234.0",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.78.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.67.0",
"pg": "^8.23.0"
},
ddiff --git a/test/describes-people.test.js b/test/describes-people.test.js
nnew file mode 100644
iindex 0000000..47724f7
---- /dev/null
++++ b/test/describes-people.test.js
@@@ -0,0 +1,20 @@
++'use strict';
++/**
++ * The owner, 2026-10-31: AI text may describe people. openvibe-sdk 0.78.0 turns its looks filter off, so a summary that
++ * describes a person is kept as written and nothing is held back over it. The explicit gate (sex acts and porn) is a
++ * different rule and stays.
++ */
++const assert = require('assert');
++const { cleanSummary, hasLooks } = require('../server/text/no-looks');
++const { check, done } = require('./helpers/boot');
++
++(async () => {
++ await check('a summary that describes a person is kept as written', async () => {
++ assert.strictEqual(cleanSummary('Cozmo is offline', 'A shirtless man in a kitchen laughs.'), 'A shirtless man in a kitchen laughs.');
++ assert.strictEqual(hasLooks('A man in a blue shirt'), false);
++ });
++ await check('an ordinary summary survives too', async () => {
++ assert.strictEqual(cleanSummary('Cozmo is offline', 'The robot is not online; chat keeps asking about its Wi-Fi.'), 'The robot is not online; chat keeps asking about its Wi-Fi.');
++ });
++ done();
++})().catch((e) => { console.error(e); process.exit(1); });
ddiff --git a/test/judge.test.js b/test/judge.test.js
iindex 64307c2..8cbd143 100644
---- a/test/judge.test.js
++++ b/test/judge.test.js
@@@ -158,17 +158,18 @@ const answer = (score, extra = {}) => (prompt) => JSON.stringify({
} finally { await t2.close(); }
});
-- await check('the rule: text that names looks never reaches the public', async () => {
++ // The owner, 2026-10-31: AI text may describe people (openvibe-sdk 0.78.0 turns the looks filter off).
++ await check('text that describes a person is published like any other', async () => {
const t2 = await boot({ ai: { answer: answer(0.99, { title: 'Cozmo in his blue shirt', summary: 'A man in a kitchen says the robot is offline.' }) } });
try {
const entry = await candidate(t2, { slug: 'looks-one', title: 'Looks one', uses: [at(0), at(2), at(3)] });
const out = await t2.ctx.judgeJob.runOnce({ force: true });
-- if (out.published !== 0) throw new Error('an entry whose text names looks was published');
++ if (out.published !== 1) throw new Error('an entry that describes a person was held back');
const after = await t2.ctx.entries.byId(entry.id);
-- if (after.visibility !== 'hidden') throw new Error('the entry is not hidden');
-- if (after.title === 'Cozmo in his blue shirt') throw new Error('the title that named looks was used');
++ if (after.visibility !== 'public') throw new Error('the entry is not public');
++ if (after.title !== 'Cozmo in his blue shirt') throw new Error('the AI title was not used');
const verdict = await t2.ctx.entries.judgement(entry.id);
-- if (!verdict.looks) throw new Error('the judgement does not say the text named looks');
++ if (verdict.looks) throw new Error('the judgement still flags looks');
} finally { await t2.close(); }
});
ddiff --git a/test/no-looks.test.js b/test/no-looks.test.js
ddeleted file mode 100644
iindex 005c333..0000000
---- a/test/no-looks.test.js
++++ /dev/null
@@@ -1,38 +0,0 @@
--'use strict';
--/**
-- * No looks in public AI text: a summary that names looks is replaced by the entry's title; a normal summary is
-- * kept and repaired only where noLooks has something to repair. Verbatim quotes are never passed through.
-- */
--const assert = require('assert');
--const { cleanSummary, hasLooks } = require('../server/text/no-looks');
--const { boot, check, done } = require('./helpers/boot');
--
--(async () => {
-- await check('a summary that names looks becomes the title', async () => {
-- assert.strictEqual(cleanSummary('Cozmo is offline', 'A shirtless man in a kitchen laughs.'), 'Cozmo is offline');
-- assert.strictEqual(cleanSummary('Cozmo is offline', 'A little robot is not online.'), 'Cozmo is offline');
-- assert.ok(hasLooks('A shirtless man in a kitchen laughs.'));
-- });
--
-- await check('an ordinary summary survives', async () => {
-- const s = cleanSummary('Cozmo is offline', 'The robot is not online; chat keeps asking about its Wi-Fi.');
-- assert.strictEqual(s, 'The robot is not online; chat keeps asking about its Wi-Fi.');
-- });
--
-- const t = await boot();
-- try {
-- await check('createCandidate stores the title, never the looks summary', async () => {
-- const out = await t.ctx.entries.createCandidate({
-- slug: 'looks', title: 'Robot is offline', kind: 'meme', summary: 'A shirtless man reacts to the offline robot.',
-- status: 'rising', first_seen_at: new Date().toISOString(), last_seen_at: new Date().toISOString(), visibility: 'hidden',
-- citations: [{ role: 'origin', source_service: 'chat', source_type: 'chat_message', source_id: '1001', quote_text: 'the robot is offline again', url: `${t.upstreams.url}/`, observed_at: new Date().toISOString() }],
-- });
-- assert.strictEqual(out.entry.summary, 'Robot is offline');
-- const quote = await t.ctx.s.db.value('SELECT quote_text FROM meme_citations WHERE entry_id = $1', [out.entry.id]);
-- assert.strictEqual(quote, 'the robot is offline again', 'the verbatim quote is not rewritten');
-- });
-- } finally {
-- await t.close();
-- }
-- done();
--})();