Skip to content

Commit

Permalink
add new admin setting to choose transcription model, enforce whisper …
Browse files Browse the repository at this point in the history
…when OpenAI is used

Signed-off-by: Julien Veyssier <[email protected]>
  • Loading branch information
julien-nc committed Nov 18, 2024
1 parent 0292b2f commit 68a51de
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
6 changes: 5 additions & 1 deletion lib/Service/OpenAiAPIService.php
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,13 @@ public function transcribe(
if ($this->isQuotaExceeded($userId, Application::QUOTA_TYPE_TRANSCRIPTION)) {
throw new Exception($this->l10n->t('Audio transcription quota exceeded'), Http::STATUS_TOO_MANY_REQUESTS);
}
// enforce whisper for OpenAI
if ($this->isUsingOpenAi()) {
$model = Application::DEFAULT_TRANSCRIPTION_MODEL_ID;
}

$params = [
'model' => $model,
'model' => $model === Application::DEFAULT_MODEL_ID ? Application::DEFAULT_TRANSCRIPTION_MODEL_ID : $model,
'file' => $audioFileContent,
'response_format' => 'verbose_json',
// Verbose needed for extraction of audio duration
Expand Down
21 changes: 21 additions & 0 deletions lib/Service/OpenAiSettingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class OpenAiSettingsService {
'service_name' => 'string',
'api_key' => 'string',
'default_completion_model_id' => 'string',
'default_stt_model_id' => 'string',
'default_image_model_id' => 'string',
'default_image_size' => 'string',
'max_tokens' => 'integer',
Expand Down Expand Up @@ -109,6 +110,13 @@ public function getAdminDefaultCompletionModelId(): string {
return $this->appConfig->getValueString(Application::APP_ID, 'default_completion_model_id', Application::DEFAULT_COMPLETION_MODEL_ID) ?: Application::DEFAULT_COMPLETION_MODEL_ID;
}

/**
* @return string
*/
public function getAdminDefaultSttModelId(): string {
return $this->appConfig->getValueString(Application::APP_ID, 'default_stt_model_id') ?: Application::DEFAULT_MODEL_ID;
}

/**
* @return string
*/
Expand Down Expand Up @@ -263,6 +271,7 @@ public function getAdminConfig(): array {
'service_name' => $this->getServiceName(),
'api_key' => $this->getAdminApiKey(),
'default_completion_model_id' => $this->getAdminDefaultCompletionModelId(),
'default_stt_model_id' => $this->getAdminDefaultSttModelId(),
'default_image_model_id' => $this->getAdminDefaultImageModelId(),
'default_image_size' => $this->getAdminDefaultImageSize(),
'max_tokens' => $this->getMaxTokens(),
Expand Down Expand Up @@ -389,6 +398,15 @@ public function setAdminDefaultCompletionModelId(string $defaultCompletionModelI
$this->appConfig->setValueString(Application::APP_ID, 'default_completion_model_id', $defaultCompletionModelId);
}

/**
* @param string $defaultSttModelId
* @return void
*/
public function setAdminDefaultSttModelId(string $defaultSttModelId): void {
// No need to validate. As long as it's a string, we're happy campers
$this->appConfig->setValueString(Application::APP_ID, 'default_stt_model_id', $defaultSttModelId);
}

/**
* @param string $defaultImageModelId
* @return void
Expand Down Expand Up @@ -561,6 +579,9 @@ public function setAdminConfig(array $adminConfig): void {
if (isset($adminConfig['default_completion_model_id'])) {
$this->setAdminDefaultCompletionModelId($adminConfig['default_completion_model_id']);
}
if (isset($adminConfig['default_stt_model_id'])) {
$this->setAdminDefaultSttModelId($adminConfig['default_stt_model_id']);
}
if (isset($adminConfig['default_image_model_id'])) {
$this->setAdminDefaultImageModelId($adminConfig['default_image_model_id']);
}
Expand Down
6 changes: 5 additions & 1 deletion lib/TaskProcessing/AudioToTextProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use OCA\OpenAi\AppInfo\Application;
use OCA\OpenAi\Service\OpenAiAPIService;
use OCP\Files\File;
use OCP\IAppConfig;
use OCP\TaskProcessing\ISynchronousProvider;
use OCP\TaskProcessing\TaskTypes\AudioToText;
use Psr\Log\LoggerInterface;
Expand All @@ -18,6 +19,7 @@ class AudioToTextProvider implements ISynchronousProvider {
public function __construct(
private OpenAiAPIService $openAiAPIService,
private LoggerInterface $logger,
private IAppConfig $appConfig,
) {
}

Expand Down Expand Up @@ -75,8 +77,10 @@ public function process(?string $userId, array $input, callable $reportProgress)
}
$inputFile = $input['input'];

$model = $this->appConfig->getValueString(Application::APP_ID, 'default_stt_model_id', Application::DEFAULT_MODEL_ID) ?: Application::DEFAULT_MODEL_ID;

try {
$transcription = $this->openAiAPIService->transcribeFile($userId, $inputFile);
$transcription = $this->openAiAPIService->transcribeFile($userId, $inputFile, false, $model);
return ['output' => $transcription];
} catch (Exception $e) {
$this->logger->warning('OpenAI\'s Whisper transcription failed with: ' . $e->getMessage(), ['exception' => $e]);
Expand Down
54 changes: 54 additions & 0 deletions src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,46 @@
</NcButton>
</div>
</div>
<div>
<h2>
{{ t('integration_openai', 'Audio transcription') }}
</h2>
<div v-if="models"
class="line line-select">
<NcSelect
v-model="selectedModel.stt"
class="model-select"
:clearable="state.default_image_model_id !== DEFAULT_MODEL_ITEM.id"
:options="formattedModels"
:input-label="t('integration_openai', 'Default transcription model to use')"
:no-wrap="true"
input-id="openai-stt-model-select"
@input="onModelSelected('stt', $event)" />
<a v-if="state.url === ''"
:title="t('integration_openai', 'More information about OpenAI models')"
href="https://beta.openai.com/docs/models"
target="_blank">
<NcButton type="tertiary" aria-label="openai-info">
<template #icon>
<HelpCircleIcon />
</template>
</NcButton>
</a>
<a v-else
:title="t('integration_openai', 'More information about LocalAI models')"
href="https://localai.io/model-compatibility/index.html"
target="_blank">
<NcButton type="tertiary" aria-label="localai-info">
<template #icon>
<HelpCircleIcon />
</template>
</NcButton>
</a>
</div>
<NcNoteCard v-else type="info">
{{ t('integration_openai', 'No models to list') }}
</NcNoteCard>
</div>
<div>
<h2>
{{ t('integration_openai', 'Usage limits') }}
Expand Down Expand Up @@ -463,6 +503,7 @@ export default {
selectedModel: {
text: null,
image: null,
stt: null,
},
apiKeyUrl: 'https://platform.openai.com/account/api-keys',
quotaInfo: null,
Expand Down Expand Up @@ -540,8 +581,15 @@ export default {
|| this.models[1]
|| this.models[0]
const defaultSttModelId = this.state.default_stt_model_id || response.data?.default_stt_model_id
const sttModelToSelect = this.models.find(m => m.id === defaultSttModelId)
|| this.models.find(m => m.id.match(/whisper/i))
|| this.models[1]
|| this.models[0]
this.selectedModel.text = this.modelToNcSelectObject(completionModelToSelect)
this.selectedModel.image = this.modelToNcSelectObject(imageModelToSelect)
this.selectedModel.stt = this.modelToNcSelectObject(sttModelToSelect)
// save if url/credentials were changed OR if the values are not up-to-date in the stored settings
if (shouldSave
Expand Down Expand Up @@ -570,17 +618,23 @@ export default {
} else if (type === 'text') {
this.selectedModel.text = this.modelToNcSelectObject(DEFAULT_MODEL_ITEM)
this.state.default_completion_model_id = DEFAULT_MODEL_ITEM.id
} else if (type === 'stt') {
this.selectedModel.stt = this.modelToNcSelectObject(DEFAULT_MODEL_ITEM)
this.state.default_stt_model_id = DEFAULT_MODEL_ITEM.id
}
} else {
if (type === 'image') {
this.state.default_image_model_id = selected.id
} else if (type === 'text') {
this.state.default_completion_model_id = selected.id
} else if (type === 'stt') {
this.state.default_stt_model_id = selected.id
}
}
this.saveOptions({
default_completion_model_id: this.state.default_completion_model_id,
default_image_model_id: this.state.default_image_model_id,
default_stt_model_id: this.state.default_stt_model_id,
})
},
loadQuotaInfo() {
Expand Down

0 comments on commit 68a51de

Please sign in to comment.