Skip to content

Commit

Permalink
Adds Join The Waitlist button, Vectara, Metaphor in Beta and other fi…
Browse files Browse the repository at this point in the history
…xes (#744)
  • Loading branch information
ogabrielluiz authored Aug 9, 2023
2 parents 91914f8 + 8c41415 commit 7985856
Show file tree
Hide file tree
Showing 14 changed files with 280 additions and 142 deletions.
1 change: 0 additions & 1 deletion docs/docs/guidelines/custom-component.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class DocumentProcessor(CustomComponent):
light: "img/document_processor.png",
}}
style={{
width: "40%",
margin: "0 auto",
display: "flex",
justifyContent: "center",
Expand Down
230 changes: 122 additions & 108 deletions poetry.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langflow"
version = "0.4.5"
version = "0.4.6"
description = "A Python package with a built-in web application"
authors = ["Logspace <[email protected]>"]
maintainers = [
Expand Down Expand Up @@ -78,6 +78,7 @@ psycopg = "^3.1.9"
psycopg-binary = "^3.1.9"
fastavro = "^1.8.0"
langchain-experimental = "^0.0.8"
metaphor-python = "^0.1.11"

[tool.poetry.group.dev.dependencies]
black = "^23.1.0"
Expand Down
56 changes: 56 additions & 0 deletions src/backend/langflow/components/toolkits/Metaphor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from typing import List, Union
from langflow import CustomComponent

from metaphor_python import Metaphor # type: ignore
from langchain.tools import Tool
from langchain.agents import tool
from langchain.agents.agent_toolkits.base import BaseToolkit


class MetaphorToolkit(CustomComponent):
display_name: str = "Metaphor"
description: str = "Metaphor Toolkit"
documentation = (
"https://python.langchain.com/docs/integrations/tools/metaphor_search"
)
beta = True
# api key should be password = True
field_config = {
"metaphor_api_key": {"display_name": "Metaphor API Key", "password": True},
"code": {"advanced": True},
}

def build(
self,
metaphor_api_key: str,
use_autoprompt: bool = True,
search_num_results: int = 5,
similar_num_results: int = 5,
) -> Union[Tool, BaseToolkit]:
# If documents, then we need to create a Vectara instance using .from_documents
client = Metaphor(api_key=metaphor_api_key)

@tool
def search(query: str):
"""Call search engine with a query."""
return client.search(
query, use_autoprompt=use_autoprompt, num_results=search_num_results
)

@tool
def get_contents(ids: List[str]):
"""Get contents of a webpage.
The ids passed in should be a list of ids as fetched from `search`.
"""
return client.get_contents(ids)

@tool
def find_similar(url: str):
"""Get search results similar to a given URL.
The url passed in should be a URL returned from `search`
"""
return client.find_similar(url, num_results=similar_num_results)

return [search, get_contents, find_similar] # type: ignore
Empty file.
50 changes: 50 additions & 0 deletions src/backend/langflow/components/vectorstores/Vectara.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import Optional, Union
from langflow import CustomComponent

from langchain.vectorstores import Vectara
from langchain.schema import Document
from langchain.vectorstores.base import VectorStore
from langchain.schema import BaseRetriever
from langchain.embeddings.base import Embeddings


class VectaraComponent(CustomComponent):
display_name: str = "Vectara"
description: str = "Implementation of Vector Store using Vectara"
documentation = (
"https://python.langchain.com/docs/integrations/vectorstores/vectara"
)
beta = True
# api key should be password = True
field_config = {
"vectara_customer_id": {"display_name": "Vectara Customer ID"},
"vectara_corpus_id": {"display_name": "Vectara Corpus ID"},
"vectara_api_key": {"display_name": "Vectara API Key", "password": True},
"code": {"show": False},
"documents": {"display_name": "Documents"},
"embedding": {"display_name": "Embedding"},
}

def build(
self,
vectara_customer_id: str,
vectara_corpus_id: str,
vectara_api_key: str,
embedding: Optional[Embeddings] = None,
documents: Optional[Document] = None,
) -> Union[VectorStore, BaseRetriever]:
# If documents, then we need to create a Vectara instance using .from_documents
if documents is not None and embedding is not None:
return Vectara.from_documents(
documents=documents, # type: ignore
vectara_customer_id=vectara_customer_id,
vectara_corpus_id=vectara_corpus_id,
vectara_api_key=vectara_api_key,
embedding=embedding,
)

return Vectara(
vectara_customer_id=vectara_customer_id,
vectara_corpus_id=vectara_corpus_id,
vectara_api_key=vectara_api_key,
)
Empty file.
3 changes: 3 additions & 0 deletions src/backend/langflow/interface/custom/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def build_template_config(self, attributes) -> dict:
elif "beta" in item_name:
template_config["beta"] = ast.literal_eval(item_value)

elif "documentation" in item_name:
template_config["documentation"] = ast.literal_eval(item_value)

return template_config

def build(self, *args: Any, **kwargs: Any) -> Any:
Expand Down
22 changes: 16 additions & 6 deletions src/backend/langflow/interface/custom/custom_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ def get_function_entrypoint_args(self) -> str:
return build_method["args"]

@property
def get_function_entrypoint_return_type(self) -> str:
def get_function_entrypoint_return_type(self) -> List[str]:
if not self.code:
return ""
return []
tree = self.get_code_tree(self.code)

component_classes = [
Expand All @@ -103,7 +103,7 @@ def get_function_entrypoint_return_type(self) -> str:
if self.code_class_base_inheritance in cls["bases"]
]
if not component_classes:
return ""
return []

# Assume the first Component class is the one we're interested in
component_class = component_classes[0]
Expand All @@ -114,11 +114,21 @@ def get_function_entrypoint_return_type(self) -> str:
]

if not build_methods:
return ""
return []

build_method = build_methods[0]

return build_method["return_type"]
return_type = build_method["return_type"]
if not return_type:
return []
# If the return type is not a Union, then we just return it as a list
if "Union" not in return_type:
return [return_type] if return_type in self.return_type_valid_list else []

# If the return type is a Union, then we need to parse it
return_type = return_type.replace("Union", "").replace("[", "").replace("]", "")
return_type = return_type.split(",")
return_type = [item.strip() for item in return_type]
return [item for item in return_type if item in self.return_type_valid_list]

@property
def get_main_class_name(self):
Expand Down
4 changes: 2 additions & 2 deletions src/backend/langflow/interface/initialize/vector_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def initialize_pinecone(class_object: Type[Pinecone], params: dict):

import pinecone # type: ignore

pinecone_api_key = params.get("pinecone_api_key")
pinecone_env = params.get("pinecone_env")
pinecone_api_key = params.pop("pinecone_api_key")
pinecone_env = params.pop("pinecone_env")

if pinecone_api_key is None or pinecone_env is None:
if os.getenv("PINECONE_API_KEY") is not None:
Expand Down
44 changes: 24 additions & 20 deletions src/backend/langflow/interface/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ast
import contextlib
from typing import Any
from typing import Any, List
from langflow.api.utils import merge_nested_dicts_with_renaming
from langflow.interface.agents.base import agent_creator
from langflow.interface.chains.base import chain_creator
Expand Down Expand Up @@ -199,6 +199,9 @@ def update_attributes(frontend_node, template_config):
if "beta" in template_config:
frontend_node["beta"] = template_config["beta"]

if "documentation" in template_config:
frontend_node["documentation"] = template_config["documentation"]


def build_field_config(custom_component: CustomComponent):
"""Build the field configuration for a custom component"""
Expand Down Expand Up @@ -257,26 +260,27 @@ def get_field_properties(extra_field):
return field_name, field_type, field_value, field_required


def add_base_classes(frontend_node, return_type):
def add_base_classes(frontend_node, return_types: List[str]):
"""Add base classes to the frontend node"""
if return_type not in CUSTOM_COMPONENT_SUPPORTED_TYPES or return_type is None:
raise HTTPException(
status_code=400,
detail={
"error": (
"Invalid return type should be one of: "
f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
),
"traceback": traceback.format_exc(),
},
)

return_type_instance = CUSTOM_COMPONENT_SUPPORTED_TYPES.get(return_type)
base_classes = get_base_classes(return_type_instance)

for base_class in base_classes:
if base_class not in CLASSES_TO_REMOVE:
frontend_node.get("base_classes").append(base_class)
for return_type in return_types:
if return_type not in CUSTOM_COMPONENT_SUPPORTED_TYPES or return_type is None:
raise HTTPException(
status_code=400,
detail={
"error": (
"Invalid return type should be one of: "
f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
),
"traceback": traceback.format_exc(),
},
)

return_type_instance = CUSTOM_COMPONENT_SUPPORTED_TYPES.get(return_type)
base_classes = get_base_classes(return_type_instance)

for base_class in base_classes:
if base_class not in CLASSES_TO_REMOVE:
frontend_node.get("base_classes").append(base_class)


def build_langchain_template_custom_component(custom_component: CustomComponent):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_custom_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def test_custom_component_get_function_entrypoint_return_type():
code=code_default, function_entrypoint_name="build"
)
return_type = custom_component.get_function_entrypoint_return_type
assert return_type == "Document"
assert return_type == ["Document"]


def test_custom_component_get_main_class_name():
Expand Down Expand Up @@ -436,7 +436,7 @@ def build():

custom_component = CustomComponent(code=my_code, function_entrypoint_name="build")
return_type = custom_component.get_function_entrypoint_return_type
assert return_type is None
assert return_type == []


def test_custom_component_get_main_class_name_no_main_class():
Expand Down Expand Up @@ -469,7 +469,7 @@ def test_build_config_no_code():
component = CustomComponent(code=None)

assert component.get_function_entrypoint_args == ""
assert component.get_function_entrypoint_return_type == ""
assert component.get_function_entrypoint_return_type == []


@pytest.fixture
Expand Down
3 changes: 2 additions & 1 deletion tests/test_vectorstore_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ def test_vectorstores_settings(client: TestClient):
assert response.status_code == 200
json_response = response.json()
vectorstores = json_response["vectorstores"]
assert set(vectorstores.keys()) == set(settings.VECTORSTORES)
settings_vecs = set(settings.VECTORSTORES)
assert all(vs in vectorstores for vs in settings_vecs)

0 comments on commit 7985856

Please sign in to comment.