feat: Add Hybrid Search functionality to AstraDB + AstraPy / LangChain Updates (#7358)
* feat: Add Hybrid Search functionality and AstraPy 2.0 and associated deps (#7357) * astrapy 2.0 tentative full pass * Update the create collection function --------- Co-authored-by: Stefano Lottini <stefano.lottini@datastax.com> * Update deps * Update uv.lock * Fix linting errors in astradb * Update package lock * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Add basic UI scaffolding for hybrid search * [autofix.ci] apply automated fixes * Continue to clean up component * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Fix the keyspace compatibility * [autofix.ci] apply automated fixes * feat: add nodeId, nodeClass, and handleNodeClass props to dropdown an… (#7406) feat: add nodeId, nodeClass, and handleNodeClass props to dropdown and string render components Co-authored-by: deon-sanchez <deon.sanchez@datastax.com> * Update uv.lock * Update uv.lock * Add hybrid search support in collection creation * [autofix.ci] apply automated fixes * Updates from review comments * [autofix.ci] apply automated fixes * Add in lexical search support * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Detect collection hybrid params * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Pass lexical terms at search time * [autofix.ci] apply automated fixes * Update test_astra_component.py * Add Query Input and Mixin on backend * Adds Query on supported types * Adds types for query modal and component * Adds size for new query modal * Adds query modal * Adds query component * Adds query component on parameter render * [autofix.ci] apply automated fixes * Feedback from review * [autofix.ci] apply automated fixes * ✨ (switch-case-size.ts): Update height value to 'h-fit' for 'small-query' case to improve responsiveness ✨ (queryInputComponent.spec.ts): Add unit test for user interaction with query input component, including updating code and testing functionality * Switch to multiline for lexical terms * [autofix.ci] apply automated fixes * Create Hybrid Search RAG.json * Update Hybrid Search RAG.json * Added queryInput in vectorstore model * Added queryInput in lexical terms * Update model.py * Update Hybrid Search RAG.json * Add query support in field validation * fix: bump Astra Assistants version to support AstraPy 2.0 (#7535) 2.2.12 Co-authored-by: phact <estevezsebastian@gmail.com> * Update uv.lock * Fixed QueryInput not receiving text from handle * Set search type to similarity search when hybrid * Always set to similarity when we have the reranker * [autofix.ci] apply automated fixes * Add logging for hybrid search support * Update starter projects * Update Hybrid Search RAG.json * Added dropdown toggle on backend * Added toggle on dropdown on frontend * Added showing only value if there is just one option in the dropdown * Added toggle to Dropdown Input on Astra Db * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * init toggle value as true or false * Change it to send null value if toggle is disabled * Added resizer on search query * Added Search Hybrid, Lexical and Vector icons * Added icons and new Lexical Search on Dropdown Input of Astra DB * Updated starter projects * Changed descriptions on astradb component * Changed starter projects * Lexical search option for dropdown * Update astradb.py * Update starter projects * One small lexical update * Update astradb.py * Update projects * [autofix.ci] apply automated fixes * Fixed dropdown changing when toggle is off * Update astradb.py * [autofix.ci] apply automated fixes * Don't show lexical terms on new collection creation * ✨ (actionsMainPage-shard-0.spec.ts): add functionality to add flow to test on empty langflow button click ✨ (filterEdge-shard-1.spec.ts): add functionality to add flow to test on empty langflow button click ♻️ (await-bootstrap-test.ts): refactor code to reuse addFlowToTestOnEmptyLangflow function for adding flow to test on empty langflow button click * [autofix.ci] apply automated fixes * 🐛 (filterEdge-shard-1.spec.ts): fix incorrect reference to memoriesAstra DB Chat Memory, update to memoriesMem0 Chat Memory for accurate testing data. --------- Co-authored-by: Stefano Lottini <stefano.lottini@datastax.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: deon-sanchez <deon.sanchez@datastax.com> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> Co-authored-by: phact <estevezsebastian@gmail.com>
This commit is contained in:
parent
fb79b80f91
commit
907a594428
30 changed files with 4901 additions and 1804 deletions
|
|
@ -65,7 +65,7 @@ dependencies = [
|
|||
"langsmith==0.1.147",
|
||||
"yfinance==0.2.50",
|
||||
"wolframalpha==5.1.3",
|
||||
"astra-assistants[tools]~=2.2.11",
|
||||
"astra-assistants[tools]~=2.2.12",
|
||||
"composio-langchain==0.7.15",
|
||||
"composio-core==0.7.15",
|
||||
"spider-client==0.1.24",
|
||||
|
|
@ -79,7 +79,7 @@ dependencies = [
|
|||
"langchain-google-genai==2.0.6",
|
||||
"langchain-cohere==0.3.3",
|
||||
"langchain-anthropic==0.3.0",
|
||||
"langchain-astradb==0.5.3",
|
||||
"langchain-astradb~=0.6.0",
|
||||
"langchain-openai==0.2.12",
|
||||
"langchain-google-vertexai==2.0.7",
|
||||
"langchain-groq==0.2.1",
|
||||
|
|
@ -183,7 +183,6 @@ members = ["src/backend/base", "."]
|
|||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/backend/langflow"]
|
||||
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/langflow-ai/langflow"
|
||||
Documentation = "https://docs.langflow.org"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from langflow.custom import Component
|
|||
from langflow.field_typing import Text, VectorStore
|
||||
from langflow.helpers.data import docs_to_data
|
||||
from langflow.inputs.inputs import BoolInput
|
||||
from langflow.io import HandleInput, MultilineInput, Output
|
||||
from langflow.io import HandleInput, Output, QueryInput
|
||||
from langflow.schema import Data, DataFrame
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -62,9 +62,11 @@ class LCVectorStoreComponent(Component):
|
|||
input_types=["Data", "DataFrame"],
|
||||
is_list=True,
|
||||
),
|
||||
MultilineInput(
|
||||
QueryInput(
|
||||
name="search_query",
|
||||
display_name="Search Query",
|
||||
info="Enter a query to run a combined similarity and lexical terms search.",
|
||||
placeholder="Enter a query...",
|
||||
tool_mode=True,
|
||||
),
|
||||
BoolInput(
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class AstraVectorizeComponent(Component):
|
|||
if api_key_name:
|
||||
authentication["providerKey"] = api_key_name
|
||||
return {
|
||||
# must match astrapy.info.CollectionVectorServiceOptions
|
||||
# must match astrapy.info.VectorServiceOptions
|
||||
"collection_vector_service_options": {
|
||||
"provider": provider_value,
|
||||
"modelName": self.model_name,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from datetime import datetime, timezone
|
|||
from typing import Any
|
||||
|
||||
from astrapy import Collection, DataAPIClient, Database
|
||||
from astrapy.admin import parse_api_endpoint
|
||||
from langchain.pydantic_v1 import BaseModel, Field, create_model
|
||||
from langchain_core.tools import StructuredTool, Tool
|
||||
|
||||
|
|
@ -195,7 +196,8 @@ class AstraDBToolComponent(LCToolComponent):
|
|||
return self._cached_collection
|
||||
|
||||
try:
|
||||
cached_client = DataAPIClient(self.token)
|
||||
environment = parse_api_endpoint(self.api_endpoint).environment
|
||||
cached_client = DataAPIClient(self.token, environment=environment)
|
||||
cached_db = cached_client.get_database(self.api_endpoint, keyspace=self.keyspace)
|
||||
self._cached_collection = cached_db.get_collection(self.collection_name)
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ import re
|
|||
from collections import defaultdict
|
||||
from dataclasses import asdict, dataclass, field
|
||||
|
||||
from astrapy import AstraDBAdmin, DataAPIClient, Database
|
||||
from astrapy.info import CollectionDescriptor
|
||||
from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions
|
||||
from astrapy import DataAPIClient, Database
|
||||
from astrapy.data.info.reranking import RerankServiceOptions
|
||||
from astrapy.info import CollectionDescriptor, CollectionLexicalOptions, CollectionRerankOptions
|
||||
from langchain_astradb import AstraDBVectorStore, VectorServiceOptions
|
||||
from langchain_astradb.utils.astradb import HybridSearchMode, _AstraDBCollectionEnvironment
|
||||
|
||||
from langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store
|
||||
from langflow.base.vectorstores.vector_store_connection_decorator import vector_store_connection
|
||||
|
|
@ -15,6 +17,7 @@ from langflow.io import (
|
|||
DropdownInput,
|
||||
HandleInput,
|
||||
IntInput,
|
||||
QueryInput,
|
||||
SecretStrInput,
|
||||
StrInput,
|
||||
)
|
||||
|
|
@ -136,12 +139,15 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
real_time_refresh=True,
|
||||
input_types=[],
|
||||
),
|
||||
StrInput(
|
||||
DropdownInput(
|
||||
name="environment",
|
||||
display_name="Environment",
|
||||
info="The environment for the Astra DB API Endpoint.",
|
||||
options=["prod", "test", "dev"],
|
||||
value="prod",
|
||||
advanced=True,
|
||||
real_time_refresh=True,
|
||||
combobox=True,
|
||||
),
|
||||
DropdownInput(
|
||||
name="database_name",
|
||||
|
|
@ -157,7 +163,15 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
name="api_endpoint",
|
||||
display_name="Astra DB API Endpoint",
|
||||
info="The API Endpoint for the Astra DB instance. Supercedes database selection.",
|
||||
show=False,
|
||||
),
|
||||
DropdownInput(
|
||||
name="keyspace",
|
||||
display_name="Keyspace",
|
||||
info="Optional keyspace within Astra DB to use for the collection.",
|
||||
advanced=True,
|
||||
options=[],
|
||||
real_time_refresh=True,
|
||||
),
|
||||
DropdownInput(
|
||||
name="collection_name",
|
||||
|
|
@ -168,22 +182,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
real_time_refresh=True,
|
||||
dialog_inputs=asdict(NewCollectionInput()),
|
||||
combobox=True,
|
||||
advanced=True,
|
||||
),
|
||||
StrInput(
|
||||
name="keyspace",
|
||||
display_name="Keyspace",
|
||||
info="Optional keyspace within Astra DB to use for the collection.",
|
||||
advanced=True,
|
||||
),
|
||||
DropdownInput(
|
||||
name="embedding_choice",
|
||||
display_name="Embedding Model or Astra Vectorize",
|
||||
info="Choose an embedding model or use Astra Vectorize.",
|
||||
options=["Embedding Model", "Astra Vectorize"],
|
||||
value="Embedding Model",
|
||||
advanced=True,
|
||||
real_time_refresh=True,
|
||||
show=False,
|
||||
),
|
||||
HandleInput(
|
||||
name="embedding_model",
|
||||
|
|
@ -191,8 +190,40 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
input_types=["Embeddings"],
|
||||
info="Specify the Embedding Model. Not required for Astra Vectorize collections.",
|
||||
required=False,
|
||||
show=False,
|
||||
),
|
||||
*LCVectorStoreComponent.inputs,
|
||||
DropdownInput(
|
||||
name="search_method",
|
||||
display_name="Search Method",
|
||||
info=(
|
||||
"Determine how your content is matched: Vector finds semantic similarity, "
|
||||
"and Hybrid Search (suggested) combines both approaches "
|
||||
"with a reranker."
|
||||
),
|
||||
options=["Hybrid Search", "Vector Search"], # TODO: Restore Lexical Search?
|
||||
options_metadata=[{"icon": "SearchHybrid"}, {"icon": "SearchVector"}],
|
||||
value="Vector Search",
|
||||
advanced=True,
|
||||
real_time_refresh=True,
|
||||
),
|
||||
DropdownInput(
|
||||
name="reranker",
|
||||
display_name="Reranker",
|
||||
info="Post-retrieval model that re-scores results for optimal relevance ranking.",
|
||||
show=False,
|
||||
toggle=True,
|
||||
),
|
||||
QueryInput(
|
||||
name="lexical_terms",
|
||||
display_name="Lexical Terms",
|
||||
info="Add additional terms/keywords to augment search precision.",
|
||||
placeholder="Enter terms to search...",
|
||||
separator=" ",
|
||||
show=False,
|
||||
value="",
|
||||
advanced=True,
|
||||
),
|
||||
IntInput(
|
||||
name="number_of_results",
|
||||
display_name="Number of Search Results",
|
||||
|
|
@ -262,12 +293,15 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
# TODO: Programmatically fetch the regions for each cloud provider
|
||||
return {
|
||||
"dev": {
|
||||
"Amazon Web Services": {
|
||||
"id": "aws",
|
||||
"regions": ["us-west-2"],
|
||||
},
|
||||
"Google Cloud Platform": {
|
||||
"id": "gcp",
|
||||
"regions": ["us-central1"],
|
||||
"regions": ["us-central1", "europe-west4"],
|
||||
},
|
||||
},
|
||||
# TODO: Check test regions
|
||||
"test": {
|
||||
"Google Cloud Platform": {
|
||||
"id": "gcp",
|
||||
|
|
@ -294,18 +328,19 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
def get_vectorize_providers(cls, token: str, environment: str | None = None, api_endpoint: str | None = None):
|
||||
try:
|
||||
# Get the admin object
|
||||
admin = AstraDBAdmin(token=token, environment=environment)
|
||||
db_admin = admin.get_database_admin(api_endpoint=api_endpoint)
|
||||
client = DataAPIClient(environment=environment)
|
||||
admin_client = client.get_admin()
|
||||
db_admin = admin_client.get_database_admin(api_endpoint, token=token)
|
||||
|
||||
# Get the list of embedding providers
|
||||
embedding_providers = db_admin.find_embedding_providers().as_dict()
|
||||
embedding_providers = db_admin.find_embedding_providers()
|
||||
|
||||
vectorize_providers_mapping = {}
|
||||
# Map the provider display name to the provider key and models
|
||||
for provider_key, provider_data in embedding_providers["embeddingProviders"].items():
|
||||
for provider_key, provider_data in embedding_providers.embedding_providers.items():
|
||||
# Get the provider display name and models
|
||||
display_name = provider_data["displayName"]
|
||||
models = [model["name"] for model in provider_data["models"]]
|
||||
display_name = provider_data.display_name
|
||||
models = [model.name for model in provider_data.models]
|
||||
|
||||
# Build our mapping
|
||||
vectorize_providers_mapping[display_name] = [provider_key, models]
|
||||
|
|
@ -325,7 +360,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
environment: str | None = None,
|
||||
keyspace: str | None = None,
|
||||
):
|
||||
client = DataAPIClient(token=token, environment=environment)
|
||||
client = DataAPIClient(environment=environment)
|
||||
|
||||
# Get the admin object
|
||||
admin_client = client.get_admin(token=token)
|
||||
|
|
@ -358,20 +393,14 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
dimension: int | None = None,
|
||||
embedding_generation_provider: str | None = None,
|
||||
embedding_generation_model: str | None = None,
|
||||
reranker: str | None = None,
|
||||
):
|
||||
# Create the data API client
|
||||
client = DataAPIClient(token=token, environment=environment)
|
||||
|
||||
# Get the database object
|
||||
database = client.get_async_database(api_endpoint=api_endpoint, token=token)
|
||||
|
||||
# Build vectorize options, if needed
|
||||
vectorize_options = None
|
||||
if not dimension:
|
||||
vectorize_options = CollectionVectorServiceOptions(
|
||||
provider=cls.get_vectorize_providers(
|
||||
token=token, environment=environment, api_endpoint=api_endpoint
|
||||
).get(embedding_generation_provider, [None, []])[0],
|
||||
providers = cls.get_vectorize_providers(token=token, environment=environment, api_endpoint=api_endpoint)
|
||||
vectorize_options = VectorServiceOptions(
|
||||
provider=providers.get(embedding_generation_provider, [None, []])[0],
|
||||
model_name=embedding_generation_model,
|
||||
)
|
||||
|
||||
|
|
@ -380,44 +409,53 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
msg = "Collection name is required to create a new collection."
|
||||
raise ValueError(msg)
|
||||
|
||||
# Create the collection
|
||||
return await database.create_collection(
|
||||
name=new_collection_name,
|
||||
keyspace=keyspace,
|
||||
dimension=dimension,
|
||||
service=vectorize_options,
|
||||
)
|
||||
# Define the base arguments being passed to the create collection function
|
||||
base_args = {
|
||||
"collection_name": new_collection_name,
|
||||
"token": token,
|
||||
"api_endpoint": api_endpoint,
|
||||
"keyspace": keyspace,
|
||||
"environment": environment,
|
||||
"embedding_dimension": dimension,
|
||||
"collection_vector_service_options": vectorize_options,
|
||||
}
|
||||
|
||||
# Add optional arguments only if environment is "dev"
|
||||
if environment == "dev" and reranker: # TODO: Remove conditional check soon
|
||||
# Split the reranker field into a provider a model name
|
||||
provider, _ = reranker.split("/")
|
||||
base_args["collection_rerank"] = CollectionRerankOptions(
|
||||
service=RerankServiceOptions(provider=provider, model_name=reranker),
|
||||
)
|
||||
base_args["collection_lexical"] = CollectionLexicalOptions(analyzer="STANDARD")
|
||||
|
||||
_AstraDBCollectionEnvironment(**base_args)
|
||||
|
||||
@classmethod
|
||||
def get_database_list_static(cls, token: str, environment: str | None = None):
|
||||
client = DataAPIClient(token=token, environment=environment)
|
||||
client = DataAPIClient(environment=environment)
|
||||
|
||||
# Get the admin object
|
||||
admin_client = client.get_admin(token=token)
|
||||
|
||||
# Get the list of databases
|
||||
db_list = list(admin_client.list_databases())
|
||||
|
||||
# Set the environment properly
|
||||
env_string = ""
|
||||
if environment and environment != "prod":
|
||||
env_string = f"-{environment}"
|
||||
db_list = admin_client.list_databases()
|
||||
|
||||
# Generate the api endpoint for each database
|
||||
db_info_dict = {}
|
||||
for db in db_list:
|
||||
try:
|
||||
# Get the API endpoint for the database
|
||||
api_endpoint = f"https://{db.info.id}-{db.info.region}.apps.astra{env_string}.datastax.com"
|
||||
api_endpoint = db.regions[0].api_endpoint
|
||||
|
||||
# Get the number of collections
|
||||
try:
|
||||
# Get the number of collections in the database
|
||||
num_collections = len(
|
||||
list(
|
||||
client.get_database(
|
||||
api_endpoint=api_endpoint, token=token, keyspace=db.info.keyspace
|
||||
).list_collection_names(keyspace=db.info.keyspace)
|
||||
)
|
||||
client.get_database(
|
||||
api_endpoint,
|
||||
token=token,
|
||||
).list_collection_names()
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
if db.status != "PENDING":
|
||||
|
|
@ -425,8 +463,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
num_collections = 0
|
||||
|
||||
# Add the database to the dictionary
|
||||
db_info_dict[db.info.name] = {
|
||||
db_info_dict[db.name] = {
|
||||
"api_endpoint": api_endpoint,
|
||||
"keyspaces": db.keyspaces,
|
||||
"collections": num_collections,
|
||||
"status": db.status if db.status != "ACTIVE" else None,
|
||||
"org_id": db.org_id if db.org_id else None,
|
||||
|
|
@ -437,7 +476,10 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
return db_info_dict
|
||||
|
||||
def get_database_list(self):
|
||||
return self.get_database_list_static(token=self.token, environment=self.environment)
|
||||
return self.get_database_list_static(
|
||||
token=self.token,
|
||||
environment=self.environment,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_api_endpoint_static(
|
||||
|
|
@ -492,14 +534,14 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
if keyspace:
|
||||
return keyspace.strip()
|
||||
|
||||
return None
|
||||
return "default_keyspace"
|
||||
|
||||
def get_database_object(self, api_endpoint: str | None = None):
|
||||
try:
|
||||
client = DataAPIClient(token=self.token, environment=self.environment)
|
||||
client = DataAPIClient(environment=self.environment)
|
||||
|
||||
return client.get_database(
|
||||
api_endpoint=api_endpoint or self.get_api_endpoint(),
|
||||
api_endpoint or self.get_api_endpoint(),
|
||||
token=self.token,
|
||||
keyspace=self.get_keyspace(),
|
||||
)
|
||||
|
|
@ -510,15 +552,15 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
def collection_data(self, collection_name: str, database: Database | None = None):
|
||||
try:
|
||||
if not database:
|
||||
client = DataAPIClient(token=self.token, environment=self.environment)
|
||||
client = DataAPIClient(environment=self.environment)
|
||||
|
||||
database = client.get_database(
|
||||
api_endpoint=self.get_api_endpoint(),
|
||||
self.get_api_endpoint(),
|
||||
token=self.token,
|
||||
keyspace=self.get_keyspace(),
|
||||
)
|
||||
|
||||
collection = database.get_collection(collection_name, keyspace=self.get_keyspace())
|
||||
collection = database.get_collection(collection_name)
|
||||
|
||||
return collection.estimated_document_count()
|
||||
except Exception as e: # noqa: BLE001
|
||||
|
|
@ -534,6 +576,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"status": info["status"],
|
||||
"collections": info["collections"],
|
||||
"api_endpoint": info["api_endpoint"],
|
||||
"keyspaces": info["keyspaces"],
|
||||
"org_id": info["org_id"],
|
||||
}
|
||||
for name, info in self.get_database_list().items()
|
||||
|
|
@ -546,13 +589,18 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
def get_provider_icon(cls, collection: CollectionDescriptor | None = None, provider_name: str | None = None) -> str:
|
||||
# Get the provider name from the collection
|
||||
provider_name = provider_name or (
|
||||
collection.options.vector.service.provider
|
||||
if collection and collection.options and collection.options.vector and collection.options.vector.service
|
||||
collection.definition.vector.service.provider
|
||||
if (
|
||||
collection
|
||||
and collection.definition
|
||||
and collection.definition.vector
|
||||
and collection.definition.vector.service
|
||||
)
|
||||
else None
|
||||
)
|
||||
|
||||
# If there is no provider, use the vector store icon
|
||||
if not provider_name or provider_name == "Bring your own":
|
||||
if not provider_name or provider_name.lower() == "bring your own":
|
||||
return "vectorstores"
|
||||
|
||||
# Map provider casings
|
||||
|
|
@ -581,7 +629,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
database = self.get_database_object(api_endpoint=api_endpoint)
|
||||
|
||||
# Get the list of collections
|
||||
collection_list = list(database.list_collections(keyspace=self.get_keyspace()))
|
||||
collection_list = database.list_collections(keyspace=self.get_keyspace())
|
||||
|
||||
# Return the list of collections and metadata associated
|
||||
return [
|
||||
|
|
@ -589,11 +637,15 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"name": col.name,
|
||||
"records": self.collection_data(collection_name=col.name, database=database),
|
||||
"provider": (
|
||||
col.options.vector.service.provider if col.options.vector and col.options.vector.service else None
|
||||
col.definition.vector.service.provider
|
||||
if col.definition.vector and col.definition.vector.service
|
||||
else None
|
||||
),
|
||||
"icon": self.get_provider_icon(collection=col),
|
||||
"model": (
|
||||
col.options.vector.service.model_name if col.options.vector and col.options.vector.service else None
|
||||
col.definition.vector.service.model_name
|
||||
if col.definition.vector and col.definition.vector.service
|
||||
else None
|
||||
),
|
||||
}
|
||||
for col in collection_list
|
||||
|
|
@ -679,7 +731,6 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"""Reset collection list options based on provided configuration."""
|
||||
# Get collection options
|
||||
collection_options = self._initialize_collection_options(api_endpoint=build_config["api_endpoint"]["value"])
|
||||
|
||||
# Update collection configuration
|
||||
collection_config = build_config["collection_name"]
|
||||
collection_config.update(
|
||||
|
|
@ -694,7 +745,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
collection_config["value"] = ""
|
||||
|
||||
# Set advanced status based on database selection
|
||||
collection_config["advanced"] = not build_config["database_name"]["value"]
|
||||
collection_config["show"] = bool(build_config["database_name"]["value"])
|
||||
|
||||
return build_config
|
||||
|
||||
|
|
@ -704,7 +755,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
database_options = self._initialize_database_options()
|
||||
|
||||
# Update cloud provider options
|
||||
env = self.environment or "prod"
|
||||
env = self.environment
|
||||
template = build_config["database_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"]
|
||||
template["02_cloud_provider"]["options"] = list(self.map_cloud_providers()[env].keys())
|
||||
|
||||
|
|
@ -721,10 +772,10 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
if database_config["value"] not in database_config["options"]:
|
||||
database_config["value"] = ""
|
||||
build_config["api_endpoint"]["value"] = ""
|
||||
build_config["collection_name"]["advanced"] = True
|
||||
build_config["collection_name"]["show"] = False
|
||||
|
||||
# Set advanced status based on token presence
|
||||
database_config["advanced"] = not build_config["token"]["value"]
|
||||
database_config["show"] = bool(build_config["token"]["value"])
|
||||
|
||||
return build_config
|
||||
|
||||
|
|
@ -732,12 +783,53 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"""Reset all build configuration options to default empty state."""
|
||||
# Reset database configuration
|
||||
database_config = build_config["database_name"]
|
||||
database_config.update({"options": [], "options_metadata": [], "value": "", "advanced": True})
|
||||
database_config.update({"options": [], "options_metadata": [], "value": "", "show": False})
|
||||
build_config["api_endpoint"]["value"] = ""
|
||||
|
||||
# Reset collection configuration
|
||||
collection_config = build_config["collection_name"]
|
||||
collection_config.update({"options": [], "options_metadata": [], "value": "", "advanced": True})
|
||||
collection_config.update({"options": [], "options_metadata": [], "value": "", "show": False})
|
||||
|
||||
return build_config
|
||||
|
||||
def _handle_hybrid_search_options(self, build_config: dict) -> dict:
|
||||
"""Set hybrid search options in the build configuration."""
|
||||
# Detect what hybrid options are available
|
||||
# Get the admin object
|
||||
client = DataAPIClient(environment=self.environment)
|
||||
admin_client = client.get_admin()
|
||||
db_admin = admin_client.get_database_admin(self.get_api_endpoint(), token=self.token)
|
||||
|
||||
# We will try to get the reranking providers to see if its hybrid emabled
|
||||
try:
|
||||
providers = db_admin.find_reranking_providers()
|
||||
build_config["reranker"]["options"] = [
|
||||
model.name for provider_data in providers.reranking_providers.values() for model in provider_data.models
|
||||
]
|
||||
build_config["reranker"]["options_metadata"] = [
|
||||
{"icon": self.get_provider_icon(provider_name=model.name.split("/")[0])}
|
||||
for provider in providers.reranking_providers.values()
|
||||
for model in provider.models
|
||||
]
|
||||
build_config["reranker"]["value"] = build_config["reranker"]["options"][0]
|
||||
|
||||
# Set the default search field to hybrid search
|
||||
build_config["search_method"]["show"] = True
|
||||
build_config["search_method"]["options"] = ["Hybrid Search", "Vector Search"]
|
||||
build_config["search_method"]["value"] = "Hybrid Search"
|
||||
except Exception as _: # noqa: BLE001
|
||||
build_config["reranker"]["options"] = []
|
||||
build_config["reranker"]["options_metadata"] = []
|
||||
|
||||
# Set the default search field to vector search
|
||||
build_config["search_method"]["show"] = False
|
||||
build_config["search_method"]["options"] = ["Vector Search"]
|
||||
build_config["search_method"]["value"] = "Vector Search"
|
||||
|
||||
# Set reranker and lexical terms options based on search method
|
||||
build_config["reranker"]["show"] = build_config["search_method"]["value"] == "Hybrid Search"
|
||||
if build_config["reranker"]["show"]:
|
||||
build_config["search_type"]["value"] = "Similarity"
|
||||
|
||||
return build_config
|
||||
|
||||
|
|
@ -778,10 +870,31 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
if field_name == "database_name" and not isinstance(field_value, dict):
|
||||
return self._handle_database_selection(build_config, field_value)
|
||||
|
||||
# Keyspace selection change
|
||||
if field_name == "keyspace":
|
||||
return self.reset_collection_list(build_config)
|
||||
|
||||
# Collection selection change
|
||||
if field_name == "collection_name" and not isinstance(field_value, dict):
|
||||
return self._handle_collection_selection(build_config, field_value)
|
||||
|
||||
# Search method selection change
|
||||
if field_name == "search_method":
|
||||
is_vector_search = field_value == "Vector Search"
|
||||
is_autodetect = build_config["autodetect_collection"]["value"]
|
||||
|
||||
# Configure lexical terms (same for both cases)
|
||||
build_config["lexical_terms"]["show"] = not is_vector_search
|
||||
build_config["lexical_terms"]["value"] = "" if is_vector_search else build_config["lexical_terms"]["value"]
|
||||
|
||||
# Toggle search type and score threshold based on search method
|
||||
build_config["search_type"]["show"] = is_vector_search
|
||||
build_config["search_score_threshold"]["show"] = is_vector_search
|
||||
|
||||
# Make sure the search_type is set to "Similarity"
|
||||
if not is_vector_search or is_autodetect:
|
||||
build_config["search_type"]["value"] = "Similarity"
|
||||
|
||||
return build_config
|
||||
|
||||
async def _create_new_database(self, build_config: dict, field_value: dict) -> None:
|
||||
|
|
@ -805,13 +918,14 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"status": "PENDING",
|
||||
"collections": 0,
|
||||
"api_endpoint": None,
|
||||
"keyspaces": [self.get_keyspace()],
|
||||
"org_id": None,
|
||||
}
|
||||
)
|
||||
|
||||
def _update_cloud_regions(self, build_config: dict, field_value: dict) -> dict:
|
||||
"""Update cloud provider regions in build config."""
|
||||
env = self.environment or "prod"
|
||||
env = self.environment
|
||||
cloud_provider = field_value["02_cloud_provider"]
|
||||
|
||||
# Update the region options based on the selected cloud provider
|
||||
|
|
@ -837,6 +951,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
dimension=field_value.get("04_dimension") if embedding_provider == "Bring your own" else None,
|
||||
embedding_generation_provider=embedding_provider,
|
||||
embedding_generation_model=field_value.get("03_embedding_generation_model"),
|
||||
reranker=self.reranker,
|
||||
)
|
||||
except Exception as e:
|
||||
msg = f"Error creating collection: {e}"
|
||||
|
|
@ -849,17 +964,21 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"options": build_config["collection_name"]["options"] + [field_value["01_new_collection_name"]],
|
||||
}
|
||||
)
|
||||
build_config["embedding_choice"]["value"] = "Astra Vectorize" if provider else "Embedding Model"
|
||||
build_config["embedding_model"]["advanced"] = bool(provider)
|
||||
build_config["embedding_model"]["show"] = not bool(provider)
|
||||
build_config["embedding_model"]["required"] = not bool(provider)
|
||||
build_config["collection_name"]["options_metadata"].append(
|
||||
{
|
||||
"records": 0,
|
||||
"provider": provider,
|
||||
"icon": self.get_provider_icon(provider_name=embedding_provider),
|
||||
"icon": self.get_provider_icon(provider_name=provider),
|
||||
"model": field_value.get("03_embedding_generation_model"),
|
||||
}
|
||||
)
|
||||
|
||||
# Make sure we always show the reranker options if the collection is hybrid enabled
|
||||
# And right now they always are
|
||||
build_config["lexical_terms"]["show"] = True
|
||||
|
||||
def _handle_database_selection(self, build_config: dict, field_value: str) -> dict:
|
||||
"""Handle database selection and update related configurations."""
|
||||
build_config = self.reset_database_list(build_config)
|
||||
|
|
@ -878,9 +997,17 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
if not org_id:
|
||||
return build_config
|
||||
|
||||
# Update the list of keyspaces based on the db info
|
||||
build_config["keyspace"]["options"] = build_config["database_name"]["options_metadata"][index]["keyspaces"]
|
||||
build_config["keyspace"]["value"] = (
|
||||
build_config["keyspace"]["options"] and build_config["keyspace"]["options"][0]
|
||||
if build_config["keyspace"]["value"] not in build_config["keyspace"]["options"]
|
||||
else build_config["keyspace"]["value"]
|
||||
)
|
||||
|
||||
# Get the database id for the selected database
|
||||
db_id = self.get_database_id_static(api_endpoint=build_config["api_endpoint"]["value"])
|
||||
keyspace = self.get_keyspace() or "default_keyspace"
|
||||
keyspace = self.get_keyspace()
|
||||
|
||||
# Update the helper text for the embedding provider field
|
||||
template = build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"]
|
||||
|
|
@ -894,6 +1021,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
# Reset provider options
|
||||
build_config = self.reset_provider_options(build_config)
|
||||
|
||||
# Handle hybrid search options
|
||||
build_config = self._handle_hybrid_search_options(build_config)
|
||||
|
||||
return self.reset_collection_list(build_config)
|
||||
|
||||
def _handle_collection_selection(self, build_config: dict, field_value: str) -> dict:
|
||||
|
|
@ -901,6 +1031,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
build_config["autodetect_collection"]["value"] = True
|
||||
build_config = self.reset_collection_list(build_config)
|
||||
|
||||
# Reset embedding model if collection selection changes
|
||||
if field_value and field_value not in build_config["collection_name"]["options"]:
|
||||
build_config["collection_name"]["options"].append(field_value)
|
||||
build_config["collection_name"]["options_metadata"].append(
|
||||
|
|
@ -916,10 +1047,30 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
if not field_value:
|
||||
return build_config
|
||||
|
||||
# Get the selected collection index
|
||||
index = build_config["collection_name"]["options"].index(field_value)
|
||||
|
||||
# Set the provider of the selected collection
|
||||
provider = build_config["collection_name"]["options_metadata"][index]["provider"]
|
||||
build_config["embedding_model"]["advanced"] = bool(provider)
|
||||
build_config["embedding_choice"]["value"] = "Astra Vectorize" if provider else "Embedding Model"
|
||||
build_config["embedding_model"]["show"] = not bool(provider)
|
||||
build_config["embedding_model"]["required"] = not bool(provider)
|
||||
|
||||
# Grab the collection object
|
||||
database = self.get_database_object(api_endpoint=build_config["api_endpoint"]["value"])
|
||||
collection = database.get_collection(
|
||||
name=field_value,
|
||||
keyspace=build_config["keyspace"]["value"],
|
||||
)
|
||||
|
||||
# Check if hybrid and lexical are enabled
|
||||
col_options = collection.options()
|
||||
hyb_enabled = col_options.rerank and col_options.rerank.enabled
|
||||
lex_enabled = col_options.lexical and col_options.lexical.enabled
|
||||
user_hyb_enabled = build_config["search_method"]["value"] == "Hybrid Search"
|
||||
|
||||
# Show lexical terms if the collection is hybrid enabled
|
||||
build_config["lexical_terms"]["show"] = hyb_enabled and lex_enabled and user_hyb_enabled
|
||||
|
||||
return build_config
|
||||
|
||||
@check_cached_vector_store
|
||||
|
|
@ -934,11 +1085,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
raise ImportError(msg) from e
|
||||
|
||||
# Get the embedding model and additional params
|
||||
embedding_params = (
|
||||
{"embedding": self.embedding_model}
|
||||
if self.embedding_model and self.embedding_choice == "Embedding Model"
|
||||
else {}
|
||||
)
|
||||
embedding_params = {"embedding": self.embedding_model} if self.embedding_model else {}
|
||||
|
||||
# Get the additional parameters
|
||||
additional_params = self.astradb_vectorstore_kwargs or {}
|
||||
|
|
@ -969,6 +1116,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
"ignore_invalid_documents": self.ignore_invalid_documents,
|
||||
}
|
||||
|
||||
# Choose HybridSearchMode based on the selected param
|
||||
hybrid_search_mode = HybridSearchMode.DEFAULT if self.search_method == "Hybrid Search" else HybridSearchMode.OFF
|
||||
|
||||
# Attempt to build the Vector Store object
|
||||
try:
|
||||
vector_store = AstraDBVectorStore(
|
||||
|
|
@ -978,6 +1128,8 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
namespace=database.keyspace,
|
||||
collection_name=self.collection_name,
|
||||
environment=self.environment,
|
||||
# Hybrid Search Parameters
|
||||
hybrid_search=hybrid_search_mode,
|
||||
# Astra DB Usage Tracking Parameters
|
||||
ext_callers=[(f"{langflow_prefix}langflow", __version__)],
|
||||
# Astra DB Vector Store Parameters
|
||||
|
|
@ -1036,14 +1188,18 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
return search_type_mapping.get(self.search_type, "similarity")
|
||||
|
||||
def _build_search_args(self):
|
||||
# Clean up the search query
|
||||
query = self.search_query if isinstance(self.search_query, str) and self.search_query.strip() else None
|
||||
lexical_terms = self.lexical_terms or None
|
||||
|
||||
# Check if we have a search query, and if so set the args
|
||||
if query:
|
||||
args = {
|
||||
"query": query,
|
||||
"search_type": self._map_search_type(),
|
||||
"k": self.number_of_results,
|
||||
"score_threshold": self.search_score_threshold,
|
||||
"lexical_query": lexical_terms,
|
||||
}
|
||||
elif self.advanced_search_filter:
|
||||
args = {
|
||||
|
|
@ -1064,6 +1220,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
|
|||
self.log(f"Search input: {self.search_query}")
|
||||
self.log(f"Search type: {self.search_type}")
|
||||
self.log(f"Number of results: {self.number_of_results}")
|
||||
self.log(f"store.hybrid_search: {vector_store.hybrid_search}")
|
||||
self.log(f"Lexical terms: {self.lexical_terms}")
|
||||
self.log(f"Reranker: {self.reranker}")
|
||||
|
||||
try:
|
||||
search_args = self._build_search_args()
|
||||
|
|
|
|||
|
|
@ -194,16 +194,14 @@ class HCDVectorStoreComponent(LCVectorStoreComponent):
|
|||
if not isinstance(self.embedding, dict):
|
||||
embedding_dict = {"embedding": self.embedding}
|
||||
else:
|
||||
from astrapy.info import CollectionVectorServiceOptions
|
||||
from astrapy.info import VectorServiceOptions
|
||||
|
||||
dict_options = self.embedding.get("collection_vector_service_options", {})
|
||||
dict_options["authentication"] = {
|
||||
k: v for k, v in dict_options.get("authentication", {}).items() if k and v
|
||||
}
|
||||
dict_options["parameters"] = {k: v for k, v in dict_options.get("parameters", {}).items() if k and v}
|
||||
embedding_dict = {
|
||||
"collection_vector_service_options": CollectionVectorServiceOptions.from_dict(dict_options)
|
||||
}
|
||||
embedding_dict = {"collection_vector_service_options": VectorServiceOptions.from_dict(dict_options)}
|
||||
collection_embedding_api_key = self.embedding.get("collection_embedding_api_key")
|
||||
if collection_embedding_api_key:
|
||||
embedding_dict["collection_embedding_api_key"] = collection_embedding_api_key
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -202,6 +202,18 @@ class DropDownMixin(BaseModel):
|
|||
"""Variable that defines if the user can insert custom values in the dropdown."""
|
||||
dialog_inputs: dict[str, Any] | None = None
|
||||
"""Dictionary of dialog inputs for the field. Default is an empty object."""
|
||||
toggle: bool = False
|
||||
"""Variable that defines if a toggle button is shown."""
|
||||
toggle_value: bool | None = None
|
||||
"""Variable that defines the value of the toggle button. Defaults to None."""
|
||||
|
||||
@field_validator("toggle_value")
|
||||
@classmethod
|
||||
def validate_toggle_value(cls, v):
|
||||
if v is not None and not isinstance(v, bool):
|
||||
msg = "toggle_value must be a boolean or None"
|
||||
raise ValueError(msg)
|
||||
return v
|
||||
|
||||
|
||||
class SortableListMixin(BaseModel):
|
||||
|
|
|
|||
|
|
@ -459,6 +459,8 @@ class DropdownInput(BaseInputMixin, DropDownMixin, MetadataTraceMixin, ToolModeM
|
|||
options_metadata (Optional[list[dict[str, str]]): List of dictionaries with metadata for each option.
|
||||
Default is None.
|
||||
combobox (CoalesceBool): Variable that defines if the user can insert custom values in the dropdown.
|
||||
toggle (CoalesceBool): Variable that defines if a toggle button is shown.
|
||||
toggle_value (CoalesceBool | None): Variable that defines the value of the toggle button. Defaults to None.
|
||||
"""
|
||||
|
||||
field_type: SerializableFieldTypes = FieldTypes.TEXT
|
||||
|
|
@ -466,6 +468,8 @@ class DropdownInput(BaseInputMixin, DropDownMixin, MetadataTraceMixin, ToolModeM
|
|||
options_metadata: list[dict[str, Any]] = Field(default_factory=list)
|
||||
combobox: CoalesceBool = False
|
||||
dialog_inputs: dict[str, Any] = Field(default_factory=dict)
|
||||
toggle: bool = False
|
||||
toggle_value: bool | None = None
|
||||
|
||||
|
||||
class ConnectionInput(BaseInputMixin, ConnectionMixin, MetadataTraceMixin, ToolModeMixin):
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ _convert_field_type_to_type: dict[FieldTypes, type] = {
|
|||
FieldTypes.CODE: str,
|
||||
FieldTypes.OTHER: str,
|
||||
FieldTypes.TAB: str,
|
||||
FieldTypes.QUERY: str,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ DIRECT_TYPES = [
|
|||
"sortableList",
|
||||
"auth",
|
||||
"connect",
|
||||
"query",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import os
|
|||
|
||||
import pytest
|
||||
from astrapy import DataAPIClient
|
||||
from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions
|
||||
from langchain_astradb import AstraDBVectorStore, VectorServiceOptions
|
||||
from langchain_core.documents import Document
|
||||
from langflow.components.embeddings import OpenAIEmbeddingsComponent
|
||||
from langflow.components.vectorstores import AstraDBVectorStoreComponent
|
||||
|
|
@ -30,8 +30,8 @@ ALL_COLLECTIONS = [
|
|||
|
||||
@pytest.fixture
|
||||
def astradb_client():
|
||||
api_client = DataAPIClient(token=get_astradb_application_token())
|
||||
client = api_client.get_database(get_astradb_api_endpoint())
|
||||
api_client = DataAPIClient()
|
||||
client = api_client.get_database(get_astradb_api_endpoint(), token=get_astradb_application_token())
|
||||
|
||||
yield client # Provide the client to the test functions
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ def test_astra_vectorize():
|
|||
collection_name=VECTORIZE_COLLECTION,
|
||||
api_endpoint=api_endpoint,
|
||||
token=application_token,
|
||||
collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options),
|
||||
collection_vector_service_options=VectorServiceOptions._from_dict(options),
|
||||
)
|
||||
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
|
|
@ -150,7 +150,7 @@ def test_astra_vectorize_with_provider_api_key():
|
|||
collection_name=VECTORIZE_COLLECTION_OPENAI,
|
||||
api_endpoint=api_endpoint,
|
||||
token=application_token,
|
||||
collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options),
|
||||
collection_vector_service_options=VectorServiceOptions._from_dict(options),
|
||||
collection_embedding_api_key=os.getenv("OPENAI_API_KEY"),
|
||||
)
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
|
|
@ -195,7 +195,7 @@ def test_astra_vectorize_passes_authentication():
|
|||
collection_name=VECTORIZE_COLLECTION_OPENAI_WITH_AUTH,
|
||||
api_endpoint=api_endpoint,
|
||||
token=application_token,
|
||||
collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options),
|
||||
collection_vector_service_options=VectorServiceOptions._from_dict(options),
|
||||
)
|
||||
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export default function Dropdown({
|
|||
name,
|
||||
dialogInputs,
|
||||
handleOnNewValue,
|
||||
toggle,
|
||||
...baseInputProps
|
||||
}: BaseInputProps & DropDownComponent): JSX.Element {
|
||||
const validOptions = useMemo(
|
||||
|
|
@ -482,6 +483,19 @@ export default function Dropdown({
|
|||
<PopoverAnchor>{children}</PopoverAnchor>
|
||||
) : refreshOptions || isLoading ? (
|
||||
renderLoadingButton()
|
||||
) : validOptions.length === 1 &&
|
||||
toggle &&
|
||||
!combobox &&
|
||||
value === validOptions[0] ? (
|
||||
<div className="flex w-full items-center gap-2 truncate">
|
||||
{optionsMetaData?.[0]?.icon && (
|
||||
<ForwardedIconComponent
|
||||
name={optionsMetaData?.[0]?.icon}
|
||||
className="h-4 w-4 flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
<span className="truncate text-sm">{value}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full truncate">{renderTriggerButton()}</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import Dropdown from "../../../dropdownComponent";
|
||||
import { DropDownComponentType, InputProps } from "../../types";
|
||||
import ToggleShadComponent from "../toggleShadComponent";
|
||||
|
||||
export default function DropdownComponent({
|
||||
id,
|
||||
|
|
@ -15,6 +16,8 @@ export default function DropdownComponent({
|
|||
nodeClass,
|
||||
nodeId,
|
||||
handleNodeClass,
|
||||
toggle,
|
||||
toggleValue,
|
||||
...baseInputProps
|
||||
}: InputProps<string, DropDownComponentType>) {
|
||||
const onChange = (value: any, dbValue?: boolean, skipSnapshot?: boolean) => {
|
||||
|
|
@ -22,22 +25,39 @@ export default function DropdownComponent({
|
|||
};
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
disabled={disabled}
|
||||
editNode={editNode}
|
||||
options={options}
|
||||
nodeId={nodeId}
|
||||
nodeClass={nodeClass}
|
||||
handleNodeClass={handleNodeClass}
|
||||
optionsMetaData={optionsMetaData}
|
||||
onSelect={onChange}
|
||||
combobox={combobox}
|
||||
value={value || ""}
|
||||
id={`dropdown_${id}`}
|
||||
name={name}
|
||||
dialogInputs={dialogInputs}
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
{...baseInputProps}
|
||||
/>
|
||||
<div className="flex w-full items-center gap-4">
|
||||
<Dropdown
|
||||
disabled={disabled || toggleValue === false}
|
||||
editNode={editNode}
|
||||
toggle={toggle}
|
||||
options={options}
|
||||
nodeId={nodeId}
|
||||
nodeClass={nodeClass}
|
||||
handleNodeClass={handleNodeClass}
|
||||
optionsMetaData={optionsMetaData}
|
||||
onSelect={onChange}
|
||||
combobox={combobox}
|
||||
value={value || (toggleValue === false && toggle ? options[0] : "")}
|
||||
id={`dropdown_${id}`}
|
||||
name={name}
|
||||
dialogInputs={dialogInputs}
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
{...baseInputProps}
|
||||
/>
|
||||
{toggle && (
|
||||
<ToggleShadComponent
|
||||
value={toggleValue ?? true}
|
||||
handleOnNewValue={(data) => {
|
||||
handleOnNewValue({
|
||||
value: data.value === true ? options[0] : null,
|
||||
toggle_value: data.value,
|
||||
});
|
||||
}}
|
||||
editNode={editNode}
|
||||
id={`toggle_dropdown_${id}`}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ export function StrRenderComponent({
|
|||
optionsMetaData={templateData.options_metadata}
|
||||
combobox={templateData.combobox}
|
||||
name={templateData?.name!}
|
||||
toggle={templateData.toggle}
|
||||
toggleValue={templateData.toggle_value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ export type DropDownComponentType = {
|
|||
nodeId: string;
|
||||
nodeClass: APIClassType;
|
||||
handleNodeClass: (value: any, code?: string, type?: string) => void;
|
||||
toggle?: boolean;
|
||||
toggleValue?: boolean;
|
||||
};
|
||||
|
||||
export type TextAreaComponentType = {
|
||||
|
|
|
|||
23
src/frontend/src/icons/SearchHybrid/SearchHybridIcon.jsx
Normal file
23
src/frontend/src/icons/SearchHybrid/SearchHybridIcon.jsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const SvgSearchHybridIcon = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M15.75 15.75L12.525 12.525L15.75 15.75Z" fill="currentColor" />
|
||||
<path
|
||||
d="M1.5 11.625C3.36396 11.625 4.875 10.114 4.875 8.25C4.875 10.114 6.38604 11.625 8.25 11.625C6.38604 11.625 4.875 13.136 4.875 15C4.875 13.136 3.36396 11.625 1.5 11.625Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M15.75 15.75L12.525 12.525M2.43903 6.75C3.10509 4.16216 5.45424 2.25 8.25 2.25C11.5637 2.25 14.25 4.93629 14.25 8.25C14.25 11.0458 12.3378 13.3949 9.75 14.061M4.875 8.25C4.875 10.114 3.36396 11.625 1.5 11.625C3.36396 11.625 4.875 13.136 4.875 15C4.875 13.136 6.38604 11.625 8.25 11.625C6.38604 11.625 4.875 10.114 4.875 8.25Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default SvgSearchHybridIcon;
|
||||
9
src/frontend/src/icons/SearchHybrid/index.tsx
Normal file
9
src/frontend/src/icons/SearchHybrid/index.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React, { forwardRef } from "react";
|
||||
import SvgSearchHybridIcon from "./SearchHybridIcon";
|
||||
|
||||
export const SearchHybridIcon = forwardRef<
|
||||
SVGSVGElement,
|
||||
React.PropsWithChildren<{}>
|
||||
>((props, ref) => {
|
||||
return <SvgSearchHybridIcon ref={ref} {...props} />;
|
||||
});
|
||||
22
src/frontend/src/icons/SearchLexical/SearchLexicalIcon.jsx
Normal file
22
src/frontend/src/icons/SearchLexical/SearchLexicalIcon.jsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const SvgSearchLexicalIcon = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M15.75 15.75L12.525 12.525L15.75 15.75Z" fill="currentColor" />
|
||||
<path d="M3.75 15H5.25H6.75" fill="currentColor" />
|
||||
<path d="M5.25 9.75V15V9.75Z" fill="currentColor" />
|
||||
<path d="M8.25 11.25V9.75H5.25H2.25V11.25" fill="currentColor" />
|
||||
<path
|
||||
d="M15.75 15.75L12.525 12.525M2.43903 6.75C3.1051 4.16216 5.45425 2.25 8.25001 2.25C11.5637 2.25 14.25 4.93629 14.25 8.25C14.25 11.0458 12.3378 13.3949 9.75001 14.061M3.75 15H5.25M6.75 15H5.25M5.25 9.75V15M5.25 9.75H8.25V11.25M5.25 9.75H2.25V11.25"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default SvgSearchLexicalIcon;
|
||||
9
src/frontend/src/icons/SearchLexical/index.tsx
Normal file
9
src/frontend/src/icons/SearchLexical/index.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React, { forwardRef } from "react";
|
||||
import SvgSearchLexicalIcon from "./SearchLexicalIcon";
|
||||
|
||||
export const SearchLexicalIcon = forwardRef<
|
||||
SVGSVGElement,
|
||||
React.PropsWithChildren<{}>
|
||||
>((props, ref) => {
|
||||
return <SvgSearchLexicalIcon ref={ref} {...props} />;
|
||||
});
|
||||
19
src/frontend/src/icons/SearchVector/SearchVectorIcon.jsx
Normal file
19
src/frontend/src/icons/SearchVector/SearchVectorIcon.jsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
const SvgSearchVectorIcon = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M15.75 15.75L12.525 12.525L15.75 15.75Z" fill="currentColor" />
|
||||
<path
|
||||
d="M15.75 15.75L12.525 12.525M2.43903 6.75C3.1051 4.16216 5.45425 2.25 8.25001 2.25C11.5637 2.25 14.25 4.93629 14.25 8.25C14.25 11.0458 12.3378 13.3949 9.75001 14.061M2.25 14.25V11.25M2.25 14.25H5.25M2.25 14.25L7.5 9"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default SvgSearchVectorIcon;
|
||||
9
src/frontend/src/icons/SearchVector/index.tsx
Normal file
9
src/frontend/src/icons/SearchVector/index.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React, { forwardRef } from "react";
|
||||
import SvgSearchVectorIcon from "./SearchVectorIcon";
|
||||
|
||||
export const SearchVectorIcon = forwardRef<
|
||||
SVGSVGElement,
|
||||
React.PropsWithChildren<{}>
|
||||
>((props, ref) => {
|
||||
return <SvgSearchVectorIcon ref={ref} {...props} />;
|
||||
});
|
||||
|
|
@ -47,7 +47,7 @@ export default function QueryModal({
|
|||
<div className={classNames("flex h-full w-full rounded-lg border")}>
|
||||
<Textarea
|
||||
ref={textRef}
|
||||
className="form-input h-full w-full resize-none overflow-auto rounded-lg focus-visible:ring-1"
|
||||
className="form-input h-full min-h-28 w-full overflow-auto rounded-lg focus-visible:ring-1"
|
||||
value={inputValue}
|
||||
onChange={(event) => {
|
||||
setInputValue(event.target.value);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ export type DropDownComponent = {
|
|||
children?: ReactNode;
|
||||
name: string;
|
||||
dialogInputs?: any;
|
||||
toggle?: boolean;
|
||||
};
|
||||
export type ParameterComponentType = {
|
||||
selected?: boolean;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import { MilvusIcon } from "@/icons/Milvus";
|
|||
import { OneDriveIcon } from "@/icons/OneDrive";
|
||||
import Perplexity from "@/icons/Perplexity/Perplexity";
|
||||
import { SearchAPIIcon } from "@/icons/SearchAPI";
|
||||
import { SearchHybridIcon } from "@/icons/SearchHybrid";
|
||||
import { SearchLexicalIcon } from "@/icons/SearchLexical";
|
||||
import { SearchVectorIcon } from "@/icons/SearchVector";
|
||||
import { SerpSearchIcon } from "@/icons/SerpSearch";
|
||||
import { TavilyIcon } from "@/icons/Tavily";
|
||||
import { UnstructuredIcon } from "@/icons/Unstructured";
|
||||
|
|
@ -754,6 +757,9 @@ export const nodeIconsLucide: iconsType = {
|
|||
OpenAI: OpenAiIcon,
|
||||
OpenRouter: OpenRouterIcon,
|
||||
DeepSeek: DeepSeekIcon,
|
||||
SearchLexical: SearchLexicalIcon,
|
||||
SearchHybrid: SearchHybridIcon,
|
||||
SearchVector: SearchVectorIcon,
|
||||
xAI: XAIIcon,
|
||||
OpenAIEmbeddings: OpenAiIcon,
|
||||
Pinecone: PineconeIcon,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { addFlowToTestOnEmptyLangflow } from "../../utils/add-flow-to-test-on-empty-langflow";
|
||||
import { adjustScreenView } from "../../utils/adjust-screen-view";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
|
||||
|
|
@ -62,6 +63,12 @@ test(
|
|||
await page.waitForSelector('[data-testid="mainpage_title"]', {
|
||||
timeout: 30000,
|
||||
});
|
||||
const countEmptyButton = await page
|
||||
.getByTestId("new_project_btn_empty_page")
|
||||
.count();
|
||||
if (countEmptyButton > 0) {
|
||||
await addFlowToTestOnEmptyLangflow(page);
|
||||
}
|
||||
await page.getByTestId("upload-folder-button").last().click();
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { addFlowToTestOnEmptyLangflow } from "../../utils/add-flow-to-test-on-empty-langflow";
|
||||
import { addLegacyComponents } from "../../utils/add-legacy-components";
|
||||
import { adjustScreenView } from "../../utils/adjust-screen-view";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
|
|
@ -9,6 +10,10 @@ test(
|
|||
async ({ page }) => {
|
||||
await awaitBootstrapTest(page);
|
||||
|
||||
await page.waitForSelector('[data-testid="mainpage_title"]', {
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
await page.getByTestId("blank-flow").click();
|
||||
|
||||
await page.waitForSelector('[data-testid="sidebar-options-trigger"]', {
|
||||
|
|
@ -73,7 +78,7 @@ test(
|
|||
"vectorstoresAstra DB",
|
||||
"langchain_utilitiesTool Calling Agent",
|
||||
"langchain_utilitiesConversationChain",
|
||||
"memoriesAstra DB Chat Memory",
|
||||
"memoriesMem0 Chat Memory",
|
||||
"logicCondition",
|
||||
"langchain_utilitiesSelf Query Retriever",
|
||||
"langchain_utilitiesCharacterTextSplitter",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Page } from "playwright/test";
|
||||
import { addFlowToTestOnEmptyLangflow } from "./add-flow-to-test-on-empty-langflow";
|
||||
|
||||
export const awaitBootstrapTest = async (
|
||||
page: Page,
|
||||
|
|
@ -15,6 +16,13 @@ export const awaitBootstrapTest = async (
|
|||
timeout: 30000,
|
||||
});
|
||||
|
||||
const countEmptyButton = await page
|
||||
.getByTestId("new_project_btn_empty_page")
|
||||
.count();
|
||||
if (countEmptyButton > 0) {
|
||||
await addFlowToTestOnEmptyLangflow(page);
|
||||
}
|
||||
|
||||
await page.waitForSelector('[id="new-project-btn"]', {
|
||||
timeout: 30000,
|
||||
});
|
||||
|
|
|
|||
35
uv.lock
generated
35
uv.lock
generated
|
|
@ -395,7 +395,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "astra-assistants"
|
||||
version = "2.2.11"
|
||||
version = "2.2.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
|
|
@ -410,9 +410,9 @@ dependencies = [
|
|||
{ name = "tree-sitter" },
|
||||
{ name = "tree-sitter-python" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a4/c5/8e0685e2e886802027bc3510142f536c3d5c8e6b4f5d72d11a6ed42c9da6/astra_assistants-2.2.11.tar.gz", hash = "sha256:580c080bd722bbf4c26517e6c3bc2ca4f7dffb6a02853d28705a75643c4e2083", size = 66264 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/39/59/b9cb94dc9ea9fe8d978d2710c45e83c4e6ba179f3c4447022e23f51d01dd/astra_assistants-2.2.12.tar.gz", hash = "sha256:1b26331e7bebeccac4929b168ec2179a3c09496a2715d2b3e702317af2549b27", size = 66278 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/85/8ea7ab5b09aab9d1274642b50495b820124a24f6d91c5ce559c268336176/astra_assistants-2.2.11-py3-none-any.whl", hash = "sha256:202bc27b31f41c3541a4676b1b8bc2f87581153bb2919aae903f3ffd682ed6e9", size = 78559 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/4c/4b9769885fb74c30dd80d40e8cab03aaa1bc9d075b2d727ab07c8adf5887/astra_assistants-2.2.12-py3-none-any.whl", hash = "sha256:126cda7b40028a76c12fec63a1268b47cc3cc95a4b270165e67fe9e35d59f77f", size = 78578 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
|
@ -424,18 +424,19 @@ tools = [
|
|||
|
||||
[[package]]
|
||||
name = "astrapy"
|
||||
version = "1.5.2"
|
||||
version = "2.0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "deprecation" },
|
||||
{ name = "httpx", extra = ["http2"] },
|
||||
{ name = "pymongo" },
|
||||
{ name = "toml" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "uuid6" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/29/cc/5996efd0598b97d44699f04b5c025080fb1665f30794010f06543f3322a7/astrapy-1.5.2.tar.gz", hash = "sha256:eaf703628b0d03891ae7c391ef04ff3aec1005837fdfa47c19f2ed4478c45a4a", size = 163233 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0c/c9/5c9488664f99f2b9738d8e4823f8a0474897f39a17c0676430f548834adb/astrapy-2.0.1.tar.gz", hash = "sha256:3a35ebd7af5c24f0abe400f9b2778dc5e8812c78ae247f97704be27e6cb9dc5a", size = 252460 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/db/48/684c270724bc3f8d12714556d201aa4610623da919505a6a09e56f50ef6a/astrapy-1.5.2-py3-none-any.whl", hash = "sha256:598b86de723727a11ec43e1c7fe682ecb42d63d37a94165fb08de41c20103f56", size = 177128 },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/6d/1481615ec3b97e1b8c9058c43c804e02612642d5114a26812894e42fb9b4/astrapy-2.0.1-py3-none-any.whl", hash = "sha256:4fa37f2955e7543a29e78565833de0dc8e39316ccc2f66263a4665b5871b7739", size = 300495 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2010,7 +2011,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "e2b"
|
||||
version = "1.1.0"
|
||||
version = "1.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
|
|
@ -2021,23 +2022,23 @@ dependencies = [
|
|||
{ name = "python-dateutil" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/23/de/d051c7f6d762e2f743a4d5efebe6b30181c866bb499ec99ac06d3897ff6e/e2b-1.1.0.tar.gz", hash = "sha256:bd054fbaa9baed48919500ba853bdb72c750b04e0bac8365bde75cdfbdf80d18", size = 45977 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0c/cc/811bf0d20aefdecb72905068107e33728c353e3deedbb6daeae355a40504/e2b-1.3.3.tar.gz", hash = "sha256:b0afb2e3b8edaade44a50d40dbf8934cbd9e2bc3c1c214ce11dbfd9e1d6815b0", size = 51402 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/af/da/c0aea566943a85ab8660e1dd69668769c5a092ae69e957b682000fb63bde/e2b-1.1.0-py3-none-any.whl", hash = "sha256:5d99c675e155cf124f457d77f91c4cb32b286d241ca6cd37ac8d6c0711fc272e", size = 83132 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/5b/5826c80e4de1a99bdde3a10995bf56c7c7d779fb58476c93fa542a626f40/e2b-1.3.3-py3-none-any.whl", hash = "sha256:1f851345fd22abc1f16fb82197e88786909323edfd140a7a17b8a6ed4bd4ef03", size = 96021 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "e2b-code-interpreter"
|
||||
version = "1.1.1"
|
||||
version = "1.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
{ name = "e2b" },
|
||||
{ name = "httpx" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4c/a0/aa992090fc02ea7eeafce9b4fc122546c8dd81e85810c0d06bfd4c29a6a2/e2b_code_interpreter-1.1.1.tar.gz", hash = "sha256:b13091f75fc127ad3a268b8746e5da996c6734f432e606fcd4f3897a5b1c2bf0", size = 9288 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c6/16/93bd4581fac26f57ae4dba209a127893901636e3dc25db9dea037d9b1952/e2b_code_interpreter-1.2.0.tar.gz", hash = "sha256:9e02d043ab5986232a684018d718014bd5038b421b04a8726952094ef0387e78", size = 9288 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/40/dcdc47d039dd85e74df2532a01e9d47031fbfdfdc20c0b2de4e42b557271/e2b_code_interpreter-1.1.1-py3-none-any.whl", hash = "sha256:f56450b192456f24df89b9159d1067d50c7133d587ab12116144638969409578", size = 12049 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/c3/90880b4d9714ce703b794890b12727cb76330b33d3d08c11387bf6720c51/e2b_code_interpreter-1.2.0-py3-none-any.whl", hash = "sha256:4f94ba29eceada30ec7d379f76b243d69b76da6b67324b986778743346446505", size = 12048 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4110,16 +4111,16 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "langchain-astradb"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "astrapy" },
|
||||
{ name = "langchain-community" },
|
||||
{ name = "numpy" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c5/0e/6fc78ecc3af34cd044f97c5fd14ebde318920cdb9d2a0106e1ec194c42c9/langchain_astradb-0.5.3.tar.gz", hash = "sha256:c9b05d6288d645416c9e867cb86d90d8ff15a679f50941dd59ffdf18d7dc1d27", size = 52093 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0f/3c/e8cd9e7a091e5c9f459856b6f7270ae56f8b84ccf953c16506f3f0c3a276/langchain_astradb-0.6.0.tar.gz", hash = "sha256:5254a85923aa3b0a5850277aa467c3a281f6bafd9b6e1454de6c66c4062ad6d8", size = 64975 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/94/93/469c6ef15198148df9309c7426a657c457d63e24ebb4af7182f49b5949d5/langchain_astradb-0.5.3-py3-none-any.whl", hash = "sha256:42b1baf690270d160caf90b6cbdb82e43e4ab224f3b2b6ffcb57bcd7d23bf265", size = 58672 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/d3/b540e6639d8e4f0907c6b9c9226e8f92756bfaeff6b5be58eadb2aed3a72/langchain_astradb-0.6.0-py3-none-any.whl", hash = "sha256:dc5886b29e50f24d6ab5356fdda6aa8b3e5b8c718e2493c8f263d9ecef42d9b4", size = 69654 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4709,7 +4710,7 @@ requires-dist = [
|
|||
{ name = "apify-client", specifier = ">=1.8.1" },
|
||||
{ name = "arize-phoenix-otel", specifier = ">=0.6.1" },
|
||||
{ name = "assemblyai", specifier = "==0.35.1" },
|
||||
{ name = "astra-assistants", extras = ["tools"], specifier = "~=2.2.11" },
|
||||
{ name = "astra-assistants", extras = ["tools"], specifier = "~=2.2.12" },
|
||||
{ name = "atlassian-python-api", specifier = "==3.41.16" },
|
||||
{ name = "beautifulsoup4", specifier = "==4.12.3" },
|
||||
{ name = "boto3", specifier = "==1.34.162" },
|
||||
|
|
@ -4742,7 +4743,7 @@ requires-dist = [
|
|||
{ name = "kubernetes", specifier = "==31.0.0" },
|
||||
{ name = "langchain", specifier = "==0.3.10" },
|
||||
{ name = "langchain-anthropic", specifier = "==0.3.0" },
|
||||
{ name = "langchain-astradb", specifier = "==0.5.3" },
|
||||
{ name = "langchain-astradb", specifier = "~=0.6.0" },
|
||||
{ name = "langchain-aws", specifier = "==0.2.7" },
|
||||
{ name = "langchain-chroma", specifier = "==0.1.4" },
|
||||
{ name = "langchain-cohere", specifier = "==0.3.3" },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue