From e20ea06c054a125bbe10cf7ab1d015e068260368 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 8 May 2026 12:48:14 -0700 Subject: [PATCH] Add URL option --- src-ui/src/app/data/paperless-config.ts | 8 ++++++++ src/documents/tests/test_api_app_config.py | 17 +++++++++++++++++ src/paperless/config.py | 4 ++++ ...cationconfiguration_llm_embedding_backend.py | 10 ++++++++++ src/paperless/models.py | 7 +++++++ src/paperless/settings/__init__.py | 1 + 6 files changed, 47 insertions(+) diff --git a/src-ui/src/app/data/paperless-config.ts b/src-ui/src/app/data/paperless-config.ts index a2fb4f411..52061dd18 100644 --- a/src-ui/src/app/data/paperless-config.ts +++ b/src-ui/src/app/data/paperless-config.ts @@ -302,6 +302,13 @@ export const PaperlessConfigOptions: ConfigOption[] = [ config_key: 'PAPERLESS_AI_LLM_EMBEDDING_MODEL', category: ConfigCategory.AI, }, + { + key: 'llm_embedding_endpoint', + title: $localize`LLM Embedding Endpoint`, + type: ConfigOptionType.String, + config_key: 'PAPERLESS_AI_LLM_EMBEDDING_ENDPOINT', + category: ConfigCategory.AI, + }, { key: 'llm_backend', title: $localize`LLM Backend`, @@ -364,6 +371,7 @@ export interface PaperlessConfig extends ObjectWithId { ai_enabled: boolean llm_embedding_backend: string llm_embedding_model: string + llm_embedding_endpoint: string llm_backend: string llm_model: string llm_api_key: string diff --git a/src/documents/tests/test_api_app_config.py b/src/documents/tests/test_api_app_config.py index ec1f45391..3372a16eb 100644 --- a/src/documents/tests/test_api_app_config.py +++ b/src/documents/tests/test_api_app_config.py @@ -74,6 +74,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase): "ai_enabled": False, "llm_embedding_backend": None, "llm_embedding_model": None, + "llm_embedding_endpoint": None, "llm_backend": None, "llm_model": None, "llm_api_key": None, @@ -868,3 +869,19 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase): ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn("non-public address", str(response.data).lower()) + + @override_settings(LLM_ALLOW_INTERNAL_ENDPOINTS=False) + def test_update_llm_embedding_endpoint_blocks_internal_endpoint_when_disallowed( + self, + ) -> None: + response = self.client.patch( + f"{self.ENDPOINT}1/", + json.dumps( + { + "llm_embedding_endpoint": "http://127.0.0.1:11434", + }, + ), + content_type="application/json", + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("non-public address", str(response.data).lower()) diff --git a/src/paperless/config.py b/src/paperless/config.py index 5204b677b..f4ade5ffe 100644 --- a/src/paperless/config.py +++ b/src/paperless/config.py @@ -194,6 +194,7 @@ class AIConfig(BaseConfig): ai_enabled: bool = dataclasses.field(init=False) llm_embedding_backend: str = dataclasses.field(init=False) llm_embedding_model: str = dataclasses.field(init=False) + llm_embedding_endpoint: str = dataclasses.field(init=False) llm_backend: str = dataclasses.field(init=False) llm_model: str = dataclasses.field(init=False) llm_api_key: str = dataclasses.field(init=False) @@ -210,6 +211,9 @@ class AIConfig(BaseConfig): self.llm_embedding_model = ( app_config.llm_embedding_model or settings.LLM_EMBEDDING_MODEL ) + self.llm_embedding_endpoint = ( + app_config.llm_embedding_endpoint or settings.LLM_EMBEDDING_ENDPOINT + ) self.llm_backend = app_config.llm_backend or settings.LLM_BACKEND self.llm_model = app_config.llm_model or settings.LLM_MODEL self.llm_api_key = app_config.llm_api_key or settings.LLM_API_KEY diff --git a/src/paperless/migrations/0010_alter_applicationconfiguration_llm_embedding_backend.py b/src/paperless/migrations/0010_alter_applicationconfiguration_llm_embedding_backend.py index c8d11f7b7..f7c64c505 100644 --- a/src/paperless/migrations/0010_alter_applicationconfiguration_llm_embedding_backend.py +++ b/src/paperless/migrations/0010_alter_applicationconfiguration_llm_embedding_backend.py @@ -25,4 +25,14 @@ class Migration(migrations.Migration): verbose_name="Sets the LLM embedding backend", ), ), + migrations.AddField( + model_name="applicationconfiguration", + name="llm_embedding_endpoint", + field=models.CharField( + blank=True, + max_length=256, + null=True, + verbose_name="Sets the LLM embedding endpoint, optional", + ), + ), ] diff --git a/src/paperless/models.py b/src/paperless/models.py index 1cd8cc513..95e52426e 100644 --- a/src/paperless/models.py +++ b/src/paperless/models.py @@ -311,6 +311,13 @@ class ApplicationConfiguration(AbstractSingletonModel): max_length=128, ) + llm_embedding_endpoint = models.CharField( + verbose_name=_("Sets the LLM embedding endpoint, optional"), + blank=True, + null=True, + max_length=256, + ) + llm_backend = models.CharField( verbose_name=_("Sets the LLM backend"), blank=True, diff --git a/src/paperless/settings/__init__.py b/src/paperless/settings/__init__.py index 47ee44bac..d021cffbb 100644 --- a/src/paperless/settings/__init__.py +++ b/src/paperless/settings/__init__.py @@ -1180,6 +1180,7 @@ LLM_EMBEDDING_BACKEND = os.getenv( "PAPERLESS_AI_LLM_EMBEDDING_BACKEND", ) # "huggingface", "openai-like", or "ollama" LLM_EMBEDDING_MODEL = os.getenv("PAPERLESS_AI_LLM_EMBEDDING_MODEL") +LLM_EMBEDDING_ENDPOINT = os.getenv("PAPERLESS_AI_LLM_EMBEDDING_ENDPOINT") LLM_BACKEND = os.getenv("PAPERLESS_AI_LLM_BACKEND") # "ollama" or "openai-like" LLM_MODEL = os.getenv("PAPERLESS_AI_LLM_MODEL") LLM_API_KEY = os.getenv("PAPERLESS_AI_LLM_API_KEY")