Release 0.6.4 (#1268)
This PR: - Updates Vectara component by @JAtharva22 - Adds Ollama components by @yamonkjd - Fixes bugs in the canvas by @Cristhianzl - adds Docker image builds on release.
This commit is contained in:
commit
57c6dad343
17 changed files with 1288 additions and 793 deletions
|
|
@ -1,2 +1,7 @@
|
||||||
.venv/
|
.venv/
|
||||||
**/aws
|
**/aws
|
||||||
|
# node_modules
|
||||||
|
**/node_modules/
|
||||||
|
dist/
|
||||||
|
**/build/
|
||||||
|
src/backend/langflow/frontend
|
||||||
16
.github/workflows/pre-release.yml
vendored
16
.github/workflows/pre-release.yml
vendored
|
|
@ -47,3 +47,19 @@ jobs:
|
||||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
poetry publish
|
poetry publish
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
file: ./build_and_push.Dockerfile
|
||||||
|
tags: logspace/langflow:${{ steps.check-version.outputs.version }}
|
||||||
|
|
|
||||||
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
|
|
@ -45,3 +45,21 @@ jobs:
|
||||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
poetry publish
|
poetry publish
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
file: ./build_and_push.Dockerfile
|
||||||
|
tags: |
|
||||||
|
logspace/langflow:${{ steps.check-version.outputs.version }}
|
||||||
|
logspace/langflow:latest
|
||||||
|
|
|
||||||
79
build_and_push.Dockerfile
Normal file
79
build_and_push.Dockerfile
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
|
||||||
|
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
# Keep this syntax directive! It's used to enable Docker BuildKit
|
||||||
|
|
||||||
|
# Based on https://github.com/python-poetry/poetry/discussions/1879?sort=top#discussioncomment-216865
|
||||||
|
# but I try to keep it updated (see history)
|
||||||
|
|
||||||
|
################################
|
||||||
|
# PYTHON-BASE
|
||||||
|
# Sets up all our shared environment variables
|
||||||
|
################################
|
||||||
|
FROM python:3.10-slim as python-base
|
||||||
|
|
||||||
|
# python
|
||||||
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
|
# prevents python creating .pyc files
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
\
|
||||||
|
# pip
|
||||||
|
PIP_DISABLE_PIP_VERSION_CHECK=on \
|
||||||
|
PIP_DEFAULT_TIMEOUT=100 \
|
||||||
|
\
|
||||||
|
# poetry
|
||||||
|
# https://python-poetry.org/docs/configuration/#using-environment-variables
|
||||||
|
POETRY_VERSION=1.7.1 \
|
||||||
|
# make poetry install to this location
|
||||||
|
POETRY_HOME="/opt/poetry" \
|
||||||
|
# make poetry create the virtual environment in the project's root
|
||||||
|
# it gets named `.venv`
|
||||||
|
POETRY_VIRTUALENVS_IN_PROJECT=true \
|
||||||
|
# do not ask any interactive question
|
||||||
|
POETRY_NO_INTERACTION=1 \
|
||||||
|
\
|
||||||
|
# paths
|
||||||
|
# this is where our requirements + virtual environment will live
|
||||||
|
PYSETUP_PATH="/opt/pysetup" \
|
||||||
|
VENV_PATH="/opt/pysetup/.venv"
|
||||||
|
|
||||||
|
|
||||||
|
# prepend poetry and venv to path
|
||||||
|
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"
|
||||||
|
|
||||||
|
|
||||||
|
################################
|
||||||
|
# BUILDER-BASE
|
||||||
|
# Used to build deps + create our virtual environment
|
||||||
|
################################
|
||||||
|
FROM python-base as builder-base
|
||||||
|
RUN
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends -y \
|
||||||
|
# deps for installing poetry
|
||||||
|
curl \
|
||||||
|
# deps for building python deps
|
||||||
|
build-essential \
|
||||||
|
# npm
|
||||||
|
npm
|
||||||
|
|
||||||
|
|
||||||
|
# Now we need to copy the entire project into the image
|
||||||
|
WORKDIR /app
|
||||||
|
COPY pyproject.toml poetry.lock ./
|
||||||
|
COPY src ./src
|
||||||
|
COPY Makefile ./
|
||||||
|
COPY README.md ./
|
||||||
|
RUN curl -sSL https://install.python-poetry.org | python3 - && make build
|
||||||
|
|
||||||
|
# Final stage for the application
|
||||||
|
FROM python-base as final
|
||||||
|
|
||||||
|
# Copy virtual environment and built .tar.gz from builder base
|
||||||
|
COPY --from=builder-base /app/dist/*.tar.gz ./
|
||||||
|
|
||||||
|
# Install the package from the .tar.gz
|
||||||
|
RUN pip install *.tar.gz
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
CMD ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
|
||||||
991
poetry.lock
generated
991
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "langflow"
|
name = "langflow"
|
||||||
version = "0.6.3"
|
version = "0.6.4"
|
||||||
description = "A Python package with a built-in web application"
|
description = "A Python package with a built-in web application"
|
||||||
authors = ["Logspace <contact@logspace.ai>"]
|
authors = ["Logspace <contact@logspace.ai>"]
|
||||||
maintainers = [
|
maintainers = [
|
||||||
|
|
@ -28,15 +28,15 @@ langflow = "langflow.__main__:main"
|
||||||
|
|
||||||
|
|
||||||
python = ">=3.9,<3.11"
|
python = ">=3.9,<3.11"
|
||||||
fastapi = "^0.104.0"
|
fastapi = "^0.108.0"
|
||||||
uvicorn = "^0.23.0"
|
uvicorn = "^0.25.0"
|
||||||
beautifulsoup4 = "^4.12.2"
|
beautifulsoup4 = "^4.12.2"
|
||||||
google-search-results = "^2.4.1"
|
google-search-results = "^2.4.1"
|
||||||
google-api-python-client = "^2.79.0"
|
google-api-python-client = "^2.79.0"
|
||||||
typer = "^0.9.0"
|
typer = "^0.9.0"
|
||||||
gunicorn = "^21.2.0"
|
gunicorn = "^21.2.0"
|
||||||
langchain = "~0.0.345"
|
langchain = "~0.0.345"
|
||||||
openai = "^1.3.6"
|
openai = "^1.6.1"
|
||||||
pandas = "2.0.3"
|
pandas = "2.0.3"
|
||||||
chromadb = "^0.4.0"
|
chromadb = "^0.4.0"
|
||||||
huggingface-hub = { version = "^0.19.0", extras = ["inference"] }
|
huggingface-hub = { version = "^0.19.0", extras = ["inference"] }
|
||||||
|
|
@ -47,31 +47,31 @@ unstructured = "^0.11.0"
|
||||||
pypdf = "^3.17.0"
|
pypdf = "^3.17.0"
|
||||||
lxml = "^4.9.2"
|
lxml = "^4.9.2"
|
||||||
pysrt = "^1.1.2"
|
pysrt = "^1.1.2"
|
||||||
fake-useragent = "^1.3.0"
|
fake-useragent = "^1.4.0"
|
||||||
docstring-parser = "^0.15"
|
docstring-parser = "^0.15"
|
||||||
psycopg2-binary = "^2.9.6"
|
psycopg2-binary = "^2.9.6"
|
||||||
pyarrow = "^14.0.0"
|
pyarrow = "^14.0.0"
|
||||||
tiktoken = "~0.5.0"
|
tiktoken = "~0.5.0"
|
||||||
wikipedia = "^1.4.0"
|
wikipedia = "^1.4.0"
|
||||||
qdrant-client = "^1.4.0"
|
qdrant-client = "^1.7.0"
|
||||||
websockets = "^10.3"
|
websockets = "^10.3"
|
||||||
weaviate-client = "^3.23.0"
|
weaviate-client = "^3.26.0"
|
||||||
jina = "*"
|
jina = "*"
|
||||||
sentence-transformers = { version = "^2.2.2", optional = true }
|
sentence-transformers = { version = "^2.2.2", optional = true }
|
||||||
ctransformers = { version = "^0.2.10", optional = true }
|
ctransformers = { version = "^0.2.10", optional = true }
|
||||||
cohere = "^4.37.0"
|
cohere = "^4.39.0"
|
||||||
python-multipart = "^0.0.6"
|
python-multipart = "^0.0.6"
|
||||||
sqlmodel = "^0.0.14"
|
sqlmodel = "^0.0.14"
|
||||||
faiss-cpu = "^1.7.4"
|
faiss-cpu = "^1.7.4"
|
||||||
anthropic = "^0.7.0"
|
anthropic = "^0.8.0"
|
||||||
orjson = "3.9.3"
|
orjson = "3.9.3"
|
||||||
multiprocess = "^0.70.14"
|
multiprocess = "^0.70.14"
|
||||||
cachetools = "^5.3.1"
|
cachetools = "^5.3.1"
|
||||||
types-cachetools = "^5.3.0.5"
|
types-cachetools = "^5.3.0.5"
|
||||||
platformdirs = "^4.1.0"
|
platformdirs = "^4.1.0"
|
||||||
pinecone-client = "^2.2.2"
|
pinecone-client = "^2.2.2"
|
||||||
pymongo = "^4.5.0"
|
pymongo = "^4.6.0"
|
||||||
supabase = "^2.0.3"
|
supabase = "^2.3.0"
|
||||||
certifi = "^2023.11.17"
|
certifi = "^2023.11.17"
|
||||||
google-cloud-aiplatform = "^1.36.0"
|
google-cloud-aiplatform = "^1.36.0"
|
||||||
psycopg = "^3.1.9"
|
psycopg = "^3.1.9"
|
||||||
|
|
@ -81,13 +81,13 @@ langchain-experimental = "*"
|
||||||
celery = { extras = ["redis"], version = "^5.3.6", optional = true }
|
celery = { extras = ["redis"], version = "^5.3.6", optional = true }
|
||||||
redis = { version = "^4.6.0", optional = true }
|
redis = { version = "^4.6.0", optional = true }
|
||||||
flower = { version = "^2.0.0", optional = true }
|
flower = { version = "^2.0.0", optional = true }
|
||||||
alembic = "^1.12.0"
|
alembic = "^1.13.0"
|
||||||
passlib = "^1.7.4"
|
passlib = "^1.7.4"
|
||||||
bcrypt = "4.0.1"
|
bcrypt = "4.0.1"
|
||||||
python-jose = "^3.3.0"
|
python-jose = "^3.3.0"
|
||||||
metaphor-python = "^0.1.11"
|
metaphor-python = "^0.1.11"
|
||||||
pydantic = "^2.0.0"
|
pydantic = "^2.5.0"
|
||||||
pydantic-settings = "^2.0.3"
|
pydantic-settings = "^2.1.0"
|
||||||
zep-python = "*"
|
zep-python = "*"
|
||||||
pywin32 = { version = "^306", markers = "sys_platform == 'win32'" }
|
pywin32 = { version = "^306", markers = "sys_platform == 'win32'" }
|
||||||
loguru = "^0.7.1"
|
loguru = "^0.7.1"
|
||||||
|
|
@ -100,10 +100,11 @@ extract-msg = "^0.45.0"
|
||||||
jq = { version = "^1.6.0", markers = "sys_platform != 'win32'" }
|
jq = { version = "^1.6.0", markers = "sys_platform != 'win32'" }
|
||||||
boto3 = "^1.28.63"
|
boto3 = "^1.28.63"
|
||||||
numexpr = "^2.8.6"
|
numexpr = "^2.8.6"
|
||||||
qianfan = "0.0.5"
|
qianfan = "0.2.0"
|
||||||
pgvector = "^0.2.3"
|
pgvector = "^0.2.3"
|
||||||
pyautogen = "^0.2.0"
|
pyautogen = "^0.2.0"
|
||||||
langchain-google-genai = "^0.0.2"
|
langchain-google-genai = "^0.0.2"
|
||||||
|
pytube = "^15.0.0"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest-asyncio = "^0.23.1"
|
pytest-asyncio = "^0.23.1"
|
||||||
|
|
|
||||||
252
src/backend/langflow/components/llms/ChatOllamaEndpoint.py
Normal file
252
src/backend/langflow/components/llms/ChatOllamaEndpoint.py
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
# from langchain_community.chat_models import ChatOllama
|
||||||
|
from langchain.chat_models import ChatOllama
|
||||||
|
from langchain.chat_models.base import BaseChatModel
|
||||||
|
|
||||||
|
# from langchain.chat_models import ChatOllama
|
||||||
|
from langflow import CustomComponent
|
||||||
|
|
||||||
|
# whe When a callback component is added to Langflow, the comment must be uncommented.
|
||||||
|
# from langchain.callbacks.manager import CallbackManager
|
||||||
|
|
||||||
|
|
||||||
|
class ChatOllamaComponent(CustomComponent):
|
||||||
|
display_name = "ChatOllama"
|
||||||
|
description = "Local LLM for chat with Ollama."
|
||||||
|
|
||||||
|
def build_config(self) -> dict:
|
||||||
|
return {
|
||||||
|
"base_url": {
|
||||||
|
"display_name": "Base URL",
|
||||||
|
"info": "Endpoint of the Ollama API. Defaults to 'http://localhost:11434' if not specified.",
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"display_name": "Model Name",
|
||||||
|
"value": "llama2",
|
||||||
|
"info": "Refer to https://ollama.ai/library for more models.",
|
||||||
|
},
|
||||||
|
"temperature": {
|
||||||
|
"display_name": "Temperature",
|
||||||
|
"field_type": "float",
|
||||||
|
"value": 0.8,
|
||||||
|
"info": "Controls the creativity of model responses.",
|
||||||
|
},
|
||||||
|
"cache": {
|
||||||
|
"display_name": "Cache",
|
||||||
|
"field_type": "bool",
|
||||||
|
"info": "Enable or disable caching.",
|
||||||
|
"advanced": True,
|
||||||
|
"value": False,
|
||||||
|
},
|
||||||
|
### When a callback component is added to Langflow, the comment must be uncommented. ###
|
||||||
|
# "callback_manager": {
|
||||||
|
# "display_name": "Callback Manager",
|
||||||
|
# "info": "Optional callback manager for additional functionality.",
|
||||||
|
# "advanced": True,
|
||||||
|
# },
|
||||||
|
# "callbacks": {
|
||||||
|
# "display_name": "Callbacks",
|
||||||
|
# "info": "Callbacks to execute during model runtime.",
|
||||||
|
# "advanced": True,
|
||||||
|
# },
|
||||||
|
########################################################################################
|
||||||
|
"format": {
|
||||||
|
"display_name": "Format",
|
||||||
|
"field_type": "str",
|
||||||
|
"info": "Specify the format of the output (e.g., json).",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"display_name": "Metadata",
|
||||||
|
"info": "Metadata to add to the run trace.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"mirostat": {
|
||||||
|
"display_name": "Mirostat",
|
||||||
|
"options": ["Disabled", "Mirostat", "Mirostat 2.0"],
|
||||||
|
"info": "Enable/disable Mirostat sampling for controlling perplexity.",
|
||||||
|
"value": "Disabled",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"mirostat_eta": {
|
||||||
|
"display_name": "Mirostat Eta",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Learning rate for Mirostat algorithm. (Default: 0.1)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"mirostat_tau": {
|
||||||
|
"display_name": "Mirostat Tau",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Controls the balance between coherence and diversity of the output. (Default: 5.0)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"num_ctx": {
|
||||||
|
"display_name": "Context Window Size",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Size of the context window for generating tokens. (Default: 2048)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"num_gpu": {
|
||||||
|
"display_name": "Number of GPUs",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Number of GPUs to use for computation. (Default: 1 on macOS, 0 to disable)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"num_thread": {
|
||||||
|
"display_name": "Number of Threads",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Number of threads to use during computation. (Default: detected for optimal performance)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"repeat_last_n": {
|
||||||
|
"display_name": "Repeat Last N",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "How far back the model looks to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"repeat_penalty": {
|
||||||
|
"display_name": "Repeat Penalty",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Penalty for repetitions in generated text. (Default: 1.1)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"tfs_z": {
|
||||||
|
"display_name": "TFS Z",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Tail free sampling value. (Default: 1)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"timeout": {
|
||||||
|
"display_name": "Timeout",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Timeout for the request stream.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"top_k": {
|
||||||
|
"display_name": "Top K",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Limits token selection to top K. (Default: 40)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"top_p": {
|
||||||
|
"display_name": "Top P",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Works together with top-k. (Default: 0.9)",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"verbose": {
|
||||||
|
"display_name": "Verbose",
|
||||||
|
"field_type": "bool",
|
||||||
|
"info": "Whether to print out response text.",
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"display_name": "Tags",
|
||||||
|
"field_type": "list",
|
||||||
|
"info": "Tags to add to the run trace.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"stop": {
|
||||||
|
"display_name": "Stop Tokens",
|
||||||
|
"field_type": "list",
|
||||||
|
"info": "List of tokens to signal the model to stop generating text.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"display_name": "System",
|
||||||
|
"field_type": "str",
|
||||||
|
"info": "System to use for generating text.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"display_name": "Template",
|
||||||
|
"field_type": "str",
|
||||||
|
"info": "Template to use for generating text.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
base_url: Optional[str],
|
||||||
|
model: str,
|
||||||
|
mirostat: Optional[str],
|
||||||
|
mirostat_eta: Optional[float] = None,
|
||||||
|
mirostat_tau: Optional[float] = None,
|
||||||
|
### When a callback component is added to Langflow, the comment must be uncommented.###
|
||||||
|
# callback_manager: Optional[CallbackManager] = None,
|
||||||
|
# callbacks: Optional[List[Callbacks]] = None,
|
||||||
|
#######################################################################################
|
||||||
|
repeat_last_n: Optional[int] = None,
|
||||||
|
verbose: Optional[bool] = None,
|
||||||
|
cache: Optional[bool] = None,
|
||||||
|
num_ctx: Optional[int] = None,
|
||||||
|
num_gpu: Optional[int] = None,
|
||||||
|
format: Optional[str] = None,
|
||||||
|
metadata: Optional[Dict[str, Any]] = None,
|
||||||
|
num_thread: Optional[int] = None,
|
||||||
|
repeat_penalty: Optional[float] = None,
|
||||||
|
stop: Optional[List[str]] = None,
|
||||||
|
system: Optional[str] = None,
|
||||||
|
tags: Optional[List[str]] = None,
|
||||||
|
temperature: Optional[float] = None,
|
||||||
|
template: Optional[str] = None,
|
||||||
|
tfs_z: Optional[float] = None,
|
||||||
|
timeout: Optional[int] = None,
|
||||||
|
top_k: Optional[int] = None,
|
||||||
|
top_p: Optional[int] = None,
|
||||||
|
) -> BaseChatModel:
|
||||||
|
if not base_url:
|
||||||
|
base_url = "http://localhost:11434"
|
||||||
|
|
||||||
|
# Mapping mirostat settings to their corresponding values
|
||||||
|
mirostat_options = {"Mirostat": 1, "Mirostat 2.0": 2}
|
||||||
|
|
||||||
|
# Default to 0 for 'Disabled'
|
||||||
|
mirostat_value = mirostat_options.get(mirostat, 0) # type: ignore
|
||||||
|
|
||||||
|
# Set mirostat_eta and mirostat_tau to None if mirostat is disabled
|
||||||
|
if mirostat_value == 0:
|
||||||
|
mirostat_eta = None
|
||||||
|
mirostat_tau = None
|
||||||
|
|
||||||
|
# Mapping system settings to their corresponding values
|
||||||
|
llm_params = {
|
||||||
|
"base_url": base_url,
|
||||||
|
"cache": cache,
|
||||||
|
"model": model,
|
||||||
|
"mirostat": mirostat_value,
|
||||||
|
"format": format,
|
||||||
|
"metadata": metadata,
|
||||||
|
"tags": tags,
|
||||||
|
## When a callback component is added to Langflow, the comment must be uncommented.##
|
||||||
|
# "callback_manager": callback_manager,
|
||||||
|
# "callbacks": callbacks,
|
||||||
|
#####################################################################################
|
||||||
|
"mirostat_eta": mirostat_eta,
|
||||||
|
"mirostat_tau": mirostat_tau,
|
||||||
|
"num_ctx": num_ctx,
|
||||||
|
"num_gpu": num_gpu,
|
||||||
|
"num_thread": num_thread,
|
||||||
|
"repeat_last_n": repeat_last_n,
|
||||||
|
"repeat_penalty": repeat_penalty,
|
||||||
|
"temperature": temperature,
|
||||||
|
"stop": stop,
|
||||||
|
"system": system,
|
||||||
|
"template": template,
|
||||||
|
"tfs_z": tfs_z,
|
||||||
|
"timeout": timeout,
|
||||||
|
"top_k": top_k,
|
||||||
|
"top_p": top_p,
|
||||||
|
"verbose": verbose,
|
||||||
|
}
|
||||||
|
|
||||||
|
# None Value remove
|
||||||
|
llm_params = {k: v for k, v in llm_params.items() if v is not None}
|
||||||
|
|
||||||
|
try:
|
||||||
|
output = ChatOllama(**llm_params) # type: ignore
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Could not initialize Ollama LLM.") from e
|
||||||
|
|
||||||
|
return output # type: ignore
|
||||||
163
src/backend/langflow/components/llms/OllamaLLM.py
Normal file
163
src/backend/langflow/components/llms/OllamaLLM.py
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
from langchain.llms import Ollama
|
||||||
|
from langchain.llms.base import BaseLLM
|
||||||
|
|
||||||
|
from langflow import CustomComponent
|
||||||
|
|
||||||
|
|
||||||
|
class OllamaLLM(CustomComponent):
|
||||||
|
display_name = "Ollama"
|
||||||
|
description = "Local LLM with Ollama."
|
||||||
|
|
||||||
|
def build_config(self) -> dict:
|
||||||
|
return {
|
||||||
|
"base_url": {
|
||||||
|
"display_name": "Base URL",
|
||||||
|
"info": "Endpoint of the Ollama API. Defaults to 'http://localhost:11434' if not specified.",
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"display_name": "Model Name",
|
||||||
|
"value": "llama2",
|
||||||
|
"info": "Refer to https://ollama.ai/library for more models.",
|
||||||
|
},
|
||||||
|
"temperature": {
|
||||||
|
"display_name": "Temperature",
|
||||||
|
"field_type": "float",
|
||||||
|
"value": 0.8,
|
||||||
|
"info": "Controls the creativity of model responses.",
|
||||||
|
},
|
||||||
|
"mirostat": {
|
||||||
|
"display_name": "Mirostat",
|
||||||
|
"options": ["Disabled", "Mirostat", "Mirostat 2.0"],
|
||||||
|
"info": "Enable/disable Mirostat sampling for controlling perplexity.",
|
||||||
|
"value": "Disabled",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"mirostat_eta": {
|
||||||
|
"display_name": "Mirostat Eta",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Learning rate influencing the algorithm's response to feedback.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"mirostat_tau": {
|
||||||
|
"display_name": "Mirostat Tau",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Controls balance between coherence and diversity.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"num_ctx": {
|
||||||
|
"display_name": "Context Window Size",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Size of the context window for generating the next token.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"num_gpu": {
|
||||||
|
"display_name": "Number of GPUs",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Number of GPUs to use for computation.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"num_thread": {
|
||||||
|
"display_name": "Number of Threads",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Number of threads to use during computation.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"repeat_last_n": {
|
||||||
|
"display_name": "Repeat Last N",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Sets how far back the model looks to prevent repetition.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"repeat_penalty": {
|
||||||
|
"display_name": "Repeat Penalty",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Penalty for repetitions in generated text.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"stop": {
|
||||||
|
"display_name": "Stop Tokens",
|
||||||
|
"info": "List of tokens to signal the model to stop generating text.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"tfs_z": {
|
||||||
|
"display_name": "TFS Z",
|
||||||
|
"field_type": "float",
|
||||||
|
"info": "Tail free sampling to reduce impact of less probable tokens.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"top_k": {
|
||||||
|
"display_name": "Top K",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Limits token selection to top K for reducing nonsense generation.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
"top_p": {
|
||||||
|
"display_name": "Top P",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "Works with top-k to control diversity of generated text.",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
base_url: Optional[str],
|
||||||
|
model: str,
|
||||||
|
temperature: Optional[float],
|
||||||
|
mirostat: Optional[str],
|
||||||
|
mirostat_eta: Optional[float] = None,
|
||||||
|
mirostat_tau: Optional[float] = None,
|
||||||
|
num_ctx: Optional[int] = None,
|
||||||
|
num_gpu: Optional[int] = None,
|
||||||
|
num_thread: Optional[int] = None,
|
||||||
|
repeat_last_n: Optional[int] = None,
|
||||||
|
repeat_penalty: Optional[float] = None,
|
||||||
|
stop: Optional[List[str]] = None,
|
||||||
|
tfs_z: Optional[float] = None,
|
||||||
|
top_k: Optional[int] = None,
|
||||||
|
top_p: Optional[int] = None,
|
||||||
|
) -> BaseLLM:
|
||||||
|
if not base_url:
|
||||||
|
base_url = "http://localhost:11434"
|
||||||
|
|
||||||
|
# Mapping mirostat settings to their corresponding values
|
||||||
|
mirostat_options = {"Mirostat": 1, "Mirostat 2.0": 2}
|
||||||
|
|
||||||
|
# Default to 0 for 'Disabled'
|
||||||
|
mirostat_value = mirostat_options.get(mirostat, 0) # type: ignore
|
||||||
|
|
||||||
|
# Set mirostat_eta and mirostat_tau to None if mirostat is disabled
|
||||||
|
if mirostat_value == 0:
|
||||||
|
mirostat_eta = None
|
||||||
|
mirostat_tau = None
|
||||||
|
|
||||||
|
llm_params = {
|
||||||
|
"base_url": base_url,
|
||||||
|
"model": model,
|
||||||
|
"mirostat": mirostat_value,
|
||||||
|
"mirostat_eta": mirostat_eta,
|
||||||
|
"mirostat_tau": mirostat_tau,
|
||||||
|
"num_ctx": num_ctx,
|
||||||
|
"num_gpu": num_gpu,
|
||||||
|
"num_thread": num_thread,
|
||||||
|
"repeat_last_n": repeat_last_n,
|
||||||
|
"repeat_penalty": repeat_penalty,
|
||||||
|
"temperature": temperature,
|
||||||
|
"stop": stop,
|
||||||
|
"tfs_z": tfs_z,
|
||||||
|
"top_k": top_k,
|
||||||
|
"top_p": top_p,
|
||||||
|
}
|
||||||
|
|
||||||
|
# None Value remove
|
||||||
|
llm_params = {k: v for k, v in llm_params.items() if v is not None}
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
llm = Ollama(**llm_params)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Could not connect to Ollama.") from e
|
||||||
|
|
||||||
|
return llm
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
from typing import List
|
||||||
|
from langflow import CustomComponent
|
||||||
|
import json
|
||||||
|
from langchain.schema import BaseRetriever
|
||||||
|
from langchain.schema.vectorstore import VectorStore
|
||||||
|
from langchain.base_language import BaseLanguageModel
|
||||||
|
from langchain.retrievers.self_query.base import SelfQueryRetriever
|
||||||
|
from langchain.chains.query_constructor.base import AttributeInfo
|
||||||
|
|
||||||
|
|
||||||
|
class VectaraSelfQueryRetriverComponent(CustomComponent):
|
||||||
|
"""
|
||||||
|
A custom component for implementing Vectara Self Query Retriever using a vector store.
|
||||||
|
"""
|
||||||
|
|
||||||
|
display_name: str = "Vectara Self Query Retriever for Vectara Vector Store"
|
||||||
|
description: str = "Implementation of Vectara Self Query Retriever"
|
||||||
|
documentation = (
|
||||||
|
"https://python.langchain.com/docs/integrations/retrievers/self_query/vectara_self_query"
|
||||||
|
)
|
||||||
|
beta = True
|
||||||
|
|
||||||
|
field_config = {
|
||||||
|
"code": {"show": True},
|
||||||
|
"vectorstore": {
|
||||||
|
"display_name": "Vector Store",
|
||||||
|
"info": "Input Vectara Vectore Store"
|
||||||
|
},
|
||||||
|
"llm": {
|
||||||
|
"display_name": "LLM",
|
||||||
|
"info": "For self query retriever"
|
||||||
|
},
|
||||||
|
"document_content_description":{
|
||||||
|
"display_name": "Document Content Description",
|
||||||
|
"info": "For self query retriever",
|
||||||
|
},
|
||||||
|
"metadata_field_info": {
|
||||||
|
"display_name": "Metadata Field Info",
|
||||||
|
"info": "Each metadata field info is a string in the form of key value pair dictionary containing additional search metadata.\nExample input: {\"name\":\"speech\",\"description\":\"what name of the speech\",\"type\":\"string or list[string]\"}.\nThe keys should remain constant(name, description, type)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
vectorstore: VectorStore,
|
||||||
|
document_content_description: str,
|
||||||
|
llm: BaseLanguageModel,
|
||||||
|
metadata_field_info: List[str],
|
||||||
|
) -> BaseRetriever:
|
||||||
|
|
||||||
|
metadata_field_obj = []
|
||||||
|
|
||||||
|
for meta in metadata_field_info:
|
||||||
|
meta_obj = json.loads(meta)
|
||||||
|
if 'name' not in meta_obj or 'description' not in meta_obj or 'type' not in meta_obj :
|
||||||
|
raise Exception('Incorrect metadata field info format.')
|
||||||
|
attribute_info = AttributeInfo(
|
||||||
|
name = meta_obj['name'],
|
||||||
|
description = meta_obj['description'],
|
||||||
|
type = meta_obj['type'],
|
||||||
|
)
|
||||||
|
metadata_field_obj.append(attribute_info)
|
||||||
|
|
||||||
|
return SelfQueryRetriever.from_llm(
|
||||||
|
llm,
|
||||||
|
vectorstore,
|
||||||
|
document_content_description,
|
||||||
|
metadata_field_obj,
|
||||||
|
verbose=True
|
||||||
|
)
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union, List
|
||||||
|
|
||||||
from langchain.schema import BaseRetriever, Document
|
|
||||||
from langchain.vectorstores import Vectara
|
|
||||||
from langchain.vectorstores.base import VectorStore
|
|
||||||
|
|
||||||
from langflow import CustomComponent
|
from langflow import CustomComponent
|
||||||
|
import tempfile
|
||||||
|
import urllib.request
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from langchain.vectorstores import Vectara
|
||||||
|
from langchain.schema import Document
|
||||||
|
from langchain.vectorstores.base import VectorStore
|
||||||
|
from langchain.schema import BaseRetriever
|
||||||
|
from langchain.embeddings import FakeEmbeddings
|
||||||
|
|
||||||
|
|
||||||
class VectaraComponent(CustomComponent):
|
class VectaraComponent(CustomComponent):
|
||||||
|
|
@ -12,13 +16,29 @@ class VectaraComponent(CustomComponent):
|
||||||
description: str = "Implementation of Vector Store using Vectara"
|
description: str = "Implementation of Vector Store using Vectara"
|
||||||
documentation = "https://python.langchain.com/docs/integrations/vectorstores/vectara"
|
documentation = "https://python.langchain.com/docs/integrations/vectorstores/vectara"
|
||||||
beta = True
|
beta = True
|
||||||
# api key should be password = True
|
|
||||||
field_config = {
|
field_config = {
|
||||||
"vectara_customer_id": {"display_name": "Vectara Customer ID"},
|
"vectara_customer_id": {
|
||||||
"vectara_corpus_id": {"display_name": "Vectara Corpus ID"},
|
"display_name": "Vectara Customer ID",
|
||||||
"vectara_api_key": {"display_name": "Vectara API Key", "password": True},
|
"required": True,
|
||||||
|
},
|
||||||
|
"vectara_corpus_id": {
|
||||||
|
"display_name": "Vectara Corpus ID",
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
|
"vectara_api_key": {
|
||||||
|
"display_name": "Vectara API Key",
|
||||||
|
"password": True,
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
"code": {"show": False},
|
"code": {"show": False},
|
||||||
"documents": {"display_name": "Documents"},
|
"documents": {
|
||||||
|
"display_name": "Documents",
|
||||||
|
"info": "Pass in either for Self Query Retriever or for making a Vectara Object",
|
||||||
|
},
|
||||||
|
"files_url": {
|
||||||
|
"display_name": "Files Url",
|
||||||
|
"info": "Make vectara object using url of files(documents not needed)",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(
|
def build(
|
||||||
|
|
@ -26,21 +46,35 @@ class VectaraComponent(CustomComponent):
|
||||||
vectara_customer_id: str,
|
vectara_customer_id: str,
|
||||||
vectara_corpus_id: str,
|
vectara_corpus_id: str,
|
||||||
vectara_api_key: str,
|
vectara_api_key: str,
|
||||||
|
files_url: Optional[List[str]] = None,
|
||||||
documents: Optional[Document] = None,
|
documents: Optional[Document] = None,
|
||||||
) -> Union[VectorStore, BaseRetriever]:
|
) -> Union[VectorStore, BaseRetriever]:
|
||||||
# If documents, then we need to create a Vectara instance using .from_documents
|
|
||||||
if documents is not None:
|
if documents is not None:
|
||||||
return Vectara.from_documents(
|
return Vectara.from_documents(
|
||||||
documents=documents, # type: ignore
|
documents=documents,
|
||||||
|
embedding=FakeEmbeddings(size=768),
|
||||||
|
vectara_customer_id=vectara_customer_id,
|
||||||
|
vectara_corpus_id=vectara_corpus_id,
|
||||||
|
vectara_api_key=vectara_api_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
if files_url is not None:
|
||||||
|
files_list = []
|
||||||
|
for url in files_url:
|
||||||
|
name = tempfile.NamedTemporaryFile().name
|
||||||
|
urllib.request.urlretrieve(url, name)
|
||||||
|
files_list.append(name)
|
||||||
|
|
||||||
|
return Vectara.from_files(
|
||||||
|
files=files_list,
|
||||||
|
embedding=FakeEmbeddings(size=768),
|
||||||
vectara_customer_id=vectara_customer_id,
|
vectara_customer_id=vectara_customer_id,
|
||||||
vectara_corpus_id=vectara_corpus_id,
|
vectara_corpus_id=vectara_corpus_id,
|
||||||
vectara_api_key=vectara_api_key,
|
vectara_api_key=vectara_api_key,
|
||||||
source="langflow",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return Vectara(
|
return Vectara(
|
||||||
vectara_customer_id=vectara_customer_id,
|
vectara_customer_id=vectara_customer_id,
|
||||||
vectara_corpus_id=vectara_corpus_id,
|
vectara_corpus_id=vectara_corpus_id,
|
||||||
vectara_api_key=vectara_api_key,
|
vectara_api_key=vectara_api_key,
|
||||||
source="langflow",
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,12 @@ import inspect
|
||||||
import types
|
import types
|
||||||
from typing import TYPE_CHECKING, Any, Coroutine, Dict, List, Optional
|
from typing import TYPE_CHECKING, Any, Coroutine, Dict, List, Optional
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from langflow.graph.utils import UnbuiltObject
|
from langflow.graph.utils import UnbuiltObject
|
||||||
from langflow.interface.initialize import loading
|
from langflow.interface.initialize import loading
|
||||||
from langflow.interface.listing import lazy_load_dict
|
from langflow.interface.listing import lazy_load_dict
|
||||||
from langflow.utils.constants import DIRECT_TYPES
|
from langflow.utils.constants import DIRECT_TYPES
|
||||||
from langflow.utils.util import sync_to_async
|
from langflow.utils.util import sync_to_async
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.graph.edge.base import Edge
|
from langflow.graph.edge.base import Edge
|
||||||
|
|
@ -140,7 +139,11 @@ class Vertex:
|
||||||
if not hasattr(edge, "target_param"):
|
if not hasattr(edge, "target_param"):
|
||||||
continue
|
continue
|
||||||
param_key = edge.target_param
|
param_key = edge.target_param
|
||||||
if param_key in template_dict:
|
|
||||||
|
# If the param_key is in the template_dict and the edge.target_id is the current node
|
||||||
|
# We check this to make sure params with the same name but different target_id
|
||||||
|
# don't get overwritten
|
||||||
|
if param_key in template_dict and edge.target_id == self.id:
|
||||||
if template_dict[param_key]["list"]:
|
if template_dict[param_key]["list"]:
|
||||||
if param_key not in params:
|
if param_key not in params:
|
||||||
params[param_key] = []
|
params[param_key] = []
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ export default function Dropdown({
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{Object.keys(options)?.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<Listbox
|
<Listbox
|
||||||
value={internalValue}
|
value={internalValue}
|
||||||
|
|
@ -71,7 +73,7 @@ export default function Dropdown({
|
||||||
apiModal ? "mb-2 w-[250px]" : "absolute w-full"
|
apiModal ? "mb-2 w-[250px]" : "absolute w-full"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{options.map((option, id) => (
|
{options?.map((option, id) => (
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
key={id}
|
key={id}
|
||||||
className={({ active }) =>
|
className={({ active }) =>
|
||||||
|
|
@ -125,5 +127,15 @@ export default function Dropdown({
|
||||||
)}
|
)}
|
||||||
</Listbox>
|
</Listbox>
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<span className="text-sm italic">
|
||||||
|
No parameters are available for display.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,14 @@ export default function ChatInput({
|
||||||
: "hidden"
|
: "hidden"
|
||||||
}`,
|
}`,
|
||||||
}}
|
}}
|
||||||
value={lockChat ? "Thinking..." : chatValue}
|
value={
|
||||||
|
lockChat
|
||||||
|
? "Thinking..."
|
||||||
|
: typeof chatValue === "object" &&
|
||||||
|
Object.keys(chatValue)?.length === 0
|
||||||
|
? "No chat input variables found. Click to run your flow."
|
||||||
|
: chatValue
|
||||||
|
}
|
||||||
onChange={(event): void => {
|
onChange={(event): void => {
|
||||||
setChatValue(event.target.value);
|
setChatValue(event.target.value);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import Convert from "ansi-to-html";
|
import Convert from "ansi-to-html";
|
||||||
import { useMemo, useState } from "react";
|
import { useState } from "react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import rehypeMathjax from "rehype-mathjax";
|
import rehypeMathjax from "rehype-mathjax";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
|
|
@ -74,9 +74,7 @@ export default function ChatMessage({
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full dark:text-white">
|
<div className="w-full dark:text-white">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
{useMemo(
|
{chat.message.toString() === "" && lockChat ? (
|
||||||
() =>
|
|
||||||
chat.message.toString() === "" && lockChat ? (
|
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="MoreHorizontal"
|
name="MoreHorizontal"
|
||||||
className="h-8 w-8 animate-pulse"
|
className="h-8 w-8 animate-pulse"
|
||||||
|
|
@ -113,9 +111,7 @@ export default function ChatMessage({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const match = /language-(\w+)/.exec(
|
const match = /language-(\w+)/.exec(className || "");
|
||||||
className || ""
|
|
||||||
);
|
|
||||||
|
|
||||||
return !inline ? (
|
return !inline ? (
|
||||||
<CodeTabsComponent
|
<CodeTabsComponent
|
||||||
|
|
@ -143,8 +139,6 @@ export default function ChatMessage({
|
||||||
>
|
>
|
||||||
{chat.message.toString()}
|
{chat.message.toString()}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
),
|
|
||||||
[chat.message, chat.message.toString()]
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{chat.files && (
|
{chat.files && (
|
||||||
|
|
|
||||||
|
|
@ -146,13 +146,14 @@ export default function FormModal({
|
||||||
newChat[newChat.length - 1].message + str;
|
newChat[newChat.length - 1].message + str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (thought) {
|
|
||||||
|
if (thought && newChat[newChat.length - 1]?.thought) {
|
||||||
newChat[newChat.length - 1].thought = thought;
|
newChat[newChat.length - 1].thought = thought;
|
||||||
}
|
}
|
||||||
if (files) {
|
if (files && newChat[newChat.length - 1]?.files) {
|
||||||
newChat[newChat.length - 1].files = files;
|
newChat[newChat.length - 1].files = files;
|
||||||
}
|
}
|
||||||
if (prompt) {
|
if (prompt && newChat[newChat.length - 2]?.template) {
|
||||||
newChat[newChat.length - 2].template = prompt;
|
newChat[newChat.length - 2].template = prompt;
|
||||||
}
|
}
|
||||||
return newChat;
|
return newChat;
|
||||||
|
|
|
||||||
|
|
@ -122,25 +122,22 @@ export default function GenericModal({
|
||||||
}
|
}
|
||||||
if (apiReturn.data) {
|
if (apiReturn.data) {
|
||||||
let inputVariables = apiReturn.data.input_variables ?? [];
|
let inputVariables = apiReturn.data.input_variables ?? [];
|
||||||
if (!inputVariables || inputVariables.length === 0) {
|
|
||||||
setIsEdit(true);
|
|
||||||
setNoticeData({
|
|
||||||
title: "Your template does not have any variables.",
|
|
||||||
});
|
|
||||||
setModalOpen(false);
|
|
||||||
} else {
|
|
||||||
if (
|
if (
|
||||||
JSON.stringify(apiReturn.data?.frontend_node) !==
|
JSON.stringify(apiReturn.data?.frontend_node) !== JSON.stringify({})
|
||||||
JSON.stringify({})
|
|
||||||
) {
|
) {
|
||||||
setNodeClass!(apiReturn.data?.frontend_node, inputValue);
|
setNodeClass!(apiReturn.data?.frontend_node, inputValue);
|
||||||
setModalOpen(closeModal);
|
setModalOpen(closeModal);
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
|
}
|
||||||
|
if (!inputVariables || inputVariables.length === 0) {
|
||||||
|
setNoticeData({
|
||||||
|
title: "Your template does not have any variables.",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Prompt is ready",
|
title: "Prompt is ready",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setIsEdit(true);
|
setIsEdit(true);
|
||||||
setErrorData({
|
setErrorData({
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue