diff --git a/js/app/store/slices/contentMetadataSlice.ts b/js/app/store/slices/contentMetadataSlice.ts index 91fbbe1f0..f0dbf54e9 100644 --- a/js/app/store/slices/contentMetadataSlice.ts +++ b/js/app/store/slices/contentMetadataSlice.ts @@ -14,7 +14,7 @@ export interface ContentMetadataSlice { // actions createContentMetadata: (params: { contentWarnings?: string[]; - distributionPolicy?: { deleteAfter?: number }; + distributionPolicy?: { deleteAfter?: number; allowAiTraining?: boolean }; contentRights?: { creator?: string; copyrightNotice?: string; @@ -27,7 +27,7 @@ export interface ContentMetadataSlice { rkey?: string; livestreamRef?: { uri: string; cid: string }; contentWarnings?: string[]; - distributionPolicy?: { deleteAfter?: number }; + distributionPolicy?: { deleteAfter?: number; allowAiTraining?: boolean }; contentRights?: { creator?: string; copyrightNotice?: string; @@ -80,7 +80,10 @@ export const createContentMetadataSlice: StateCreator< ...(contentWarnings.length > 0 && { contentWarnings: { warnings: contentWarnings }, }), - ...(distributionPolicy.deleteAfter && { distributionPolicy }), + ...((distributionPolicy.deleteAfter || + distributionPolicy.allowAiTraining !== undefined) && { + distributionPolicy, + }), ...(contentRights && Object.keys(contentRights).length > 0 && { contentRights, @@ -142,7 +145,10 @@ export const createContentMetadataSlice: StateCreator< ...(contentWarnings.length > 0 && { contentWarnings: { warnings: contentWarnings }, }), - ...(distributionPolicy.deleteAfter && { distributionPolicy }), + ...((distributionPolicy.deleteAfter || + distributionPolicy.allowAiTraining !== undefined) && { + distributionPolicy, + }), ...(contentRights && Object.keys(contentRights).length > 0 && { contentRights, diff --git a/js/components/src/components/content-metadata/content-metadata-form.tsx b/js/components/src/components/content-metadata/content-metadata-form.tsx index a21ec8156..f4d19a24e 100644 --- a/js/components/src/components/content-metadata/content-metadata-form.tsx +++ b/js/components/src/components/content-metadata/content-metadata-form.tsx @@ -198,14 +198,19 @@ export const ContentMetadataForm = forwardRef( ({ deleteAfter, allowedBroadcasters, + allowAiTraining, }: { deleteAfter?: string; allowedBroadcasters?: string; + allowAiTraining?: boolean; }) => { let newDistributionPolicy: place.stream.metadata.distributionPolicy.Main = { ...distributionPolicy, }; + if (typeof allowAiTraining === "boolean") { + newDistributionPolicy.allowAiTraining = allowAiTraining; + } if (typeof deleteAfter === "string") { let duration = parseInt(deleteAfter, 10); if (isNaN(duration)) { @@ -304,7 +309,10 @@ export const ContentMetadataForm = forwardRef( metadata.contentRights = filteredRights; } + // AI training is opt-in: absent an explicit choice, save the record + // with training disallowed. metadata.distributionPolicy = { + allowAiTraining: false, ...distributionPolicy, }; @@ -336,6 +344,7 @@ export const ContentMetadataForm = forwardRef( }, [ contentWarnings, contentRights, + distributionPolicy, selectedLicense, customLicenseText, hasMetadata, @@ -760,6 +769,24 @@ export const ContentMetadataForm = forwardRef( )} + + + handleDistributionPolicyChange({ + allowAiTraining: checked, + }) + } + label={ + "Allow your content to be used for generative AI training" + } + style={[{ fontSize: 12 }]} + /> + +