First pass at ai admin settings
Signed-off-by: Marcel Klehr <mklehr@gmx.net>pull/39567/head
parent
78856f354f
commit
fc9780a41d
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2A2,2 0 0,1 14,4C14,4.74 13.6,5.39 13,5.73V7H14A7,7 0 0,1 21,14H22A1,1 0 0,1 23,15V18A1,1 0 0,1 22,19H21V20A2,2 0 0,1 19,22H5A2,2 0 0,1 3,20V19H2A1,1 0 0,1 1,18V15A1,1 0 0,1 2,14H3A7,7 0 0,1 10,7H11V5.73C10.4,5.39 10,4.74 10,4A2,2 0 0,1 12,2M7.5,13A2.5,2.5 0 0,0 5,15.5A2.5,2.5 0 0,0 7.5,18A2.5,2.5 0 0,0 10,15.5A2.5,2.5 0 0,0 7.5,13M16.5,13A2.5,2.5 0 0,0 14,15.5A2.5,2.5 0 0,0 16.5,18A2.5,2.5 0 0,0 19,15.5A2.5,2.5 0 0,0 16.5,13Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 513 B |
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
|
||||||
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||||
|
*
|
||||||
|
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||||
|
* @author Daniel Kesselberg <mail@danielkesselberg.de>
|
||||||
|
* @author Joas Schilling <coding@schilljs.com>
|
||||||
|
* @author Lukas Reschke <lukas@statuscode.ch>
|
||||||
|
* @author Morris Jobke <hey@morrisjobke.de>
|
||||||
|
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\Settings\Controller;
|
||||||
|
|
||||||
|
use OCP\AppFramework\Controller;
|
||||||
|
use OCP\AppFramework\Http;
|
||||||
|
use OCP\AppFramework\Http\DataResponse;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\IRequest;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\IUserSession;
|
||||||
|
use OCP\Mail\IMailer;
|
||||||
|
|
||||||
|
class AISettingsController extends Controller {
|
||||||
|
|
||||||
|
/** @var IL10N */
|
||||||
|
private $l10n;
|
||||||
|
/** @var IConfig */
|
||||||
|
private $config;
|
||||||
|
/** @var IUserSession */
|
||||||
|
private $userSession;
|
||||||
|
/** @var IMailer */
|
||||||
|
private $mailer;
|
||||||
|
/** @var IURLGenerator */
|
||||||
|
private $urlGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $appName
|
||||||
|
* @param IRequest $request
|
||||||
|
* @param IL10N $l10n
|
||||||
|
* @param IConfig $config
|
||||||
|
* @param IUserSession $userSession
|
||||||
|
* @param IURLGenerator $urlGenerator,
|
||||||
|
* @param IMailer $mailer
|
||||||
|
*/
|
||||||
|
public function __construct($appName,
|
||||||
|
IRequest $request,
|
||||||
|
IL10N $l10n,
|
||||||
|
IConfig $config,
|
||||||
|
IUserSession $userSession,
|
||||||
|
IURLGenerator $urlGenerator,
|
||||||
|
IMailer $mailer) {
|
||||||
|
parent::__construct($appName, $request);
|
||||||
|
$this->l10n = $l10n;
|
||||||
|
$this->config = $config;
|
||||||
|
$this->userSession = $userSession;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
|
$this->mailer = $mailer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email settings
|
||||||
|
*
|
||||||
|
* @PasswordConfirmationRequired
|
||||||
|
* @AuthorizedAdminSetting(settings=OCA\Settings\Settings\Admin\ArtificialIntelligence)
|
||||||
|
*
|
||||||
|
* @param array $settings
|
||||||
|
* @return DataResponse
|
||||||
|
*/
|
||||||
|
public function setAISettings($settings) {
|
||||||
|
$params = get_defined_vars();
|
||||||
|
$configs = [];
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
$configs[$key] = empty($value) ? null : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete passwords from config in case no auth is specified
|
||||||
|
if ($params['mail_smtpauth'] !== 1) {
|
||||||
|
$configs['mail_smtpname'] = null;
|
||||||
|
$configs['mail_smtppassword'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->config->setSystemValues($configs);
|
||||||
|
|
||||||
|
$this->config->setAppValue('core', 'emailTestSuccessful', '0');
|
||||||
|
|
||||||
|
return new DataResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\Settings\Sections\Admin;
|
||||||
|
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\Settings\IIconSection;
|
||||||
|
|
||||||
|
class ArtificialIntelligence implements IIconSection {
|
||||||
|
|
||||||
|
/** @var IL10N */
|
||||||
|
private $l;
|
||||||
|
|
||||||
|
/** @var IURLGenerator */
|
||||||
|
private $urlGenerator;
|
||||||
|
|
||||||
|
public function __construct(IL10N $l, IURLGenerator $urlGenerator) {
|
||||||
|
$this->l = $l;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIcon(): string {
|
||||||
|
return $this->urlGenerator->imagePath('settings', 'ai.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getID(): string {
|
||||||
|
return 'ai';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string {
|
||||||
|
return $this->l->t('Artificial Intelligence');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPriority(): int {
|
||||||
|
return 40;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,163 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
|
||||||
|
*
|
||||||
|
* @author Marcel Klehr <mklehr@gmx.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\Settings\Settings\Admin;
|
||||||
|
|
||||||
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
|
use OCP\AppFramework\Services\IInitialState;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\IServerContainer;
|
||||||
|
use OCP\Settings\IDelegatedSettings;
|
||||||
|
use OCP\SpeechToText\ISpeechToTextManager;
|
||||||
|
use OCP\TextProcessing\IManager;
|
||||||
|
use OCP\TextProcessing\IProvider;
|
||||||
|
use OCP\TextProcessing\ITaskType;
|
||||||
|
use OCP\Translation\ITranslationManager;
|
||||||
|
use Psr\Container\ContainerExceptionInterface;
|
||||||
|
use Psr\Container\NotFoundExceptionInterface;
|
||||||
|
|
||||||
|
class ArtificialIntelligence implements IDelegatedSettings {
|
||||||
|
public function __construct(
|
||||||
|
private IConfig $config,
|
||||||
|
private IL10N $l,
|
||||||
|
private IInitialState $initialState,
|
||||||
|
private ITranslationManager $translationManager,
|
||||||
|
private ISpeechToTextManager $sttManager,
|
||||||
|
private IManager $textProcessingManager,
|
||||||
|
private IServerContainer $container,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TemplateResponse
|
||||||
|
*/
|
||||||
|
public function getForm() {
|
||||||
|
$translationProviders = [];
|
||||||
|
$translationPreferences = [];
|
||||||
|
foreach ($this->translationManager->getProviders() as $provider) {
|
||||||
|
$translationProviders[] = [
|
||||||
|
'class' => $provider::class,
|
||||||
|
'name' => $provider->getName(),
|
||||||
|
];
|
||||||
|
$translationPreferences[] = $provider::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sttProviders = [];
|
||||||
|
foreach ($this->sttManager->getProviders() as $provider) {
|
||||||
|
$sttProviders[] = [
|
||||||
|
'class' => $provider::class,
|
||||||
|
'name' => $provider->getName(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$textProcessingProviders = [];
|
||||||
|
/** @var array<class-string<ITaskType>, class-string<IProvider>> $textProcessingSettings */
|
||||||
|
$textProcessingSettings = [];
|
||||||
|
foreach ($this->textProcessingManager->getProviders() as $provider) {
|
||||||
|
$textProcessingProviders[] = [
|
||||||
|
'class' => $provider::class,
|
||||||
|
'name' => $provider->getName(),
|
||||||
|
'taskType' => $provider->getTaskType(),
|
||||||
|
];
|
||||||
|
$textProcessingSettings[$provider->getTaskType()] = $provider::class;
|
||||||
|
}
|
||||||
|
$textProcessingTaskTypes = [];
|
||||||
|
foreach ($textProcessingSettings as $taskTypeClass => $providerClass) {
|
||||||
|
/** @var ITaskType $taskType */
|
||||||
|
try {
|
||||||
|
$taskType = $this->container->get($taskTypeClass);
|
||||||
|
} catch (NotFoundExceptionInterface $e) {
|
||||||
|
continue;
|
||||||
|
} catch (ContainerExceptionInterface $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$textProcessingTaskTypes[] = [
|
||||||
|
'class' => $taskTypeClass,
|
||||||
|
'name' => $taskType->getName(),
|
||||||
|
'description' => $taskType->getDescription(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->initialState->provideInitialState('ai-stt-providers', $sttProviders);
|
||||||
|
$this->initialState->provideInitialState('ai-translation-providers', $translationProviders);
|
||||||
|
$this->initialState->provideInitialState('ai-text-processing-providers', $textProcessingProviders);
|
||||||
|
$this->initialState->provideInitialState('ai-text-processing-task-types', $textProcessingTaskTypes);
|
||||||
|
|
||||||
|
$settings = [
|
||||||
|
'ai.stt_provider' => count($sttProviders) > 0 ? $sttProviders[0]['class'] : null,
|
||||||
|
'ai.textprocessing_provider_preferences' => $textProcessingSettings,
|
||||||
|
'ai.translation_provider_preferences' => $translationPreferences,
|
||||||
|
];
|
||||||
|
foreach ($settings as $key => $defaultValue) {
|
||||||
|
$value = $defaultValue;
|
||||||
|
$json = $this->config->getAppValue('core', $key, '');
|
||||||
|
if ($json !== '') {
|
||||||
|
$value = json_decode($json, JSON_OBJECT_AS_ARRAY);
|
||||||
|
switch($key) {
|
||||||
|
case 'ai.textprocessing_provider_preferences':
|
||||||
|
// fill $value with $defaultValue values
|
||||||
|
$value = array_merge($defaultValue, $value);
|
||||||
|
break;
|
||||||
|
case 'ai.translation_provider_preferences':
|
||||||
|
$value += array_diff($defaultValue, $value); // Add entries from $defaultValue that are not in $value to the end of $value
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$settings[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->initialState->provideInitialState('ai-settings', $settings);
|
||||||
|
|
||||||
|
return new TemplateResponse('settings', 'settings/admin/ai');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string the section ID, e.g. 'sharing'
|
||||||
|
*/
|
||||||
|
public function getSection() {
|
||||||
|
return 'ai';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int whether the form should be rather on the top or bottom of
|
||||||
|
* the admin section. The forms are arranged in ascending order of the
|
||||||
|
* priority values. It is required to return a value between 0 and 100.
|
||||||
|
*
|
||||||
|
* E.g.: 70
|
||||||
|
*/
|
||||||
|
public function getPriority() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string {
|
||||||
|
return $this->l->t('Artificial Intelligence');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizedAppConfig(): array {
|
||||||
|
return [
|
||||||
|
'core' => ['/ai_.*/'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<NcSettingsSection :title="t('settings', 'Artificial Intelligence')"
|
||||||
|
:description="t('settings', 'Artificial Intelligence features can be implemented by different apps. Here you can set which app should be used for which features.')">
|
||||||
|
<h3>{{ t('settings', 'Translations') }}</h3>
|
||||||
|
<h3>{{ t('settings', 'Speech-To-Text') }}</h3>
|
||||||
|
<template v-for="provider in sttProviders">
|
||||||
|
<NcCheckboxRadioSwitch :key="provider.class"
|
||||||
|
:checked.sync="settings['ai.stt_provider']"
|
||||||
|
:value="provider.class"
|
||||||
|
name="stt_provider"
|
||||||
|
type="radio">{{ provider.name }}</NcCheckboxRadioSwitch>
|
||||||
|
</template>
|
||||||
|
<template v-if="sttProviders.length === 0">
|
||||||
|
<NcCheckboxRadioSwitch disabled type="radio">{{ t('settings', 'No apps are currently installed that provide Speech-To-Text functionality') }}</NcCheckboxRadioSwitch>
|
||||||
|
</template>
|
||||||
|
<h3>{{ t('settings', 'Text processing') }}</h3>
|
||||||
|
<template v-for="(type, provider) in settings['ai.textprocessing_provider_preferences']">
|
||||||
|
<h4>{{ type }}</h4>
|
||||||
|
<!--<p>{{ getTaskType(type).description }}</p>
|
||||||
|
<NcSelect v-model="settings['ai.textprocessing_provider_preferences'][type]" :options="textProcessingProviders.filter(provider => provider.taskType === type)" />-->
|
||||||
|
</template>
|
||||||
|
<template v-if="Object.keys(settings['ai.textprocessing_provider_preferences']).length === 0 || !Array.isArray(this.textProcessingTaskTypes)">
|
||||||
|
<p>{{ t('settings', 'No apps are currently installed that provide Text processing functionality') }}</p>
|
||||||
|
</template>
|
||||||
|
</NcSettingsSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<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 { loadState } from '@nextcloud/initial-state'
|
||||||
|
|
||||||
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AdminAI',
|
||||||
|
components: {
|
||||||
|
NcCheckboxRadioSwitch,
|
||||||
|
NcSettingsSection,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
dirty: false,
|
||||||
|
groups: [],
|
||||||
|
loadingGroups: false,
|
||||||
|
sttProviders: loadState('settings', 'ai-stt-providers'),
|
||||||
|
translationProviders: loadState('settings', 'ai-translation-providers'),
|
||||||
|
textProcessingProviders: loadState('settings', 'ai-text-processing-providers'),
|
||||||
|
textProcessingTaskTypes: loadState('settings', 'ai-text-processing-task-types'),
|
||||||
|
settings: loadState('settings', 'ai-settings'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
saveChanges() {
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
enforced: this.enforced,
|
||||||
|
enforcedGroups: this.enforcedGroups,
|
||||||
|
excludedGroups: this.excludedGroups,
|
||||||
|
}
|
||||||
|
axios.put(generateUrl('/settings/api/admin/twofactorauth'), data)
|
||||||
|
.then(resp => resp.data)
|
||||||
|
.then(state => {
|
||||||
|
this.state = state
|
||||||
|
this.dirty = false
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('could not save changes', err)
|
||||||
|
})
|
||||||
|
.then(() => { this.loading = false })
|
||||||
|
},
|
||||||
|
getTaskType(type) {
|
||||||
|
if (!Array.isArray(this.textProcessingTaskTypes)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return this.textProcessingTaskTypes.find(taskType => taskType === type)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
script('settings', [
|
||||||
|
'vue-settings-admin-ai',
|
||||||
|
]);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="ai-settings">
|
||||||
|
</div>
|
||||||
Loading…
Reference in New Issue