workin on llm_factory

This commit is contained in:
pseco 2026-02-26 18:02:46 +01:00
parent 77751ee8ac
commit e01e424fac
4 changed files with 779 additions and 453 deletions

File diff suppressed because one or more lines are too long

36
src/config.py Normal file
View File

@ -0,0 +1,36 @@
from pathlib import Path
from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY=os.getenv("OPENAI_API_KEY", "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")
OLLAMA_URL=os.getenv("OLLAMA_URL", "http://host.docker.internal:11434")
OLLAMA_LOCAL_URL=os.getenv("OLLAMA_LOCAL_URL", "http://localhost:11434")
OLLAMA_MODEL_NAME=os.getenv("OLLAMA_MODEL_NAME", "qwen3-0.6B:latest")
OLLAMA_EMB_MODEL_NAME=os.getenv("OLLAMA_EMB_MODEL_NAME", "qwen3-0.6B-emb:latest")
LANGFUSE_HOST=os.getenv("LANGFUSE_HOST", "http://45.77.119.180")
LANGFUSE_PUBLIC_KEY=os.getenv("LANGFUSE_PUBLIC_KEY", "pk-lf-0e6db694-3e95-4dd4-aedf-5a2694267058")
LANGFUSE_SECRET_KEY=os.getenv("LANGFUSE_SECRET_KEY", "sk-lf-dbf28bb9-15bb-4d03-a8c3-05caa3e3905f")
ELASTICSEARCH_URL=os.getenv("ELASTICSEARCH_URL", "http://host.docker.internal:9200")
ELASTICSEARCH_LOCAL_URL=os.getenv("ELASTICSEARCH_LOCAL_URL", "http://localhost:9200")
ELASTICSEARCH_INDEX=os.getenv("ELASTICSEARCH_INDEX", "avap-docs-test")
DATABASE_URL=os.getenv("DATABASE_URL", "postgresql://postgres:brunix_pass@host.docker.internal:5432/postgres")
KUBECONFIG_PATH=os.getenv("KUBECONFIG_PATH", "kubernetes/kubeconfig.yaml")
HF_TOKEN=os.getenv("HF_TOKEN", "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")
HF_EMB_MODEL_NAME=os.getenv("HF_EMB_MODEL_NAME", "Qwen/Qwen3-Embedding-0.6B")
PROJ_ROOT = Path(__file__).resolve().parents[1]
DATA_DIR=PROJ_ROOT / "data"
MODELS_DIR=DATA_DIR / "models"
RAW_DIR=DATA_DIR / "raw"
PROCESSED_DIR=DATA_DIR / "processed"
INTERIM_DIR=DATA_DIR / "interim"
EXTERNAL_DIR=DATA_DIR / "external"

152
src/llm_factory v1.py Normal file
View File

