diff --git a/lib/Controller/ConfigController.php b/lib/Controller/ConfigController.php
index dae11002..3c40d6a3 100644
--- a/lib/Controller/ConfigController.php
+++ b/lib/Controller/ConfigController.php
@@ -72,8 +72,11 @@ public function setSensitiveUserConfig(array $values): DataResponse {
* @return DataResponse
*/
public function setAdminConfig(array $values): DataResponse {
- if (isset($values['api_key']) || isset($values['basic_password']) || isset($values['basic_user']) || isset($values['url'])) {
- return new DataResponse('', Http::STATUS_BAD_REQUEST);
+ $prefixes = ['', 'image_', 'tts_', 'stt_'];
+ foreach ($prefixes as $prefix) {
+ if (isset($values[$prefix . 'api_key']) || isset($values[$prefix . 'basic_password']) || isset($values[$prefix . 'basic_user']) || isset($values[$prefix . 'url'])) {
+ return new DataResponse('', Http::STATUS_BAD_REQUEST);
+ }
}
try {
$this->openAiSettingsService->setAdminConfig($values);
diff --git a/lib/Controller/OpenAiAPIController.php b/lib/Controller/OpenAiAPIController.php
index df7e9114..c27fba4e 100644
--- a/lib/Controller/OpenAiAPIController.php
+++ b/lib/Controller/OpenAiAPIController.php
@@ -26,12 +26,13 @@ public function __construct(
}
/**
+ * @param string|null $serviceType
* @return DataResponse
*/
#[NoAdminRequired]
- public function getModels(): DataResponse {
+ public function getModels(?string $serviceType = null): DataResponse {
try {
- $response = $this->openAiAPIService->getModels($this->userId, true);
+ $response = $this->openAiAPIService->getModels($this->userId, true, $serviceType);
return new DataResponse($response);
} catch (Exception $e) {
$code = $e->getCode() === 0 ? Http::STATUS_BAD_REQUEST : intval($e->getCode());
diff --git a/lib/Service/OpenAiAPIService.php b/lib/Service/OpenAiAPIService.php
index a7652aec..9b11c22b 100644
--- a/lib/Service/OpenAiAPIService.php
+++ b/lib/Service/OpenAiAPIService.php
@@ -66,21 +66,47 @@ public function createQuotaUsage(string $userId, int $type, int $usage) {
}
/**
+ * @param ?string $serviceType
* @return bool
*/
- public function isUsingOpenAi(): bool {
- $serviceUrl = $this->openAiSettingsService->getServiceUrl();
+ public function isUsingOpenAi(?string $serviceType = null): bool {
+ $serviceUrl = '';
+ if ($serviceType === 'image') {
+ $serviceUrl = $this->openAiSettingsService->getImageUrl();
+ } elseif ($serviceType === 'stt') {
+ $serviceUrl = $this->openAiSettingsService->getSttUrl();
+ } elseif ($serviceType === 'tts') {
+ $serviceUrl = $this->openAiSettingsService->getTtsUrl();
+ }
+ if ($serviceUrl === '') {
+ $serviceUrl = $this->openAiSettingsService->getServiceUrl();
+ }
return $serviceUrl === '' || $serviceUrl === Application::OPENAI_API_BASE_URL;
}
/**
+ * @param ?string $serviceType
+ *
* @return string
*/
- public function getServiceName(): string {
- if ($this->isUsingOpenAi()) {
+ public function getServiceName(?string $serviceType = null): string {
+ if ($this->isUsingOpenAi($serviceType)) {
+ if ($serviceType === 'image') {
+ return $this->l10n->t('OpenAI\'s DALL-E 2');
+ }
+ if ($serviceType === 'tts') {
+ $this->l10n->t('OpenAI\'s Text to Speech');
+ }
return 'OpenAI';
} else {
$serviceName = $this->openAiSettingsService->getServiceName();
+ if ($serviceType === 'image' && $this->openAiSettingsService->imageOverrideEnabled()) {
+ $serviceName = $this->openAiSettingsService->getImageServiceName();
+ } elseif ($serviceType === 'stt' && $this->openAiSettingsService->sttOverrideEnabled()) {
+ $serviceName = $this->openAiSettingsService->getSttServiceName();
+ } elseif ($serviceType === 'tts' && $this->openAiSettingsService->ttsOverrideEnabled()) {
+ $serviceName = $this->openAiSettingsService->getTtsServiceName();
+ }
if ($serviceName === '') {
return 'LocalAI';
}
@@ -111,13 +137,15 @@ private function isModelListValid($models): bool {
/**
* @param ?string $userId
* @param bool $refresh
+ * @param ?string $serviceType
* @return array|string[]
* @throws Exception
*/
- public function getModels(?string $userId, bool $refresh = false): array {
+ public function getModels(?string $userId, bool $refresh = false, ?string $serviceType = null): array {
$cache = $this->cacheFactory->createDistributed(Application::APP_ID);
- $userCacheKey = Application::MODELS_CACHE_KEY . '_' . ($userId ?? '');
- $adminCacheKey = Application::MODELS_CACHE_KEY . '-main';
+ $userCacheKey = Application::MODELS_CACHE_KEY . '_' . ($userId ?? '') . '_' . ($serviceType ?? 'main');
+ $adminCacheKey = Application::MODELS_CACHE_KEY . '-main' . '_' . ($serviceType ?? 'main');
+ $dbCacheKey = $serviceType ? 'models' . '_' . $serviceType : 'models';
if (!$refresh) {
if ($this->modelsMemoryCache !== null) {
@@ -155,7 +183,7 @@ public function getModels(?string $userId, bool $refresh = false): array {
}
// if we don't need to refresh to model list and it's not been found in the cache, it is obtained from the DB
- $modelsObjectString = $this->appConfig->getValueString(Application::APP_ID, 'models', '{"data":[],"object":"list"}');
+ $modelsObjectString = $this->appConfig->getValueString(Application::APP_ID, $dbCacheKey, '{"data":[],"object":"list"}');
$fallbackModels = [
'data' => [],
'object' => 'list',
@@ -177,7 +205,7 @@ public function getModels(?string $userId, bool $refresh = false): array {
try {
$this->logger->debug('Actually getting OpenAI models with a network request');
- $modelsResponse = $this->request($userId, 'models');
+ $modelsResponse = $this->request($userId, 'models', serviceType: $serviceType);
} catch (Exception $e) {
$this->logger->warning('Error retrieving models (exc): ' . $e->getMessage());
throw $e;
@@ -200,7 +228,7 @@ public function getModels(?string $userId, bool $refresh = false): array {
$this->modelsMemoryCache = $modelsResponse;
// we always store the model list after getting it
$modelsObjectString = json_encode($modelsResponse);
- $this->appConfig->setValueString(Application::APP_ID, 'models', $modelsObjectString);
+ $this->appConfig->setValueString(Application::APP_ID, $dbCacheKey, $modelsObjectString);
return $modelsResponse;
}
@@ -223,9 +251,9 @@ private function hasOwnOpenAiApiKey(string $userId): bool {
* @param string|null $userId
* @return array
*/
- public function getModelEnumValues(?string $userId): array {
+ public function getModelEnumValues(?string $userId, ?string $serviceType = null): array {
try {
- $modelResponse = $this->getModels($userId);
+ $modelResponse = $this->getModels($userId, false, $serviceType);
$modelEnumValues = array_map(function (array $model) {
return new ShapeEnumValue($model['id'], $model['id']);
}, $modelResponse['data'] ?? []);
@@ -779,7 +807,7 @@ public function transcribe(
$endpoint = $translate ? 'audio/translations' : 'audio/transcriptions';
$contentType = 'multipart/form-data';
- $response = $this->request($userId, $endpoint, $params, 'POST', $contentType);
+ $response = $this->request($userId, $endpoint, $params, 'POST', $contentType, serviceType: 'stt');
if (!isset($response['text'])) {
$this->logger->warning('Audio transcription error: ' . json_encode($response));
@@ -822,7 +850,7 @@ public function requestImageCreation(
'model' => $model === Application::DEFAULT_MODEL_ID ? Application::DEFAULT_IMAGE_MODEL_ID : $model,
];
- $apiResponse = $this->request($userId, 'images/generations', $params, 'POST');
+ $apiResponse = $this->request($userId, 'images/generations', $params, 'POST', serviceType: 'image');
if (!isset($apiResponse['data']) || !is_array($apiResponse['data'])) {
$this->logger->warning('OpenAI image generation error', ['api_response' => $apiResponse]);
@@ -891,7 +919,7 @@ public function requestSpeechCreation(
'speed' => $speed,
];
- $apiResponse = $this->request($userId, 'audio/speech', $params, 'POST');
+ $apiResponse = $this->request($userId, 'audio/speech', $params, 'POST', serviceType: 'tts');
try {
$charCount = mb_strlen($prompt);
@@ -930,7 +958,7 @@ public function updateExpTextProcessingTime(int $runtime): void {
* @return int
*/
public function getExpImgProcessingTime(): int {
- return $this->isUsingOpenAi()
+ return $this->isUsingOpenAi('image')
? intval($this->appConfig->getValueString(Application::APP_ID, 'openai_image_generation_time', strval(Application::DEFAULT_OPENAI_IMAGE_GENERATION_TIME), lazy: true))
: intval($this->appConfig->getValueString(Application::APP_ID, 'localai_image_generation_time', strval(Application::DEFAULT_LOCALAI_IMAGE_GENERATION_TIME), lazy: true));
}
@@ -943,7 +971,7 @@ public function updateExpImgProcessingTime(int $runtime): void {
$oldTime = floatval($this->getExpImgProcessingTime());
$newTime = (1.0 - Application::EXPECTED_RUNTIME_LOWPASS_FACTOR) * $oldTime + Application::EXPECTED_RUNTIME_LOWPASS_FACTOR * floatval($runtime);
- if ($this->isUsingOpenAi()) {
+ if ($this->isUsingOpenAi('image')) {
$this->appConfig->setValueString(Application::APP_ID, 'openai_image_generation_time', strval(intval($newTime)), lazy: true);
} else {
$this->appConfig->setValueString(Application::APP_ID, 'localai_image_generation_time', strval(intval($newTime)), lazy: true);
@@ -958,17 +986,54 @@ public function updateExpImgProcessingTime(int $runtime): void {
* @param string $method HTTP query method
* @param string|null $contentType
* @param bool $logErrors if set to false error logs will be suppressed
+ * @param string|null $serviceType
* @return array decoded request result or error
* @throws Exception
*/
- public function request(?string $userId, string $endPoint, array $params = [], string $method = 'GET', ?string $contentType = null, bool $logErrors = true): array {
+ public function request(?string $userId, string $endPoint, array $params = [], string $method = 'GET', ?string $contentType = null, bool $logErrors = true, ?string $serviceType = null): array {
try {
- $serviceUrl = $this->openAiSettingsService->getServiceUrl();
- if ($serviceUrl === '') {
- $serviceUrl = Application::OPENAI_API_BASE_URL;
+ $serviceUrl = '';
+ $apiKey = '';
+ $basicUser = '';
+ $basicPassword = '';
+ $useBasicAuth = false;
+ $timeout = 0;
+
+ if ($serviceType === 'image') {
+ $serviceUrl = $this->openAiSettingsService->getImageUrl();
+ $apiKey = $this->openAiSettingsService->getAdminImageApiKey();
+ $basicUser = $this->openAiSettingsService->getAdminImageBasicUser();
+ $basicPassword = $this->openAiSettingsService->getAdminImageBasicPassword();
+ $useBasicAuth = $this->openAiSettingsService->getAdminImageUseBasicAuth();
+ $timeout = $this->openAiSettingsService->getImageRequestTimeout();
+ } elseif ($serviceType === 'stt') {
+ $serviceUrl = $this->openAiSettingsService->getSttUrl();
+ $apiKey = $this->openAiSettingsService->getAdminSttApiKey();
+ $basicUser = $this->openAiSettingsService->getAdminSttBasicUser();
+ $basicPassword = $this->openAiSettingsService->getAdminSttBasicPassword();
+ $useBasicAuth = $this->openAiSettingsService->getAdminSttUseBasicAuth();
+ $timeout = $this->openAiSettingsService->getSttRequestTimeout();
+ } elseif ($serviceType === 'tts') {
+ $serviceUrl = $this->openAiSettingsService->getTtsUrl();
+ $apiKey = $this->openAiSettingsService->getAdminTtsApiKey();
+ $basicUser = $this->openAiSettingsService->getAdminTtsBasicUser();
+ $basicPassword = $this->openAiSettingsService->getAdminTtsBasicPassword();
+ $useBasicAuth = $this->openAiSettingsService->getAdminTtsUseBasicAuth();
+ $timeout = $this->openAiSettingsService->getTtsRequestTimeout();
}
- $timeout = $this->openAiSettingsService->getRequestTimeout();
+ // Currently only supporting user api keys for the default service
+ if (empty($serviceUrl)) {
+ $serviceUrl = $this->openAiSettingsService->getServiceUrl();
+ if ($serviceUrl === '') {
+ $serviceUrl = Application::OPENAI_API_BASE_URL;
+ }
+ $apiKey = $this->openAiSettingsService->getUserApiKey($userId, true);
+ $basicUser = $this->openAiSettingsService->getUserBasicUser($userId, true);
+ $basicPassword = $this->openAiSettingsService->getUserBasicPassword($userId, true);
+ $useBasicAuth = $this->openAiSettingsService->getUseBasicAuth();
+ $timeout = $this->openAiSettingsService->getRequestTimeout();
+ }
$url = rtrim($serviceUrl, '/') . '/' . $endPoint;
$options = [
@@ -978,20 +1043,11 @@ public function request(?string $userId, string $endPoint, array $params = [], s
],
];
- // an API key is mandatory when using OpenAI
- $apiKey = $this->openAiSettingsService->getUserApiKey($userId, true);
-
- // We can also use basic authentication
- $basicUser = $this->openAiSettingsService->getUserBasicUser($userId, true);
- $basicPassword = $this->openAiSettingsService->getUserBasicPassword($userId, true);
-
if ($serviceUrl === Application::OPENAI_API_BASE_URL && $apiKey === '') {
return ['error' => 'An API key is required for api.openai.com'];
}
- $useBasicAuth = $this->openAiSettingsService->getUseBasicAuth();
-
- if ($this->isUsingOpenAi() || !$useBasicAuth) {
+ if ($this->isUsingOpenAi($serviceType) || !$useBasicAuth) {
if ($apiKey !== '') {
$options['headers']['Authorization'] = 'Bearer ' . $apiKey;
}
@@ -1001,7 +1057,7 @@ public function request(?string $userId, string $endPoint, array $params = [], s
}
}
- if (!$this->isUsingOpenAi()) {
+ if (!$this->isUsingOpenAi($serviceType)) {
$options['nextcloud']['allow_local_address'] = true;
}
@@ -1095,7 +1151,7 @@ public function request(?string $userId, string $endPoint, array $params = [], s
* @return bool whether the T2I provider is available
*/
public function isT2IAvailable(): bool {
- if ($this->isUsingOpenAi()) {
+ if ($this->isUsingOpenAi() || $this->openAiSettingsService->imageOverrideEnabled()) {
return true;
}
try {
@@ -1103,7 +1159,7 @@ public function isT2IAvailable(): bool {
'prompt' => 'a',
'model' => 'invalid-model',
];
- $this->request(null, 'images/generations', $params, 'POST', logErrors: false);
+ $this->request(null, 'images/generations', $params, 'POST', logErrors: false, serviceType: 'image');
} catch (Exception $e) {
return $e->getCode() !== Http::STATUS_NOT_FOUND && $e->getCode() !== Http::STATUS_UNAUTHORIZED;
}
@@ -1116,7 +1172,7 @@ public function isT2IAvailable(): bool {
* @return bool whether the STT provider is available
*/
public function isSTTAvailable(): bool {
- if ($this->isUsingOpenAi()) {
+ if ($this->isUsingOpenAi() || $this->openAiSettingsService->sttOverrideEnabled()) {
return true;
}
try {
@@ -1124,7 +1180,7 @@ public function isSTTAvailable(): bool {
'model' => 'invalid-model',
'file' => 'a',
];
- $this->request(null, 'audio/translations', $params, 'POST', 'multipart/form-data', logErrors: false);
+ $this->request(null, 'audio/translations', $params, 'POST', 'multipart/form-data', logErrors: false, serviceType: 'stt');
} catch (Exception $e) {
return $e->getCode() !== Http::STATUS_NOT_FOUND && $e->getCode() !== Http::STATUS_UNAUTHORIZED;
}
@@ -1137,7 +1193,7 @@ public function isSTTAvailable(): bool {
* @return bool whether the TTS provider is available
*/
public function isTTSAvailable(): bool {
- if ($this->isUsingOpenAi()) {
+ if ($this->isUsingOpenAi() || $this->openAiSettingsService->ttsOverrideEnabled()) {
return true;
}
try {
@@ -1148,7 +1204,7 @@ public function isTTSAvailable(): bool {
'response_format' => 'mp3',
];
- $this->request(null, 'audio/speech', $params, 'POST', logErrors: false);
+ $this->request(null, 'audio/speech', $params, 'POST', logErrors: false, serviceType: 'tts');
} catch (Exception $e) {
return $e->getCode() !== Http::STATUS_NOT_FOUND && $e->getCode() !== Http::STATUS_UNAUTHORIZED;
}
diff --git a/lib/Service/OpenAiSettingsService.php b/lib/Service/OpenAiSettingsService.php
index 1d2e1931..12c0abdb 100644
--- a/lib/Service/OpenAiSettingsService.php
+++ b/lib/Service/OpenAiSettingsService.php
@@ -47,7 +47,31 @@ class OpenAiSettingsService {
'chat_endpoint_enabled' => 'boolean',
'basic_user' => 'string',
'basic_password' => 'string',
- 'use_basic_auth' => 'boolean'
+ 'use_basic_auth' => 'boolean',
+
+ 'image_url' => 'string',
+ 'image_service_name' => 'string',
+ 'image_api_key' => 'string',
+ 'image_basic_user' => 'string',
+ 'image_basic_password' => 'string',
+ 'image_use_basic_auth' => 'boolean',
+ 'image_request_timeout' => 'integer',
+
+ 'stt_url' => 'string',
+ 'stt_service_name' => 'string',
+ 'stt_api_key' => 'string',
+ 'stt_basic_user' => 'string',
+ 'stt_basic_password' => 'string',
+ 'stt_use_basic_auth' => 'boolean',
+ 'stt_request_timeout' => 'integer',
+
+ 'tts_url' => 'string',
+ 'tts_service_name' => 'string',
+ 'tts_api_key' => 'string',
+ 'tts_basic_user' => 'string',
+ 'tts_basic_password' => 'string',
+ 'tts_use_basic_auth' => 'boolean',
+ 'tts_request_timeout' => 'integer',
];
private const USER_CONFIG_TYPES = [
@@ -384,6 +408,153 @@ public function getUseBasicAuth(): bool {
return $this->appConfig->getValueString(Application::APP_ID, 'use_basic_auth', '0', lazy: true) === '1';
}
+ /**
+ * @return string
+ */
+ public function getImageUrl(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'image_url', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getImageServiceName(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'image_service_name', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminImageApiKey(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'image_api_key', '', true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminImageBasicUser(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'image_basic_user', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminImageBasicPassword(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'image_basic_password', '', true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function getAdminImageUseBasicAuth(): bool {
+ return $this->appConfig->getValueString(Application::APP_ID, 'image_use_basic_auth', '0', lazy: true) === '1';
+ }
+
+ /**
+ * @return int
+ */
+ public function getImageRequestTimeout(): int {
+ return intval($this->appConfig->getValueString(Application::APP_ID, 'image_request_timeout', strval(Application::OPENAI_DEFAULT_REQUEST_TIMEOUT), lazy: true)) ?: Application::OPENAI_DEFAULT_REQUEST_TIMEOUT;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSttUrl(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'stt_url', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getSttServiceName(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'stt_service_name', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminSttApiKey(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'stt_api_key', '', true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminSttBasicUser(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'stt_basic_user', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminSttBasicPassword(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'stt_basic_password', '', true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function getAdminSttUseBasicAuth(): bool {
+ return $this->appConfig->getValueString(Application::APP_ID, 'stt_use_basic_auth', '0', lazy: true) === '1';
+ }
+
+ /**
+ * @return int
+ */
+ public function getSttRequestTimeout(): int {
+ return intval($this->appConfig->getValueString(Application::APP_ID, 'stt_request_timeout', strval(Application::OPENAI_DEFAULT_REQUEST_TIMEOUT), lazy: true)) ?: Application::OPENAI_DEFAULT_REQUEST_TIMEOUT;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTtsUrl(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'tts_url', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getTtsServiceName(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'tts_service_name', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminTtsApiKey(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'tts_api_key', '', true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminTtsBasicUser(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'tts_basic_user', '', lazy: true);
+ }
+
+ /**
+ * @return string
+ */
+ public function getAdminTtsBasicPassword(): string {
+ return $this->appConfig->getValueString(Application::APP_ID, 'tts_basic_password', '', true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function getAdminTtsUseBasicAuth(): bool {
+ return $this->appConfig->getValueString(Application::APP_ID, 'tts_use_basic_auth', '0', lazy: true) === '1';
+ }
+
+ /**
+ * @return int
+ */
+ public function getTtsRequestTimeout(): int {
+ return intval($this->appConfig->getValueString(Application::APP_ID, 'tts_request_timeout', strval(Application::OPENAI_DEFAULT_REQUEST_TIMEOUT), lazy: true)) ?: Application::OPENAI_DEFAULT_REQUEST_TIMEOUT;
+ }
+
/**
* Get the admin config for the settings page
* @return mixed[]
@@ -421,7 +592,31 @@ public function getAdminConfig(): array {
'chat_endpoint_enabled' => $this->getChatEndpointEnabled(),
'basic_user' => $this->getAdminBasicUser(),
'basic_password' => $this->getAdminBasicPassword(),
- 'use_basic_auth' => $this->getUseBasicAuth()
+ 'use_basic_auth' => $this->getUseBasicAuth(),
+ // Get the service details for image, stt and tts
+ 'image_url' => $this->getImageUrl(),
+ 'image_service_name' => $this->getImageServiceName(),
+ 'image_api_key' => $this->getAdminImageApiKey(),
+ 'image_basic_user' => $this->getAdminImageBasicUser(),
+ 'image_basic_password' => $this->getAdminImageBasicPassword(),
+ 'image_use_basic_auth' => $this->getAdminImageUseBasicAuth(),
+ 'image_request_timeout' => $this->getImageRequestTimeout(),
+
+ 'stt_url' => $this->getSttUrl(),
+ 'stt_service_name' => $this->getSttServiceName(),
+ 'stt_api_key' => $this->getAdminSttApiKey(),
+ 'stt_basic_user' => $this->getAdminSttBasicUser(),
+ 'stt_basic_password' => $this->getAdminSttBasicPassword(),
+ 'stt_use_basic_auth' => $this->getAdminSttUseBasicAuth(),
+ 'stt_request_timeout' => $this->getSttRequestTimeout(),
+
+ 'tts_url' => $this->getTtsUrl(),
+ 'tts_service_name' => $this->getTtsServiceName(),
+ 'tts_api_key' => $this->getAdminTtsApiKey(),
+ 'tts_basic_user' => $this->getAdminTtsBasicUser(),
+ 'tts_basic_password' => $this->getAdminTtsBasicPassword(),
+ 'tts_use_basic_auth' => $this->getAdminTtsUseBasicAuth(),
+ 'tts_request_timeout' => $this->getTtsRequestTimeout(),
];
}
@@ -801,6 +996,191 @@ public function setAdminTtsVoices(array $voices): void {
$this->invalidateModelsCache();
}
+ /**
+ * @param string $url
+ * @return void
+ * @throws Exception
+ */
+ public function setImageUrl(string $url): void {
+ if ($url !== '' && !filter_var($url, FILTER_VALIDATE_URL)) {
+ throw new Exception('Invalid image service URL');
+ }
+ $this->appConfig->setValueString(Application::APP_ID, 'image_url', $url, lazy: true);
+ }
+
+ /**
+ * @param string $name
+ * @return void
+ */
+ public function setImageServiceName(string $name): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'image_service_name', $name, lazy: true);
+ }
+
+ /**
+ * @param string $apiKey
+ * @return void
+ */
+ public function setAdminImageApiKey(string $apiKey): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'image_api_key', $apiKey, true, true);
+ }
+
+ /**
+ * @param string $user
+ * @return void
+ */
+ public function setAdminImageBasicUser(string $user): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'image_basic_user', $user, lazy: true);
+ }
+
+ /**
+ * @param string $password
+ * @return void
+ */
+ public function setAdminImageBasicPassword(string $password): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'image_basic_password', $password, true, true);
+ }
+
+ /**
+ * @param bool $use
+ * @return void
+ */
+ public function setAdminImageUseBasicAuth(bool $use): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'image_use_basic_auth', $use ? '1' : '0', lazy: true);
+ }
+
+ /**
+ * @param int $requestTimeout
+ * @return void
+ */
+ public function setImageRequestTimeout(int $requestTimeout): void {
+ // Validate input:
+ $requestTimeout = max(1, $requestTimeout);
+ $this->appConfig->setValueString(Application::APP_ID, 'image_request_timeout', strval($requestTimeout), lazy: true);
+ }
+ /**
+ * @param string $url
+ * @return void
+ * @throws Exception
+ */
+ public function setSttUrl(string $url): void {
+ if ($url !== '' && !filter_var($url, FILTER_VALIDATE_URL)) {
+ throw new Exception('Invalid STT service URL');
+ }
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_url', $url, lazy: true);
+ }
+
+ /**
+ * @param string $name
+ * @return void
+ */
+ public function setSttServiceName(string $name): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_service_name', $name, lazy: true);
+ }
+
+ /**
+ * @param string $apiKey
+ * @return void
+ */
+ public function setAdminSttApiKey(string $apiKey): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_api_key', $apiKey, true, true);
+ }
+
+ /**
+ * @param string $user
+ * @return void
+ */
+ public function setAdminSttBasicUser(string $user): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_basic_user', $user, lazy: true);
+ }
+
+ /**
+ * @param string $password
+ * @return void
+ */
+ public function setAdminSttBasicPassword(string $password): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_basic_password', $password, true, true);
+ }
+
+ /**
+ * @param bool $use
+ * @return void
+ */
+ public function setAdminSttUseBasicAuth(bool $use): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_use_basic_auth', $use ? '1' : '0', lazy: true);
+ }
+
+ /**
+ * @param int $requestTimeout
+ * @return void
+ */
+ public function setSttRequestTimeout(int $requestTimeout): void {
+ // Validate input:
+ $requestTimeout = max(1, $requestTimeout);
+ $this->appConfig->setValueString(Application::APP_ID, 'stt_request_timeout', strval($requestTimeout), lazy: true);
+ }
+
+ /**
+ * @param string $url
+ * @return void
+ * @throws Exception
+ */
+ public function setTtsUrl(string $url): void {
+ if ($url !== '' && !filter_var($url, FILTER_VALIDATE_URL)) {
+ throw new Exception('Invalid TTS service URL');
+ }
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_url', $url, lazy: true);
+ }
+
+ /**
+ * @param string $name
+ * @return void
+ */
+ public function setTtsServiceName(string $name): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_service_name', $name, lazy: true);
+ }
+
+ /**
+ * @param string $apiKey
+ * @return void
+ */
+ public function setAdminTtsApiKey(string $apiKey): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_api_key', $apiKey, true, true);
+ }
+
+ /**
+ * @param string $user
+ * @return void
+ */
+ public function setAdminTtsBasicUser(string $user): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_basic_user', $user, lazy: true);
+ }
+
+ /**
+ * @param string $password
+ * @return void
+ */
+ public function setAdminTtsBasicPassword(string $password): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_basic_password', $password, true, true);
+ }
+
+ /**
+ * @param bool $use
+ * @return void
+ */
+ public function setAdminTtsUseBasicAuth(bool $use): void {
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_use_basic_auth', $use ? '1' : '0', lazy: true);
+ }
+
+ /**
+ * @param int $requestTimeout
+ * @return void
+ */
+ public function setTtsRequestTimeout(int $requestTimeout): void {
+ // Validate input:
+ $requestTimeout = max(1, $requestTimeout);
+ $this->appConfig->setValueString(Application::APP_ID, 'tts_request_timeout', strval($requestTimeout), lazy: true);
+ }
+
/**
* Set the admin config for the settings page
* @param mixed[] $adminConfig
@@ -909,6 +1289,81 @@ public function setAdminConfig(array $adminConfig): void {
if (isset($adminConfig['tts_voices'])) {
$this->setAdminTtsVoices($adminConfig['tts_voices']);
}
+
+ if (isset($adminConfig['image_url'])) {
+ if (str_ends_with($adminConfig['image_url'], '/')) {
+ $adminConfig['image_url'] = substr($adminConfig['image_url'], 0, -1) ?: $adminConfig['image_url'];
+ }
+ $this->setImageUrl($adminConfig['image_url']);
+ }
+ if (isset($adminConfig['image_service_name'])) {
+ $this->setImageServiceName($adminConfig['image_service_name']);
+ }
+ if (isset($adminConfig['image_api_key'])) {
+ $this->setAdminImageApiKey($adminConfig['image_api_key']);
+ }
+ if (isset($adminConfig['image_basic_user'])) {
+ $this->setAdminImageBasicUser($adminConfig['image_basic_user']);
+ }
+ if (isset($adminConfig['image_basic_password'])) {
+ $this->setAdminImageBasicPassword($adminConfig['image_basic_password']);
+ }
+ if (isset($adminConfig['image_use_basic_auth'])) {
+ $this->setAdminImageUseBasicAuth($adminConfig['image_use_basic_auth']);
+ }
+ if (isset($adminConfig['image_request_timeout'])) {
+ $this->setImageRequestTimeout($adminConfig['image_request_timeout']);
+ }
+
+ if (isset($adminConfig['stt_url'])) {
+ if (str_ends_with($adminConfig['stt_url'], '/')) {
+ $adminConfig['stt_url'] = substr($adminConfig['stt_url'], 0, -1) ?: $adminConfig['stt_url'];
+ }
+ $this->setSttUrl($adminConfig['stt_url']);
+ }
+ if (isset($adminConfig['stt_service_name'])) {
+ $this->setSttServiceName($adminConfig['stt_service_name']);
+ }
+ if (isset($adminConfig['stt_api_key'])) {
+ $this->setAdminSttApiKey($adminConfig['stt_api_key']);
+ }
+ if (isset($adminConfig['stt_basic_user'])) {
+ $this->setAdminSttBasicUser($adminConfig['stt_basic_user']);
+ }
+ if (isset($adminConfig['stt_basic_password'])) {
+ $this->setAdminSttBasicPassword($adminConfig['stt_basic_password']);
+ }
+ if (isset($adminConfig['stt_use_basic_auth'])) {
+ $this->setAdminSttUseBasicAuth($adminConfig['stt_use_basic_auth']);
+ }
+ if (isset($adminConfig['stt_request_timeout'])) {
+ $this->setSttRequestTimeout($adminConfig['stt_request_timeout']);
+ }
+
+ if (isset($adminConfig['tts_url'])) {
+ if (str_ends_with($adminConfig['tts_url'], '/')) {
+ $adminConfig['tts_url'] = substr($adminConfig['tts_url'], 0, -1) ?: $adminConfig['tts_url'];
+ }
+ $this->setTtsUrl($adminConfig['tts_url']);
+ }
+ if (isset($adminConfig['tts_service_name'])) {
+ $this->setTtsServiceName($adminConfig['tts_service_name']);
+ }
+ if (isset($adminConfig['tts_api_key'])) {
+ $this->setAdminTtsApiKey($adminConfig['tts_api_key']);
+ }
+ if (isset($adminConfig['tts_basic_user'])) {
+ $this->setAdminTtsBasicUser($adminConfig['tts_basic_user']);
+ }
+ if (isset($adminConfig['tts_basic_password'])) {
+ $this->setAdminTtsBasicPassword($adminConfig['tts_basic_password']);
+ }
+ if (isset($adminConfig['tts_use_basic_auth'])) {
+ $this->setAdminTtsUseBasicAuth($adminConfig['tts_use_basic_auth']);
+ }
+ if (isset($adminConfig['tts_request_timeout'])) {
+ $this->setTtsRequestTimeout($adminConfig['tts_request_timeout']);
+ }
}
/**
@@ -1010,4 +1465,25 @@ public function setAnalyzeImageProviderEnabled(bool $enabled): void {
public function setChatEndpointEnabled(bool $enabled): void {
$this->appConfig->setValueString(Application::APP_ID, 'chat_endpoint_enabled', $enabled ? '1' : '0', lazy: true);
}
+
+ /**
+ * @return bool
+ */
+ public function imageOverrideEnabled(): bool {
+ return !empty($this->getImageUrl());
+ }
+
+ /**
+ * @return bool
+ */
+ public function sttOverrideEnabled(): bool {
+ return !empty($this->getSttUrl());
+ }
+
+ /**
+ * @return bool
+ */
+ public function ttsOverrideEnabled(): bool {
+ return !empty($this->getTtsUrl());
+ }
}
diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php
index 05c3442e..af3b8b2d 100644
--- a/lib/Settings/Admin.php
+++ b/lib/Settings/Admin.php
@@ -31,6 +31,12 @@ public function getForm(): TemplateResponse {
$adminConfig = $this->openAiSettingsService->getAdminConfig();
$adminConfig['api_key'] = $adminConfig['api_key'] === '' ? '' : 'dummyApiKey';
$adminConfig['basic_password'] = $adminConfig['basic_password'] === '' ? '' : 'dummyPassword';
+ $adminConfig['image_api_key'] = $adminConfig['image_api_key'] === '' ? '' : 'dummyApiKey';
+ $adminConfig['image_basic_password'] = $adminConfig['image_basic_password'] === '' ? '' : 'dummyPassword';
+ $adminConfig['stt_api_key'] = $adminConfig['stt_api_key'] === '' ? '' : 'dummyApiKey';
+ $adminConfig['stt_basic_password'] = $adminConfig['stt_basic_password'] === '' ? '' : 'dummyPassword';
+ $adminConfig['tts_api_key'] = $adminConfig['tts_api_key'] === '' ? '' : 'dummyApiKey';
+ $adminConfig['tts_basic_password'] = $adminConfig['tts_basic_password'] === '' ? '' : 'dummyPassword';
$isAssistantEnabled = $this->appManager->isEnabledForUser('assistant');
$adminConfig['assistant_enabled'] = $isAssistantEnabled;
$adminConfig['quota_start_date'] = $this->openAiSettingsService->getQuotaStart();
diff --git a/lib/TaskProcessing/AudioToTextProvider.php b/lib/TaskProcessing/AudioToTextProvider.php
index 2f0d9fc9..3cc15d24 100644
--- a/lib/TaskProcessing/AudioToTextProvider.php
+++ b/lib/TaskProcessing/AudioToTextProvider.php
@@ -38,7 +38,7 @@ public function getId(): string {
}
public function getName(): string {
- return $this->openAiAPIService->getServiceName();
+ return $this->openAiAPIService->getServiceName('stt');
}
public function getTaskTypeId(): string {
diff --git a/lib/TaskProcessing/TextToImageProvider.php b/lib/TaskProcessing/TextToImageProvider.php
index dd4c7011..e6bd61a0 100644
--- a/lib/TaskProcessing/TextToImageProvider.php
+++ b/lib/TaskProcessing/TextToImageProvider.php
@@ -40,9 +40,7 @@ public function getId(): string {
}
public function getName(): string {
- return $this->openAiAPIService->isUsingOpenAi()
- ? $this->l->t('OpenAI\'s DALL-E 2')
- : $this->openAiAPIService->getServiceName();
+ return $this->openAiAPIService->getServiceName('image');
}
public function getTaskTypeId(): string {
@@ -81,12 +79,12 @@ public function getOptionalInputShape(): array {
public function getOptionalInputShapeEnumValues(): array {
return [
- 'model' => $this->openAiAPIService->getModelEnumValues($this->userId),
+ 'model' => $this->openAiAPIService->getModelEnumValues($this->userId, serviceType: 'image'),
];
}
public function getOptionalInputShapeDefaults(): array {
- $adminModel = $this->openAiAPIService->isUsingOpenAi()
+ $adminModel = $this->openAiAPIService->isUsingOpenAi('image')
? ($this->appConfig->getValueString(Application::APP_ID, 'default_image_model_id', Application::DEFAULT_MODEL_ID, lazy: true) ?: Application::DEFAULT_MODEL_ID)
: $this->appConfig->getValueString(Application::APP_ID, 'default_image_model_id', lazy: true);
return [
diff --git a/lib/TaskProcessing/TextToSpeechProvider.php b/lib/TaskProcessing/TextToSpeechProvider.php
index b02d2e69..04a32405 100644
--- a/lib/TaskProcessing/TextToSpeechProvider.php
+++ b/lib/TaskProcessing/TextToSpeechProvider.php
@@ -38,9 +38,7 @@ public function getId(): string {
}
public function getName(): string {
- return $this->openAiAPIService->isUsingOpenAi()
- ? $this->l->t('OpenAI\'s Text to Speech')
- : $this->openAiAPIService->getServiceName();
+ return $this->openAiAPIService->getServiceName('stt');
}
public function getTaskTypeId(): string {
@@ -77,7 +75,7 @@ public function getOptionalInputShape(): array {
),
'speed' => new ShapeDescriptor(
$this->l->t('Speed'),
- $this->openAiAPIService->isUsingOpenAi()
+ $this->openAiAPIService->isUsingOpenAi('stt')
? $this->l->t('Speech speed modifier (Valid values: 0.25-4)')
: $this->l->t('Speech speed modifier'),
EShapeType::Number
@@ -89,7 +87,7 @@ public function getOptionalInputShapeEnumValues(): array {
$voices = json_decode($this->appConfig->getValueString(Application::APP_ID, 'tts_voices', lazy: true)) ?: Application::DEFAULT_SPEECH_VOICES;
return [
'voice' => array_map(function ($v) { return new ShapeEnumValue($v, $v); }, $voices),
- 'model' => $this->openAiAPIService->getModelEnumValues($this->userId),
+ 'model' => $this->openAiAPIService->getModelEnumValues($this->userId, 'tts'),
];
}
@@ -143,7 +141,7 @@ public function process(?string $userId, array $input, callable $reportProgress,
$speed = 1;
if (isset($input['speed']) && is_numeric($input['speed'])) {
$speed = $input['speed'];
- if ($this->openAiAPIService->isUsingOpenAi()) {
+ if ($this->openAiAPIService->isUsingOpenAi('stt')) {
if ($speed > 4) {
$speed = 4;
} elseif ($speed < 0.25) {
diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue
index da93ea1f..edc1a252 100644
--- a/src/components/AdminSettings.vue
+++ b/src/components/AdminSettings.vue
@@ -16,6 +16,18 @@
{{ t('integration_openai', 'Assistant app') }}
+