diff --git a/src/backend/langflow/chat/config.py b/src/backend/langflow/chat/config.py new file mode 100644 index 000000000..274f4d5bd --- /dev/null +++ b/src/backend/langflow/chat/config.py @@ -0,0 +1,2 @@ +class ChatConfig: + streaming: bool = True diff --git a/src/backend/langflow/chat/manager.py b/src/backend/langflow/chat/manager.py index 4a1b8e77c..b693e00a3 100644 --- a/src/backend/langflow/chat/manager.py +++ b/src/backend/langflow/chat/manager.py @@ -209,3 +209,5 @@ class ChatManager: except Exception as e: logger.error(e) self.disconnect(client_id) + + diff --git a/src/backend/langflow/interface/initialize/loading.py b/src/backend/langflow/interface/initialize/loading.py index 756588058..cfa5b5717 100644 --- a/src/backend/langflow/interface/initialize/loading.py +++ b/src/backend/langflow/interface/initialize/loading.py @@ -6,6 +6,7 @@ from langchain.agents import agent as agent_module from langchain.agents.agent import AgentExecutor from langchain.agents.agent_toolkits.base import BaseToolkit from langchain.agents.tools import BaseTool + from langflow.interface.initialize.vector_store import vecstore_initializer from pydantic import ValidationError @@ -20,6 +21,7 @@ from langchain.chains.base import Chain from langchain.vectorstores.base import VectorStore from langchain.document_loaders.base import BaseLoader from langchain.prompts.base import BasePromptTemplate +from langflow.chat.config import ChatConfig def instantiate_class(node_type: str, base_type: str, params: Dict) -> Any: @@ -76,10 +78,21 @@ def instantiate_based_on_type(class_object, base_type, node_type, params): return instantiate_utility(node_type, class_object, params) elif base_type == "chains": return instantiate_chains(node_type, class_object, params) + elif base_type == "llms": + return instantiate_llm(node_type, class_object, params) else: return class_object(**params) +def instantiate_llm(node_type, class_object, params: Dict): + # This is a workaround so JinaChat works until streaming is implemented + # if "openai_api_base" in params and "jina" in params["openai_api_base"]: + # False if condition is True + ChatConfig.streaming = "jina" not in params.get("openai_api_base", "") + + return class_object(**params) + + def instantiate_chains(node_type, class_object: Type[Chain], params: Dict): if "retriever" in params and hasattr(params["retriever"], "as_retriever"): params["retriever"] = params["retriever"].as_retriever() diff --git a/src/backend/langflow/interface/utils.py b/src/backend/langflow/interface/utils.py index 8d45aa1b1..ff89e92bf 100644 --- a/src/backend/langflow/interface/utils.py +++ b/src/backend/langflow/interface/utils.py @@ -4,10 +4,12 @@ import os from io import BytesIO import re + import yaml from langchain.base_language import BaseLanguageModel from PIL.Image import Image from langflow.utils.logger import logger +from langflow.chat.config import ChatConfig def load_file_into_dict(file_path: str) -> dict: @@ -49,9 +51,9 @@ def try_setting_streaming_options(langchain_object, websocket): if isinstance(llm, BaseLanguageModel): if hasattr(llm, "streaming") and isinstance(llm.streaming, bool): - llm.streaming = True + llm.streaming = ChatConfig.streaming elif hasattr(llm, "stream") and isinstance(llm.stream, bool): - llm.stream = True + llm.stream = ChatConfig.streaming return langchain_object diff --git a/src/backend/langflow/template/field/base.py b/src/backend/langflow/template/field/base.py index a9c18ff63..fdfdca562 100644 --- a/src/backend/langflow/template/field/base.py +++ b/src/backend/langflow/template/field/base.py @@ -21,6 +21,7 @@ class TemplateFieldCreator(BaseModel, ABC): name: str = "" display_name: Optional[str] = None advanced: bool = False + info: Optional[str] = "" def to_dict(self): result = self.dict() diff --git a/src/backend/langflow/template/frontend_node/constants.py b/src/backend/langflow/template/frontend_node/constants.py index 20b8a0c61..d30239ff7 100644 --- a/src/backend/langflow/template/frontend_node/constants.py +++ b/src/backend/langflow/template/frontend_node/constants.py @@ -32,3 +32,13 @@ You are a good listener and you can talk about anything. HUMAN_PROMPT = "{input}" QA_CHAIN_TYPES = ["stuff", "map_reduce", "map_rerank", "refine"] + + +# This variable is used to tell the user +# that it can be changed to use other APIs +# like Prem and LocalAI +OPENAI_API_BASE_INFO = """ +The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. + +You can change this to use other APIs like JinaChat, LocalAI and Prem. +""" diff --git a/src/backend/langflow/template/frontend_node/llms.py b/src/backend/langflow/template/frontend_node/llms.py index 272e42c7f..65bffc303 100644 --- a/src/backend/langflow/template/frontend_node/llms.py +++ b/src/backend/langflow/template/frontend_node/llms.py @@ -2,6 +2,7 @@ from typing import Optional from langflow.template.field.base import TemplateField from langflow.template.frontend_node.base import FrontendNode +from langflow.template.frontend_node.constants import OPENAI_API_BASE_INFO class LLMFrontendNode(FrontendNode): @@ -15,6 +16,9 @@ class LLMFrontendNode(FrontendNode): if "key" not in field.name.lower() and "token" not in field.name.lower(): field.password = False + if field.name == "openai_api_base": + field.info = OPENAI_API_BASE_INFO + @staticmethod def format_azure_field(field: TemplateField): if field.name == "model_name": diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 4347b88ca..0701bfcd4 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -25,6 +25,7 @@ import { nodeColors } from "../../../../utils"; import ShadTooltip from "../../../../components/ShadTooltipComponent"; import { PopUpContext } from "../../../../contexts/popUpContext"; import ToggleShadComponent from "../../../../components/toggleShadComponent"; +import { Info } from "lucide-react"; export default function ParameterComponent({ left, @@ -36,9 +37,11 @@ export default function ParameterComponent({ type, name = "", required = false, + info = "", }: ParameterComponentType) { const ref = useRef(null); const refHtml = useRef(null); + const infoHtml = useRef(null); const updateNodeInternals = useUpdateNodeInternals(); const [position, setPosition] = useState(0); const { closePopUp } = useContext(PopUpContext); @@ -79,6 +82,18 @@ export default function ParameterComponent({ }); }; + useEffect(() => { + infoHtml.current = ( +
+ {info.split("\n").map((line, i) => ( +

+ {line} +

+ ))} +
+ ); + }, [info]); + useEffect(() => { const groupedObj = groupByFamily(myData, tooltipTitle); @@ -126,8 +141,25 @@ export default function ParameterComponent({ className="w-full flex flex-wrap justify-between items-center bg-muted dark:bg-gray-800 dark:text-white mt-1 px-5 py-2" > <> -
+
{title} +
+ {info !== "" && ( + + + + )} +
{required ? " *" : ""}
{left && diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 743339a48..40a306ce6 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -244,6 +244,7 @@ export default function GenericNode({ ? toTitleCase(data.node.template[t].name) : toTitleCase(t) } + info={data.node.template[t].info} name={t} tooltipTitle={data.node.template[t].type} required={data.node.template[t].required} diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 630526193..b1570ddda 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -1,10 +1,4 @@ -import { - ComponentType, - ForwardRefExoticComponent, - ReactElement, - ReactNode, - SVGProps, -} from "react"; +import { ReactElement, ReactNode } from "react"; import { NodeDataType } from "../flow/index"; import { typesContextType } from "../typesContext"; export type InputComponentType = { @@ -41,6 +35,7 @@ export type ParameterComponentType = { name?: string; tooltipTitle: string; dataContext?: typesContextType; + info?: string; }; export type InputListComponentType = { value: string[];