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: 0 additions & 2 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ class Application extends App implements IBootstrap {
public const DEFAULT_QUOTA_PERIOD = 30;
public const MAX_QUOTA_PERIOD_DAYS = 3650;
public const MAX_QUOTA_PERIOD_MONTHS = 120;
public const DEFAULT_SUMMARY_SYSTEM_PROMPT = 'You are a helpful assistant that summarizes text in the same language as the text. '
. 'You should only return the summary without any additional information.';
public const DEFAULT_QUOTA_CONFIG = ['length' => self::DEFAULT_QUOTA_PERIOD, 'unit' => 'day', 'day' => 1];

public const DEFAULT_OPENAI_TEXT_GENERATION_TIME = 10; // seconds
Expand Down
29 changes: 1 addition & 28 deletions lib/Service/OpenAiSettingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class OpenAiSettingsService {
private const ADMIN_CONFIG_TYPES = [
'quota_period' => 'array',
'usage_storage_time' => 'integer',
'summary_system_prompt' => 'string',
];

private const USER_CONFIG_TYPES = [
Expand Down Expand Up @@ -136,19 +135,6 @@ public function getUsageStorageTime(): int {
return $this->appConfig->getValueInt(Application::APP_ID, 'usage_storage_time', Application::DEFAULT_QUOTA_PERIOD, lazy: true);
}

/**
* System prompt for the summary provider. Empty falls back to the default unless $raw is true.
*/
public function getSummarySystemPrompt(bool $raw = false): string {
$default = $raw ? '' : Application::DEFAULT_SUMMARY_SYSTEM_PROMPT;
return $this->appConfig->getValueString(
Application::APP_ID,
'summary_system_prompt',
$default,
lazy: true
) ?: $default;
}

/**
* @param string|null $userId
* @return string
Expand All @@ -160,13 +146,12 @@ public function getUserSTTLanguage(?string $userId): string {
/**
* Get the instance-wide admin config for the settings page
*
* @return array{quota_period: array, usage_storage_time: int, summary_system_prompt: string}
* @return array{quota_period: array, usage_storage_time: int}
*/
public function getAdminConfig(): array {
return [
'quota_period' => $this->getQuotaPeriod(),
'usage_storage_time' => $this->getUsageStorageTime(),
'summary_system_prompt' => $this->getSummarySystemPrompt(true),
];
}

Expand Down Expand Up @@ -233,15 +218,6 @@ public function setUsageStorageTime(int $usageStorageTime): void {
$this->appConfig->setValueInt(Application::APP_ID, 'usage_storage_time', $usageStorageTime, lazy: true);
}

public function setSummarySystemPrompt(string $summarySystemPrompt): void {
$this->appConfig->setValueString(
Application::APP_ID,
'summary_system_prompt',
$summarySystemPrompt,
lazy: true
);
}

/**
* @param string $userId
* @param string $language
Expand Down Expand Up @@ -274,9 +250,6 @@ public function setAdminConfig(array $adminConfig): void {
if (isset($adminConfig['usage_storage_time'])) {
$this->setUsageStorageTime($adminConfig['usage_storage_time']);
}
if (isset($adminConfig['summary_system_prompt'])) {
$this->setSummarySystemPrompt($adminConfig['summary_system_prompt']);
}
}

/**
Expand Down
28 changes: 28 additions & 0 deletions lib/Service/ServiceConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class ServiceConfig implements JsonSerializable {
'llm_extra_params' => 'string',
'max_tokens' => 'integer',
'chunk_size' => 'integer',
'system_prompt_summary' => 'string',
'system_prompt_translate' => 'string',
'multimodal_image_enabled' => 'boolean',
'multimodal_audio_enabled' => 'boolean',
'multimodal_video_enabled' => 'boolean',
Expand Down Expand Up @@ -83,6 +85,8 @@ public function __construct(
private string $llmExtraParams = '',
private int $maxTokens = Application::DEFAULT_MAX_NUM_OF_TOKENS,
private int $chunkSize = Application::DEFAULT_CHUNK_SIZE,
private string $systemPromptSummary = '',
private string $systemPromptTranslate = '',
// these mirror the defaults of the single-service configuration, so
// that a migrated service and a newly connected one accept the same
// kinds of attachment
Expand Down Expand Up @@ -150,6 +154,10 @@ public function with(array $values): self {
break;
case 'chunk_size': $new->chunkSize = (int)$value === 0 ? 0 : max(Application::MIN_CHUNK_SIZE, (int)$value);
break;
case 'system_prompt_summary': $new->systemPromptSummary = (string)$value;
break;
case 'system_prompt_translate': $new->systemPromptTranslate = (string)$value;
break;
case 'multimodal_image_enabled': $new->multimodalImageEnabled = (bool)$value;
break;
case 'multimodal_audio_enabled': $new->multimodalAudioEnabled = (bool)$value;
Expand Down Expand Up @@ -349,6 +357,24 @@ public function getChunkSize(): int {
return $this->chunkSize;
}

/**
* The admin-configured fallback system prompt for the summary task type.
* An empty string means the built-in default prompt is used.
*/
public function getSystemPromptSummary(): string {
return $this->systemPromptSummary;
}

/**
* The admin-configured system prompt appended to the built-in translation
* prompt for the translation task type. The built-in prompt is always kept,
* as it enforces the expected JSON response format.
* An empty string means only the built-in prompt is used.
*/
public function getSystemPromptTranslate(): string {
return $this->systemPromptTranslate;
}

public function getMultimodalImageEnabled(): bool {
return $this->multimodalImageEnabled;
}
Expand Down Expand Up @@ -466,6 +492,8 @@ public function jsonSerialize(): array {
'llm_extra_params' => $this->llmExtraParams,
'max_tokens' => $this->maxTokens,
'chunk_size' => $this->chunkSize,
'system_prompt_summary' => $this->systemPromptSummary,
'system_prompt_translate' => $this->systemPromptTranslate,
'multimodal_image_enabled' => $this->multimodalImageEnabled,
'multimodal_audio_enabled' => $this->multimodalAudioEnabled,
'multimodal_video_enabled' => $this->multimodalVideoEnabled,
Expand Down
10 changes: 8 additions & 2 deletions lib/Service/TranslateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ public function translate(
$promptStart = 'Translate the following text to ' . $toLanguage . ': ';
}

$systemPrompt = self::SYSTEM_PROMPT;
$adminSystemPrompt = $service->getSystemPromptTranslate();
if ($adminSystemPrompt !== '') {
$systemPrompt .= PHP_EOL . $adminSystemPrompt;
}

$cache = $this->cacheFactory->createDistributed('integration_openai');
foreach ($chunks as $chunk) {
$progress += $increase;
Expand All @@ -105,12 +111,12 @@ public function translate(

if ($service->isUsingOpenAi() || $service->getChatEndpointEnabled()) {
$completionsObj = $this->openAiAPIService->createChatCompletion(
$userId, $service, $model, $prompt, TranslateService::SYSTEM_PROMPT, null, 1, $maxTokens, TranslateService::JSON_RESPONSE_FORMAT
$userId, $service, $model, $prompt, $systemPrompt, null, 1, $maxTokens, TranslateService::JSON_RESPONSE_FORMAT
);
$completions = $completionsObj['messages'];
} else {
$completions = $this->openAiAPIService->createCompletion(
$userId, $service, $prompt . PHP_EOL . TranslateService::SYSTEM_PROMPT . PHP_EOL . PHP_EOL, 1, $model, $maxTokens
$userId, $service, $prompt . PHP_EOL . $systemPrompt . PHP_EOL . PHP_EOL, 1, $model, $maxTokens
);
}

Expand Down
4 changes: 1 addition & 3 deletions lib/TaskProcessing/ProviderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use OCA\OpenAi\AppInfo\Application;
use OCA\OpenAi\Service\ChunkService;
use OCA\OpenAi\Service\OpenAiAPIService;
use OCA\OpenAi\Service\OpenAiSettingsService;
use OCA\OpenAi\Service\ServiceConfig;
use OCA\OpenAi\Service\ServicesService;
use OCA\OpenAi\Service\TranslateService;
Expand All @@ -36,7 +35,6 @@ class ProviderFactory {
public function __construct(
private ServicesService $servicesService,
private OpenAiAPIService $openAiAPIService,
private OpenAiSettingsService $openAiSettingsService,
private ChunkService $chunkService,
private TranslateService $translateService,
private WatermarkingService $watermarkingService,
Expand Down Expand Up @@ -82,7 +80,7 @@ private function getTextProviders(ServiceConfig $service, string $model): array
new TextToTextProvider($this->openAiAPIService, $this->l, $service, $model),
new TextToTextChatProvider($this->openAiAPIService, $this->l, $service, $model),
new TextToTextChatWithToolsProvider($this->openAiAPIService, $this->l, $service, $model),
new SummaryProvider($this->openAiAPIService, $this->l, $this->chunkService, $this->openAiSettingsService, $service, $model),
new SummaryProvider($this->openAiAPIService, $this->l, $this->chunkService, $service, $model),
new HeadlineProvider($this->openAiAPIService, $this->l, $service, $model),
new TopicsProvider($this->openAiAPIService, $this->l, $this->chunkService, $this->logger, $service, $model),
new ContextWriteProvider($this->openAiAPIService, $this->chunkService, $this->l, $service, $model),
Expand Down
54 changes: 38 additions & 16 deletions lib/TaskProcessing/SummaryProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

use OCA\OpenAi\Service\ChunkService;
use OCA\OpenAi\Service\OpenAiAPIService;
use OCA\OpenAi\Service\OpenAiSettingsService;
use OCA\OpenAi\Service\ServiceConfig;
use OCP\IL10N;
use OCP\TaskProcessing\EShapeType;
Expand All @@ -25,11 +24,13 @@
class SummaryProvider implements ISynchronousProvider {
use ProviderIdentity;

public const DEFAULT_SYSTEM_PROMPT = 'You are a helpful assistant that summarizes text in the same language as the text. '
. 'You should only return the summary without any additional information. ';

public function __construct(
private OpenAiAPIService $openAiAPIService,
private IL10N $l,
private ChunkService $chunkService,
private OpenAiSettingsService $openAiSettingsService,
private ServiceConfig $service,
private string $model,
) {
Expand Down Expand Up @@ -76,6 +77,11 @@ public function getOptionalInputShape(): array {
$this->l->t('The maximum number of words/tokens that can be generated in the completion.'),
EShapeType::Number
),
'system_prompt_summary' => new ShapeDescriptor(
$this->l->t('Summary system prompt'),
$this->l->t('Summary system prompt. When set, it overrides the default prompt and the Format and Complexity options are ignored.'),
EShapeType::Text
),
];
}

Expand All @@ -100,6 +106,7 @@ public function getOptionalInputShapeDefaults(): array {
'max_tokens' => $this->service->getMaxTokens(),
'format' => 'auto',
'complexity' => 'medium',
'system_prompt_summary' => '',
];
}

Expand Down Expand Up @@ -144,21 +151,36 @@ public function process(?string $userId, array $input, callable $reportProgress)

try {
$completions = [];
$summarySystemPrompt = $this->openAiSettingsService->getSummarySystemPrompt() . ' ';
if (isset($input['format'])) {
if ($input['format'] === 'paragraph') {
$summarySystemPrompt .= 'Return the summary as a paragraph. ';
} elseif ($input['format'] === 'bullet_points') {
$summarySystemPrompt .= 'Return the summary as a list of bullet points. ';
} elseif ($input['format'] === 'sentence') {
$summarySystemPrompt .= 'Return the summary as a single sentence. Do not include more than one sentence. ';
$customSystemPrompt = isset($input['system_prompt_summary']) && is_string($input['system_prompt_summary'])
? trim($input['system_prompt_summary'])
: '';
if ($customSystemPrompt !== '') {
// A user provided prompt overrides the others; format and complexity are ignored
$summarySystemPrompt = $customSystemPrompt . ' ';
} else {
// Fallback to the admin-configured prompt, then to default. Format and complexity appended
$summarySystemPrompt = $this->service->getSystemPromptSummary();
if ($summarySystemPrompt === '') {
$summarySystemPrompt = self::DEFAULT_SYSTEM_PROMPT;
} else {
$summarySystemPrompt .= ' ';
}
}
if (isset($input['complexity'])) {
if ($input['complexity'] === 'complex') {
$summarySystemPrompt .= 'Use complex language and vocabulary appropriate for an expert in the subject. ';
} elseif ($input['complexity'] === 'simple') {
$summarySystemPrompt .= 'Use simple language and vocabulary appropriate for a 5 year old. ';

if (isset($input['format'])) {
if ($input['format'] === 'paragraph') {
$summarySystemPrompt .= 'Return the summary as a paragraph. ';
} elseif ($input['format'] === 'bullet_points') {
$summarySystemPrompt .= 'Return the summary as a list of bullet points. ';
} elseif ($input['format'] === 'sentence') {
$summarySystemPrompt .= 'Return the summary as a single sentence. Do not include more than one sentence. ';
}
}
if (isset($input['complexity'])) {
if ($input['complexity'] === 'complex') {
$summarySystemPrompt .= 'Use complex language and vocabulary appropriate for an expert in the subject. ';
} elseif ($input['complexity'] === 'simple') {
$summarySystemPrompt .= 'Use simple language and vocabulary appropriate for a 5 year old. ';
}
}
}
if ($this->service->isUsingOpenAi() || $this->service->getChatEndpointEnabled()) {
Expand Down
26 changes: 2 additions & 24 deletions src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,6 @@
</NcButton>
</div>

<h3>{{ t('integration_openai', 'Text generation') }}</h3>
<div class="line line--full">
<NcTextArea
id="summary-system-prompt"
v-model="state.summary_system_prompt"
class="input input--full"
:label="t('integration_openai', 'Summary system prompt')"
:helper-text="t('integration_openai', 'System prompt used when generating text summaries. Leave empty to use the default prompt.')"
:rows="5"
resize="vertical"
@update:model-value="onInput()" />
</div>

<h3>{{ t('integration_openai', 'Usage limits') }}</h3>
<div class="line">
<QuotaPeriodPicker
Expand Down Expand Up @@ -128,7 +115,6 @@ import NcInputField from '@nextcloud/vue/components/NcInputField'
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import NcSelect from '@nextcloud/vue/components/NcSelect'
import NcTextArea from '@nextcloud/vue/components/NcTextArea'

import axios from '@nextcloud/axios'
import { showError, showSuccess, showWarning } from '@nextcloud/dialogs'
Expand All @@ -155,7 +141,6 @@ export default {
NcLoadingIcon,
NcNoteCard,
NcSelect,
NcTextArea,
},

data() {
Expand Down Expand Up @@ -385,6 +370,8 @@ export default {
llm_extra_params: service.llm_extra_params,
max_tokens: parseInt(service.max_tokens) || 1,
chunk_size: parseInt(service.chunk_size) || 0,
system_prompt_summary: service.system_prompt_summary,
system_prompt_translate: service.system_prompt_translate,
multimodal_image_enabled: service.multimodal_image_enabled,
multimodal_audio_enabled: service.multimodal_audio_enabled,
multimodal_video_enabled: service.multimodal_video_enabled,
Expand Down Expand Up @@ -430,7 +417,6 @@ export default {
await this.saveAdminConfig({
quota_period: this.state.quota_period,
usage_storage_time: parseInt(this.state.usage_storage_time) || 1,
summary_system_prompt: this.state.summary_system_prompt,
})
}, 2000),
async saveAdminConfig(values) {
Expand Down Expand Up @@ -491,14 +477,6 @@ export default {
width: 300px;
}

.line--full {
width: 100%;
}

.line .input--full {
width: 100%;
}

.services {
display: flex;
flex-wrap: wrap;
Expand Down
Loading