fix: fixed bugs on ollama integration, added ingestion on onboarding (#330)

* Updated ollama components

* Changed ollama display name to be correct

* Changed prompt of provider validation

* removed event dispatched from file upload

* Changed onboarding to upload the entire knowledge

* Changed default models for ollama
This commit is contained in:
Lucas Oliveira 2025-10-30 09:02:06 -03:00 committed by GitHub
parent 7b635df9d0
commit b9ea9c99f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 628 additions and 748 deletions

View file

@ -31,7 +31,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Any\nfrom urllib.parse import urljoin\n\nimport httpx\nfrom langchain_ollama import OllamaEmbeddings\n\nfrom lfx.base.models.model import LCModelComponent\nfrom lfx.base.models.ollama_constants import OLLAMA_EMBEDDING_MODELS, URL_LIST\nfrom lfx.field_typing import Embeddings\nfrom lfx.io import DropdownInput, MessageTextInput, Output\n\nHTTP_STATUS_OK = 200\n\n\nclass OllamaEmbeddingsComponent(LCModelComponent):\n display_name: str = \"Ollama Embeddings\"\n description: str = \"Generate embeddings using Ollama models.\"\n documentation = \"https://python.langchain.com/docs/integrations/text_embedding/ollama\"\n icon = \"Ollama\"\n name = \"OllamaEmbeddings\"\n\n inputs = [\n DropdownInput(\n name=\"model_name\",\n display_name=\"Ollama Model\",\n value=\"\",\n options=[],\n real_time_refresh=True,\n refresh_button=True,\n combobox=True,\n required=True,\n ),\n MessageTextInput(\n name=\"base_url\",\n display_name=\"Ollama Base URL\",\n value=\"\",\n required=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Embeddings\", name=\"embeddings\", method=\"build_embeddings\"),\n ]\n\n def build_embeddings(self) -> Embeddings:\n try:\n output = OllamaEmbeddings(model=self.model_name, base_url=self.base_url)\n except Exception as e:\n msg = (\n \"Unable to connect to the Ollama API. \",\n \"Please verify the base URL, ensure the relevant Ollama model is pulled, and try again.\",\n )\n raise ValueError(msg) from e\n return output\n\n async def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None):\n if field_name in {\"base_url\", \"model_name\"} and not await self.is_valid_ollama_url(field_value):\n # Check if any URL in the list is valid\n valid_url = \"\"\n for url in URL_LIST:\n if await self.is_valid_ollama_url(url):\n valid_url = url\n break\n build_config[\"base_url\"][\"value\"] = valid_url\n if field_name in {\"model_name\", \"base_url\", \"tool_model_enabled\"}:\n if await self.is_valid_ollama_url(self.base_url):\n build_config[\"model_name\"][\"options\"] = await self.get_model(self.base_url)\n elif await self.is_valid_ollama_url(build_config[\"base_url\"].get(\"value\", \"\")):\n build_config[\"model_name\"][\"options\"] = await self.get_model(build_config[\"base_url\"].get(\"value\", \"\"))\n else:\n build_config[\"model_name\"][\"options\"] = []\n\n return build_config\n\n async def get_model(self, base_url_value: str) -> list[str]:\n \"\"\"Get the model names from Ollama.\"\"\"\n model_ids = []\n try:\n url = urljoin(base_url_value, \"/api/tags\")\n async with httpx.AsyncClient() as client:\n response = await client.get(url)\n response.raise_for_status()\n data = response.json()\n\n model_ids = [model[\"name\"] for model in data.get(\"models\", [])]\n # this to ensure that not embedding models are included.\n # not even the base models since models can have 1b 2b etc\n # handles cases when embeddings models have tags like :latest - etc.\n model_ids = [\n model\n for model in model_ids\n if any(model.startswith(f\"{embedding_model}\") for embedding_model in OLLAMA_EMBEDDING_MODELS)\n ]\n\n except (ImportError, ValueError, httpx.RequestError) as e:\n msg = \"Could not get model names from Ollama.\"\n raise ValueError(msg) from e\n\n return model_ids\n\n async def is_valid_ollama_url(self, url: str) -> bool:\n try:\n async with httpx.AsyncClient() as client:\n return (await client.get(f\"{url}/api/tags\")).status_code == HTTP_STATUS_OK\n except httpx.RequestError:\n return False\n",
"value": "from typing import Any\nfrom urllib.parse import urljoin\n\nimport httpx\nfrom langchain_ollama import OllamaEmbeddings\n\nfrom lfx.base.models.model import LCModelComponent\nfrom lfx.base.models.ollama_constants import OLLAMA_EMBEDDING_MODELS\nfrom lfx.field_typing import Embeddings\nfrom lfx.io import DropdownInput, MessageTextInput, Output\nfrom lfx.utils.util import transform_localhost_url\n\nHTTP_STATUS_OK = 200\n\n\nclass OllamaEmbeddingsComponent(LCModelComponent):\n display_name: str = \"Ollama Embeddings\"\n description: str = \"Generate embeddings using Ollama models.\"\n documentation = \"https://python.langchain.com/docs/integrations/text_embedding/ollama\"\n icon = \"Ollama\"\n name = \"OllamaEmbeddings\"\n\n inputs = [\n DropdownInput(\n name=\"model_name\",\n display_name=\"Ollama Model\",\n value=\"\",\n options=[],\n real_time_refresh=True,\n refresh_button=True,\n combobox=True,\n required=True,\n ),\n MessageTextInput(\n name=\"base_url\",\n display_name=\"Ollama Base URL\",\n value=\"\",\n required=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Embeddings\", name=\"embeddings\", method=\"build_embeddings\"),\n ]\n\n def build_embeddings(self) -> Embeddings:\n transformed_base_url = transform_localhost_url(self.base_url)\n try:\n output = OllamaEmbeddings(model=self.model_name, base_url=transformed_base_url)\n except Exception as e:\n msg = (\n \"Unable to connect to the Ollama API. \",\n \"Please verify the base URL, ensure the relevant Ollama model is pulled, and try again.\",\n )\n raise ValueError(msg) from e\n return output\n\n async def update_build_config(self, build_config: dict, _field_value: Any, field_name: str | None = None):\n if field_name in {\"base_url\", \"model_name\"} and not await self.is_valid_ollama_url(self.base_url):\n msg = \"Ollama is not running on the provided base URL. Please start Ollama and try again.\"\n raise ValueError(msg)\n if field_name in {\"model_name\", \"base_url\", \"tool_model_enabled\"}:\n if await self.is_valid_ollama_url(self.base_url):\n build_config[\"model_name\"][\"options\"] = await self.get_model(self.base_url)\n else:\n build_config[\"model_name\"][\"options\"] = []\n\n return build_config\n\n async def get_model(self, base_url_value: str) -> list[str]:\n \"\"\"Get the model names from Ollama.\"\"\"\n model_ids = []\n try:\n base_url_value = transform_localhost_url(base_url_value)\n url = urljoin(base_url_value, \"/api/tags\")\n async with httpx.AsyncClient() as client:\n response = await client.get(url)\n response.raise_for_status()\n data = response.json()\n\n model_ids = [model[\"name\"] for model in data.get(\"models\", [])]\n # this to ensure that not embedding models are included.\n # not even the base models since models can have 1b 2b etc\n # handles cases when embeddings models have tags like :latest - etc.\n model_ids = [\n model\n for model in model_ids\n if any(model.startswith(f\"{embedding_model}\") for embedding_model in OLLAMA_EMBEDDING_MODELS)\n ]\n\n except (ImportError, ValueError, httpx.RequestError) as e:\n msg = \"Could not get model names from Ollama.\"\n raise ValueError(msg) from e\n\n return model_ids\n\n async def is_valid_ollama_url(self, url: str) -> bool:\n try:\n async with httpx.AsyncClient() as client:\n url = transform_localhost_url(url)\n return (await client.get(f\"{url}/api/tags\")).status_code == HTTP_STATUS_OK\n except httpx.RequestError:\n return False\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -99,44 +99,27 @@
"legacy": false,
"edited": false,
"metadata": {
"keywords": [
"model",
"llm",
"language model",
"large language model"
],
"keywords": ["model", "llm", "language model", "large language model"],
"module": "lfx.components.ollama.ollama_embeddings.OllamaEmbeddingsComponent",
"code_hash": "c41821735548",
"code_hash": "9ef83e250bee",
"dependencies": {
"total_dependencies": 3,
"dependencies": [
{
"name": "httpx",
"version": "0.28.1"
},
{
"name": "langchain_ollama",
"version": "0.2.1"
},
{
"name": "lfx",
"version": null
}
{ "name": "httpx", "version": "0.28.1" },
{ "name": "langchain_ollama", "version": "0.2.1" },
{ "name": "lfx", "version": "0.1.12.dev32" }
]
}
},
"tool_mode": false,
"last_updated": "2025-09-29T18:40:10.242Z",
"last_updated": "2025-10-29T19:54:23.774Z",
"official": false
},
"showNode": true,
"type": "OllamaEmbeddings",
"id": "OllamaEmbeddings-vnNn8"
},
"id": "OllamaEmbeddings-vnNn8",
"position": {
"x": 0,
"y": 0
"id": "OllamaEmbeddings-3JO8z"
},
"id": "OllamaEmbeddings-3JO8z",
"position": { "x": 0, "y": 0 },
"type": "genericNode"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -194,21 +194,6 @@ export async function uploadFile(
raw: uploadIngestJson,
};
window.dispatchEvent(
new CustomEvent("fileUploaded", {
detail: {
file,
result: {
file_id: fileId,
file_path: filePath,
run: runJson,
deletion: deletionJson,
unified: true,
},
},
})
);
return result;
} catch (error) {
window.dispatchEvent(

View file

@ -2,7 +2,7 @@ import { AnimatePresence, motion } from "motion/react";
import { type ChangeEvent, useRef, useState } from "react";
import { AnimatedProviderSteps } from "@/app/onboarding/components/animated-provider-steps";
import { Button } from "@/components/ui/button";
import { uploadFileForContext } from "@/lib/upload-utils";
import { uploadFile } from "@/lib/upload-utils";
interface OnboardingUploadProps {
onComplete: () => void;
@ -29,7 +29,7 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => {
setIsUploading(true);
try {
setCurrentStep(0);
await uploadFileForContext(file);
await uploadFile(file, true);
console.log("Document uploaded successfully");
} catch (error) {
console.error("Upload failed", (error as Error).message);

View file

@ -110,7 +110,7 @@ async def _test_openai_completion_with_tools(api_key: str, llm_model: str) -> No
payload = {
"model": llm_model,
"messages": [
{"role": "user", "content": "What's the weather like?"}
{"role": "user", "content": "What tools do you have available?"}
],
"tools": [
{
@ -233,7 +233,7 @@ async def _test_watsonx_completion_with_tools(
"model_id": llm_model,
"project_id": project_id,
"messages": [
{"role": "user", "content": "What's the weather like?"}
{"role": "user", "content": "What tools do you have available?"}
],
"tools": [
{
@ -356,7 +356,7 @@ async def _test_ollama_completion_with_tools(llm_model: str, endpoint: str) -> N
payload = {
"model": llm_model,
"messages": [
{"role": "user", "content": "What's the weather like?"}
{"role": "user", "content": "What tools do you have available?"}
],
"tools": [
{

View file

@ -562,7 +562,7 @@ WATSONX_LLM_COMPONENT_DISPLAY_NAME = os.getenv(
)
OLLAMA_EMBEDDING_COMPONENT_DISPLAY_NAME = os.getenv(
"OLLAMA_EMBEDDING_COMPONENT_DISPLAY_NAME", "Ollama Model"
"OLLAMA_EMBEDDING_COMPONENT_DISPLAY_NAME", "Ollama Embeddings"
)
OLLAMA_LLM_COMPONENT_DISPLAY_NAME = os.getenv("OLLAMA_LLM_COMPONENT_DISPLAY_NAME", "Ollama")

View file

@ -182,7 +182,7 @@ class ModelsService:
{
"value": model_name,
"label": model_name,
"default": False,
"default": "nomic-embed-text" in model_name.lower(),
}
)
elif not is_embedding and has_completion and has_tools:
@ -191,7 +191,7 @@ class ModelsService:
{
"value": model_name,
"label": model_name,
"default": "llama3" in model_name.lower(),
"default": "gpt-oss" in model_name.lower(),
}
)
except Exception as e: