File size: 3,178 Bytes
2edb151
 
 
676f5d4
2edb151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676f5d4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2edb151
676f5d4
2edb151
676f5d4
2edb151
 
 
 
 
 
 
 
 
 
 
676f5d4
2edb151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from __future__ import annotations

from app.config import Settings
from app.route import resolve_brain
from backends.apple import AppleEmbed, AppleLLM, AppleOCR
from backends.base import EmbedBackend, LLMBackend, OCRBackend
from backends.cpu import CpuOCR
from backends.gemma import GemmaEmbed, GemmaLLM
from backends.nvidia import NvidiaEmbed, NvidiaLLM, NvidiaOCR
from backends.ollama import OllamaEmbed, OllamaLLM, OllamaOCR

__all__ = [
    "EmbedBackend",
    "LLMBackend",
    "OCRBackend",
    "build_embed",
    "build_llm",
    "build_ocr",
]


def _with_brain(settings: Settings) -> Settings:
    """Point llm/embed URLs at the resolved Gemma 4 12B (direct vLLM or Hermes)."""
    route = settings.llm_route.lower().strip()
    backend = settings.llm_backend.lower().strip()
    if route == "studio":
        return settings
    if backend in {"ollama", "lightning", "apple"}:
        return settings
    try:
        brain = resolve_brain(settings)
    except RuntimeError:
        return settings
    if brain.kind == "studio":
        return settings
    updates: dict[str, object] = {}
    if brain.base_url and brain.base_url != settings.llm_base_url:
        updates["llm_base_url"] = brain.base_url
        updates["embed_base_url"] = brain.base_url
    if brain.model and brain.model != settings.llm_model:
        updates["llm_model"] = brain.model
        if settings.embed_backend.lower() in {"omni", "gemma", "gemma4"}:
            updates["embed_model"] = brain.model
    return settings.model_copy(update=updates) if updates else settings


def build_llm(settings: Settings, *, client=None) -> LLMBackend:
    settings = _with_brain(settings)
    name = settings.llm_backend.lower().strip()
    if name in {"gemma", "gemma4", "unified", "hermes", "auto"}:
        return GemmaLLM(settings, client=client)
    if name in {"nvidia", "vllm", "qwen", "qwen38"}:
        return NvidiaLLM(settings, client=client)
    if name in {"ollama", "lightning"}:
        return OllamaLLM(settings, client=client)
    if name == "apple":
        return AppleLLM()
    raise ValueError(f"unknown llm_backend: {settings.llm_backend}")


def build_embed(settings: Settings, *, client=None) -> EmbedBackend:
    settings = _with_brain(settings)
    name = settings.embed_backend.lower().strip()
    if name in {"omni", "gemma", "gemma4"}:
        return GemmaEmbed(settings, client=client)
    if name in {"nvidia", "nemotron", "vllm"}:
        return NvidiaEmbed(settings, client=client)
    if name in {"openai", "ollama"}:
        return OllamaEmbed(settings, client=client)
    if name == "apple":
        return AppleEmbed()
    raise ValueError(f"unknown embed_backend: {settings.embed_backend}")


def build_ocr(settings: Settings, *, client=None) -> OCRBackend | None:
    name = settings.ocr_backend.lower().strip()
    if name in {"", "none", "off"}:
        return None
    if name == "ollama":
        return OllamaOCR(settings, client=client)
    if name == "nvidia":
        return NvidiaOCR()
    if name == "apple":
        return AppleOCR()
    if name == "cpu":
        return CpuOCR()
    raise ValueError(f"unknown ocr_backend: {settings.ocr_backend}")