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}")