From ae9348bb2a2cad99b8e89ea62db056309dafb208 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 7 Sep 2026 15:25:30 +0100 Subject: [PATCH] fix(package): review pass on the PyPI package - docsgpt api binds 127.0.0.1 by default, like gunicorn and uvicorn do; --host 0.0.0.0 exposes it. The docs say so. - The embedded Milvus and LanceDB defaults derive from the data home, so they follow DOCSGPT_HOME like the faiss indexes and uploads do. A checkout run from its root and the Docker image resolve to the same paths as before. - The docs and the pyproject comment describe the CPU torch install as two steps (torch and torchvision from the PyTorch CPU index first, then the docling extra): pip picks the highest version across indexes, so --extra-index-url only yields the CPU build while that index keeps pace with PyPI. - AGENTS.md separates DOCSGPT_HOME (moves the data home) from DOCSGPT_ENV_FILE (selects the .env file); the docs example uses a password placeholder. --- AGENTS.md | 5 +++-- docs/content/Deploying/Pip-Install.mdx | 15 ++++++++++++--- docsgpt/cli.py | 4 ++-- docsgpt/core/settings.py | 5 +++-- pyproject.toml | 5 +++-- tests/core/test_paths.py | 19 +++++++++++++++++++ tests/test_cli.py | 2 +- 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8b878d56..d096cf22 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,8 +41,9 @@ The backend is also an installable package (`pyproject.toml`, hatchling). `uv sync` installs it editable and puts a `docsgpt` command on PATH: `docsgpt api --reload`, `docsgpt worker`, `docsgpt migrate`, `docsgpt prefetch-models`, `docsgpt verify-offline`. Runtime data (`.env`, -`inputs/`, `indexes/`) lives in the checkout by default; `DOCSGPT_HOME` and -`DOCSGPT_ENV_FILE` move it (see `docsgpt/core/paths.py`). +`inputs/`, `indexes/`) lives in the checkout by default; `DOCSGPT_HOME` moves +that data home, and `DOCSGPT_ENV_FILE` selects only the `.env` file (see +`docsgpt/core/paths.py`). Dependencies are declared in `pyproject.toml` and locked in `uv.lock`; the `docsgpt/requirements*.txt` files are exported from the lock. To add or diff --git a/docs/content/Deploying/Pip-Install.mdx b/docs/content/Deploying/Pip-Install.mdx index 41586200..84358c96 100644 --- a/docs/content/Deploying/Pip-Install.mdx +++ b/docs/content/Deploying/Pip-Install.mdx @@ -34,7 +34,14 @@ pip install "docsgpt[docling]" # DOC_PARSER_ENGINE=docling: OCR backend, struc pip install "docsgpt[milvus]" # VECTOR_STORE=milvus ``` -The `docling` extra pulls in PyTorch. On Linux, PyPI's torch wheels bring the CUDA stack with them; on a CPU-only machine add `--extra-index-url https://download.pytorch.org/whl/cpu` to the install command to get the CPU build instead. `uv pip install` and `pipx install` work the same way. +The `docling` extra pulls in PyTorch, and on Linux the PyPI torch wheels bring the CUDA stack with them. On a CPU-only machine install the CPU build first, then the extra; pip keeps the torch it already has: + +```bash +pip install --index-url https://download.pytorch.org/whl/cpu torch torchvision +pip install "docsgpt[docling]" +``` + +`uv pip install` accepts the same two commands. With `pipx`, install `docsgpt[docling]` and then run `pipx inject --index-url https://download.pytorch.org/whl/cpu docsgpt torch torchvision` to swap the CUDA build for the CPU one. ## Configure @@ -49,7 +56,7 @@ LLM_NAME= API_KEY= # User data -POSTGRES_URI=postgresql://docsgpt:docsgpt@localhost:5432/docsgpt +POSTGRES_URI=postgresql://docsgpt:@localhost:5432/docsgpt # Worker-to-API authentication (required for uploads) INTERNAL_KEY= @@ -61,10 +68,12 @@ Redis defaults to `localhost:6379` (`CELERY_BROKER_URL`, `CELERY_RESULT_BACKEND` ```bash docsgpt migrate # create the database if it is missing and apply the migrations -docsgpt api # the API on http://localhost:7091 +docsgpt api # the API on http://127.0.0.1:7091 docsgpt worker # in a second terminal: the Celery worker, with the scheduler ``` +`docsgpt api` listens on localhost only. Pass `--host 0.0.0.0` to accept connections from other machines or containers, and put a reverse proxy with TLS in front of it for anything public. + The API applies pending migrations when it starts (`AUTO_MIGRATE`), so `docsgpt migrate` is the explicit step for deployments that want the schema in place before the first request or that run the API with a restricted database role. The worker is not optional: query embedding runs on it, so search fails without one. `docsgpt worker --help` lists the queue, concurrency and pool options; `--no-beat` starts a worker without the scheduler when another worker already runs it. diff --git a/docsgpt/cli.py b/docsgpt/cli.py index 4c227f83..046ed9f9 100644 --- a/docsgpt/cli.py +++ b/docsgpt/cli.py @@ -14,7 +14,7 @@ from typing import Optional, Sequence from docsgpt.version import __version__ -DEFAULT_HOST = "0.0.0.0" +DEFAULT_HOST = "127.0.0.1" DEFAULT_PORT = 7091 DEFAULT_QUEUES = "docsgpt,parsing,embeddings" @@ -105,7 +105,7 @@ def build_parser() -> argparse.ArgumentParser: commands = parser.add_subparsers(dest="command", metavar="") api = commands.add_parser("api", help="serve the HTTP API") - api.add_argument("--host", default=DEFAULT_HOST) + api.add_argument("--host", default=DEFAULT_HOST, help="interface to listen on (default: localhost; 0.0.0.0 for all)") api.add_argument("--port", type=int, default=DEFAULT_PORT) api.add_argument("--workers", type=int, default=1, help="gunicorn worker processes (default: 1)") api.add_argument("--reload", action="store_true", help="development mode: uvicorn with auto-reload") diff --git a/docsgpt/core/settings.py b/docsgpt/core/settings.py index 46f3f34b..f926485b 100644 --- a/docsgpt/core/settings.py +++ b/docsgpt/core/settings.py @@ -326,11 +326,12 @@ class Settings(BaseSettings): PGVECTOR_IVFFLAT_PROBES: Optional[int] = None # Milvus vectorstore config MILVUS_COLLECTION_NAME: Optional[str] = "docsgpt" - MILVUS_URI: Optional[str] = "./milvus_local.db" # milvus lite version as default + # milvus-lite (embedded) database file, under the data home like the other local stores + MILVUS_URI: Optional[str] = Field(default_factory=lambda: str(home_dir() / "milvus_local.db")) MILVUS_TOKEN: Optional[str] = "" # LanceDB vectorstore config - LANCEDB_PATH: str = "./data/lancedb" # Path where LanceDB stores its local data + LANCEDB_PATH: str = Field(default_factory=lambda: str(home_dir() / "data" / "lancedb")) # LanceDB local data LANCEDB_TABLE_NAME: Optional[str] = "docsgpts" # Name of the table to use for storing vectors FLASK_DEBUG_MODE: bool = False diff --git a/pyproject.toml b/pyproject.toml index 3577d6c0..99fcf8a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -122,8 +122,9 @@ dependencies = [ # attachment parsing, and read_document's `structured` output. Pulls torch and # transformers; with uv on Linux torch resolves from the CPU-only PyTorch index # (see [tool.uv.sources]) so the extra does not drag the CUDA stack in. pip -# users on Linux get the same by adding -# --extra-index-url https://download.pytorch.org/whl/cpu. +# users on Linux install torch and torchvision from that index first +# (--index-url https://download.pytorch.org/whl/cpu), then the extra; pip keeps +# the torch it already has. docling = [ "docling>=2.119.0,<3", "rapidocr>=3.9.2,<4", diff --git a/tests/core/test_paths.py b/tests/core/test_paths.py index 54c74d19..f6cb7a0b 100644 --- a/tests/core/test_paths.py +++ b/tests/core/test_paths.py @@ -36,6 +36,25 @@ class TestEnvFile: assert paths.env_file() == tmp_path / "custom.env" +class TestSettingsFollowTheHome: + def test_embedded_vector_stores_default_under_the_home(self, monkeypatch, tmp_path): + from docsgpt.core.settings import Settings + + monkeypatch.setenv(paths.HOME_ENV, str(tmp_path)) + monkeypatch.delenv("MILVUS_URI", raising=False) + monkeypatch.delenv("LANCEDB_PATH", raising=False) + fresh = Settings(_env_file=None) + assert fresh.MILVUS_URI == str(tmp_path.resolve() / "milvus_local.db") + assert fresh.LANCEDB_PATH == str(tmp_path.resolve() / "data" / "lancedb") + + def test_env_overrides_still_win(self, monkeypatch, tmp_path): + from docsgpt.core.settings import Settings + + monkeypatch.setenv(paths.HOME_ENV, str(tmp_path)) + monkeypatch.setenv("LANCEDB_PATH", "/srv/lancedb") + assert Settings(_env_file=None).LANCEDB_PATH == "/srv/lancedb" + + class TestPackageDir: def test_holds_the_shipped_data(self): assert paths.package_dir().name == "docsgpt" diff --git a/tests/test_cli.py b/tests/test_cli.py index 00d2c8bc..8574b5e1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -43,7 +43,7 @@ class TestApi: run.assert_called_once_with() argv = sys.argv assert argv[0] == "gunicorn" and argv[-1] == "docsgpt.asgi:asgi_app" - assert argv[argv.index("--bind") + 1] == "0.0.0.0:8000" + assert argv[argv.index("--bind") + 1] == "127.0.0.1:8000" assert argv[argv.index("-w") + 1] == "2" assert argv[argv.index("-k") + 1] == "docsgpt.gunicorn_worker.BoundedDrainUvicornWorker" assert argv[argv.index("--config") + 1] == "python:docsgpt.gunicorn_conf"