Merge branch 'logspace-ai:dev' into Add-Ollama-LLM
This commit is contained in:
commit
6c0b4fb416
23 changed files with 833 additions and 650 deletions
3
.github/workflows/pre-release.yml
vendored
3
.github/workflows/pre-release.yml
vendored
|
|
@ -8,6 +8,7 @@ on:
|
||||||
- dev
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
POETRY_VERSION: "1.5.1"
|
POETRY_VERSION: "1.5.1"
|
||||||
|
|
@ -40,7 +41,7 @@ jobs:
|
||||||
generateReleaseNotes: true
|
generateReleaseNotes: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
tag: v${{ steps.check-version.outputs.version }}
|
tag: v${{ steps.check-version.outputs.version }}
|
||||||
commit: main
|
commit: dev
|
||||||
- name: Publish to PyPI
|
- name: Publish to PyPI
|
||||||
env:
|
env:
|
||||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
|
|
|
||||||
1005
poetry.lock
generated
1005
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.3a5"
|
version = "0.6.3"
|
||||||
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 = [
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from fastapi import (APIRouter, Depends, HTTPException, Query, WebSocket,
|
from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSocketException, status
|
||||||
WebSocketException, status)
|
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from langflow.api.utils import build_input_keys_response, format_elapsed_time
|
from langflow.api.utils import build_input_keys_response, format_elapsed_time
|
||||||
from langflow.api.v1.schemas import (BuildStatus, BuiltResponse, InitResponse,
|
from langflow.api.v1.schemas import BuildStatus, BuiltResponse, InitResponse, StreamData
|
||||||
StreamData)
|
|
||||||
from langflow.graph.graph.base import Graph
|
from langflow.graph.graph.base import Graph
|
||||||
from langflow.services.auth.utils import (get_current_active_user,
|
from langflow.services.auth.utils import get_current_active_user, get_current_user_by_jwt
|
||||||
get_current_user_by_jwt)
|
|
||||||
from langflow.services.cache.service import BaseCacheService
|
from langflow.services.cache.service import BaseCacheService
|
||||||
from langflow.services.cache.utils import update_build_status
|
from langflow.services.cache.utils import update_build_status
|
||||||
from langflow.services.chat.service import ChatService
|
from langflow.services.chat.service import ChatService
|
||||||
from langflow.services.deps import (get_cache_service, get_chat_service,
|
from langflow.services.deps import get_cache_service, get_chat_service, get_session
|
||||||
get_session)
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Annotated, List, Optional, Union
|
from typing import Annotated, Any, List, Optional, Union
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from fastapi import APIRouter, Body, Depends, HTTPException, UploadFile, status
|
from fastapi import APIRouter, Body, Depends, HTTPException, UploadFile, status
|
||||||
|
|
@ -16,7 +16,7 @@ from langflow.api.v1.schemas import (
|
||||||
)
|
)
|
||||||
from langflow.interface.custom.custom_component import CustomComponent
|
from langflow.interface.custom.custom_component import CustomComponent
|
||||||
from langflow.interface.custom.directory_reader import DirectoryReader
|
from langflow.interface.custom.directory_reader import DirectoryReader
|
||||||
from langflow.interface.custom.utils import build_custom_component_template, create_and_validate_component
|
from langflow.interface.custom.utils import build_custom_component_template
|
||||||
from langflow.processing.process import process_graph_cached, process_tweaks
|
from langflow.processing.process import process_graph_cached, process_tweaks
|
||||||
from langflow.services.auth.utils import api_key_security, get_current_active_user
|
from langflow.services.auth.utils import api_key_security, get_current_active_user
|
||||||
from langflow.services.cache.utils import save_uploaded_file
|
from langflow.services.cache.utils import save_uploaded_file
|
||||||
|
|
@ -49,7 +49,7 @@ async def process_graph_data(
|
||||||
task_service: "TaskService" = Depends(get_task_service),
|
task_service: "TaskService" = Depends(get_task_service),
|
||||||
sync: bool = True,
|
sync: bool = True,
|
||||||
):
|
):
|
||||||
task_result = None
|
task_result: Any = None
|
||||||
task_status = None
|
task_status = None
|
||||||
if tweaks:
|
if tweaks:
|
||||||
try:
|
try:
|
||||||
|
|
@ -270,7 +270,7 @@ async def custom_component(
|
||||||
raw_code: CustomComponentCode,
|
raw_code: CustomComponentCode,
|
||||||
user: User = Depends(get_current_active_user),
|
user: User = Depends(get_current_active_user),
|
||||||
):
|
):
|
||||||
component = create_and_validate_component(raw_code.code)
|
component = CustomComponent(code=raw_code.code)
|
||||||
|
|
||||||
built_frontend_node = build_custom_component_template(component, user_id=user.id)
|
built_frontend_node = build_custom_component_template(component, user_id=user.id)
|
||||||
|
|
||||||
|
|
@ -289,7 +289,6 @@ async def reload_custom_component(path: str, user: User = Depends(get_current_ac
|
||||||
raise ValueError(content)
|
raise ValueError(content)
|
||||||
|
|
||||||
extractor = CustomComponent(code=content)
|
extractor = CustomComponent(code=content)
|
||||||
extractor.validate()
|
|
||||||
return build_custom_component_template(extractor, user_id=user.id)
|
return build_custom_component_template(extractor, user_id=user.id)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise HTTPException(status_code=400, detail=str(exc))
|
raise HTTPException(status_code=400, detail=str(exc))
|
||||||
|
|
@ -300,7 +299,7 @@ async def custom_component_update(
|
||||||
raw_code: CustomComponentCode,
|
raw_code: CustomComponentCode,
|
||||||
user: User = Depends(get_current_active_user),
|
user: User = Depends(get_current_active_user),
|
||||||
):
|
):
|
||||||
component = create_and_validate_component(raw_code.code)
|
component = CustomComponent(code=raw_code.code)
|
||||||
|
|
||||||
component_node = build_custom_component_template(component, user_id=user.id, update_field=raw_code.field)
|
component_node = build_custom_component_template(component, user_id=user.id, update_field=raw_code.field)
|
||||||
# Update the field
|
# Update the field
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from typing import Callable, List, Union
|
from typing import Callable, List, Optional, Union
|
||||||
|
|
||||||
from langchain.agents import AgentExecutor, AgentType, initialize_agent, types
|
from langchain.agents import AgentExecutor, AgentType, initialize_agent, types
|
||||||
|
|
||||||
from langflow import CustomComponent
|
from langflow import CustomComponent
|
||||||
from langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool
|
from langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool
|
||||||
|
|
||||||
|
|
@ -20,18 +19,34 @@ class AgentInitializerComponent(CustomComponent):
|
||||||
"memory": {"display_name": "Memory"},
|
"memory": {"display_name": "Memory"},
|
||||||
"tools": {"display_name": "Tools"},
|
"tools": {"display_name": "Tools"},
|
||||||
"llm": {"display_name": "Language Model"},
|
"llm": {"display_name": "Language Model"},
|
||||||
|
"code": {"advanced": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(
|
def build(
|
||||||
self, agent: str, llm: BaseLanguageModel, memory: BaseChatMemory, tools: List[Tool], max_iterations: int
|
self,
|
||||||
|
agent: str,
|
||||||
|
llm: BaseLanguageModel,
|
||||||
|
tools: List[Tool],
|
||||||
|
max_iterations: int,
|
||||||
|
memory: Optional[BaseChatMemory] = None,
|
||||||
) -> Union[AgentExecutor, Callable]:
|
) -> Union[AgentExecutor, Callable]:
|
||||||
agent = AgentType(agent)
|
agent = AgentType(agent)
|
||||||
return initialize_agent(
|
if memory:
|
||||||
tools=tools,
|
return initialize_agent(
|
||||||
llm=llm,
|
tools=tools,
|
||||||
agent=agent,
|
llm=llm,
|
||||||
memory=memory,
|
agent=agent,
|
||||||
return_intermediate_steps=True,
|
memory=memory,
|
||||||
handle_parsing_errors=True,
|
return_intermediate_steps=True,
|
||||||
max_iterations=max_iterations,
|
handle_parsing_errors=True,
|
||||||
)
|
max_iterations=max_iterations,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return initialize_agent(
|
||||||
|
tools=tools,
|
||||||
|
llm=llm,
|
||||||
|
agent=agent,
|
||||||
|
return_intermediate_steps=True,
|
||||||
|
handle_parsing_errors=True,
|
||||||
|
max_iterations=max_iterations,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from langflow import CustomComponent
|
||||||
from langchain.llms.base import BaseLanguageModel
|
from langchain.llms.base import BaseLanguageModel
|
||||||
from langchain.chat_models.azure_openai import AzureChatOpenAI
|
from langchain.chat_models.azure_openai import AzureChatOpenAI
|
||||||
|
|
||||||
|
|
||||||
class AzureChatOpenAIComponent(CustomComponent):
|
class AzureChatOpenAIComponent(CustomComponent):
|
||||||
display_name: str = "AzureChatOpenAI"
|
display_name: str = "AzureChatOpenAI"
|
||||||
description: str = "LLM model from Azure OpenAI."
|
description: str = "LLM model from Azure OpenAI."
|
||||||
|
|
@ -28,7 +29,7 @@ class AzureChatOpenAIComponent(CustomComponent):
|
||||||
"azure_endpoint": {
|
"azure_endpoint": {
|
||||||
"display_name": "Azure Endpoint",
|
"display_name": "Azure Endpoint",
|
||||||
"required": True,
|
"required": True,
|
||||||
"info": "Your Azure endpoint, including the resource.. Example: `https://example-resource.azure.openai.com/`"
|
"info": "Your Azure endpoint, including the resource.. Example: `https://example-resource.azure.openai.com/`",
|
||||||
},
|
},
|
||||||
"azure_deployment": {
|
"azure_deployment": {
|
||||||
"display_name": "Deployment Name",
|
"display_name": "Deployment Name",
|
||||||
|
|
@ -40,18 +41,14 @@ class AzureChatOpenAIComponent(CustomComponent):
|
||||||
"required": True,
|
"required": True,
|
||||||
"advanced": True,
|
"advanced": True,
|
||||||
},
|
},
|
||||||
"api_key": {
|
"api_key": {"display_name": "API Key", "required": True, "password": True},
|
||||||
"display_name": "API Key",
|
|
||||||
"required": True,
|
|
||||||
"password": True
|
|
||||||
},
|
|
||||||
"temperature": {
|
"temperature": {
|
||||||
"display_name": "Temperature",
|
"display_name": "Temperature",
|
||||||
"value": 0.7,
|
"value": 0.7,
|
||||||
"field_type": "float",
|
"field_type": "float",
|
||||||
"required": False,
|
"required": False,
|
||||||
},
|
},
|
||||||
"max_tokens": {
|
"max_tokens": {
|
||||||
"display_name": "Max Tokens",
|
"display_name": "Max Tokens",
|
||||||
"value": 1000,
|
"value": 1000,
|
||||||
"required": False,
|
"required": False,
|
||||||
|
|
@ -71,8 +68,6 @@ class AzureChatOpenAIComponent(CustomComponent):
|
||||||
temperature: float = 0.7,
|
temperature: float = 0.7,
|
||||||
max_tokens: Optional[int] = 1000,
|
max_tokens: Optional[int] = 1000,
|
||||||
) -> BaseLanguageModel:
|
) -> BaseLanguageModel:
|
||||||
|
|
||||||
|
|
||||||
return AzureChatOpenAI(
|
return AzureChatOpenAI(
|
||||||
model=model,
|
model=model,
|
||||||
azure_endpoint=azure_endpoint,
|
azure_endpoint=azure_endpoint,
|
||||||
|
|
@ -80,5 +75,5 @@ class AzureChatOpenAIComponent(CustomComponent):
|
||||||
api_version=api_version,
|
api_version=api_version,
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
temperature=temperature,
|
temperature=temperature,
|
||||||
max_tokens=max_tokens
|
max_tokens=max_tokens,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import weaviate # type: ignore
|
import weaviate # type: ignore
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
from langflow import CustomComponent
|
from langflow import CustomComponent
|
||||||
|
|
||||||
|
|
@ -12,18 +12,29 @@ from langchain.embeddings.base import Embeddings
|
||||||
class WeaviateVectorStore(CustomComponent):
|
class WeaviateVectorStore(CustomComponent):
|
||||||
display_name: str = "Weaviate"
|
display_name: str = "Weaviate"
|
||||||
description: str = "Implementation of Vector Store using Weaviate"
|
description: str = "Implementation of Vector Store using Weaviate"
|
||||||
documentation = (
|
documentation = "https://python.langchain.com/docs/integrations/vectorstores/weaviate"
|
||||||
"https://python.langchain.com/docs/integrations/vectorstores/weaviate"
|
|
||||||
)
|
|
||||||
beta = True
|
beta = True
|
||||||
field_config = {
|
field_config = {
|
||||||
"url": {"display_name": "Weaviate URL", "value": "http://localhost:8080"},
|
"url": {"display_name": "Weaviate URL", "value": "http://localhost:8080"},
|
||||||
"api_key": { "display_name": "API Key", "password": True,"required": False, },
|
"api_key": {
|
||||||
"index_name": {"display_name": "Index name","required": False,},
|
"display_name": "API Key",
|
||||||
"text_key": {"display_name": "Text Key","required": False, "advanced": True, "value": "text"},
|
"password": True,
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
"index_name": {
|
||||||
|
"display_name": "Index name",
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
"text_key": {"display_name": "Text Key", "required": False, "advanced": True, "value": "text"},
|
||||||
"documents": {"display_name": "Documents", "is_list": True},
|
"documents": {"display_name": "Documents", "is_list": True},
|
||||||
"embedding": {"display_name": "Embedding"},
|
"embedding": {"display_name": "Embedding"},
|
||||||
"attributes": {"display_name": "Attributes", "required": False, "is_list": True, "field_type": "str", "advanced": True},
|
"attributes": {
|
||||||
|
"display_name": "Attributes",
|
||||||
|
"required": False,
|
||||||
|
"is_list": True,
|
||||||
|
"field_type": "str",
|
||||||
|
"advanced": True,
|
||||||
|
},
|
||||||
"search_by_text": {"display_name": "Search By Text", "field_type": "bool", "advanced": True},
|
"search_by_text": {"display_name": "Search By Text", "field_type": "bool", "advanced": True},
|
||||||
"code": {"show": False},
|
"code": {"show": False},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import Any, List, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from langchain.agents import AgentExecutor, AgentType, Tool, ZeroShotAgent, initialize_agent
|
from langchain.agents import AgentExecutor, ZeroShotAgent
|
||||||
from langchain.agents.agent_toolkits import (
|
from langchain.agents.agent_toolkits import (
|
||||||
SQLDatabaseToolkit,
|
SQLDatabaseToolkit,
|
||||||
VectorStoreInfo,
|
VectorStoreInfo,
|
||||||
|
|
@ -15,7 +15,6 @@ from langchain.agents.agent_toolkits.vectorstore.prompt import ROUTER_PREFIX as
|
||||||
from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS
|
from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS
|
||||||
from langchain.base_language import BaseLanguageModel
|
from langchain.base_language import BaseLanguageModel
|
||||||
from langchain.chains.llm import LLMChain
|
from langchain.chains.llm import LLMChain
|
||||||
from langchain.memory.chat_memory import BaseChatMemory
|
|
||||||
from langchain.sql_database import SQLDatabase
|
from langchain.sql_database import SQLDatabase
|
||||||
from langchain.tools.sql_database.prompt import QUERY_CHECKER
|
from langchain.tools.sql_database.prompt import QUERY_CHECKER
|
||||||
from langchain_experimental.agents.agent_toolkits.pandas.prompt import PREFIX as PANDAS_PREFIX
|
from langchain_experimental.agents.agent_toolkits.pandas.prompt import PREFIX as PANDAS_PREFIX
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ from typing import Any, Dict, List, Type, Union
|
||||||
|
|
||||||
from cachetools import TTLCache, cachedmethod, keys
|
from cachetools import TTLCache, cachedmethod, keys
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from langflow.interface.custom.schema import (CallableCodeDetails,
|
from langflow.interface.custom.schema import CallableCodeDetails, ClassCodeDetails
|
||||||
ClassCodeDetails)
|
|
||||||
|
|
||||||
|
|
||||||
class CodeSyntaxError(HTTPException):
|
class CodeSyntaxError(HTTPException):
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@ from uuid import UUID
|
||||||
import yaml
|
import yaml
|
||||||
from cachetools import TTLCache, cachedmethod
|
from cachetools import TTLCache, cachedmethod
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from langflow.interface.custom.code_parser.utils import (
|
from langflow.interface.custom.code_parser.utils import (
|
||||||
extract_inner_type_from_generic_alias,
|
extract_inner_type_from_generic_alias,
|
||||||
extract_union_types_from_generic_alias)
|
extract_union_types_from_generic_alias,
|
||||||
from langflow.interface.custom.directory_reader import DirectoryReader
|
)
|
||||||
from langflow.services.database.models.flow import Flow
|
from langflow.services.database.models.flow import Flow
|
||||||
from langflow.services.database.utils import session_getter
|
from langflow.services.database.utils import session_getter
|
||||||
from langflow.services.deps import get_credential_service, get_db_service
|
from langflow.services.deps import get_credential_service, get_db_service
|
||||||
|
|
@ -46,34 +47,6 @@ class CustomComponent(Component):
|
||||||
def build_config(self):
|
def build_config(self):
|
||||||
return self.field_config
|
return self.field_config
|
||||||
|
|
||||||
def _class_template_validation(self, code: str):
|
|
||||||
TYPE_HINT_LIST = ["Optional", "Prompt", "PromptTemplate", "LLMChain"]
|
|
||||||
|
|
||||||
if not code:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=400,
|
|
||||||
detail={
|
|
||||||
"error": self.ERROR_CODE_NULL,
|
|
||||||
"traceback": "",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
reader = DirectoryReader("", False)
|
|
||||||
|
|
||||||
for type_hint in TYPE_HINT_LIST:
|
|
||||||
if reader._is_type_hint_used_in_args(type_hint, code) and not reader._is_type_hint_imported(
|
|
||||||
type_hint, code
|
|
||||||
):
|
|
||||||
error_detail = {
|
|
||||||
"error": "Type hint Error",
|
|
||||||
"traceback": f"Type hint '{type_hint}' is used but not imported in the code.",
|
|
||||||
}
|
|
||||||
raise HTTPException(status_code=400, detail=error_detail)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def validate(self) -> bool:
|
|
||||||
return self._class_template_validation(self.code) if self.code else False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tree(self):
|
def tree(self):
|
||||||
return self.get_code_tree(self.code or "")
|
return self.get_code_tree(self.code or "")
|
||||||
|
|
@ -206,8 +179,7 @@ class CustomComponent(Component):
|
||||||
return validate.create_function(self.code, self.function_entrypoint_name)
|
return validate.create_function(self.code, self.function_entrypoint_name)
|
||||||
|
|
||||||
async def load_flow(self, flow_id: str, tweaks: Optional[dict] = None) -> Any:
|
async def load_flow(self, flow_id: str, tweaks: Optional[dict] = None) -> Any:
|
||||||
from langflow.processing.process import (build_sorted_vertices,
|
from langflow.processing.process import build_sorted_vertices, process_tweaks
|
||||||
process_tweaks)
|
|
||||||
|
|
||||||
db_service = get_db_service()
|
db_service = get_db_service()
|
||||||
with session_getter(db_service) as session:
|
with session_getter(db_service) as session:
|
||||||
|
|
|
||||||
|
|
@ -65,12 +65,13 @@ class DirectoryReader:
|
||||||
|
|
||||||
def filter_loaded_components(self, data: dict, with_errors: bool) -> dict:
|
def filter_loaded_components(self, data: dict, with_errors: bool) -> dict:
|
||||||
from langflow.interface.custom.utils import build_component
|
from langflow.interface.custom.utils import build_component
|
||||||
|
|
||||||
items = [
|
items = [
|
||||||
{
|
{
|
||||||
"name": menu["name"],
|
"name": menu["name"],
|
||||||
"path": menu["path"],
|
"path": menu["path"],
|
||||||
"components": [
|
"components": [
|
||||||
(*build_component(component),component)
|
(*build_component(component), component)
|
||||||
for component in menu["components"]
|
for component in menu["components"]
|
||||||
if (component["error"] if with_errors else not component["error"])
|
if (component["error"] if with_errors else not component["error"])
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
from langflow.interface.custom.directory_reader import DirectoryReader
|
from langflow.interface.custom.directory_reader import DirectoryReader
|
||||||
from langflow.template.frontend_node.custom_components import \
|
from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode
|
||||||
CustomComponentFrontendNode
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -75,10 +74,9 @@ def create_invalid_component_template(component, component_name):
|
||||||
"""Create a template for an invalid component."""
|
"""Create a template for an invalid component."""
|
||||||
component_code = component["code"]
|
component_code = component["code"]
|
||||||
component_frontend_node = CustomComponentFrontendNode(
|
component_frontend_node = CustomComponentFrontendNode(
|
||||||
description="ERROR - Check your Python Code",
|
description="ERROR - Check your Python Code",
|
||||||
display_name=f"ERROR - {component_name}",
|
display_name=f"ERROR - {component_name}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
component_frontend_node.error = component.get("error", None)
|
component_frontend_node.error = component.get("error", None)
|
||||||
field = component_frontend_node.template.get_field("code")
|
field = component_frontend_node.template.get_field("code")
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,20 @@ from typing import Any, Dict, List, Optional, Union
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from langflow.field_typing.range_spec import RangeSpec
|
from langflow.field_typing.range_spec import RangeSpec
|
||||||
from langflow.interface.custom.code_parser.utils import extract_inner_type
|
from langflow.interface.custom.code_parser.utils import extract_inner_type
|
||||||
from langflow.interface.custom.custom_component import CustomComponent
|
from langflow.interface.custom.custom_component import CustomComponent
|
||||||
from langflow.interface.custom.directory_reader.utils import (
|
from langflow.interface.custom.directory_reader.utils import (
|
||||||
build_custom_component_list_from_path, determine_component_name,
|
build_custom_component_list_from_path,
|
||||||
merge_nested_dicts_with_renaming)
|
determine_component_name,
|
||||||
|
merge_nested_dicts_with_renaming,
|
||||||
|
)
|
||||||
from langflow.interface.importing.utils import eval_custom_component_code
|
from langflow.interface.importing.utils import eval_custom_component_code
|
||||||
from langflow.template.field.base import TemplateField
|
from langflow.template.field.base import TemplateField
|
||||||
from langflow.template.frontend_node.custom_components import \
|
from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode
|
||||||
CustomComponentFrontendNode
|
|
||||||
from langflow.utils.util import get_base_classes
|
from langflow.utils.util import get_base_classes
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
|
|
||||||
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]):
|
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]):
|
||||||
|
|
@ -174,9 +176,7 @@ def get_field_dict(field: Union[TemplateField, dict]):
|
||||||
return field
|
return field
|
||||||
|
|
||||||
|
|
||||||
def run_build_config(
|
def run_build_config(custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None, update_field=None):
|
||||||
custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None, update_field=None
|
|
||||||
):
|
|
||||||
"""Build the field configuration for a custom component"""
|
"""Build the field configuration for a custom component"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -311,7 +311,6 @@ def create_component_template(component):
|
||||||
component_output_types = component["output_types"]
|
component_output_types = component["output_types"]
|
||||||
|
|
||||||
component_extractor = CustomComponent(code=component_code)
|
component_extractor = CustomComponent(code=component_code)
|
||||||
component_extractor.validate()
|
|
||||||
|
|
||||||
component_template = build_custom_component_template(component_extractor)
|
component_template = build_custom_component_template(component_extractor)
|
||||||
component_template["output_types"] = component_output_types
|
component_template["output_types"] = component_output_types
|
||||||
|
|
@ -343,12 +342,6 @@ def build_custom_components(settings_service):
|
||||||
return custom_components_from_file
|
return custom_components_from_file
|
||||||
|
|
||||||
|
|
||||||
def create_and_validate_component(code: str) -> CustomComponent:
|
|
||||||
component = CustomComponent(code=code)
|
|
||||||
component.validate()
|
|
||||||
return component
|
|
||||||
|
|
||||||
|
|
||||||
def update_field_dict(field_dict):
|
def update_field_dict(field_dict):
|
||||||
"""Update the field dictionary by calling options() or value() if they are callable"""
|
"""Update the field dictionary by calling options() or value() if they are callable"""
|
||||||
if "options" in field_dict and callable(field_dict["options"]):
|
if "options" in field_dict and callable(field_dict["options"]):
|
||||||
|
|
@ -378,6 +371,3 @@ def build_component(component):
|
||||||
component_name = determine_component_name(component)
|
component_name = determine_component_name(component)
|
||||||
component_template = create_component_template(component)
|
component_template = create_component_template(component)
|
||||||
return component_name, component_template
|
return component_name, component_template
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
|
|
||||||
from cachetools import LRUCache, cached
|
from cachetools import LRUCache, cached
|
||||||
from langflow.interface.agents.base import agent_creator
|
from langflow.interface.agents.base import agent_creator
|
||||||
from langflow.interface.chains.base import chain_creator
|
from langflow.interface.chains.base import chain_creator
|
||||||
from langflow.interface.custom.directory_reader.utils import \
|
from langflow.interface.custom.directory_reader.utils import merge_nested_dicts_with_renaming
|
||||||
merge_nested_dicts_with_renaming
|
|
||||||
from langflow.interface.custom.utils import build_custom_components
|
from langflow.interface.custom.utils import build_custom_components
|
||||||
from langflow.interface.document_loaders.base import documentloader_creator
|
from langflow.interface.document_loaders.base import documentloader_creator
|
||||||
from langflow.interface.embeddings.base import embedding_creator
|
from langflow.interface.embeddings.base import embedding_creator
|
||||||
|
|
@ -70,5 +68,3 @@ def get_all_types_dict(settings_service):
|
||||||
native_components = build_langchain_types_dict()
|
native_components = build_langchain_types_dict()
|
||||||
custom_components_from_file = build_custom_components(settings_service)
|
custom_components_from_file = build_custom_components(settings_service)
|
||||||
return merge_nested_dicts_with_renaming(native_components, custom_components_from_file)
|
return merge_nested_dicts_with_renaming(native_components, custom_components_from_file)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from langchain.agents import AgentExecutor
|
||||||
from langchain.chains.base import Chain
|
from langchain.chains.base import Chain
|
||||||
from langchain.schema import AgentAction, Document
|
from langchain.schema import AgentAction, Document
|
||||||
from langchain.vectorstores.base import VectorStore
|
from langchain.vectorstores.base import VectorStore
|
||||||
|
from langchain_core.messages import AIMessage
|
||||||
from langchain_core.runnables.base import Runnable
|
from langchain_core.runnables.base import Runnable
|
||||||
from langflow.interface.custom.custom_component import CustomComponent
|
from langflow.interface.custom.custom_component import CustomComponent
|
||||||
from langflow.interface.run import build_sorted_vertices, get_memory_key, update_memory_keys
|
from langflow.interface.run import build_sorted_vertices, get_memory_key, update_memory_keys
|
||||||
|
|
@ -105,10 +106,23 @@ def get_build_result(data_graph, session_id):
|
||||||
return build_sorted_vertices(data_graph)
|
return build_sorted_vertices(data_graph)
|
||||||
|
|
||||||
|
|
||||||
def process_inputs(inputs: Optional[dict], artifacts: Dict[str, Any]) -> dict:
|
def process_inputs(
|
||||||
|
inputs: Optional[Union[dict, List[dict]]] = None, artifacts: Optional[Dict[str, Any]] = None
|
||||||
|
) -> Union[dict, List[dict]]:
|
||||||
if inputs is None:
|
if inputs is None:
|
||||||
inputs = {}
|
inputs = {}
|
||||||
|
if artifacts is None:
|
||||||
|
artifacts = {}
|
||||||
|
|
||||||
|
if isinstance(inputs, dict):
|
||||||
|
inputs = update_inputs_dict(inputs, artifacts)
|
||||||
|
elif isinstance(inputs, List):
|
||||||
|
inputs = [update_inputs_dict(inp, artifacts) for inp in inputs]
|
||||||
|
|
||||||
|
return inputs
|
||||||
|
|
||||||
|
|
||||||
|
def update_inputs_dict(inputs: dict, artifacts: Dict[str, Any]) -> dict:
|
||||||
for key, value in artifacts.items():
|
for key, value in artifacts.items():
|
||||||
if key == "repr":
|
if key == "repr":
|
||||||
continue
|
continue
|
||||||
|
|
@ -125,6 +139,11 @@ async def process_runnable(runnable: Runnable, inputs: Union[dict, List[dict]]):
|
||||||
result = await runnable.ainvoke(inputs)
|
result = await runnable.ainvoke(inputs)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Runnable {runnable} does not support inputs of type {type(inputs)}")
|
raise ValueError(f"Runnable {runnable} does not support inputs of type {type(inputs)}")
|
||||||
|
# Check if the result is a list of AIMessages
|
||||||
|
if isinstance(result, list) and all(isinstance(r, AIMessage) for r in result):
|
||||||
|
result = [r.content for r in result]
|
||||||
|
elif isinstance(result, AIMessage):
|
||||||
|
result = result.content
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import ast
|
||||||
import contextlib
|
import contextlib
|
||||||
import importlib
|
import importlib
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
from typing import Dict
|
from typing import Dict, List, Optional, Union
|
||||||
|
|
||||||
from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
||||||
|
|
||||||
|
|
@ -260,14 +260,13 @@ def get_default_imports(code_string):
|
||||||
"""
|
"""
|
||||||
Returns a dictionary of default imports for the dynamic class constructor.
|
Returns a dictionary of default imports for the dynamic class constructor.
|
||||||
"""
|
"""
|
||||||
typing_module = importlib.import_module("typing")
|
|
||||||
default_imports = {
|
|
||||||
"Optional": typing_module.Optional,
|
|
||||||
"List": typing_module.List,
|
|
||||||
"Dict": typing_module.Dict,
|
|
||||||
"Union": typing_module.Union,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
default_imports = {
|
||||||
|
"Optional": Optional,
|
||||||
|
"List": List,
|
||||||
|
"Dict": Dict,
|
||||||
|
"Union": Union,
|
||||||
|
}
|
||||||
langflow_imports = list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())
|
langflow_imports = list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())
|
||||||
necessary_imports = find_names_in_code(code_string, langflow_imports)
|
necessary_imports = find_names_in_code(code_string, langflow_imports)
|
||||||
langflow_module = importlib.import_module("langflow.field_typing")
|
langflow_module = importlib.import_module("langflow.field_typing")
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
from typing import TYPE_CHECKING, Any, Dict, Optional
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
from celery.exceptions import SoftTimeLimitExceeded # type: ignore
|
from celery.exceptions import SoftTimeLimitExceeded # type: ignore
|
||||||
from loguru import logger
|
|
||||||
from rich import print
|
|
||||||
|
|
||||||
from langflow.core.celery_app import celery_app
|
from langflow.core.celery_app import celery_app
|
||||||
from langflow.processing.process import Result, generate_result, process_inputs
|
from langflow.processing.process import Result, generate_result, process_inputs
|
||||||
from langflow.services.deps import get_session_service
|
from langflow.services.deps import get_session_service
|
||||||
from langflow.services.manager import initialize_session_service
|
from langflow.services.manager import initialize_session_service
|
||||||
|
from loguru import logger
|
||||||
|
from rich import print
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.graph.vertex.base import Vertex
|
from langflow.graph.vertex.base import Vertex
|
||||||
|
|
@ -35,7 +34,7 @@ def build_vertex(self, vertex: "Vertex") -> "Vertex":
|
||||||
@celery_app.task(acks_late=True)
|
@celery_app.task(acks_late=True)
|
||||||
def process_graph_cached_task(
|
def process_graph_cached_task(
|
||||||
data_graph: Dict[str, Any],
|
data_graph: Dict[str, Any],
|
||||||
inputs: Optional[dict] = None,
|
inputs: Optional[Union[dict, List[dict]]] = None,
|
||||||
clear_cache=False,
|
clear_cache=False,
|
||||||
session_id=None,
|
session_id=None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="side-bar-arrangement">
|
<div className="side-bar-arrangement">
|
||||||
<div className="side-bar-buttons-arrangement">
|
<div className="side-bar-buttons-arrangement">
|
||||||
{hasStore && (
|
{hasStore && validApiKey && (
|
||||||
<ShadTooltip
|
<ShadTooltip
|
||||||
content={
|
content={
|
||||||
!hasApiKey || !validApiKey
|
!hasApiKey || !validApiKey
|
||||||
|
|
@ -263,7 +263,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
</button>
|
</button>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
</div>
|
</div>
|
||||||
{!hasStore && ExportMemo}
|
{(!hasApiKey || !validApiKey) && ExportMemo}
|
||||||
<ShadTooltip content={"Code"} side="top">
|
<ShadTooltip content={"Code"} side="top">
|
||||||
<div className="side-bar-button">
|
<div className="side-bar-button">
|
||||||
{flow && flow.data && (
|
{flow && flow.data && (
|
||||||
|
|
|
||||||
|
|
@ -129,12 +129,12 @@ import { NotionIcon } from "../icons/Notion";
|
||||||
import { OpenAiIcon } from "../icons/OpenAi";
|
import { OpenAiIcon } from "../icons/OpenAi";
|
||||||
import { PineconeIcon } from "../icons/Pinecone";
|
import { PineconeIcon } from "../icons/Pinecone";
|
||||||
import { QDrantIcon } from "../icons/QDrant";
|
import { QDrantIcon } from "../icons/QDrant";
|
||||||
import { WeaviateIcon } from "../icons/Weaviate";
|
|
||||||
import { SearxIcon } from "../icons/Searx";
|
import { SearxIcon } from "../icons/Searx";
|
||||||
import { ShareIcon } from "../icons/Share";
|
import { ShareIcon } from "../icons/Share";
|
||||||
import { Share2Icon } from "../icons/Share2";
|
import { Share2Icon } from "../icons/Share2";
|
||||||
import SvgSlackIcon from "../icons/Slack/SlackIcon";
|
import SvgSlackIcon from "../icons/Slack/SlackIcon";
|
||||||
import { VertexAIIcon } from "../icons/VertexAI";
|
import { VertexAIIcon } from "../icons/VertexAI";
|
||||||
|
import { WeaviateIcon } from "../icons/Weaviate";
|
||||||
import SvgWikipedia from "../icons/Wikipedia/Wikipedia";
|
import SvgWikipedia from "../icons/Wikipedia/Wikipedia";
|
||||||
import SvgWolfram from "../icons/Wolfram/Wolfram";
|
import SvgWolfram from "../icons/Wolfram/Wolfram";
|
||||||
import { HackerNewsIcon } from "../icons/hackerNews";
|
import { HackerNewsIcon } from "../icons/hackerNews";
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -3,14 +3,10 @@ import types
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fastapi import HTTPException
|
|
||||||
from langflow.interface.custom.base import CustomComponent
|
from langflow.interface.custom.base import CustomComponent
|
||||||
from langflow.interface.custom.code_parser.code_parser import (CodeParser,
|
from langflow.interface.custom.code_parser.code_parser import CodeParser, CodeSyntaxError
|
||||||
CodeSyntaxError)
|
from langflow.interface.custom.custom_component.component import Component, ComponentCodeNullError
|
||||||
from langflow.interface.custom.custom_component.component import (
|
from langflow.interface.custom.utils import build_custom_component_template
|
||||||
Component, ComponentCodeNullError)
|
|
||||||
from langflow.interface.custom.utils import (build_custom_component_template,
|
|
||||||
create_and_validate_component)
|
|
||||||
from langflow.services.database.models.flow import Flow, FlowCreate
|
from langflow.services.database.models.flow import Flow, FlowCreate
|
||||||
|
|
||||||
code_default = """
|
code_default = """
|
||||||
|
|
@ -368,16 +364,6 @@ def test_component_get_code_tree_syntax_error():
|
||||||
component.get_code_tree(component.code)
|
component.get_code_tree(component.code)
|
||||||
|
|
||||||
|
|
||||||
def test_custom_component_class_template_validation_no_code():
|
|
||||||
"""
|
|
||||||
Test the _class_template_validation method of the CustomComponent class
|
|
||||||
raises the HTTPException when the code is None.
|
|
||||||
"""
|
|
||||||
custom_component = CustomComponent(code=None, function_entrypoint_name="build")
|
|
||||||
with pytest.raises(HTTPException):
|
|
||||||
custom_component._class_template_validation(custom_component.code)
|
|
||||||
|
|
||||||
|
|
||||||
def test_custom_component_get_code_tree_syntax_error():
|
def test_custom_component_get_code_tree_syntax_error():
|
||||||
"""
|
"""
|
||||||
Test the get_code_tree method of the CustomComponent class
|
Test the get_code_tree method of the CustomComponent class
|
||||||
|
|
@ -535,12 +521,12 @@ def test_build_config_field_value_keys(component):
|
||||||
|
|
||||||
|
|
||||||
def test_create_and_validate_component_valid_code(test_component_code):
|
def test_create_and_validate_component_valid_code(test_component_code):
|
||||||
component = create_and_validate_component(test_component_code)
|
component = CustomComponent(code=test_component_code)
|
||||||
assert isinstance(component, CustomComponent)
|
assert isinstance(component, CustomComponent)
|
||||||
|
|
||||||
|
|
||||||
def test_build_langchain_template_custom_component_valid_code(test_component_code):
|
def test_build_langchain_template_custom_component_valid_code(test_component_code):
|
||||||
component = create_and_validate_component(test_component_code)
|
component = CustomComponent(code=test_component_code)
|
||||||
frontend_node = build_custom_component_template(component)
|
frontend_node = build_custom_component_template(component)
|
||||||
assert isinstance(frontend_node, dict)
|
assert isinstance(frontend_node, dict)
|
||||||
template = frontend_node["template"]
|
template = frontend_node["template"]
|
||||||
|
|
@ -554,7 +540,7 @@ def test_build_langchain_template_custom_component_valid_code(test_component_cod
|
||||||
|
|
||||||
|
|
||||||
def test_build_langchain_template_custom_component_templatefield(test_component_with_templatefield_code):
|
def test_build_langchain_template_custom_component_templatefield(test_component_with_templatefield_code):
|
||||||
component = create_and_validate_component(test_component_with_templatefield_code)
|
component = CustomComponent(code=test_component_with_templatefield_code)
|
||||||
frontend_node = build_custom_component_template(component)
|
frontend_node = build_custom_component_template(component)
|
||||||
assert isinstance(frontend_node, dict)
|
assert isinstance(frontend_node, dict)
|
||||||
template = frontend_node["template"]
|
template = frontend_node["template"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue