+
+
+ @if (title) {
+
+ }
+
+
+
+
+ @if (showReveal) {
+
+ }
+
+
+ {{error}}
+
+ @if (hint) {
+
}
-
- {{error}}
-
- @if (hint) {
-
- }
diff --git a/src-ui/src/app/data/paperless-config.ts b/src-ui/src/app/data/paperless-config.ts
index 0c309c7d2..96e4da924 100644
--- a/src-ui/src/app/data/paperless-config.ts
+++ b/src-ui/src/app/data/paperless-config.ts
@@ -44,6 +44,7 @@ export enum ConfigOptionType {
Boolean = 'boolean',
JSON = 'json',
File = 'file',
+ Password = 'password',
}
export const ConfigCategory = {
@@ -52,6 +53,11 @@ export const ConfigCategory = {
AI: $localize`AI Settings`,
}
+export const LLMBackendConfig = {
+ OPENAI: 'openai',
+ OLLAMA: 'ollama',
+}
+
export interface ConfigOption {
key: string
title: string
@@ -191,7 +197,8 @@ export const PaperlessConfigOptions: ConfigOption[] = [
{
key: 'llm_backend',
title: $localize`LLM Backend`,
- type: ConfigOptionType.String,
+ type: ConfigOptionType.Select,
+ choices: mapToItems(LLMBackendConfig),
config_key: 'PAPERLESS_LLM_BACKEND',
category: ConfigCategory.AI,
},
@@ -205,7 +212,7 @@ export const PaperlessConfigOptions: ConfigOption[] = [
{
key: 'llm_api_key',
title: $localize`LLM API Key`,
- type: ConfigOptionType.String,
+ type: ConfigOptionType.Password,
config_key: 'PAPERLESS_LLM_API_KEY',
category: ConfigCategory.AI,
},
diff --git a/src/documents/tests/test_api_app_config.py b/src/documents/tests/test_api_app_config.py
index 0e298545c..25d18e140 100644
--- a/src/documents/tests/test_api_app_config.py
+++ b/src/documents/tests/test_api_app_config.py
@@ -32,33 +32,31 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.maxDiff = None
- self.assertEqual(
- json.dumps(response.data[0]),
- json.dumps(
- {
- "id": 1,
- "user_args": None,
- "output_type": None,
- "pages": None,
- "language": None,
- "mode": None,
- "skip_archive_file": None,
- "image_dpi": None,
- "unpaper_clean": None,
- "deskew": None,
- "rotate_pages": None,
- "rotate_pages_threshold": None,
- "max_image_pixels": None,
- "color_conversion_strategy": None,
- "app_title": None,
- "app_logo": None,
- "ai_enabled": False,
- "llm_backend": None,
- "llm_model": None,
- "llm_api_key": None,
- "llm_url": None,
- },
- ),
+ self.assertDictEqual(
+ response.data[0],
+ {
+ "id": 1,
+ "user_args": None,
+ "output_type": None,
+ "pages": None,
+ "language": None,
+ "mode": None,
+ "skip_archive_file": None,
+ "image_dpi": None,
+ "unpaper_clean": None,
+ "deskew": None,
+ "rotate_pages": None,
+ "rotate_pages_threshold": None,
+ "max_image_pixels": None,
+ "color_conversion_strategy": None,
+ "app_title": None,
+ "app_logo": None,
+ "ai_enabled": False,
+ "llm_backend": None,
+ "llm_model": None,
+ "llm_api_key": None,
+ "llm_url": None,
+ },
)
def test_api_get_ui_settings_with_config(self):
diff --git a/src/paperless/serialisers.py b/src/paperless/serialisers.py
index 461eef587..4ff9ceb46 100644
--- a/src/paperless/serialisers.py
+++ b/src/paperless/serialisers.py
@@ -185,6 +185,10 @@ class ProfileSerializer(serializers.ModelSerializer):
class ApplicationConfigurationSerializer(serializers.ModelSerializer):
user_args = serializers.JSONField(binary=True, allow_null=True)
+ llm_api_key = ObfuscatedPasswordField(
+ required=False,
+ allow_null=True,
+ )
def run_validation(self, data):
# Empty strings treated as None to avoid unexpected behavior