@ -0,0 +1,152 @@
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
from typing import Optional
from langchain_ollama import ChatOllama, OllamaEmbeddings
class Provider(StrEnum):
OLLAMA = "ollama"
OPENAI = "openai"
ANTHROPIC = "anthropic"
AWS_BEDROCK = "aws_bedrock"
HUGGINGFACE = "huggingface"
@dataclass(frozen=True)
class ChatModelConfig:
provider: Provider
model: str
temperature: float = 0.0
# Ollama
ollama_base_url: Optional[str] = None
validate_model_on_init: bool = True
# OpenAI / Anthropic / Azure
api_key: Optional[str] = None
azure_endpoint: Optional[str] = None
azure_deployment: Optional[str] = None
api_version: Optional[str] = None
@dataclass(frozen=True)
class EmbeddingsConfig:
provider: Provider
model: str
# Ollama
ollama_base_url: Optional[str] = None
# OpenAI / Azure
api_key: Optional[str] = None
azure_endpoint: Optional[str] = None
azure_deployment: Optional[str] = None
api_version: Optional[str] = None
def build_chat_model(cfg: ChatModelConfig):
match cfg.provider:
case Provider.OLLAMA:
return ChatOllama(
model=cfg.model,
temperature=cfg.temperature,
validate_model_on_init=cfg.validate_model_on_init,
base_url=cfg.ollama_base_url,
)
case Provider.OPENAI:
from langchain_openai import ChatOpenAI # pip install langchain-openai
if not cfg.api_key:
raise ValueError("Missing api_key for OpenAI provider.")
return ChatOpenAI(
model=cfg.model,
temperature=cfg.temperature,
api_key=cfg.api_key,
)
case Provider.ANTHROPIC:
from langchain_anthropic import ChatAnthropic # pip install langchain-anthropic
if not cfg.api_key:
raise ValueError("Missing api_key for Anthropic provider.")
return ChatAnthropic(
model=cfg.model,
temperature=cfg.temperature,
api_key=cfg.api_key,
)
case Provider.AZURE_OPENAI:
from langchain_openai import AzureChatOpenAI # pip install langchain-openai
missing = [
name
for name, value in {
"api_key": cfg.api_key,
"azure_endpoint": cfg.azure_endpoint,
"azure_deployment": cfg.azure_deployment,
"api_version": cfg.api_version,
}.items()
if not value
]
if missing:
raise ValueError(f"Missing Azure settings: {', '.join(missing)}")
return AzureChatOpenAI(
api_key=cfg.api_key,
azure_endpoint=cfg.azure_endpoint,
azure_deployment=cfg.azure_deployment,
api_version=cfg.api_version,
temperature=cfg.temperature,
)
case _:
raise ValueError(f"Unsupported provider: {cfg.provider}")
def build_embeddings(cfg: EmbeddingsConfig):
match cfg.provider:
case Provider.OLLAMA:
return OllamaEmbeddings(
model=cfg.model,
base_url=cfg.ollama_base_url,
)
case Provider.OPENAI:
from langchain_openai import OpenAIEmbeddings # pip install langchain-openai
if not cfg.api_key:
raise ValueError("Missing api_key for OpenAI embeddings provider.")
return OpenAIEmbeddings(
model=cfg.model,
api_key=cfg.api_key,
)
case Provider.AZURE_OPENAI:
from langchain_openai import AzureOpenAIEmbeddings # pip install langchain-openai
missing = [
name
for name, value in {
"api_key": cfg.api_key,
"azure_endpoint": cfg.azure_endpoint,
"azure_deployment": cfg.azure_deployment,
"api_version": cfg.api_version,
}.items()
if not value
]
if missing:
raise ValueError(f"Missing Azure settings: {', '.join(missing)}")
return AzureOpenAIEmbeddings(
api_key=cfg.api_key,
azure_endpoint=cfg.azure_endpoint,
azure_deployment=cfg.azure_deployment,
api_version=cfg.api_version,
)
case _:
raise ValueError(f"Unsupported embeddings provider: {cfg.provider}")

179
src/llm_factory v2.py Normal file
View File

