diff --git a/CHANGELOG.md b/CHANGELOG.md index 50e097c68..301fe02ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,17 @@ --> +## 13.x.x (unreleased) + +### General +- 投稿したコンテンツのAIによる学習を軽減するオプションを追加 + +### Client +- + +### Server +- + ## 13.12.1 ### Client diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 8bbf9459f..f9e1e9559 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1038,6 +1038,8 @@ thisChannelArchived: "このチャンネルはアーカイブされています displayOfNote: "ノートの表示" initialAccountSetting: "初期設定" youFollowing: "フォロー中" +preventAiLarning: "AIによる学習を防止" +preventAiLarningDescription: "投稿したノート、添付した画像などのコンテンツを学習の対象にしないようAIに要求します。これはnoaiフラグをHTMLレスポンスに含めることによって実現されます。" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/backend/migration/1683682889948-prevent-ai-larning.js b/packages/backend/migration/1683682889948-prevent-ai-larning.js new file mode 100644 index 000000000..9d1a19c10 --- /dev/null +++ b/packages/backend/migration/1683682889948-prevent-ai-larning.js @@ -0,0 +1,11 @@ +export class PreventAiLarning1683682889948 { + name = 'PreventAiLarning1683682889948' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_profile" ADD "preventAiLarning" boolean NOT NULL DEFAULT true`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "preventAiLarning"`); + } +} diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 453c1473d..cb0b15fac 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -445,6 +445,7 @@ export class UserEntityService implements OnModuleInit { carefulBot: profile!.carefulBot, autoAcceptFollowed: profile!.autoAcceptFollowed, noCrawle: profile!.noCrawle, + preventAiLarning: profile!.preventAiLarning, isExplorable: user.isExplorable, isDeleted: user.isDeleted, hideOnlineStatus: user.hideOnlineStatus, diff --git a/packages/backend/src/models/entities/UserProfile.ts b/packages/backend/src/models/entities/UserProfile.ts index 60c1c55de..6eab846c1 100644 --- a/packages/backend/src/models/entities/UserProfile.ts +++ b/packages/backend/src/models/entities/UserProfile.ts @@ -147,6 +147,11 @@ export class UserProfile { }) public noCrawle: boolean; + @Column('boolean', { + default: true, + }) + public preventAiLarning: boolean; + @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 529c1303d..9d630db4c 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -302,7 +302,11 @@ export const packedMeDetailedOnlySchema = { }, noCrawle: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, + }, + preventAiLarning: { + type: 'boolean', + nullable: false, optional: false, }, isExplorable: { type: 'boolean', diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 42229c8f2..12e656a2f 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -68,6 +68,7 @@ export default class extends Endpoint { emailVerified: profile.emailVerified, autoAcceptFollowed: profile.autoAcceptFollowed, noCrawle: profile.noCrawle, + preventAiLarning: profile.preventAiLarning, alwaysMarkNsfw: profile.alwaysMarkNsfw, autoSensitive: profile.autoSensitive, carefulBot: profile.carefulBot, diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 6c66300bb..4cc173c2d 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -98,7 +98,7 @@ export const meta = { message: 'This feature is restricted by your role.', code: 'RESTRICTED_BY_ROLE', id: '8feff0ba-5ab5-585b-31f4-4df816663fad', - } + }, }, res: { @@ -138,6 +138,7 @@ export const paramDef = { carefulBot: { type: 'boolean' }, autoAcceptFollowed: { type: 'boolean' }, noCrawle: { type: 'boolean' }, + preventAiLarning: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, showTimelineReplies: { type: 'boolean' }, @@ -242,6 +243,7 @@ export default class extends Endpoint { if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot; if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; + if (typeof ps.preventAiLarning === 'boolean') profileUpdates.preventAiLarning = ps.preventAiLarning; if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug index 4c692bf59..f92a437ca 100644 --- a/packages/backend/src/server/web/views/clip.pug +++ b/packages/backend/src/server/web/views/clip.pug @@ -21,6 +21,8 @@ block og block meta if profile.noCrawle meta(name='robots' content='noindex') + if profile.preventAiLarning + meta(name='robots' content='noai') meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) diff --git a/packages/backend/src/server/web/views/flash.pug b/packages/backend/src/server/web/views/flash.pug index 5166855ea..fcdb136ed 100644 --- a/packages/backend/src/server/web/views/flash.pug +++ b/packages/backend/src/server/web/views/flash.pug @@ -21,6 +21,8 @@ block og block meta if profile.noCrawle meta(name='robots' content='noindex') + if profile.preventAiLarning + meta(name='robots' content='noai') meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) diff --git a/packages/backend/src/server/web/views/gallery-post.pug b/packages/backend/src/server/web/views/gallery-post.pug index ca0663a48..4470266f8 100644 --- a/packages/backend/src/server/web/views/gallery-post.pug +++ b/packages/backend/src/server/web/views/gallery-post.pug @@ -21,6 +21,8 @@ block og block meta if user.host || profile.noCrawle meta(name='robots' content='noindex') + if profile.preventAiLarning + meta(name='robots' content='noai') meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index 65696ea13..84bcd51e2 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -22,6 +22,8 @@ block og block meta if user.host || isRenote || profile.noCrawle meta(name='robots' content='noindex') + if profile.preventAiLarning + meta(name='robots' content='noai') meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug index 4219e76a5..eef066f57 100644 --- a/packages/backend/src/server/web/views/page.pug +++ b/packages/backend/src/server/web/views/page.pug @@ -21,6 +21,8 @@ block og block meta if profile.noCrawle meta(name='robots' content='noindex') + if profile.preventAiLarning + meta(name='robots' content='noai') meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug index 119993fdb..a25fcf6d7 100644 --- a/packages/backend/src/server/web/views/user.pug +++ b/packages/backend/src/server/web/views/user.pug @@ -20,6 +20,8 @@ block og block meta if user.host || profile.noCrawle meta(name='robots' content='noindex') + if profile.preventAiLarning + meta(name='robots' content='noai') meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 51537dda1..7f556fddf 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -145,6 +145,7 @@ describe('ユーザー', () => { carefulBot: user.carefulBot, autoAcceptFollowed: user.autoAcceptFollowed, noCrawle: user.noCrawle, + preventAiLarning: user.preventAiLarning, isExplorable: user.isExplorable, isDeleted: user.isDeleted, hideOnlineStatus: user.hideOnlineStatus, @@ -390,6 +391,7 @@ describe('ユーザー', () => { assert.strictEqual(response.carefulBot, false); assert.strictEqual(response.autoAcceptFollowed, true); assert.strictEqual(response.noCrawle, false); + assert.strictEqual(response.preventAiLarning, true); assert.strictEqual(response.isExplorable, true); assert.strictEqual(response.isDeleted, false); assert.strictEqual(response.hideOnlineStatus, false); @@ -462,6 +464,8 @@ describe('ユーザー', () => { { parameters: (): object => ({ autoAcceptFollowed: false }) }, { parameters: (): object => ({ noCrawle: true }) }, { parameters: (): object => ({ noCrawle: false }) }, + { parameters: (): object => ({ preventAiLarning: false }) }, + { parameters: (): object => ({ preventAiLarning: true }) }, { parameters: (): object => ({ isBot: true }) }, { parameters: (): object => ({ isBot: false }) }, { parameters: (): object => ({ isCat: true }) }, diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index c83c48d5a..29a9efa2d 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -24,6 +24,10 @@ {{ i18n.ts.noCrawle }} + + {{ i18n.ts.preventAiLarning }}{{ i18n.ts.beta }} + + {{ i18n.ts.makeExplorable }} @@ -71,6 +75,7 @@ import { definePageMetadata } from '@/scripts/page-metadata'; let isLocked = $ref($i.isLocked); let autoAcceptFollowed = $ref($i.autoAcceptFollowed); let noCrawle = $ref($i.noCrawle); +let preventAiLarning = $ref($i.preventAiLarning); let isExplorable = $ref($i.isExplorable); let hideOnlineStatus = $ref($i.hideOnlineStatus); let publicReactions = $ref($i.publicReactions); @@ -86,6 +91,7 @@ function save() { isLocked: !!isLocked, autoAcceptFollowed: !!autoAcceptFollowed, noCrawle: !!noCrawle, + preventAiLarning: !!preventAiLarning, isExplorable: !!isExplorable, hideOnlineStatus: !!hideOnlineStatus, publicReactions: !!publicReactions,