Skip to content

Commit 6aefcfe

Browse files
authored
feat: Add do not train section to manifest-summary-v2 (#241)
1 parent 0ed0ec3 commit 6aefcfe

File tree

10 files changed

+131
-3
lines changed

10 files changed

+131
-3
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "c2pa-wc",
5+
"comment": "Add do not train section to cai-manifest-summary-v2",
6+
"type": "patch"
7+
}
8+
],
9+
"packageName": "c2pa-wc"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "c2pa",
5+
"comment": "Add selectDoNotTrain",
6+
"type": "patch"
7+
}
8+
],
9+
"packageName": "c2pa"
10+
}
Lines changed: 12 additions & 0 deletions
Loading

packages/c2pa-wc/i18n/en-US.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
"manifest-summary-v2.ai": "AI Info",
2929
"manifest-summary-v2.no-ai": "Created without generative AI",
3030
"manifest-summary-v2.camera-captured": "Camera-captured",
31-
"manifest-summary-v2.more-info": "More info available"
31+
"manifest-summary-v2.more-info": "More info available",
32+
"manifest-summary-v2.dnt": "I request that generative AI models not train on or use my content."
3233
}

packages/c2pa-wc/src/components/ManifestSummaryV2/ManifestSummaryV2.stories.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Default.args = {
7575
},
7676
],
7777
contentSummaryTag: 'ai',
78+
doNotTrain: true,
7879
unrecordedChanges: false,
7980
error: false,
8081
} as ManifestSummaryStore,
@@ -88,6 +89,7 @@ Minimal.args = {
8889
nameVerifier: null,
8990
socialAccounts: [],
9091
contentSummaryTag: null,
92+
doNotTrain: false,
9193
unrecordedChanges: false,
9294
error: false,
9395
},

packages/c2pa-wc/src/components/ManifestSummaryV2/ManifestSummaryV2.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { hasChanged } from '../../utils';
1313
import '../../../assets/svg/monochrome/verified.svg';
1414
import '../../../assets/svg/monochrome/inspect.svg';
1515
import '../../../assets/svg/monochrome/alert-notice.svg';
16+
import '../../../assets/svg/monochrome/dnt.svg';
1617

1718
import '../Icon';
1819
import {
@@ -190,6 +191,21 @@ export class ManifestSummaryV2 extends Localizable(LitElement) {
190191
.inspect-link:hover {
191192
background-color: rgba(0, 0, 0, 0.15);
192193
}
194+
195+
.dnt-container {
196+
display: flex;
197+
flex-direction: row;
198+
gap: 10px;
199+
font-size: 14px;
200+
font-weight: 400;
201+
line-height: 21px;
202+
color: #222222;
203+
}
204+
205+
.dnt-icon {
206+
flex-shrink: 0;
207+
width: 20px;
208+
}
193209
`,
194210
];
195211

@@ -239,6 +255,7 @@ export class ManifestSummaryV2 extends Localizable(LitElement) {
239255
: null;
240256
const socialAccounts = this.manifestStore.socialAccounts;
241257
const unrecorded = this.manifestStore.unrecordedChanges;
258+
const doNotTrain = this.manifestStore.doNotTrain;
242259
const error = this.manifestStore.error;
243260

244261
const inspectUrl = this.inspectUrl;
@@ -356,6 +373,15 @@ export class ManifestSummaryV2 extends Localizable(LitElement) {
356373
</div>
357374
`
358375
: nothing}
376+
${doNotTrain
377+
? html`
378+
<div class="divider"></div>
379+
<div class="dnt-container">
380+
<cai-icon-dnt class="dnt-icon"></cai-icon-dnt>
381+
${this.strings['manifest-summary-v2.dnt']}
382+
</div>
383+
`
384+
: nothing}
359385
`}
360386
${inspectUrl
361387
? html`

packages/c2pa-wc/src/getManifestSummaryData.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
isHandmade,
1212
Manifest,
1313
ManifestStore,
14+
selectDoNotTrain,
1415
selectFormattedGenerator,
1516
selectGenerativeInfo,
1617
selectProducer,
@@ -24,6 +25,7 @@ export interface ManifestSummaryStore {
2425
socialAccounts: SocialAccount[];
2526
contentSummaryTag: ContentSummaryTag | null;
2627
unrecordedChanges: boolean;
28+
doNotTrain: boolean;
2729
error: boolean;
2830
}
2931

@@ -62,6 +64,7 @@ export function getManifestSummaryData(
6264
socialAccounts: getSocialAccounts(activeManifest),
6365
contentSummaryTag,
6466
unrecordedChanges,
67+
doNotTrain: selectDoNotTrain(activeManifest),
6568
error,
6669
};
6770
}

