Merge branch 'dev' into migrations_service
This commit is contained in:
commit
a6cacbf377
18 changed files with 529 additions and 433 deletions
|
|
@ -66,3 +66,30 @@ def merge_nested_dicts(dict1, dict2):
|
|||
else:
|
||||
dict1[key] = value
|
||||
return dict1
|
||||
|
||||
|
||||
def merge_nested_dicts_with_renaming(dict1, dict2):
|
||||
for key, value in dict2.items():
|
||||
if (
|
||||
key in dict1
|
||||
and isinstance(value, dict)
|
||||
and isinstance(dict1.get(key), dict)
|
||||
):
|
||||
for sub_key, sub_value in value.items():
|
||||
if sub_key in dict1[key]:
|
||||
new_key = get_new_key(dict1[key], sub_key)
|
||||
dict1[key][new_key] = sub_value
|
||||
else:
|
||||
dict1[key][sub_key] = sub_value
|
||||
else:
|
||||
dict1[key] = value
|
||||
return dict1
|
||||
|
||||
|
||||
def get_new_key(dictionary, original_key):
|
||||
counter = 1
|
||||
new_key = original_key + " (" + str(counter) + ")"
|
||||
while new_key in dictionary:
|
||||
counter += 1
|
||||
new_key = original_key + " (" + str(counter) + ")"
|
||||
return new_key
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ async def stream_build(flow_id: str):
|
|||
)
|
||||
else:
|
||||
input_keys_response = {
|
||||
"input_keys": {},
|
||||
"input_keys": None,
|
||||
"memory_keys": [],
|
||||
"handle_keys": [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ from langflow.api.v1.schemas import (
|
|||
CustomComponentCode,
|
||||
)
|
||||
|
||||
from langflow.api.utils import merge_nested_dicts
|
||||
from langflow.api.utils import merge_nested_dicts_with_renaming
|
||||
|
||||
from langflow.interface.types import (
|
||||
build_langchain_types_dict,
|
||||
|
|
@ -48,14 +48,21 @@ def get_all():
|
|||
build_langchain_custom_component_list_from_path(str(path))
|
||||
for path in settings_manager.settings.COMPONENTS_PATH
|
||||
]
|
||||
logger.info(f"Loading {len(custom_component_dicts)} custom components")
|
||||
|
||||
logger.info(f"Loading {len(custom_component_dicts)} category(ies)")
|
||||
for custom_component_dict in custom_component_dicts:
|
||||
custom_components_from_file = merge_nested_dicts(
|
||||
# custom_component_dict is a dict of dicts
|
||||
category = list(custom_component_dict.keys())[0]
|
||||
logger.info(
|
||||
f"Loading {len(custom_component_dict[category])} component(s) from category {category}"
|
||||
)
|
||||
logger.debug(custom_component_dict)
|
||||
custom_components_from_file = merge_nested_dicts_with_renaming(
|
||||
custom_components_from_file, custom_component_dict
|
||||
)
|
||||
logger.info(f"Loaded {custom_component_dict}")
|
||||
return merge_nested_dicts(native_components, custom_components_from_file)
|
||||
|
||||
return merge_nested_dicts_with_renaming(
|
||||
native_components, custom_components_from_file
|
||||
)
|
||||
|
||||
|
||||
# For backwards compatibility we will keep the old endpoint
|
||||
|
|
|
|||
|
|
@ -170,6 +170,26 @@ def initialize_pinecone(class_object: Type[Pinecone], params: dict):
|
|||
|
||||
def initialize_chroma(class_object: Type[Chroma], params: dict):
|
||||
"""Initialize a ChromaDB object from the params"""
|
||||
if ( # type: ignore
|
||||
"chroma_server_host" in params or "chroma_server_http_port" in params
|
||||
):
|
||||
import chromadb # type: ignore
|
||||
|
||||
settings_params = {
|
||||
key: params[key]
|
||||
for key, value_ in params.items()
|
||||
if key.startswith("chroma_server_") and value_
|
||||
}
|
||||
chroma_settings = chromadb.config.Settings(**settings_params)
|
||||
params["client_settings"] = chroma_settings
|
||||
else:
|
||||
# remove all chroma_server_ keys from params
|
||||
params = {
|
||||
key: value
|
||||
for key, value in params.items()
|
||||
if not key.startswith("chroma_server_")
|
||||
}
|
||||
|
||||
persist = params.pop("persist", False)
|
||||
if not docs_in_params(params):
|
||||
params.pop("documents", None)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import ast
|
||||
import contextlib
|
||||
from typing import Any
|
||||
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
|
||||
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
||||
|
|
@ -30,7 +31,6 @@ from langflow.interface.retrievers.base import retriever_creator
|
|||
from langflow.interface.custom.directory_reader import DirectoryReader
|
||||
from langflow.utils.logger import logger
|
||||
from langflow.utils.util import get_base_classes
|
||||
from langflow.api.utils import merge_nested_dicts
|
||||
|
||||
import re
|
||||
import warnings
|
||||
|
|
@ -423,4 +423,4 @@ def build_langchain_custom_component_list_from_path(path: str):
|
|||
valid_menu = build_valid_menu(valid_components)
|
||||
invalid_menu = build_invalid_menu(invalid_components)
|
||||
|
||||
return merge_nested_dicts(valid_menu, invalid_menu)
|
||||
return merge_nested_dicts_with_renaming(valid_menu, invalid_menu)
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ class ChatManager(Service):
|
|||
self, client_id: str, payload: Dict, langchain_object: Any
|
||||
):
|
||||
# Process the graph data and chat message
|
||||
chat_inputs = payload.pop("inputs", "")
|
||||
chat_inputs = payload.pop("inputs", {})
|
||||
chat_inputs = ChatMessage(message=chat_inputs)
|
||||
self.chat_history.add_message(client_id, chat_inputs)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ async def process_graph(
|
|||
|
||||
# Generate result and thought
|
||||
try:
|
||||
if not chat_inputs.message:
|
||||
if chat_inputs.message is None:
|
||||
logger.debug("No message provided")
|
||||
raise ValueError("No message provided")
|
||||
chat_inputs.message = {}
|
||||
|
||||
logger.debug("Generating result and thought")
|
||||
result, intermediate_steps = await get_result_and_steps(
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@ class UtilitiesFrontendNode(FrontendNode):
|
|||
FrontendNode.format_field(field, name)
|
||||
# field.field_type could be "Literal['news', 'search', 'places', 'images']
|
||||
# we need to convert it to a list
|
||||
# It seems it could also be like "typing_extensions.['news', 'search', 'places', 'images']"
|
||||
if "Literal" in field.field_type:
|
||||
field.options = ast.literal_eval(field.field_type.replace("Literal", ""))
|
||||
field_type = field.field_type.replace("typing_extensions.", "")
|
||||
field_type = field_type.replace("Literal", "")
|
||||
field.options = ast.literal_eval(field_type)
|
||||
field.is_list = True
|
||||
field.field_type = "str"
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,52 @@ from langflow.template.field.base import TemplateField
|
|||
from langflow.template.frontend_node.base import FrontendNode
|
||||
|
||||
|
||||
BASIC_FIELDS = [
|
||||
"work_dir",
|
||||
"collection_name",
|
||||
"api_key",
|
||||
"location",
|
||||
"persist_directory",
|
||||
"persist",
|
||||
"weaviate_url",
|
||||
"index_name",
|
||||
"namespace",
|
||||
"folder_path",
|
||||
"table_name",
|
||||
"query_name",
|
||||
"supabase_url",
|
||||
"supabase_service_key",
|
||||
"mongodb_atlas_cluster_uri",
|
||||
"collection_name",
|
||||
"db_name",
|
||||
]
|
||||
ADVANCED_FIELDS = [
|
||||
"n_dim",
|
||||
"key",
|
||||
"prefix",
|
||||
"distance_func",
|
||||
"content_payload_key",
|
||||
"metadata_payload_key",
|
||||
"timeout",
|
||||
"host",
|
||||
"path",
|
||||
"url",
|
||||
"port",
|
||||
"https",
|
||||
"prefer_grpc",
|
||||
"grpc_port",
|
||||
"pinecone_api_key",
|
||||
"pinecone_env",
|
||||
"client_kwargs",
|
||||
"search_kwargs",
|
||||
"chroma_server_host",
|
||||
"chroma_server_http_port",
|
||||
"chroma_server_ssl_enabled",
|
||||
"chroma_server_grpc_port",
|
||||
"chroma_server_cors_allow_origins",
|
||||
]
|
||||
|
||||
|
||||
class VectorStoreFrontendNode(FrontendNode):
|
||||
def add_extra_fields(self) -> None:
|
||||
extra_fields: List[TemplateField] = []
|
||||
|
|
@ -45,16 +91,62 @@ class VectorStoreFrontendNode(FrontendNode):
|
|||
|
||||
elif self.template.type_name == "Chroma":
|
||||
# New bool field for persist parameter
|
||||
extra_field = TemplateField(
|
||||
name="persist",
|
||||
field_type="bool",
|
||||
required=False,
|
||||
show=True,
|
||||
advanced=False,
|
||||
value=False,
|
||||
display_name="Persist",
|
||||
)
|
||||
extra_fields.append(extra_field)
|
||||
chroma_fields = [
|
||||
TemplateField(
|
||||
name="persist",
|
||||
field_type="bool",
|
||||
required=False,
|
||||
show=True,
|
||||
advanced=False,
|
||||
value=False,
|
||||
display_name="Persist",
|
||||
),
|
||||
# chroma_server_grpc_port: str | None = None,
|
||||
TemplateField(
|
||||
name="chroma_server_host",
|
||||
field_type="str",
|
||||
required=False,
|
||||
show=True,
|
||||
advanced=True,
|
||||
display_name="Chroma Server Host",
|
||||
),
|
||||
TemplateField(
|
||||
name="chroma_server_http_port",
|
||||
field_type="str",
|
||||
required=False,
|
||||
show=True,
|
||||
advanced=True,
|
||||
display_name="Chroma Server HTTP Port",
|
||||
),
|
||||
TemplateField(
|
||||
name="chroma_server_ssl_enabled",
|
||||
field_type="bool",
|
||||
required=False,
|
||||
show=True,
|
||||
advanced=True,
|
||||
value=False,
|
||||
display_name="Chroma Server SSL Enabled",
|
||||
),
|
||||
TemplateField(
|
||||
name="chroma_server_grpc_port",
|
||||
field_type="str",
|
||||
required=False,
|
||||
show=True,
|
||||
advanced=True,
|
||||
display_name="Chroma Server GRPC Port",
|
||||
),
|
||||
TemplateField(
|
||||
name="chroma_server_cors_allow_origins",
|
||||
field_type="str",
|
||||
required=False,
|
||||
is_list=True,
|
||||
show=True,
|
||||
advanced=True,
|
||||
display_name="Chroma Server CORS Allow Origins",
|
||||
),
|
||||
]
|
||||
|
||||
extra_fields.extend(chroma_fields)
|
||||
elif self.template.type_name == "Pinecone":
|
||||
# add pinecone_api_key and pinecone_env
|
||||
extra_field = TemplateField(
|
||||
|
|
@ -208,45 +300,6 @@ class VectorStoreFrontendNode(FrontendNode):
|
|||
def format_field(field: TemplateField, name: Optional[str] = None) -> None:
|
||||
FrontendNode.format_field(field, name)
|
||||
# Define common field attributes
|
||||
basic_fields = [
|
||||
"work_dir",
|
||||
"collection_name",
|
||||
"api_key",
|
||||
"location",
|
||||
"persist_directory",
|
||||
"persist",
|
||||
"weaviate_url",
|
||||
"index_name",
|
||||
"namespace",
|
||||
"folder_path",
|
||||
"table_name",
|
||||
"query_name",
|
||||
"supabase_url",
|
||||
"supabase_service_key",
|
||||
"mongodb_atlas_cluster_uri",
|
||||
"collection_name",
|
||||
"db_name",
|
||||
]
|
||||
advanced_fields = [
|
||||
"n_dim",
|
||||
"key",
|
||||
"prefix",
|
||||
"distance_func",
|
||||
"content_payload_key",
|
||||
"metadata_payload_key",
|
||||
"timeout",
|
||||
"host",
|
||||
"path",
|
||||
"url",
|
||||
"port",
|
||||
"https",
|
||||
"prefer_grpc",
|
||||
"grpc_port",
|
||||
"pinecone_api_key",
|
||||
"pinecone_env",
|
||||
"client_kwargs",
|
||||
"search_kwargs",
|
||||
]
|
||||
|
||||
# Check and set field attributes
|
||||
if field.name == "texts":
|
||||
|
|
@ -269,7 +322,7 @@ class VectorStoreFrontendNode(FrontendNode):
|
|||
field.display_name = "Embedding"
|
||||
field.field_type = "Embeddings"
|
||||
|
||||
elif field.name in basic_fields:
|
||||
elif field.name in BASIC_FIELDS:
|
||||
field.show = True
|
||||
field.advanced = False
|
||||
if field.name == "api_key":
|
||||
|
|
@ -279,7 +332,7 @@ class VectorStoreFrontendNode(FrontendNode):
|
|||
field.value = ":memory:"
|
||||
field.placeholder = ":memory:"
|
||||
|
||||
elif field.name in advanced_fields:
|
||||
elif field.name in ADVANCED_FIELDS:
|
||||
field.show = True
|
||||
field.advanced = True
|
||||
if "key" in field.name:
|
||||
|
|
|
|||
|
|
@ -82,13 +82,15 @@ export default function BuildTrigger({
|
|||
const parsedData = JSON.parse(event.data);
|
||||
// if the event is the end of the stream, close the connection
|
||||
if (parsedData.end_of_stream) {
|
||||
// Close the connection and finish
|
||||
finished = true;
|
||||
eventSource.close();
|
||||
|
||||
return;
|
||||
} else if (parsedData.log) {
|
||||
// If the event is a log, log it
|
||||
setSuccessData({ title: parsedData.log });
|
||||
} else if (parsedData.input_keys) {
|
||||
} else if (parsedData.input_keys !== undefined) {
|
||||
setTabsState((old) => {
|
||||
return {
|
||||
...old,
|
||||
|
|
|
|||
|
|
@ -62,8 +62,7 @@ export default function Chat({ flow }: ChatType) {
|
|||
tabsState &&
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].formKeysData &&
|
||||
tabsState[flow.id].formKeysData.input_keys &&
|
||||
Object.keys(tabsState[flow.id].formKeysData.input_keys).length > 0
|
||||
tabsState[flow.id].formKeysData.input_keys !== null
|
||||
) {
|
||||
setCanOpen(true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ const ApiModal = forwardRef(
|
|||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://docs.langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
|
|
@ -127,7 +127,7 @@ const ApiModal = forwardRef(
|
|||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://docs.langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
|
|
@ -168,7 +168,7 @@ const ApiModal = forwardRef(
|
|||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://docs.langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
|
|
|
|||
|
|
@ -67,14 +67,17 @@ export default function FormModal({
|
|||
const id = useRef(flow.id);
|
||||
const tabsStateFlowId = tabsState[flow.id];
|
||||
const tabsStateFlowIdFormKeysData = tabsStateFlowId.formKeysData;
|
||||
const [chatKey, setChatKey] = useState(
|
||||
Object.keys(tabsState[flow.id].formKeysData.input_keys).find(
|
||||
(k) =>
|
||||
!tabsState[flow.id].formKeysData.handle_keys.some((j) => j === k) &&
|
||||
tabsState[flow.id].formKeysData.input_keys[k] === ""
|
||||
)
|
||||
);
|
||||
|
||||
const [chatKey, setChatKey] = useState(() => {
|
||||
if (tabsState[flow.id]?.formKeysData?.input_keys) {
|
||||
return Object.keys(tabsState[flow.id].formKeysData.input_keys).find(
|
||||
(k) =>
|
||||
!tabsState[flow.id].formKeysData.handle_keys.some((j) => j === k) &&
|
||||
tabsState[flow.id].formKeysData.input_keys[k] === ""
|
||||
);
|
||||
}
|
||||
// TODO: return a sensible default
|
||||
return "";
|
||||
});
|
||||
useEffect(() => {
|
||||
if (messagesRef.current) {
|
||||
messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
|
||||
|
|
@ -419,68 +422,70 @@ export default function FormModal({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{Object.keys(tabsState[id.current].formKeysData.input_keys).map(
|
||||
(i, k) => (
|
||||
<div className="file-component-accordion-div" key={k}>
|
||||
<AccordionComponent
|
||||
trigger={
|
||||
<div className="file-component-badge-div">
|
||||
<Badge variant="gray" size="md">
|
||||
{i}
|
||||
</Badge>
|
||||
{tabsState[id.current]?.formKeysData?.input_keys
|
||||
? Object.keys(
|
||||
tabsState[id.current].formKeysData.input_keys
|
||||
).map((i, k) => (
|
||||
<div className="file-component-accordion-div" key={k}>
|
||||
<AccordionComponent
|
||||
trigger={
|
||||
<div className="file-component-badge-div">
|
||||
<Badge variant="gray" size="md">
|
||||
{i}
|
||||
</Badge>
|
||||
|
||||
<div
|
||||
className="-mb-1"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
<div
|
||||
className="-mb-1"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<ToggleShadComponent
|
||||
enabled={chatKey === i}
|
||||
setEnabled={(value) =>
|
||||
handleOnCheckedChange(value, i)
|
||||
}
|
||||
size="small"
|
||||
disabled={tabsState[
|
||||
id.current
|
||||
].formKeysData.handle_keys.some((t) => t === i)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
key={k}
|
||||
keyValue={i}
|
||||
>
|
||||
<div className="file-component-tab-column">
|
||||
{tabsState[id.current].formKeysData.handle_keys.some(
|
||||
(t) => t === i
|
||||
) && (
|
||||
<div className="font-normal text-muted-foreground ">
|
||||
Source: Component
|
||||
</div>
|
||||
)}
|
||||
<Textarea
|
||||
className="custom-scroll"
|
||||
value={
|
||||
tabsState[id.current].formKeysData.input_keys[i]
|
||||
}
|
||||
onChange={(e) => {
|
||||
setTabsState((old) => {
|
||||
let newTabsState = _.cloneDeep(old);
|
||||
newTabsState[
|
||||
id.current
|
||||
].formKeysData.input_keys[i] = e.target.value;
|
||||
return newTabsState;
|
||||
});
|
||||
}}
|
||||
>
|
||||
<ToggleShadComponent
|
||||
enabled={chatKey === i}
|
||||
setEnabled={(value) =>
|
||||
handleOnCheckedChange(value, i)
|
||||
}
|
||||
size="small"
|
||||
disabled={tabsState[
|
||||
id.current
|
||||
].formKeysData.handle_keys.some((t) => t === i)}
|
||||
/>
|
||||
</div>
|
||||
disabled={chatKey === i}
|
||||
placeholder="Enter text..."
|
||||
></Textarea>
|
||||
</div>
|
||||
}
|
||||
key={k}
|
||||
keyValue={i}
|
||||
>
|
||||
<div className="file-component-tab-column">
|
||||
{tabsState[id.current].formKeysData.handle_keys.some(
|
||||
(t) => t === i
|
||||
) && (
|
||||
<div className="font-normal text-muted-foreground ">
|
||||
Source: Component
|
||||
</div>
|
||||
)}
|
||||
<Textarea
|
||||
className="custom-scroll"
|
||||
value={
|
||||
tabsState[id.current].formKeysData.input_keys[i]
|
||||
}
|
||||
onChange={(e) => {
|
||||
setTabsState((old) => {
|
||||
let newTabsState = _.cloneDeep(old);
|
||||
newTabsState[id.current].formKeysData.input_keys[
|
||||
i
|
||||
] = e.target.value;
|
||||
return newTabsState;
|
||||
});
|
||||
}}
|
||||
disabled={chatKey === i}
|
||||
placeholder="Enter text..."
|
||||
></Textarea>
|
||||
</div>
|
||||
</AccordionComponent>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</AccordionComponent>
|
||||
</div>
|
||||
))
|
||||
: null}
|
||||
{tabsState[id.current].formKeysData.memory_keys.map((i, k) => (
|
||||
<div className="file-component-accordion-div" key={k}>
|
||||
<AccordionComponent
|
||||
|
|
|
|||
|
|
@ -248,6 +248,27 @@ export function buildTweakObject(tweak) {
|
|||
return tweakString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get Chat Input Field
|
||||
* @param {FlowType} flow - The current flow.
|
||||
* @param {TabsState} tabsState - The current tabs state.
|
||||
* @returns {string} - The chat input field
|
||||
*/
|
||||
export function getChatInputField(flow: FlowType, tabsState?: TabsState) {
|
||||
let chat_input_field = "text";
|
||||
|
||||
if (
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].formKeysData &&
|
||||
tabsState[flow.id].formKeysData.input_keys
|
||||
) {
|
||||
chat_input_field = Object.keys(
|
||||
tabsState[flow.id].formKeysData.input_keys
|
||||
)[0];
|
||||
}
|
||||
return chat_input_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get the python code for the API
|
||||
* @param {string} flowId - The id of the flow
|
||||
|
|
@ -365,6 +386,7 @@ export function getWidgetCode(flow: FlowType, tabsState?: TabsState): string {
|
|||
const flowId = flow.id;
|
||||
const flowName = flow.name;
|
||||
const inputs = buildInputs(tabsState, flow.id);
|
||||
let chat_input_field = getChatInputField(flow, tabsState);
|
||||
|
||||
return `<script src="https://cdn.jsdelivr.net/gh/logspace-ai/langflow-embedded-chat@main/dist/build/static/js/bundle.min.js"></script>
|
||||
|
||||
|
|
@ -377,11 +399,9 @@ chat_input_field: Input key that you want the chat to send the user message with
|
|||
${
|
||||
tabsState[flow.id] && tabsState[flow.id].formKeysData
|
||||
? `chat_inputs='${inputs}'
|
||||
chat_input_field="${
|
||||
Object.keys(tabsState[flow.id].formKeysData.input_keys)[0]
|
||||
}"
|
||||
chat_input_field="${chat_input_field}"
|
||||
`
|
||||
: ""
|
||||
}host_url="http://localhost:7860"
|
||||
}host_url="http://localhost:7860"
|
||||
></langflow-chat>`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue