e93507a09c
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
118 lines
6.2 KiB
Python
118 lines
6.2 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
|
|
|
"""RAG config; every value is env-overridable."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
|
|
DEFAULT_EMBEDDING_MODEL = "unsloth/bge-small-en-v1.5"
|
|
EMBEDDING_MODEL = os.environ.get("RAG_EMBEDDING_MODEL", DEFAULT_EMBEDDING_MODEL)
|
|
# Under bge's 512 limit, leaving headroom for the 2 special tokens (else overflow:
|
|
# llama-server 500s, ST truncates). Keep <= embedder_max - ~12.
|
|
CHUNK_TOKENS = int(os.environ.get("RAG_CHUNK_TOKENS", "500"))
|
|
CHUNK_OVERLAP = int(os.environ.get("RAG_CHUNK_OVERLAP", "64"))
|
|
TOP_K_LEXICAL = int(os.environ.get("RAG_TOP_K_LEXICAL", "30"))
|
|
TOP_K_DENSE = int(os.environ.get("RAG_TOP_K_DENSE", "30"))
|
|
TOP_K_HYBRID = int(os.environ.get("RAG_TOP_K_HYBRID", "10"))
|
|
RRF_K = int(os.environ.get("RAG_RRF_K", "60"))
|
|
|
|
# Whole-document context: a thread-attached file under the token budget is injected
|
|
# in full (every chunk, in order) instead of top-K retrieval; above it, use retrieval.
|
|
THREAD_WHOLE_DOC = os.environ.get("RAG_THREAD_WHOLE_DOC", "1") == "1"
|
|
WHOLE_DOC_MAX_TOKENS = int(os.environ.get("RAG_WHOLE_DOC_MAX_TOKENS", "6000"))
|
|
|
|
UPLOAD_EXTS = {".pdf", ".txt", ".md", ".markdown", ".docx", ".html", ".htm"}
|
|
# Reject uploads larger than this, so one pathological file can't drive unbounded parse
|
|
# + vision work at ingest. 0 disables the cap. Default 200 MB.
|
|
MAX_UPLOAD_BYTES = int(os.environ.get("RAG_MAX_UPLOAD_BYTES", str(200 * 1024 * 1024)))
|
|
|
|
# Extract PDF text as layout-aware Markdown (pymupdf4llm) instead of flat text, so
|
|
# tables, headings and lists survive into chunks and retrieval. Falls back to plain
|
|
# PyMuPDF text when off, when pymupdf4llm is missing, or when extraction fails.
|
|
PDF_MARKDOWN = os.environ.get("RAG_PDF_MARKDOWN", "1") == "1"
|
|
|
|
# Figure captioning via the loaded vision model: detected figures are transcribed +
|
|
# described so they become searchable. On by default, a no-op without a vision model;
|
|
# the chat's "Describe figures & charts" toggle overrides it per upload.
|
|
CAPTION_IMAGES = os.environ.get("RAG_CAPTION_IMAGES", "1") == "1"
|
|
# Total per-document tile budget (figure-bearing pages are tiled, see below).
|
|
CAPTION_MAX_IMAGES = int(os.environ.get("RAG_CAPTION_MAX_IMAGES", "24"))
|
|
CAPTION_TIMEOUT_S = float(os.environ.get("RAG_CAPTION_TIMEOUT_S", "60"))
|
|
# Larger than a one-line caption since captions transcribe every label. FIGURE_DPI is
|
|
# high enough to keep small box/axis labels legible when tiles are rendered.
|
|
CAPTION_MAX_TOKENS = int(os.environ.get("RAG_CAPTION_MAX_TOKENS", "768"))
|
|
FIGURE_DPI = int(os.environ.get("RAG_FIGURE_DPI", "200"))
|
|
# Figure pages are tiled into an overlapping ROWS x COLS grid of high-DPI tiles (plus
|
|
# an optional full page), so small labels and every sub-figure are covered without
|
|
# exact region detection. MAX_PAGES bounds figure pages; MAX_IMAGES bounds total tiles.
|
|
FIGURE_TILE_ROWS = int(os.environ.get("RAG_FIGURE_TILE_ROWS", "2"))
|
|
FIGURE_TILE_COLS = int(os.environ.get("RAG_FIGURE_TILE_COLS", "2"))
|
|
FIGURE_TILE_OVERLAP = float(os.environ.get("RAG_FIGURE_TILE_OVERLAP", "0.12"))
|
|
FIGURE_FULLPAGE = os.environ.get("RAG_FIGURE_FULLPAGE", "1") == "1"
|
|
CAPTION_MAX_PAGES = int(os.environ.get("RAG_CAPTION_MAX_PAGES", "4"))
|
|
|
|
# Scanned-PDF OCR: a page with little extractable text is rendered and transcribed by
|
|
# the vision model so it becomes searchable. Needs a vision model, else skipped (page
|
|
# stays empty). MIN_CHARS is the text length below which a page is treated as scanned.
|
|
OCR_SCANNED = os.environ.get("RAG_OCR_SCANNED", "1") == "1"
|
|
OCR_MIN_CHARS = int(os.environ.get("RAG_OCR_MIN_CHARS", "16"))
|
|
OCR_MAX_PAGES = int(os.environ.get("RAG_OCR_MAX_PAGES", "20"))
|
|
OCR_DPI = int(os.environ.get("RAG_OCR_DPI", "150"))
|
|
OCR_TIMEOUT_S = float(os.environ.get("RAG_OCR_TIMEOUT_S", "60"))
|
|
OCR_MAX_TOKENS = int(os.environ.get("RAG_OCR_MAX_TOKENS", "2048"))
|
|
|
|
# Embedder backend. "auto": sentence-transformers on a CUDA/ROCm GPU (torch fp16
|
|
# wins bulk indexing), else torch-free GGUF llama-server. Switching backends changes
|
|
# the vectors, so the index must be rebuilt.
|
|
EMBED_BACKEND = os.environ.get("RAG_EMBED_BACKEND", "auto")
|
|
|
|
|
|
def effective_embedding_model() -> str:
|
|
"""The embedding model actually in use: the persisted Settings override when
|
|
one is stored, else ``EMBEDDING_MODEL`` (env/default). Read at call time so a
|
|
Settings change applies without a restart."""
|
|
try:
|
|
from utils.embedding_model_settings import get_rag_embedding_model
|
|
return get_rag_embedding_model()
|
|
except Exception: # noqa: BLE001 - settings store unavailable (tests, early boot)
|
|
return EMBEDDING_MODEL
|
|
|
|
|
|
def _names_gguf(model: str) -> bool:
|
|
"""True when "gguf" appears as a whole name segment, so plain substrings
|
|
like "bigguf" don't count."""
|
|
return "gguf" in re.split(r"[^a-z0-9]+", model.lower())
|
|
|
|
|
|
def effective_gguf_repo() -> str:
|
|
"""GGUF repo for the llama-server backend, tracking the effective model.
|
|
|
|
An explicit ``RAG_EMBED_GGUF_REPO`` env always wins. Otherwise any custom
|
|
model (saved in Settings or via ``RAG_EMBEDDING_MODEL``) maps to its
|
|
``-GGUF`` companion repo (the unsloth convention the default pair follows),
|
|
or is used as-is when it already names a GGUF repo.
|
|
"""
|
|
if "RAG_EMBED_GGUF_REPO" in os.environ:
|
|
return EMBED_GGUF_REPO
|
|
model = effective_embedding_model()
|
|
if model == DEFAULT_EMBEDDING_MODEL:
|
|
return EMBED_GGUF_REPO
|
|
if _names_gguf(model):
|
|
return model
|
|
return f"{model}-GGUF"
|
|
|
|
|
|
# llama-server backend only. F16 over Q8_0: faster (no per-block dequant for this
|
|
# tiny model) and exact vs fp32, for ~30MB more on disk.
|
|
EMBED_GGUF_REPO = os.environ.get("RAG_EMBED_GGUF_REPO", "unsloth/bge-small-en-v1.5-GGUF")
|
|
EMBED_GGUF_VARIANT = os.environ.get("RAG_EMBED_GGUF_VARIANT", "F16")
|
|
EMBED_DEVICE = os.environ.get("RAG_EMBED_DEVICE", "auto") # "auto" | "gpu" | "cpu"
|
|
EMBED_HOST = os.environ.get("RAG_EMBED_HOST", "127.0.0.1")
|
|
EMBED_PORT = int(os.environ.get("RAG_EMBED_PORT", "0")) # 0 = auto-pick a free port
|
|
EMBED_BATCH = int(os.environ.get("RAG_EMBED_BATCH", "64"))
|
|
EMBED_STARTUP_TIMEOUT_S = float(os.environ.get("RAG_EMBED_STARTUP_TIMEOUT_S", "120"))
|
|
EMBED_REQUEST_TIMEOUT_S = float(os.environ.get("RAG_EMBED_REQUEST_TIMEOUT_S", "60"))
|