packages/c2pa/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export {
6262
} from './src/selectors/selectGenerativeInfo';
6363
export { selectProducer } from './src/selectors/selectProducer';
6464
export { selectSocialAccounts } from './src/selectors/selectSocialAccounts';
65-
export { isHandmade } from './src/selectors/isHandmade';
65+
export { isHandmade, isHandmadeManifest } from './src/selectors/isHandmade';
66+
export { selectDoNotTrain } from './src/selectors/selectDoNotTrain';
6667
export { C2paSourceType, Source, SourceMetadata } from './src/source';
6768
export { BlobUrlData, DisposableBlobUrl, Thumbnail } from './src/thumbnail';

packages/c2pa/src/selectors/isHandmade.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function isHandmade(manifestStore: ManifestStore): boolean {
1515
return manifests.length > 0 && manifests.every(isHandmadeManifest);
1616
}
1717

18-
function isHandmadeManifest(manifest: Manifest): boolean {
18+
export function isHandmadeManifest(manifest: Manifest): boolean {
1919
const actionsV2 = manifest.assertions
2020
.get('c2pa.actions.v2')
2121
.filter((assertion) => !!assertion);
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* Copyright 2025 Adobe
3+
* All Rights Reserved.
4+
*
5+
* NOTICE: Adobe permits you to use, modify, and distribute this file in
6+
* accordance with the terms of the Adobe license agreement accompanying
7+
* it.
8+
*/
9+
10+
import { pick, reduce } from 'lodash';
11+
import type { Manifest } from '../manifest';
12+
13+
export const ENTRY_KEYS = [
14+
'cawg.ai_inference',
15+
'cawg.ai_generative_training',
16+
'c2pa.ai_inference',
17+
'c2pa.ai_generative_training',
18+
] as const;
19+
export const USE_VALUES = ['allowed', 'notAllowed', 'constrained'] as const;
20+
export type UseValue = typeof USE_VALUES[number];
21+
export const NOT_ALLOWED_VALUES: UseValue[] = ['notAllowed', 'constrained'];
22+
23+
export type EntryKey = typeof ENTRY_KEYS[number];
24+
25+
type EntryMap = Record<
26+
EntryKey,
27+
{
28+
use: UseValue;
29+
constraint_info?: string;
30+
}
31+
>;
32+
33+
declare module '../assertions' {
34+
interface ExtendedAssertions {
35+
'cawg.training-mining': {
36+
entries: EntryMap;
37+
};
38+
'c2pa.training-mining': {
39+
entries: EntryMap;
40+
};
41+
}
42+
}
43+
44+
export function selectDoNotTrain(manifest: Manifest): boolean {
45+
const entries =
46+
manifest.assertions?.get('cawg.training-mining')[0]?.data?.entries ??
47+
manifest.assertions?.get('c2pa.training-mining')[0]?.data?.entries ??
48+
({} as EntryMap);
49+
const filteredEntries = pick(entries, ENTRY_KEYS);
50+
const disallowedActions = reduce<EntryMap, EntryKey[]>(
51+
filteredEntries,
52+
(acc, val, entry) => {
53+
if (NOT_ALLOWED_VALUES.includes(val.use)) {
54+
return [...acc, entry] as EntryKey[];
55+
}
56+
57+
return acc;
58+
},
59+
[],
60+
);
61+
62+
return disallowedActions.length === 0;
63+
}

0 commit comments

Comments
 (0)