aboutsummaryrefslogtreecommitdiffstats
path: root/apps/settings/src/components/AdminAI.vue
diff options
context:
space:
mode:
Diffstat (limited to 'apps/settings/src/components/AdminAI.vue')
-rw-r--r--apps/settings/src/components/AdminAI.vue131
1 files changed, 93 insertions, 38 deletions
diff --git a/apps/settings/src/components/AdminAI.vue b/apps/settings/src/components/AdminAI.vue
index ea444fc25cf..0d3e9154bb9 100644
--- a/apps/settings/src/components/AdminAI.vue
+++ b/apps/settings/src/components/AdminAI.vue
@@ -1,5 +1,47 @@
+<!--
+ - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
<template>
- <div>
+ <div class="ai-settings">
+ <NcSettingsSection :name="t('settings', 'Unified task processing')"
+ :description="t('settings', 'AI tasks can be implemented by different apps. Here you can set which app should be used for which task.')">
+ <NcCheckboxRadioSwitch v-model="settings['ai.taskprocessing_guests']"
+ type="switch"
+ @update:modelValue="saveChanges">
+ {{ t('settings', 'Allow AI usage for guest users') }}
+ </NcCheckboxRadioSwitch>
+ <h3>{{ t('settings', 'Provider for Task types') }}</h3>
+ <template v-for="type in taskProcessingTaskTypes">
+ <div :key="type" class="tasktype-item">
+ <p class="tasktype-name">
+ {{ type.name }}
+ </p>
+ <NcCheckboxRadioSwitch v-model="settings['ai.taskprocessing_type_preferences'][type.id]"
+ type="switch"
+ @update:modelValue="saveChanges">
+ {{ t('settings', 'Enable') }}
+ </NcCheckboxRadioSwitch><NcSelect v-model="settings['ai.taskprocessing_provider_preferences'][type.id]"
+ class="provider-select"
+ :clearable="false"
+ :disabled="!settings['ai.taskprocessing_type_preferences'][type.id]"
+ :options="taskProcessingProviders.filter(p => p.taskType === type.id).map(p => p.id)"
+ @input="saveChanges">
+ <template #option="{label}">
+ {{ taskProcessingProviders.find(p => p.id === label)?.name }}
+ </template>
+ <template #selected-option="{label}">
+ {{ taskProcessingProviders.find(p => p.id === label)?.name }}
+ </template>
+ </NcSelect>
+ </div>
+ </template>
+ <template v-if="!hasTaskProcessing">
+ <NcNoteCard type="info">
+ {{ t('settings', 'None of your currently installed apps provide Task processing functionality') }}
+ </NcNoteCard>
+ </template>
+ </NcSettingsSection>
<NcSettingsSection :name="t('settings', 'Machine translation')"
:description="t('settings', 'Machine translation can be implemented by different apps. Here you can define the precedence of the machine translation apps you have installed at the moment.')">
<draggable v-model="settings['ai.translation_provider_preferences']" @change="saveChanges">
@@ -18,24 +60,6 @@
</div>
</draggable>
</NcSettingsSection>
- <NcSettingsSection :name="t('settings', 'Speech-To-Text')"
- :description="t('settings', 'Speech-To-Text can be implemented by different apps. Here you can set which app should be used.')">
- <template v-for="provider in sttProviders">
- <NcCheckboxRadioSwitch :key="provider.class"
- :checked.sync="settings['ai.stt_provider']"
- :value="provider.class"
- name="stt_provider"
- type="radio"
- @update:checked="saveChanges">
- {{ provider.name }}
- </NcCheckboxRadioSwitch>
- </template>
- <template v-if="!hasStt">
- <NcNoteCard type="info">
- {{ t('settings', 'None of your currently installed apps provide Speech-To-Text functionality') }}
- </NcNoteCard>
- </template>
- </NcSettingsSection>
<NcSettingsSection :name="t('settings', 'Image generation')"
:description="t('settings', 'Image generation can be implemented by different apps. Here you can set which app should be used.')">
<template v-for="provider in text2imageProviders">
@@ -58,10 +82,11 @@
:description="t('settings', 'Text processing tasks can be implemented by different apps. Here you can set which app should be used for which task.')">
<template v-for="type in tpTaskTypes">
<div :key="type">
- <h3>{{ t('settings', 'Task:') }} {{ getTaskType(type).name }}</h3>
- <p>{{ getTaskType(type).description }}</p>
+ <h3>{{ t('settings', 'Task:') }} {{ getTextProcessingTaskType(type).name }}</h3>
+ <p>{{ getTextProcessingTaskType(type).description }}</p>
<p>&nbsp;</p>
<NcSelect v-model="settings['ai.textprocessing_provider_preferences'][type]"
+ class="provider-select"
:clearable="false"
:options="textProcessingProviders.filter(p => p.taskType === type).map(p => p.class)"
@input="saveChanges">
@@ -75,9 +100,10 @@
<p>&nbsp;</p>
</div>
</template>
- <template v-if="!hasTextProcessing">
+ <template v-if="tpTaskTypes.length === 0">
<NcNoteCard type="info">
- {{ t('settings', 'None of your currently installed apps provide Text processing functionality') }}
+ <!-- TRANSLATORS Text processing is the name of a Nextcloud-internal API -->
+ {{ t('settings', 'None of your currently installed apps provide text processing functionality using the Text Processing API.') }}
</NcNoteCard>
</template>
</NcSettingsSection>
@@ -86,17 +112,17 @@
<script>
import axios from '@nextcloud/axios'
-import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
-import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'
-import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
-import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
-import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
+import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
+import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
+import NcSelect from '@nextcloud/vue/components/NcSelect'
+import NcButton from '@nextcloud/vue/components/NcButton'
+import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import draggable from 'vuedraggable'
import DragVerticalIcon from 'vue-material-design-icons/DragVertical.vue'
import ArrowDownIcon from 'vue-material-design-icons/ArrowDown.vue'
import ArrowUpIcon from 'vue-material-design-icons/ArrowUp.vue'
import { loadState } from '@nextcloud/initial-state'
-
+import { nextTick } from 'vue'
import { generateUrl } from '@nextcloud/router'
export default {
@@ -123,22 +149,32 @@ export default {
textProcessingProviders: loadState('settings', 'ai-text-processing-providers'),
textProcessingTaskTypes: loadState('settings', 'ai-text-processing-task-types'),
text2imageProviders: loadState('settings', 'ai-text2image-providers'),
+ taskProcessingProviders: loadState('settings', 'ai-task-processing-providers'),
+ taskProcessingTaskTypes: loadState('settings', 'ai-task-processing-task-types'),
settings: loadState('settings', 'ai-settings'),
}
},
computed: {
- hasStt() {
- return this.sttProviders.length > 0
- },
hasTextProcessing() {
return Object.keys(this.settings['ai.textprocessing_provider_preferences']).length > 0 && Array.isArray(this.textProcessingTaskTypes)
},
tpTaskTypes() {
- return Object.keys(this.settings['ai.textprocessing_provider_preferences']).filter(type => !!this.getTaskType(type))
+ const builtinTextProcessingTypes = [
+ 'OCP\\TextProcessing\\FreePromptTaskType',
+ 'OCP\\TextProcessing\\HeadlineTaskType',
+ 'OCP\\TextProcessing\\SummaryTaskType',
+ 'OCP\\TextProcessing\\TopicsTaskType',
+ ]
+ return Object.keys(this.settings['ai.textprocessing_provider_preferences'])
+ .filter(type => !!this.getTextProcessingTaskType(type))
+ .filter(type => !builtinTextProcessingTypes.includes(type))
},
hasText2ImageProviders() {
return this.text2imageProviders.length > 0
},
+ hasTaskProcessing() {
+ return Object.keys(this.settings['ai.taskprocessing_provider_preferences']).length > 0 && Array.isArray(this.taskProcessingTaskTypes)
+ },
},
methods: {
moveUp(i) {
@@ -159,6 +195,7 @@ export default {
},
async saveChanges() {
this.loading = true
+ await nextTick()
const data = { settings: this.settings }
try {
await axios.put(generateUrl('/settings/api/admin/ai'), data)
@@ -167,7 +204,7 @@ export default {
}
this.loading = false
},
- getTaskType(type) {
+ getTextProcessingTaskType(type) {
if (!Array.isArray(this.textProcessingTaskTypes)) {
return null
}
@@ -190,13 +227,31 @@ export default {
.draggable__number {
border-radius: 20px;
- border: 2px solid var(--color-primary-default);
- color: var(--color-primary-default);
- padding: 0px 7px;
- margin-right: 3px;
+ border: 2px solid var(--color-primary-element);
+ color: var(--color-primary-element);
+ padding: 0px 7px;
+ margin-inline-end: 3px;
}
.drag-vertical-icon {
float: left;
}
+
+.ai-settings h3 {
+ font-size: 16px; /* to offset against the 20px section heading */
+}
+
+.provider-select {
+ min-width: 350px !important;
+}
+
+.tasktype-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ .tasktype-name {
+ flex: 1;
+ margin: 0;
+ }
+}
</style>