@ -0,0 +1,179 @@
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
from typing import Optional
# ---------- Providers ----------
class Provider(StrEnum):
OLLAMA = "ollama"
OPENAI = "openai"
ANTHROPIC = "anthropic"
AWS_BEDROCK = "aws_bedrock"
HUGGINGFACE = "huggingface"
# ---------- Provider-specific configs ----------
@dataclass(frozen=True)
class OllamaCfg:
base_url: Optional[str] = None
validate_model_on_init: bool = True
@dataclass(frozen=True)
class OpenAICfg:
api_key: str
@dataclass(frozen=True)
class AnthropicCfg:
api_key: str
@dataclass(frozen=True)
class BedrockCfg:
# depende de cómo autentiques: env vars, perfil AWS, role, etc.
region_name: Optional[str] = None
# model_kwargs típicos: temperature, max_tokens, etc. (según wrapper)
# lo dejamos mínimo para no acoplar
pass
@dataclass(frozen=True)
class HuggingFaceCfg:
# puede ser token HF o endpoint, según uses Inference API o local
api_key: Optional[str] = None
endpoint_url: Optional[str] = None
# ---------- Base configs ----------
@dataclass(frozen=True)
class ChatModelConfig:
provider: Provider
model: str
temperature: float = 0.0
# EXACTAMENTE una de estas debería venir informada según provider:
ollama: Optional[OllamaCfg] = None
openai: Optional[OpenAICfg] = None
anthropic: Optional[AnthropicCfg] = None
bedrock: Optional[BedrockCfg] = None
huggingface: Optional[HuggingFaceCfg] = None
@dataclass(frozen=True)
class EmbeddingsConfig:
provider: Provider
model: str
ollama: Optional[OllamaCfg] = None
openai: Optional[OpenAICfg] = None
bedrock: Optional[BedrockCfg] = None
huggingface: Optional[HuggingFaceCfg] = None
# ---------- Helpers ----------
def _require(value, msg: str):
if value is None:
raise ValueError(msg)
return value
def _require_cfg(cfg_obj, msg: str):
if cfg_obj is None:
raise ValueError(msg)
return cfg_obj
# ---------- Builders ----------
def build_chat_model(cfg: ChatModelConfig):
match cfg.provider:
case Provider.OLLAMA:
from langchain_ollama import ChatOllama
ocfg = cfg.ollama or OllamaCfg()
return ChatOllama(
model=cfg.model,
temperature=cfg.temperature,
validate_model_on_init=ocfg.validate_model_on_init,
base_url=ocfg.base_url,
)
case Provider.OPENAI:
from langchain_openai import ChatOpenAI # pip install langchain-openai
ocfg = _require_cfg(cfg.openai, "Missing cfg.openai for OpenAI provider.")
return ChatOpenAI(
model=cfg.model,
temperature=cfg.temperature,
api_key=ocfg.api_key,
)
case Provider.ANTHROPIC:
from langchain_anthropic import ChatAnthropic # pip install langchain-anthropic
acfg = _require_cfg(cfg.anthropic, "Missing cfg.anthropic for Anthropic provider.")
return ChatAnthropic(
model=cfg.model,
temperature=cfg.temperature,
api_key=acfg.api_key,
)
case Provider.AWS_BEDROCK:
# wrapper típico: langchain-aws (según versión) o langchain-community en algunos setups
# aquí lo dejo como ejemplo con guardrail claro
try:
from langchain_aws import ChatBedrock # pip install langchain-aws
except Exception as e:
raise ImportError(
"To use AWS Bedrock, install `langchain-aws` and configure AWS credentials."
) from e
bcfg = cfg.bedrock or BedrockCfg()
# OJO: ChatBedrock suele usar model_id en vez de model, depende del wrapper/versión.
return ChatBedrock(
model_id=cfg.model,
region_name=bcfg.region_name,
model_kwargs={"temperature": cfg.temperature},
)
case Provider.HUGGINGFACE:
# depende MUCHO: endpoint, local pipeline, inference API...
raise NotImplementedError(
"HUGGINGFACE provider not implemented here (depends on whether you use Inference API, TGI, or local pipeline)."
)
case _:
raise ValueError(f"Unsupported provider: {cfg.provider}")
def build_embeddings(cfg: EmbeddingsConfig):
match cfg.provider:
case Provider.OLLAMA:
from langchain_ollama import OllamaEmbeddings
ocfg = cfg.ollama or OllamaCfg()
return OllamaEmbeddings(
model=cfg.model,
base_url=ocfg.base_url,
)
case Provider.OPENAI:
from langchain_openai import OpenAIEmbeddings # pip install langchain-openai
ocfg = _require_cfg(cfg.openai, "Missing cfg.openai for OpenAI embeddings provider.")
return OpenAIEmbeddings(
model=cfg.model,
api_key=ocfg.api_key,
)
case Provider.AWS_BEDROCK:
# Igual: depende del wrapper
raise NotImplementedError("Bedrock embeddings: añade el wrapper que uses y mapea aquí.")
case Provider.HUGGINGFACE:
raise NotImplementedError("HuggingFace embeddings: depende del wrapper (endpoint/local).")
case _:
raise ValueError(f"Unsupported embeddings provider: {cfg.provider}")