mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-10 22:32:16 +02:00
Merge 6fafedca6a into aa7388f2f7
This commit is contained in:
commit
146cc7d0d6
8 changed files with 160 additions and 6 deletions
|
|
@ -48,7 +48,12 @@ ETL_SERVICE=DOCLING
|
||||||
# Local: sentence-transformers/all-MiniLM-L6-v2
|
# Local: sentence-transformers/all-MiniLM-L6-v2
|
||||||
# OpenAI: openai://text-embedding-ada-002 (set OPENAI_API_KEY below)
|
# OpenAI: openai://text-embedding-ada-002 (set OPENAI_API_KEY below)
|
||||||
# Cohere: cohere://embed-english-light-v3.0 (set COHERE_API_KEY below)
|
# Cohere: cohere://embed-english-light-v3.0 (set COHERE_API_KEY below)
|
||||||
|
# Ollama or OpenAI-compatible embedding endpoint:
|
||||||
|
# EMBEDDING_MODEL=litellm://ollama/nomic-embed-text
|
||||||
|
# EMBEDDING_BASE_URL=http://host.docker.internal:11434
|
||||||
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
|
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
|
||||||
|
# EMBEDDING_BASE_URL=
|
||||||
|
# OLLAMA_EMBEDDING_BASE_URL=
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# How You Access SurfSense
|
# How You Access SurfSense
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,10 @@ COMPOSIO_REDIRECT_URI=http://localhost:8000/api/v1/auth/composio/connector/callb
|
||||||
# # Get Cohere embeddings
|
# # Get Cohere embeddings
|
||||||
# embeddings = AutoEmbeddings.get_embeddings("cohere://embed-english-light-v3.0", api_key="...")
|
# embeddings = AutoEmbeddings.get_embeddings("cohere://embed-english-light-v3.0", api_key="...")
|
||||||
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
|
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
|
||||||
|
# Optional: use a separate endpoint for Chonkie/LiteLLM embedding models, for
|
||||||
|
# example EMBEDDING_MODEL=litellm://ollama/nomic-embed-text.
|
||||||
|
# EMBEDDING_BASE_URL=http://host.docker.internal:11434
|
||||||
|
# OLLAMA_EMBEDDING_BASE_URL=http://host.docker.internal:11434
|
||||||
|
|
||||||
# Rerankers Config
|
# Rerankers Config
|
||||||
RERANKERS_ENABLED=TRUE or FALSE(Default: FALSE)
|
RERANKERS_ENABLED=TRUE or FALSE(Default: FALSE)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@ from chonkie import AutoEmbeddings, CodeChunker, RecursiveChunker
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from rerankers import Reranker
|
from rerankers import Reranker
|
||||||
|
|
||||||
|
from app.config.embedding_settings import (
|
||||||
|
build_embedding_kwargs,
|
||||||
|
resolve_embedding_base_url,
|
||||||
|
)
|
||||||
|
|
||||||
# Get the base directory of the project
|
# Get the base directory of the project
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
|
|
||||||
|
|
@ -876,16 +881,13 @@ class Config:
|
||||||
|
|
||||||
# Chonkie Configuration | Edit this to your needs
|
# Chonkie Configuration | Edit this to your needs
|
||||||
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL")
|
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL")
|
||||||
|
EMBEDDING_BASE_URL = resolve_embedding_base_url()
|
||||||
# Azure OpenAI credentials from environment variables
|
# Azure OpenAI credentials from environment variables
|
||||||
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
|
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
|
||||||
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
|
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
|
||||||
|
|
||||||
# Pass Azure credentials to embeddings when using Azure OpenAI
|
# Pass provider-specific settings to embeddings when supported.
|
||||||
embedding_kwargs = {}
|
embedding_kwargs = build_embedding_kwargs(embedding_model=EMBEDDING_MODEL)
|
||||||
if AZURE_OPENAI_ENDPOINT:
|
|
||||||
embedding_kwargs["azure_endpoint"] = AZURE_OPENAI_ENDPOINT
|
|
||||||
if AZURE_OPENAI_API_KEY:
|
|
||||||
embedding_kwargs["azure_api_key"] = AZURE_OPENAI_API_KEY
|
|
||||||
|
|
||||||
embedding_model_instance = AutoEmbeddings.get_embeddings(
|
embedding_model_instance = AutoEmbeddings.get_embeddings(
|
||||||
EMBEDDING_MODEL,
|
EMBEDDING_MODEL,
|
||||||
|
|
|
||||||
48
surfsense_backend/app/config/embedding_settings.py
Normal file
48
surfsense_backend/app/config/embedding_settings.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import os
|
||||||
|
from collections.abc import Mapping
|
||||||
|
|
||||||
|
EMBEDDING_BASE_URL_ENV = "EMBEDDING_BASE_URL"
|
||||||
|
OLLAMA_EMBEDDING_BASE_URL_ENV = "OLLAMA_EMBEDDING_BASE_URL"
|
||||||
|
|
||||||
|
|
||||||
|
def _clean_env_value(value: str | None) -> str | None:
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
stripped = value.strip()
|
||||||
|
return stripped or None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_embedding_base_url(environ: Mapping[str, str] | None = None) -> str | None:
|
||||||
|
"""Return the configured embedding endpoint, if any."""
|
||||||
|
environ = os.environ if environ is None else environ
|
||||||
|
return _clean_env_value(environ.get(EMBEDDING_BASE_URL_ENV)) or _clean_env_value(
|
||||||
|
environ.get(OLLAMA_EMBEDDING_BASE_URL_ENV)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _supports_embedding_api_base(embedding_model: str | None) -> bool:
|
||||||
|
return (embedding_model or "").startswith("litellm://")
|
||||||
|
|
||||||
|
|
||||||
|
def build_embedding_kwargs(
|
||||||
|
environ: Mapping[str, str] | None = None,
|
||||||
|
*,
|
||||||
|
embedding_model: str | None = None,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
"""Build keyword arguments for Chonkie's embedding provider."""
|
||||||
|
environ = os.environ if environ is None else environ
|
||||||
|
|
||||||
|
embedding_kwargs: dict[str, str] = {}
|
||||||
|
embedding_base_url = resolve_embedding_base_url(environ)
|
||||||
|
if embedding_base_url and _supports_embedding_api_base(embedding_model):
|
||||||
|
embedding_kwargs["api_base"] = embedding_base_url
|
||||||
|
|
||||||
|
azure_openai_endpoint = _clean_env_value(environ.get("AZURE_OPENAI_ENDPOINT"))
|
||||||
|
azure_openai_api_key = _clean_env_value(environ.get("AZURE_OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
if azure_openai_endpoint:
|
||||||
|
embedding_kwargs["azure_endpoint"] = azure_openai_endpoint
|
||||||
|
if azure_openai_api_key:
|
||||||
|
embedding_kwargs["azure_api_key"] = azure_openai_api_key
|
||||||
|
|
||||||
|
return embedding_kwargs
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.config.embedding_settings import (
|
||||||
|
build_embedding_kwargs,
|
||||||
|
resolve_embedding_base_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.unit
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_embedding_base_url_prefers_generic_value() -> None:
|
||||||
|
environ = {
|
||||||
|
"EMBEDDING_BASE_URL": " http://embed-host:11434 ",
|
||||||
|
"OLLAMA_EMBEDDING_BASE_URL": "http://ollama-embed:11434",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert resolve_embedding_base_url(environ) == "http://embed-host:11434"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_embedding_base_url_falls_back_to_ollama_specific_value() -> None:
|
||||||
|
environ = {
|
||||||
|
"EMBEDDING_BASE_URL": " ",
|
||||||
|
"OLLAMA_EMBEDDING_BASE_URL": "http://ollama-embed:11434",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert resolve_embedding_base_url(environ) == "http://ollama-embed:11434"
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_embedding_kwargs_maps_base_url_to_litellm_api_base() -> None:
|
||||||
|
kwargs = build_embedding_kwargs(
|
||||||
|
{"EMBEDDING_BASE_URL": "http://host.docker.internal:11435"},
|
||||||
|
embedding_model="litellm://ollama/nomic-embed-text",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert kwargs == {"api_base": "http://host.docker.internal:11435"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_embedding_kwargs_does_not_leak_api_base_to_other_providers() -> None:
|
||||||
|
kwargs = build_embedding_kwargs(
|
||||||
|
{"EMBEDDING_BASE_URL": "http://host.docker.internal:11435"},
|
||||||
|
embedding_model="cohere://embed-english-light-v3.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert kwargs == {}
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_embedding_kwargs_preserves_azure_settings() -> None:
|
||||||
|
kwargs = build_embedding_kwargs(
|
||||||
|
{
|
||||||
|
"AZURE_OPENAI_ENDPOINT": "https://example.openai.azure.com",
|
||||||
|
"AZURE_OPENAI_API_KEY": "test-key",
|
||||||
|
},
|
||||||
|
embedding_model="azure_openai://text-embedding-3-small",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert kwargs == {
|
||||||
|
"azure_endpoint": "https://example.openai.azure.com",
|
||||||
|
"azure_api_key": "test-key",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_embedding_kwargs_combines_litellm_and_azure_env_when_set() -> None:
|
||||||
|
kwargs = build_embedding_kwargs(
|
||||||
|
{
|
||||||
|
"EMBEDDING_BASE_URL": "http://host.docker.internal:4000/v1",
|
||||||
|
"AZURE_OPENAI_ENDPOINT": "https://example.openai.azure.com",
|
||||||
|
"AZURE_OPENAI_API_KEY": "test-key",
|
||||||
|
},
|
||||||
|
embedding_model="litellm://openai/text-embedding-3-small",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert kwargs == {
|
||||||
|
"api_base": "http://host.docker.internal:4000/v1",
|
||||||
|
"azure_endpoint": "https://example.openai.azure.com",
|
||||||
|
"azure_api_key": "test-key",
|
||||||
|
}
|
||||||
|
|
@ -39,6 +39,7 @@ All configuration lives in a single `docker/.env` file (or `surfsense/.env` if y
|
||||||
| `AUTH_TYPE` | Authentication method: `LOCAL` (email/password) or `GOOGLE` (OAuth) | `LOCAL` |
|
| `AUTH_TYPE` | Authentication method: `LOCAL` (email/password) or `GOOGLE` (OAuth) | `LOCAL` |
|
||||||
| `ETL_SERVICE` | Document parsing: `DOCLING` (local), `UNSTRUCTURED`, or `LLAMACLOUD` | `DOCLING` |
|
| `ETL_SERVICE` | Document parsing: `DOCLING` (local), `UNSTRUCTURED`, or `LLAMACLOUD` | `DOCLING` |
|
||||||
| `EMBEDDING_MODEL` | Embedding model for vector search | `sentence-transformers/all-MiniLM-L6-v2` |
|
| `EMBEDDING_MODEL` | Embedding model for vector search | `sentence-transformers/all-MiniLM-L6-v2` |
|
||||||
|
| `EMBEDDING_BASE_URL` | Optional separate endpoint for Chonkie/LiteLLM embedding models. Use with values like `EMBEDDING_MODEL=litellm://ollama/nomic-embed-text`. `OLLAMA_EMBEDDING_BASE_URL` is also accepted as an Ollama-specific fallback. | *(empty)* |
|
||||||
| `TTS_SERVICE` | Text-to-speech provider for podcasts | `local/kokoro` |
|
| `TTS_SERVICE` | Text-to-speech provider for podcasts | `local/kokoro` |
|
||||||
| `STT_SERVICE` | Speech-to-text provider for audio files | `local/base` |
|
| `STT_SERVICE` | Speech-to-text provider for audio files | `local/base` |
|
||||||
| `REGISTRATION_ENABLED` | Allow new user registrations | `TRUE` |
|
| `REGISTRATION_ENABLED` | Allow new user registrations | `TRUE` |
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,23 @@ http://<host>:11434
|
||||||
|
|
||||||
Replace `<host>` with the LAN IP or domain for that machine.
|
Replace `<host>` with the LAN IP or domain for that machine.
|
||||||
|
|
||||||
|
## Embeddings on a Separate Ollama Server
|
||||||
|
|
||||||
|
Search-space model connections configure chat and completion models. The global
|
||||||
|
embedding model is configured in the backend environment.
|
||||||
|
|
||||||
|
Use Chonkie's LiteLLM embedding provider when embeddings run on Ollama:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
EMBEDDING_MODEL=litellm://ollama/nomic-embed-text
|
||||||
|
EMBEDDING_BASE_URL=http://host.docker.internal:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
If chat and embeddings run on different Ollama instances, keep the chat model
|
||||||
|
connection pointed at the chat server and set `EMBEDDING_BASE_URL` to the
|
||||||
|
embedding server. `OLLAMA_EMBEDDING_BASE_URL` is also supported as an
|
||||||
|
Ollama-specific fallback when `EMBEDDING_BASE_URL` is not set.
|
||||||
|
|
||||||
## Add the Connection
|
## Add the Connection
|
||||||
|
|
||||||
1. Open Search Space Settings.
|
1. Open Search Space Settings.
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ Edit the `.env` file and set the following variables:
|
||||||
| GOOGLE_OAUTH_CLIENT_ID | (Optional) Client ID from Google Cloud Console (required if AUTH_TYPE=GOOGLE) |
|
| GOOGLE_OAUTH_CLIENT_ID | (Optional) Client ID from Google Cloud Console (required if AUTH_TYPE=GOOGLE) |
|
||||||
| GOOGLE_OAUTH_CLIENT_SECRET | (Optional) Client secret from Google Cloud Console (required if AUTH_TYPE=GOOGLE) |
|
| GOOGLE_OAUTH_CLIENT_SECRET | (Optional) Client secret from Google Cloud Console (required if AUTH_TYPE=GOOGLE) |
|
||||||
| EMBEDDING_MODEL | Name of the embedding model (e.g., `sentence-transformers/all-MiniLM-L6-v2`, `openai://text-embedding-ada-002`) |
|
| EMBEDDING_MODEL | Name of the embedding model (e.g., `sentence-transformers/all-MiniLM-L6-v2`, `openai://text-embedding-ada-002`) |
|
||||||
|
| EMBEDDING_BASE_URL | (Optional) Separate endpoint for Chonkie/LiteLLM embedding models, such as `http://localhost:11434` with `EMBEDDING_MODEL=litellm://ollama/nomic-embed-text`. `OLLAMA_EMBEDDING_BASE_URL` is also supported as an Ollama-specific fallback. |
|
||||||
| RERANKERS_ENABLED | (Optional) Enable or disable document reranking for improved search results (e.g., `TRUE` or `FALSE`, default: `FALSE`) |
|
| RERANKERS_ENABLED | (Optional) Enable or disable document reranking for improved search results (e.g., `TRUE` or `FALSE`, default: `FALSE`) |
|
||||||
| RERANKERS_MODEL_NAME | Name of the reranker model (e.g., `ms-marco-MiniLM-L-12-v2`) (required if RERANKERS_ENABLED=TRUE) |
|
| RERANKERS_MODEL_NAME | Name of the reranker model (e.g., `ms-marco-MiniLM-L-12-v2`) (required if RERANKERS_ENABLED=TRUE) |
|
||||||
| RERANKERS_MODEL_TYPE | Type of reranker model (e.g., `flashrank`) (required if RERANKERS_ENABLED=TRUE) |
|
| RERANKERS_MODEL_TYPE | Type of reranker model (e.g., `flashrank`) (required if RERANKERS_ENABLED=TRUE) |
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue