Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/labrinth-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
GIT_HASH: ${{ github.sha }}
SCCACHE_CACHE_SIZE: ${{ needs.skip-if-clean.outputs.internal == 'true' && '20G' || '' }}
RUSTC_WRAPPER: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'sccache' || '' }}
RUST_MIN_STACK: '16777216'
RUST_MIN_STACK: '268435456'
steps:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/public/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ components:
- ai_content_code
- ai_content_assets
- ai_content_text
- ai_content_functionality
- ai_functionality
- advertisements
- epilepsy_triggers
- system_interactions
Expand Down Expand Up @@ -2202,7 +2202,7 @@ paths:
- `ai_content_code`
- `ai_content_assets`
- `ai_content_text`
- `ai_content_functionality`
- `ai_functionality`
- `advertisements`
- `epilepsy_triggers`
- `system_interactions`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const emit = defineEmits<{

const { formatMessage } = useVIntl()

const AI_USES: AiUsage[] = ['code', 'assets', 'text', 'functionality']
const AI_USES: AiUsage[] = ['code', 'assets', 'text']

const messages = defineMessages({
title: {
Expand All @@ -35,9 +35,8 @@ const messages = defineMessages({
description: {
id: 'project.settings.disclosures.ai.description',
defaultMessage: `You must enable this if this project contains a substantial amount of AI-generated code, any
assets that are substantially AI-generated, the project's functionality relies on the use of
generative AI, or if any element of your project's page such as description or publishing
relies on generative AI.`,
assets that are substantially AI-generated, or if any element of your project's page such as
description or publishing relies on generative AI.`,
},
contentRules: {
id: 'project.settings.disclosures.ai.content-rules',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script setup lang="ts">
import { BrainCircuitIcon } from '@modrinth/assets'
import {
commonMessages,
defineMessages,
SettingsFormGroup,
StyledInput,
useVIntl,
} from '@modrinth/ui'

import DisclosureToggleCard from './DisclosureToggleCard.vue'
import type { DisclosureCardMetaProps, DisclosureLockStatus, NoteDisclosure } from './types'

const model = defineModel<NoteDisclosure>({ required: true })

const props = defineProps<DisclosureCardMetaProps>()

const emit = defineEmits<{
setLockStatus: [status: DisclosureLockStatus]
}>()

const { formatMessage } = useVIntl()

const messages = defineMessages({
title: {
id: 'project.settings.disclosures.ai-functionality.title',
defaultMessage: 'Contains generative AI functionality',
},
description: {
id: 'project.settings.disclosures.ai-functionality.description',
defaultMessage: 'Placeholder',
},
notePlaceholder: {
id: 'project.settings.disclosures.ai-functionality.note-placeholder',
defaultMessage: 'e.g. The in-game assistant uses generative AI to generate dialogue.',
},
})
</script>

<template>
<DisclosureToggleCard
v-bind="props"
v-model="model.enabled"
:icon="BrainCircuitIcon"
:title="formatMessage(messages.title)"
:description="formatMessage(messages.description)"
@set-lock-status="emit('setLockStatus', $event)"
>
<template #expanded>
<SettingsFormGroup
:title="formatMessage(commonMessages.explanationLabel)"
title-for="ai-functionality-disclosure-note"
optional
>
<StyledInput
id="ai-functionality-disclosure-note"
v-model="model.note"
multiline
:rows="3"
class="max-w-[40rem]"
:disabled="disabled"
:placeholder="formatMessage(messages.notePlaceholder)"
/>
</SettingsFormGroup>
</template>
</DisclosureToggleCard>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function findDisclosure<T extends DisclosureType>(
return disclosures.find((disclosure): disclosure is DisclosureOf<T> => disclosure.type === type)
}

type NoteDisclosureType = 'advertisements' | 'epilepsy_triggers' | 'archived'
type NoteDisclosureType = 'ai_functionality' | 'advertisements' | 'epilepsy_triggers' | 'archived'

function createNoteModel(
disclosures: ProjectDisclosureData[],
Expand Down Expand Up @@ -66,6 +66,7 @@ export function disclosuresToForm(disclosures: ProjectDisclosureData[]): Disclos
uses: ai ? [...(ai.uses ?? [])] : [],
note: ai?.note ?? '',
},
aiFunctionality: createNoteModel(disclosures, 'ai_functionality'),
advertising: createNoteModel(disclosures, 'advertisements'),
paidFeatures: {
enabled: isActiveDisclosure(paidFeatures),
Expand Down Expand Up @@ -110,6 +111,8 @@ export function formToDisclosure(
uses: [...form.ai.uses],
note: form.ai.note.trim() || null,
}
case 'ai_functionality':
return { type: 'ai_functionality', note: form.aiFunctionality.note.trim() || null }
case 'advertisements':
return { type: 'advertisements', note: form.advertising.note.trim() || null }
case 'paid_features':
Expand Down Expand Up @@ -151,6 +154,9 @@ export function formToDisclosures(form: DisclosureFormState): ProjectDisclosure[
if (form.ai.enabled) {
set.push(formToDisclosure(form, 'ai_content'))
}
if (form.aiFunctionality.enabled) {
set.push(formToDisclosure(form, 'ai_functionality'))
}
if (form.advertising.enabled) {
set.push(formToDisclosure(form, 'advertisements'))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as AdvertisingDisclosureCard } from './AdvertisingDisclosureCard.vue'
export { default as AiDisclosureCard } from './AiDisclosureCard.vue'
export { default as AiFunctionalityDisclosureCard } from './AiFunctionalityDisclosureCard.vue'
export { default as ArchivedDisclosureCard } from './ArchivedDisclosureCard.vue'
export { default as DerivativeDisclosureCard } from './DerivativeDisclosureCard.vue'
export { default as DisclosureToggleCard } from './DisclosureToggleCard.vue'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type DerivativeDisclosure = {

export type DisclosureFormState = {
ai: AiDisclosure
aiFunctionality: NoteDisclosure
advertising: NoteDisclosure
paidFeatures: PaidFeaturesDisclosure
telemetry: TelemetryDisclosure
Expand Down
11 changes: 10 additions & 1 deletion apps/frontend/src/locales/en-US/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -3839,11 +3839,20 @@
"project.settings.disclosures.advertising.title": {
"message": "Contains advertisements"
},
"project.settings.disclosures.ai-functionality.description": {
"message": "Placeholder"
},
"project.settings.disclosures.ai-functionality.note-placeholder": {
"message": "e.g. The in-game assistant uses generative AI to generate dialogue."
},
"project.settings.disclosures.ai-functionality.title": {
"message": "Contains generative AI functionality"
},
"project.settings.disclosures.ai.content-rules": {
"message": "Please refer to Section 6 of <rules>Modrinth's Content Rules</rules> for more information."
},
"project.settings.disclosures.ai.description": {
"message": "You must enable this if this project contains a substantial amount of AI-generated code, any\n\t\t\t\tassets that are substantially AI-generated, the project's functionality relies on the use of\n\t\t\t\tgenerative AI, or if any element of your project's page such as description or publishing\n\t\t\t\trelies on generative AI."
"message": "You must enable this if this project contains a substantial amount of AI-generated code, any\n\t\t\t\tassets that are substantially AI-generated, or if any element of your project's page such as\n\t\t\t\tdescription or publishing relies on generative AI."
},
"project.settings.disclosures.ai.note-placeholder": {
"message": "e.g. The Chinese and Arabic translations are AI-generated."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { computed, watch } from 'vue'
import {
AdvertisingDisclosureCard,
AiDisclosureCard,
AiFunctionalityDisclosureCard,
ArchivedDisclosureCard,
DerivativeDisclosureCard,
type DisclosureFormIssue,
Expand Down Expand Up @@ -293,6 +294,14 @@ const { confirmLeaveModal } = usePageLeaveSafety(hasChanges)
(status: DisclosureLockStatus) => setDisclosureLockStatus('ai_content', status)
"
/>
<AiFunctionalityDisclosureCard
v-if="isDisclosureVisible('ai_functionality')"
v-model="current.aiFunctionality"
v-bind="disclosureUpdateProps('ai_functionality')"
@set-lock-status="
(status: DisclosureLockStatus) => setDisclosureLockStatus('ai_functionality', status)
"
/>
<AdvertisingDisclosureCard
v-if="isDisclosureVisible('advertisements')"
v-model="current.advertising"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
INSERT INTO project_disclosures (project_id, type, metadata, updated_at, updated_by, set_by_moderator, deleted_at, lock_status)
SELECT
project_id,
'ai_functionality',
'{"note":null}'::jsonb,
now(),
0,
set_by_moderator,
deleted_at,
lock_status
FROM project_disclosures
WHERE type = 'ai_content'
AND metadata -> 'uses' ? 'functionality'
ON CONFLICT (project_id, type) DO NOTHING;

DELETE FROM project_disclosures
WHERE type = 'ai_content'
AND metadata -> 'uses' ? 'functionality'
AND jsonb_array_length(metadata -> 'uses') = 1;

UPDATE project_disclosures
SET metadata = jsonb_set(metadata, '{uses}', (metadata -> 'uses') - 'functionality')
WHERE type = 'ai_content'
AND metadata -> 'uses' ? 'functionality';
4 changes: 3 additions & 1 deletion apps/labrinth/src/models/v3/disclosures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub enum ProjectDisclosure {
note: Option<String>,
uses: BTreeSet<AiUsages>,
},
AiFunctionality {
note: Option<String>,
},
Advertisements {
note: Option<String>,
},
Expand Down Expand Up @@ -161,7 +164,6 @@ pub enum AiUsages {
Code,
Assets,
Text,
Functionality,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, IntoStaticStr)]
Expand Down
6 changes: 5 additions & 1 deletion packages/api-client/src/modules/labrinth/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@ export namespace Labrinth {

export type TelemetryConsent = 'opt_in' | 'opt_out' | 'always_active'

export type AiUsage = 'code' | 'assets' | 'text' | 'functionality'
export type AiUsage = 'code' | 'assets' | 'text'

export type DisclosureLockStatus = 'unlocked' | 'cannot_disable' | 'fully_locked'

Expand All @@ -1320,6 +1320,10 @@ export namespace Labrinth {
uses: AiUsage[]
note?: string | null
}
| {
type: 'ai_functionality'
note?: string | null
}
| {
type: 'advertisements'
note?: string | null
Expand Down
2 changes: 2 additions & 0 deletions packages/assets/generated-icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import _BoxIcon from './icons/box.svg?component'
import _BoxImportIcon from './icons/box-import.svg?component'
import _BoxesIcon from './icons/boxes.svg?component'
import _BracesIcon from './icons/braces.svg?component'
import _BrainCircuitIcon from './icons/brain-circuit.svg?component'
import _BrushCleaningIcon from './icons/brush-cleaning.svg?component'
import _BugIcon from './icons/bug.svg?component'
import _CalendarIcon from './icons/calendar.svg?component'
Expand Down Expand Up @@ -505,6 +506,7 @@ export const BoxIcon = _BoxIcon
export const BoxImportIcon = _BoxImportIcon
export const BoxesIcon = _BoxesIcon
export const BracesIcon = _BracesIcon
export const BrainCircuitIcon = _BrainCircuitIcon
export const BrushCleaningIcon = _BrushCleaningIcon
export const BugIcon = _BugIcon
export const CalendarIcon = _CalendarIcon
Expand Down
27 changes: 27 additions & 0 deletions packages/assets/icons/brain-circuit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 18 additions & 5 deletions packages/ui/src/components/project/ProjectSidebarDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@
</span>
</div>
</div>
<div v-if="aiFunctionalityDisclosure">
<BrainCircuitIcon aria-hidden="true" />
<div class="flex flex-col gap-1">
<span>
{{ capitalizeString(formatMessage(messages.aiFunctionalityTitle)) }}
</span>
<span v-if="aiFunctionalityDisclosure.note" class="text-sm text-secondary">
<BasicMarkdownText :text="aiFunctionalityDisclosure.note" :target="linkTarget" />
</span>
</div>
</div>
<div v-if="advertisingDisclosure">
<MegaphoneIcon aria-hidden="true" />
<div class="flex flex-col gap-1">
Expand Down Expand Up @@ -226,6 +237,7 @@
import type { Labrinth } from '@modrinth/api-client'
import {
BookTextIcon,
BrainCircuitIcon,
CalendarIcon,
CircleDollarSignIcon,
CircuitBoardIcon,
Expand Down Expand Up @@ -263,7 +275,7 @@ const formatDateTime = useFormatDateTime({
dateStyle: 'long',
})

const AI_USE_ORDER: Labrinth.Projects.v3.AiUsage[] = ['code', 'assets', 'text', 'functionality']
const AI_USE_ORDER: Labrinth.Projects.v3.AiUsage[] = ['code', 'assets', 'text']

const props = defineProps<{
project: Labrinth.Projects.v2.Project
Expand Down Expand Up @@ -304,6 +316,10 @@ const messages = defineMessages({
id: 'project.disclosure.ai-generated-content.title',
defaultMessage: 'Contains AI-generated {types}',
},
aiFunctionalityTitle: {
id: 'project.disclosure.ai-functionality.title',
defaultMessage: 'Generative AI functionality',
},
derivativeWork: {
id: 'project.disclosure.derivative-work.title',
defaultMessage: 'This is a derivative work of:',
Expand Down Expand Up @@ -346,6 +362,7 @@ function findDisclosure<T extends Labrinth.Projects.v3.ProjectDisclosureType>(ty
}

const aiDisclosure = computed(() => findDisclosure('ai_content'))
const aiFunctionalityDisclosure = computed(() => findDisclosure('ai_functionality'))
const advertisingDisclosure = computed(() => findDisclosure('advertisements'))
const paidFeaturesDisclosure = computed(() => findDisclosure('paid_features'))
const telemetryDisclosure = computed(() => findDisclosure('telemetry'))
Expand Down Expand Up @@ -388,10 +405,6 @@ const aiUseLabels = {
id: 'project.disclosure.ai-generated-content.use.text',
defaultMessage: 'text',
}),
functionality: defineMessage({
id: 'project.disclosure.ai-generated-content.use.functionality',
defaultMessage: 'functionality',
}),
content: defineMessage({
id: 'project.disclosure.ai-generated-content.use.content',
defaultMessage: 'content',
Expand Down
Loading
Loading