From 5e8cec40c9b5bbf62577c6f158046611c89f58c3 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 15 May 2024 21:51:32 -0300 Subject: [PATCH 01/47] Refactor utils file --- src/frontend/src/App.tsx | 14 +- .../addNewVariableButton.tsx | 2 +- .../components/inputGlobalComponent/index.tsx | 2 +- .../components/parameterComponent/index.tsx | 3 +- .../utils/group-by-family.tsx | 119 +++++++++++++++ .../src/modals/genericModal/index.tsx | 9 +- .../genericModal/utils/var-highlight-html.tsx | 6 + .../components/PageComponent/index.tsx | 3 +- .../utils/is-wrapped-with-class.tsx | 4 + .../pages/GlobalVariablesPage/index.tsx | 2 +- .../globalVariables.ts | 6 +- .../utils/get-unavailable-fields.tsx | 13 ++ src/frontend/src/utils/reactflowUtils.ts | 16 +- src/frontend/src/utils/utils.ts | 138 +----------------- 14 files changed, 175 insertions(+), 162 deletions(-) create mode 100644 src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx create mode 100644 src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx create mode 100644 src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx rename src/frontend/src/stores/{ => globalVariablesStore}/globalVariables.ts (91%) create mode 100644 src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 2d8fc3caa..88d990c93 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -19,15 +19,15 @@ import Router from "./routes"; import useAlertStore from "./stores/alertStore"; import { useDarkStore } from "./stores/darkStore"; import useFlowsManagerStore from "./stores/flowsManagerStore"; -import { useGlobalVariablesStore } from "./stores/globalVariables"; +import { useGlobalVariablesStore } from "./stores/globalVariablesStore/globalVariables"; import { useStoreStore } from "./stores/storeStore"; import { useTypesStore } from "./stores/typesStore"; export default function App() { const removeFromTempNotificationList = useAlertStore( - (state) => state.removeFromTempNotificationList + (state) => state.removeFromTempNotificationList, ); const tempNotificationList = useAlertStore( - (state) => state.tempNotificationList + (state) => state.tempNotificationList, ); const [fetchError, setFetchError] = useState(false); const isLoading = useFlowsManagerStore((state) => state.isLoading); @@ -45,10 +45,10 @@ export default function App() { const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshStars = useDarkStore((state) => state.refreshStars); const setGlobalVariables = useGlobalVariablesStore( - (state) => state.setGlobalVariables + (state) => state.setGlobalVariables, ); const setUnavailableFields = useGlobalVariablesStore( - (state) => state.setUnavaliableFields + (state) => state.setUnavaliableFields, ); const checkHasStore = useStoreStore((state) => state.checkHasStore); const navigate = useNavigate(); @@ -92,8 +92,8 @@ export default function App() { } }); - /* - Abort the request as it isn't needed anymore, the component being + /* + Abort the request as it isn't needed anymore, the component being unmounted. It helps avoid, among other things, the well-known "can't perform a React state update on an unmounted component" warning. */ diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index 2745ba1bf..1ea7142ab 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { registerGlobalVariable } from "../../controllers/API"; import BaseModal from "../../modals/baseModal"; import useAlertStore from "../../stores/alertStore"; -import { useGlobalVariablesStore } from "../../stores/globalVariables"; +import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { useTypesStore } from "../../stores/typesStore"; import { ResponseErrorDetailAPI } from "../../types/api"; import { sortByName } from "../../utils/utils"; diff --git a/src/frontend/src/components/inputGlobalComponent/index.tsx b/src/frontend/src/components/inputGlobalComponent/index.tsx index 2ca1aed22..7ab3cae33 100644 --- a/src/frontend/src/components/inputGlobalComponent/index.tsx +++ b/src/frontend/src/components/inputGlobalComponent/index.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { deleteGlobalVariable } from "../../controllers/API"; import DeleteConfirmationModal from "../../modals/deleteConfirmationModal"; import useAlertStore from "../../stores/alertStore"; -import { useGlobalVariablesStore } from "../../stores/globalVariables"; +import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { InputGlobalComponentType } from "../../types/components"; import { cn } from "../../utils/utils"; import AddNewVariableButton from "../addNewVariableButtonComponent/addNewVariableButton"; diff --git a/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx b/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx index dbcb1e3dc..c77d7308c 100644 --- a/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx @@ -49,7 +49,8 @@ import { nodeIconsLucide, nodeNames, } from "../../../../utils/styleUtils"; -import { classNames, groupByFamily } from "../../../../utils/utils"; +import { classNames } from "../../../../utils/utils"; +import groupByFamily from "./utils/group-by-family"; export default function ParameterComponent({ left, diff --git a/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx b/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx new file mode 100644 index 000000000..a38a31b59 --- /dev/null +++ b/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx @@ -0,0 +1,119 @@ +import { APIDataType, TemplateVariableType } from "../../../../../types/api"; +import { + groupedObjType, + nodeGroupedObjType, +} from "../../../../../types/components"; +import { NodeType } from "../../../../../types/flow"; + +export default function groupByFamily( + data: APIDataType, + baseClasses: string, + left: boolean, + flow?: NodeType[], +): groupedObjType[] { + const baseClassesSet = new Set(baseClasses.split("\n")); + let arrOfPossibleInputs: Array<{ + category: string; + nodes: nodeGroupedObjType[]; + full: boolean; + display_name?: string; + }> = []; + let arrOfPossibleOutputs: Array<{ + category: string; + nodes: nodeGroupedObjType[]; + full: boolean; + display_name?: string; + }> = []; + let checkedNodes = new Map(); + const excludeTypes = new Set(["bool", "float", "code", "file", "int"]); + + const checkBaseClass = (template: TemplateVariableType) => { + return ( + template.type && + template.show && + ((!excludeTypes.has(template.type) && + baseClassesSet.has(template.type)) || + (template.input_types && + template.input_types.some((inputType) => + baseClassesSet.has(inputType), + ))) + ); + }; + + if (flow) { + // se existir o flow + for (const node of flow) { + // para cada node do flow + if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group + const nodeData = node.data; + + const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado + checkedNodes.set(nodeData.type, { + hasBaseClassInTemplate: + foundNode?.hasBaseClassInTemplate || + Object.values(nodeData.node!.template).some(checkBaseClass), + hasBaseClassInBaseClasses: + foundNode?.hasBaseClassInBaseClasses || + nodeData.node!.base_classes.some((baseClass) => + baseClassesSet.has(baseClass), + ), //seta como anterior ou verifica se o node tem base class + displayName: nodeData.node?.display_name, + }); + } + } + + for (const [d, nodes] of Object.entries(data)) { + let tempInputs: nodeGroupedObjType[] = [], + tempOutputs: nodeGroupedObjType[] = []; + + for (const [n, node] of Object.entries(nodes!)) { + let foundNode = checkedNodes.get(n); + + if (!foundNode) { + foundNode = { + hasBaseClassInTemplate: Object.values(node!.template).some( + checkBaseClass, + ), + hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => + baseClassesSet.has(baseClass), + ), + displayName: node?.display_name, + }; + } + + if (foundNode.hasBaseClassInTemplate) + tempInputs.push({ node: n, displayName: foundNode.displayName }); + if (foundNode.hasBaseClassInBaseClasses) + tempOutputs.push({ node: n, displayName: foundNode.displayName }); + } + + const totalNodes = Object.keys(nodes!).length; + + if (tempInputs.length) + arrOfPossibleInputs.push({ + category: d, + nodes: tempInputs, + full: tempInputs.length === totalNodes, + }); + if (tempOutputs.length) + arrOfPossibleOutputs.push({ + category: d, + nodes: tempOutputs, + full: tempOutputs.length === totalNodes, + }); + } + + return left + ? arrOfPossibleOutputs.map((output) => ({ + family: output.category, + type: output.full + ? "" + : output.nodes.map((item) => item.node).join(", "), + display_name: "", + })) + : arrOfPossibleInputs.map((input) => ({ + family: input.category, + type: input.full ? "" : input.nodes.map((item) => item.node).join(", "), + display_name: input.nodes.map((item) => item.displayName).join(", "), + })); +} diff --git a/src/frontend/src/modals/genericModal/index.tsx b/src/frontend/src/modals/genericModal/index.tsx index 02000df4d..0e111c548 100644 --- a/src/frontend/src/modals/genericModal/index.tsx +++ b/src/frontend/src/modals/genericModal/index.tsx @@ -24,8 +24,9 @@ import { postValidatePrompt } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; import { genericModalPropsType } from "../../types/components"; import { handleKeyDown } from "../../utils/reactflowUtils"; -import { classNames, varHighlightHTML } from "../../utils/utils"; +import { classNames } from "../../utils/utils"; import BaseModal from "../baseModal"; +import varHighlightHTML from "./utils/var-highlight-html"; export default function GenericModal({ field_name = "", @@ -82,7 +83,7 @@ export default function GenericModal({ } const filteredWordsHighlight = matches.filter( - (word) => !invalid_chars.includes(word) + (word) => !invalid_chars.includes(word), ); setWordsHighlight(filteredWordsHighlight); @@ -133,7 +134,7 @@ export default function GenericModal({ // to the first key of the custom_fields object if (field_name === "") { field_name = Array.isArray( - apiReturn.data?.frontend_node?.custom_fields?.[""] + apiReturn.data?.frontend_node?.custom_fields?.[""], ) ? apiReturn.data?.frontend_node?.custom_fields?.[""][0] ?? "" : apiReturn.data?.frontend_node?.custom_fields?.[""] ?? ""; @@ -209,7 +210,7 @@ export default function GenericModal({
{type === TypeModal.PROMPT && isEdit && !readonly ? ( diff --git a/src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx b/src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx new file mode 100644 index 000000000..d88be4965 --- /dev/null +++ b/src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx @@ -0,0 +1,6 @@ +import { IVarHighlightType } from "../../../types/components"; + +export default function varHighlightHTML({ name }: IVarHighlightType): string { + const html = `{${name}}`; + return html; +} diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index bc0a0e362..3a456f540 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -34,9 +34,10 @@ import { updateIds, validateSelection, } from "../../../../utils/reactflowUtils"; -import { getRandomName, isWrappedWithClass } from "../../../../utils/utils"; +import { getRandomName } from "../../../../utils/utils"; import ConnectionLineComponent from "../ConnectionLineComponent"; import SelectionMenu from "../SelectionMenuComponent"; +import isWrappedWithClass from "./utils/is-wrapped-with-class"; const nodeTypes = { genericNode: GenericNode, diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx new file mode 100644 index 000000000..eff34d330 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx @@ -0,0 +1,4 @@ +const isWrappedWithClass = (event: any, className: string | undefined) => + event.target.closest(`.${className}`); + +export default isWrappedWithClass; diff --git a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx index 0ecdd588b..148f4359f 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx @@ -11,7 +11,7 @@ import { Badge } from "../../../../components/ui/badge"; import { Card, CardContent } from "../../../../components/ui/card"; import { deleteGlobalVariable } from "../../../../controllers/API"; import useAlertStore from "../../../../stores/alertStore"; -import { useGlobalVariablesStore } from "../../../../stores/globalVariables"; +import { useGlobalVariablesStore } from "../../../../stores/globalVariablesStore/globalVariables"; import { cn } from "../../../../utils/utils"; export default function GlobalVariablesPage() { diff --git a/src/frontend/src/stores/globalVariables.ts b/src/frontend/src/stores/globalVariablesStore/globalVariables.ts similarity index 91% rename from src/frontend/src/stores/globalVariables.ts rename to src/frontend/src/stores/globalVariablesStore/globalVariables.ts index 3adf8cbf8..873e6e899 100644 --- a/src/frontend/src/stores/globalVariables.ts +++ b/src/frontend/src/stores/globalVariablesStore/globalVariables.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; -import { GlobalVariablesStore } from "../types/zustand/globalVariables"; -import { getUnavailableFields } from "../utils/utils"; +import { GlobalVariablesStore } from "../../types/zustand/globalVariables"; +import getUnavailableFields from "./utils/get-unavailable-fields"; export const useGlobalVariablesStore = create( (set, get) => ({ @@ -45,5 +45,5 @@ export const useGlobalVariablesStore = create( getVariableId: (name) => { return get().globalVariables[name]?.id; }, - }) + }), ); diff --git a/src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx b/src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx new file mode 100644 index 000000000..63da1dbe2 --- /dev/null +++ b/src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx @@ -0,0 +1,13 @@ +export default function getUnavailableFields(variables: { + [key: string]: { default_fields?: string[] }; +}): { [name: string]: string } { + const unVariables: { [name: string]: string } = {}; + Object.keys(variables).forEach((key) => { + if (variables[key].default_fields) { + variables[key].default_fields!.forEach((field) => { + unVariables[field] = key; + }); + } + }); + return unVariables; +} diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 65a85960b..64008aa68 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -36,12 +36,8 @@ import { unselectAllNodesType, updateEdgesHandleIdsType, } from "../types/utils/reactflowUtils"; -import { - createRandomKey, - getFieldTitle, - getRandomDescription, - toTitleCase, -} from "./utils"; +import { createRandomKey, getFieldTitle, toTitleCase } from "./utils"; +import { DESCRIPTIONS } from "../flow_constants"; const uid = new ShortUniqueId({ length: 5 }); export function checkChatInput(nodes: Node[]) { @@ -1286,6 +1282,14 @@ export function downloadFlows() { }); } +export function getRandomElement(array: T[]): T { + return array[Math.floor(Math.random() * array.length)]; +} + +export function getRandomDescription(): string { + return getRandomElement(DESCRIPTIONS); +} + export const createNewFlow = ( flowData: ReactFlowJsonObject, flow: FlowType, diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 5e1786404..23bd275ea 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -15,6 +15,7 @@ import { } from "../types/components"; import { NodeType } from "../types/flow"; import { FlowState } from "../types/tabs"; +import { getRandomElement } from "./reactflowUtils"; export function classNames(...classes: Array): string { return classes.filter(Boolean).join(" "); @@ -90,20 +91,6 @@ export function toTitleCase( .join(" "); } -export function getUnavailableFields(variables: { - [key: string]: { default_fields?: string[] }; -}): { [name: string]: string } { - const unVariables: { [name: string]: string } = {}; - Object.keys(variables).forEach((key) => { - if (variables[key].default_fields) { - variables[key].default_fields!.forEach((field) => { - unVariables[field] = key; - }); - } - }); - return unVariables; -} - export const upperCaseWords: string[] = ["llm", "uri"]; export function checkUpperWords(str: string): string { const words = str.split(" ").map((word) => { @@ -115,133 +102,10 @@ export function checkUpperWords(str: string): string { return words.join(" "); } -export const isWrappedWithClass = (event: any, className: string | undefined) => - event.target.closest(`.${className}`); - -export function groupByFamily( - data: APIDataType, - baseClasses: string, - left: boolean, - flow?: NodeType[], -): groupedObjType[] { - const baseClassesSet = new Set(baseClasses.split("\n")); - let arrOfPossibleInputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let arrOfPossibleOutputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let checkedNodes = new Map(); - const excludeTypes = new Set(["bool", "float", "code", "file", "int"]); - - const checkBaseClass = (template: TemplateVariableType) => { - return ( - template.type && - template.show && - ((!excludeTypes.has(template.type) && - baseClassesSet.has(template.type)) || - (template.input_types && - template.input_types.some((inputType) => - baseClassesSet.has(inputType), - ))) - ); - }; - - if (flow) { - // se existir o flow - for (const node of flow) { - // para cada node do flow - if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group - const nodeData = node.data; - - const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado - checkedNodes.set(nodeData.type, { - hasBaseClassInTemplate: - foundNode?.hasBaseClassInTemplate || - Object.values(nodeData.node!.template).some(checkBaseClass), - hasBaseClassInBaseClasses: - foundNode?.hasBaseClassInBaseClasses || - nodeData.node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), //seta como anterior ou verifica se o node tem base class - displayName: nodeData.node?.display_name, - }); - } - } - - for (const [d, nodes] of Object.entries(data)) { - let tempInputs: nodeGroupedObjType[] = [], - tempOutputs: nodeGroupedObjType[] = []; - - for (const [n, node] of Object.entries(nodes!)) { - let foundNode = checkedNodes.get(n); - - if (!foundNode) { - foundNode = { - hasBaseClassInTemplate: Object.values(node!.template).some( - checkBaseClass, - ), - hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), - displayName: node?.display_name, - }; - } - - if (foundNode.hasBaseClassInTemplate) - tempInputs.push({ node: n, displayName: foundNode.displayName }); - if (foundNode.hasBaseClassInBaseClasses) - tempOutputs.push({ node: n, displayName: foundNode.displayName }); - } - - const totalNodes = Object.keys(nodes!).length; - - if (tempInputs.length) - arrOfPossibleInputs.push({ - category: d, - nodes: tempInputs, - full: tempInputs.length === totalNodes, - }); - if (tempOutputs.length) - arrOfPossibleOutputs.push({ - category: d, - nodes: tempOutputs, - full: tempOutputs.length === totalNodes, - }); - } - - return left - ? arrOfPossibleOutputs.map((output) => ({ - family: output.category, - type: output.full - ? "" - : output.nodes.map((item) => item.node).join(", "), - display_name: "", - })) - : arrOfPossibleInputs.map((input) => ({ - family: input.category, - type: input.full ? "" : input.nodes.map((item) => item.node).join(", "), - display_name: input.nodes.map((item) => item.displayName).join(", "), - })); -} - export function buildInputs(): string { return '{"input_value": "message"}'; } -export function getRandomElement(array: T[]): T { - return array[Math.floor(Math.random() * array.length)]; -} -export function getRandomDescription(): string { - return getRandomElement(DESCRIPTIONS); -} - export function getRandomName( retry: number = 0, noSpace: boolean = false, From 245eb3c102c2ee549cb51ada389d54ef796a3199 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:37:07 -0300 Subject: [PATCH 02/47] Refactor: move sensitiveSort to extrasidebar folder --- .../extraSidebarComponent/index.tsx | 2 +- .../utils/sensitive-sort.tsx | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index fbd0c12d1..9ec1031c2 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -22,12 +22,12 @@ import { import { classNames, removeCountFromString, - sensitiveSort, } from "../../../../utils/utils"; import DisclosureComponent from "../DisclosureComponent"; import ParentDisclosureComponent from "../ParentDisclosureComponent"; import SidebarDraggableComponent from "./sideBarDraggableComponent"; import { sortKeys } from "./utils"; +import sensitiveSort from "./utils/sensitive-sort"; export default function ExtraSidebar(): JSX.Element { const data = useTypesStore((state) => state.data); diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx new file mode 100644 index 000000000..c0e7bd265 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx @@ -0,0 +1,25 @@ +export default function sensitiveSort(a: string, b: string): number { + // Extract the name and number from each string using regular expressions + const regex = /(.+) \((\w+)\)/; + const matchA = a.match(regex); + const matchB = b.match(regex); + + if (matchA && matchB) { + // Compare the names alphabetically + const nameA = matchA[1]; + const nameB = matchB[1]; + if (nameA !== nameB) { + return nameA.localeCompare(nameB); + } + + // If the names are the same, compare the numbers numerically + const numberA = parseInt(matchA[2]); + const numberB = parseInt(matchB[2]); + return numberA - numberB; + } else { + // Handle cases where one or both strings do not match the expected pattern + // Simple strings are treated as pure alphabetical comparisons + return a.localeCompare(b); + } +} + \ No newline at end of file From 78fe9f53b22473cfccdad97b254a049f02e47fa7 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:41:30 -0300 Subject: [PATCH 03/47] Refactor: move getRandomName to pageComponent folder --- .../components/PageComponent/index.tsx | 2 +- .../PageComponent/utils/get-random-name.tsx | 35 ++++++++++++ src/frontend/src/utils/utils.ts | 57 ------------------- 3 files changed, 36 insertions(+), 58 deletions(-) create mode 100644 src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 3a456f540..c902ec2d5 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -34,10 +34,10 @@ import { updateIds, validateSelection, } from "../../../../utils/reactflowUtils"; -import { getRandomName } from "../../../../utils/utils"; import ConnectionLineComponent from "../ConnectionLineComponent"; import SelectionMenu from "../SelectionMenuComponent"; import isWrappedWithClass from "./utils/is-wrapped-with-class"; +import getRandomName from "./utils/get-random-name"; const nodeTypes = { genericNode: GenericNode, diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx new file mode 100644 index 000000000..d6213bcc0 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx @@ -0,0 +1,35 @@ +import { ADJECTIVES, NOUNS } from "../../../../../flow_constants"; +import { getRandomElement } from "../../../../../utils/reactflowUtils"; +import { toTitleCase } from "../../../../../utils/utils"; + +export default function getRandomName( + retry: number = 0, + noSpace: boolean = false, + maxRetries: number = 3, + ): string { + const left: string[] = ADJECTIVES; + const right: string[] = NOUNS; + + const lv = getRandomElement(left); + const rv = getRandomElement(right); + + // Condition to avoid "boring wozniak" + if (lv === "boring" && rv === "wozniak") { + if (retry < maxRetries) { + return getRandomName(retry + 1, noSpace, maxRetries); + } else { + console.warn("Max retries reached, returning as is"); + } + } + + // Append a suffix if retrying and noSpace is true + if (retry > 0 && noSpace) { + const retrySuffix = Math.floor(Math.random() * 10); + return `${lv}_${rv}${retrySuffix}`; + } + + // Construct the final name + let final_name = noSpace ? `${lv}_${rv}` : `${lv} ${rv}`; + // Return title case final name + return toTitleCase(final_name); + } \ No newline at end of file diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index c1ae07039..6868113fa 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -106,38 +106,6 @@ export function buildInputs(): string { return '{"input_value": "message"}'; } -export function getRandomName( - retry: number = 0, - noSpace: boolean = false, - maxRetries: number = 3, -): string { - const left: string[] = ADJECTIVES; - const right: string[] = NOUNS; - - const lv = getRandomElement(left); - const rv = getRandomElement(right); - - // Condition to avoid "boring wozniak" - if (lv === "boring" && rv === "wozniak") { - if (retry < maxRetries) { - return getRandomName(retry + 1, noSpace, maxRetries); - } else { - console.warn("Max retries reached, returning as is"); - } - } - - // Append a suffix if retrying and noSpace is true - if (retry > 0 && noSpace) { - const retrySuffix = Math.floor(Math.random() * 10); - return `${lv}_${rv}${retrySuffix}`; - } - - // Construct the final name - let final_name = noSpace ? `${lv}_${rv}` : `${lv} ${rv}`; - // Return title case final name - return toTitleCase(final_name); -} - export function getRandomKeyByssmm(): string { const now = new Date(); const seconds = String(now.getSeconds()).padStart(2, "0"); @@ -463,31 +431,6 @@ export function createRandomKey(key: string, uid: string): string { return removeCountFromString(key) + ` (${uid})`; } -export function sensitiveSort(a: string, b: string): number { - // Extract the name and number from each string using regular expressions - const regex = /(.+) \((\w+)\)/; - const matchA = a.match(regex); - const matchB = b.match(regex); - - if (matchA && matchB) { - // Compare the names alphabetically - const nameA = matchA[1]; - const nameB = matchB[1]; - if (nameA !== nameB) { - return nameA.localeCompare(nameB); - } - - // If the names are the same, compare the numbers numerically - const numberA = parseInt(matchA[2]); - const numberB = parseInt(matchB[2]); - return numberA - numberB; - } else { - // Handle cases where one or both strings do not match the expected pattern - // Simple strings are treated as pure alphabetical comparisons - return a.localeCompare(b); - } -} - export function groupByFamily( data: APIDataType, baseClasses: string, From a480021a54a592e14af900e3761b0777d3b09886 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:50:49 -0300 Subject: [PATCH 04/47] Refactor: move getPythonApiCode to apiModal folder --- .../apiModal/utils/get-python-api-code.tsx | 58 +++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 64 ------------------- 3 files changed, 59 insertions(+), 65 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx b/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx new file mode 100644 index 000000000..207ae2d48 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx @@ -0,0 +1,58 @@ +/** + * Function to get the python code for the API + * @param {string} flowId - The id of the flow + * @param {boolean} isAuth - If the API is authenticated + * @param {any[]} tweak - The tweaks + * @returns {string} - The python code + */ +export default function getPythonApiCode( + flowId: string, + isAuth: boolean, + tweaksBuildedObject, + ): string { + const tweaksObject = tweaksBuildedObject[0]; + return `import requests + from typing import Optional + + BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run" + FLOW_ID = "${flowId}" + # You can tweak the flow by adding a tweaks dictionary + # e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}} + TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} + + def run_flow(message: str, + flow_id: str, + output_type: str = "chat", + input_type: str = "chat", + tweaks: Optional[dict] = None, + api_key: Optional[str] = None) -> dict: + """ + Run a flow with a given message and optional tweaks. + + :param message: The message to send to the flow + :param flow_id: The ID of the flow to run + :param tweaks: Optional tweaks to customize the flow + :return: The JSON response from the flow + """ + api_url = f"{BASE_API_URL}/{flow_id}" + + payload = { + "input_value": message, + "output_type": output_type, + "input_type": input_type, + } + headers = None + if tweaks: + payload["tweaks"] = tweaks + if api_key: + headers = {"x-api-key": api_key} + response = requests.post(api_url, json=payload, headers=headers) + return response.json() + + # Setup any tweaks you want to apply to the flow + message = "message" + ${!isAuth ? `api_key = ""` : ""} + print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${ + !isAuth ? `, api_key=api_key` : "" + }))`; + } \ No newline at end of file diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index a5cc47721..5165949ea 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -15,7 +15,6 @@ import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { getCurlCode, - getPythonApiCode, getPythonCode, getWidgetCode, tabsArray, @@ -27,6 +26,7 @@ import { checkCanBuildTweakObject } from "../utils/check-can-build-tweak-object" import { getChangesType } from "../utils/get-changes-types"; import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value"; import { getValue } from "../utils/get-value"; +import getPythonApiCode from "../utils/get-python-api-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 6868113fa..276585b18 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -113,11 +113,6 @@ export function getRandomKeyByssmm(): string { return seconds + milliseconds + Math.abs(Math.floor(Math.random() * 10001)); } -export function varHighlightHTML({ name }: IVarHighlightType): string { - const html = `{${name}}`; - return html; -} - export function buildTweakObject(tweak: tweakType) { tweak.forEach((el) => { Object.keys(el).forEach((key) => { @@ -146,65 +141,6 @@ export function getChatInputField(flowState?: FlowState) { return chat_input_field; } -/** - * Function to get the python code for the API - * @param {string} flowId - The id of the flow - * @param {boolean} isAuth - If the API is authenticated - * @param {any[]} tweak - The tweaks - * @returns {string} - The python code - */ -export function getPythonApiCode( - flowId: string, - isAuth: boolean, - tweaksBuildedObject, -): string { - const tweaksObject = tweaksBuildedObject[0]; - return `import requests -from typing import Optional - -BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run" -FLOW_ID = "${flowId}" -# You can tweak the flow by adding a tweaks dictionary -# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}} -TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} - -def run_flow(message: str, - flow_id: str, - output_type: str = "chat", - input_type: str = "chat", - tweaks: Optional[dict] = None, - api_key: Optional[str] = None) -> dict: - """ - Run a flow with a given message and optional tweaks. - - :param message: The message to send to the flow - :param flow_id: The ID of the flow to run - :param tweaks: Optional tweaks to customize the flow - :return: The JSON response from the flow - """ - api_url = f"{BASE_API_URL}/{flow_id}" - - payload = { - "input_value": message, - "output_type": output_type, - "input_type": input_type, - } - headers = None - if tweaks: - payload["tweaks"] = tweaks - if api_key: - headers = {"x-api-key": api_key} - response = requests.post(api_url, json=payload, headers=headers) - return response.json() - -# Setup any tweaks you want to apply to the flow -message = "message" -${!isAuth ? `api_key = ""` : ""} -print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${ - !isAuth ? `, api_key=api_key` : "" - }))`; -} - /** * Function to get the curl code for the API * @param {string} flowId - The id of the flow From 9bd70b2616fc362bd6bbe530f269f7cd38b63fe4 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:54:01 -0300 Subject: [PATCH 05/47] Refactor: move getCurlCode to apiModal folder --- .../modals/apiModal/utils/get-curl-code.tsx | 26 ++++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 27 ------------------- 3 files changed, 27 insertions(+), 28 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-curl-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-curl-code.tsx b/src/frontend/src/modals/apiModal/utils/get-curl-code.tsx new file mode 100644 index 000000000..9ae8ec48f --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-curl-code.tsx @@ -0,0 +1,26 @@ +/** + * Function to get the curl code for the API + * @param {string} flowId - The id of the flow + * @param {boolean} isAuth - If the API is authenticated + * @returns {string} - The curl code + */ +export default function getCurlCode( + flowId: string, + isAuth: boolean, + tweaksBuildedObject, + ): string { + const tweaksObject = tweaksBuildedObject[0]; + + return `curl -X POST \\ + ${window.location.protocol}//${ + window.location.host + }/api/v1/run/${flowId}?stream=false \\ + -H 'Content-Type: application/json'\\${ + !isAuth ? `\n -H 'x-api-key: '\\` : "" + } + -d '{"input_value": "message", + "output_type": "chat", + "input_type": "chat", + "tweaks": ${JSON.stringify(tweaksObject, null, 2)}' + `; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 5165949ea..26b9d765f 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -14,7 +14,6 @@ import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { - getCurlCode, getPythonCode, getWidgetCode, tabsArray, @@ -27,6 +26,7 @@ import { getChangesType } from "../utils/get-changes-types"; import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value"; import { getValue } from "../utils/get-value"; import getPythonApiCode from "../utils/get-python-api-code"; +import getCurlCode from "../utils/get-curl-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 276585b18..7bd08208d 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -141,33 +141,6 @@ export function getChatInputField(flowState?: FlowState) { return chat_input_field; } -/** - * Function to get the curl code for the API - * @param {string} flowId - The id of the flow - * @param {boolean} isAuth - If the API is authenticated - * @returns {string} - The curl code - */ -export function getCurlCode( - flowId: string, - isAuth: boolean, - tweaksBuildedObject, -): string { - const tweaksObject = tweaksBuildedObject[0]; - - return `curl -X POST \\ - ${window.location.protocol}//${ - window.location.host - }/api/v1/run/${flowId}?stream=false \\ - -H 'Content-Type: application/json'\\${ - !isAuth ? `\n -H 'x-api-key: '\\` : "" - } - -d '{"input_value": "message", - "output_type": "chat", - "input_type": "chat", - "tweaks": ${JSON.stringify(tweaksObject, null, 2)}' - `; -} - export function getOutputIds(flow) { const nodes = flow.data!.nodes; From 69f3b16fb73231c07728c721a7e1d5b2194b6d65 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:56:02 -0300 Subject: [PATCH 06/47] Refactor: move getPythonCode to apiModal folder --- .../modals/apiModal/utils/get-python-code.tsx | 17 +++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 18 ------------------ 3 files changed, 18 insertions(+), 19 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-python-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-python-code.tsx b/src/frontend/src/modals/apiModal/utils/get-python-code.tsx new file mode 100644 index 000000000..d5327c3e7 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-python-code.tsx @@ -0,0 +1,17 @@ +/** + * Function to get the python code for the API + * @param {string} flow - The current flow + * @param {any[]} tweak - The tweaks + * @returns {string} - The python code + */ +export default function getPythonCode(flowName: string, tweaksBuildedObject): string { + const tweaksObject = tweaksBuildedObject[0]; + + return `from langflow.load import run_flow_from_json + TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} + + result = run_flow_from_json(flow="${flowName}.json", + input_value="message", + fallback_to_env_vars=True, # False by default + tweaks=TWEAKS)`; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 26b9d765f..bf45d9eae 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -14,7 +14,6 @@ import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { - getPythonCode, getWidgetCode, tabsArray, } from "../../../utils/utils"; @@ -27,6 +26,7 @@ import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value" import { getValue } from "../utils/get-value"; import getPythonApiCode from "../utils/get-python-api-code"; import getCurlCode from "../utils/get-curl-code"; +import getPythonCode from "../utils/get-python-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 7bd08208d..4e15fc4ad 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -158,24 +158,6 @@ export function getOutputIds(flow) { return arrayOfOutputsJoin; } -/** - * Function to get the python code for the API - * @param {string} flow - The current flow - * @param {any[]} tweak - The tweaks - * @returns {string} - The python code - */ -export function getPythonCode(flowName: string, tweaksBuildedObject): string { - const tweaksObject = tweaksBuildedObject[0]; - - return `from langflow.load import run_flow_from_json -TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} - -result = run_flow_from_json(flow="${flowName}.json", - input_value="message", - fallback_to_env_vars=True, # False by default - tweaks=TWEAKS)`; -} - /** * Function to get the widget code for the API * @param {string} flow - The current flow. From 5850634c04fd425d5fe09fef86a80676e1549610 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:57:34 -0300 Subject: [PATCH 07/47] Refactor: move getWidgetCode to apiModal folder --- .../modals/apiModal/utils/get-widget-code.tsx | 24 ++++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 25 ------------------- 3 files changed, 25 insertions(+), 26 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-widget-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx b/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx new file mode 100644 index 000000000..a44cba757 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx @@ -0,0 +1,24 @@ +/** + * Function to get the widget code for the API + * @param {string} flow - The current flow. + * @returns {string} - The widget code + */ +export default function getWidgetCode( + flowId: string, + flowName: string, + isAuth: boolean, + ): string { + return ` + + `; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index bf45d9eae..625261bfd 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -14,7 +14,6 @@ import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { - getWidgetCode, tabsArray, } from "../../../utils/utils"; import BaseModal from "../../baseModal"; @@ -27,6 +26,7 @@ import { getValue } from "../utils/get-value"; import getPythonApiCode from "../utils/get-python-api-code"; import getCurlCode from "../utils/get-curl-code"; import getPythonCode from "../utils/get-python-code"; +import getWidgetCode from "../utils/get-widget-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 4e15fc4ad..244a17963 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -158,31 +158,6 @@ export function getOutputIds(flow) { return arrayOfOutputsJoin; } -/** - * Function to get the widget code for the API - * @param {string} flow - The current flow. - * @returns {string} - The widget code - */ -export function getWidgetCode( - flowId: string, - flowName: string, - isAuth: boolean, -): string { - return ` - -`; -} - export function truncateLongId(id: string): string { let [componentName, newId] = id.split("-"); if (componentName.length > 15) { From 7547f0a17825a061084037211ef435fb89a759cb Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:00:39 -0300 Subject: [PATCH 08/47] Refactor: move tabsArray to apiModal folder --- .../src/modals/apiModal/utils/tabs-array.tsx | 78 ++++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 4 +- src/frontend/src/utils/utils.ts | 79 ------------------- 3 files changed, 79 insertions(+), 82 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/tabs-array.tsx diff --git a/src/frontend/src/modals/apiModal/utils/tabs-array.tsx b/src/frontend/src/modals/apiModal/utils/tabs-array.tsx new file mode 100644 index 000000000..434086b88 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/tabs-array.tsx @@ -0,0 +1,78 @@ +export default function tabsArray(codes: string[], method: number) { + if (!method) return; + if (method === 0) { + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + ]; + } + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + language: "py", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + { + name: "Tweaks", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[4], + }, + ]; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 625261bfd..6e614e03f 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -13,9 +13,6 @@ import { useTweaksStore } from "../../../stores/tweaksStore"; import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; -import { - tabsArray, -} from "../../../utils/utils"; import BaseModal from "../../baseModal"; import { buildContent } from "../utils/build-content"; import { buildTweaks } from "../utils/build-tweaks"; @@ -27,6 +24,7 @@ import getPythonApiCode from "../utils/get-python-api-code"; import getCurlCode from "../utils/get-curl-code"; import getPythonCode from "../utils/get-python-code"; import getWidgetCode from "../utils/get-widget-code"; +import tabsArray from "../utils/tabs-array"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 244a17963..3cd67b2a8 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -181,85 +181,6 @@ export function truncateDisplayName(name: string): string { return name; } -export function tabsArray(codes: string[], method: number) { - if (!method) return; - if (method === 0) { - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - ]; - } - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - language: "py", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - { - name: "Tweaks", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[4], - }, - ]; -} - export function checkLocalStorageKey(key: string): boolean { return localStorage.getItem(key) !== null; } From 05859becd4bd0356108217e2c9dd34728b973ad1 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:20:27 -0300 Subject: [PATCH 09/47] Refactor: move get-field-title and sort-fields to customNodes folder --- .../utils/group-by-family.tsx | 119 ------------------ .../src/customNodes/genericNode/index.tsx | 4 +- .../src/customNodes/utils/get-field-title.tsx | 10 ++ .../src/customNodes/utils/sort-fields.tsx | 40 ++++++ src/frontend/src/utils/reactflowUtils.ts | 3 +- src/frontend/src/utils/utils.ts | 48 ------- 6 files changed, 55 insertions(+), 169 deletions(-) delete mode 100644 src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx create mode 100644 src/frontend/src/customNodes/utils/get-field-title.tsx create mode 100644 src/frontend/src/customNodes/utils/sort-fields.tsx diff --git a/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx b/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx deleted file mode 100644 index a38a31b59..000000000 --- a/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { APIDataType, TemplateVariableType } from "../../../../../types/api"; -import { - groupedObjType, - nodeGroupedObjType, -} from "../../../../../types/components"; -import { NodeType } from "../../../../../types/flow"; - -export default function groupByFamily( - data: APIDataType, - baseClasses: string, - left: boolean, - flow?: NodeType[], -): groupedObjType[] { - const baseClassesSet = new Set(baseClasses.split("\n")); - let arrOfPossibleInputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let arrOfPossibleOutputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let checkedNodes = new Map(); - const excludeTypes = new Set(["bool", "float", "code", "file", "int"]); - - const checkBaseClass = (template: TemplateVariableType) => { - return ( - template.type && - template.show && - ((!excludeTypes.has(template.type) && - baseClassesSet.has(template.type)) || - (template.input_types && - template.input_types.some((inputType) => - baseClassesSet.has(inputType), - ))) - ); - }; - - if (flow) { - // se existir o flow - for (const node of flow) { - // para cada node do flow - if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group - const nodeData = node.data; - - const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado - checkedNodes.set(nodeData.type, { - hasBaseClassInTemplate: - foundNode?.hasBaseClassInTemplate || - Object.values(nodeData.node!.template).some(checkBaseClass), - hasBaseClassInBaseClasses: - foundNode?.hasBaseClassInBaseClasses || - nodeData.node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), //seta como anterior ou verifica se o node tem base class - displayName: nodeData.node?.display_name, - }); - } - } - - for (const [d, nodes] of Object.entries(data)) { - let tempInputs: nodeGroupedObjType[] = [], - tempOutputs: nodeGroupedObjType[] = []; - - for (const [n, node] of Object.entries(nodes!)) { - let foundNode = checkedNodes.get(n); - - if (!foundNode) { - foundNode = { - hasBaseClassInTemplate: Object.values(node!.template).some( - checkBaseClass, - ), - hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), - displayName: node?.display_name, - }; - } - - if (foundNode.hasBaseClassInTemplate) - tempInputs.push({ node: n, displayName: foundNode.displayName }); - if (foundNode.hasBaseClassInBaseClasses) - tempOutputs.push({ node: n, displayName: foundNode.displayName }); - } - - const totalNodes = Object.keys(nodes!).length; - - if (tempInputs.length) - arrOfPossibleInputs.push({ - category: d, - nodes: tempInputs, - full: tempInputs.length === totalNodes, - }); - if (tempOutputs.length) - arrOfPossibleOutputs.push({ - category: d, - nodes: tempOutputs, - full: tempOutputs.length === totalNodes, - }); - } - - return left - ? arrOfPossibleOutputs.map((output) => ({ - family: output.category, - type: output.full - ? "" - : output.nodes.map((item) => item.node).join(", "), - display_name: "", - })) - : arrOfPossibleInputs.map((input) => ({ - family: input.category, - type: input.full ? "" : input.nodes.map((item) => item.node).join(", "), - display_name: input.nodes.map((item) => item.displayName).join(", "), - })); -} diff --git a/src/frontend/src/customNodes/genericNode/index.tsx b/src/frontend/src/customNodes/genericNode/index.tsx index 811e812a6..26dc0f764 100644 --- a/src/frontend/src/customNodes/genericNode/index.tsx +++ b/src/frontend/src/customNodes/genericNode/index.tsx @@ -27,8 +27,10 @@ import { validationStatusType } from "../../types/components"; import { NodeDataType } from "../../types/flow"; import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils"; import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils"; -import { classNames, cn, getFieldTitle, sortFields } from "../../utils/utils"; +import { classNames, cn } from "../../utils/utils"; import ParameterComponent from "./components/parameterComponent"; +import getFieldTitle from "../utils/get-field-title"; +import sortFields from "../utils/sort-fields"; export default function GenericNode({ data, diff --git a/src/frontend/src/customNodes/utils/get-field-title.tsx b/src/frontend/src/customNodes/utils/get-field-title.tsx new file mode 100644 index 000000000..93db719df --- /dev/null +++ b/src/frontend/src/customNodes/utils/get-field-title.tsx @@ -0,0 +1,10 @@ +import { APITemplateType } from "../../types/api"; + +export default function getFieldTitle( + template: APITemplateType, + templateField: string, + ): string { + return template[templateField].display_name + ? template[templateField].display_name! + : template[templateField].name ?? templateField; + } diff --git a/src/frontend/src/customNodes/utils/sort-fields.tsx b/src/frontend/src/customNodes/utils/sort-fields.tsx new file mode 100644 index 000000000..d4dc473e5 --- /dev/null +++ b/src/frontend/src/customNodes/utils/sort-fields.tsx @@ -0,0 +1,40 @@ +import { priorityFields } from "../../constants/constants"; + +export default function sortFields(a, b, fieldOrder) { + // Early return for empty fields + if (!a && !b) return 0; + if (!a) return 1; + if (!b) return -1; + + // Normalize the case to ensure case-insensitive comparison + const normalizedFieldA = a.toLowerCase(); + const normalizedFieldB = b.toLowerCase(); + + const aIsPriority = priorityFields.has(normalizedFieldA); + const bIsPriority = priorityFields.has(normalizedFieldB); + + // Sort by priority + if (aIsPriority && !bIsPriority) return -1; + if (!aIsPriority && bIsPriority) return 1; + + // Check if either field is in the fieldOrder array + const indexOfA = fieldOrder.indexOf(normalizedFieldA); + const indexOfB = fieldOrder.indexOf(normalizedFieldB); + + // If both fields are in fieldOrder, sort by their order in the array + if (indexOfA !== -1 && indexOfB !== -1) { + return indexOfA - indexOfB; + } + + // If only one of the fields is in fieldOrder, that field comes first + if (indexOfA !== -1) { + return -1; + } + if (indexOfB !== -1) { + return 1; + } + + // Default case for fields not in priorityFields and not found in fieldOrder + // You might want to sort them alphabetically or in another specific manner + return a.localeCompare(b); + } diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 1e67fdf93..d47ba4981 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -36,8 +36,9 @@ import { unselectAllNodesType, updateEdgesHandleIdsType, } from "../types/utils/reactflowUtils"; -import { createRandomKey, getFieldTitle, toTitleCase } from "./utils"; +import { createRandomKey, toTitleCase } from "./utils"; import { DESCRIPTIONS } from "../flow_constants"; +import getFieldTitle from "../customNodes/utils/get-field-title"; const uid = new ShortUniqueId({ length: 5 }); export function checkChatInput(nodes: Node[]) { diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 3cd67b2a8..cb8451299 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -346,54 +346,6 @@ export function getSetFromObject(obj: object, key?: string): Set { return set; } -export function getFieldTitle( - template: APITemplateType, - templateField: string, -): string { - return template[templateField].display_name - ? template[templateField].display_name! - : template[templateField].name ?? templateField; -} - -export function sortFields(a, b, fieldOrder) { - // Early return for empty fields - if (!a && !b) return 0; - if (!a) return 1; - if (!b) return -1; - - // Normalize the case to ensure case-insensitive comparison - const normalizedFieldA = a.toLowerCase(); - const normalizedFieldB = b.toLowerCase(); - - const aIsPriority = priorityFields.has(normalizedFieldA); - const bIsPriority = priorityFields.has(normalizedFieldB); - - // Sort by priority - if (aIsPriority && !bIsPriority) return -1; - if (!aIsPriority && bIsPriority) return 1; - - // Check if either field is in the fieldOrder array - const indexOfA = fieldOrder.indexOf(normalizedFieldA); - const indexOfB = fieldOrder.indexOf(normalizedFieldB); - - // If both fields are in fieldOrder, sort by their order in the array - if (indexOfA !== -1 && indexOfB !== -1) { - return indexOfA - indexOfB; - } - - // If only one of the fields is in fieldOrder, that field comes first - if (indexOfA !== -1) { - return -1; - } - if (indexOfB !== -1) { - return 1; - } - - // Default case for fields not in priorityFields and not found in fieldOrder - // You might want to sort them alphabetically or in another specific manner - return a.localeCompare(b); -} - export function freezeObject(obj: any) { if (!obj) return obj; return JSON.parse(JSON.stringify(obj)); From aef52637f67b3387bb553b107cfd6f575ab4770c Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:27:22 -0300 Subject: [PATCH 10/47] Refactor: move convert-test-name to cardComponent folder --- src/frontend/src/components/cardComponent/index.tsx | 3 ++- .../src/components/cardComponent/utils/convert-test-name.tsx | 3 +++ src/frontend/src/utils/utils.ts | 4 ---- 3 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 src/frontend/src/components/cardComponent/utils/convert-test-name.tsx diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index 0698edd73..9b2ecdbe3 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -11,7 +11,7 @@ import { storeComponent } from "../../types/store"; import cloneFLowWithParent, { getInputsAndOutputs, } from "../../utils/storeUtils"; -import { cn, convertTestName } from "../../utils/utils"; +import { cn } from "../../utils/utils"; import IconComponent from "../genericIconComponent"; import ShadTooltip from "../shadTooltipComponent"; import { Button } from "../ui/button"; @@ -23,6 +23,7 @@ import { CardTitle, } from "../ui/card"; import Loading from "../ui/loading"; +import { convertTestName } from "./utils/convert-test-name"; export default function CollectionCardComponent({ data, diff --git a/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx b/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx new file mode 100644 index 000000000..ac8800540 --- /dev/null +++ b/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx @@ -0,0 +1,3 @@ +export function convertTestName(name: string): string { + return name.replace(/ /g, "-").toLowerCase(); +} diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index cb8451299..46495c942 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -351,10 +351,6 @@ export function freezeObject(obj: any) { return JSON.parse(JSON.stringify(obj)); } -export function convertTestName(name: string): string { - return name.replace(/ /g, "-").toLowerCase(); -} - export function sortByName(stringList: string[]): string[] { return stringList.sort((a, b) => a.localeCompare(b)); } From e2ca4b79f82f937687b3fbd629e1b960cf089a9e Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:30:10 -0300 Subject: [PATCH 11/47] Refactor: move sort-by-name to addNewVariableButton folder --- .../addNewVariableButton.tsx | 2 +- .../addNewVariableButtonComponent/utils/sort-by-name.tsx | 3 +++ src/frontend/src/utils/utils.ts | 9 --------- 3 files changed, 4 insertions(+), 10 deletions(-) create mode 100644 src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index 1ea7142ab..f80755a46 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -5,13 +5,13 @@ import useAlertStore from "../../stores/alertStore"; import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { useTypesStore } from "../../stores/typesStore"; import { ResponseErrorDetailAPI } from "../../types/api"; -import { sortByName } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import InputComponent from "../inputComponent"; import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Label } from "../ui/label"; import { Textarea } from "../ui/textarea"; +import sortByName from "./utils/sort-by-name"; //TODO IMPLEMENT FORM LOGIC diff --git a/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx b/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx new file mode 100644 index 000000000..96a1b6b68 --- /dev/null +++ b/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx @@ -0,0 +1,3 @@ +export default function sortByName(stringList: string[]): string[] { + return stringList.sort((a, b) => a.localeCompare(b)); +} \ No newline at end of file diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 46495c942..487448665 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -1,21 +1,16 @@ import clsx, { ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; -import { priorityFields } from "../constants/constants"; -import { ADJECTIVES, DESCRIPTIONS, NOUNS } from "../flow_constants"; import { APIDataType, - APITemplateType, TemplateVariableType, } from "../types/api"; import { - IVarHighlightType, groupedObjType, nodeGroupedObjType, tweakType, } from "../types/components"; import { NodeType } from "../types/flow"; import { FlowState } from "../types/tabs"; -import { getRandomElement } from "./reactflowUtils"; export function classNames(...classes: Array): string { return classes.filter(Boolean).join(" "); @@ -350,7 +345,3 @@ export function freezeObject(obj: any) { if (!obj) return obj; return JSON.parse(JSON.stringify(obj)); } - -export function sortByName(stringList: string[]): string[] { - return stringList.sort((a, b) => a.localeCompare(b)); -} From c795a3646885ef36333efa0608b2e2515299c934 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:34:00 -0300 Subject: [PATCH 12/47] Refactor: move get-tags-ids to shareModal folder --- src/frontend/src/modals/shareModal/index.tsx | 2 +- .../src/modals/shareModal/utils/get-tags-ids.tsx | 8 ++++++++ src/frontend/src/utils/storeUtils.ts | 9 --------- 3 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx diff --git a/src/frontend/src/modals/shareModal/index.tsx b/src/frontend/src/modals/shareModal/index.tsx index 75c3c1382..b6c5a2aed 100644 --- a/src/frontend/src/modals/shareModal/index.tsx +++ b/src/frontend/src/modals/shareModal/index.tsx @@ -22,10 +22,10 @@ import { removeFileNameFromComponents, removeGlobalVariableFromComponents, } from "../../utils/reactflowUtils"; -import { getTagsIds } from "../../utils/storeUtils"; import BaseModal from "../baseModal"; import ConfirmationModal from "../confirmationModal"; import ExportModal from "../exportModal"; +import getTagsIds from "./utils/get-tags-ids"; export default function ShareModal({ component, diff --git a/src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx b/src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx new file mode 100644 index 000000000..9bb71e20e --- /dev/null +++ b/src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx @@ -0,0 +1,8 @@ +export default function getTagsIds( + tags: string[], + tagListId: { name: string; id: string }[], + ) { + return tags + .map((tag) => tagListId.find((tagObj) => tagObj.name === tag))! + .map((tag) => tag!.id); +} diff --git a/src/frontend/src/utils/storeUtils.ts b/src/frontend/src/utils/storeUtils.ts index c0a0fc440..9c2735a35 100644 --- a/src/frontend/src/utils/storeUtils.ts +++ b/src/frontend/src/utils/storeUtils.ts @@ -20,15 +20,6 @@ export default function cloneFLowWithParent( return childFLow; } -export function getTagsIds( - tags: string[], - tagListId: { name: string; id: string }[], -) { - return tags - .map((tag) => tagListId.find((tagObj) => tagObj.name === tag))! - .map((tag) => tag!.id); -} - export function getInputsAndOutputs(nodes: Node[]) { let inputs: { type: string; id: string; displayName: string }[] = []; let outputs: { type: string; id: string; displayName: string }[] = []; From af5e3697a9c052df434a05f8ee04600063467391 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 22 May 2024 21:20:05 -0300 Subject: [PATCH 13/47] Refactor: Make My Collection search input use the same component as Store input --- .../headerTabsSearchComponent/index.tsx | 20 +++++++- .../components/inputSearchComponent/index.tsx | 32 +++++++----- src/frontend/src/pages/StorePage/index.tsx | 49 +++++++------------ 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx index a15b84601..8dca45f3c 100644 --- a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx +++ b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx @@ -19,6 +19,11 @@ const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => { const [tabActive, setTabActive] = useState("Flows"); const setErrorData = useAlertStore((state) => state.setErrorData); const allFlows = useFlowsManagerStore((state) => state.allFlows); + const [inputValue, setInputValue] = useState(""); + + const setSearchFlowsComponents = useFlowsManagerStore( + (state) => state.setSearchFlowsComponents, + ); const handleDownloadFolder = () => { if (allFlows.length === 0) { @@ -34,8 +39,19 @@ const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => { return ( <>
- - + { + setSearchFlowsComponents(e.target.value); + setInputValue(e.target.value); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + setSearchFlowsComponents(inputValue); + } + }} + /> ) => void; + onClick?: () => void; + value: string; + onKeyDown: (e: KeyboardEvent) => void; }; -const InputSearchComponent = ({ loading }: InputSearchComponentProps) => { +const InputSearchComponent = ({ + loading, + divClasses, + onChange, + onClick, + value, + onKeyDown, +}: InputSearchComponentProps) => { const pagePath = window.location.pathname; const [inputValue, setInputValue] = useState(""); @@ -38,24 +50,18 @@ const InputSearchComponent = ({ loading }: InputSearchComponentProps) => { return ( <> -
+
{ - setSearchFlowsComponents(e.target.value); - setInputValue(e.target.value); - }} - onKeyDown={(e) => { - if (e.key === "Enter") { - setSearchFlowsComponents(inputValue); - } - }} - value={inputValue} + onChange={onChange} + onKeyDown={onKeyDown} + value={value} /> -
+ } + }} + onClick={() => { + setSearchNow(uniqueId()); + }} + />
@@ -176,7 +177,7 @@ export default function GlobalVariablesPage() { overlayNoRowsTemplate="No data available" onSelectionChanged={(event: SelectionChangedEvent) => { setSelectedRows( - event.api.getSelectedRows().map((row) => row.name) + event.api.getSelectedRows().map((row) => row.name), ); }} rowSelection="multiple" diff --git a/src/frontend/src/stores/globalVariables.ts b/src/frontend/src/stores/globalVariables.ts index 3adf8cbf8..8c477507e 100644 --- a/src/frontend/src/stores/globalVariables.ts +++ b/src/frontend/src/stores/globalVariables.ts @@ -13,7 +13,7 @@ export const useGlobalVariablesStore = create( delete newFields[field]; set({ unavaliableFields: newFields }); }, - globalVariablesEntries: [], + globalVariablesEntries: undefined, globalVariables: {}, setGlobalVariables: (variables) => { set({ @@ -45,5 +45,5 @@ export const useGlobalVariablesStore = create( getVariableId: (name) => { return get().globalVariables[name]?.id; }, - }) + }), ); diff --git a/src/frontend/src/types/zustand/globalVariables/index.ts b/src/frontend/src/types/zustand/globalVariables/index.ts index d22170ed2..4b178088c 100644 --- a/src/frontend/src/types/zustand/globalVariables/index.ts +++ b/src/frontend/src/types/zustand/globalVariables/index.ts @@ -1,5 +1,5 @@ export type GlobalVariablesStore = { - globalVariablesEntries: Array; + globalVariablesEntries: Array | undefined; globalVariables: { [name: string]: { id: string; From e39b00cdd6bc7381ce1b234709a778481e202de8 Mon Sep 17 00:00:00 2001 From: Madhavan Date: Thu, 23 May 2024 08:34:01 -0400 Subject: [PATCH 23/47] Minor documentation update (#1948) * Update to use non-deprecated output parser imports * Update documentation * Revert "Update to use non-deprecated output parser imports" This reverts commit 11a969d82b6b2b3659eb7c3c26b5b29a98815834. --- docs/docs/tutorials/rag-with-astradb.mdx | 2 +- docs/static/img/astra-rag-flow-run.png | Bin 194688 -> 95265 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/tutorials/rag-with-astradb.mdx b/docs/docs/tutorials/rag-with-astradb.mdx index 09395c598..9bb813f55 100644 --- a/docs/docs/tutorials/rag-with-astradb.mdx +++ b/docs/docs/tutorials/rag-with-astradb.mdx @@ -143,7 +143,7 @@ The RAG flow is a bit more complex. It consists of: style={{ width: "80%", margin: "20px auto" }} /> -To run it all we have to do is click on the ⚡ _Run_ button and start interacting with your RAG application. +To run it all we have to do is click on the 🤖 _Playground_ button and start interacting with your RAG application. tQr0omu>f~SarBnbPkwnH zK)+19{t1PQWc`anukUe6Au`V(7YO+si&hF4lnH?t0RcN>3yP+-)4CbCGUHzi*TOZAnPrR z4^n$X<|@t^J22EW&r0i&r_7FLT8o~Ju715mE#R_~lc|xIALGN)u zaiBP0QbaGEG-8y^tJtv;;;zX_R5w+30g70h4xL^l^|~XII4eRAjTIb3l2RC{;4lR1wvg1b^};t1s*I$ z9|Ar$B3pr@>=zS!i=5#9ISYj67isj89{#ft?+hk}A9WUX8hHB~jXnATLi!5j&J(W{ z8X_=x2Qq>;CJ8E-g9dp;7gjl#@B$q zf0FJyDyfx)u_N*W9$gHQ&B_LjH-7#Vow$qBn0DA7ew7}|k_Kk=bz1d=3hSe4bs?=j zxf1e3{}tH0ns~$p#zG8?+M!H9#x^!CC_+$5kZA(p133fr0=EOPb2!FBb|jwCoP>sl z5{Gz%jC2!si>x8b2fdSUq?V3VlYc3n_eEerdV+dF5D^j43(+FT9x+xTL!zkDIA{n} z7&UXC_?;6+s?bL!>T3i{1UV&*+t1{Fi8^zouuD{5=sZraYKf%|c zPk6~gzoh1wC#AumX2LL{KKO=FRiM~e((-k3q0QG}%`HY&Efy`2Y)>tB?Vw_lT%6*# z>?-9=-$DG(-fvopD~qEU-*Ufosoz8VX~-zSomEvNv}d(PwkK^xjxNiY?eM;+hH8#d zSI|~Y>CK2Cvy5%5ZsVL~t(|}bZ@$yc?iu{N}#)V66{j+gElY{&`h50oeK3WOgPWw7H3}CG{}z*7W?ZqV)}`Bp zBqK$gAN&1%s%q-EtSRog_BwZOWbZxg9xX|{e!OnHY(Abk<|JbN&wRIGdvnEVu4+c^rcYdhPoEw~>^*a19!OvsA{o*hB752NCgvw&iA;$W zC%Ogg@B&x0?UtK0(!TS)@D!%4hAr4ebCzqqrIx#Xb2edqsWNxwdaks>y2`^8V$52x zZ0R%Rw}*95(VN|~nwlG*`=fHyp=01X!+25WE=zpxQ`0h2L)Tsb5B_p{kLu@`pru2RVv%tXGZ7Wfb1!vIYp;)YBzFl{ z>8E`+NH>s^_M!2uBR=l5Y*2x(8C0mJuHx1=Q&%7b_RbLC%yO zc{9)s!;8cmr;g&_9UqGjQ;X1@PM}ivL`a>S)y7>vd@OlROAe2ea0E|ef^>a1ea~=c zQRp?%KB*qbJSi`yoz6lnbOfsEsSXyQq&0?g9@%8h>RDWlI3%gF6mas#r8iM)W&5JC?zN z7;QP!7mH~61U3e2FVH{z8u72%GUqm%{QhmHX;|YT{wrOdaDmYFWM@*4EMXB74r^1} zjOX!O&zO^!laGPFPN&{Pl?G&YFi&_$d#E@;awtBb{wteyYjmywfN+2M{WyqyN%UlYRy%JCqpdb zWgc(5-=P2O{Ylg8(Cp+YI*(gjaHzFa&h5c{NpN^yr_xgH;nV#v^}HY@1zs14=SOF4 z)tp~|6ULIzhF4+HXjNHphT&UhB9a7B?_<3+h=D9Px`xDztW?n4`Rf|rIn)^bM@55i zq3X=cBHr>32dWh*g=*{5<9JQF%k&AsH{QC3XTh9bIIk^a#p(2}}kfFPT zkA!P13zp~*+jb)8@d@CD3FowJEm)fkL|l3{2SZDSOCqO9%DMI38ock^J}yVs3)b;2 z*f)(kPhOil^?i-vtQWFNZ$I?9ogf`ew@#-_Cp8#1xcoKRIPVqhQ~v0EbI*(ENERV9 z>=Edtaix9jFo0W1_tPioUUm6!#;d8XdHZIvzW~$2y_NNG_~z95?E~jvb=-E-nDveA ztqS@T#)2pNt@N_Oz)+ZQb7PB2`B(AFOwIt05!H@a>|{M~Fy2+vhDDtAfNym6e~Y z9EyPGk3p{?Ij3C*q3$0RvO*!g4&cX7I`dx+P6$~T=%%LFw5&;3EP@{NJ$*96bpBpYvc4=%XbF;ZGT5;1~9a0Y0!g z|Ng?q1%r@)e>lJgng#w_8eu65{_in31h@tgSC^ER2Y%H}9nH+_oZds6Lz2@AfD^YinwvT?9-a4-WUn4R41oQx%tlAb(iYGe(1r*P7oX5S<^O+I{@3FFsj2`z%)e4hx@(X`ts@BUTlox?9OCIaZ+iPE&2WV%NT+J=qGWS(n z-L^)VA32+o-M1E;7Fa?g=rL4`wwI`#Eu*7~N7g-GJ#qK&h;7egZES8XnTmGkYHYmT z*xZz+6!-2;JtjjC6T^~IQp)4Dp87slYt6vS9GR1wYq|41`{eQH$ewK?rsMjPA}R_7 z1tumYx`(tD1ql4_dsKpgnlsfO3{U@kxlboQ(A^h=OoVM8aAYn84=JGmt(NL?&A@?O zX*$M~F-QfZO0>%J59jOEEiD;b_NO9)(TQceZq6uGR8*Ry#_$C`9&Mp&_L7K$5X6AD zm@pV?>4#}}g18ta0!7R2H&hI^C&&;CqZd!dH&O5i2qyBCQoqnGgyPcCQ&9Lm!62cR zZqO{%Z4@G}1&Kk`!i;rbrs3p<@5gLQF$ zBN|(zUud1F@WhysZkAwteEb@>--f%0_14oYYk5VjAI@`DyFRK%lL>Q$&+ZJ%_#SNy zPxUOoh6fv=7i@$U5oBT=8Ndi<r$W7<4k2^8*}Q zDRLUWlMJdoF^>%e!Ny!Ygf%h8&~?^qV}HNoCtF$$IWk1qSVj^2Pq#n_2Qq+w#qYVM zSl55N)$bB(W^DO+?#QMvycbulmtnx9eX ze0@2w0qrVIX;`x4nQeYb$xwoWYujKBWCQT;^9K%Fg3eS1OiwTzGfEntg9NI5Dvxc> z+M3DURB5VWzx{4rVq8H%L4xGC*ITS5X9(3(tUvvCRswWUHWKj7PplQtX9=&wHY6*n zBCyKwgr2WIQ%Fb%7*qQIyCfDH7Ci$)cBx+dU|t~-CK(>s69gEN9PPXJ<2gau886%Y zj|Y+!LWS7fi3fnAdC@6y(XcA~ z#dLL3@K*T9^k2O~?dk58W91`Q(~fca30@s}!yN4%073>9pRcbivKX`)UA6`c{s62$ zrSgRFfd-IjLKBjw@CXNTD@UtcjtqMV%zA}6IsQdUl zoJMIv?!3bdt$`$z^P3;$f9qWnP_{V@n+6gb5;d@*zCF#~v_C})XAq>zY-tr9nC{b? zG|LxKfwov$+MXeTU8rAcXh@~XiXlk_nF~5QSR-a($~`!is13UDF^!-IKf0r9Di5O6OMxeLj`eh9F%p9LyGw%iUtZ0-Yw+Sk!Pc{ z!{0t5zo4NR7k#{==FD{r{sDlD99)^t9wwkcyZi9MTnx9&eJ?gU&A}4S9Xn4l)}?l0ccw~!%PCeG5F8yH-veSf$n-rug`{O=72u+z z8@_*k-Ity;-cQ-`>|2N4pP_)@N&s7|e*O#t1ox3@CE;^C(&|XIV*Zj5zVV3md-bJ~ zY3p-lNoYw1`h~AAHBLxmihEw1CTHi z{L^lz3w|Zi61RQN~Y`K07 zos)nHI&ScpnVG34vXC;+)4z5BSx?zuv471eblE35xwz1*ZAYVe){7~6Cj*akkt-9K zqj4BcEb1eY3|N*#qW(mBXIGcTZ^&2%yoRBn45?rpAvmIa@1FT>TNvOvC7E@(;^n1( z9KYHTMwj8?;C%hyqgQtjlcUq@TG~H7J-zmT zK`z21-2i|G>U`o5O<@aOtzNwy$J9F)^!vM0@*F!AtGSxWZ+i7jP3Malv9Z$gb%$S; zT0PXHq~K@Ms9F#awMC|HqTu`f-~b4j57Q3-*;Et=0Ce%w9=3BwE=f0J&Y}-j#OH_e zdio!^)fOo%EuYmmZIii^PGyNV?A?Wqt4|(JaL;5lvAWN??BH z$iXeh^zvoyTOR{u_$O!hm*wa`4_?)!$Hd6>MQ47=5N=l0PP%c(xE4A-I?B2@oR4d7 z&)hq`U5~~;5i-7Yhc;;KVs`4`znIA)1lM6Lad2=HefgrXK=IKUM{@6AR*K;W5eaFE z9&g6K^84aWcc}VFpH8@F@%1(0r;H2+pQP5-RvY%9=ks#%^6^xtk8Dn^2DL-UoX6ch z9oNytbB39BA6Zyf#0|5qt_pp`Kc%Njy1OI(s4xz^qAv4hs_pK6=a9Y4%yJ_!{IFUy zk{~TDUE_Xgo{WEfb-XUIgI+)>8H^Qfud4b+dMlnzMSZ<@JmpT6nUOL7%NINb*V`+7 zylKjopXRCuNPof#tin)V=AioS?ibf9@#J+WxFDCJ*h^-PkJE>mD z%YU9Wwi4t&(%0Tu|M(64d7z~u>j389^-VIV4Bu>aN*(~c%IN}e1(NRtjTFPk{>bh zhFF>v4K+?k4r~RHAyM|U#u0zuKI<*G4sWR@Bd@i*t0tp7<(^+qL8~n>@F;(a7s+-y z+?N^^a-PD5@dOU5Faad`dA=T!sUOzlw5@!-QT(>u8-TICC{k|xte2QLoqA?eS5NaHyR>>&f@m&jUfQ?@{n12q7&M2zj>a$|c7z zI#VT6F$0j`lu+zf<`7C&9+Za9pAy3DkLW3~M8P`z?i+`&kbAG-@#pdZI~5kluL;L!jQ7HKJ+JTpn~;>0 z8IjL0Z19^(e0mYjJ5!nIbI|`d4|@Y3Ak&||NNThO zhP?IM)wN$o0_r4JZTy`gO92ePWB2T9oxu5KH`eQ$n+aby_%F!QK&<^C@>!=|>(Q#w zUpekDIS+Us5FH)R!vXYz{z(98`=`2Q#KqbXs;a9k7n@wv0u|)svH;gZoRAY79IPvB zj||bI?t=R-sE`5X?;qD@F9FC)`(8N8L4yn#HIW~NM>tbh*%*jd^PR7;#Kk8dPy?KB z9Twtp@nNm=3oXC7AuvsvXvq%FxmPHNY76SO@MTdfFJ!F|h zy5auzGCngi)0n|(f2!1)ge$QA`LPk*UxO0+FS73VhC)$N6hQnv`D66g{81Z&VRWEJ z6fa*YpxRqY3pI3iO980NfKDp#=?Ny8;#NYA1az{TnVsXWf)IcKk$ihaM2-9--B(Xl z{#jMZR62Q-My!~fUE8n#5za<|3G4gku)v|1&VH>MrAzHcP7W0;Ce;s{Yj%Tlsc9fX zex7!b{q_5PbFdgR9oq`<>Ojy4DBJ0z5?DEo@TMOqR>TlqDJWP1t4=KtSdHY@x3_@B z9-t6nE%<`r@960}rv1zVv;F_|lpy4tAi&aFwZZEkI2T~)sDFH^TMGv$j>k8I7U+_V zG6gkt0FW55N&|*@vu6!aeJ8~i$eS836YyvDR-OZs*BG46t}qQmn6eMerhVJrDj17y`foP?GKKcr7M|2xwHpH;mR+5~ya&mxB)|#syG`dLpatUs$$) zS>r5o#C4+pFqks$Cp*vwAmX(ld5Vr8)*%K|ghO2V(-RQ#4?n1Vd?_{#+XWd z+d{yuN7j;9k@;u=2~n235&z5)pp!FLcMX~R9DIERfYL=>_@#5cfEJ0xq;LV96vF~} z0TbuH39>RQc~DO!jE9HwKMIZ)s|V`rPH_ZY z3~68hlF380Ppr{aOS7_K1_uY}DLP+0c4&Aw&h_;8Sas1A$eBMSCo|g+ z(vK0=(rIaEDE9R9ta)_QsXuze#K*sEhujICPiAHI?r6 z^rY!Z7|{5|vxtj7A#6t@%8VLxeV?su>Gb^PmH-nobAZ2pO(VujX6D=$p~-zV?y;wB zmkg}s6h1yMpZZ+j$QO^N0`1d`GU6FTGXWB=`kl)=6iy1L#uDt`xEw2R>595Hq^Y)Vb%df>| zqOz_Z2l2nXW@2*pZfUaC5|>)~eJx#s)lXfk<+k*Sw>3K1n4PI}1Y)-? zw18?Oh1IWQgIYUlps!+6QdlxWDyr<1cgr{M_`db_C)iH${Dtv5fJ3u zkb^VqG&Q4)9jFu5yMDrxP$VOH$F} zRrkt*B7!aMP?Zj#mG{ENo${|pQt8D?OgK}$;_YXXYID&%eC zp&{?H#$B{S^|?(vN%Oa^zbyqE9J?MHs@=aK@$~6!OIrXUQ)L-g=i@qTQM{LlGWDUxZT*(R1t@&pQeV@?MrtM05125Zvf1?JHX&0 zXf+6@_&@B@Q0PeL)T>Q5LIUsvhN;!WADs1x0T`&o?(_zrQ5bOW`A9E~p8mz_1{lPZ z9kMxMRlu@g1^VnL16VyYS7%f(g%J%ccFnCn4V?3}vtpzOLc*k{qFrobODkhJrZ7X!9`UizjU=EiY)!Ohj(bfgIU*IXj zr-Te?;qL1aX@2*cuMybuRqm$DP1VKGU(L9L*;rk=+oW|D@00CE;N4r*CUuz0+Fo?Ik|3Qg4s^ zJ0Qs{ly^or-&^v#lM=WY+zihfvOJA~cb-S5et*?r_}Oj#z$sWRhQsXQ)_Jp{&3XN& zq|Fq|b4OdS`nI>&?z360!(H|tHL*9(&KlZR#C$$H40yajYIpjLt$T9*`^Oj67t%Zp zN!-cs61>(p(uca-c~k64O1%{>)8aP=&7zifGkQhpw+XbjN8dhx-`-dF^VrSHqFJcC zAV-hW)De{+SsjKAsoI5|7mEV$4b}gTZ}32Y^eOj_r;^{1BO8f%%pJ!e<#!0ygv`kEz7>qfAudi7S&9v+7kyZg(sL#IA|JgdznZ<5 z-y+J?g4zDyK(qLwTb@ASP=~C~98ceHs|h3ms(h|{I>o%?gA+n+o`VVaXf zHF!(jxDq#+B|HijE^8(TQpXODlA=1ryg_xKPp1afTLi zy4Bu5y1c!eXhl?^)7NSm@Aw?PHq3CMIPzPkCX7gtFuBDyaic(5elJ{WFtV~14 zS<$F1LX>E4*gYSf`!=DxK(*^uwO+YYS`>~T)QhRVJA9pgl#o@NirS*IO?ag;}azjhpPH&RNYxJ8fv;S1_`|;=y}0{Y^n>S#>1wIi%-N@q>#faAhWU$g_Iq!l%dYK?>kVfs+)2fX z!s{0GD0QKwh#+3Gx0QUnZ`*fxkg(~g@ECQ``Xq;Ox8!`F^xqM zJ0-vt3Szr)iE0&aDxDM2*B-R6!(X!H~_z1`eh3M&~1Rc^9E{4WX*e+|Jz$f z+Vpp02FtzMvvsT0fm#iyv+!m2;*VDgXO8l(MzStNZ*@=&9RsdDN(VJV$mCl+T-A8S z<5`)oD!-T%dTiHK84wgVRQS3r_WLBev(w0FTFazJDqlc~+~=8)V`KIiyCmHK9KM>QaV zH@U?k+iJ>xOtJ3x<722<~IXjsDl#MCMOAT!uflHZdV_y7>6EbC0je8+#eK7NlQ8> ztyl~=yG62ggiG$C>gJkdUkBlKJY0UuVJ^5w;;BMSv$cx_j(dW*3g2S7KlFz^K2+OY zQW__kodptEBu16)bNT#w?1)vbx%z4Gu7s(n20N*(h1w`K4F(Mck`7HNxc5&-84S zuzkX--atC>{1@Y8>2g(~_k&Yu#bM8Br1ZtOiKVmSt6+IWt{wtU@86=%amuKE2}8r% zH}_1R_9A=hhU&?PdZ@6bFsbDnx9@#cAA=BLWN4Vhz1G|=*0O+VC=X7$nY~GbGINB$9ax{f7UjBF{dit;i*k6y$d{Y@^#|6|UXuCU=2L z8(3hpdf&x+d@#=GbFB4=QYaWYK+d|ldHq;plYX?t7z1~uW3_?%GVqpaFYG&FCJPz6p?hEp=Nkm9o= z!o%NfI%<XkLAr5;_JSd**w1fixd2x&Ja;Vv=p zU-GXXIdKxGhntVDk+d(q<74VS6!nbTYCj9aTgI&FX9zUEsA=9h8T#^((c{yxcB6d` z8qG6c@i;6D5RG4Cc`t5W&&olAscI( z`a0Sbm>xcc|K5w#LZ^Hf{e`o(w%jRmU@+Kj{3_=e0sJg(L-rNfNteHQXUXZ0Owz1YZ#>xjO~T zeB&M1LXC!G9(@SI(xG%ON>+pFEQFVPQ?x*v2B21hu1@7Yd!VK&)o&l?#Bj-)A_Y)c zh4U()oa^T_KlGrx3`2l-3iHR7eP*bFm$%1ImR&4?cqS)Wb`h=G-32OA{X9MBpvn!u1Bb7;lw1 z-<>)+D?pg)vm@2T*Q1%+1jfhFBkv2Wg&HqWCGQim#=v@(PU6gPrvhQ~stsN2b~;oQ zC2zS7vxl7WjesCa+~2%96C*>)Z+$L_ui32nsy99SB0@2XS^VM*f4y%v}l`G@z=joK*j!xq0 zbis4gye7{#Rj8+NL#h%n@8FW#WeFfUI@GRk5PNwSf61scs3m=*kuXxl$7?*N_oK~)^TVB=p5opK z(nFiQq5v}F&3B`KC$NbJJu~q2C57EhrS^0--~=X~`}CV3F!5ek05T*{3cbl6_Ezb& zT1!=7`5eT%l3_iCSr z_btfV6`tJk(zR6jR=S?r34B<4ddxB7iT&bjC~jXQLnm>&1#43JZ4^;LD&vsi+Yc9T zRxkWdr!^WDKbu_7S+4eUhQdJ^Xu>h|_o!QhZw@?XWj1}!T2zyfJha?DJkaU0;IkJ1 zxgUejhAy%S|D>6hr@m4S=5JmW;=04!@}Pn^stBUr>z7O<6$Ohnlw1s%%%R7$FT;JT zPN1gIc|p~zy#(rer!VO^jK+^YRGwW~VM~q~cBVSishD{lr1u+!)tVKQ4m^1kQ9qcY zY~uKQ#Pc4vt3`dXI#71=W7YoND5jy~FtF$JGVDmxU6eI<^U4fJLx(Av97vryQ@OVv zxY!MqZE~1+H_h_tq)tK_)%!weQtUX!k^6*NbeY&&9|rwCe|!UYg|%bzQ38_rm>{+& z6)pG1QpZtyMgE6$H4!}=x)`LMb_EiTlS+2pkD)d$pU^X8Zn`C> zJMjyWpd)jCY;rExW-;~mohJwfQo!D2dPna3e|zR2>WJO!PZG<(qm?KfWJg>J@w7Ph&1!kh12bJnzK8ZlJ$CUw^h`_ghy{W1QT;0OvN zT%@hxU94%YgAmJT@xUzeEN5sn_H#4{T@dK#rg<6lcXs%Yl6x{kAO3noG&la}oB(7z z@e|#gDQgxFbLwE8^8*#}%RaV}=%b5;VQH#xQ@`16jI`{Zl2BB`x!i!zzLhlhW3R3@lvnMJ4wrobd%y&`nopa#fl?EWC9ggKTw^F$eJ~H+_>A=c8sr z+AG(;x~iXcqdEavCjO8j zKV^ucvi-$)LEuLs)@<)AwH#bBG#|QIbpWZYaF+0XcOi1p_5W@;)`u1ecvLeEy)G60 z$b`RyN9>RjF%Ka!7DBkrz|FBY!7~$i!)OGLTqp<3R+#-b7xE5lL!FcePLd7AV{&Ji z0d}UcSiv9gm-yBV2#&gJyWug09Li>b6GRSsJ} z=cT9uw!0&*ZP(0`aZ!J0;FVVlN)WKV_0oMeZ!=k3^sTF)$+cL|YS3vTA_X$?VemzQ zw#%XY0^`Mksp^hJtZ#O7e{V6AjImFfT8M#6a2n+|HHI@pAF8u*#Q+(kIDbWcDkW6X zeOlCMh^q*YM`+Rr4XxfjuS#J&{PCj2A%ZvR&2){bBn)qburs~SFm^w?IFO)ysSq&i z?&M@S2)ddiw?@}da?b=%`vy=5)MhMfbG$|BEEEZ{8Ldeu4Y=cE)2W}DjA)Rlj9ZdR z`xNb0L$gZo(h>*+8GH$P@jG&o)0~En+RzAsP?{f@YQEa$Wq2YN_}E=BJ^a#z#q!W~ zDZ;nmUns^RnkQrKwJi5TjuiFig(iWlko$c9r!>nfnP|_6Q@`432rR-QOuo0<=MsWb#EdGuNCyWa5%pK+( zKZsOwPu4bDJ#_Y@vR$Zq`@yP`Fhz|IdNa%`l4mXTHGf}fn3lyeV5k$-qr0O1lN#Rz zk%g1ZR6{o9sG1qjf#l0kEvo&EJT*D>s7)FVfYcIRdDNTf^R_V**cD;nl&Uh~gxstL ziygHr>t8FpQ@WQ%4vvm&RDBYvwMU;5NJ9n@4Qu0@+{49Ok}wdcQA=TiqE&(T^r0j4 zL9K|14;Rt;34*%s=r-e6I5Ml)zOkRq=!I-|E=l)(yJ`gX2DD!Y9Y=5moVYp#^~hZ` zt#{+7(?w;+WIckf9$P$xOR;9nA`xYKhU9b}N@}iKLu${XLmJ=Au16+DWGE>nNTioX z*Q*%-)cw^`y@DzK{gIr<@a7p#%L~2CA%rI+Uou+>8x=DzV;AaHKBGLr>GOYWPzgmOF#1&9UuUiGbH{fRr^k z?kx~R-QBO}?Y&wOY08yX8kAfU2lf@PJ~K!7MFOuxpg4BgRWPav8le9R3= zx--PaxfT}fScw?14NPRQxRQqZ?=}@8;8}rPX-q*QJaZu4;)F*`1@1gJ%XR>nh9EY5 zOHcc(pgRNYGG6ujUaH7Onm2&gjq$0a zXgo!?dnZ+>ZI{d{&HPJ{oj<)U&;3Twc0F%q_o}j2_reu zPm46>DqJ#$?~)T@-v9(Bo9wjEPYRc#w#D7{ae|EZ@%AD?=HZGFtHzWZuRY+8KPbN7 zH!4qI!agng98#UvT~q8_xSH#TyF_2?7ZKez1fLs3(cuLB&FQf2&7}!VaQRGTNHQNO zJkK}v49$jwFnYHA`ddB6>)VL!-a*B15>vY^f0gdLaLXob$3Zd~{ZBR}58mD;$!{@N z8Kxxatceu!cw1`XIYUocZZ7tiOub3@$>>bg4JJxkpZb@-^IY_~deM5jtHRMm8(lA- zEB9QMWzl1P4%c_0%qt@gGZRRw(~s8ny~}h4ZE8@ z^**EIy*RQ*Nnl0aJ^Ie1(wy7SXut{4FD?1*j`Py=_J7Sw2D(lYf4X!X7Z#*F`S#sd zB=!=-Qo`4u+Myr!K>P~PCbKBFXfO<*KHHKMi$7UByz7$m|2nM!^=%a z%9hi{cJCpwf9qiFXPd!yo&GQQlmT3dr+@enh8^B;z>}!NaP6-Mgs!5?UuF z<^#layJNIOk&Ewt2n2jZsEd;pn%@D!fPC{ViYpFG9RuL zlkeN)DVz)$8#nfscMclybXb|VwBOy3Fa(ysI}R9|Me~+*Clm7TuToz|67cRHK0Ta1 z3r3_foJwFukYXt{c|LjXrvFkJ`(ma@32OQzt=reMxYFpNeZD+Ffv=I7fOy9A;OKbr z6HCIpgC)^3nS))|P%PYrJL))w3fY*-%V!X+sx-s7R`^KnL7V{|or_EJUEv>(6D(Dt zWp53PSEHpPW;jD9;MsG;3(tm|r4g2Sl@B`loaTK>m#9o9kGGXOWzs^OqK-5GC-1-! zrP6+HaAF>7cJWCzsDqFxh}RJHZlW3!mBnY^Y3YJy?hf*E`oLOj2{~>S&x6EeR>GV? z_C~zeu_4Mt1FA$7?~6qa+||fv0Gh0TI6Cs%^VP`t)!#TC`edRmnk?fRwoF_OPle1H zc_ExydoNoYQUND*Fn%5pa@fnhvxQPF9VKZ|WSN;lT89dYLcVM@q7af?WdX%qIy z84lA=J?cGl#7PMEXMTLrpju6fzImc%im6s+F~a}lj^$^9zTf<2Cng;q84a4ZnaL7U z!=lsaXR72O_SO65F)8S+^oyMmLs2zKn`M9FMgp-I6IO{mqF`Ieann(9DVgtEe^<`xw7y|< zC_+UqOlMaiy$aP~O4Dij5-BY{YVr){ZaHppulJklraS$Rcu7g$yv`XtKKrq!XUjY8 z3#jSpp;D#uC$wj9&JPuOMj)-ky_PP%^Z8@G*- zik{sVpLJE^-c*L<)?A?-@q9`jHUW;d0e)k;523J7#c+*`+>8zc*bv-{#6tJ=Edz8m zS?jLvVGnR8<{y%Tk@-;JEO3^rObvCQC8ge8m%jy_C78}{lI^gT-f5x#)>_`O_asFD zLbJV@rx=sZ;0$r@*U1SJ5k-OBZjM;_P0EMsF@hT%(^ft2hAsv5)2FGEj~|@@>tV!hGhGfWB$S-?$^f;T?HFuAnf&M zTt@rG8d+KQG-08e4bTxLG9Qe&q5Mu!5fNb+@MPvsP2LWmvl$!U? zZB-AXqE!0j`Jn@jpF%8WTI4^;Z)t94`Rn-l-or*q?s4`MtPAs@h-PQ1bg(H1L`U)i zA-`Ab_#DU^Ii4d3CE^=qdNNl$Yc)SGGLpNopfz9vX2>K#T!)ycrc z6}YgtXv>XWefTLMVImZ_0LC@|*s4Z#QOvyN@7}4px?*r!;Yqi(iPYK5+2|b~qjZ`t z!N~muK+_A*o$u@bX$u>mn#QK4rZT6NO=ub$Q}*;_;@)%T`+|HL$pMb4;>=$L4}}pT zoE|E~!NH>EJcE_{J(i5F{>S5c|VyWz{YHmlq(PTQkH zxBmV8Pc}C5yuYsG%Bu9A2L7fQS&RlqCW{+8S!FQg9-}*Yd$(Z~q*$LIF4zB#xuYfo zC>`gb&P=atXDWgK(jSv|n&e*C?AkiOu4Q0h@dKzNd7;|fK2T`X-N%JKS+C0XeNnr*0f|wYiaNF0@Ve;|}pHfnkOZEC<2nZQIVv-ZyU!lg< z#nSrh@Yv4D01xndUKV!p+1VQ$S#V$yJ0+h2NH5P>)F@h#se^3)BM~Lw07Meko$sm+ zrDXI7QS?e>T|9ORjOCWI$6|+Z@$m`(YxvW&mo6U}@N7y#Sa^7mbhvqnP|H&Fwr>Mr z=$D-xxu5BLgF{1>LkXlm@)Trup;>i@SB5XxkA-S2CkKy?bVo#Hi~LEAQ@E|ahQ4pI zomaM+<&Y5|OLAHR3^>1b+_e>XMgsa0AkCbdpfWTi--3Tw`-M|%eb8~4;Y9RMU?aJ`Hlaewk zU|6G5^jz&Ad}`$(bF!elV|rV;lizbm!OHqJBc3VA>QuNt!K5NF@n*@z%xqI)m=){( z_;O|K5(C(rG^77dLjZ9|VfAp$C8_W*$2sMDkAb*2H3pNDFl>N6a`hqocJ-%-t|#V| zVchT9;?uH#qh1TXFcuU*4U?PQZ1eys6u{`DMZ=*3e`qAWTL?A`EtVosXJjzN>z4qw z)lx|ydcf}au%7G?0=$#wz~cX!9n|z+$3FvLU!sVRDc;ct0Fo1nhrmx8fXwijpZyt@ zy)IBXZK@^-;JE!mG<*-kS=yv=6y%vm05qDjW&3IY;hMyhFe3GLc$m|z0Qde~a8U|C z@%1?jY9u%X7}^Em?9IS_Xx@#jAMhb4G@q-e0?Wj4#1h#B?Cnq>O`hz zLQApoKaRz}fcQESkaYem7YVC^4ruq{OLUv{e~(R3WWm@j&L+sflQI8tp-4Uf#gVv4 zg3-YQFqEUD*O<%zP8}xa$^y;r!*&fbo<;pD8~DBg(%t$;?G;jFK3FU<`u+`FGA_Wo zV}Fqk2Ub=F1{P0DH2Ig;3)7B@R^48Bo_G5%x2UL^to(oiW@7Jw`K z^jxj>XhU5%14HH2@_l;eUOPhu{n&R@y20`Dp;MOF6JTVHx}1 zzzE?FgF6aVXnh8i8qu!_me>IE7z5={!X$M%p5;|jcoiwOZ7d3X;oOg1{wSTww0$c)uF8j7{Z?ikpy78#e(2( z75~nVScf>w03$GaPnEzU65{y#BL|}seS3n6oOM|vL^8a!5mSI&s-}kT*f*{hMAgv%R-QA6J zw{&+SN~Z|Y-QC?HjWkk6y1TpnbNuM{_gv3)`N9{R`<#1b&&=LyueHXk*z9v~Oq^=3 z%5T5R^}RKT)Ko%N(;91;f3#KNbXqWkv&W(~e;38#|Cgb(sG_0rJd#b3obI8Zc^T$g zOw3nyw(P_8mAwzRh>N$GgPgfk`; zC2dybvcfS&s?F|Qu9NR!E{okM0$8ZHFf`5na0p)l1Mj%~b{MT+!TzJyr=!BWOqjvK zdcp5|&wKp>P4qEfb}_*qJby(DXfHpul2NeZV$hLoTRV0J=Y$~fHekJ;BzF|^x6eSw zk~P$T_wP&n-%F;$`&L#mUN48zn|6g@qs>=8+TZlT!ipV%KO&;%Sev%dz(%yuh!W)k zpF9J>RKj~|`!833!g~^GpNXA&kS+%5QvwO9^1G^+c z&|!)V_M0d$K@LVc`n!LBhMo_IpIsZ+Fu+L`(YrccJN>1q`@YV4ZnKXf?X{1O4=DUT z?fl$R(yHfoyAly}J;7lJtJbteiexk4Eqcd>W=jYjklYg+|Mc&SPeb!H4|%aPVm(cm zhK7dI^(33IzGw=wpYaULo|m>l2th~2{Jv}~=)HZ^SQ0qgy#wQlRck;vXI_bT4gzQM z|ESad1$hs2bu#P)y#M@BkeHP$j183_d?MN)rBtinpAi0q-iu9WlbX8! zoT52}mq3n#qhTUfMhXe>u*}+>719dSIOZe7$%(91G=7rwNi`Ow8OR-&cE1XpCaO$S zLxN28N<(Doa&mHz&+eIlE?W67Yq)>8m|I9skH#Obhut7;l=?|n!G6Dj=>xI*fkXEliKdBlbAmfVh z^vf%r{cyH@Hc_C6aD+goaE1VT>rv_RK(alSlXdw6k2LSel8hB{me;?9ZVi=;obU4h z+OO|2XYo@vk0Kv}?h7)Y1IP?OAyZ~kP*Gte;PsT&x~O5(3M`nRT(|*B-uF9`41X!4 zRuE?eM@K9cvoZ1C9v+3W+6jmhHP&;Y+w&<0Z+<8PHI|&LY)*Z>>-IUi=(v7-xzVmcrW>Y3$46mubHW zs5 z$NhUaij1O@s8L+M4ef}m#2OZ407bbn(&L8u^L5qgAuN{y_IrA@p8SQgSu=jW=Vav;JtzFgDKTns`Xpfq;K< z8qVFf*w{XYvAGnhJXV=|!kFF@1!Tz4frPqx!R7%U1dv`Ax;G#H-3^lyfVPSaC*(3w z9CCwB|I44Ww(b0aY%OyN8E-z))Qes{bLI{a5^*3g9W57n6BT;#)%ti|EBu~46=G4= zLJrqjb-G(M9D?m^W!?-_OY1+|7Fm;%vXE?8g+Jy(PmgvQu!S2}=#l;16h40Rhh{?R z({G?h!$j1hP%AKIIH?}3%pdx(Dg=x4OK1gLi?GqD-hmIYqyBjYH~8;*gC6z&p78;C zHg`X*;cuUZtF?lVuQWLA|4ty6O@79RY54(i2@dy!O@_)wxDcH4WI{YMw_1IuuQEevKv}Wk~+MU<5~%b*@8k#M05a z+Ia`S-QlW%Fjt0aa`WlGVT=Mh9aI6cN&|<4gtR%xwt)5033VJ(j#~ieVCvk>p`wG_ zGFT*G_m$*k&)I4#K9pTZ_$T3QQy)G^9$;SO(l;3bJps%$G)dsAZ5RJ{^rA!eY2hOM zpQZf73=C20Ln+i4E8j+dVn^i3Lab9FD-c%bS3L*-B5FDy8z_1TG9ICxbuEjcbO`0U zjlbQVtYA6YpXoD(1+6=#7*j+rCwXBx|lFjr@1${;!ir^BSnVo@g|? zGC1wceoJ**e|daVuuv!nSR|jOglbrloJS+u$}%?dpExd9slEqv$kXK_B88%Oa>oaP zsgXe4dqK*Amw-`>uqo|H>Q!+{FDWsQ&Sl*!NF%hTQ$`803S8b-K<={G3C-0i>=;=7 z?x-Ws!}C7{_?Pyv9I359BJcF?pAp9E?N)l{=H@!cipriWmAJDu&N^_?Ma=_zACIA) zZO-)!jiVL?ay~XZFgZ#cO_cG-N4LL!C?`%=Q_y9O`RldTnEIsp^$uS(z+|D^<^uKT ze9qyg9hxblOZ?!=|4O>Tw*F>GAN#>CD|q%|@bgD_I4UYCplKJWwp$Tx+$n7`J>47y z6QK@LfLOaqi;}TQ#>A`Z9s_kVVi`P_I(-`YL0v(>6qL>ic!*P8nOfV~+6-noy}i77 zcDCMj@&@}`%-E>}>Wf4D zg>Gj~hFnrUpmO(MuzF*WA(8dS`$P1S({(edne9WWV}n|3VT@dxrfAbSVTMQF<%v-~MTe5S78L*qwlvwUjok_xkW}a&kwrd+tLKT=qSY2DLBY!vXkU zKGoQu@M~EWEW0d05ilFLWQ$=PkVz}9J_sa~ZcDu_Y}z~pX@;YL*={Vf+I>%Sd#nLg zd#nZ7PR-xz26e2V^R@e0&c@cfhqZE%M>X=_jF}ah|L3xgzCfIiB&MU24Y5K;M`t$d zeujjIn12?3tprLOB6qx3H+MEgW^?OvtUG3%i@c=N+j>P1;C1pxC`G(T3b#wroFXHh z9cMC>HxP)L%XLs+pfT3=Q1Qw8%8G;M>hkkMmdBL&j`IAdN&DLn%aM<$+PS3gM;TG#B_4U`5D>Eob9X9YcsFCHeW&y`p~G z{Sm$SY(5D}!|qqAmJ*G&&tqND4-he3{pq-b6d~Q)1^X!MGdlB`-`7q9X!FnB9zB8X zh|-ADLar;08$2G7#C&!c@4VG`KOl zPNOiN`9F2s8Jtq(3e3zjaKEgOz#<@!IN4}bvf|nOS2zDprBcej*zOC>%zJ8Klz9tB%H zH3v$h$I&m;{DU{zo3l}{&sy%QEeQy??IpXtnJjNF22Yr9$J4!eXi9ajTpiL#niH}< zSwYtqzY#qUL(K%}cw_S1F7hy+tZfv<8!T}Vjs3nl7(rd2&G3c2#ydALHXdCf>!EzZ z@{P0FM#>6OU1-1bUfmVIO1X+a_yQ&E4h+zz(`q`) ztErX$J^)~Cb#AnM;Lg_t7U{8{(YrH%f-LwtDunRcI4?_pabYm@U3j zFq;ee;ElEAWt6hm{FQz`g3}5H5+F8X&#rt;|Btbv9?rLlBBywa2Fz>7OBOw`*sJ8t z=?%>n-%U=pEe_=E?1FE9K7c^;YrR|MF`sM9(bohtgfi?Rv!ByXPw$tnn6Iyko}FC| zW^d?ZmbKjl8$?>M(U{QE(!M#Dy*VlS)p^hWhX6lT72Q25ggQ^nr+G8nuWVtuQR>CK zc9mDm>9{zuW4bcCP{R4-+u!7#UkVIOb#{2GR(Sh@&w~t+*C~4V3x-dGZmZ}`(nJ8C zDA!z|L^dfgOdL&NyTh&93+^i$#}>L71H|l?cv{fY8pw+@-Z^~IhnN@yn@MUs;kgi= zvv#g0L9}_2?D_`*AcxzfZ1y@miaT8%IPq77h;RIs=a?0Co*{W2Ki5ZVJ*A)@vaQe2ITm-Qd+O}P27!_ z4ITGbRM9+US{{~gtCtUIPDgKSMx3U?m`^`!C2^e0V+=_A*jlQ%Q06cim`s_d@WMwz zK`yC0IDTI@f^g6ZAmuKlnLw0(p@IO$<5Ukm?EA~7w`Wtjr=Xf20hPUsVRu*s1Pi!; zptLvz8OTF4nRycWNiY#T>|fQ+1Jti5|`U`WHNhaC5FdejPvbbKN|z z58-`SwQ4A?J?4d?YkzjZ|80RoqWtJ{qTowVxeq^T=K))n(#w(^&%s>n)0G1Yqup8{ z)=`wzdECPNKxV#>+aR4?ei?nR<@nppea&C2Z+I%nTel)grFcfNZo!oUWgGINafs?y zz@f@hL|!Pu*4_qpsY{o`+%9Nt?W+?Lw zv&lW=6e5@QK5f3m=9_~h*!nbYpbP`1w-lFlWsoubYVrUKLTAM|ba z5_}Jp$-EDzDO4VSR$A#`U*NSd@OEq0m#PP_y#52+{)e8};=qJ#I?p*xjka7&dab3E zxPo*8TOxcmm@iH^&GQ7o9}a$GvnXJM1ATn2DeVDgKt5@tfN5jXr%qQ0rQ`Ef-Uo|d zrc7SfsTv^3`{5q>9LOcnGogb@@kY;PY43thWkd*^plP(~;#sAyWJ7vpnr9TZd@knn z1--iZf1TbCQJW3l3&kXU6>V_4QpjJCti_m5eZiODed(5PD0@OkNMh3x3!QkL1qB=$tLgkkioA>j)-kaM$W`^>$K-g`B^4nl>|h8 zPiuZTkQ;6F;k^jW!c?oZeCc(6wULcG8tw*~mF-o9)y2}TRaTk5@SS@{Jwlo5-xwst z#pNLyXp`54V^u7avW48KESL$p7SRj5LIuZIG2AX~^AX0-eoMgUqQKoII1V{igYR)qEJvG&#)}(lg4Il|wvN$13kQs?V`04#-j%4eyy9~LOkh`QNqhLU zlbw^?ft-wPXL?MZEbgv_!uvbA64KO{Q$_oCRxV*V{88CU(UJ3v1@=_u&qPE;d*Pn< zN36yuZL=MkyI<@zIR45X_%;Y6Bmc$n9KhjoxuW&>pG)ek^?$22>cha}ac2gztlgLZ z588(D9oN2CaWP|8tIU!z1KHX)k?#-o353gc--Sek5Zl-p8V)SycW8=;_@A!Zy11|z zomIVw>$d`s#DI4_AFX5pnidCk<<|=NL0&frypxHLH4(^Y+g$-iRj5_mw{M}XzYC25 zl!{DftpX2x_lkQLK7;npQOnH%Ti1LC{_uVSuJPCyk#|-L*F(l*q0+2-FOSi$sPoJT zuEXhxd`@H1pr5F zlE@jYc5|F#+(q=dxqvH^7(Ap9cmpi$^+v5QCh1I-ro0t*mB`ng3@Y{=9eqz4@AeE> z{}s&=Jh*y2+?6q#%KM1h~8TKPBu}b>QZFL^y`DI$N4KX7_pa7Oc4g= zc4y2_xrgTeY>mj|ogneQO*t)l7Lf13D58CYtY|yJhy~7+Z_D{z{nEb z`B_+2n|WCP0e&)}K0Z6EIkzp^c{m*>nrL$QV`H>U>L@BoZiW4l`R262kCYUzw_;ns z71CgVs?BxH+ju`4b(*9md41J`ywxA|1BFI?b4|^J)=*=l5PJc?c4KvY^w-pa2!&i~ z>3dfxN!cigS5HuPrKH-l4cJrbP+xe`u7x^i9Jz8iuD%F=;TGDfGXran!bks@%laA&b5Q+>SAXFE5_eSU?hS+V0H1-35GK zLHW0B`9bY|!tv`AOidAM%zjMi^A-*tA{;H2>9)-SxHD?oD<|i}$WV&Ms*^5k)Rq>s zAq>21CK?>X?5yz9on5M-8u!U!N+?`dY$PwO&slguMOKVeSq z+t+8iGlNDV0VUVkZQeYz8r4Cf5w9c+dm_F;(M|-X%@LJoi|-2}rqOiTobON8W!7M? z`%gX{sw5!tCcRk%s|NtB-w=n}4-en{>cV;w7a#xHC*~?}=F)haMhV~2NB|(yqKvU$ zQ4)(Pp5lbYn;03v{(3+=t9x5Mau(xLISL>!L&c@|qlFrPT zsfBxC!sSfAuF6D%X1g0z9WSmuT-@{@0ngJ%ry?_xceSoJ$8CDWxQ!MsEkX{vop5P& z1gmtk-*#0LiTvj9A*sBpa)-UUzCmid*w@^uQO$Fx;l!0qJUnF@-y%9H&yw1B?kI6V z7ZVFy4bF+O9hO}#zs05Ic^ov<4DGEzQ4r|Ak+0BM2OdyYi%jh7^3glx<9RDaDvq?m zyyvEJm@nt>S;MeopKl{6T0T6pv-(cx_o`8758>qZ0zlV;%hIlN6!x%Xb_a1OD(Bd& zUzPN=yj}=h4ccJ?7%oYrr8-zE(#W`U*}y1roGg-?G)Y!QChp?Pu46m3@&p~AFW6gq z@)-<)=G{c?$LQ*Ve9%Q)>|qAyila0?eFr27c_GiOj6Syl^|wfsakIR?T5A1b0=pUB zU5$N75Q2u}V?iVD>jJU0omDdjbL@Eqh4IY{G4j!&xtmoH)BO4`2@H2HXImZ0unvKQ zcHi^JBQ5CCZeVM1$;0#ac}vAJ0h4cbeuEAwm7Eh!h<#Y!tfa9q4)#;I@1h1Td6E9E z#*h5UAb%`m{EmZ`AKnfuDa`I~uM7$t`0)6=o5=}NYr+c}@4z3BecmGnXK%t{I|6h% z!LMRo8hmHl{I9PHB_t!-G`@p_Ji(L^x(*U9}$n9=vUCPBl;mm1HL%LD#r<1v(qG#bA82ctr+Rdw*M zvO%BfuTdbs1NiC8ViC{(;r<0sn1{;2fRPF#C^R%HPRCuskK2q?w??*?6Vw01h;gAXJt5i!?i8TQ@8jFAKIaJ_{Rt_C?i{K32|NTBFhTY8!V1giEpOZa}17d{9WGFj6{zYIn z@bAnR%$r{fmFmy0&sK7+Z|Jkk-QCK~sly)z4wUZaA_HLbYN39c&NQPKf1g=T3LaT% z>h!aL6Y4t4>~rtQX}kDHCXF`*xV!3VD+kW($EwOZe%BWb^(~a-e@&lbZ}-&!NAcYG z>;r`Euxukkx=GU3^qN{WmZ_D$NDi(9sFcke?0^F#H=pkKnMtFT}!db@~9qcXx{Ebus6{?7XXn$6=qXm|;u(mddv$ zNim`NKKi{M>srk{?PLi&c)&_P7I;84lt!RAzX=?n{vbEWP-==v)!TJLT3=u{Io5R0 zDpfb{UUa)KyK<(pP*Prx)sZw`lD%}fOI!O=4gjPKD9up%3Y0J7Uh}LQ{vS00s(mn= zeww8e*j}pLWW?w{K;M>3=)Otf#984`WG(XM16XpFaE>-mD#VFaIcRwE>q2XT0m2vm z5)F1d@YD!nhOj9WIAA;}4BAk+IxX&_<8pko(VVk|Ry;MJTmJuNMv%&@sR%3(af_LZ zA-^SIO0y5`e@inGm?`90Ad*isH&KD^7Fs;=fAk|_`F~C^Ca-PRf4&4gXFNcx3efR9 z5;+ETyWM8}9DqrqG0u742?D1Qv~v3Ax8=FYNN zPGI%?H+UYwfO*Fsf>kB^0#*=x^C1jyTO0)=AdhJ6XoLWJnuoM&gGR6NiAd) zD=CpeAZ!a?XsSB05T}3abMWciewDpXkLY)1C(|bL9RpzG^WRSN(E`fYoIQ8>HWL>U zGx9TmiIRjwz`c>h`uDVQt}NiwbWcREy$4}p!W8xbF8NzKI!V0@ZU=r`X~($Lbf<#$Mz+vxa{4<^eld2vH zE0-EsAtX_Q zUX4hBe@_RF+tB^$%yM6nsTG_oEqCXT>JI}r3Gx{p7yG5mUL2}ykH5bat{xa9!klFA zU9F}$#-5Q8{Is2l{f>en4!GD+zJ49g&BLRdW+f?!2W$xC_4FP=?aSvEW~zd*UcRKe zK2>fh10@L5bgR4^?Ioh(-g73VDiK`Vw{PEyPs`p-jBN~4gto$n*vk3XJ77L;QleQ~ zTZ@T_5k$c&-{A+-i%xP}#_EC1 zoDF>1_^l5(5N-k6yV*xq&x6zP-r#p_+5Wx^FJX;On<7%k))CRUpF?OD% z=G7CSGnmrW>lB!2#qI+0M69W5{nZVVIj8tHR;s0nT3Uh$3F^mt)7GVrCki3$s& zag)P+^>YFCtZe~MZ513AZ_phszM{=j`6L~wvqAZ$UESU2p*B{K+OMBNW}^W$Bo3{E zG~aBT{1`Pg@$M)RRQDG7s%3=72#QequZamqPB+F_PM3ZD@84@YZYEr~#UftiA)yzy zDi`4_qc&W3EC--y=7UI>$bTQR%{L?>(gi$NS+_^CiV)x8spu-z5Dw!COGxxhWC(Fl zB2BsT^HA^3dC2Q9SDTJXXFpMW$Ta;`STj*$VFLK8nf*kK#lvZpNe z##Gnqr?Jv?quSAw40$o^id$?h7bHgt7L+*4Q#`r{U(RMl5XMjSw>#Yoqe`-?rO$t? ztb|&kqWC>%JWhxCyZkm|9`WT<;Z8lqUbZn!xJ)BDu2k##l*|(XDuKDCivf$X^}!_5 z+BxB*g4jk}L^bcT@14+t#QuViEr znH97*R}gA}?{K;l-4=Pu<84MAsfeqkKqAwvu^dN;Rh?p$F>StL-t)1U?_Ujf6gL*X zXC0@O0z0=vcFtn$rYNY<@aQPYU%(SpD=`F8r!6=R# z$YeWK8D*=yeA6LjZgcakPYc2?AM^H4luQ%L!KhVIQc`gnPmx8;Arbx<=SYV1w6vBz zGoM33Bs)doS>-${D=WL2n^&XdT%@oH-BX)y9S=MFkvKhAb#8rBLM&-YD;B#Q*ytD- z7?x2Ds_XO3XnHotn$2enV{|RtAMS_XW^EajS z(oQ*+oeX|%Fs`D6M1f-=A__{BK>?eFdj-rIDQqF>U0g`=>zg3VyQ5Lu3iP&R2m z@u+5BYBiyV*VTC@Qsumz#!kbmWy#xBbXwDyJ1v#Ny?7tInfGSQ#v>ewKq z<`(}I7b$4vfC3R+p!WitAFSlSl28b^^u;_7vD@93V)gG`feEfwv7ie zGO`^{^pl$`{wl^r@X7Ugcl|7Tkb>fK2yvxh8 zJ(^xebA{hC82`o}JKE!j7A0aqVO#wpnH>YEC7GRyEIzb%VtSy#eAkM$pai* zspx8;iE#p?f*f!`Dt7%xKYdJu5<1qpS3t$^cmnK??T^y^DcJ9YolpEfri*dFtyo~}D-_bm+6 zre^wgghs`6Uf!7beAc7ooA_tA*@C&4lXoTPd4hvl)yy2U@!==%s0I0viz5v1B8^Uv z;&R#+R?L+i?Oc&Q`1!jt(fPINNYghhN6)PUj*ieDO*(zpT37_RDB$LT^z3Xu_PP4y zU(VO3W?S3CQflgYJ7YPaSdiIjv#j7IPT0FOaSX2(GTBNioPD|B(0Hr$&N>GUkv};} zjP~mt-VwHdfVxVn-sKJ^3asW;OyL81F1y=1 zc!`fcTBTDsl}lL@7z_i*?Vb=kZh<Au(9cO2N%kzDB^Yo0FP23Om@%9 zcO^P4iM7^qk~FP$&k%8@urfeE(=t{iepaKq*O0w*B6@?YA08SfZeXjtVQP-GDzzl| zNQ#~&!(qn%bZY4}dim9InhMV5y3S0Wmc!X>H-jwu3rG2n*TG`jEb>r3$e*77bK#Ff z=DA@-&{Ls!ia84)p^!(qKwRV*d6qzBv{F)2KnItcCBzm#N# zgJ~p()>f5NB~hO=6%@X{qDHn93V4?B81_kirDJs||Bw;R$j*+O{Bhg7B}>hZOvvSZ zN&fqCt1gD;0RwDLJcSm^jxeth*F(Mjrd^AhaO~bx9xYcPMw-cQw2EMsWT?kB#b{wX zdHCFpjb?6lXR1WT0&Hs<^ zDBnLc3W%UT#zq&IF|w+d45^(&siTs7FI@g{S96+#AMv&C?oH}p+s3kA+?Tbr561I9 zn-@HJBQNHErg#kBrIOg}+YGfJfU6zm*6~Dv4=xH{R$QsXM<(ID`4-I(tJ|RkupZ4W z50~uGRb>72CQ3AftGt@|!doRJ^E6T;$Mjaj>zl5-MpAeTJMk=0o);bh`J`-NyP`Bl zG$rf*l0GLu&vbupmmsaRx|Fd$TRf3s_BRhNV0a{_}dff5yHIs)M`D)Ia{s|dlXrfmPVxQ^h=qsF+BQpyjc;JgPdG2 zV!e<_RYA<`d!=;xu3)n~yYH>51^&zDOs`%Zk$>emjCKWVwMK)#RI`txPqi?>RaW-6 z?lNqEK6OeBd(I+~-q@H3(l`M?>SVT4wDZ2} zYf!BG+VHg@9(naRwSo~e>w!}-eaq!?DC3d3!@fk}X-5b34$3ox?JR*+u6z?6{Np6{w(U#>*%z}4Yf*9#z7 z1BHr>leQ?|Lr4qcWN>P>E0j6Fh5rpbJ$>U*H~v;>(|#rZD8!1GZ{5JxACSHP(AA$M>I`yy zV_b49dpno~uM2{^y91v*z^WXdt}xV24)B@-M%6?VG4@dIj_k(>a)EXMnA%SOZDE^p z9G6kBMMgrhFBd&YezG*k-TEo#?@|Nfi)b@A`keud_{!F6sl(s?D!zxv=au*_lxr+2 z|2CHo{J}MoSSay`223*V?GIGGY@4>bST)GD zr4v3jc?uXBSJiIgqMT`VDy5$XES3TS0|#(@&Mz*?Oek8xbt;Ivkh(}{P~)-N5<|Hd z~&PkQc$O=T2 zcXqDzTw7h0_x9$sV|5@RBBJcAcrhg(vvL4%o!nuJvVH8&vlHaDrRN9gbzz*xlp4$ApZAaw#4GQ2;XHUurF`4(EpLM$hs z&%F_3fBttSBhcBMNx#kCUE+iMEegBZVoDb2eQk}?_6s3EEupAEHM=>+8N!+ee%h4n z!;o4FB}GLc&xITSh;hvKEC6ck8V5I|omH|lLmU?mF9b2i-SMbP2L`$#y{;VrYZ-Ph zo}57T5vd`%VRU`D zz%nuPC0~4NZ~k!5SCCT|-kfONwq-usdP98Yu;#OgdND8X8R0bB$Fn)nd6z@DDwkJs zuXCYGu2n_ce~+R%hY%04i^`Bv*}L`|5g1RB`E48f9E##RdMWdf z9~thFl1i)|qz4+M3+Fcr52>XM>xno+_9Z`zaptLt3eCoAz0O{#=;%nWkT#Ak4Cl?? z6KXFP2tDhZbeC7URZ!NZCFMF-2n$l$nIo&v84QUxjy#NglQ}1wV=RBLAB?qlpjk%f z`DaUJLR&PgW#O~Tpu{B1uAdHV}BE+duUB_tfquSaG2u{*o#^>^bSqP<&q@|6x2hbD}3^p3o$!4cMR~Jf`oo@ zXl?;ajso|hW<@EE%D{N3gh9*-7aeY+>UeV~iKLvhTdc@SSrAUU${W9{OLzqPu5rpD zmj!h2F^}M(xtg@-VwiaPJ5}MPxwE33t?nhE>@!LeM$_-Q^LZwOO_3OwbRx&z4aQ_v zvyFl4!}0P{135Nc(m(@r+A;1!Y(qcXcz5n?tGqNw$lLGkK-0^DwH9+gGxjzqFV7_9 z?Nt1`JVa-2Z|{CeS2jebzNH}-UrcByktK9_`4wg*${2xA{NtrTH0zJ(;b4QGe1W|S z``8N+dNq|X&0121Nvd0b`}uBx+z)cgE@eM9oPZFiesG;jl4o-Z-HFm;dQVzofhVD7 z&gPw1lY$j=2@0{p)HGB$JD)E5R^n1DtFoFizaAeWOVBaS^#_$mR``5p-DfaVZNqX(J7woa{vu+7P-a72W~wz9lDapcj#3mX8yFn)^2+H?))@V2>B4=y)kKuxNJ zbFD=-p$B>2WedR9W?45$YyO-%Nfk)|@ZV&awseNMHN2T>yZ;8XF2dk0xeRa{Tt8*5 z@j+bdc@yXfc8tyvxdd(HE&<=qNOy7dpI5Rp)&xZO0hV{IbfOOO=%Iy^y* z`9`?-aR(tJAHh0s3Z4pWJSHYwB*!{sWm`r@;d(^ul!Tfhjj@VewqnV_-8noj!j8dy zkVMlXi)?oM8?47K&G^|=Z@V@oMh9$%)uuEwb}=27oZDhVn;&I(Z*g%qC_DNmSt?-9 zwkIX7sB#l>$9>82HWM@MD4Ac&??0^H&?<}|+YkvOMC49qddE`d|}Wv87I;o+U7WEAqCIx0^#hF)PIR`{JG9Q36o5wUg|pMZp=`w+I+mH@_N zI5lTV*Cz!Cl}&-_$`PRVQ^4Bf-e^7^@fw{&MZl}` z+Biedlp167gH~+TbSVMrVkOH)OzjoVofgiXB&TTb(da~pl-Tp;tgw@rvD^p(QZxQE z>q>U9J*#=TS@fAXcb9|LOlx-4cxA!e;}!_#TarfvnMUe4sJ!#3SY%H;Qg>woAzW=niwYNqq+@tlLRpzU1*lHZt>;DRq}`~2=LW5#{C-P8wkdnfqB zE07YuWS8aaY^!LVk0QB9bd3cr zND~vDpx~`m(o}DPn?h*wGi9MXenogPs>hF;5N-YN#To&aYhYfW-ARXS|7MAnmMq%& zfKOKF$$38Ro0<7H6j({iz;)$VeOKec;5(dMH1l<{iy zC1-N72E}hmM=8kxvmbIz{)kv~WLq(JC=1y7Aqd95b1RRSvlA0%Ip0eLhcwyqqmtxm zha4{(VI&)6Dpk8cdUbopzw!D7J{hGi-OW>yXt)wlXkMYL`OWr0krc+tzjg97RHP+# z60p(E>a_{8ts!3VjX^AtF@Dcvp4tc!WaF0+DbQcrl=YepL|L`fS4O^Cwf__dj$zEv zAYTJrAChM37BbFg=ZJGcZUGX5YihqbDXl}G$^q9}T1?tx{IaOiA}_x)nUkByGcnno zURoAHf#A68bI}laKYQs)$w;9qtZg&XkY>z%gXkYvLx<1i$EMl1e)DtrySsof{(>Liw%VQSn2f z85_e|#m2BAA@(Shth7{1=J#r)?gr}>S&}bqz~Uyv^CrL8PZ+4_Go9wc- z>yUuJ?N*93jE=b@C5~S;NoqtT`l2d1#1s*|=sS&b&Ob!#WM+mBLd01GtAAM3P{HM{R zn>1VtXKJD{0NdTv1aCy;ibGgq%hh^P=MER&)oL_UIhvJdX5IuEK(k(xtf1a(!XXkTdG1-+f8Dv&*hWqM%7*)^}bKD4fsf6XOQq0vN?7ItoZJ(KnD#|{!m8GQXN;Zm6 z=e0vEz8IXnV4$y8V-RKSsMEO8H$-+w<*nOYuJ$U)r2pr`$uG}Z0Z}4fK=0t*@bu!M zEz_UrL5cooAV&3GkW3_CJgKye8_A?^f%j{$u{XUi>xUK7`L>50>L_3ZH}~~Pe?{y( zNpp>GZ%yP0p6PjzQ!OcB*@qtdGP$0PS8Xtz$N0CEck_o#MBvf!MiNrnfFeg&qEQn< z=zXc*cs4m%7Mh=9rBa9w1lG-F6|MOs%^!@C!7Y*sQ7{~$_Z8!Kqful%BCM&zAwh_k zpQEM5Q>snlgg&|K|CRz;Rh%8%>gGdNO{-qqgd5P60cgByLPB}TS&ifU*0@R6gs(~2r;J!u$S69=Pnj#I&NS-yf!9rMs=ZaIM!K975%gY<*$s48# z#l^3p^r<43SGc~UrIi)019*Uur@pSPZd*|*I$G{&nj3N|dbZek0l2~Cy@7#PR3)$Q z3Cq^yL0>Q?Wn~M0)ZAA#Rm^#IgWWs=gzemH)y;z zLlo@P{2_&~0B{8*(sUzAukA>~9iHlh8e9LMeA#RUm;2+&SRI{1R$v_XO?1KAYp#NR z$`TMhBSwC1+}ByBwGb5(Hv?-I1>@a_kPxg3{n-ey_#Hr?%a@81b|W&THxV1Kb3Otk z=9-rp|Ht!8tVl1a&c^bJ3hvnEdO9l$tBp-ZNIu6KcUiYO>@9G`+bWjY2Rs@+G#klm zML(`JZS+%inBi2rx1m7;v3LFeNWu&!;EENEB%GTqtts>@RWo0`y^`LZW{{1mc&$tE zlb)Ph!Fb5(Tg7v%`KF7H6R!k?AZ(nmKtK9ODLE7MF^eDDy`ehQB!R*A@1uONC0lzy zZMzyNYh>gXhGaU}P(nNKIlV;FMd4tcCwqEo_C!;YSMFKuaH^mDxh;X9IH+wxjHwOxJM@pXyvsz;{{;>Wu}r0`}uqfIl1ovPb{J zsc+Ts8t%K(PiJHu9b@R&JRx-l7+zbX_XqG6bif^kXknysvE=t*L*ilg6rmjUnmA*` z<+5e&ojbV#MU)Z$4Av->=xd}!nluzPUJCx#6!q@CT{Yv*6a-PhPh-x0;l;YFdZ@eQ zpdm&Zjlra9^pDy%MMs2W!*HAy;rrOl)O7TrN2GC6PZl&Oh>E}UG7UYPO!R&!;JOkB zvv90rfKHGnt*t!mP#FSDZ4JWN;1TCRXfTr;o`!~Q4QZBT>FO}mm)?WAT!TjJiyS6V zOPMv1&teS=MN4(e{kwB#Jj)Z!lejv*C{!yeOu7lKiUfKUw0XdM#JPCuogH`By%I&p z)7W=YZah+GpP!!}FPkbIC75PUlq=aKqh!A>oe0{OU22Rfyh_%Y@#akz2Yjz#*gGht zi)DJ3lSwlk+aRyG5r$)2)h&@ow1Bh)GCN>5y#VhDX2| z`{ct!#?wDhBGf1MlKncjfKt*NZ#biqkT6xja#7k&!^YoVL;-HxaPW~1g0I_kNSL#` zv=|M2*_TW9SsBz=n*2kj%${h0RGc2Zh}+NIqih;B%@O#h+v=Y4Q1F=Zd9(Kq!$_Xo zVEQZ3?}LNd_q|(7T&+)6lAfl*<)@e{c8(20X!2B<)w|vHuvcPB^TQqc zTKpcD$@1!hYBI{idE!bC!jOvl0DWM8Qd!J|W7M}(ES9iNYD^y+S6blLYZ_0SNejxn z>#nIu^9mhJaob1QQ+iazU%3T$3UYrcnH5Egdq)v_F45j5zWK`jin~9|B1g}h>sQRo z(Wz#w=8PYtQ^WlVi-y#l$Ld~}RYipZ;Q)$qXb(bs=!Q(f=@!q|ooPflKr7G1YCCw?eu-X91JWX4n{hDg5*E%haGQ zT*!j3$Mu1Df*|_$eR{&&Ee67+1xZ4(O%}o>Q?^#zB_PS6aWjTrkhAMdB-=Yut8T!( z2qfE+O=cJ9>+56Op%&{sYT;_TRQpkqp_k{m;X*j@7AB=q_iE^%pV#_x4=FeK(ov8- z>RdT3OWTRN=g*M=skVyO7bOLzLg3a;cU-3eNq&?i8RgINFA?LD+w;=AC81jUh1+#D zM{trQHnVjzEMWVy4YBr*v$}=iythJ`damflHWZ<*r9c-=2p3F~&Oz!cXs(efuCpjL z^?Xm)C3;8@1+`l3^-6Jivn<|%mcxvvoe*EXF55P7E)sJM0rseQk8rg{jQBMgMQ(QG z$03W}6mf|-D^N3Pr}ppJK52GHXt4KjHAVaujL$T*t4>F{>dlZ%UxV7pey6!5r0G{T zc^*pkRBC|AsC%mXT)@dorSlz+9~+^btpeh?f927v2e_Rl$B<&EHxM3_-XA#JD-?c9 zpD3+-Ne^9yP?Gc$q6re*2&o^G7F0^&yZ-4O`nUg_QVnYBdd%$o+h&dK9-ql;D2cIe z$jZP<{zFpJZrbsMV6Y`M4PDL@PMZ_}^~@bL3hi|q4#2jMxI+}-`-np6W=Hoyl1wZj zoA3T8GVZayohZYCTFULai^hI?_1X!>kt%5Z7ISc1cO1WW;WjhhF?+B$AjC3zw(kLGAdS|bt0 zdpmC1<3rmlL=xw-{U|khaR2pyAVeT)Fan+lC(RZ4@FF8s8}ltWm6o^7ei~-pQ2*QJ zkbZOZFtQp9;R%%sx~I!e_Qn#D6V66Pqhly1KdxBFI(7c@0&xD_bxo8ZNW42%04owy zK+tatK@f|kw$(1#!ZpF3^Vx*MM%ItU6b@_Nmo$q=?MNE)iI5$@XLKhetU6Zv&{7{dB`h=Fr^W2 zXuR{(vlh=c9G@-3X)boOW=cnDr6+Pqx_ueZEh5!IwpdY^6T(<~6Z5Px{OV)YG&@q1 zE;m7}ZtcRiyNG7C$yB@>pbHj2clysJO6`3?DEcC02b6ILy>OLi+M=|fy9?2DLA&Uw z%{d07(t!_dC}yy zY^#*lH8=}UdiM5k<&xG|=+5FpM$5V2{okz8!6`ttw6t=?rF~|~-6F%pUybB>V?0}* zJKS&KmmIeV4>5vXl>F$&;=ny5Ok(35OkVaCZK|ty5 zP62^$?xUQ0?-}nO-xwSQj`KV_)?RzAx#s*uiwUy~!T24NF#X8LNXI0S;g*(zruiRH zmTUG;rpSZbLIPX`9pl2dcg+^>z&q$hG3$tEJn()u`I>_EE2{^9FS9qUb_pLbVG*&_ zr3g7%l|kg6ZhsHK61PW|`iaR@Q}FvzJriIU359kw)7GK>$c;wU%y{`xrvJHKMD-Mj1QZ5urBYf8~Ou$QwS%zqoOU7`Hv#Qaz9%eO_{I zPbG_ZimIFK2JIV;5=Y4S)t=uO_eVqe;Xwq<9FYqdgi?})=C|fH9ey^y6w#(qz(tG0 zKf03=#tV>1*K4aKv7nX(Rre z=>k0-{Z90iJG^L@C-bOqw>?<#%xP?u15@5`@JUAB#Lme!e~NzSppe{|FxB2itbush zT|$|E`Pu0{lVn{R8mVyNgDSUktdF5^Y`k>y&C(9RI##L!*(ww%q*^BhQ}K}MMMsiI z5>ziF-qOi&NT$UpX_hvzU|3te_p|3l;G!y3A4clY02Q;49<4{6X!LEJjNhTq#yVk~ z8+ObtlS{>>^M*!kSE&QUREXPMD(1_#e|{IH@xPOW!efs+k(D3wlTTGuhwd~K?c%Q> z1|6T?^|_@>xj>sLym3C%LBM4OO}D4Ok4_h0wU^XXmuOG`Xp;7`*jT03^Vno-rd4jN zjIUKN+Kd1YALYY33DEXs@%p0m1m|medjzgk70;KQ#XbhXkxfVW;GUb)+LI6J<2I|$ zU-{eit3zbCNR9nCLnJBr_%u5`7kg6CbIU zi#tm>1&`gbI#0l;n$w00IN$$tXm23rz|~OAxpH1Ut?8*Y@z)Tdpm+)7Od28 z0_2dmxR>t)Awb}8sY)a2I)-dl<}yH(Pu(vAs5WPe^(AepD$V+k1+>2~9RQ2#pc&B? zx^5e3RX8wU5p%o*p%;IN%NOlwUh=-+Lz~k93A0taD;_95%@`5DUz1efdyi5ujYCK{ zsKLI{hq$taoKJQ8+av7`fPW{5rV>BAw80Hl#$Vba zimUq;$+!qm;&i3ddp&>)w6=Jn`vWX7SXMkzonci(dgk$x$sa$yF@kMNrhLL1T`w3;%_D8T-xI!XPvYY*z)I-hNP0v~*9ZEJfWI5O%OMEb3RF}d!X z*X50EwH(F|Ef+9yHHw}Ot`B`w>#EI*$AAmif&cmdbAV~ii22`+D?Q#X=pIOd&;6UlFGu_9>k=~E zC3ow<=sJ>!Xk&u1dt8bg^`8XvpIKx{qew;l4Wdn}wnSCYM#iA8KX3K@xY~rJC9{}v z2WTmC1k{68O#3(k;lg=%ooqg8RsshiH}S=&7OqCEXSGMguAj(nAJ}B@^;6{QBzZfju=iqfSxUu z&nKn=lIPAKWr-Ey{p*x^SF9Ro#l_tj;^gp2OQUhy?N?s}xLBI)bTjc!)#&05;(8JV z&RPGmrC6W}f+1&_JP;cYjao=NtfD-Apvq0r#vKxPx ztW3zH8v>-uhNqJusbjY#ziSI@J{=nzmJxnm#%1Dg^)Dogi@Hu}MzAA7k{26ywHdo) z$K%5VaPer-N*j7hukfwWtfr=B2gK);K}t>1ZH|8w0tzGG&0?eQFzkVy-gEYG*$z<~%~RTPSOvRkGM}c3%cALBU6-PL^5nX0&cJp=-l8G? zq{cmYTE7!3Dl5T&us_cxejF2U)Z}+fdQc(0oPT5TvU!LVzUg^PJH| zMD=lPpKp*^J{L7KO#kfzH9ptvIVF%j!KW=6jzNp3sUv5Y@m~E~V&fNL;f5@grk`&net|TC_UxR()D-)~i% zo*ZErQMH>QLWg;@zFQSY1SK)!dMb)?`m066WOu25=l6D(%IV25mI;-tGR7ShmnS4? zU-z~vSB;y5tNu(Xm{;HFll{$0*T2ml((WFBU>rrKkx6<=%5wrH4N-XIGF!;qgY#=o z+&JH1k!b%Hh$9eP2U1T6GSb9$*8t2H zT2`bzAI+1h2DV6&a$ z>b^X199`ic4f1gs;r-uq`}TlQvWU$vrlBpI zmXVlVQi2I<9zApmO4Dywc8-?Yhi$}AfH;}-Q-g<@*d5$eZo67H?i8{%HAKrkJvdd!CH+jPizK65t(MKfJeE*?6pnLrX{J?=D>s6>GJhM-w!$xuEFjTUi<-N*Q}C~V2BV8PEI_TW9BzDxy=V~SUK^@ z$;D2OYQ55c=<+%<)30Ior~P9`NA5h$;!xkKWK7KklY8;K861m?^9wVr*OmqgctOMY zQx=Q6JW{A@R~-RRIIxY2<|B9_H7lK7RLM_GJqB1%NghalGGlr0T!XSq*~$uO_JxdP7ZgMMX=2??ZNWl!zdiKy&{wPN4{2$#0-CZJDY&IFy)0%joHy z2WpmzgG1Wfb2gG^bFvlJMt=F;H^+TDJRL`U65c1SW84!VDQl&Gd!4GPh_LW4M+&6K z9*D|;N(HxEDArIJ_Q0%gaLY{(g`9M@bQ?olrkm4(jte*{&J-D>eN#f5oN*e-P{kgU zz{ttYPT?JMc>%R*ZR_etU+hy_PzAhfa9eS^h=$(gjvJR|DD5sz#^ozPw*b#7cq^>e zkg4@9MVR=zOh3O;vFjeIpjvY`_*2R)w(i=VBFJHwPyCP;9@Nh_DXxu0FiB<;4am}R zb8}CL#KxH@Bw0M~@8?!-9n`ut#Zt`HC^$MYB1sYFliW*X{42BoUr2+4x<<`n7%1bk z&kh$e9s6V-*5Ar0U#PsYrKMCnma&wbl@&SYuXnm0zkNE<`w3+-FN^W~(Z6rp3RQB( z#+=!{!QO^rNpRG3I70Q|G`^ainc4U968=JVPJV@j$Ha%xy~O!=cauR-cgj>$>+9qxD9 zOr~pQ$i`4pUlh=)?PD2(vJH#pd7|G7eYTydU0%5HAgN*Ez`aAuqKYt$3Kf?u}!=T>ofGWvmF5jtRci- zt_=M|aCBN9pI*97NZ8jHfWH{XnBSex{@vm}#7E3U0-`4P;3R(`hYuDBPxsbr+w9}) zK|S}p$V#(=nxYK?8V({?)A+s7Ey}Z90gjCliYDK|mL4^rWT^hsAJY?jUsZ1Y}*~TuilOzVy_{s2B26Ii}A-hYP7%Jg+JoDeLOB zy=z%793Cxn--!K}i&c2TXJ@+{#Mb6O9kr`>sws$pn>*5~e3rm%!Uz3pTU*=XY6<5R zMBhtK`Bo-k>sN78>IFZ}hpen{g-S$R97w}6t0DAp{Er4pAZ3o7lAJx86s~adxzkfa zLt2N2%LR+6VZtfN$&_wW0rVgAYdr@R;ZGbNr-%LAgrxlV^giCrXj@xBGb%n4qWU4) zcXuh1DSY|U@SI*rC1okk;PcC(qNphI#oMh?5~yOpkz~nsxa9U`!y%4-CbINWEySwpZ>-t?;OYkjP$|?uU+dVv91!U zbY9PZH1um$Iu#Yw+$s*!AfjU|SD2#AjU4+0^%C1-xSZJVZ6QDaKCmkh}vCv>zY7+)e~SLJ8NWck3t_yg_%S&fXxKhbZN) z7p@UaD4h4aUt#ELJ^>?G;&EWd@3?eL*L5~>XQKgI#l___v8-Q+JR(jlJ<(&)21D?v z9fLMlf%4|f7j$y55&+%B7ux9-Z{{T;DE+sR@h7hXq6mEcXC2!{3#`V(lg-%u;^N}7 zT2`=~$rtB6sfLuv;4VI)p>y>+*`LS+S5A0CC-3i-s$o>dFwK2B>#rTsGVqQYm4JeKw%SN ze?k0%FW*W_DI8}^5b&dij*sR}YPUNDc3|Jv2Qa-`bac(_x<0EN2to&wl=NTqa1+oC zEhE6?%c}zwgQr_B8~m_U3iPUL_;;nasYYT>oDwX%sepbcZ%M`ZR1 zQB#d_E^-xs@Kse~@7U&g?3bD77KjK(AIv8?JCa7N1DL(7l8EeVe#;>no@>@QjN=Fj z9h&hGad9%d;~t!&?(5Z%GYu}e*`Q$Df}vob*|55U#It!kqNnseBBuvk0Pkf%!X6|= zKV1m|V6kqBO(ZD6a6mkr%M|J1;`b$of zJc5z5yopxZtH)DL{Lgf(I7g-%=0j?oXIMW&M4>a{9$mOB{%}wo-f_uXm1sW zlMkH7pYe{`G+@mDufBlFq{9%7Y)`BnSCIP87D>I-1!iZ7#ZL}|T#Q9}r#n*Vvkufk z%j4U6&iIgu$f!TG<;GXX7U9~vNRHqR)le{nvPR`jIR&hL*Z;F)> zeJy~4GeVYZI?QHv9Te9)QA3TDnX$b-xQLPyPmQz8PJJ zpPkLSRk)fyUrS|Wyk|$NWp-G+fKji2H)|0fHS{OJSZF(l;DN%BNzOyG@6eTGWX#IQ zh^nftcF?3Lh74FxaHO@bPbHe^4v-*cmX{faEw1aJUshKi#M$22+ap+}FsYp|k(9ik z`&o2L8YcA~@hi|)mefvsPJ7hpDH_LXok1%T)eRW~vRW4|H(p73GLl$O5XNFIt@`kx zlB46Nodoirrl`oswo~hNl`sp%rY72{i{G?=$sd`b{N7Kis?sUV%tZwSg8Vk}SAS^| z=g?v)A?Gq$Ju19mOQEK;E}To%3)om-uDrN5;$p^N%utQ63mW}#?MA*Adf1PHzebZw z+TQ%8|K4;`&=YBF_Nbli-{e}vVTBm2)9QJ=s*^Rr(~nR_{N2xDOnb)N8gS7Ozh=PL9TN z7MF7T0(owhSUebbwx&Y|TH>m?`U6Qwnp{<#mi9uKYZb_({?yz3Rn?!&c@;qtDeFng zRi_{W&`jR}GUJ0UA;mF6m77>SP=<W+W$z`Yjjj zH?9slLxd7>TzqrOI(S8>tH%y1MeoI4T=XZ&G3oHq*xuSQo$svvSY24S*ZUL_I=8Fy z|3+xG^W3k>016OzR84715k)C^HSdzw!K~R0j;F7yu=^_V;^PH}ij9-1u&-cMyHI45 zv{Da)YWZUA=`rgjs)r|KXP@-&$Gxrh;w>LaN?y9{F0rgzMwXVijTai=H#IpXzkKP! zP-EJEb+GO3kEMR|MM#FzzTRJLd1Goy>@d~Huryv9rlGHJR5X()ByA@v-3Gf$BHmut^>EOWr&o??W=WWKfAyRHQlipxSym^1vam;o?u*se^4zyX^P1 zwMoCQ2LlTk1eUCF@0%@Y28M=4Jn($d(m&GjSV>Hb3icUhC*pNZ^K)}DxUXJO3sJB1 z_I0%`zfA33d3O6FEU!b=?#?-x?*_hqSG?EkdT_Hv$w14R6u0@rd|X%}nqCY1OtxY% zF?XzY{G?V-68YZJp|#uSN(hG@ws&?$KF`{cxKbZCL@xO+5lsv2`?WEs#-~p-i=n%< zJKP8Arr0^bhWpDQ7r4o9zV!2J-NYDIS^rTa?oV#M(EVQAj zUz?em-@0?>>l*sDr9qv~)fHZHnIQpk+mh;`p(|To1kpnlpf_wHoS4^yoxl4oy`Gvm zj0zQX7iMqa*T-yK^``C4P*Sf}woRNvUUDv8Jgm=5|HxD`7F6|SGi0z_X`4dAw=H_A z``@%OnH}Z@Z-^YX#BTf#3#jTMYw;B-mguSJX+wu$5JD`F5q(ZYS%;y5gdQK!aGTxhXGef z?@%gyhU#7V#6X$#cod`PB^(<>Jw*OxSVkN@Y*Ji>?<@(TFskLg4k~5QtI~LR&5yqe zr^EsSiH4IGiOy6VG9Zo4vmM-Y`v#<_bkGCA>Eg-C%e$_^j=BIf#)#)6YYimxzSYeL z_uoa>M^XeLudmD(e>5cV1NtVH)ySO+SfN8qs4aRC4V?s^RKCAia3K*~QZ(te$3So$ zUTWmgYY7=#oLVR~Xz&eaIyhSXc<%>o5a1_=khEu*IOSpp5`Qt6vK`-@JKa!-zoR5< z>JFO=vV3%UEu@BTet=(n#wV`6^tocA`EeXaNW{(IUx}34S$c1inTs2jqS%_+a1*rJ*i;fYYf6|Fvi>|LO&^uPwsk{PC4o_6jke|wsd@cE6GhTsPS}~FvyCj zW)l==7@K$qMu3`c(Y*G>2kZ~rRmIPBB`JV$O33vu!i31a zNs=tg>TiAc?xVH=vYq|w>%$KR+ljlB{C*Hse!EfBZS2>(*p`NwU2XGTa@%U1P`tJ_ z<>n{zqO{G+IylDyFjo`05jL_bMMu=Vd-uL&r3yZa(Em+Ff}xQBPb$a#N8>TnkRQ)$ zw(lU~D^R?UMD#Qo8zq8vua24`8Y`Bx{@Z_ctvWGvW#h-9tkqj?LTC&OSu>zt$OUs$JjBkH`H-Ibh=^5WTj1%>DsDZUh>x~i(9!^9jM z7?>jb?C^eg9|!=@u_~ zR#o=BwF*st(|xSqn_gXq#kX#onJxCAF7B*9GyNFvr!5fcW$YDrWlt&F?$8}d^$9}m zrDKfH4T5wb%@XMOj<}ZbK3sS1{8;2^IEQ1y1H;+5cW%h~4Fn6io(bz(B0nop5O&Po|n6luRar8rQbJ z*w}e%Kc`l0D6v|4W^z(Ym!H0O@}|^cM{Tu~{fOOX1|GUMc>K+>I4)ctbt#UxEl$K~yY=e?VdsR1%`&^$tOLxd)z|+*3Z; zex&FlWSYwSC*-J8cE@jkrn4A!n0w&fs)(u|H4j~26lvi1EwKd1?*b;#)Lr`Kyc|?R>~ngF=yh>n*(yX2H8u6pGv7KjY(gNQ zio+A-dx=HAh$t$NNA%oNK|_39v=BW+-HM32ckjmD_C2N)#Tm1~g)Rf~<6VIU81N{j zBa&(!YvO0WPvRVoH*%J52t7N*#G-H|9Nk?WHfgQbwDU4hD)KiWk*lfk+&PX_F!{D! z&>gLx_nue^ZF=+S=HbnFJhy|&hL3!D!>eAB^=R&;3XNLUjLu2nlI{c)?^8)? zisnn&zM);X(2w7%@wE8*;IBIfW84zikVdhZS)(Fh%iB+7SYiT_^u|6J3J`j(fZTaV zl~BGE0pbtrv%CGF5GS+xWV|f%Baaasc3R13kd9;FTo@2oOAp+-taW-k@7Tg~T9UAK zGJ4aYFQmbAb^kPdaK2h%e_Y$kEo-2DxID!!c4zmzX_ZzretB*Gs=BZVbCs=t7mkWtjzn`WQIX!TvcRBu+}^4Izh{kN?7`$I zCT*upAb^qTKzgkzrq7zi0ARM!HpP?t2apc+)t>CK#v-K#ZuR*$qynVnvAa+f+br!P295Dzzt(>ne?SGA1`S9LT!{dVEV@icwf zuME$4*uwN^BelzPs+hHhk&~{Ev4AC|$9YsfNZ%`c%+w9TTA**sbkpmtVdWRk#GS*0 z<6A$D-rO-US2T@$_iWP<&+z)gucN0RNmY?0^V0GkXErusm_>B2692g>oWdkgmHOdf#<9$K{aEp0{lvRrf*xMFui~ri z58JjuImtUi{^adQk{g{Ijr!*}s~TIhW5b`MT7@=z%o;lvkL{b3D-JUB2NI6Htqd-* zdOeFCJ8iMM;o9Knc+`Kgv7eAtGU<|$J1{={;)JVe*f8AMk0Z!*vw1o~U74W`OBy4+ zbRB$Rl}Fml0RAYgzWaTG113dza88fX zpL#&o zD+=rWBHm)scgQNK*2MguL8dS6*Wuh4(%Und&D8IG8NjL-wx%nQ;M^m3 z(+{Bg2@ls{=z00qYg-m=nwuPlKcA;iaK5~|PwiafsqJKYA@bqC_fK&|xT2g^E0Ugx z%u;*(2`{l>!SqFnW3R1zln@!TeAH?L`_Tuzp)6p%?LZS?p`U4}2aZ ziadzwQ*s`=Yt5ohxv#FS-Uov98LTxr%uVIASM=YHkJ_t`@|k&Qc-@W@{_!j$@vG6W zZ?qrDv6Z6W=ughr*YaPYFoj=uyCTJ&f^{ZqKBT(#gN@8%KEc@pw!(ISruXmr8>~F1 znuEPY2dU@t$Uh0ez|GgNc7kI$n0w?tn7HrV+WiwtN`unICaVkwdX{v<%Y$OVtprqK;j$e$tHuD^7H&9$sq~v!P9sA zj<+|TS6v}s>i)fG6c^mo>Wc)j!h9ctKX*X+=rSByc9M?h63SJWf^%&A@gKP1p=jaX zI|dT|`|FHq2>9rOz40z#&jo`)WB|B-2kZS6i}Y55)0s*V>^?uM6F!o>iEIPy?6;e! zv#x`&*#kYj#E_Ddwfth^zE*`?PFzw_a3vfvqQv{66%p_8=JAu%*70$L(NHdBU{y1K z-~o{1(GGr@P+UxkjFkICeS~iuzqPYt(wI`Z`mL)g6KoW^HzpfQM?Tv|ys`6zvPVW; zov0mtOnS+P3+{MdW|y+8Y{X|hk55n_(N$EGXliQWNR2Kl+cWol`ZS(UcspV_4~pC7 zW3@9gD%Y-Gr}7|7cGU)rO^3A+*B(6@VCQ|^gWC!v!#Z13(=UBss7lXFx>++m?YKTN zy89VhKpNDguTc&(_qjnaH?zH+iH}@qt)ax?ZHw^3hy9P4TBmWL4iV2p!`7`IN;^7I zLMAgXFaQ>NnX@huVMR}EZ7+cs+m-QGLCY#opFpY%JSw273=U%=Q5G(v3H**)W>*Et zO$XPupbuH*+qf~xhK#L-?BwZ8f&l#jwav;{0?layv_kU^ylfKb$~}+oLHk-?m*0Uo zp+!XScT2f(msJG@X-jCr>#PZUyeV$nLjqPkS!ro$q#{YBbJ!QfEZ{%(ML}geU0HX{hlhNt}8Lr;1|}$u6y@xJj>njxsG9kL&LztLl+C) zuUlSMm#pv+UV=Ptr%fnmMf$4!q7yhE#i> zDR7F`DIq;r4~ph}2|;nmu%p726&+WFoF>djUqQaZ;1&!qvBO{~mu75qfep;-pIUBW zfl}Z0_LZ089y2b==Hs@tc6M8h8gE)|4u#P|O)}lTH9Y*Aki!$q??WwGC|!@Yb`8gM z$$c`^1Re;Lm%Az}?rfQPI6>F;)wMA!DFEbm*d#m`lc%o>xQ5uZc|N^s0%$e)GW3h@ z5Zl=8BOIZ##-lNwqKb>Xkw`ZWhPUW6gaPi(3+`B=kR+Use0k*G+{lG@)fI|-mQjj|SDeGAGWEgkGGjJ#;rp~rS zYnS*fL~$Y;(~FKJm;Rz52at%#Un8L)n#>M|xsm$(nJ*IEaI6Z0aiK<@0%h;s64O2j zx*tAKi-i1B9`LF7bySVBZjKQGplKg_u}ayE)Z3Xk?_Q#Zv}}%MgTNxH&s*f=*Yx*H z1q!#h7-Oa%;ts7bFh+cDg@?}kF1F#4jXWt*&=D1(KPoqw$nHh;ca+)h)w1ynXqYSA ztFq;R9446#K4I1?q5JpFC*0s*<%wNAPX>`O{Pf#0dkoAqBP%h@R}c@+ZxIYTh~@@V zPn;TtE;Y0xeU$%4*SqliU$?x{59J|n$WOSG@|j4&0K(5S0q_Xk#>J6*@b+GU|Cbed z?fO~RmqBh+dF`IDE+Rxs=un|qfeHSxi5&R}IqC%&&=QHBYmX5J$Rtnx`@;6`@O7Yr zvYnX(#UnnzeY)pRMMYI$RJodhz6}Ge2V_9LO32IhtVl1laT~3_Pu1& z*}dZ-_x>`jN170M0Yv{!t$H3$u{5`_9S z;!|Pg?2Jx;)BWn)6>FdKo-^yqc{1+*s%eYXX`yj&*fZSfPD1%@!)n0XmBLGDgZL}z zT>6_@u%{U;59Fmn`%xu-c>vT8#D_3abEUmsm4W}>a!-R<)ySFzl{uL zgYQ>SI%&J}b5oX{+slbA-=pk?t=G+WN?jK*taoiDWH`}4SnTQDR|paij2nAorJ+&# z|7`R}R)y45Q2RKU&f6hYZ1W_GoaWZ6BO_nMtE#H1TZh|H!<7$LpKoMPm=~9oI4mkd zS)Lb4xxpx?s2yWuKdd?6k;u-my*tBVUqp(zkFNUgQ6_WvI9-rT#~D-gH5*tmW7SE{ z&Nj==&!^iAuc{K9-C;16YyeA&<;b*xQNOEXZ(zUc_1pFa`{S22A*tLrIPeH2InE{n zjtQdXj6mzf>VBaO>Egs~cD#J$hJWieLnhcA+u1v(J}T4jB_04g37q=^V`j)VTe|guO9GWAhj$moB^pk4{#fKkmeo1lSf3OIs$nnl$WqNxD zAh9{TINrd_)$sc4-1YFJB-R5L_odr4Ad&3b($O~;!)d(m(>N)e{YmrJXjdk`bTwq? z%*Z9Z{$8D^J{*2$He^6l)EfDV&Z>TI>$1#;yBIcZ3VZf9vY|+rCRk3bG@R zJf(&SIhbY0g^Cgl?}HN`{>oWN8+LLq@s2d#(_p+qrXZ)AoN*juPGdyh2+HM4S6}zZ z@5b6?`))YR$=|yRMVYaKPm68%W8K0d_DIuu``wJG3AJKjF{BIaM zhZ2GVE3g2hT~*^jA+twpUH7z9oCh=Hv|)?2wk0e(8p~RcS6Ju|^~tDx12Hke^#&H! z^f7Ysqm36Q&^WWTUQX3(lKWm_+~o=Axzq&{av3uc4MkA%(k@*|7JlZYe6&X;r;#?c z2CVG|GHuEEy7&x~b^6tTaUT|c6yYmZ`iF(lTCX2IX{D1l?OOxm;=tv!R3aH)-U?yi zmt{PYjv;T&%~`w4a|JiiNBpXqD2HV0wW0R~t>9=BZ%D~e>UvUJmG2vz7hS#uU=;*y zDdgtRCyBub{=hps_IDdsKD1#gn3=`?!gdln+4wQW1ugtuzyeDG93vAzLRouB8+ASn z%51X~UZ zK*i1x82g4F7$mc>v&gw692|YO*X_xB07C}ChQ`tLoyV^YcF@L-WX(f8Z)Ro&{AN^Y z|Mx*eGG?qVVPdNwne_@$W}C(vNfq)iDJdxceD0w*DEErtHui}5zxxsrDg}Fx82cPJ)Q^semt^ipRPF;;pCN5w z65sPSC>}9;IgE^ytdj<*RJpoww8^Y?KyBprL}G?vTU0dC=pEfkT28TlNkh)SUO z#D9jQbHsp6(nD2MfA?$7y6X))6`9ozkji#PH=}FmG6+V^961qK?R?IhUEn8>*~O8S zENgU;I4zOL2FX zWhS7h_l8)O9(Kv%epma;Y)dYp$RXezG@_NWzYVP!r8Z*1o{ust^dy z1?#zwU4cO$1ZowJ<^0wV$b62&mE*#55RD0Js4LEvTY02_5wOw2g|UESwO3!~b)$i% zo=eZjvtMmsXN#a*0Da)kO;e(9|B;nep`HQ~($Ydo&q6Vhq-l0#F5qJPfW*#71~n-T zj+rOTbtf71U*H-DF{UG$jeZ0@Xc#{b&A8)S#j|Fn=!6{{lg0SC5alCU_$zlt4(kZ? zM#VpWsL({IVxu!=$AZNG;x3Oi0qBYnBfJ>k@FA}>kf>si+yRyn%2C@EGP$UR^EftiKK7aiGxN)GV&`i*xlk?tg~7jz zfUE*Uxn@|`=n<%|2GU4eK2Uv24tPE^#@m*@q5yXmI^OA*3`_aw0SdqmBWTxX?~0?ewt(fxGw&XVk!L%CW2DQfbJ-35 z*Tf6#1;DhVfENpbS0C$06~ZZu6V)@g1d~?TLBhSVOYAS93wik;q0ky$SEXE|O{o_L zWkD=Oc&tpIRv33FA=Z}V?cT~T7@o1k3kvPJ-Uj^0OTxeaIeBU6_w$MFp-2{XgVQKD zz#XMe*GJUUm3Ef!nu_dGcL}44=M6n)@kKElWOx}O+t6L8ZVv=z!wG_sAr7xH@ME6u zH16@E@S;j#ye)A}5&edHS3zq-LqjO%uo~JQ$+@FT8`t{4#9U2p(0;BRSK(x2RfL#U ztnLz;*`JsTUZm-da<}Kuu#=_#31?vaLVv!-?@m$zYn0k%${y$wAmq*gWTs1ac6{r6 zzb|t5{9D_%rQEe2?4h2#bAz!#_>d61o_^7c#@3|zr0##zJShDT@a zVT*GuqTL1x-=CP-9Vx12MFlNi6$uSCSGNg+;`|M;m0dtaF0^pCS5;n~yn27q81(z3 zut#`(0S>g#{uA@?*IO?YC@)kP?~u*V5$q3`L39B^oVm<76HH%RvuX#}y>n(WyBrPRK=r0DTIR{;4`6-R^n-2TdR)ZGLsK6ZK>!#REly{G_5uzN)`OXJX z35<=roi?{Q-cGiDvRdeYc=AuD3OcNIm zPif4XJ7_4)v~^S3@_JO8vCQWmca%})9vJBuf8jVA=$Lck^fQ4kWx1zD)%~qjsVWv% z&I8%+Zz)i_f2ro!FH2?~jjy953tu5UE%5#weQ=jE$-W=A2NfCszm1^y0Jo?Y!B3qW zt!L_=9u6``G#lWs@tjX|ilw*8W@OAUy!J6V8r{|1H6R*2Wg>W$U*l~1o{a}|w+|^F zA5>*G<-Ey$HPPIr475%a@1(M9%lF7-P9tGYXPoF82Zpt;onLxz)-_(LF2QX~02}t? zY8G?Fu~;&gECe%PLJ*aK13(Aht=yq=4RaG;lF|XAG?&le<$}t z$o+I9=7gS`w>qfBn`#$f5WyCCP>UWA3LaR5hPc(bsA-6Ms1^Y}jh;b~r=T zjPQnI3v(><_W*xhe4Sf#9Gl~(C%n&oP5L38MoUAVasrtAvi{9E|L2cKe|C>{X3_-X zW2YOOrl?Xi7r+korRASEBA>zJPWAcVPrk?wIur^hHddF2M!p+ylF;&eY=n zIo8>d%YuNK14eXJHJRQpojZ350?x=gys;zA}!zdnPlmGK&6AN8NQ})7gFf zVYPaWX6ejxIZC2FbISAhcqjn}bq>Ri*dAfN!y|e80E31q0wbxw1WxmD(w>XhC@i^xfl z#c-+ITJ5PPsIxlgQ*l#zpF_d;U%%LVQIu%Lniahw9`crzdD}0Q*dn>#{?Lx;h%z<5J%29BRGZa;x#0? zOlfKl?kuX%&^23Pn)48zSI=`BYb?C3_ZVcW=x25o@ia>~;^Z6&KwW(Kt z!KE)FSm?|$VJ{*X3pVf?vUALzZqKcbJ^oSi3_bn*`yOpf?drn|%O8%}s$G`1dPYZ? zq1W>{z+ed5o}xiMiRJAJbnIbI4YjBvBEW%NwU-a!IW8=J6Tfmo4J=-fn^y=sd5;TQ zJD+H%s1)aFZa)t(I5=24GLQ-*kTx}qS@dJx!fW8M`0;e9^);WpQLN{?Bci=J)Ua>; z>IH=@iEU5h+wy_41*ps)p88f+rOQhzKcx1fC4=VTYVwYX(h{|S?`&~s&==oQn4iz$ zIulMWhgtb8RA2WA0b%sF$p$G|5sR!}{st9ECSE2dzxiM^o`eZmb~&nKnu)CZ4tPK_ zrn7EfpnT#YhcqdrrKJ3bDUIWvKFHl3xbv*y`^DLv9o2bGRL6WUJ!vug79p)CpUvOh zn28V- z-GN6F+b3C$q}w*fCg$dEx3(U{-LiY;qga++QK7aIKhNqL`Hm>c>aj*(G!d9~g-i4N zTJ&3-sLjvU<5HTT_kDPyfe62WBc8tAL7(9^zhUSmsr&o-XPC=e?782yF>`XvUk?nZ zk)%G`Y2flT73?9JJJiXybe{QY8|Sc%+n}XAymIjH?Wk}lYPCjBf4^l5Mm}qM&TN(n z?H+YG-9ZWVc`3+_ZG)NuZ~ou7^fK~XKv|)gyfcaT zR7Zm4=jh)cQlo_k*&nPq*P0uZ%3j*9q^V1HVBQ z8bn**U~Ip}SVYgQ0gG41ggsH}|9(f5lIgtI_jNjXlA@GX7m`?V8FZ7Y( zc|7YEA2(*oQE0|GuTQRDxg@yt_2yRP__6$2#WIWLXPe1a1kmJ6RtyzZs{_o1*UH2MJ<2y6i zvvpSKKO=MwWs+KSidjdix5ugE-A^k=qf+h1kE@PDd5=AL@vK7&TMUX=Ykz zlZ_it);+4Sb2X!E+_O>^JPB&HA`5<`SuEr;oBRIflInh7Nc8iT?u5$qf4^adB2-=7 z+tWh}D)~nJDKu2V12n3KcvgqFD#!ENVpAQNdmGEW0@0p}GWs8_e+`t?&_bAP@ZyxA z{=Y9aC5{-1Qu=H^%^3BEFMdO+$M>@meiGz~9M!bRonG}Qh$~okx{`Y{pv+rh;rGhY z(i>}!X%ai|vMGl-0eOUggIXx}e`gkDBU*~tGKqB6D~;6P{v|X#^FvOy201V6-`mxC zG-Dn?`c*YY>$Uo@B+?=K6hr7Q5qhD@{I5LdpR2_Af}#}Ckq6i2f=={#5f$Is=c)EY zxlh}{VFFCj#mW9{r~`bXIQ=DcP)}Gx3HBNkV{san|2w@f2>i`Vmnk<1z6jLS$x*y} zO7iQd&d}pT9vP=@N9aH+Ig}1}@QyR_j@UGGU)jF>e{wS9S~PqN>Z=mTpEy|L{#?V`Fefpd#achh$m@X7(NHIvc&?M>JzvT3YEjIS`TF zRMWg(T3VtN7S;o5SqD?mt@#cWO-)*2;>FU=N2-Vo(g8qWZi9bPxWIbVcCMWOKYvzyMWNR;%7nKBQ%(F>d#yDy=J_qf@C*M?-_Th!af6ow%^KXp2KQ zU$Y8VD~q|jN8a$}4PF8Tx|@gk!~SB!r$d6*f21RSHiMHB>-& zEFI9tGzS$&A@uaLw0A^vCyy1MJxk4#3PYt}&;9suC>~q6NeXj$W#vutJui0IBdpQU zlgApCmesbwyz|>OAqIJLzKgaKH579Kz7N$0W1k4NlA|jrSsis(D3~Sb9vKLC&YnEc zcrhyVySb3deFe*v`f7bpLP7$aFL%te=y2z;?SzPL|Ia6sf=@Im7yUlDh8WzCdGq!- zSPHUI3oqTS*%wW0c-CSV=dMlOqa+F_OO*;rtEmwK0Q?hdG+y(=2U)DuB@Y3K0jYdz zr@{=s$+NB2haVp|*|m0cJu{@ecc87Q8RId_s2@HuqEmjfR%zKyp`i-x4^m-|c8}i< z@8$NeJUW`zkM_u}$tgn1q|Yf?_d9!G`+TCdwb4PxYw5RicNBWfs4Ye-qGtjbqaMi1 z@749&Y#l+GlCoN9GwBiMV58jXeHVxuhGAvIoEeE_6j&NeCbh!HJ2x~d9Kx>=%wfBw zT+x!upj`a`R2S_iW^E?8sxM4#-5*0q`K$!qZO?V=K~8KnLVe-F0f*xf%{;qo*m`E7 z7BizdOPQ^`qBo_mrk);yROqiD1NVJ$HbQJj=!hY)9s0B^t6MCK$>=~12^DBT9?C%` z4;UV(DCrO|y_=`?g-vP0)ujxDL83WfhTN7fv(c>VEqaODL>U2yi0zMei#L5uYsJv> zp`Hnuxt@n@vFtlV6BbG{OnZS_gEJkRUAdo*3xRh)c`xTn5WjuK-B2>dHV9y~L#X9Jz5w$G$7N0&46h-Q_F^4N0 z{p4;R1{&~_E6J?-m3uC{S_Z?uSfY&MLd?Pb*7xF4avwkR!v_lu-Y&2wAF~Z!a;kn; zW!ArKHyarphwK*sZq6bpNk99sjmtNk&$<%6|MR3fSF>+5jcD+CzTWZk4nEm+TL4I%-tqNf=x}$()YA_7uvwEg6qS=b!G~RnC~&X{B2U4%P$Noq^hY1U7kow z$B-53E#+oG$ISiatKeYFIEOyX3-iK5LqnD*q6&8T3TRr+y1FmeuL*qJVxJa8pRGvx z^=>mGVHcbm-p;f;C5|Y{knNZpEw0?BD3)~COV$$`h{+Hh$}iaomV0zaMCt6{Fcc&F z^QUGfy5o?O+e3BZsznPT3U*oJF_Yh0xD7i~Vy33$t1G%@m?}9zLR^!1gbu%(3f=G< zQsgjYHtk3wqSfCW(~R0@lB6>QR)wd~*Xm0*?`8tuBy1H>Fst9}T`}eJ# zE>{MLGEiGbMo3wU2OS4g?d^+!zwgEuz5I$!$S*VFFu)*I-gd)21 zCc7hP?77v|1r&4BI{C%upA^#O?eve?R{IX$Rp%EcIR?K@$ZPQ#o~bBJ@cbsmdTj|) zVDOSbo`Oh6+BBO!=h*L-LIV5-2c|{Oy$U^(UY>2@28ZFDA0$lJIEMT+b8bx7Xm=Ho zAw$FKQ0vR($TiwH>eIA z=-v)t=+ZNE#Q+gL_8pGGlY@^zdxpCpZZyr67D)z)km7ibrxzTB9_kp5^ zP5|oC&qq#o6dwUt?J|972)~1rg+EAfMedwb1}~%oP=n~!`R<+$iE;BsSEH|)y4Thk zT6r(sS$uKzorkfBiGPOME=oyL(+nAxsoxMl`$gu$!4uGOet`@r*4o}&4zib%p5;YF z&&pPOkW%;Wzr~|yZV+JpxhQw@@No%n+;s{ zkwWIo;lo$~pjPSX#{R?)v!hL^S0!Fe;5765Jt0M-ktj}GT2Yb4#l3{=&|p1e1+ZPM zUs4eQzuY0++uhv&P6I9iu*F5mX6aI{9lOuRk5{!2C4`3$WrIVztV=p_;ZT1<0+DA| zsi@fS;I$d#L6h&7i4Wr6^QS+;SHE&9eIUeNuxhtou*mYS6Z zvusni_)l8?$Sq)i%C{oajvcz6lGC5<*DB>0<1fHLh}_`dOIS!#Sn&2~;C$6!oMVilhe3knKO!e(jZL-rFsm6Eaq`Qz#bN2C_+ zZ%}Psc@v+`wN9se`}P@TE;-9?NxKlb6sD?Z_BgYLTA9W<4jy?=2J%KJUIG@LNARDR zhmfHCm2ZNFH0$;oB2m{poDT=>=AL`uc7FZq3jKM=fsPld;vzBG<{76+U%= z;ld$UsfmY`AuX4#uuyq<+)<)1?X{$ za2X#TDJfE3UVfwY4Bk!jO#Vu)Q&!%=vC(`2(;?xd_B{1OCER0s`*WiLlS(!wria!Z z5hHiquUP2i=0E26?+ZL~tOA&gOU}wNL;+#|y2#0&{vH@$djH-b05;T1;4Oa1g;(k3 z(1J zl#~&Z&0%N5ZkxPOA5C~p;im17m}r!coGiJzw#FbLvRKmlcDEWrKO;ZCB($m@WO+%oMovdnTv}3F9Cmk#+feQ;2 zdTN}5ih6w`r3Cuh)_;Z0$6d;LYDxisHf~$xh@kpHWTC~MU^i# zTb6Hsf7siNs#6kIrUC~f`}3DRdm)rd)~n`Gl!;kcjn$d=GPvX>WHcjju6-RxM}*A>E_O;=y1fQJ#WrF!Lc%qi5Nd#H zu+Svf`YvBM&UYuzu(1?cro=bD*)Ashs@0}qP^NVgn7e-Q*(dzml1#EOOV5D z+za%(oM$zo-J$nOkqE`bW#*lKS>@?ddPc@XCXbdJ+)SZ4FHa$lNHDr}l$R z7b~brXm2B!6)z1EeiaPv(oaIc?!HcD0g7ZU+bK6f{1z82@Kp&-+c3cBI$Iq-rKB6K z43ex_u58!)>-9X+3-vA666HgVSom4W+ml?Xf&gT3w2{VNOiLp<(!w~9bSqR7R@29x(TC0j~M zw5X`4rL13@#soX4~c%?A`;oCbMZ5RG(7JxZvvv1te?+J z+*zio0Fiiye*q>8ZO zwhX8RfJ2}(ZCF5FI#j$#Ss5Sj`4 zv)BLPRJQ2Q69%V`s8eirn0dt)w@?n;!kxQyZ%=8tBScb;zmm@pMjGY=7H+ov6wInl z2RnC_YQhe-+F9r-&8L^{A0SDN9Ib-@`tayZeN0S19kttZs@;50a-o%B!)jAVy-w-& zRgNqB*($#}XnISw*#e@2ncD8II7#w;xY(Unzu7|*R5a~-9rb}XJ6fdRRZ)q9#op&8 ztn1^9aIi~gVj2XG>06GBhM>;p>$e5(pfHx$#pK295ySaI7vk;>q-}9QhlA`8uGB4L zX?R~5#~9$wv4G^I@fO+*;ZSnjJ(m%@zwNg)XyP+d>JTYBCb*)~|NFX*y>5oJHD-liJ$t?DA#P>19wms4KBiF_S=kn!a~q)?r$$Z7)a+tz^YVtZ zO;Ggd5B|{EePPApS()7vCi=gS{Qu#vXjg%L_lavc?v-y8y%oi(mG!Os-P>uxe7Bt? z(GUV^*Lxy6v71f#Wh;q$y|pNgbTXt}ngB!Ht*dN`;*N37%Z(|ox+k;CL$ga#wDyb! zr5&(O(zMuHotYcTORc;vCKT+yX%Z`*v&)%F%@fN?OG>IO`(kK#TpJvQ;u`Y6)#=ow z8Rmmw`ZO&q%-c^WhOZ<^0PRwrMa~~uOt0`cq(|6Ndv1z6D63}3!K|#1tm)cXM^`L$ zop0FE-9fuY)6LQBYtyZTf9g~*(?^S&hi_wA-?OM{S}aP1SZV)sRP{4l+tq6dX3x`k zuoqDH)@vkb>wA#uI>(@X*?Fxc&SafOWx%XR^XP;xaIb81`Jcs>nm{Y>&c=3)p7&`Sogv zICNf8E}-M@9t4KxUvdC0zgT;paU`c8zhw7#RwqN{M`9$pyjV@zB+Pj$MwGsIV__-7 za{S#fY=d7Jy{e9l!9KJ|5~BDTjgYwSUxG1=Ve5sFk*sSg-MGmCQj8xjZ0p=5guH%P}H|rSDt(OU~Xq#VI;8 zG5h1aQ+96l)g#zP`#pny_HZO+YBtFJaVq&48PO|LKpiKk@O! zsv_7~g%p!{9D4z7wD1X2nEI=b)o*EOy!pKB7vxjt+I}s85-G1QH8pjQ0YG7rLX_jp z?iKArqw#?jU~9bbLM$mV=xKM>LSt`3BTGm_70J%;;B=mbk(G2e&e5Z)w{*%;wn9w{ ze`4cTTb729M)ktjS)@Vjr?Pjg(WSU4ttBk;%^S@jgQA<3h0b$y{rZcn+w_5&EVl$1 zO=BFy@Zq#+cXV{;vBmy4|D-(9J`HP(l8^H$!BFxw^p<0g+%EGM9VTOS!V=VVxMj(Z z9H~yyXIHJJrrq|O)Db-#EIi7Ft&tX_cA_CjSDdTEgil70+upK#KuicrTe_>b>uR=+ zOmZP?WH>QCeRhA#6aCxVf-7TmZewkeokm4=Cpiq0H_wqhBC=oPkfp0M{dK9c*n1xR z5fd}gsO<)9Y9nlCYZj1}nkuIdefK66m5X!<^kjtHv5ed0H~G!b;kIp;#5I19w+3qY z(?fv8H@Z&Amdr)5<(s*v@1bVO{h6bm(c8ITRj_@MqWZGE>L#Omy)+FpdrL;szRA5C zz4oj6KTEc4mcH1P?aHsdU2^Lb*^l0Id0@NHN8cubC9pDTzOvi2IOry3vHhoRDrvJ+ zqwFP)8Qq+tzLpVia&5XkhGtJkTI$1+&PIhNO^AjFMgqG^Axa;!wI#W*7H+SB8#;x> z?C(ffIPaQnhX7^>>?ceQe!n(TKjF7Gsy?+dnOy!kV|2}BP1rW%r0|ML=fL$CNBw*) zza}Qb`d*9B(Q<|RyQ>QwGT02CIy9ZCQI7PKtRjZF=XPNdzd%9zedN2?h8!_n^U8N; zHkeMsCTAt>8iz`TkV#&~=fIEKPm&_Hsf@X%aqa6JCWZ>U5ke8Q)zzV4FK7Z4UB-2` z%W7KcX$qw|ZZELTRd0r$<4pDLY>wVX? zLD2?t9nR6Fjq?5L87?h0$F=8h7!UrEUgsr^Kr`2so45ymghq(bgZ4dH<=Ar3Msqvo zi8oW4mfa|H%T-P1u61QUblzxhaQJ1G@~uHti`ADsXQS8Z+{|tUxfX$u3zyn16@PYQR)R z(8tDGSg@2|7p2%r{E;oIJE1#8g>(w+>gjIy&9XP(tTTw4(iq)RdhRdoCbC{XvAUw@ z`q*_vXR|3{WUFW`*rD5WglXlcr7crbnSE^a;BgXRrkJhu5O%fJH;lavT{i>Y?mbr4 zO2+YB3yP|-+5X|YP^7-v%VULJqS#gxjouEEw39WJ%-5QaCzoE0cYQD?pwmy;HFwcvctaq2+r4dEDtwibsXOvVh z6frf>lkCk$sy+ZsJEI`e022nd>a6Su5jRxblvND2PrWHG%rAXjQht9!7#V^q-#mvK zcu$HXAffW_9a^@yk{X%CGxZAlkuuV`>xt?Mq(r>4QOosW*Oi|gua-0@nyLwh5_6h{ z-i@U{C762Y@K$Tj1AB6{Bd8O-v~#e!jh~sgzhhA2B1$;Cn(F}B`Qv|UFpIgDzvyLkWU?@r|@@0k4@mp#3ht&+Ptv&u8W zC&v1pwl#@5Zv}4PCMd>1NY}$KQy}W#bjbgUr3pGr%-3mvy7fB{PMfZ@{y>eH1 z3&;J@z8Q`$_MJ;_H3}vjal^(xqD6`$+lIEuvAZ-hmcjO&oSJ;ThK-RgV#(?t!t2aU~&E|UpN^(3P|pN#8;q7B8j4$2jdp16l6f^LLQ-SgsS zn{P-~Y4SwwrDA7iDJP9Y3)_Oz8`4O2*OHr4^D(Ps1c_N-ci+nDRI|#MWi=y$t%{+}rIB_)V5-2d$~~!R@RFlWu(-Q{Jn)s6h28=|`nrMo-}>~QmMtocR=_UFi^*}r#A zl`gsdkRKN=-gXdhTuA8Z>FIx^H}VAP*&* zcKWkI%`&&8VQz=t)$ZPn;kl@(M_n z*E~f7B=A9 zw{o=j=)AZMZP#ooI}{G54pEEePjkT=sn<@+m}n3Ho#SC)8AGoTnccIz>fgpY6S*6j z^}W5ku9*4n%|N+vq2$1O*x#h7b?V1#%%ffveHS;J3ipdlVvNFE zbvwX);5TS#?~VJE((1#^zc=g5)IIb$ClUNem6)#oPatOb_!hf9 z9$LpM;FC+&BxNjVL4I=dmc&6_!|T`laE_60DaHx-)a_R7>Y-mbFN0@AQ+U-vvhmWP znhKgjU*T-UXEoWUyc4?5Jsd}GtpxrC78JahzkKxk;nzXE}jrM4|mXmx0 zqk0>3e$8OgKsTsq+kfoljrzcE-)Tphne!xtrM%ksoFy zUgm@N`O`vA&CV`ARjYVpz3P(FM?{d)6YJmWRnyXrMWCg0+rRFl5XGhUoq?%n$umtO zzhfP180xC#{y?(W2LU8z+)Oc}Ec+U16?Ao(i8?N7`XFv9Ok`gw)2pM_Xv;APWE2^3 z5tXZ>e~|)=g99@?O>ku7q~lt1p-lu>UxZ%f6W7FxC@mcJ zu$U|}AceA`kQxpS@4>6jtS&%AH*}Htsw^B88v4f>r)@tb5n&a|iCDf2f;$JYM-|2= z-}u}A`1b9h{43)l-hOrwr#sPI#7RuRUuH#;I9rS5J8ilmkFR=oJQP}nCn_N1&r@Jh z?Wm|e6et`qmH;BBwJ1-=I%jZF-pD8!Uz3kM?HpNc`r?HI*+byrm$^UOb;#}SZPiGYKS5RwA)%#B{dB|h9&qFgR zxw&X5=Q#a^q~phh%XVurce!1*pKwq-1c^mLLBW&TDYGDc{IJO3=!$3Hc9kYnZEcg* zCVjN;_7!h_&A*&9V_AB7p2Z_dMC-*lIKC?GxC#`y%RcmUbX<2V>zrtn6iqEEs?~g8 z$~`#4>_JW*l{J{yaIu#nFqbB2;)1+ILSmuftrv7UoANqb3&5LqxE8lvPNK+JA5TY} z$f@O&S7?cxOQuPpaQ*({hrw?K(OpjA-nqS)n3##XUMY1Id%K?Iq7od7#CQfTh1Bo! z#nTVRcq2nnR6+duIrL{6o(m9BcvZA0NZae1>Sx~hCpFp;QzPjDIK_}K{*ysY z$hP(KuhMkA%mU{8!^}219qRrftTxkM^I|Mw{I&&!ia*8YMd1=69Oo^+HmJLq_Zpzq z5CVK$thLm3FHqa!M1;{V?dviv$f_K@5aNAWU60!`uJU*xLWpIEimj`}&V&Ev0dRDSj(i~$M}-j$*ahNs<9*PpYdxtw|vFN zNEWeiwC07qgH@#??kfzybllBVd6&lGm4DjwCFr>SJNmhElEFy~&s|lBxIfMo`7F@< z;P3p!R7q$@_(iZWt?*fdeh$#9WVA8aL+v`(mLYaapr-I&E~rA zVj2`m^N)4so(nin!*Rt#+JYs{`oFIUe~G``#hzq1+_@1#ccDPvef7Jbw44+a9UB5J z9;kxDpL+1C=B!;QR%$Ra9yQhX4$oN}K6K?E)YvY7Chg>*&pD&f^x^y#B?BAEe`6618}) zpszsrkVNeC2}yV;US7Ld;|}K{_;&GdIyM65aEMQe^T(G9Q!Y0hx(Klw_*!6M&vUI- zd}a3%!D0CF>kdpgU+Y!Y0F{tx4TfC4!GjN<*cSdI<$UKN*yvU+@yR!M9K=B9{qZkB zR)1aH!$5mV8g%uuLxAGfANa~CyRrWB=V5_JD=wCFbaH~7VxGmt#YG~YLNzvpd7x*e zgj-o0*5?!!mALp}q=uqm#`?N-#I|mUnysCkM&+!rsCjRHzrmn9%4)aWMQJk#>VX`= zplM4&JC@{XsjBApvvc7R7g^GIkJpKRN@-Iaw28=Dv$?kAhnSzOQraZaRa^EY+2?8= zwd7O*rrb`1+NDl>tCrJWn^M^sQ&q|DffWw%bQ5j1BU%%no@^fY7u`mIvaA<1r zn@pqERte-Mxw~vsxLEYVpz__D3$VKl@&-B+beybkqK9hy%wF zDH)m752K>L`R`)7UW5tR<;g|x)i6DMxV`7kIyx|L3+l3wU=e>71Zb2E8j`tYk2|Dq zva|aq%2G%_e7OCs@p40iwxh`plkAHV0?ME#lw9q3%!XU8@@oRsEj#qPSx48WrlbS{ zaA^2Q-UJ0vrza?(0DknSo7&Z@S0}TYrk%VHroHJQUSx!TO+cVOB&A|g-SmQc3g3yM zTH2^c!~%UI1jN_4xy(}Z4GN+Cqr7BLdkdOid>NRF{Sb;Gg)$(bGu7?W7oxpl`S#PF zb1f}wP_7|-1zSv4y^>sR?O=1<**YTt{SctUDzNkx82PQ=dd&xMCSGIiLdk#HNB&aB z`60TybF*wvO?-yi9}pm<3xKVcJ4qrq05jnbpb^QQIfnMEsVVe92!3;dZVfXc7S?7O zac@71jsVyk5)1;o5VBBF1LuSO-N!gYLxc2Rzk%{%jt+WHIMdJt;Onnu60PD^4I(hx zky^h7Rv-pY>cY3R^zb<4#a!O_^VTgd_-d7=C@3WL2lJ?sXlx57CkvK5(Zf!UpydL( zLfpL&H`DnQ0lQUDALlWYv!R9}&*p5rV%TNdpeyA?eh5cuNUgtVx)#P&%`^J-OV3=x2H?AZO2@#OedCOv(m`P*z3)y1gT@$J}#oAP%Ol9-&r zxZ=(Pd66+o-Fq|05L1+!lM~KhSPJktoJ>5`R0c2xm(2rdP;IS=Cs@c?TBgX~cro)E z^VA{gLK4;N8M4(VW@DSdtCSIDxT#6~es$aJ$RqdoR%NMFZQYWz~UphMxkA7i_dLSwe`>T#k-DzKO z--yYj!S{<$h$%)1nh&%p;$QtvtEi3g?QO&ibLAW1OG>gnZGzNSQqdqz(uiDr!*u>r zwMM&&$D2cioFncR@N4n)%icJ$OfUYm3x1!TY<3Rrnv?S$3ISpX5X-&41XFtssz1}F zpPQzSNV&NvD#AzXpk{C=2A;NrjO_Y|n17KYRn)N3Q)P~@D=7hyvwOHEy6&(;5|SfF z?O?$j>Q`E2JbgPqPuAsr_T)@B#{|`6I&H|K+sH#v`{;>(^gQ(B?Mrr@#qN_c`k&U* zSp5!VkEh?ggCzB{@hKJEuVVL=f86HHmoY5DhMJJl@K7079ahkA;?avwOy0*2yy%7b z;Kq4JFE1beV}`{N4y&HF72w4$ax&URyb=t@fii~=mUIyxp^vi!@~ zh<#OjT}|n9PwMmu5$&ty0p^AMb3>1=Gdz1AbQpTb0#35M=~!adb*$7-MMJ|WIVao= zjixdT(8z#1R7Sxt9Qs0hiZn+){L7tx6ni3J+-Y%U@`z3fVhT~5KzY64o zsS@Am1Go_XC+$U;#P|1DGKmjP82(fUX25z2;a|?(I|v8i*wZKB*^O;K3)@Q^K31#` z4=?`D->O(UDbm1T3Oa7+Zr;2}N=`m?@q2NxMot;1SEc3TUOo%CG%_@#yAOTEQqIni zYum8eGw|`%+9!b-->0>0XiyAVSdf!eP_Wfj1$_<(M`RTgf*BYJkj0RO&dtt#2Hgv= zK{jPBQ&T|!U%uQ(Nx4Z%MTIUYgVl?HgQKozt|+Ughc6`qnTeBeb}m89C*dnjWaIp$3=;Gs2PEL-DN-#Bnh^|_$Nw!)W7b~o+486r(KFn9+L36*o z{cvt!;Wihm@PckA^=M5^B7(B&#f$lcy>FHhZFA`~AR_>bgctQr&<@IqvJUB~Sz3DK zuEPR3CtP1^H)!xsMF*?k7nm`tn<13l7G_xH$vjVZ# zioNaj#Dz_BijlvTc$o~Y)ZEgWWiEro*@KpqniQ0A(p8<%mpXFcTdwCmlt8Nn7=6VYZ#1!xp#jz-;1=2jD7HTKE} z8EZq1iL$|X^|2Ysq$m#xogs#%V75Fef?j4p304*%deAB6GQaA@fGVIZ`d6}i#CW1| zjxAac8p+BoUYtBv6nMhQiT6UDX|Fb3Ata1Fk-bpSDCoMAFqd$l* zYWg-$rj;9a`(-}J;KMj8T!`>Yln-V84x@(waTcb+MTX$iKt&`(`Q*!az0^qP>e}GG zqn15=Qa#5w7WO6*^g{@K7%Fv&$%h`uzB5*1$?CA>?i}OK0)r;oiBRT1CO}t!bh8{W zg!n#W^dIH|r(J9!bYeC@`|#b`%qm+(!{*R=#=n>*uaM5fOpw_Ox(92204dH7R;};5 zoSR&7WI5#I(9;MM)53dw9WFD>{ER_EK$F=%BC~ZH>$El-lLGye;A%M-n$p18OM>RV z&7Y6g%yVv1NP=L;a69{C5)EI4L!2V>vHws^!S-HwJYzYYz^cYMx?ZKE#UHgW>Q*1E zY}DKiDthlJRFC-=*ow8!H5B#kEfW{UIUjb*i#YMpC&lX~TCy!ls7Y4TtjV|=D7 z1^Rzu{s^wd*a^BCZ?( zMSezf;o@y$BP~=Xi-?FJmkEI~L8D{9nm=2&g1<$G_D^qLTOp@McJ@@CjAxqax_L_H zQ;w_ZsEXL+#c3xl+tf&A5YM}(sfuXP00tU3)A^$ZuNSg6J@%`YD96KtN$JiC#AakNcV?gd`mE_g9aQS}{N z2&|7B8F5jDF}z4bo#I)o+M5{ZBcqV+Ou1x-R&sdEnMt7YQOvp^^=BBQfUb=1()O$W zcme2N-i_z*kch|w$rlJR(i54ItWy&wF7%rBQdG@1TPDxE+T`K#Ld1`fw7Dd2R9TO9 zDe_=vJx}U}W+?K2PGsOjj4v~cMi~wfuGpbhVI(T27s4b5{8UbPb*9y(rvF#Qkyegy zqkoHS=Rasdu<#$;FcbKfVDb7sd`N70^Xk6^s8^7-OIQqMPaO_2M~)H0hXU1!#{U)+ z>+xxNp?O>Ip#&O&;+>1ME7Rvg;tsZM;*kZNDg@%mJYkK44P|)b@CSs(5%)De9^zr( z+W+58{@*i`?(j6*E{$-UJn0Y+5<=h6(V-v#y`2)M2w^AiSxyl8yO06a9btktSq#j~ z0vSuQ9durPej$*6F|xC_I=Fz{Lcm;SvXrfDFbHFz7y?awzSP3(JVpv3poC7gF&P6H z^8-{QR7>z; zDRy!aTpQ4~Ivqa~{4T3#Yn$LYz&s%!fnigx0gRLT)zlwBH(36}g<%em7hcacYyrOr z)NaDhpVF|}xvIVRj$5gp>r9NBDUlA$!Q&dLoS9?rV*ntvT^;hT$hNKqD5t=7wme3+ z^apNJ$wHw8$oHJx*fV5j%`9p#Wra{n>C}la)>Z5Ix|@lAgwU(KW2o8Li)l!_mBc9# zLF2UV-+xA7;HnxZN2$uhGP^2*{i+9H*JL>(m!y#ADQ|ngOJq=elZ+K7= z)+vqxyJv%nHx5i{MT#S{Uvm=@x}s+T0*48jpw8jd|6uUUTJKoI%Zle$nxCh6u4>CA=U}Y$u${o z>HXTRQp>Joe8jKQDyw><#?Ja~~ffk+ua8Ud`gn=JHo*(O zB**1BUIQ4ATz%L!0hpc7WL}T%*UE&;Tb0ryS80}9>3;cA6`Q+hk+r8YTh5B4P>|dn z`vawu&}xmhrAOxDX<)~p#}R#iMNnQxt{UM{3@%56>6r1j{H8qG6Du`xks{>7H1+zi zZ+=kynC5lGen5oV50<$kH>5O!0g5&0Yo-xAxSFC1*Vg~N_FDT0=0eqNuN1P}ZQVX> zVAvZ#6Y3IzcQ*W=_O=%FBp)vhy_}zox*a-8R18QuV#?Nqu6^6u_H9qR&ppdU zkpTrE3CF~z6CX*Mpe;mM^3(@AA>wuCKYaZF28z(Mzg3Ak zPe>v&MlUC=$WDZo=Rtp*U};p7OC6{Dx7m|SG;djjGv=|aMxv=de&9H`7Is=wsUs?! z&sV)k?x(17lpn+jgyiSs^jZ1g$A%yx+hd_deOWLtUOSE7OWq#;Hh1>dX|F=l+v2e zG;av&8Q>hSyUoSL*K$&Y6u727!<3-cRU=iZ$?3zS22 z$mKkTH9lpNSL+2y}!+$)dz|HlB z3m0ooiV?m=5lTOuB*m4!I#DWyXE~tO0{lb6cnu-+heZi(N?BWfLVGeYG8T>81y8Y= zW>;>>+a3~3&#zx8*XX}D+} z3j!HANsf^dfpRlZMrn!!wy=j-W<|B-h&-_73mbF9bMz@->P`1SSnwwujC^ zAeRM#ZJ2)-c>n2R%0;{UYRT6_e_gH0L9gF??>8al=MLaHaOg(POy6^hrsoE8wCd+D zbb%QlkSNNz4Y;fmjvRq@ChzrYlPn(O6d?mHN*vsUW#{8@zSIPc9g-Ys1+F=HdEu8; z7TNH!n(R&;A`o1Vp&Vm}Z1CtZ*Toosf;S?UPaG9bvmry&=^8pn7*I4yBk*d7iPNQ; zQ#d2~j%A}Sqf2BHPFKx)SfrO?x?73)lW|s;DqaPWiKp4tEBzKD@M!rJBH^#zI}4}S zAxPKj2*Sd`qIK2$q7veyMc|5KV;`@pwR?k+;$mIEfKKmTh_?PJdDU&5gg}>5O`a#& zR+3a*)=%)OF)CUB8$5lsl-M)4adWUW|AO_RgtQ@xRz<|Dgf}@0W zHnQRuqzHxo$0?wLh;PitaVDHP4xcEU-ADuXWPGJ+qCDsAWYN!?Cv-GmoR;F z20n}=Q$G4{(0~CdFW%KEMiKv(sYgQRkClSl;bK2TApaW>qe(TQ%>OM@e+lkNEdpHR z|Aq@5;5D~WW;S_O{)LYCRS0GKnd&G1332}oNdC8Oa_ju;>_R|r5Aoc>d;mzO=Fn)& zV>X-rxu8$pjalGXw$NRs>_%(_9cCCtug$d>{`Tug{ zJAbhkG64z6Oag;+q{vp|o0tE-5$DrSp7ai0v3RBm)Hk?g4gLsqK#q~r9VdlOgb8@96>*qhl)0AHMmL zZFST1$1Ox}oo^U16FTO9OKhA@NkimrUc@f{-2wl!W%~A!k?STmz4COfG+&i2IjJ0& z^*7G@<^7szSg>WY;A!{mzHRQ`%4k-8jv!^gh!4O!!283C#mqsqjZu8@qCQs4M!s~? zFnN%$uwrNOgcrZ3&%=(t!P$9d_h0g4^H((za&xsvNyiy@83ne;AJf5|JwG9(nMwJ{ z=;#L6LOP}vBah0LFfudBJbX5~S$dKM3sN*YStXjkAH7e{Xg^zb9{c`+GO=^0;kK5j z?o|q*d2R=K_#AI%;0<;LY+Wb&-0qjYS1W%++Fl*8anmaM_qHm_`>eLf7jmy9D`gykb$mo(v`{x~WjXoXq05TRw;HA5l^y{V(0ef4_E@Dc#|%Sk8vV>094%7O5br zF&lXI?81kOM@cFCfBzmUj9Mrk>rXce`s<6L%)`yj-g!YMNG;rB;#0z^2aUVzN&X%y zd$Q9EgE{whg_r%RBl4NP(w(4t23Pcef4^YVeq+>f^qtvjNq2WIe)*h}dnZ*8IrsrO zD(?EXibPE6>OYS;~3oSb}`fNx{i%jwiXE~Qaj>p-QnTkxWSMwUyNCY^R=9uJj2L4%m>+*r#{4MV-Y1k6BBF9R8s{mjhEzT-M=5t zz>KmyFZ3z5I7b5dRv!qHkzww<9JMt!M;pF(GS^(`u!ZUnC~j`^ds;yzr}|+%k~5sF zQ);to843?f9yOb86(}i}hgr^6R^GxC)iv)Gh$utt33t-7hu58zlt*>>!Q74B#2{GW zh&xD<3NC{r$ur;x4tXQ@6pD2In0vK`?ZYgpwNtgRf=OpSnI01*u<-U}%q>rMnXRA} zmo33-aREx+Pm&9pyn7|-_^UMJR3i&i%8WA6XXmZJjWc+BoD^TZfqwpzxeFC%|FZZ= z0?1s&BydWDDYQ*^r8+yytY0_m&d*FYqqBzC<4qu33}MsI4rWPLV*=QGT<6s)4m$lG zpfmxdLCxz9zOf(GTh4&DM1tx~gfr#VvrM<%qqFgTA~$7sr_>1 zuqrnXPpgw~pW?zu>8R@$GiZk1us>~!oe9o&#H@k6gB)d*Ci5j;><-w=8q|E80{e z1Q15ZK73dd)o{D-Bavo`?5I8&~SUVqo|Ju_oiI!gAnl22Lck)>`k*LeX`8{uw2Y%QXT>i+*=^qlG<8u35RT z_cDa%X(3{xnr zi*SltZN!Gx@qO#SQz&{A0|6B?%3eRS7pg~;o=K_Pf3I-wGJpL_h)AFQbp;6|L&2CD z?}<$j8cAK7ZO#1orae2|gcpdQs={&JG^iWKd78^+YgLDP{ zUbL5QadNI)+7e#gwFq|xW3y~jm85(rA7Rk-^I#9e4)#D*FW&aMRecxezg&lZ9}S<4 zw$L6QT}$dF4t`C!I1k#D|GFr#EO|HLon-uatR3+NR!U?1N;$kU;X2XpR_8*Nb(H!f zv^k!{ulhxT?qSF(E#3oH1n`N4Kj`}FUne2HY98@Ou6ut3w^U%vq{96G&zwlz&%F9~ zaQ*}QO$3e63-KfFu_vW8iO^L)V%dJ}Q4XN12Hpn))@px2((_NZ$TdRfOTJW4cx-fK zy5Q&y@Fh)!U}^hqh4t5-P_%}h%_bWRhV5bt`PR3TrJk=Me~;1s06M$|QhXN;D8Ha&$nOzJ&-j4vCMEqj^>qD->2iR$egl= z=x@+;4fH%#uVp~c!l?_xM9(yF?m7c}`JPY3_je`m<F)F*N+k`yS-w3gD)SuIRujo* zla=bQAucU1EwagoSNjsc6<+(Ql)!&=AAj zhwouf`wus0?%rkSq9@t8mtHpCcs*oH0^S5)coY8IQEKcv4R3;vP_C~c49Z0Iu$t*V z=SdVxU>dPq9H2Li8Ki}hf>8rxRP{8}TiGs)6{0(u+BWFMZ0#B7g~a=tR{F3cZeMu5 zkC~8T8@mp7jfZ-F>vG%?XYn_7?=A;e(z&hK(fs5Hv@iZl+D3og8HSLKQhSIMM{+H| zZRZb;;rexvt@K;i3OIx$?N~ZNu`N?xjgz4!5Q<%v_xt3v|9y%X5_&eL7Kz*k{Z57BDJYBJ)up z*jL6fDeUN`-BOA8S;AM67}t@D0&sS^Gl&8f4zz6cYM zKr5BRIcg@2NQ3+E8WAzLNS= zJr3u@#H2{vs)L)U(uz^J%q_v4x4h`da$gotvYjGYZ%`H+!A^(H+u}V@S7N(fVL>p@oNK4GYZWTT3*) z-sh;>yu4*ky3YF7O-;lscvHFUpxqjOWRy=Ud0*?s?V|}qgF^U_`8-QGuQ^6nOt95# z`_3I%d1k}xo4bRGxY3ZnK*kWZ$lm=ju!Fi;-xLI9kd4J7D~8YtC9`jO-0jR4GW*4J z4!71X*|f_>Qv263a7)u@r>T4rk%{UJmnFwi&1_xiM@{Le-+@LOxSlNAn3#}yPf!qN zIBSrQ9B!po)*LOOzBm6=Rq9j!Osh+dops|(`G(A0=OrO+=3cGbg`t|Q!MBj%lGH!> zN52+Jf4&v!NlqILKFCGcJ8W7dkM{PG%KgK5l65YY$7Kz$2gZb0br|@8siV&R^wIv} z{jXXZ*lv=B9S1A+?XrqX-vFv%y)!5m62)VjT6DCaMLB~ea+6CHtfF5@GzWr$PDgok zXWt@7RCFb^P(%OYwIN(wb*LW->pCmfUlXz)beoTNQ#C3m=z4KWo%Y1|_;w8CLI`ur zGd7wsZ1&sI+p|_NxOK^?wS1THlHOLf8TZlse9g`8s_b-;n;z#Kb?-8b_+ArY+}{&* z(sTWV;WnBK|L zE|hM11ZVNHJ(_)<|LCj17w)qLHe7>#N;lfGV&C8EFJ916>2o4Gh9HpY`{L?&_LVaQ zu63h7e{~%@JTo<~-PYzczt>5ng-g*;!~2gOU5&8MR!~XbrWCY8QA!R+ zULosK!d$hioI1MkF6^#C%V@k4^VW;6Z0bfCo*(#m*ELDpu&X*-jtfuhFO$pWyyzIn zmNl(!G7Nf8Equ<3BGrGx>#1x66DK(ly7$V#%x) z`fg5|5F@r6rIH~>NoGFFaimt@9OU9kkRHQ%oY*tCy6D)-( zvG+aw?!9HASY_w#$ zKEhz+a`!J=+Jmd=otMj}<)Ze4=%u4&iabcL$BJy{Xrl&E*T?1G)LOUoXvJn)V^oG6 z3D(UB)wA`-=U$!~SRW0kl4Zsv=NT)JjeJWj;e8W)><=H2j$hO%DW!PXFuE%_X3q#^ zC^)J=nDeFi3Ph$9>Y{D?>}DB6>&lrh-|wUOS)^tjlt@3aAG%*1Q5W(0?EgQA=Z`Hu z_!Z-ofAnqH`+h5mtdOppm*dN}vIsV%EJ6C(#rvMNX^5`Px96q|6iZw>ihqpPZb_wf zo32wwin>WR8uj*&f96M8xLUlkFScB}G^AgCxB1?WVEONfpS0G8+?J16j20cge!YL3 zHHHV;G!hjokJu?#iVBV$eVu_= zERk>)nCT}gCeIj*E+wd_tYIlkKZaeaj62y$OE$>U!s@w+Sow`SdNp30e|6BE^JTr% zqNI0A9kKb_t`wzJt3=VXcUN5R{3=8BXU}NL=cTGY-xqb0%|4bp|M=G1w9YqLSma5R{*2u>)c6&;fcLYsSa(crrUSB)Gg&Nf%nWZD_n33Q{lNee)Eg*T; zLO@)b#NJeyBEPpdd zUl+!;d&-*m6eKT{6+mO>pSpXRzkf_FU!iCaS!Fcvh9kSolL_{2V_w4X+_xO+phzZjd{qHI@UL}`@I;LWb4?;(5$>)1kjjkssiotB}O=R&*-7W*FO=PRI z#YmfCkt3|M+VSu2Cy-%jF`d&lkualrED~Ndo}+e$n0ev z6%(m7d+#xl$-WgWVKx0ZqFXTwW^exTVe|N{E)_FfrMTxB$ol%Dn1D}e`%Rji*Hhc@iYsa{VI zzPBJW#^@jD`u?~%Y=DOIX4F@1KZt-dpK0)qBfG|i=1Gjr4Khx<5l}Xcf<%Ex@3hXfVX`-(| zc$3Ya?bc`5*>p4m@AB{ystMy{FfotqS!Gx$D@!VmGBYvaF6B_$Ykutf(KNc9KTRfl z>w`%lnR{c@49D2fY*@BQ75X9e@mrRX=rTV`wK+IS7Q$?L;>iD81tL)CQJi^;WHnW!Bg_;pucp~=HQ$03zj8@q2Hw7)n( zR`f>2-n8ZLj|W0x#eC1%ulCpg;Q*WhwvNQ~EV~U0g!{q6i`zOzu>c))8lru=`U4@P z_m?D_ZZcRys_X{ng=Zj%iOaG0z4~!mqLUu}!KWem>jWlEq8cJ3SXfwv_YRt8Vw?D9 zsGwB3{EtPCL0wax;_Ba9GQ7~(4x5KcZ05gL_{q8D?R z48ZVSLw@BY9PUhP*#&s@4-eVg;xc@>@~mPU?d!Yq{NpNFk6c$XtT{|C=6dZc-QCvw z0ufQG?S|Qg+x_ugqHmzB&oD!yMaqg1P)@P?I{kf!Pt(gU8|Dz9vnd588mGtJm4Ecw zJQFq&Hl4{q2VTBx`kLi|HA2ia!%I>cQzx)@x45LF!?%?Yr5KK23;yF^(#QPAbZZJ&DDTr7y7|tIHD3pvShF z$YPuEJJTzs#F16+8*+V~?!n2GQBE}58wKj*YsdXI_0!g?^_{?{=(+gM`%iCvty1^8 zDNXb^uQv3*^|&zX;Hv**eSAD7O2Ylniut;IaRh{%n&#SNKhUdp*HONBm&YYb#?|rG z^49foq0)=5RJ-6snt)d#T~$T+Z^wj4`2o#xI)&8+8Q~8TZ>qMwFmRxp-|ri-UY$YA z3zeYbPgsfj%dF9(Kx2$Hvv2#B)UtYyA;r22Sm!ms_VPNe%!d}YbZ&ll9+DmYGI z_2MO+S2U*|r9=50Uy5R!SQ2b_6AFGO@^#aEhrHyYCwyQk*2bdCrFz1zte%bSCw_J4 zgMK_)o<9HUIO}0$u%azM+Y$e`vcWC-HTI_e=&D+$J4ofkW-a&;Iuk@pyTqyw9uh{P z!uSa(qG1nroo`_Ku1F^(+HGOUGny$J0-Qw@t@;wgG7nMpez77q4fF=MA;73hf^Pzs zJOb5YoL{KkRu*?{!kYzFDIfO=vB{GU4F$Jv3*Ucj zp$TqqXohi(8Br(!+z};5!x0QQV?RoQ7DahV+&YI-G zsYM}`+E~)AOoE;t&1+|5kA>(}axtk3#Mb4*S-D*%7;4Gf8! zpxQblvIV9S!eh)?x-K5i3AJWwd9!3WpR0ym=%=1vTacq7w}*H)sctPD zUj>&5AXPkcqne7MbJuh1mg`0P0w!4IYW*8+%}>#r>Pn+6GS{nzkxwksTgQI#G0G;| z^<w%PQ1&Ja=x>*_~n2+Hnstzg?xyyhwYM-@Dl6 zi1Fs5E@AI)*xkNNp7)-Y%0p)w(F)%qjpa^4qQf4P{O+3HmFnR!CbINo%olN$)X*&* z2T);u;H73Yjbc8&KH)?%y~BdG#M<#1l`E$gL%);vzRli0wJa$&TcOk(`HW;persEe z{0g|Ustfh<#Gp}uoGU1<`!rlt$WdMaoM#g63;Ech#t`q=*`|}HqSOvD$pCdtw^mv_ zC@=`JX0kw#xNG;_H}6fjbp=69?3Z_f{0$reB}xMw@?<%Xd7wARP5o=$ESa6PU~>qu zf>;j$%RQCtg&aQm^xJkWb34i8iy8*IVE8z%B9*-A`yi4EI+}uGN`E$O4WqD|)rfB& zxPLnLMzE*t1Y9@*pQZCg+@FCXyB_A^7$3tYG- zXrD2#$^y7GE4|KCO4Mi@g!p|o2 z)ym@bdRWeCI;e`XZ{4c|zp0b9ScGPtJfDm+^!LVEy(hD3gmv+unE{O(+4f9xFYy3W zWw;H#O@z%wIQkB#A+_px7zu5-`s3M&Oov;pmW9Tg%rgZdq8|zFGWpp_`o31(eO1VP zA7Rq^IwKS=kJc<_7JDG`&BqN6>1@(hi=8qcl1y9%<#g?_@I_6e!9{3#&wWbB)oOD) zkK^Ds-g3+lqLW~Ubbc^KCi{Z@96kSJ&{fSt+^4j>hR;j3*!@wXi_tCKHey4OL~jZI z)L9Q-tYpqXh<5=W_RYr(UX9KN+*IX|)YG+DV$wK=q>;m|tuhwRBX}WcHw&;i`65e^;o=~9@9bdUI zm%j)ZOwM0#>r9n7)(@-u0XI|cXqb&)xmFv-GAznxIPw~q> z544_;avs`(5ca*1+XdRvBRupgR~)&Li*2l(){SjB$h^x_>PY$gUGeXCg?bWH-fBT= zREL!=OIT~56WVx(*deRa{-2}o`vRP9d{S!yS^B}o@rVSm8^+`u4qJUFO%4cRtM^UX znZ<3pkPKHblPRM9DX_i#*Wun$NK=Q#);)(87P;7Gff4t;6Z`$M6%O4xcAJ4r!tT4R z=y|SyFF|Lgj`v+}`;Ny{X-~^^x>b&CYIIb<4-q^Og(GN+lZ7gX9Jv@!huP&d*T=~@ zId&6`{g8^+>Vuu{BQ5NR?z=Y1rL%*BmRAh@U>OWupA@gJ#jsCRqLrbquEx9Z0xg)- zK2k4%ad{Z={{sp5CQ*LIgWWQj%7rHT`nF@)zDo6mc{w*^)+Cq4OBrauPlW+})N8pq z8UB5O!16+)OocKE4bdzXwO>6>`>TgZeA~wzXeFpyAeCK;PA9AZm4Hm2;D&UPL}GMcdSfiT#<^J4epE!zIFT$*fe(Zp6~%&JkYqbVd+0E1!7 zQZXdjy^~+EExRklIdz)NKgO#5t{|%_=!dheH0S=l3}#Ij4-L=dfqrj)-Awm-2>I;k zAMzggM1S-u?pGsmDVg&P{Vl`9HG&XH+3HTtFXyf?Y=*P|fMWDm<-K;5xA9xLS^mj7 ztz3JkardYDaD&^gV6N_MCA~6DyLf&W!XFgu$qHb3rsRyvAO$pxBR)_svNn<}lxWxEs8HQ#sZyTXWuA>k(oYBURqR^dK3=W12t-9VQaRRs0Xsv@(S>iy;ecu2kdI zLqdW>j6Th*V10K%2bBIE49^^eAF6mjhbB0O*gN7jEUgo1FSnPF+g@Kc(QHMy#v_or zRvSm_eF?-zfB*IRL)_!emVx2qY}h?Xe<_YtSla9@Y*JZ5nU-dpUYjevTB%ZE=KRq? zt!b}CUjkDI4U+(`5rxmHEH>XZ@UksRr%-%X>UxchO(M`rbvX(|7fuJMrRFcJ)@-6Hl}HLaik8TDyqKCFEKe zUX*OmBD==+CWWE~4rjPdyq~x3gcKb=Y$xy8FPGPO&SR7f1DV7pzvT|FaMCFaucPxE zbWSH;&S5qatbIqi^Qmq5HDbA`oX))SE@gMgV$EeB5o!d%aSHGXpZ!x>#!;KV!JtS1OrlL4*bp7_Her9ZgCBDUsB zQBk5K9&y&7NgcMW8Q$5-YL4CZ@mpS(M{EIOgAsB8PbB4i`oz&JeGlmHQe}W={mQ~J zfoQwm@+p+UK6J28y#1|NA5!vLOQGm4+D2)cFkUkHyAqw8Fyn&>z)s0=BwU(8QmiCo zd)f+rDhG(bf9Yq^{yIdp%S`xq5UmokFrGaJNflIPs(H$vF!qnR(iTIrWJ`Ci_E zo2n`xlre`GFaGhRctS}M8H&M2yxPgdHKE@p(@pd_Uw1%8qM^=S(M3#X>W(ZQRB-MarGyscRPbmHR3$s%ofRSPAl1ywF zsS_lK;T|Qy{gwwq#YOlz$c2jGX?Q(&>&{hIYZ-xy!aFctcMxwG0*;YT9?z7=Z?T`- zM-7*0E)Wc0Jv zu_oFt-(a06@;`67=R9^fatNfNGoil#2dEPDHBn&^*lKUkY0xChpy2MCNgj~?!A_ZGpWV`m+Wu?oL2$>`#^%Yls z=1++UkkwqntcPNWeGq^?i4-}!y%Q?Z!;lS<7?-!1o5Wi~nZ431ordY0%~0>eW5#UJ zOh9_?cR1ETu0lN>~ZOmgw?xzK>^@FTSckXc}$+;*S6Hh2mQ z*ZeZCX9gL5kV1P@OOutNiR@ILGyJUCH)D(ykv+`>V! z%l2&-A^;KjrF&r12ns#LPok0kPKgEi-7jRgcD2sfVQ_l@YP7|bmIO4S+ueiMs9A3W z{NwIqerbq8DVtZ;X0h$%a&#&Y-GcUqEI7U^|?zOA`8x5^-=p3l7lP8uhES9}Dbk z(*gQ))KTCnY6{z|Z$sM}Lqhz3S-CSwYV~jmW=j!)qrIB1&vB@(3uXLR4`^(Wu_$zbmi+$wI>xA^8CD)FYi$@_4DFH3ggv>1{8 zd1r&*Ys~2er>z25-eW+<2!@zJ-g8WsKN>qr*`De=IX{^s3I+W|#6jytc2{#~<}{1H zvkRy-_aaY!*Lv@x8B0}{LkwFhy*ukH7cmDCBiztaM8H|U0*V|HWqPP%xCT?-6Z4$< z-u=om4km6m_t^7lo@{Cm*OYLkWY2#2stn^Jtd-DI{womxP;(0Qz*hx5BsP{MVxBX4r|c0;1-@+$w~Ls z(Fl!@V%f7z;ehA!;m7$6VR|D2o|>?Rx;<`@-jUX~Oo#h2@>n*uKLbK}{37alk?KR{ z=2_l%;(?M8^uim6->wl*tM&63YV$hgquB*&KR9pxmOY|dyz3m8ddo=~>!jOc#Y$bn z!7Eq%`e{RR`By0)YOZT-E>Ldou=B|^n+TTT&=E~lXUPWN5R^!!{MCib%RIV4&Z>T1 z(P}!iHGWj~z1t@CJ+~>4!pM(Fz_E?BLR<(m_wl1p4vZMDQf#>5(GdAH`o&N>^pF_X}uH>ygY7igUAwlb^LBut1Wdmp4&O z^RX44+h)G^j7t_=)l1;{)+x*4CYJIwM8Jq6zp-AMp;)YS%XSZ&D#hNFCi zO%rJ<;6I7b4r-)ruVeSz7@;2wShky7X%(2ZoS;Y8fZ(1Xelg2JQ=(tS?ZQ6uzYQw%b+ltjM0DbJHWU^zhALbvXyw^cUVp6XrEY*FNd3RFb zI3vUz*qf1V2?e9|y;Au68gS3=ye|HD|Hkf#A`8}@YqVc0=-4Lz5+*{mWVKRtzP?#D zzaV?+R&PMnjInHsE*y2kuaLn@jce*em9p7KRUwe&nZkXD9CF9lEZR&NtC790JMK08 z{h;o0{`;&T`i5IhyI#R)a#m2Xws@o3`ASMU#BwQnhEuqxfyJ)C{kISRn!fL%S{`E~17r_mPKXkYxh#Md$Hjy7lR} zBggF)pWQ=`bq0-U45btXZt0|e0R)RShxQh zk?kdC!9H?!C^64!SN-DZ`c93?*i>kP3Db1-L;kH}Qv}iYJfX2tjW<2rBReH)QmI-M z^LHjyY;S4jw1P0ev#NO;Uc%&<5H;4UsFds)G~Bx^L{Zhq&hOZZyKpUen}> z75AxIK|az{Umpw0oNN?}BOf1`%$5%Y8N83$l*}d`RqLBBsTqdIH0`~9`o`wvyJjXb z>#B16@O7`$`{Q}dO5yj-cysq1@oK!{-Q188CG=ISLnct8JFM&M@3_T!`mw?0(-$#j zqo4O}H)mH2N^8T#=%}uL^ZCLc+fE>}49nU+)Nu$T$b01H^X7^QU%ny*Pn2dA54`YU zG4kL-kA*({5XLLk3{Q~=^aEjmKs&K0yOPiOBBa6cR;kacr;*%9v|r@>my7k$M-0F~ zcN@Y&o&GL+X%5&&W2^!^@t5(qUM`lSM z(Q8DcI+C*QZbWk;q`rrPS2=Oy1d0@plWA4m>$w^NUJ-$8>n8D_2NayA?7E=!tjkoq zpE9kx+&}d|9$b%|NJ_Qz;pGo^ky#&4{JA-nTty+NJoP9EVgD^{aE*kCwcRv80qPt0 zILkld|DaRI@YlKcq91V}LoDdl7~tx0%#MOWP|;&L|9S3rv)S_eP`le9x7k{g zmzggD0>9f?K!`^c81!%D`=MDeYqFf4)J>QCu%OLd<9@!q^Pn1i? zx87F|(S}>)$tJ?dFAj~aG$Mck8HT~o517d6P8VnJwM2PTm1*Hm!4KvYeh~}u2%H5`4NZxa6lNrbbKjgj18ygJU5XA}-k?PGDE;x7 z4A@J(o{&aDk)_T?BX9BHhDl^L=$fGJ_k#9C@e*$iCP+yxg?!1gl%83-D_ah>7lvrD zN%GYoan_vo4IZ+#S76zi`F>u%PKg+buEotp+X+}H8GTL5(pOPbHq%tTpcSpuGj+d+ex zMCL>zrsClajiO*f()}|rD5uX7NtzRysmBp1pS^xDXJX#6skL6`>ocbiAQMeWuS)jc zOtdd566Vb&oGXe<_X=k8Df!4xk<$%twV}9g=R2Q#=2ZKZ#((++w1=eBJRzh-I`9A1 zNCn4m@ppo>R`Vg{jX+1~E+F)DfWlwU58I6uFOx!u6HTCO6DuvsYk1*7S2LyN!c_zh z`YPbpC&6&7LQg38%++-c+Yz1+6Pui#d$dMobs;<Cro-#6s_DZ#m+UqH;`IEy-Gn zIlrl`n#<*RCLhBaY#qQ)IsAv#h;!RV z#nVOkr_|tgw84kCl3>}|Q=FQ?T$b?OVO8AyxBA1w%?_gv8X?}5x4b=h$x_Rv#U%OJ zcDX6(AEe@Dna#eE1UZt5k>_>vjhjz*a?S}|DAS|I0$kf}#Y5PNl>y35s) zSMocbcY%80+MPSn)!bhIPBm66=B9+JBg=il{=uUeI_Loo^Ixl8aSNY@ zW6g42w~Lsr8T7!!P5u*`JOjZx*?cE2@`Ca|l|>W?lUNj|@}$JAZ-E_HH0;{q#DMmr z&dj#PN|DV*_OzUtQ^M>&hCz*Y1$M5eKraV&%mn?tNDu-3EZ@Vu_ugambT^!f5n zq=*>gER!E*g93bOzLM~zz2mx>NjdJl?~c2Wp^Wx0Y3&6apI@IFO=$~Di(=e?&~fbK+pHixMDvRv7$zmtM}ZF^3hbx1 z_9U&+=UFDx0G_Z?)4Bg*h+;{}l*{8Qi&irkpiCKA8oI$H8qCNSmgN-X^*(Q#kE!_ONay&w%(QEpRV7(yk70a(TT&c2;B2im)RT>rE3S&e2|vb&^!2= zkk`9MuXsp;IW+FkX((8U4%}4jM=~cyA*j2%yEmd4hAP;2MSlHi=;nc~?Ov_FGK@@* zW={|4`t+g&v}SYd;fSVej9)DM;awr#%(1Wbt^G7TD_dlva}rCHB0A+SqLg2;=e~E7 zO@pgewYm*Qr~4eaii3%fx~V)-Glx~y2vkHj!EPqTZqTprZQG%)XWbe(9RK1wh%Q2? zr(^5RLy9YoM;P)Nie~wzAeW^B`e9s)$)EU6yT^WV6o_x-QrsLiB8-S8Y4e2Q2rEd_ z^ngIUQVr^C@%pfXgJr4JBp?WmcNltL0`Wgm)qQV+Tzw*qOr40Eys z(hm3BH&S|>=@AAdj|mQ|*&7Rm9iVzE1?HFCuPx@7c0-=z{htwF7zXWZdbMID#M7~tF_S@fGFT=Gf<4urd@|CP1Y{nF%yPr8tHKS8_R6A_7wr~dk3UiYaFAP zZf*W=SFaH6S8rSULD4Lqs$z+e*!|rf!E;&a6Mw8WQ;tSE-l_P==8(ctE!7%H#Qjt6 z`Vk*I>Eh41=Z0yE89HhluR`6cDR2+S2!Q1rL>iA=+b>U`G4j##KR7^H=;>em+!#7)BSI=t zu~@bQ-3&Mn&Hl3D9gTP|F8pnghL|N4pFsulHBaeqS?VtH>##d^xJU6%^zYzV>oU&n z;E-f-kjixVctAgM13JM3us&dKHiK65tPn*pt?O5=9hdNtQQmMvk9?e>@z~?+gY|r( z)gR_mf+#dEOPA)^)i^4|eg7wh_2r?!Bo8gRR+752><38uc1?b=NiWsK@H~`Kyczie z8W{#TAL4UjA8=emdeC-WS%k^s+poP5XBUIzb2Pp}rG~9~N1aKAa39)CuumMBs!FbQ;CKY_-=&}PW)5jH;TL~8eqom*j@wkGXOD$XLKS4%@r;i3F6Q<3VMZ*>m`FyKC$s0jPt zxKWtLwAlTr1H1Aj_LFVyYoV?a;e`Fqw8BHev^RWFoI9b1^!s9uHJ5?h=K~-pK4ucd z@c%Mjh6vzZH1cUT`)Hm;Cd1y7zY ziRepYAq1K)AcbMmR@aJT2>YNX8^lt*ptSx&A$KOa!DF-FpUPt^wghgXaNbo*+;TZx z*OmruN(&4$4$75@*U5OkX@k<|5ghZ@$i4Emn}z=tD~;FwH45GUhWR*xj($UBrCo=B zdxgsOO{p@Rg93A&hwxyN0OZhOosP5 z$Vk%GZr)p?2L75A`XW&zl>6S&AUE&3%b;oxR^q)bjw&JMth^gRk4q9!F$}TQ&e@Q> zDlRrPGAw%>o8`8yyGpg9g|U!yL+iw}RigcRq0-O4JYy&WF1)nV)VR`wyzqg76oLYb zn(QaA11$-e;P_HVlTI)&#i~adQiPYL^kP!IqZ;&sEu6 z&+J5uk%m}e{oI?eObtfa3_>ELUAo-o>);Fdn8NX)GthpS76$E?jE z0+dsCM+`x}69s-=A13NcV&ln`O&I?;^{x4EF+9-Y>QL-*e~v<%V=t^yE~%4u%r_GB zE-VaB$YC9!T^bHvRaXHl=yr+=6#2lpovsJsGQ=@Ktw9vn`M~KuLvccE7?~lpvckRn zIn;Zyz8K2%jVsu;7&4$V2Mfk+Q4~qoldu~(Esd|HB?t)>qaD5U8`wZ54x)pNLyU8W zOGE7M565ELLcpfqS)^)8gcay=z$9QiP8cLFt002`8n-oZw?QLjdN z$$t0%v)9!z?!7;j)9dTSwOJs(nHotO2ec;hzJ_ z^3+QiLS85`aWqw)KcgZe;q5)KekEbja*yq!LN^9|R+oLAHXxDMp`fjh8pBF`pk=m- z6<5uf*cV3gapT0%(_ap2XfM;MLT_k4_ASM*e3iDlzglMUwr(ys$T;z!P|k*=!BjT7 z10^Cj3jR%NLLDA3Cy=`lQY|5$M}MPGNaXv|vm>E>+PyCQraX+U`qO%$p`kq~IdTxl zTk?)Q$E3rQNyuYCB>BtJb}0rB0PPka?L6xp7GQB%FKFXVG@fBhM1iGZ zEfq~XZ-xgH@S-2b#wy#h=%q~o1T{rc7Wk(TbTN-b5 zcA^0mq(}ukO*d8m){_7fsU}wL`3W-YU?@-haw0KVyP&Wl$!=oeB4sMzSRY#q4zo+pwa>KlrxNU3=9!w*KU9rRP0ABy^HO_CDx-Lap6 z`xPmq#?;?c9Kt0|x_O#MChII4F-fV<$0XLDX$#CB67)R(;Sa!6o)z`U3t%BoIXP9q zzjFwsLuw4)uA(A07%RF`sm|7SAEZd4gUUxC-aHGQ>a*Z6tTPyJJ_{Ziu8fqYh;L}a z_4v4&;y->=#=&r?Hl#FH&J9nSuB)5|bA&qJoV#97?90o|ym^@oZx{r~0pDU7IYUkNFe*{b;J8)Uyh7BNU&OFfXnQYV_AgOE(WC`j202k`dv?)f3HZ|v; zgNA>b1f%C9WzwDXa6C_AgZ}^5G(I4iiFTl5_u{3O=O$>*q6vbwW0GV_mQ`=Q+yFM~ zk1UN8z*&uFAxYSdvnhGjkQRY5?ZT9wiB2xhcU1qZ4QH0)7NhiiOZePv_8`s!=cLx4OT0dc0#37xW&9ssM_1@o41Z zv@F%7qyAD-?|E0FvSMFyJn!mi#4M=mJ2+`Dt-^Oqm4c50GCVZPc4*8`hA+;e!hvM+ zE~uar>#soj02sECxk!h4y5u;q4D~KlRwoNS8UXM1oYq}jyn)nTucAT68Nrk2cy1Ua zg)^g+L;>$#SwsVP8DzLkp9T0%GZlY*C!oVBl*K$wJch#!+cB&Gurt3^R5P2<3V;4x zq?uI5B2Cz3T#?)lZBS10dHw_wn}sb`x-?r9Xb0;yjdU?3lM{LXs87nm zXom$=588vIldI$FyTL(e?E~j+J{L`IpnM|{D=Fm*FYCMR<#b6BC1+?n`jC-k3E_*)*5V#(KhZ zs$>P2$*q6l^+}702Fp!tY=L-t+I{1l}+C zWWy&Wh9y}V@)$=`PrJBp+Oq1Z8R6EgjG-b9-Vq5m{;O7>MdS1OYHnhfvYz|6TR>@H zdq#CAmn+u~g>tdz<$?RjP#!d?>Q~WUHi^j$+C2M5C3u6g$bGgU%8C!tiT}G^9xTi? zH36uiLU9(*Vj41z#v>p_bT?;1#X{xl-OBnaM=IK^s7QZOI^*wi!eSkL@DO#Rp@E4| zG8XgNJ|wi#xOdsh30zcVu{mUD=i3D0DS~cqklu+j8-kD5l*yuRR-5cZ3wR5jRrbG< z4&cN0iIRdmld33KA;!`blBuQht=geIri+V^&MAyK*wR@XY%cL_{a zRmAQ@szM2P&OytijQ@p#`$ptC|Cl}rq|leX1b8x4 z^q}t(q3C7iU_Axj;<_|ZvS`WizKOjH-Pp|6J8$~91W^2kAL+-xG}=*pOq+=PU+O+# z#zf1#SPeG3#z9DZP=?HtW09h9LVVHov0UMw@qOFTk${2_rE)a!kdz!C*M`P z`W5Nzl=rDC>%ETt^#utI&`mD|sAGA!9R^OOk@cl;2I>a=Rz+&92HaBkp$e5ehZqJ` z$<}`7L4zg-ykpI3;aFl+cq+D79Du};$X^}}MGS_1`zGJI9A51I@t~QaIJ2$kbzU-c&qDyLW zVZ*MBW;JMwkSBkWR5dD=W*IA@-Lw#fW4f~16{1wCW!NqBk(KGx-pT1rJJ6B6@5j63 z3&SQ#bCsD}c2hS>hRYd)L7;d7C{th#&-rr3E0We9ed#Tb6k;f9?|qnPM0qty+GaET4P@*fyiEMj~UI@n&0i&CtrBY zc84de-d+$Zfn8&Hy^`@RfCl=)2#EQ?o;MCP_F4{1)s!dG46X(TP!RB8^<)tY^W{&{zj zfrXq4?0LiH69#!{S#2z{aZv?%IyS^zp}=`b56EOa4Mx*A5a8GR5>?^eMpd%nYAPjq z3@4~KPL=-@1KL)bH~~&2b=nmHTETUhgpjbX3BxgW6zegWH6LSe zh^%;*txxCtef%%i`{MvF!nj3Q$ahXsEdmw}QS`7jAa)hKJvRr=c$D2DL`ALJE8${d zc6b-%viVV^FXiNTDiL6RAz=Nq8CaA^059@0tQJb&c~ZDe;PBRK)@vz5`@s<54D7sz z-pg*Sb9HVA9PT>XgOGX=>c`KN>um)Vy}zvl`bu^J4gRzq0AXqYu(l^NUvk|t@5Hq_ ze+X6FD1%Djl_9-paF-BT#c;BHvgLYn;wj|PaEJM+FlYlABYGv*e0Q=)d!A@ML`tqz z3Gt5D^O0iiXCB5xv8Ft_!6Ugq=oj++W1-5n1E3gRZ{y0fSdD>8m~N`l0YB;pai)B6 zWz@lEzl(~>rqYt*#hnrsAS-B@8`t`WQ9@|K`qVeUIHccu3`hRx+uj4m*gUCVyen&N zy95$n^&0lUHs)Y-Vf?(dClhXLF2NAfr!|rUP5?CAyr*fCd!s-yxZ2lSuuZTPbq{UE zs)l~@20JlCC>DNDkdR@8y^FIMh~RO{{~LP&O8A%rPBy)DOExFnOocILso5;n<;@y1 z+2GE{o+($qAWlK|jfjD8C-*3w!E&hrifQ)9$Ic8gUQ zRJPTw-Nxl`82=bfKGDAsNXGxya{s?h1_T3Pzc(K^gy*fP1o+B$=kzRpZR808>`hl+ z1moURfx7;GmZN1Wbt1Wzwu9&Tew@v?cGp2dKVv%9z|xI$#}3z2F}Hto!@CK+&aMgV zIdJ_yJjQ!e*gE?n0l?J$na^zTmxcqK#Dc(0{uFt%&!)CR9w~Y5MpxZfbD)r?jMGgM zS|++@uQuS?|BWCuPw}{I!W`eDtTo~Xj?S|MHNWW zH<;FI$%d!5=nbTDf8_8=@iY9dCGU8`wBwR=#@#}}My8^sHt$JgLQ?t95DUJ(>KL$` z-)to3&bRH}?8$<2Y9*nQ@Wzee04f=`IN(mN61f%JF1JPp58ui~aUVXG8pT z>nTUI`lCoUyg;O$_2N8R=+lr^O+p^a%@0k-zgr=T2>vk9sw!JQ%3F0SNW!jq8g7kY)uo%nJ(Hu#uqDDCP1Zs z1kBd`jLz+U*Z+*L(KLEou@1YQA)J1v`zwTqSjQT0U1m+S`HpY4==E7fX1cm*b2Tuq z*rIg)Zd(hf)|--@EW7{vU7F9Rx2Ddw0hzz<-b+mOc>1v%x$shIqB>s1K;86$M&`*= ztP^OV`bZ&Iy5Q?%YWoi|l>Zed3ItDBKLnSSmUDjR}@Kr2U-JP~$)dw-Uf>bBypg;uncLN?2^7yz~W z=C5)&W`_gC(6~F9#j3|Eqe>x7LBDq@pLwr}Eu8{ki ziEX@yba=WT5#xW@{mhySaf)9D^9_J_(&_r1{>@VW8w^00e#b}SYnyUdoPYwEc9c-M z-l(Ct(0-IJ$gztMEBJ2v@#B6weu|d4HUGxx$i4fSOMW!;f44CbtgSeJ>DyZ2G2;AX zkA8%&a;LZ@zo|nMbP9SN$kgx7h{gt=2PO>)my=>i51q*tW3?1t5^BBwBzLoZ`d^*= hZ^Hug#qxWCAI@utFC9Yv2m}1dNGOPxi+=Y1e*g#mft~;W literal 194688 zcmYJaWl$Ymw6%)`cY?cz;O@E!?y_+R?(Po3gS)%CTX1)G-M9vK*uc$u&iU&8Skv$X{wIlCiC93w6a{a?V9-Gp1<#6I!E=dWk|p6miw?#x zeQ$HafF%6$z2N7U!I)L8uigd>-@ct2^@WaSew}qSc-i&=ZN6Lyn}0YTZKiu)LFBn5 zP-2=Eog`rY41kGZID_d=k=1@hrd?H>J3Q&u*FNXdV^I((N8klL_*RH^oV z{9GyM+dp=K6e%E6I6QQ6CKG~(&>zB%xPu^*@oYTxq@WAMwumqcKxaqf~$sc|bfkec5y=%U_49FN~u_hsu)(Tji%U|BklzHM}}M8s4Z} zi1Gn0`@YAr1l8J!=X5|*2vj0^ZGA(0XP))1jmCX|Oqg3mmybwf)P zP^|f7Pv6i=oN6!w-T&*g$s>AU60)>I=Ozi~&QZh9=>XKh7=al7Z-cPtaEOhR{a<~o zGRWdkSar!Q0?A^D;p&+NBVXDf>k%`j_R3ii4J-f|X+vt)$Gk@A2IaM32~{2?VxRJ` zxz)2HYDnyRnB*lQHaW~v;Q^Z1Mq!&(t4bkLZT-l=!MJEmOv-2w(H>qm%cx>a>|tpH zwDH$RYTkCh-4K^K{3-@wr!X@mlV%QSRq{mq5ZduCy`0)6ATn8dXP&m+#{lyg?K@gBz$ds9y%BS zgY*D3_Ac?^R#fPq2et9GQcx=K;b=m_B+wlFI6x^5<%+sNx!=$pVTaBH=JR?wFd1oo zDpY;_^Xi5Ck$)gqF6~!5vS(2xiWVkx_{ZQ+BeFTzm60w-MFC`eUqjb^{I<7Qf$j~g z91K4ASOjkP>|lOXm>+w&1;}vOO2SIqL_M!eTg5*;LEaKc9@y@ z&=NMuh1;0TWvm}sh5Sq8hS(86JVXFV%pb^UXuHZvN20H%Xj*AKsuRVK!%#-~9M+Rh zOFv~&V_a<K++@f8UtHZUVv{T>Lo#vjnD({!>2Rqiuc3a$;Am)Dq&0HnE)6SgLzY6(%V#1VI{m<_LBeYwnBW8cYM=+B z3P)U_dat1G6i}HdcfwI*V1xQ`8Ks*f?YV zL}>#A<$a~z%Vbntl}syd)s8EG6b}Jiz(ytG3V9&C8oerio|{&+Ms}55`LxP$ z*^F|nnsAk$Y?nb$39AI93Z~!DQE61O9p=QkNtU^ z*_OHK**{I;+CXiaYPo8aYC-J_ZQu2b_33ql^)Ktm>myD4t}Mi|#4QRf(@xp%eB7== zu`EP=M17?7CgNM+m6Sp!F^dmNhvz9L%jes(?^Tj3NV603I^`>6Pa>o%txK`Xxivk? zpHY5SQq}P}laCd1nJnD|=dk~xCH zeF?!~4r6=cz#D>ntYPMpbr%}JOnn9W;-_@HG?+{&xt6r1Oyo4}^x;gL^yN$;mclgF z$@$6UwC1#jbi&NA%o(;?&K_&gmYdS}Tzmt3cA_bl*M)BGMyjByQ#1CM@KoF_D`~J7TrZvdL~! zNLE-GQ5k`a$>wjd{A+E_Z{B?;alFCAk?N58gNc#JKyOQTsK&KM(C)~N&Q9H~6;C_r z+px;8r~9vt+&A5)!pmF%UBO#{M{n?<&m%z;+Txaxe+_F;g?CR|A*%8AQ z!@asA2Mz%$AJ^x1_(*s|abv1*6UmwwA9Pb}PR27S4pzSJf7o8NCezZiSdWb?>s5{1 zhq`0$B6UdInYa1$F+mA=DJ-n{G`oNT|GkRA>6^ll84`awX<_NO#Uwcy1*z?vO=0q% z{p$#NSb8)#ik-Y;Rw{i(NQn=$=88gGKWq`r#{<8L$rz2-Br#`6DR7nwCueK_3t3ag z6-R?xA5Uu!K_BLi?;m#@wN2`lTc`S`l?&c%K5XM`USAkQLv~!v9F9sR(X`^V_#0pw zu^P{vlblqXP?0!8wECCJB~+10+`|8g4;4&Xk}NDMoMVOkZat=GPjt$>ZQ6KR(6&`8bY;{_bZQs-I=dL~bP5Nd!W22neRPKWXm-Ax^?`YN{ zFQfC+5mVL%C$q)&^h?r<)}24I6N9$;y`AXZucMGqq+>>(TiIFW=AnwAy*-^s0bE<{ zC}tc6I|DYiu~%x4j0ZKYEV1l_Ob^2$Q`hr(n!$uWv2IFBm2dm`Z8Uv2eK5UU&AnE; zbMkOSzq%qYtkzBwV4&J?w6#uW&78!WYO5`&MXR-{b2B&?Yo`YtNOAA zz8YisYh7UL?wJHA+BFlIJK65FQ>*UfF(r=?WhrIJR3}2`u2pCwrS4+WJ_=;ja&FJO z_2C-kAbC8UmR-$h$I01&?8aF8!jrd3`NbD+|R}{2NpLe>te_mM8Db(4R3C`j5=equT>OAR8JMEnw~6x_#N!Gef!@N;Lgy-NeBe0J_e3rUlmrSjbp*2&4Mw$ zK351&V-uzAiajojJ`%pb$IWL?`Bv4Zxt!h{dS;r=6E8Y1-dP=R>2R)kZIuBrc;czH zrTfNLuXd;w4#ePF`Q$djf9%fquKbP$I_@NWR=QQb+Mia8Qal!-_45;Ac}F^xebLCQ zodSvVY>`gl6Mc0YBwDM5fThn!f$hyChEPg`$m_eqH~j?$)6$27C%*%BgbiQtm4UjD zWkH`;b6wY0M>r7Pt$q8riyE2mB44osc-#YGi1~HHrmY&Bi<{7Qd4D<&t}JG$UEBW# zPrd*)g|2y+#GY|Uz&7r0KyND(RH4FhE0wFCfs^$Utx63lgRMPbdpWA-=PU%j!LK-WB znj+dO+^R>hRCH zFHphgVq_et!x=>x^o>qAcSjeW_PK=VtqpcDu696F{tCMs=NUm-qY>df@xRX_F~sSe zV%IzHNsxit@i*7a23^FV!_J0^I=&X=)rePXt>lXurp(gOh&()e7);19A)j}WwPBkk zLO#1W*8RhwXS4bS#NX-JQa6P`xO)?2+KS(E;_K^s7n(Vj^2Kh{G}Nb`+CDGgd7xqf zDB~!gjQ6pmy#@GiEOMfMSTt)5bsv7c#%UPH zk7}qD0ZAE#$HrLbI!A_w8MjMHUX|)&Zn)w!dUMkUVjjS#RRMbr7({{UArKcMgM;Ec zuCKZ~KKr4MN?Ka@Rvgo^m5heqRc;oGcU5`yf?5mobp6jH7oSjXQ!e^;z^EBLP@T6* z(y-hw^nM8n4P>Vsn7abojz&j^wgjz&oei52*CMT*Wh5xe z$*d4v@Y(k)x!53LS6CPKuLkTf|88|Wk8ya*{g}zGF*YvWc+a5RfoH%B)LI+SwVN;a zZJdbc%3%o$s~udyhLPto48ym}F;E2SFhp*vJ5KGM)UMkmsk?})CE^$$Q(jXAzmE>u zPt51bL^5voDH}gi6)#{XBO#awG4yRiW4_@yOv zH(jZhf(7Jo2(gu4$b0W&YEmQdcH6777G4XJ9>c>U7a#fghWx{zx!)c&?diuy%NNq_ za-m2Oof--j7@*P7G7Qs$FX?CJ=PA)`by3fx{~koM8J;Cjh7>_DzDcpk`Q=A*X(jpH z;R^IHN@ztz5vdGPqNPxtfLHIJxKSNC?Kh*Iloas(88?FEenO~Ey4;U47607oaunAK zLNQm>Mj=Lu%}QAbwB4LB?At@O1jc;RCU^wID2ZMp zv^1D6jcYPv1{efqXP8|-*i=_wUteu?=T=wAwxwR9gk+0-q)3D0?<;lV{0gqH(@n%| zYO3Z@^EHmCW>!bT@x2_P|7cY=h}N8~6A(gAVb4s0Qohejdf>eJwlC00l0C)jXc zw{>)Ed}j-GElA^@s!U`4iq03mP&%`Ek;!Gtq9RZoYOBWlE!t6Iu_RBuN5b?)QfW_p%g zfP|003gGL?WfN!WUCFRV4#LG<)GdoAOeEq+TWTmN?W>Fz%MXJ4znC$V2uS|XGy<-N zyoC`bylAY^8u%OS%z$~H+GsvQsDE)$T>_^z;YAnyfi&?d{wZ@GmCfH;S_XFj@c#^m zCp#g$-@3TCuxrLeYHXz|mzPtn-*P{*XV>Qi0R6H( zVlBc?{e~SL=Tj>N^$O!A1J2ByM4_RQ{j)ntWlLoDA8*^lXXjST@~b_(|H+P0u!xvd zbl5)aHbN660MH!*utM8%ZbdI)z26uuj?G ze#MZfd}3tsy}PxcTj;OXH6XvCoBXfufpVk6j9S0_WDNlD2g{6l<3Y#HWsu=e@=r&9 zIjx_?lR>m_l^anq!(x7}(2d&3#f7?Or|nhWxk)x2BHpH(d{2L%}!ug2Ea7C3X{g_`{|8ef>-TFWf( z^!LsxGnCVi#fERa!>)7tp!;E2hkAqJA&YvPJ+;dDqh<4Sif(fKm6dqd)z)yYT^a$h z3P028`#>9?K0^h~BAGr>0=1YBWh#_$gH!55haVwPCVbZbmJ@v<(iEqbH>?v0($f&k zGf@tUzNF>aLPB7SMNGE^tMqf%zwfZ~FAK&4zy>0R>-Rth=m@%lw!Y_zMNq z+O)hxbX6DHjK*-dm=*=a8od-PNJS{iIIV9775{nAi8!cZ33uTA&j^OI9@ZT#{>A{cz92F%yk|xI5WN~Uanwka>`effS zHItm~S-7E8r|vgft2+!z-)fT+UC)J!{SVZi$TzGrbi{0RjCONElX&r6f9}?#N&^qu z;{YpK!-&6zdkOjJvdbGQ`H@FG3jOnhkx@}X5XJx>bM6gnUoXzi*z|1nOXSTULFz2% zB&lykQ9PxRIFXW}41gTKpC^~6j9sZlDexN5ngaK!aKXjRE#v024%uIlb~rfyzNPcN zD~BX85-fM*oL>X1LBSohX9VU99Y4?0rto*ksv2y7WH2uov@ETxz8?sX(;w@&{lQBs zYa`@xS*6r;C@tq;pU_iJ&iyUS#H$_U)3}8MD=&|d3eI9;!d7)E^ynt(R1{Wnm?%Ew;P0vQJ+ohG*@V{dr z@`M}7t%&g>#u6UJTGBi;kxrv|1gH6NBH6edQ3BnMvycPCkv&W(G(B&Mv4l51BNyCb zueFSu?pJzd#Tt4>mcm7k?RU8S0St?o1O#G@Rj-#FS4<0;ezylR17#-s;PLao!$tQl z9UL`^YXoE!&zQiS_a{)buZ>kd$_l9rn8?~95y*Gr zd6w-qn_&{nUFvO{xPQ9PmX^_ay1!pbII~b5fnR4>PO^tBHlNXxgKhkR%gKA{59mK{ zKQ`c+cwyAxPRr71wPDqbXVg9efQ=7h3C96&k6J?W+K_yNuzp+r90Cv)s)g-*Qp+06 zVP>|-&0!*C%F17?Z8p7$-h4Wz@zD*$*-_o4ho8VKkGOsu69e>KrIAUVYidgi6erHPcB;m9n3QmF%025j!Q$8fasIu=~EarwQA0Mc=!6`-XA1 zFN`Gadpv@D=L_&8@yDBi&r4-~e!dWREElYEikp~k0K9H`3zEQQ7^m}5@MO@Ox(EOga()qBg%r5i14D#LZsFM_aC2v2sUjCh=jW2*4;{S3? znzp^beE!tZvV6V$)ID;*j18K!j!ZT`x{G}8-aKUlb}#vSG6Z|?F@;1Guf_ey3upi1 zNv8p>hnD8|BY1QAV#1iZIjXC$Ny+4xS6!u97LWEc<^!}dxh4*{a`V*~;3<)aXCcqM zMBjT*SIM(#bfQ#cq<7!MTbqe|1yEX#ofSO`w6~R&fzAFe7dw$D&4ykmS(KHopF0(` zj_)xnLmTyEnBk-V(85!ui<;M=gSo|T>lhjf(H^?}@PD5e82HzsjJjQ|8?Fsv68*b* zr^PxsGU_OWEG*4dgTt@j+Nvt9Y;z^qWb%HvhjQj;_FS}5M0{2b4kP@KKtT4X@+cX1 z;e7on5s)^-ePVB(*92U~u$1wg@IZp5eq0jN&l2Ks#6XHcgQXn^zq_@P+J;E5pkiMI zuBVzXaiC6PXy5+x1y@;4go=rnmS)6uCtY1zv&!`ec~yMy`Z`XlfQ=MD3<(XDV$Hj? zvb1DuBClgzxr_LSe$mFjfs6Skw|?M9`&i#M(?VqTf@vF!m;bSl3-GhWA|l4(K%G?= zf%G&52GwJm1t1370cDHr;R19)AK=fsOHwP5m&h+!G4w%~c?RHKEPWMFO;4pXV(G;u zui00u%#JxD?n}f`9a7F-ty(h>yzqqJB(9za@sG&U+`G7sJ zifv;_5Xl`hUH;+w`%n~3ELVJnDE=cjP*R@{Ki$NTx{~3%m~t*uE%JHfdRJyXlku~B zC5V&AP`W=GoMO$s5N_JeplY=Li+RE+cojXB(r%9-b#tMuXdlbZ>|-BheDd6p1~7hQQPYY7BoyytCyTmG`E6fg&7tDMgzqu^5b$~Q zzja<+C;Zp@=b|p)e28e@En>ZsDt#+SKxCp*uoU{BG4H(QCC^(^(~GSCi@fuO)5%V^ zQZXcUx4qUGc*3CjXUZWQ+F$nUeQSfyl=xfsEm!NZ)GxpwSUJr>;g>se6Hk3Czc;Md zarGRhymwo%V%_txCoB2B&x-hCYBsnO9WLwBCRiiFrdBlQsTKXi;#8><%8?jr5q12_ zwtbpA3`7iU=%=TrN9(vH-0d?#Gbivht>QYwtsb{-!miv|+jJwa#JY}%rZC^&V zQo5zufjiz8_nkao*_MhYYSuW~=ufC~cmA8^g0@5TB|p~)Yy{@~zK(^$WIO0zz{ z>sh~3Et|OC9hEWH|3I(ahWifa^X>EJ>pUfze=jon$KTJ78QAw+@C|M$u(=`OhV*ln zpWHcZa_H|<5`>LS#lf|teg}}=~uH}#3*`zB^7uBlstDaAi>I6$P z_f5Z!`?6gJ>eKp+GPMsz=nr#I_(_>I<`c`FF$_%zD2^zb;0gq;DRJOftNOATtFsjq z;ZmAtTkAMfw^g7}HBMX+Xzzcc{Xbhvjeh+SjhQ#;gdkgH$EY>DhuA@zXbW0!Ft) zyplc&wa%gc_O~c0j*{a5qm=tW-&w~WK4#1w6%&s`(>tI5l2#5;`eFZ`?n}G?G6(*m zp)No`H|+k1FObr6(EPils(FQVQK=>Rggvi36*4l7&_R5zwWcu!t_dHgu^sU(MwTSp z6E+`jLr%^jE{n>@BTg~1NST7S+RKEpNxAyl$=|=gEHB{8D5BzkzU5D?SVeCZfZgqJ z-#_!P%mvkm52ZlpLyZ+=O&D_TB$;`+>jaZxb?xpc_pd_xOiv}m-)!8KFe|ELkBYUJ zNxYe3DHlS2qWfd~9rDt6U;*Kw%a{U0kNAGSi1Ituo5ti_&_yBhuwrIVKAO);OQNwA z^R)c)xX^!-f75gOQF_#9t@@**p`|AH2UrbJ!$r(bk~6}dFWN+MrYyDg6}FfdP)xI? zbsDxCc#4}q2Wv7d%{)PGp!`7+f8BDc@Mk`4Zx=t@L(0kpuDg*fuFH}|7Z1;9h(sT+ z#4-A2#!dY5B-s%957woTLuzzPP>qxlCdGT>yav@k+4VG)DPKM*lf@6JTCzkGR;rr^ zY?pEjb{4Xj^uBAOFNG|WBs4@Uw`7_^)MzWaYjq#T&eW$@rr|1;z&2xG7=)l|IPRR9W)W(>l|^Iv}h!nm9=OHFWaA{XUQih zU<;p7{62lC(Rf17p;h>uU za8DZvr^+b5nDsmHK8|!ioD;6MF(LDe+y?e38tz+;mGPIz!+2RJ5m852J%D?F)V{%1 zxV7NSQ*{IUNPl^`R%VrS&BaE`YH)Ar=WVU6lG{Zy9K$xQJ`Y2JHyM$jpBVJOpnav5 zkMB{Up|NCGiZ-n`AMs|-3T!e%G-|#`2IXHO$ONL7dYhi}7#-w9^ITb<7Len{ltcmO z{c=OTTRxMIYUC#m_>8bcW#>5}vE|oJY|nK^1B7)m_2M(o_wfanvkcX2X~;yp&}Xht z((6B_^$-bRLY%KlKe)`?kaKq^0U_4)Ify~oW$=Ea(LXvg&Ej#H1aGe!VbSlWnfOi- zV;qo0%2O_Aa?oPy0wRBCq$s>$RDqAH+i%Dr8B!moXU22PAzX&>SHQWX$h$KY zNj`b)-O!p+v0&=+gMno!vKeRs;Jl0ayEfoF##NXQxbD8&?UZHVz&~k};ch0E-PdYi z81*8yNqQJ<0Sl7l?8FC8d~x&#>M%kZt++paLf{uBtDQlkov#`Jcm!pLtFV=%FDI02 z!+7vRw;ZGMAJ6evhIQ^_y0iLx=wScb7iK9%s}+;}Hm$+WwcK~w1-L8Ur|gvNx+qbl z#FT_>o0nLpH%C91EQefD${xxeFl1Z!IO=PEtQeJ-16-&lX-d<6#E$=m8X+ZrhL8s= zjn^>*UuVOYk3s~a1yXjC=o}8r`OwWXSF^n6WmN_TR7fcRm4dxcpa?lEjN+0tGbh+= zysAu|@@DD+EmaKxDhzX`(6ur&g>3IYLp$w;MIL4ywwmWT!KI%uf(dF}wzi z1${7fl_X^fx_kqoDtz&k^xN1kkTlEIYnY?LdpI89ZUgp-)~ zc2Ni?=PuJNCuw`A_RU}yk{ncqQV`#vNm8{|jA`Zi3*L7KWjE$6E1IpY*NencvoCy3 z$_97N*w$nqmX(2}Yweb_@Ma$j&$BBeEa4aSKRoAuuuhc`%;d_RqMsQdQ}@d-hH7uU zzS(RbJ+hCs|4pplOiE>g*1}>&{Ri?cr=>Ao)n)7rrOuC-~}hs;_KdB>(5Na_hM9HtpS< z#$zVDwP~g3W03DLgfWi;no#C>+d%eN3 z5M@|`1HF3L8BNfkc1Y*1N~rf5xVf^DKb_^9`1mSo=8~C>lQDZm@hTSbCa1+dJ6{#` z?kh|1imhrOiq6YdI2J-9XBOfY7ILmK$g4Ppd$I@XW&%ub+zOX}a@9egKr}KnllAvz zVI?+0WunGheyEsUZ2*MI`-Qs#zGv_TBe?Zyt!se>q>wFSeX({unkLV7*<;q)UZiP_ z=i#@E2Gtg9x!uUTXunN>>U(x)cIx-H1C+3lbTixJtXKwW<2AWQ)g?G_jr86Q`9y>? z=&_89+T(1my*nE&ao9=BoolYnx4jBfqC3B=0-hw(=h^=(3Q+FLb0MJFD)eiL<6uQy zZ843kW;n>g_RHk5Tw|)~P>_HLPJdb*`tczuyyY8x zFLdhIMw{e>^F0|J)M_z5m|E7zFgYBCvdWr*$P<|@F zPtn+wEMVq=MvJ?itw6DR=tYQ!$EZe;Y=ODjnIh*0Nu#o*7>-gYMBA#p#kVbSc~QHfyu+Woeu4b>Uh2K^`XkvZsh4{)yqlK4L<1YT$jul?!YV z^0fo+z)z*fRO+`n!AOR{$ND>4+JhE+oL_ph&~hsD=<0fosOKiiB7r?2cwn5IM7hFChCx zcB)QB1V#vG8(MC1|DVY`hlG60`B|(ek$6No?jV76v>=qe0u7Zj(i|J`VC`g|px(1m z=ZLlCum{ki#r~t8@0aFn)Vm~S>n&MERGzw#I$Z9(e(Lnfqf5ERloncyG+(Z?l|6$+MPQ%rNnIE zZSG=>lrPD)=pQu}{ZqJ~RzoFdD)k5L6#+(I8B}CGQ$TeJZ5cCxD`-V}&;K!n9Y;v~ zYBBE^Xaz`BftnY4HRX9$vGA&6}prT8-T=;`+b#@kg6b@0Cx z)BdQ!DRD2ttsZf~M&H>Ibu=sg)?K;=k6`M1)B%Ihc9qd3;k4~EA>ZJDj{;Y_Wly#3 z-g7r2@rZ&FHTu*NE)`!)LKJ8OL-0dF`1OPmXwdzys%i|>_NEtF9XT{;oUUr9(>2cn z76!7Iym5cLZZvSs!`|F7BhGbuU!hViIKK5mT+inF-mYz9eTY89_O0W7lHDlBe0iFD zjr=0`F~RKi6x{QXNt$kd7lZnur~WSN-Mx^4@Bepzl*OG<@qJH&t9)@ZKqpa-czrMu zrLX&T$vzmPJ$tRm5^KMDmiqH9?s4OAph@p(Ql}_&gSR zM_??hK{L1i+aMid4}NInP$F5Hzl3e{xH_>ws+J*L5!7_@{Lh9pM?;9O*JN*0zxy5^ zSW?#ItZZYQxICa}qfk;f&eRa|S*b^jN}>IeJrM}mr)BG!WM6F3W-_HMGY8k76++u@$4m3tnMt}7vmQ^=n^@w%UX*A`!tNY zQe0=KAm-)#>m9Kt!m@n6rH_xBJmP>_k`yO32CF4xo|lkEH06)3L~- zGmuiO;{Enk1^XR6gX17;!@bMBSw*f(kwVx3`;L*FJpf-*PSdRPt zL4i7LwJuKNXy#ZCsN8c2u~|**4n3|b8ez-zgQI8NhK99|zI9zMLVGv84-z1Z(j0OP zzpe#pXJLh-t&wkCbnMXx(xA=8Uo*~hgl>wE>#!64r3Pv`B^QFunj@^7oeMF{&2Ear z$tJ9<4=413)L~1J>l)8C8Y#Z8r59bm3ezBvZSp?-kGeubuJf;BjXv?<)N#pQR<}vK z#moJvMH3K6wI+ppU5a{LL=+0~+pM{v`1-}K586g++yTI<*;9_>s z=|&1>VVc`NGLr9<`j7FVq=4KVfKGoJPCp^(3A8qOcs)!Fjrkc-38=n7B+&<2J1{)i z$K1RWp9h^grxpuOE273m+-+$b~&@%eoy3B=5?FoCvZ z`jjv?G<v948Mdb-H*W$7-;&CIun;K(bfwyJNcL~bhKME1 z^||+Rw6U2eZv`xJ!sRj{s%DtdYlKVfyu*_f0(bOT5f^3t|dcWl`C`P(6-v39|_*TkWvk$O8JDN_%?B*(ku(1V3_3%S8WiSWg;RMvAgx;5`d_ z*?wcNRuXfwR+-AL=vhqOOLj7<6EXAowCUd340srK*Kmk` zW?aPLR?&pPan&N=R|8-6EIwDhPVji8M2az)s39_44b3S>?(2o(cmE4E8jA+`-K%6F z1pLopX5XPG-WGe=`&Rb#L?|cHtr3P#YQ@;_XCu$F;MHc|4%6(2M8EdCx5&?1>V-(W z{cEBZ+t&M{<8r%A?@z&e=ZMp(lut`4u#M1vg)$oXr|%X;Z!fkJZt54UDRdk-DG4Z( z@8k&qE(Ak?YvN)=9!59nM0G-xBFI>KJE@|yr^fM-M!dX%$pp}Iu!Ii7F3-{E2-Ksd zVo}_~xI@2FmXUv_i(U{)F;tCkw)e_02D*^b+DarhS>7Y{tf6S^qIoF7(}QPJXjpr~ z`*}^1Y-+e_(vJqs314=&g_5v};Ge#RY5LuGF|35sj|-CT;W}nV`0J7@5pf^W1Ranl z!Hs$b!KaQ@bWR;4F6Y%?rGW$FetO~?n)wLGh98DGiKN9c#Johj=psENaoZeuoBTXc zgrvzFI?m9_bW(f&0@%b<%I)ir(FBOx#7u_DR>5J6XfoY+SK-zR4W7rF|Mq(@;z#cp zxdjXl1>-6D&~#s^UI8EjG!-col)Ildt%Ou!T6p7Ws_NWMQw?mZ*1s9UZq`o)IfOk| zCj6Sll+7@bdKL1$-mPh6Y_evT-tOSzvRDj0)9$zAOudmw$bO`$^dqbEQkhb=We&n; z=+ya@I!Ia?2SbW9TUVymt?lvKjF< zZv@s_tu#2U3wN=@NZp4lyRI|9y2Gq1h|OP_n7nM8fu@AZrz!I7aF3s{?xyk*dP~Y+ zs>*%?TwMzi2jBL`n^#eBLFdQ+(Rv~Dop;68x1z29xk8la*VR{%KIc>TujF|jzACS< z?_d=%g+VukDYvo_-sCfQ&i#0LSC2IDr}y9!c}@GmLR#{hiR}{X zpo`bMu>9Eku)Itbk_I;sZuaewYT0Clne#Ji+b?9|++K=Z$X_+%r80a*)QSIKRi5!k z)*2ZfakZm1)rYL(h|!s7@vc(&A_^5tS6<>3Mn_u~dX58(<@QFlkc|CDueip3cT2r3 z&20-&b3b7U*Z9xgITQvV;cb3xP-z9SB_~PV1gTClJSGZy$0c!a+5Bbsm5crB#D*}5 zq{gP#a_kfz^TV7DUU!^=i5k{_7(=rVUc@ek7gQX|9UOMqqle;{EtPI%E%gQmJNfHR zBO$0zlvuoj;7CS`Zb8~KYUl8!@%T>^i+L~VOS7wLhbubAxC_O*?|QV(Q+*@n&ClW~ zU(E(~P5=Gs{fxdPSkm>ZDA?3cTyEx3sCM`6%8?w>#9CH@>*`EyP00ZoV~%b4=!PoQ zfyl})T*w06y9J!rgPdi3PmMFgEnqcu;OKg*Xk*(&zG;p1Nc~{3Duj+xd z&hh~VF`(4g-Ep&teBimuEU@N#X5<#M3@uiRjdECJgYl_gA_Z=TH_Fqv6{9)UhoIm) z&ebv_p{qf|Ul7G2DJ2hwp^;M$xMV3+u%lIHjd;D)*{T8d$8NzH2F?{U^!mNRVYBfD zjch6#H5xkRVtS)_hkA`?`!|aQkRuAZ^k$l!z^@JM>e7uCyH1muki8I}ZdsZ@IQ!0qXCCr{x~-LLL7XzE!Yw5FMUrI z|E%srT{!k-)Ds!)JQ7au!k2 z1Z`tM&_;52gM=fDKJ{gyT!1x}@lzZv}C75*!g# zib=}FrKk{lT+=Xj;JQ)h@IQ`Q!sMT39Mhg!KLJ2%%^Fa`Rs;D}t+tW`vh`u2H1sW8 z-&hf}r!jhrH@brypVBwW8*}iI|Lw%Eqrk}Y@tJnCu5mwfD<%v>4!HuI#`Rz}Ix#4K zOO?tm97|VA$!`akEz1B)2N&+;CVVUe-owG#Ny0u=RY-w@H)Ldw^q}cU?4cqF*W=UH zSySS)6sLPaM#ec%(aY1Vzisu2yjM2V+Gd~(5gr{iuU=lDgNS647c_H!d)EK;){EZw znVjFuOJ2}UEYKe79-K^^M4CvkIl`Z_6|mYD^GdF*R$6c0A}Q!l@A(-wIBN=@_X<+_&j*aND&RcbxD7fiQq#W)%<1 zBSGVZA{#?j>x2}Gr)UI5hpU6d$xg_#=J9Gr)bo0mx_HV8+cV~eqhp>x!c-7V(~C+j z7sVN81F`UC+{LCMKmT_hE*u8=x|)1}f6MIOkFC$6XAw_hG!FNdqUbAz^}*B$G-KuL zondY9gTy+J6`q%4!795Ciyn3O2-ppj_yOPoaGqcr@-ctBk)6 z9963p;zwK8x#i-MZIM@*!|tuAb@dGg?*Gp8z%20oKHN{aRws&cx|uuY8?2H!ysr8R z&>7?jzM(co9xiMr5`cOUmF(p38_qt7i&8xsGIu!8e_x?pdmF}N1P3P4rN9luR?)!M z>6=pojD?||=Kkw5R|}M@Ti7G*MgH3-K^dd+66^T?w>*ruD9FaSZdNH^7CkEFhWhav z?lhRY%?6h_J1}!~g#FG|Bv!jV1>Lm=Uhf;jqNz6O$Zw|jDE3ey_Y+H*SMz*7Ir;xS zjrhM>Q$E^t(cK989VDxA4S20oudJ2$IVsmHYh-$q&6ynAz&@e}j%*9r7U|V89JCjg zi=wo|NXF!{L7nw>6E6q!csw&UPHto9i%b{G0S?=h`C*^Rz2VD7MI508@}|xVH$MQcDl(?9jEb0 z*}~Hn%%mjHMXzl0*d3e(J%J1pAu%e7piNu&$cJo8w26!IYwpRws8NF+$1dhkF>)6)8j^<9NXV~So*$qZMV57?iD#KFS8ZYpY;F(#RrbP$@sCN zV|}j)hk`6+k8O{KaKl(m{@-vW944=o_Exb_7|R_k_KR$jJ{}+DJu=&%r)|@bLa!dO znK!RPLfx5qQPP{P+gFS(;WdYeXt?M!;exlau&eGvucgAD^o$-e_J90(B8J~a%yQy7 zia?dv7>f~h?VN@Q7Ck=nfbbb?vJ?={ZOl^Q4Fb)iLo{WB)@jy?S^i=*EXIc%84%2d-B#?l$J)#mR#X4mi_sXvpOycJLl+}p2BuI zB{Om%QjrhFt05(;Cl4ZEd_3vcPP-%tFv5N_Ym+dC0nI`1i(_k|g|Q&PA;DdPTW}5T z?(P!Y-GaNjCrE<3yF0<%2M7>sa2vi!PIB&hzI%W1G(FQjUA0U0s;bq<20sdGvZ*^^ z`U*jgldk2>i%$GG;tmhd?%hE8@#?1^7G^=`JHD{HFw}IoZL!8MosFZS&5nS*9@cF4 zc-H-n;5Q|F9>g|P(CcL{;-l1OCs*zpZ>2xgw~8&PgvyR>Y)?SA`pf^MkQM^%%O(xrHu!aP-6Eur^Woey6X*(XR1sTWTFn zhD6S%ag2R#U}KDawMKYw9<|c)D-&O&nxxX3ORR{^>P|5BPMKVr9x3^qk?nr>SKr9r z3QwRDY4@FZ{ekgt4V1n&uH5j+NAca{B1Tg)^7)VVTve&7m;!3GRAI!;E07&N#RRh} zpq-+qsg;`it0C(mV>(d9UHe>zZq$X7D0Mc|n@!@goa1kIS%+DyKZmVt7H7zA1@Xo{ zmrzMjxes`ov=f|U+R^^{&fUhhM?~y{R{MQt(6bYG%icwR*;PA<9-!#Ef3Fc!Z*ykJ z;*J!b*=)-Vn$#k1vgfN_q>pbJcIPa70$ID^eY`tjt<^JS+zzOu_Uo#rmj>l@z1%Um zzWwA8moR$gSF+u1e&$A=#CF6$`l-zfLB`U`?mcXTb#q>KqOYduQ5{peo#|$eZ`-(W zrvVIu9qk4ms8MU3-{Zx$k-n^@U}Sjp%aA-C?s?}eMduGvyhqA7^dV`B%YBr4hcwp` zAer}VwfB(v<1=>c+<|tOgJt5iMGZS+>V}~A{;Rq-Lq)Gd4a$6$jj!DuUKq*iaueb_ z=tB?+Tf7gj$g4>gNI7fP26oZ|R->})xkwPNv>9SPHckc|qoqw3iGT4a6I0H0@&Xlc z+79%DMDcf*#)eHO)E0={$EsHqwz)Ua_k~9^vuE88rDfX{B<$W?P$Yzga*aS0^usT8kV6!l19rX_noU z_F>&a43Xv3nifG}!uwS6HZSS|gdo849XI`K1q!d{JnwPfN>nTuHJ`EokN9I=&Iw;& zHq?D>5|K`h9O{<)OP!wQR1|YjlBYU5R?7*r(0jbYw@F8-Ra_~Tw) zoY(Wdj=j$F5Y+l`bFb+nT@`U%3f3Y~yja9huWn$Y#p8lpY87}lR1?t-$w0i9^J8uU zW<(mX16%vLM&>%BwZVW+H~#Qy8S#b)h1Q>^rh}BslS?DB?4C2rBfGDb@MWbhv$_}g zP2f$1TBl(Y^}V_?NYCwW0ra04u7(JR)Dx!X0ss07$@S2fg1yY=?Z!u9BsJt6q*R<* zb5e#cd@*$wgt=OfSf?`MqnZ9l8mu~vHY|Omgsbj2n~Dsl1AU`n-3YfSIvkA4YQiKn z@%^9Qs7TcmGuOY?%n%;^@LhQ0!`ghfPsn-i%nVf1C651_=CBwH1Wjra+fn-`BvPbr za7J*4<_oKCRX%QURx0ATX=e3ybG|_6sh^a@dc>FrQEI%0BEVIjBC?RVzJb>idKB^T z_`O7*8AffbFwPAaIQd347j0}2ipk2TZAj*fxO0{|~P@lt%_7OcD$da?~quV>BKs-}K2 zZs-12%$oM7{#unjB~9_fB&Y2pNm!b^Y;c$Hy;$_u`%0mG4TS&l;f zy`=JTl5aS>52Yn+7sd2`t33PS z;maH>hUPQ}Sgp}wr)UT@SMe|})O1I)*&-pp;+=VF-h=x#I)P)ul)C0H<2#yIea&A2fR_IXpV2*Ua^iQ*vDgJd6;K089@mg zyF?2Dppqq^?Pkl<;EZ_R_>^ePovw8*hxhVm|0q(PdZgqu%PJqIJ8v7|X^n!-%RCmJak>Eu$ zDcKDw(b_}DDDr)TTfDYp)bOP|0q2#Sg6O5MfPH)vE$stFT_h9N-2z7o5o4Nm*DooL zF^eahe5*QH<6aq3s7V?U{9FTRnOOl9Z^9_$~I_oXZ z#n!f;%w&@|t4mVmBV>?IqXG{WMEJp<9;SG8Mn}i$!Spq4u0ecWXZVs<+H!p0^`vWPeZ=#%gxe6N*kW_h|r;RU8 zHgbTcPXN^?F(A6em*%7CzLfp^3;o)KD=JbGxG_y`Vcq>@JycL&Rbr`a8@VD{sco1R zMxCzSdJn$8?LYbEuNpuRDKqJ9wY?yS|6ZdCg?IB2q}XL8v-I2}VVg87eKN8CE2^tg zK?(HgX6)@K>w(+E21pBQ0>*Kba_+3d!e!u%w9?0n3B+TNRhNgM-7%j~0*iy-1+=t| z-NV@{MIs$z+u)!U6T531h?p*dCfUehNwQqgrqjUH`){Ok6B-SY{n^8duWhqG2nm$u zl9D8#lc9{cmb;83-RGyauSs+(V;eh&77{IVv)|>*D&-mZcn3< z)f^SKu0QwLT^(Y46D9!#D4e*PMCku>-&)V}fHO-Lf-+~(=mgd6i3UcVRQaNO;x#mV zI`x20qP@>z5Gp?NryjWY;QsXYJO0O^Vn=As#pmF)a4`=Gi+tQ?^(PNP+Z@77K#=~Xwn6@y=k9l%~N*n zN{4zR#N4tYj7YzksgZ)vqws|~TNw{%Z!RqWZGG`&Et$t|%nRBuC^C7Q5f*uo&U0XT z6xEU=tv)JipkiyhivWr&#M0!+$)+Ff!x_#XC#2kvbiid0a_xDMaYOw#kpnLg2C{&$w9JJYMY^$@%zdmT z8-u8jpPt$(@Z+OyAAX|m7-m7*WcGxUh~Y4>ky6jVBNZc{#Rf|{tfajGQ8028lRN2R z(33H~x{Cp%i(9$odN7R=_x+ zir@5cZzZ8lwBgG#8xtNRJUC3XX<)6dNpwWJx^TFVXmi?Fvgb`O5&4aIG)!d8^+c-r zExJC6_Qr%-M91Nd0|UQ4$+g>c|2Fg% zLZDvs8PLMOYu!hC)AjgTyg6pnE0uM<#^g(ph8oG8c~V36VvmuEgf)&G4zh&8+%m-w zs^0@0`DAtBK@RauxuEEQ_gTk8d7DBmk3T{uM-2&8!lN_$hmNmb>Rx<+ zakC7Ppn_s`LhLmiVFF<0LE#Y)ushx4u2wA;it7mju`<73D=X~MA~OTldxbMnV99Cg zuu;3L_T~liC(K-J!)~+#wy4e-iMYMAEi%p@vZxau*!axP_Cir?aVXMc>mg-}pP!aB zRO1HOxBG&lS3-)tycHzz7v&yrPT~1izTcd6USbwu_fiYqC|b^UBF;Mz_Mu$2x!X0k zZD}yIbFiZe-Tz!|=%ea}l?b(+-9Q8m#AYuNFPU8T!7w~+^U%?!S9|Zp>@HxbS(`zN z3Ov8-VxrhmKkEPHO!jkcNFSIafo8-SAZKT{rwo&uZfF=PZ0)}8`ejMz|-^ki~N z$McQFG|L_I?;b{QdleF-S4|;x8xL-rS3nDFGQ3iloJ=P05Hi9M;ZyKM}TCxPo` zb1xf%?h+am2t6EefNxnK1}8??cwIzK+YKpc8ibsxsBmzNi0QlT3^;f_L(n zw7D5&8zqD18>%VeUVOYk#8^tUPyC|rLxf}>RCXyWO*VGpNXJ`q?%3K7e3-b(lC-8Z z6Mlk5F%{iv2GUyOJh5UesBl6rV35l94)Mq#Vnk?Dc?T?I{&!-=xRs_ccrl=1w zCHm3FNjng-r;wytN1T(joKUanl6@+<1OTKAK9^tG_RZX;c*U~^@^;=QxK}LB?mP`T zJM`Hix`ud7^7atHWq;wi%j_cODUrLFi(F*CQs>UbgQ$+U}Iq>85P!3b|&ba2#El8>UPI^5Mf zGfhIrPUDyUDUEB4S}}f-Mz)#?DG_Gy;2CY{Tw@9DZ9S1w}uZe0XW;SC{RMNu`M-(6JH%qZLz52xuhU$m66|6%?qzx#l7M9Z0I47i2g*tn6Yh)`EPQe0_Z;s7#iyXnSUpGQ zuMQ!>kdh%cYR@Dq17kb7`!)P&6rJ~1nPBCqiRidT$+Tm~&xt&8D>WPAK8ww1Q`+Sv zfHqa%=w>B9&j#pVO}}Yy!0$~!y9myw+_(d=au4udJWHQiq{y(I(^PU6axycUUa(JZ zyh(W(cMDjN=8=WTpX>7cS*W$fX-O8)Xmndyk(SUOJ_>_*D7!RT(avEoFo0HRkmx1r zE!^&=wD<+pGnX8^c>-Eb9XEdFn2vu}Z!%qkWS0gnd-cX_s8a8c*!1*-xSnc=3M)bE z>~zmw?l9RS%z*z%`-f8AWtlb#S5^&h zNwYtF<9|Tnk(Am^VtK%Q^_Qi>1V(*@yXhwI4_A79nk*nBd=*rmBPGZ))CWrXr*FKw zRU`o9sTc|-z-!4KL{|>@h)73p$ePZfyj_NIoer^^8s?& z;GlR^(}z$FtF2EyTTV}R2$-%@x$9}$iF0wHRpw-*6)p#T=F0a(XJ-vHa>dG(CLz?R zCqKpZekZm9P<7hPRX)>t!V>xI@cn@;T1{ir??qolr=qvLiZT!9hI*~y7%nqiir7z# z^*Y!X7#Yih(Q>g&6E!ZgF)nL~L8D4w%y$8jB$#Zf%`X5cbCVLmzeD#SaZ^eU$G%@8 zU`=crI5dcH1|mU93JJVX_o>AsgZyZ4HB=7VP3ui~>VKNN8v%}Nkq3v{xBHuW zI_4aZ1rnWQc}900?Iu{j7v<8uHIQ{L*pnsjG4@+f=6}@`PJF=fW|u?fe!zRzk%Mpd zkzh=)(uS4@4IR#^_H&U~rKWU9#z{bK^{Ph+e7iHu@C_HP1$HFp-NQF8UVXJzeXMl> zSM4X=_Vl;h9r5vtTd_g}bPObkTGb{yOjs!?T+n3aR%vy*S#stdCSE7>Y?Ee5)=apt zU-X!+M~?rHhW1MtVN*kP>2-hFJFO#fz%fzEy)q4WEU6_;q{JEl6vqV!HzM9Z_F+t<;Oz2jg9!_NG8~`Vub7P z=+{P6G!*i*@^7xGf+siD({%Fnl>*E2!$>PzTfN4Q+=V)eYF0KIY|FIN3-wTEN8Kps zO?Xq(+lk`H742Y19ybLT5UD8Z#pphbCu#-XX%o+}q<3H-x>Ko4jsVNrN;rMa9^+QU zTXdRiQ&;oxDuh0=uy&d*f7`^JAI0X7<#+oTyzYKL*c7_3uYjz~7m6AswsysP_SFjwLzgtMN zKhN?VCbHoS(aS)}Fiy`n(%ue}dGYQh7+)~7C3T1(v~^tACzFjj(>d~75%o?c#|W~* zJYfMXbq}3c5s!gcit2QmOZYF)_Bt{pcpRVDO%S*#Zds*Dav3ii*)KI{ZGnRx_zfTQ zj0K^!8dhH&i3|6t*n_+CS?>EH{t`u8heN2JNafeX+qShvnX(wqWKsC1q2ew=OPla- zN}tXsFg$&v`Ru!`@R;*kkh-zmJ_TTDAvlV6 z=wf1}4!^#`)Nl}0GAFOvIr9V0E`SM_&{k8NP)Sl5jUE*AzlHG1u~rt6EN%K+TK+gA zhOcUWXiYf0zOFl4{veaPILZlIv)T}bVEX7=7Jzk&|!x}bWk|3DAXHvFXW1TFbkN|xmcOyNQUeXr;6GQ8N6d1Sy@^2q!;Nv>(p6PQ>j>@{8J59 zL24W;#tPxhqlS$ZPY*}p-QkJ7#I{moy?U4&+8sr8illY!9;knp=P@Sa50_T>a98?O zEsC(*9?xw-1HRw1V83}`gux&sWzRn9Z^oWq|B3CM7Y-PSwB>DFjx5$|bH__)MO$P> zDx|AZ+h?@ykS)}&VAV!A6#lx}&%Gu^G$v+St5;NpcD5qQ$>M5&kl2d!$1cWV10G<) zuOs<#U=E%#1hk10buYU9oQv)LjPB6uI~{-jcNYLY;lK{&p&59KR8ZW%udboOq2Rqo zqL?oqEg=OW$)aDq7QyOVhfhr*uafyQ0SumZ|Bfu%5*v{t{vjCGAWef=Vd9@+hv7W= zR`6pflkn6(^f&+Bb`73_(eyKQMCVNPgHR%Q(rq>3=Rjf($NF zC_szF_5E}FcRogp9IfK*uA>;@aql0A(bGX~aMIJQ<);4*u+~J7Zm~eHg0*0ll(OUg zT0>b>K+}*0w!gwJ3XuP^iT`_9Pc*PJJRNRSD>0zt&vhxc__cl`(&i*vCl^RUPi6lE z@BiP!WQum{jh2rX>vd%qlk>0DW?HM`HpWHAhDAooel4rWSn=?C{=CcmJOAA}BIy<; zU)dcQF&$8vk)PG4_G_q$Rn0w;7S0!T?Mb_=D#UQq`t!?X#32~I=D#i?Y#2KDBck44 zzcA!&cvPJWOfl>c&$sW@dXuIYA?C_$QwP@)izM!U7Zp7*)O4+{@&t2`tTwnY32~yP zX>?2ji;l6#6hw(0U2_nM7iY|1Np zcy_OC)Qaxy@^FYzxqXRoM&Zg2O3UiRTY1m?1{}O$eyeso0_<$!PfT{X(NFHB>rrSB==0ChH~dQ`$UK(CRVD=vO=PFBYjqSZHshq>=Kn%NA6&VnAUmFf8Mz#nyJK+9haaVU9~ zTQStOT5c@UN-bgH%>#{PgtqQX@* zpWB$(sRhC}>8I>p$=KFS`7qjhdVKsXiGMBo&(YW?@GZum>Zoh8;c-&*?~>-x^Lmof zRU-oq^8PN)JrR;+UUDtZ_h!qLjmw#bdzgJH+TY+k#5BKA?mGQh=Y_FCjwKpCxn9CV z1%FaWHF2=>DAR?=^?867`i9>_PDn*A<1Tp{iKo}_GQ#q#$}j#$%VTKygrV98{`Hnj z1QivXKOwuSH_*O*kA&;}>hnBATf4!0{>1Z3_+Z09g>h&~GjlllQ@1pn_+`qOOgqHN`1A(A1*m{XyvX1RGgZ~a1 zG_-Ym+L8F@IsQ`z0NaXT3>g?_m=sSMF#1U2aWO#0m6x4eUqVNlSk$k9rZyrm_O@$R z8N+Thz5Xt({#eFwEs8&m1LmT6>EPM#k7(#5x>vVCj5HaaDU04TrU#hPAbI@pF|v zsr>s?etusp85I?g02k_<_q||(MiNj@k5N=*QPIfnohU95Q3hEWY0B}@N0ou1rlw6% zTg$I(Ep&7;Sks^DlE(Is(mt`V_ z1@>O=CGw8yFoKza=CXctQWhWnk5V;pppYI$-zpkVQDZ*S*{Ydqqo&K+2Iw&o@ag|m zy`dQy1PxIOZ0unrDt!}Cyo2Nq7N=v{i`m^*7`ortOG`0yxfHC`_#MTbqb`?)pD2ke z+NP?0FEj|KI*e1i#6t@_B3rjqeHp8-v!Q#JBLPmaH{+*zKl3Q;c9>8LP)T#&pSqA7 zx&;8(M+q-$mY$|u{ka`Wf~0v$3WIWFP+tB-w_j01njDRKaI651!b^{UYS6@r8_WAG zKM5&9qDMj((#IL&0pQ~w$McJ!Q;3n%2*}!)8}+28T?{lbCcAmLXs%B;7YIR#cYwOU z-cg8Sig-|p=C@@uHzwOIF@CBe%0MI4IW)6fD17?mCp6c8@pKHqMw{>{(3K%|vu5;L zXtuzb>;aL9Yb1g3esnsFEi`RTI|4B>57(3xUI!Qdx*|HlK&K2%4K1|%iFZB<|S^(#X$%)U{{I@Zbz0A1l+*@>~QJj-5lm0 z)%>!|kK!a>v}O}kvK(nt2$;o$*(=5eaYyTYnx>NJTFs@}wzCm59-1lG%B;o+FKDn& z(bF`uis7zU_72H!Z%|{GLIxkMe6|!ywk-ZS&F)cQ5)DlR4vt*S%K1fgYelbn!}p9< zjEmj1PhLWw)hDT6njN+#eT)u$^lhH^EX&JTU9A2F@<6%|-GiecDWH@_jg39gGp}iA ztSFOy$|HHOse72W`7=JlgNz+K=7=g%Q9WmJqt4P9kh^}dvmPV<$_dBT1CpaG;|4Ss zdwEVm`A6~N_7c5$KrS35F&6_S{Y5bDX!aRASX1W?r_euXET8)SNg@n$$eD?ie2dPL zWnMBDpxZUNW>|p-f8z}kR3%(8<73JvL~Z$}_03 z@I#57C{Wf&B{5>nREoGUDsDRO-!w>_5h_W0`Ry&QR*Q10>HqU$8j;{2rV*Jh*hK*| zUNN4SdlmLq^#A&yKdIEee>5|GB@(P-X6uqES>tV}x2`HHxk|r{d4UruMC8WA!<%Xv=!lRp~Dk^TyfwDMEY|Cja( zLm*5a6TS=y`@aZz?49EqxwxnTyo8%Y2EmRx#QU_B|2;c!$T1J>zdB|k;+KG&3Z=#2%N8=~dgCANSXfRwsIAhLm zPVxXJs)Mbq{E@|(H5*_8nG<=J9imzy{tRbU&id!fM+t_mB(N*8zvX;CcbM*xJWf*) zwcbHWJ$6ECgeFV{U_)SJS7T4Lle0xuoXDsg;ZHzJ!mx2N?gdmXI4jOXm^B00S@2JznV2CgIETw9NUN5C5#DrA00Bk ze@~yNTIi}~wp8a`A~}0uD9tw9iO*(o3Q*R zGukr4v4dpNeZ<=53i2V55a4A&7%_Z9LxYi}C?>pDYiFnaJrPRW%N>I6STNN*DgAm& zE{$f-R7UvAzlqCl?@&$kYnLa7Rc7&ru;jN*1YXBL_#B%GSWq}=Sh)W{uZe!eojMl( zMbi{@SWZ%XVHjFOgp{1_to36;jj{5O5#XA4VGQPHL5+E6;ejLxR=W32PhuA0a;eSN z?`Ln{HoujkUywpMO?hIXnetQM$h5>-8Ps z8S{=He$pkX9_(D2#q{!e6g~)v;wT6(b3=OCaIIN|zh%hckoFjPXVmk#KY|U1d95P$#<{( z>Njf8Y0PE&U#GUf02SZLU;FXwjpq}S;9bJ@dCQb9ZGA)IFfAV@EL>P0m|ctvDLnc4 zUZpG9%t@sAGFB&sS->Cksigon86Q1dXKiwBPBqNBa@pFHJ7G_3*m#|fl@)J;&q?-H zE|ieW#d=S^sG~!!&}oByfwZ~?Z%Qhc&0-S2$N$I5vm0_6$KV>Rz>eq9p+P7jcB}AN zx1y!ZXfUW#U|pl=lFHcx>O<^+049vq{p-9a2jY3yJf@DjQlS4d`~}Jgj1`fHcz?B) z$=J@*W!_7&sa?Zno7p|+zyK5)ej?ipdI$;~dL;+3^{H63HEHzr{JSO2PvRNcPegS# zg1$%fa!5WeHN?1(&n*i6Gdp4Buwiz4K~J5|5B2cpkq!;>9)JK-UlHJuj1#$yW% z;+1hSc2w+>IlT6wk6;F1ip90Q^mZypaRa}e;hTaX;-rC=wf%P$qsaKe*FDw~GyKL% zNAP}3oeoQ*7e-o*oa`Lh%ZZx_(?)cSp*|fI1b5wVn-+E!ei!4;>KX#)-|cm;-(nU4 z0gM0jDXDOQE$s7q2|X%~|Kr?$8H=(Q1S=jVb^H!y?f#&4Yexl*%@51B2)Z;-zRd5V zL{G3sR%ci72hAq-A{ciaFW z`Ex_XH2pD?{+sQ}5Ji zYe2N~3k6)jC8l;!J_2mQ{b=!aLd9Hv$Wek}U8}j@`u)!THo$`SZ0ls;klD)MHP!sT z_G675$b#M`5lhTDwyR^`ISp?YepVj7*gmXWUa@)G&A+d{_wxL(8KF5DtOIBx_BUM3C%F}20qb|1`zg9ZKeheY88 z$?||`-@^<%CjdS#BB=Du`3|;D(pdY=iOcohL;(Id3H!)EI=`ErT5@PeA%whcx-XIspHh}lnfpWyA_J)e4R$Kq%=>z_=a-1vIRZr)~90?a;T`$~y_r!ocFuydRe|sMlvA*BEn)4zn#q#m{f*S9s z%5N#KX%>YJVhcZ)L#ZZ|Eo%YAS+-;(Uwo`!yJr*~C-9xp&<JquK%BsVt(Z{cyx+WvHz>2*Z>dXgxouVFpn@@`|ng= zaM4H8sYD`oMhgp+vh+tIJ#F47YpJi0#ZXgGiIt+Hi@Bx@A85Dme8aj&PKZ%(dCH7K zii@-)PKZiE6mK@Eh$-R-b}rJ*xw=J8r{uu51L{Ocdif2lBc-m~B@LZ%s{@83UM>p~ zjL3KIH%P1nB2K0w0B+D}a0TdU=wRa=XmFlbmvT0 zIW=1}es~W)T`^I>5|M6d)|#xN@{9jQP%Im5-($r{1@812_NccNX45 z$v0OW?p%-mANUsxfXSnyp+`m~IijyMTlBzr3x`s9bVsS1mx(2+M?Dd;?`XuO+n@V- z--dswgumTzwy?BLvUeVsX5gfLxtB3uANxrNBo!d*eVSj~WR_2{fJ4CClr<{|Wz2Up&L5bZ zaMg965XO)jk_?FFIQ97%CO93M7i2WFP*Knlg3L!}n!`^75)(Mi0-TyR0S53MCl)tY zfsb8J_lx5@M7O+#!Bck}T1EC7jZ#3<@e}0!JKeyDkdi#l1rEIR4r>d`kCsR!@_8&# z&(Lr;89M32&w!Ed%bwHK{bu8rK?VlOWsRnDS=iYf#$Pc28UFSP8 z(ma@;Yihw_pe4)kON(jECIIT|(N;k`c8x*9S-xIrybcbP9+0-|9*S$ux)#ddDcN;i zvdDCY9Gi88FJ+V4f-Lkcnoau3#)927+{?p%XbHhv5vE_jf#w|=PBfb0yICa1S*lff z+KF&P#}qnHMiBB4B_!WYuTV+=d-5MF?{{s204m-+cqtAGvp*{8+tvEsLY#Us5eX%S zwxx-hz8a1HhLTVZ=7^o7U3oDbEwK0&ug4~JU27E$Q-l6~B^!O{j(BJf5x|bMqWLKa z_SE2`=y_u!2fmU4rSjtFq@)&lQ{)#VQ+p8+J)9I`#~De{kueL;TB)yEL&q(z;f)ej zxm#R%!g#TM#P9wX9{^6#8>uq;^pInB?!l3+x!WWS_@|;|aB#@p>O=rDmMH*4y6jhhEwZl)>d&%V=e(G_&3zaDR6&%{-Zc>k35uuN?;Z|} zP68+b=Z#?=g5E>>LXrZRtd1ob!=iR9C{z9s{ESdO#WsrP$`{Hy0;N-{x$`|7{3bfN zba}wlVI9`QU<|(8wtQKSg%$0EySuy26S!Ht@vchMJQof%wO8B;mrq+eQ)OW9=kg`h zM;#pwg>qo^egEe_kC2Ed%&3#yJi2Gq^W@o?DXJu{_D-ypUU{@sJq5kSHw z9Zcqg5hIz>sAY8WtCq?E3lWg&;&}3euhz?0mBmDG< zKANZUv~_sl8Xxi(LkA-t95(sg4?82zztVqS=5p2)7^D$|-}AGrewdWH($f+?#udn3 zy|tk*W!snEFHv|VyOK)dY4)!|A8pR+QSOij4NfOaN!o|n#EM3f(cqHsq@!_pU8VE; zKiZxp7I`Kbz(0XsP$9oV&9w6Kvb*3pbx80bXe!g+GrO2XtB8tZ7#oHazlD*4ndM@* z@2t-2dJFm%Kh^*=W{=0+DR+%bhUb48gQsG%^xbaHq3?PzV>Js^;7UL1>r#zx*|zUl zhx<}+5BOac#`rU=U>v8Y`DQyOy%t_O+%SF*KmO!Ej`mvQ(S=kWc<6s+bg zT1JK$!sj13?($h4ZEm&-$Z19Ui+SK`3HU8(LOcvVKi9;+^wA_`eoGP?VqJuOKUl_+ ztZ@q5?Zjho&-fPtO!)-iCB&_k4m`r8do>`60=pA`9KUGuBO>o6ihq4YgbkY(_;x?2 zLk83z24HGe6IdV}p{p;T%?f6{%l!^PjA*-q`vww~#Xuu&puT+Bm1&XGtfn#aM{e>S z+hV!{cq7Vg0$10cDjg~3T3;sr^`@V*nTWOPP^8v$=otwHG4=eK4C5=jZAb*7&zHD3 zxurr_tK`?o44wm@h@yPyCoYswxjzI{2Q>E#@!@w0Yi_~9d9oyT(>_Z>d5Yb9Ec&1e zpr-4(KzqjCi-q$c-7BNO?wmBb>7lP8v`Mml`)aH=dQ^l_hXSedw5L-V6V=s~o$6A! zd^PIQ$nq_7-Q^DP0T&!LurC;6;Vxc{d{m|A=^@TKC19H&$`^=GY={V{Dzp5HWDA@i zM!-{e3EekG&zHjGn;cz~y#7UBz?_97TBND*xtb=kX`ihN(ZjRMX7D*EF2G$srlK5FUP3Y9 z=DpJ2p}+e!jvBXqz#3X@sI8I!+^2OtA(Jak*DZmZ^8J_89sM3=U!?J~b_7h7Q@2IT z8=~hy2EM!YF|sG^4%5K9+}n1YN_FkN9^VKBpwBSP2I#!P{yFLJ1Gcw!bm8-fg3lcM zUiAftqYE*xPofX1al9@-_@JDWS7Mbgc#4NR7CSpJKWkXfzcd4gEQ2l4y zefA%X^99$OZ%@R1x(+(M_w3uJ?Wl93dIKI~iTsCRHT%Bw72ysuUFUzRp?Lzss`v>f z>)ZBS*Lrn0PdP6)CepN+pndz!3N@IZ?G}SB<5LaTP&nk5&6f^^4DSqZej8kRnX|pv z<+q{R;PZq@jHtt5|6Z9_P751D<4gIIRu6NzR08-t2K+9rZlTx)KFgyGB3O^Iu}}M9 z0_n2v-l${JQ|NaM{lfMFGvL2#G<|$Q>a8b=k0nF9hPc5XE&K-8??x;D;TzChXr@it zQ#A6qk2deh{8%R~kxJ7>)mvT?Gp%TNXX+Oaz4F0Oy_cUO-U?%Mpt`8R=Ns4L&ZSfT zR6aIeBwW|P!N4KYbvuC*_Ly?z-60Hu;~?JzO0^~^#YceVm5FYUrf^Dm_6%@y1ZD~V z2$s8Ykk9FJVmN7SO002R{++9762osf^BpQ!9N}B-b**_psCNga)Op0d( z=WggvlLXal^tuhKw7b;F?XyKCZS-FzY^fm?1936j4U55)?<9(F`WzSf%hC} zAPKZNFs;!0hJSG!tDlSp13c7^4>~T?3JeU9^rkQ2rtX&$cHCZ4W%dfRS*C}|m$xEh zivKB_Y4|~}%v!Sqb5r#@w?T&GQoB{q={FXGAJZWyJS*x63wL-2xw`V9IJNnlW1vq2 zDvob+n5l#qbx)F|)1ES1Z(%6BgK~E53CqrqGx@$xi4!Df&<|de=+mX~VREmbQ3-2U znSChYpm=4mv#VdeC9#L$sGE8(8(MfcSo6;NGFLekK>V{zEp3njlNDGH-Cd=XglD+* zd+QKLCz1~a>a{CuB3gKs{SNjDDsFDIvtOf{o9XC(V5d^^?xR5ryX`xS= zea8%e@}TLgO?Xrio%_>(RgtH@UCS8Zi*U72XwSA%TS}mR%Tc$msnjJAY&BCCuvE-* z7kP0RfC{OdL&1;o5AqVoN+R?Urh_W{Oi#Bwx~`DM z3kvBS++cl|ujz>i#FH%HeBbo01SDjGI?}|m6gOIdBa&axy7nZhUHG`-&+ z6vOS+Lxx;rL_3u&jQ2Az$lDW?;tUqJ@1%U0ked*{x;+Lco-m$ zcKt5vE^UD4o-k~D!S{|oPW-*@&=BA42Rlsg8&Rv*7s-yjsBolT%@C^!GJC{j zT_^xBHaiLt7eDC``8=SE=J9)QMsZPZZ4$Y&mcJuWr6Jy0p)d0Y_;GxOm;+pVBnJJQ zV(@>NeK{X8_tm6y;$;YemGMCL?~a*=1h7$yz>m_=<$<>F8I-Wmb2fi9WgMeHvXg&Y zOLD7Hwk0|Nj5nrnq@b<3JtpqtISu7~{+cGL7BIlv1_(>;91lV45(9mbau}t$si2`e zoBm~%c%oaSEN**8LdLi$yr6XXl_94wz0si~=yVbRgU~x{r5gWl`2xE}JTVBvq z4mPKt+aDY6f5K-Ywh-Xz-9-p9)!D6~n37DEO?cBpwY+X>|FcrRw9R@mpto})3UU0> zdx~FZp#t$uYWq8g>)cY&{fRw(>b!BjG3VUN+|R07*-hnQ46^q}qDGxO^lR{+jy&s; zl&o0pS8{mWQ%ujS^^2p&%>^6Bo2*dA zp{n6Unvd;1Ebn^v%?~QjefGztXcn9@*?qZM*!U8k2K?_^k!gmyj=l$eSmw5kIb*qJ z63cPB9zeF^bbeGEG{vBXgYKHny-ib5r5bH4iAQ_hL~3&M9Cj0tAPIVq$ZMgV)E zuE;0s_efqo#>&WTuM&1B@pJjT-07{7;=u95Z&^!PT>Ny!;ZPnqq&RR=(Q-~x_G>7x zR5vkBi9uyn#Z3Ufb8~*VOkcF{72f5BrM_M2sHM$ageM)R;`8>LNukX9g>G-EZBQw9Nrd#KI#_^(0#) zBU|7aRQ9REL%C!3R&+;D9gVrXbZcQ}@Lj-XQIxxJd+co@J;u4*CgX9=-*NTd@*_c@ z-Y-VbwjV|w%B;dd(Y%;xF)?w}FZ-KM5#guzfPp;kjpRK+pF=a1?3W#lPSe+yS)6vu z7gh>q`e!ogG4NkI$3-q!71v$Y_@ybKVPUdwc z{N=^a6fR4gy&WoV6vXwHDgT>U)jHWVLp#6sTJ8S>88l-DzUz%5oV_Jle_&ecL_b1! z(`e^9h*_WZ9Jy10GBdL|uvwdvzFB6>6k0lyOwUpC zrL#S^GLsn{1@m&*btgmj6|{BhPknfN#!g1)^mGkI(_TFiR9c!=iS%XguB;|8`GLfE z?cKZ<-dy=V5rf9V&kXKYG!iQ(V+$o1Erw$i@&wE%?(?38UJC1@GwAT~;x#IVvH1kH znGEU%0S(7ZiO@mNBUR74{^?sy&;BohAcd9!8tRuH#2{rSLrX=>h7hR%c>=-A@nPSI zXexAT4f6V?Ch9{~A2~7rm__Bk1=GJr-5X*M+na5~x(mY(_kf3q)qQa+Ba)-*$ym1w z^oo%>g*^6|#EAX_K<$mUpjV&W-I#%gJl_XvDo)ghmzc9o<3TP=Npd6F)QTZX1{n4Ot{s0j6pwS7k#eT0WUa2&zgpSO)?Tn%V$=TLFb z?z;)x z-0?!43R^MspP&0(vym`ExC5ceOUhLA1|~)bBHgEfrtnv(7pUyqA%q+}E4+ow_VUtE zd!|ano662&LjWM97ONAnH^bN2xAs~Yh=`+}Z>|`Q5+<$ut9<$rsb+*w*)N!euP2fv zua#R&FW&BnG-{1{orhM5D?XZM4jeG)fBY|5Fd(H46cd9x_pHQ{R!?5S89q{B0}5^)&UJY^Lt zs5&W==^p2OawvXWQoe(C!-`5=pcxZqA<@kU$pm|dmNMs{7|iv}hcC=MpnAdC z_xptkbAm%@vQI5+`}BZ?WviqqiitaZct0^6D986wf>Z ze0>avuiAHg&wbH%oWrN~a_{<~8IM}h#@=2EL1JAz+_k5X9KRvs9CEM8oTQ{)n+dd3Qd}cVOX{*GY=IX}iAH4(I=i zyZh&!@of(Q^Cx?O%G;zYmAdQpsGS7PC(ea-X>0b&FBdANQMfFYPU@*0|GT6iY8=bPT& z1;^xPWLP=B`FiEcZ{B4nY7*k$eAQ1SjE;3Fc}6U_TMn7!KVFR3v3>$HbeoxTHGvUe zr`6pchS(6lhC>8{znQ2ED7MKD3xnq!RFew-9?;{q+K;p)!i%5(aFX5i`?~8HlL7n8 zXtXhi8|~rOT?57^3RUd~0SerTqx3=G=-1202s!L#uag5LI3@enyQFY*;Y5ZxxDL2_ zTOWJ+t#eJR8{|yIuCVq7-5#?8(l#r{k|wLoT04bG5ZpjlUhehk-sF zuw3{@G-pm;#dUgTw#Eg0v^3hV?v#ClK&adBO%7ToUbUWEyL4nE#tf?S^V78umn{oW z-$^PE_;FFz20cJR5(5={5g0c*q{Wag>Z2C8^P;v_zHDg+{&!B_9g0{+wL#q`oCmY zC!&xWC|FyO!&qWK7pFR$`3bgJ{T@LH9vHlR=2dya&3krVmE`%gA(XF)HIu9AX!zo{`MQWV~TpjWDQNyOyt(XLHBLQp8` z3Ia#AK3jm}51@oY8-Y*ICKN)8eNCuv5R6kw)$yf3l|l&&g&1z0=P@dC6zu}Bb^uMq z29!KAb&l>u==$V}Pfr2K6t0lBA_3w?{DGD)%)kKWxRau}xr8&{|We;5%?lhwfAIEiDOrXRt4l3~lK5 zjJ)_$VHdZ2jRQ4)r&vu{4+I#r;WKI&9h;n^G+tBF-v)N!C|omdGY0}Q8{vH7@-@fN zJeq7sI@nei58rZ>GU{UW$9@za$k&3l!;ZTtWm1D|R9c&d_GgwvXS>Z1b_|C*nd!Fd zt}o+WLOxNDNpt`>Lmkw(I3VFW(7Q&)%h7Q~;?DbW+)KM%Ap@xDeJCwf^&a&8u>U>S z(a8}@oxdn^DKpdh`C>5r3#J>GgrOQ}qkLkh7uREHrMEKQDtFwt_Zif4b~QgQb6nfq zbR%7FYG#^b%kKHB%X`0##@_Y2*DLNE=f$|!G5g7b_gn2dLvy*#MCsM7oXzqiX;8jT zmdx8zr`K}F3$uwF@ZO_y%cBah7@BMu@h?T||9#T_4Bhl1V4JIo)ZT?y?OC0s)FP8` z#rI3g=ga59K_9~xUdN;>v5_BU76-z4+CVvpq~)6VLxF^kivdw0HA4YbI$Qjgm_dj) zxX3T%=bifgw+xb;<8FrnT9xfildchOZ`PzW>zxsHytZB?XwfI~_$Lbhomy8Wlh=FfY&+tQm4{@P8~@V=H28CUr5AnE z=#McTI=9P`=7NnmcG)3&ex9Jl_16W7YkK5c7+QxK@apFwi*qbFd49Jc+lP%_S_(K( zI(g{sh-DX1jif&HQLJuUZZ*C($5pYffVY16iagk#jcX3%tLv|u$9o-xYj(j`rSsOb z8ArkDUlu*bM}>oLr-yA9n9d zL5$fSc9W5LN?_18ajJvhz^&Kbcblm0xuyUeaCUt8^~YZwh#4+>WTDRmJ3Y`zCvJef z=E5%>I(Ck?E5k_q=ZI#RG@}&jPir7=)Oz= zu>7z$%|hl~^+FeQ=a~#=8hi$>`cWpwhk!232s%?JX zunp}&@II${Y)*9jR5W$j*g;nDyDv2r50wPZ21-_=_i@J|M;2DewKNXm))@!WGSBW5 zMc40mBWDUhG6E&N?njVQN|U2>U@gHy-%h*}Ts#IE;XnYtnV-*qEYk8!%DhL#B?nuI zN!4Ama`PN+wj&dlPYg89CQ(1v{3w&X;5aqS>0usNq3yb>GR(Xk!oCAP4|M!RxCW7& zm;6xg2YlQIZfIrODBtac-KXH^wlzV^h7jBNFvIa`$;!35wbC3IyNYIp1K&Asf=%^` z+qP!Hj!#ppjMS$pT*iFRQ6U32>F5O(A?wwI*_l zLA^meoT6GC2f}7HHu6h1im#KMPrQElt*yA*cfan#{NG>K-|>eBTX%6~TjRW+`N`R2YpEO)-*COR|@VXD+JIg!u4 zbiFgYZxbH!H1`OG$nVLEo&AftEC|CW(9;)9wHAFozG)hWO=i`n!rcAPSFwsozcBr4>dlriBX{>XI^(#~^gg z%k85N8DX5JHd+@dNjkA2vDhXq4At~_I+uRlj_hNg$jRkO!t@gN6mdNqUFxZ)ui1qL!J2zvHWNr=a*>ew`T8`{q-hn+g@~; z!lvYoO!{(=rf?5{cF^<;KCmPJ*dN1VZ(C-`0V97idX(8;QC8aOU6mQaCUGOv}k^5qaK*|t{|x(pXhscZ{J5C4zF~U*d122IdZeO zT5VP*Z4*C}!vY0-km4)c5ymihPr2RAFfQ{GWu2}JET2op(8s=H-19ZKe8A*enGXhx z3vWan@PcKvrjq*H!|0y(wdzor5`d#UQY~_GFUP6(Uss5U2t>}4u2i#6%$M&A7Ah`o zZM)g>>kTNKyU7nt_u;o!BAw3P0;;1BJqJCuc3PWr?n|W24(6}Nc8|slkj|kpqd7k` zy-ycLE_uwwEAPimu~6vV_!HR0v=PfS;o`lS@Dn4|^6?E4fb@JPNr_u!6K2OyuH8EC=isV_TAJ3 zWHSn^6@K`9@7_%zD@iD^C~oj2f}i?6 z@l^}?Toirc;{3m`wk~AX8Dt-y@FR`6TT`$Hs6lD}faqPAdj+=KFBK9GK|M)b_0hRs z=ty{r0|ZHynz@49E{baNKaeqojV4g)V}KLSvS^v;)eGlw2ijFi^BBccES#Vd`aPq~ zEZ>649PJIBz?8~|!)*YJ_TUe+**wCn8I@Ho#H;vZl6i2w(EWGqY%(C8TNPmty;AXtKi>o;gK0ghXXJ<^gKq1mNz7yEV7^*V36N$uJ=~O zBgXhz-;a2^fxfuO*Q1cAh;saPF@ecmTpB$q&?qPgED!>RR70;w=b@-)cWN)=9by9O zG9y0N#`VS#!vjj?8MAjo=0|?!ls2EoE6h6P38xO&}@3zF+?HQC3`s-Ah3--no(9Tj=G2+ zpk0PdB}e)?`j|#Qa${+AvRZ=jrKvkWwt%}Ab<#z}Y-P@X5&58CWp~|nt0}CkPtM=t z2-VYPONp!yC8^;TpMmn}aa_82_4L_(JE-!RY*#I-JOnJ|&sxhOGyLx-s2Jx;8T)ce z>#qABJaWb}y?f%XWr4&V{K;^MA67HE4SJKcRs_ubsLy)`5B%FbEd2=S9f&r#qg=3n z03lK&qP1~;r@5)+^)R7yglI0n!cqBhV*8KuLh?4NrTFp)|E2xvwd*~%3GA*xf68$l z;|zWVp6fg(+jxIWtC%*i$Y|rSWr+ps}J4k10h`Y=0 zoq-R;^U~%V40!72ZSM00_xY9WHXa`iC6=XZ#5L_kt8bj2wATMc8JuAuRCp8{KWkO}wJAqd1?zl3*ura0JwS1oH*EO6Ia?#v#l=EGSw> zVoZmqMsN_u$BM;&NhEF(ePgr8qx5}-D>>Hl+o?e^&!X+zuC9+9A8zFMMUwEWBwBJ~ zKJfV*r72+Dy~2lf$W`q2Qpij3d^|_1K|qS(SdApMr60z{I*Ykman|LBP>`5{mvEO2 zi=LkmsqeKb0oB#?xZl0~YBuaPGwsFO0byNJ`v)oRM$1soUVUxpV!ymVBPaC6ZqmGI z^s~T__y4WcHid(rTJChRdP|eXmv7O81u7&3K9=Y|O%BR1v8hUR zlwTKhG}I5u8+b6fxfgMpDdu+luPz`80wQ{o-);M6OxMF+AQHT__-7zUu-JpP-GrCo z7hm~NLKtA#c{7yOkhL8>h%`yHK3Z5O_cJ|n-aqQx({b@cs7h!q$JQpvyrZ#jVDPa> zAyR~EXxlAj%qAy(j#YU&)l%s>5*XByQ**j&)J!-T+^??~7iccmhA=vgDzTkBG|TEt z%t>hIa{DAVtdd5LIk%;)r$&fA!z z8^_>+ylhp1D?Haw->~!wC}~`cz&EL-9cRnWofQT047&YmYPgj%pHxE631Y_HZ)>0Njdo>0&V* zZ4GC6bgzxm3Duk#UAoBtJH4LVY?1SxHAMK&uY9yPrmLrB>f%R$^RH359^$Hp&&ldv zcc1rlTs01@VUONvqB^Yg=Qy#ZfzL;u@11sqxT`b>#`8qUfE}!~2h&93TpRk5VA1tin zgL)gf&QwcJI#SCNXN{UIAZr4K;FfCgKKYU~h) z(*~r3(V|?=tPpv11y=^?ZXJsxSK^-^kfWxwXv}7(ZKuKQ()XyUp)ZGf?lgQ^Y=$cI zyH(lfe-IsGUfV~JK8t{-;K0oKh*~{K3ir`Q53HEP*1;0OC{>8wuF&UzUM1SP=oGi1a zC--sImG`Cbj2O5-7^VDmiA~)6hTUp5PEhZUR%49_gZb@Ac zj;b`>QJj~@B^L~2S!9)vQ*hXbd@GcfE(h$y5vl;bAKv)FHOgq;=~&189^BS8IV*IM z8pPd0!d#Rpj^d2!IhzI^w6>N|zP)4o7fKvn%AEpc)1P*wrb$u)QK-9jj^{*`)*9E_?IHgtkLKv=@I#cC#Y7~{b0vU z#oDDHncm9I8Kv7+692*8qR}DZy{qx8P4x4)i~u|x^GD#-Z|L)kujJHnV#ZRy_ovf) zlm_qDlx?7%I3p+T!jCiktCAU14mMh&@q7Lji@ukHYR>D!xA81)^S+n6Ebvh(sBaa; zkKfB0+C59H|DGg3=wmhs6~k7@mMeA+(3EYHNZ#44!%{!miHLOhHTS^KdtC-=InLt^+m!{4iFYLqcH_(vkuABF%x|+sbtPN-Z!!ecXrt*WejdbA0x$i%5D-f%~ED{_ya4=?GH~Gq) zOZG^3kMDYYWUNdrFx*R(*J?aHVd46 z*~(i2^N`dZC~9YhrnNG&g>JX!SyA76`-@cXwmoV*W)k23#;Gr@Vc;@Y`DN`fG9>8S z&&jgWmLB|G;*R|LqlMNKjOh>bDZ)zH;ctk;v)ySF_w1fvMzjt0A-^H*<9Nwf9?m=nm%&m<&SyNupNt}i(|~YjVn!*+H{=CO$0i$+keaU)sPC~{OAQ6 zxN|47tl9gJToxP6iikS=-ZYkqsMb%epcc_%6drt-5%>q`5^IUWQWH`3Xmf(83qg-H?@MjzAlCEAW39up1;OKgl;>*1;6 z)A6Eg7H(s6AUVx~Vk;^^yw{lIz<`aA>TEq+29m!9cY|_0&{gNb^IZ2tEQjBdEbm$; z>&h{C2KJIul;mM8GV5FZiv~ye{YnS}%Ji<#!a_k#`)l&<=qYK^Su`|kjQI4#R@+ifLpcC4}D@?zMg)MSq2=Zp3l=;>{AtUX06U0?r8EQuq7AAvVo zuQJ-Z+S+DoAQn~nuYcj2i70~B>h$WR_dKaaO_}>ZL0KreKL8#do3l>o*q5 zzKX2v|MZYmx=7K8+f4Y?U(bIiNp6#upm@GecwTPVlnd(WHIt?AjG+Og+Cb(0hES zZ25opeYTJg5HY%y!8gW}-jF2s0k&E>AMs)5XE+Z#N{`NcgosIk@3J*N+o3Szd8|Ut zujeA+1ISugK!<8Q0K{XZvAkW}yb zujX`wXV2vXKGMmpwfQ^V&#j2DP|XRC(DLx)AC#K1_-Eqk@?LbWUX1h1-_u-dQV?BU zI$Q?5cWroTzY(7KnldE(Z0RT>9-Ao+eJEr3*l!l!elhBb^Vfr$@<907>QX@y4x;#K zaw^6@vDfw2(lV&Pe|)7Uua2^53W$w_u#VN^NBh4*T^q9UHP3gdI7E(viD;v zc8>w)u-B8e$?^^dpoIEe%gA!B3uj-vl})4XgqySVqe`ngJAm?WMxT5KRaUlJls(SJ zeSrtUA_s%{VKi-J0bL!GsWzuZWF%WB{;ZCAGHI>FPP1Bihs(@EL)*y3nDIYEE`ccI zohC0>0$j%u@%SP^R=}E=O;weoavrc&hW4FF z^+!@oqs%N>2&+`>LLN>Mo#sS5+A75sBknxgnPEgan6uU&v>>?SYTB`fQ~jUU+VJJ; z|7kz|gJN3?Wq*^p!<4^CnR@jgM9`f2y)TtY#LD1(M#si@w0nt7y5eo`^o4pb<(Z$? zdnW#(p5`H9B?+1IcY|>9g}fA>?B_YWyi;7p&HcZ@1|A_81#7f0Q3pz9-PBJm9e713 z3|s`iFuQGL|58xHfgIkv!e3WsmS98@x&Z2N*=7Jv8n!z|rht#Of)REi)=<~v4GsAG z|E7F^hyYmdp~sGfpUBuntC-~k3JvR=vihN&E0W3$sv-^SX)W!g0fp2$t$=(Vh1^R|0em@$ z{qGpMKmROmAeahN#gC0KXx1O*VO(=IGX5YnvTifpx#g%P<%@tvH`m4?KpeiaJi3FY zy`3%>q=@`~>AT}UDN9ce50h3zKEuh_)XM|=L%^&Kuho^oI?S~4$=4m&gQPHjz= z{~dFyu0eSCe+(CYe9jF)APwGf?|7vSH2COw=15|qNDBjyy)@W~dKsE)Db~3;`p|4R z%|7CeCBl4;rENfDj9n69fQ^`?cRr-=ztih71&LZBhU@)-GIq~GYQ_jjybhR|3jg#@ z{}swH_b0uozWS1MSw!zwTYQ_n6H9l7Orfzj@5EZ{%eFj$BxrJ%48xhLD`M zb72i3Xqk9za}Bj9oV3<{HQ`FyC2gBaJ1G^fF^ zY08V{m296P^jgJEna^mlq=Jt8->hs|7#Qd2)m-hRlhw1}|2#CP=%SC- zipEtdsn-prruL-cL47K5Ch2oFwrZ`z22X-GRr+@X?XniuGm!$WI?rcjqC-mM$5Jq8 zOJQJOsDzX(q^{d}H)}O)mldD%vF=}Z*xA_ySnj)&!Bq2R?Zif5LdWfDF>-nrF(0BY z>J)ts|BjLkADEOCCqLhD7i+};vfid>E1a5faxN^U?lh`})RZJmfe&=VtCZyo%Kuay zhCukwr|esXTm|@^Vkrl2KWwS~pOumS$&TO+0;QS^9waXX=kFYiB3s|C z=LW?B_~s`(YS{9(DDdN^nawQ%f8)_hwsLdFrZ2^mONGUq!F$44|NXA?{?flfO*mhZ zt4P7bJjhjUGtR|)jq-nbd1*Th>)hr-IYPQPJl^uU>wi6TwbHEl9hz^VKI0KLh$$P| z@NrsO!6+nPCbxK?u#^sKNx$nm>gBa}glnVe62m`Pc8I>_9nyR&G6fYp3khe(;CloA zwr;Dw0+#EeVFx-h2iu1!i~gsFhw5nuEmTIWr&$@&3u6{F7BJ^!Xy?&KESp1Nf>><4 zsQy1{9qLqz)%`iUW@^wjGpC!SQ&DBCfINL391YyjH!A;>?4du(-l$Bz1kzx;_#t7C~Ohi8>&4GoR59HlQ9=jzHKzaV-q6=G->QaxYxIEdej(_a0} z9&I}v+vC3kTc*%3P>kB+*BU~$;p;pKx0`7sG*Q!$Yxi>Y19YrSuP7q5IPGe2Rc2Jc zNzqabrAee`kcj)7ZVM~_epV)7pRx|6ABHMeKSUx+QF?>#M@a1cU?)}k$icHc=CgLA z&w{H`0;7K=zTpIcodQ!9A0h3ZLH6PL+ZO;HvUW{yP>^`}>HS(itz_6zWT8BP+|sf} z94a=|ni;g5G!UWteJw~ejx*oD(6I+nXI1+YgCRtKhmDif;&iP0Ei+H{lHYExsdyD6 z5sck~Hlm5}o1pvqi{XF>1eG3-6VYrG5g(PP<07H#EoAN9kTqq}QF{>~1Xb{~9$m7j+{QIIk8BSVF6oFD+)Mm6)WBt2^4O)^{B(3|bf;1K@ zgGfZnDI8Abf=8d|PQ>7&bnn{|%O|#o$ZS{&EGZF4-EV^2F%NJ4F2)mjkb^eDj7GVM zSY|tmHhzpQ*D0g|+Gfty-A8iON{Z!y|EO`QGGnpQ^ePkU0P4q zjL$BnPD!9u(6BNp-V}bet>}u$FgA zy!_c%eC+$vnw0~!LsKa$_5l@z33O|?YZiTiXafVqdIv|W%$NAMUtYwADik1cLH$sbK4Gu8>`ZlWIAqSfs9)Av@><$<;lPw3*b?C zg9q%pct5lh^U_KS))Day9-%`$(pk?Qbjo{e)lqXJ-rQq%Uw@ryS>E=qN=xp!uNiC& zmEf8^ecJipF6h)n*zuHz?7pAHmGCE7h0>uAB%46(TfXsOiivCKgtjtuxBFhPycgM4gR^3YK52#xD`L4dFE@9ilWD)q+pk- zZJ>Ot2Z!Cy*4f7kw#JZf!azGJno=yPwYIRRbs}4_L!U0{!sF5=8I>kkQ>@5M#>z+t z1E)rDU&1Ky=N`HfjXBLXl%shdkS$wUO=b5!yH$}p&Yz{xb^ZyMIfnL+8eJ5R82P&o z=!ztX9&?}ee>T@yeb`acqVXVlW1V$Dqh7~kG_z9jjgh2k~*&-g+}E=U+g zzUN>3ll0~)LZ|*glTO1*v*fyDrCX0h;-45-s{{MnQHg*sjO{bK9D%W`MjTi8giM5|I$!ck}jD~B_d1kl9}EV46dq37}F57preoe=^reuwG2}H!|-gu#P2{j z3QE~^I9yc$B9X_H5^3KzHP25>+5I*09QQTH4>{J!9^pxfo10_D;$SCroXV_FhO^6b zzt+Fx_$%+UHkJM&jSS#1a+Z58O#xe{kIVm##y$Wwj850u%^N81}92i^kZuatN2-`;3sG z;gqwKvC$;^G^mIUTXt~S#2Lz=#RXslL|i1xA7OO?f@Bx^_S<__*VH^rTt+)n%vl^3 z)(S+ypNck%4V>y4mux67!~2l@U()?iUJxJ?0B9C{B>RNCu3cN9ee8M2B6AVTq+&$% z4MgdKOTDgAL~y%IUGWqr>WBLc<=lQpmuL@EvP z^K}5UPsi--Zzi(A?Ohy4uAo-@_E?40+#nc%A+W^eZMHWPF~NKqWCL1ATUmRbnRlWsX4jX@wQ;8*HJ9+lZHG2zp3GK zbuKizck+jDz~0ub1zU>S9;_u^SJvkP7B^H5Z;aFtn0}(7Kr&zh| zmqDI6z{!%XP*Iz$WfC&vqy@AEH2NpD0UT)(58?z43; zl?2IJbM}hZFZHU(OkgqRscx(^f5ev=yOm;FzB5#XFyS-Q@OX@0kcUv+?PNym19sP7 zzqD9#+|gx@0*X3KjQ1jna?T`Ls)bvY;|W?~4v>6`NOV*#IA^($Ed|ulxV~k`7M)SD zsuS-QyBq&7SI7TQQdl4I5QN1*jZdX!GV7~QW-5|%l(RBXx3%AbLZ9d8Ez=^=k}??m z?Blq;`TJC6Ui9%u;2gZxq z)=ASDJ_D{+Drl9x>7ecK(Ct{yRJlDq^5fQ;=&W%o=AR-22l>!pl0Z1w4HGhU&s2F{ zodYmbbd$NZcTmEhmh;lnP3{ntu=lh~Oo}n)!T@>?Cb6M%q&)!l4=yZJJEYf^hwdw1 z9m4(Rgb2_rOX244NBQ_Res=5@v|U*Y*}c-QPX(LrQl`lc7*C!2^VUEY|DOnPXyTc! z?dZ`5ogjryhy6%d*CCvq3^6Qt-;NHx>qf7O4MB^Uo12?5yj&qv%rWu{k47kod(5bN z?8(cmkT*j?^kUpxX0f)$#*$tE^hUu)CkBDGuxR!g(6Xi9)_$|oe*uqOnF2n6H#Jv| zX(Op<{QfT)A75@Yb4hN0rXfhQVk6tc_rj8#E{Xp1x)j~xTTCahk>>%EH|$07QT{m+ zp!I$*<%EjV_V7aarGtH~x#-@4(@l(T&F#J8{R&r%D~s1@MB*9)S)zq zK2zsDhvxShK0!bTbl+*yq8G5$Ze_H*%;NPN32w0QelJX1+t2juIWjnJd#gs?gU9h{`R&QW1N2bzZ8;C0f%6?tP{YhR9?za(`}^GdMtRGP9jdbX%=_VB zFBhlB4PJ_u^~Da5KW%ju+Af(hdzI|3s!3b;Bz4{wEd-Ky9v`TW4UbU-*H=zPi9hte z^Gv}+Cuz3HJJ^@T`vSZIuN@I&LH&W~Duzb<7=wu&{#my#m0%Q{M2 zWvmhq)B=3v8X`U(!8qI)@txefHJs%IHX%{guFv4w32w~CT5{vW)zQHZy@AKTblBH0GN42}L*YJCz=owNU^fN{ zlH=M0G}#`iD0nKS?fErp!89~OpQyd6`{SuG>IWbMwhh`_rnOSZ4t`c2L}iRsn75_J zLNE98Lrx@q_tC0*4*hiT2Z2=6>1q_r{Ec$Oe8ocdl!zreJ=4c7(b1D*9HCjA2pr+40%|88((ahqzPM23(zXO7=MH8D2=5)W!RYE(8 zkefhzK4VDaIF$uK;5`|BO$GGHH?65;5Ph=&!=nK+L%st1vd?l8&x*~MLe7U%JH!Iq zDJ&>}KSWSYgv{Dj7m(jg8FBUUnj3L)-Wq01>-o%MD$w5p$%BQ{hO9+2W2Ug$K}VQv z9>3b+B%P4@^^h715dk4J_VwnFS*#2ZZo>mLi4m%Hyh^v{JM3?@PpK)NnjD?XP_X;c zM8OaP!D=W7F7#mRc(p>!C3a^gxMpU};fZL(SZZqA#ne}#mjA|r7BXNIe#^*=VtwME z)}2NQ5pylUlZ3`u5s!jgUw~sBZ)BsC=k;0%?A2|z8wdn4v*5p<$tv}tf1@v+kVCeprGQaf=Ub0?nvStSye0OFa|_yRhFDWh86#l2=;<9@`Q&-s zrs6Bb13#YfNwhYPWcPOenK;Ub1UgnJh|x~#tUW6M1CBo@L)h8)$|GyiuUd61_+!_j z3(-V;ash-B!FX4ER|FNyGHddjeEIe^8X4Y52Y|+SYRD-OhXkI)hqG{hP6CeKE@SCf zJCrQ9x9bq|^bA4Gn!gnfN@Z~HqN|3v9!n@sx4soYLuQg)!F4;$-=X3!AH^LJk>A`H zsv>p~#j-TG%jx(-M-JNjfk;Ds$@n0UH z`DFbkwB(K$!eWjM=s37gGel-lE&Oe+NuZaQW}T|q0J-fIOO{%>97^Gn8m$i@xKf6d zgmZ(saEHVD3G{lAVd2+&#@{%i+z}^bL5=L6L7T}FUF9t{Aq*#8s8&Cf;oe57L%#hL zi~@36kCO^ihs7c|9kmS#2TR6x#&c5H9iv}=5850nullaOToz+Q<3Pln*IHW@zQ8AzLyQTTH=t8G8+?*n*td zYGPm!s`5I;Xf!GkNE;U;msa*oRloLA>+Cs85~^f@Lz-HN8IzVF<}x4&>E$>;&BYjA ztf^&_%i6hx#b$ong-el^l1eAv{o7I+hNQeRN!IPu!2q6bd!Ub}{7_oB=}zv>^OVbM z8Bh2fm7B2QI`TThI`g`HSV#MU&Tg!b&Mu9c7){m^3_^N^r4a0+aV>HqY-p_-`pabo z>O)0RUKM4uO^m!z_dOAZ0jFxFJ4XQpJL z?-t3}E3z$cimO4mrFy90KSu5vfo%Fs0_ODO&7g1{nzV2T=iDg@q-_tQbh})yzDnM(S!4FN< z!zCF%qGCO5S^7wmyIwJ*%4$vhd%z@IfWu>}iq%}#`#yIBH&D})W~Ngi82P|woJ#?* zd-o&p@snZ^^aee{+y@-Wr9qse(hH`LB#FOrbDL zi(0=-`F&mDkYLL9b}lwQu-R`vUPnpeuUlUeZWx32vz1t>7HfZwNXEeSDMnFE>O42<3nyK^st@=`RR583cIvwB zNh;56mwak{)Ngv%Y!oZo_PMWEYZV_5IY@_L^bf&S)o-==@Gx~d(iYqjilN^4Dw8?r z8ErE{ab!3=B-+%E#8BkbENkk$#E2cD&bK;TuB-XBsz;Ux&@cATK9*$Vwo{FUi6Q^?NZ z_Y2KmgaVvzi$Axx{$4+qwMmeAy|3j*3k_h3$P~x3*_Wy1n;j*vD&v&duRm}`C#__@ zOc2czuV~Kd(tp* zJI}8LB#Pa@A21Sv8Q#;Oh~8vHx`?e+`CxaUGu;gN>95AAFl}8OqegFHax!Ewp^FcP4wQ3#O>ajmRX z+2M>S!-Tw5zu zW+TYO@6hHNpni|)Bod{&zkbBbVg$Th+2}G+dEF*;=s87qK6lHHu9@)N`ah-?X4GkN z9kE@Hyl8pt;Pq`Qf}04 z@42Nk4%a|TJ_j8m@T02cq92P193!uUp0gor9`mb@&l5!LWGY`e+~Lx$PncK@*MT?FEw%W#a> zD5HCRYvv%lO!1EN5*jG?Ln&4x^2ZF-(so}FUM>+4yyEEEFUeX{Fdoxj*W4-mOPlyt zF*E?f?g=b*j*T0 zQ9tsEVgX8?1!LQ`hcWl-A4fKi5=^vB)ecKvs^lujaM3Xf%lPh-El;~ld_YX3*tlIl z%7Ee4Nad@hcBDOix#Z*O$6+V_VKb7h zf)$h2*u~l?v$2WLiEsBhHnGTd7t1->6}_JaU#$-Q3ti2$;;9~E=jGD4i{a3Gfq=Qg z=}^wLsBg_6yXNcN7UR?)+hOE7(XlE2**5#FHMjidd5@`Ll}i~KX?H%7<%Nc)lq*=y zP*qvdhg5cyK`&_js|C;wG|)aCn2QW$IkC=z$=z?*^Qup86on?`)1hpYd|Jnl^HOf% zeTGk&$ve!6#iifb8v^iGdMB8OvifDIjl4M3RZO;idcIqg8x03lVToUTwfUG4kS?7$ zT>m5Xh(vNF?$@N-v`#rROKMim$;DqJnm{6qX$MJaJ^`B_nE%s76`wX>7SP` z28+I}70hguOK5-Z#w>;qrYu%rl0-5bpX?Q$tE%;T+vkJqLVy|q{ep92{8tvhz(8S{ zez?3k&ZD1_hlJ8G9 zNYOd9W18EQ2gpGXG{uZ*Uc4$+Jaor$CYGRTJbWPfq6*Y{t{&w#RwQFQL$qb+x@I+c zFxG8T;c~tI(muOy68Ct>an5!d$W7`p3J;Xe8_DB&PN)Q|t;8Vh#!Hm&KR>yYd0ioT zZ90f~sgliY2ye9etwi2o?0o)x#Ml>P_iUYv#}a)%!#m~cpr$ZhYi$1mq7VE0|M2w| zKyh_T)F>e&xI+l80fGj1hTsx3!QI{6-Q6961$WoMHE6Iwg6rTmIB)WOx%a>SdsVOM zRLvAN=WM!r_g=kvwJKGE<*`H58`vxkBm9L)Rqsdm1v*)AC;eF7O1XO0%uACpVpykl z7`yCupB^Yb!z+?(#-8$2!KhSIY6mUW#zZ7vwlaC^G>~o;IQqrO(JbUG(l8vT3-$ZM zV^aWM&XqmU<%kGaNg>r;*Gys50LUZF(H)8;i&R!iCPhQ@8)GKHa>OsZGSpTi@5F-I} zrHG1fnLRQW;|m51(O!`+oR3cg*xpFioo2URCC!WYMUeL4AXdilmAR^GO99P))=#O) z!P8m3D{J4HZUNj(Eohl+voCy>#?Gf$@tM8*8a+UeMie86y&yfQ;bPdPQh<U+3sZs{F)9a#j>es5i5f_{^1Kr2W<#LhZ^qK5EKi+n}kkDTBC=Qr^r&Rlrk)uy%WgDhkM@|ad0{uq| zU=1TX1(cN-%H1x21iUUnMx3>N+FXs+D45f|U0AD1AjE(mI_U8MgnG zQb&ISt*~;z@Zmzv&+Wn1K&JzxedmQU4myfZbW+X$Z!@!DkHrFm<&hgyn06WYym)@@ zMVesc1fm2b6yu!-Ql0wQ96|dS;YyKC>Hj@(y)wtO}vycY36->v-~WA{kT5I z3tef;m=H=TdlE5KT=!Yqj25s|AhB9p!Ze~>a-GWPu#^qfY)M}902m5=>BR2o`ZXO{*KZjjvxz#ho?5zb zo^OwuENS@;(lavH9&J|fYv1zX8osj%ZjcJ67WOf47@g6MI#4ab=kpfOp9sqT_)ut8 zPIsG8&biAWh1KHftbAIGzf7_6u5VlR*DsV2UAd*gt_>eLTJ=`uc;bpba#G#T!Z3BG zhp5p)iLAE#bj#-;CaikdJLEeUA2aCp)yakMrP7;PpbQJf*6sSqT&^7&I0cjz9{2OF z@}NoXbW_G@lF4Yx(eBD1+)elB$Yu*yRHzPZm3%{WP7}5mGh}gj*_imbU!qH>GX!bD z6!4TJ0By6V7WHP{RLrb`f70osTyucCp@DT$61colA6t9RgR(I$i7!lqk1gRa6i=#7 z@ygz3bDuo&C2Dt=EH@hV`+NEQ#UvRz@5@yVMRhQ9^832>h9K5AV(xQQ1esY9L}L-mgYqJYPSd3@?l#hFpdR8txnF!FA!-HU zLq1X><5FCspI{FtJ8_HfbR$2osJEIZhvDYRHQyd}U1i#av{-EzWOp~h&4hS==s%M9 zkaJwm76oj+CA*=_(W*A8T9HpoDofjVu90d(G=8G?Is4QrOJnc*r#cK}1PbY3K6aLM zs0apoB4`;232xR4&@CtbqS^^w9}NoOx$}RnaPm4qXMbdJA$m0`<9v&?w4_;K2>M-V zA-vCCeJ!OUuwDL^Tn{eGip}4EshBsMcmLz9JKFpmDe&d(z^Mtbe`gHL+_oBYCUe0z zSyjR?49Ifq+vif}yt(d@l?G@s_D@MOjt5E(UGT>d#t0y;dn$+(tUIo)WuZKZA>yI9 zw$tn-z+$Ic%C@S0y)F1VxYt7wjze$|k$v6FLjKDHTs|JGcF^fnmKSP7n286+@G;uQ zG4f47m-nx*9X6U+vuv5cK^j^AH~#4QQPnE*1xh|51jMPm1uBg_H51Tw6MS=TA!$ap z0zO0R&6teDf;Xj24bVa`3#;$v2v6b25R(g^wN^fx^IV^!5~!Ax_u`BIH?8guR(1jG zq?_TMFCXVu&5>?oRBacX<+B7zpJYd%0&d4`^DaqV7yi7so9Wp06X#lAof9}fL1!_@ z=Kf*1I68141x!fQV6M>dXZ4Tjl0(qmR?PFzxlh#VeVBN1Vg#d3q6jnyxBA%<65aN9 zvwH!t)kt_C!lP48ETh3NhS11$%F*QB#Dxa6Th;hEM%1z zSTToN`GR{T=6l>!1Xsy7mo?Zo#qOZ0_evDI(#zU5#OCGV#- z;){GRtA2HY`GCmL2Ui)_1{b2vbU@59(0nufJ+S-p0V?Kf#UMA9G>$4QgKT^iN7)7S zvHy3@IetMsXB}h29iGGh#xyMCgbvP{SpAv8o}^_A@w!w=eYtgRY%~y@H*Y^*7L89) zVBV+}<;lCD^iQ(e$84Gscuyyi5|Vwn{x%Nr>{rjmOO$$ngKGEd-(d>zHo z4m{+vd$OGZBcH)6a9K$h>5xB``heyCsW6M5rqYTAovfYQHqS7zBef&35nh4}8SW7C z*t|VSmBfX_A9scLIU9b>aK#ltA@!f%{6EWw2*HtyJ65gIVgW4SG3zvh@JQc4nOEB& z(_GwAwTiYIgcBpB)cak^5Wo0A3;t$FVnqMf8}yvK>1k=4R52vUGa5ZfDPyhM-Ts1K z?F$Nnh=w5CqLW_cJ(9WL3!b0PJZ^JwMtA1@ckCwVtgNU z_|ZN3VqJ~2OF_&E9lcrYv5(Sdah^(}0tg}OdIfWrFX^6z&%nz?W6s;RXSd1emh4B6+wXp%e{X}pXGSYYb zpK8wk5`6Vy$7UKTfU z^pVw5eWe@0YQkjcq)1k(Xg`{hVjSl2#%ll`BGHfknB{1LGVlMLG;WQjDE^9B=3^`` zzc--qh-(dv3k~r%!<_r)Tk| ziMwIYGhC~Yt1mwi*3P$Vp=l>QkuoBZsjPH+`O^;ZM}P2kmm@*k-EY^UN$-x?z2|oq zhkWOMBJ1A(`_D@^iO709^$PhRH8pjVk;F9GhTLmngQs9TofT&aDsg6>C)sIDqFJ%8v8G9SxG zEhD@(a*uUkQ&f;9l6f8*%ofJ}ZCh+V-h1WN8s6z2*nKY7T_=3?Hyw7cp3&WVzpnzh zTNgfHp08s)9ZNVC;z4+Wgmoz2I6YG=(ry>d50QM-Q>R!(a!2r9{zp}*rXGQobb4sG zu3rnCC9y&($UAo~)@j@}`L)Jy=G~q?DP^2bhgJ2R(vcy` z^J->OB&||BbC>he1M+d|AA3;-G*(j>G?QI4iFKjdc{=Q``+cmbUVC4Ac{z~vu^~Mu z`cgwPas#P%9ViBc2xrM&eIrqwR^JhIyA3x z>q@b{`gZz4@I_aUIF+pK$ciA^Onp0n=0UszwImjDKs@s}pI5vVAO$6h~i=eQ- zMM?576iduL*QLGvr(IKT4`Yf;CZ}0JsW`1m@nWHJSKCQcbKLA#lC|@Ec{*kc&8E9gh<8EY4HGOp~k4s9ufbl;xTHfOOy#KktT4guK>?kZQ5i5~qkj&N=Z97UT*0%Dchcdkxnc z7F2O#)<86lWN(>PJyD>X<0<=is*q%+Qo%DUS zU&mO=XRxtpQt8G)_H#Umc2-bYpYDk(=7l8Qdx>gd|1gs}g%i(YJDtYz$e%W0r0q5G zjS#%KyWI@&RH2~IhfX~B%SoF9;|u-l5r$*4C_P z-g{@=gtjcbgIQh@Q!F(GJ!)$}u^Zk_^)o?)kN(oa@`(CKq1Vx`k24kEeGDEiI|cJC z{NRUh!3%swAu<6I&E>_RRh(D3S968Swootzs_svT0hFJ2at1*PS}8dnh(QSW(d_BE zv@{F0YmFU#QYE#&j2I5@56A-5#pkM~D!dv?>NdiENiYC8RllLP@R#>(FR%d27s9gA z@Jx(-nL&94DKuDP>BeBM@m;ibuX8W#V1r;@Iix9g<{Vc%Z$vD9{uVE9D2%qiT8goD zpxi!tQA4;{Pr6jm33Nl>98wh)AZpR=WerlL>vsbscg2iKFQ!JU-N1E_-TZphF_Wh* zeYX_XM5^`Wdl>pny4QS@Q-W+6-9!K9`seveZBIeHWBhT~e9g z-iu#eO7p4XMzcXqE=@WC3YGC(4NbVSVJXXuJG$VVS}^Fsu$|D~BE{wnauLjj*wS~( z4N7uqBtVCmlP)~@?0>g^p+HOp^3VAClzA1E23UDh+={b0TI}zAxqtyM&PlCzJmuw! zW?$wsH8nI;mzvH+cd0Y8GT8Oiig!uaCqDBFS@jKGdL2XU0v*r)0aPBEne)Xk)C%Yf z9a(1qgbu%oPrEf6a{g%;D_|1D7i3Jf)|p>RRwNX==No102A%^zILOo zpPrs5;T_aFL655?0s8e+3XIcT?;hjBbilVNkYdD}Yb&d(j%%w5*Qf`Po)~oZS;(*Y z%d#+rF;$<)(s|EzzGM9UJq68=rBB3L8kWBNCx5!`%@|;}bDj?V(uq_f=bzHiaFU|Nv4-?0me}WR?;Ak^Q>@w5}wR%ldppXO9vBF z8p&69-F4^R!|0h1T$!P@vcz}6+F2ZNNjxO1&C)JCWn^3`l^^_5DY?)Q2Bfb<^Vgo+ zPig8MFA3ro$~xdf4Q%Iv6xv~$h?9;O0&Vv%j|Mp z#|ZpZa5sz_T{Sgiz!~GOO^Nnm19nTQp5NdBN1^NIr`m8OVdQ2K|&Cbf~XOQFCvEe_m*6>spE`iThBjDi!>i zDx&tHsg^nKEc5Rq>yl8IH*XmD%FD)Dsb!I{C3+%kRS}9tEYf=g(PMGBV~_ z6QN`UDs8NA(bTej=}uSs+Jv8D0;ku6&EH6MpyM#{8f@nn8KD}mx6E_Snq{zGclq-- z>#6XXqW0Aol(m19=@7Rd9fEiz%-365b>{9`Tz1@;Xbu&Ij&WkfDs4(s%}LMAu4pYE z%C17=OBU5NP#SB9NM7BBqH4m*3qNID(iv;C`;QHyGk$YZtupR&G$21Zf$~GG+-yceB>FV4drWLR#IG*+VW3{N}eX*RGT& z#4}H^ek4uLdnx9$7riBzW~cxTQRhnwSOPflcH65DOE2H=i2vbJLo1^g%kaAa3HSbC zVmCY1a7m*mk^uCWZZwK+g!_?$^zGeaz7d(V7sZ(Z#bw`98C{I?-}T)){^ z?j~BQ+AK=O)SJpvTUS;}nX0Dl0?m;El;dwtfu4#5BJ?A9eelj5A9&pM^)MR4d7g9f91ZI`hGsJF$|5ZMS}kZ> zbYSJ=HQCedwC_9IkIfaRDPNxj*@8V~pRh?ywx>BiQ(kfHeCjpl_tw3c3j5eW!f2T&)8@(o z%Y??6#%xz>#>}pl9t5@O7P*4Wqd#2H8+6$DE910g8}s(I)YYY^A1q>FeF610r(9Je zdfEii?rNtY7n3>m*XTK+`z7ka7gg+>%*x7Ye#d{Art9${-Lp+?VB^GkHdd7mJqGTE zrtwfe=`1aQl!97AvhqSG6$1uO#E+etza-m=#(Gn}z+Ru#6&48`il0)bAu%WCp%6bA zIjb|(R^rst3iS+-FoC;7H*wK})m(XBOAK=uHhnmDpe12u+U)*RN?|)&i&m$n>k5MF zgajG4pkQ*+(x_CsR}Z$h1kKN)@v=^-bIZz+?sdPeaO$naU9rWW@_D?KIcjI>vvK6CCpy=4 zCc$GazxEdX+eYL0%3nb)R!vEfLs9N)>Ij7%AuH(s=Em8Eh((z3ua8m!RwmT5v7-c7 zU%bn!tM~F2UYlJIDth&j1XsFs_VBR7%7 zXDxaM@ja`nc`u{mb^37@EfR3MpspY|~VCkuz0r+$C3g zD~moGTtG?b04|Cb8NiGBsx;Fb7?_BhUk+LrsW zx!0fP{6Qj?EKXbU`2xK5=`q)Rw*z$7y!MC}x zb!YH|cj0%QMSrGPL>+7>Dw3Mf$tK@@@G{l4))t0#6_5J<* z&*;sh;Tw~u!6BaKsp0|8@rlU~*~i3K11@QFM4QkV;`;Umjw4Z8BU97h0iB^0^Szk7Sp+UY2J}f2IN?^t*39BTLPV2oZo0EG}+>&dQ5Y1ZE2X| zLKs5b5Z@VBiS-o~1?zy$CT3+qPye<+{}Cv-M+ou|N+o8%fik#OpVn;5$&xYwszzq*}>~w?yvvT1}=f`&+a^S)A!?ASm66F5~*#eIy(8< zzW!8iZ+}}q(qTG1zKd70x(Mn;gqrKHtzU$UqmL_&xAgtute=Lz*xaKt>E*a@@WgM( zjEq%xq~HuRX7M_&ByGm+oauE6ta6sp9Sn4i@Sl)sj6SD7%4}F26ytsMPG(gt40|U!=8ih3N;JZeK$_M zf3FPjGa37+Z$Gz$`6Qi3tppXm+_-kx9uOyj@%gE=rmtJ_TOIB)+>2XW1im17ZV%@b zs!y&2{uyCX@~}II!cf&(%fQBdWbK-UChg)etI$**cOVqR_6VnYOuKAIF6N~k6ed9s zdFArX-iV{Zva-Pn58~nStEG^S@-Q3x@E3j|`3z^)GpKUhXET1{aBC<4W03Y?%uj$| zIf%hJv>{}WnXXh1u+^VAcl;FoF#>$7ep&t>EgNju_9Ck=%1c8+KA9*&WpuJ=e?0$L z^lNA{H|xRfZ>qsW4*0;%xqH>7gWpI9ar<$*Uo=Mh3(s^~IH|MU?9F}!<@2<@+2)_? zih>uJM#D$9{~Zi)A=bnKyamM&=5&Zw-w87vfR9;74|!yD=x7d1+NmDKlv3HyHSAC; z+^C|)#~R6P%oTc=rS&Hf0^hV&lgqBp32P+D@xHYqt)DGKR6ggfM2$Y9LQ{l(LdUJQ>2Tyk4Pitvf1JUhcIk!eX}NP_CU?Nq$R zf8$e#pgF=YV)uv6Ci)Oc>SN|I0d23Odf4de*;AoPX*O6xsXC{j&po_`j+{#M;N0qp z)3-*4n3ey|h{_eB?%)%a40DA!iYeYG{o@)E?_bp!rl{rB980{9b+*a&fI&qUp1;OB zs-5z)40_6c^u#h~wFLa{ga@nl{+(LrLPwHe*M4fp%V*=&jub7TBq7HYuQ~a6m&UCq zk8C+R3-c;F=d>ztG?8}OpKM=l+EpaHZW84)XP%%$|Ee^xYv0`?^YXo?3ubSggHv$w zZG&0R6SL3GUUV91Qh92YILG6(?+f#I=U9J#L#s1%U%7vI-}(%Ak$(w{KL_5(cTr;r zepwn7Ezy0sUn9t4a?zP|`FKbF6texYRP8f2>@|LChW%q=JR%Hl!&mRjFYM;sWjKI` zCmrg5y^>G#sg5iak-))wi# zJh>m_bJ+}``H2H3L2J>P|0t&D0m;Zhw9{GdSR?Poe=|4F`#qR>@es=lzopWlCd_^w zEL^IDrqA6klfN?sr4q9CvK8GIysvpye=Yo6PwUC^hru8dlEx8})?jL6%}Al%%23ft z|6=*DRsr&vf(KbN;xH?8h!#kO;e0O=wfIc%ZVKl8N?@zUkJGA$(b0;fJ&3r6vxuXD_boYY^b=}0Fa5|s$9SRLGskhYy1%3K=T@}~3 z^*jDnE+$N)^%|-2H-o$*As?Pf-pLKTEe`w8{%kv(;rlfZjvC2MR-~;cVJ2qfaR}}{ zvAZhZ!M=ky=!W!h9sc630jp~nb6(f`dd`kKaFX#iq<+zdC>`=Oy`-j@U^Aun_qV?8 zTK@ogu+Ke%whHzq|7RK@i5xjTOKL>`9+dRnx%>R0<>?HM(!yVIh^t*}2}`X9OKnGl zAPOvTCz9S|y?XshtIq3W2*Buj#0COBa{+OCZvpoMx(KQC)!yLi8qqz$8jP2Az-4pY z8}-7MlhY@C25w$D;E`HaY;3e?fg$BZ>9e|e6IY$?-Q3#fJG|67Hq#%@J0_e=cx;AP zz;mIV-Xh)G%C*#ojNr5M$=>2i4HR7Pi=ze&W-~if&@9FaI@I#na-RWLy`FNoU^+S` z#su)Zm5Zdx{&Ir;EW+t~sdBS=>cy#T5_PvIAxJg$1TD`1&mK0gpTWAG z0ztO}$sdy4*&m95k1`szWVxdIp_8M=?EcvZSHbHO--&Czt*sd=mOv6}Lm9;7EhbuGI+agw>o zWyr$~wf5NwhNSL0B}3p-=i^e6ogiP&I|qt{sIGa?-e;p|>VDa6R6MtD_h zDZRxJ;S9_*}&_edT&;y-ZYMNnpjBo5&WnbDnu-)$n6iLj%@RfkyNxJaRr-kX`f~&uKALMg4J9sJFga z1~c|@}ELfOf z988@T=MS_|A8M+$h3%~uE1PEC)b$v${m?kjqKL;9BDU`625v2EzS+zuNz zcbfOU2V$irHit1<8LmvQ;T+qsqBhB#t|k| zZmOkJoblw(;9FPX9cC`~_euVJ9z9qAGP1}^rLj-W*!5Qv-wnf7gKTn!7{~7}O?TLQ z*xRq4gU`mF@4;)xJufuA7i^&6Gdq{3!NwJV=uMm8;$&0$eAh4Efd~!WW3duF>8qRe zNpo{^m3VB%Pz{w0;kUlWYAt+e-8OJd892u{Mh8`)rRiar z7#T?vTAo0&)tZ&S$4+G~QaWc{uT6y8Nc&AerM0+!Tps#ImIymn&>S`d$Ng}mxD zgdgPA>U6Sc#?B=?pZv(2O$0+4I-89^nwmjD0?!&upZ0|8s ziE6XwqA{0&cjLAp$m#my0nxFsrp#Tp1_;ORmSb;44x5i^om6R?aB}m#kof)>2h_#l zgvtYB0TS@oZUnCw$8Z(r8%k1utnvjrm;Wy3(-$EJiQE2@Jx@E3?7BJJ8R1K9YzGmO z@q8m09c6$6zV1a`MQS8IJT^BYT+DbgG$!gGoOGNmOc8rTKUgo3#lSHmHeo3ZkL7_eHcuoyd${4+cENP>LUE(x}W^D5n6hd-$bG3 zV!*zMepAMndl^Wxo#RDFZHECnBy2ZS=WTBOG3dq!B*?*mE4W;(3nWQ_J}LUe`F(~9 zY}CQ|L+;?s@m`1RzuT1?tQ6o{;o^)TJK&#>|L6JtU4=9uUo38i9_YO@fS~N&cQQNg zkqa++dshuSeSKPEG)ogkz5q=$ zIbLs?$_?RX{O?`=f8TeLAQFYI$4t5~EUUl2hC-nFAfLO79XsMcV?HJ$hNjbVY$x{r z_dWk#kKk|kc|9HZM6Hn~_gJlYOZ@FC65r!w=?^+k6B=+WC=NdBEfN?2_y23&|F6eD zlY%)mFf?RCMip5Oc*j7uAG^TFOQoi3151M-wX~a-7rlnU$B@9kR>E`rp;|Pn6aZA#Mq! z2dlrX?OYs|4i@GVV89!uJw^K`oFV(0Qnyex(Tv?BCnqzGxm1Ac$pf9+8JAt}lH?XQ zT)-|jt6#Ef&=;Ex|1ppMM2&wx)>|6JUi+nf?pnNQesP#2Xq{;*ydo_*;&q(^>F_Al z@A70}6|3Xrm>PM272YzOhv<4b!pVp!pYVfa^;7fNs?SDmupMRKJsG|KRXaY3{m9oH!8UxQR_sI@`S*oa z?UNr|F%x%k#_MS8&6~|^*G{P=ijDs+(UYW}cFMOP2cFY>=XO$s>b<7|i^ldR%K3fr zLZ8LN`&XFLzW+4|63VI5CqI)hXRE^@ewRRa{_Z8;pl#f|ho=IMLfuN0`X5$Ydq&fO zIK-M+cE0bOcVcZIJN;sD4i)*+|O9xGu_{bZ|d; zbVJN_MhdwWs_82~f2{6ueYjI8?OyD;I>|y18;WikFt)oZR09>nUExYyy(q+Vhpa*Z zhXx`|HLLwVM20H1+lMEVZzdT{NZ>Uj)>h zY-QIg=zW?A$5uxVw*ECJYP)Z6``8~?Jepaj(A`c2?q6ksK=r2iqzdKJ=-iK2?B;9- za)3a)C*CK&K1in|{VDuU34ou^`zJrgy$SwW(r)K}?D`)wjYXJJS!;9VyMMLM95yB* z5~zIuKc(^u-R*MRm7)(%r)7T5r~C2I;Oh06g%Du<@vdGQ49`v=Yu}2kH8?ofUz8Rd zh2k2F{AvASkkA%BHC3lAhf${ZzTotC%Hr=~rl{Gvy&+3bakZSW2x~~UEgzG~^YTMI zD60R4+4s~&g%P)|{^CGT;M>Tc(X~#4Eky4CKy9~#ctqRc`Wh)vjLw-(OXr(GNA;XV z8QEAF1AP9gTKH3&sS_YO8Z+_Lnm~L1-&N6ros8)YAwksD)J%q{nPxp3e)y3D!{X;2 zC7k#EElyvbi2V^L`2@5R^m%kpT*TWpN2q(%;D;yEzzrzb0Fw2s&`Rh{q}0b~JcQR7 zCP)|B#x_3FvPT{DY6-_189<330#4;G8;97XkCs^9;rOv;Xd=27)z-=D2@I-N{zhMlE< zkFUnc;3s_fOWwi zr4@+}$#K)x96JQu>*JI-Yzpxu&X!jZ35RPEoa~_i4e6YQV6tJq5<9kRr38j<-Ph?0h-97EUMW- zb;wlSYcbRmWF_GmKN>5WQIYZ(+kNzxj9W)#T2-TuRn}k8bhp+*=7naQuUu=#e@{6_ zCAFqpqM}YA4mgm{Fux;F&-fK8jv?=DK2vI=?g6IA)=f2=xLY~V^hK6dJ2xsOJy=-S z2~^obuG1@iL?9u=a&?>al|Avv7#CMb35%8y&7SuxD!1kdB4rpQ-6;?l7!O5i-_s29 za@`ca_e5NYWpJ*GPTr}ofAP^$@;Kp1)@|1h2Mz_@B&2WsvHorrnm^%J#~D81^QJyP zaLHpSdx9|}+_`Z&k`+ZOX}wCKdYgcHEQG4z(gM9fn&TS#(Bc7J#sbXcz{OTR9nw6s zveu;`l3~-e-nwM>>ITMWw4!R!7%geIB>WL)jdMxN7y&%vztip&DIET%_W#C;CA-uVeKW>7oY0^_;|q_ydU*FruHpt zPX)t<@7Z7`!Iq6t>WAA+fUkvx(mA}*9Ve-Qn|CG2(=ueoFg18ur^8-*(}moVn~iV? zZ#UHlQ*}beXXiD!)#Nys7xg5QAc!r^7qaWglHhaFiX8t8s;>YgqHkk1u6ghMSXrOt zSl5jK18)5Z@sU^FH5_5>t+|7>5n;jcT#?O+;-X=-wej39tEZ1-7a21eyn(!s$II0E zx#YPc=I2d%dvr@nFzD>8MknwBnLlZKd}7FGWM>S|_X5&*g5%WQXreyBXAy15dH`7dRS! zV~wI~$>m^7y}ZS~K@w{WEjc?ZCE}LSHG?8G>~L+=EnjOJG@I(p=Ia}*00dqWbN`cr zu5)A2nkD_jPWd>+EGxe)I~@I!%AoDO8Uf^LvxcniVeZbevO@NqauMB9k+TAlnxZPQ zuai*3-Fug?GWTh!%k%VemadLA;%Aaqgj)$kMLQV3@lv^e55I#>P-`>p9GZFBcs)~X zQm|#H?p{#AU03l77Ed0jrYZ%Y$X5uXd}z*WL({+4oVae)Q? zZwTIh`)Ubr|LT2cU966nXH3jM%cc?Z`A`!PRlX7xU>a^dtEIlH^C++O*i zBTjgoOb0QO_oG5pqeMHQudo?^Gp+}d$IEC4SE4~MFZb04?MS?ZoHUoMg{ zCSG~~x1Q6v-j@=#rkBXbAm4{Uu>Z*%@MgM(>ZKR>6lf=LiJkirb>F^o^t9~Sd+%lQ zxwm~~6z59vzOMfscw6m@yWssyBS;tkNqxB_4QWr&y?uDmMmV+Ye5w-ln>(6VZD%>l zg|a-)Es)MD5nWf*CfPG%BWPIOI^bJJr z)om88tVkY-^S=}@`+OXI=#5+u@w1(DHE`hfyxT!Hxi0d!@$@~DfI`rV@yki03pPEZ zh$mMPuoCueILegeUPoKxDk$snKn*#MJ~`F9w7=npKN&_m&rEsk;WuQKgc)q!3_pFM z-D3AyJ~X;iz>|l%rQ9P!TKo_sduQic(~yvQ;uxN0=9 z$qfG_SNW`ld%a}(VE+c}@CO9^&qbsQ+uAei!Q`|SAKVUSrqdFkpEsBAwjH_7Z0Php zqGH2tD1g)n?kMB!?sae51am)jPD^r6OOV*v*=1MBfV#|1V+Dolr*f=ORcC>PV9)nO z0J3tYm7fd@4B|P>RI}BiwnqtCBYKL!9}ZKwU6m565-Fh+O!+;Vn@Vbvcpq|9sU%Z( z=EZJ~=mOt~S{qn*k#BUy3(Qhps^ujL?(|CVJ+G@5raaIc@XknRshZdQ@S5xk6e7Bi zddR*@AQ3!0xLoUW1T^v4m#5H!uAo91HV|(@#O5c&a^YxvBsvlM!!HOYZ#qd!zKP(N zM;>bb^{z$iS4-?V?}H7dCn8-UIYSZ6ugcsKWNqf%@=;ciB5$Uh?+jCuJ=LvQDmPa~ z+j6K05ps{MT61MVu;v<~%;n|YWbm7ZVk7A6>)dH)lp`7=4X?&RYXQpizv5LKI*R>008JJm%8}Hqdj7O4>DocfshQQ2}sq zuMjCRu^_~Mk8pYbxP+;g#pg;}Z+eCm%mwxK?E=!L5^CV(wLHe8c_Lyh^V~!0d5=}0 z%Ea?hQMi>#z&)uC#6@Mg@Sf(HM6r_=`=*V$Sr^DgnsWR`YR5FB3^ax}Scj7)Sj0qWD(6hS>9ZP%s!FcHIxBrD3(4>T3 zYd&Th9zdWDGcPlLT#;C-T+CaDL}?4q{M3KaAG$w`9E6H*ejC6MWnh7CuJTT^QQW2Am+1XFIjV zUgdYw)rq<>{3^JO-7EJj;)e6u1VlqsVIaV>X{)#CgK#h`T-Q8tQuLXt%s2S|*?Gv~ z;9MUY3%*V>706Bx{?aiVC$W|va_$(2=qzipwkRR8UVR$yX!=1@v#UY~$_To_Sea{L zf(pah7>iqGh^7hw3U5-uXgITH;>$7xLui^@e(=HvkzdxiF}ai0<#w+7NS{BE{OT!# zLI7hfO;9-J*U(Yj|N2A&wqA_@)hjP)!4YUdT|U(95%Tf?OeA-x9&U`hg0`cW+E1T) z?ZLB{rLr<7<9jx##0B5}5 z9+@j+wx+PGuGH?K-;fZkA_G1AelhKfm;`r|XEo)jFxdH6*yQZLJ!4gCw zNxR}p*`2u)yl=~ZLsE%!dj z6Q5z&{wZN^`I(C=$nr4b4dZ^qhX)UB6|alQnB1EmC&3STJ&oJ0#JU$${je4N5*Rc< zP%BS30@kLpjgO6Bd2_`x{!^lO8+dVMq*Zpq~EJ#HH1o3G)GjN_=7>7bGw)PzFM8)iwEiXJfRG{boRlzE}DibtZj0Hra zte~4tu3Y=lKgVw(04zKf6vaFb7Bdc+L#+=Xy`KsdwptsD+Bol9$NJyxFpC-%0hF5S zDR-h0!qH_tntCsM(++%)(4TvCLd()cWU8@;z;$<@k>Nfpz#W7n|2}Oi(~d zdHR@1CMedRE^Gr*w*Nw&&^^uq_KkX(th}r^%VO-SdQt1g^4Qqe0sD^1_0b}#NC&N2 zJ@c5gtDZa!8}ll#+GCQX)N2ScbeO@2Y?P>t*7SB{?uc{brj3=PyN!C)+_s^&q&dZ5 zY!sTQ=?@x8Z&8;Zca%=dT^WZvr5V3m*VrA2!3eb^F}{UVj(z4-2Xem#Ogu@zW2cPP z9*grkKjRC(3&XpZYLC&dIq&)%ix96L#Xp4YidQ}@-U;UZL@oEiUGDj7R~~YHO>FM^ zdVGR{B)oI_{GX8g`F$kHmtcpnxjS>+wHI}luCC6X(vjU1;`lP_wfH4-%}OxR4@ zVxiBYI2vZB9j_+`+S}Wcl7sbR(%Sm*25@ZY0IFk1Wr30`ENjKQhP=mU1kb0>5_8}l zYU8IdItbfLM0PY4Uoya%7v&RfB(7ZivJo7-0yoxoQYgjzD+?72GarGwNEA3SShFA8 z3{e90bmDJg+KC>!9Rm^05l(I$_nz_Ir3x#QtiKh1nNP;RMoaXFNUkyLYCDlyaj4Zf zar1cU5l4Lb=foHT@K@0JhKDU(wp>bDN>7X?0aN=_+58(R`w$BKvur#bmRE45RPn9T|f@Nlnay6~n+NMjbmC7xn}NjpV)h^z1BLv5>0+IHVg=<5R;I+>iY66@V!lgOkk}3)U8S+`utG5 zpDSm8A17>yvs%TZ=$_nlS68uyk2cM?K$#yLp3NaG0zOZ)M*M_>??Zi1(zuP?p6JV! z`Rg4$wRt0>ZhmccA4K}ih8MWrUVv}d{Aky^47|g$U!Yu^cGr!12Br>{zvwt4_8?VJ z${R#zR)3%ftY9?U-}$}iv?dT72za;w44?chTQ5WuwNx4>gPs=#c<1Wg^bFWuWBwnb zfyH+6NBF?2Yb~~5rrd+Bf`G@^=g2wtpc1#em8VoRY@-%Y&=3TSpzxTqIcR2OsZ;=C z{z?+klFUS|itwY*5B8CvCBSq*Mq)U7Ee`(Ezw<;niG$JMk|}3kV9>X02OFr}4#@!I z%YXR`+O3;%h8zB_?%Lj;D|Qi8@qo<@`y;#H<~R>$Lj=Bj!{+#gK(O(;mpTC!zzf6s z4Rq%E`R{1A`QPUn1P%DY4~|Ey!tst)nGGEAJXDQr5wSBSM)J`-`owP=&*yQ^I4rw6 z#1`?4>$1;TZy19egg~nQvWl0m>BxdPTYbEYzoMmQpJIP1f3zk04Zc>&z{%i1&*ydL z{WLRueTp7@yofrT#c}eg)pNhPiE7SflvF7=tmTvxF!{#Mw`E*84>97yj{iCV?t-3x zt0r5+9(~l8Tt9i^cm5Zh4xsYXxPc~$)Ods)(5UOAr4@!3D#Xx8l3t@O$a!L0*xp*2yC2 zoWUkiFVbs7h9_bdLDYt3GF8&E1m-tY_Jdq47@g{vr0G(6CHQK`(_$!bHu|FB^m^;W zDiZ^n*H{bIIQ)M0P&`J($$K`vs8+*yH_pt+h??kvfM5qpF(PH~=^g;KF*OdcGsk$Hvx08tGL2KLg+2@%W)gWQ}@ljk729vqp?J8hNjBs!etUpUQRZ!(w-v? zff(9ld{I;j9ada=64A~;q5)dVXVpZ5P#1lgi3s1$h@6zH`G~;l;+3GU6^)=|N!n*X zJxfhXQxwZ`i^ha{eJt%|MzN4iw>(!~;RB)~4coSp9Nxa~H+B5^k|Z6(M&?L%F~VR` zm$4fIDch}tItDfh)41&zlim<&vl{VYxPn$&0wXJ%rCTcT!< zkE0^?@~-^lj63bZ{N`$R9S1@l0y!o*JI2F|Jje~?ho~Y%0l|BJW`EKULEd$#>`4jA z`79@iv>AqIw$XYF_x;-i96<>8btI9zAsTTVJnFYGREP);YJ(eLUcj${75Ab@3=>)9 z*ctYRF4u#y><2Npx!C6b1A1rG}UWf<0H99m5attJsOXPMaXpaZo=T_9xx6FVG zZr~LFG#S~Hh)X>))8FRvOyym~HKq1#?O!AShz>(AwU3))J6_wCG7|Z-s)T9;ODp~2 zJ^LcfuNYDA@@KOyEuXc6OP}z4O`K*4cUtndd*b}NLj?&n5+aZWAI8G(_T_quBUA6K zC6q#Smko`9BUQs!J3D%#?|6X$H3=zusEv({IC2320hcc`w~;Cn>>Pr7cp`amnYH!w zK1{FEoB|@EPM3c2Oz#K4qSD@4FlW){cGT7q^yzr}*tLAV8boK8;mar@Bmz?6^ZX>o zOuC-(&{in<-qNq%k)aSAVKfdhv$tn}Y@)Brf~!yN>*%`djGZYcb;qS-M2XlweZt=5 z@z`|Z?y6$uW0GqvQZ_ZPvEhDOm=y3SYOUq0gNd{)(tV?k(7K{-NlR}8WFZW8hqA!X zFrT4C=whZyJvdHrEOU^}`T*(cX1Q-6waR&1t;~wA(l++Wkd6|}^{{n&vQR_OBn@R-o9&Qm z{gbcR(cr)XaqwB6G{jDvam)B1EAEi7#vGsR@hFI=BK zGnUag;`iLpHNVDR>Gkt)v#ceG4j%xwa&bqxvU|pye5Nr}@4z1B<5mlU(8Lip<$H~E zPum1u=5`^;%`Ne{iMZ8+4J+NZ_=CQ@(}h#@=F%jlEyX~)(cR|JOf|vH0M^}YU9}T> zG08v@>QoQ&t8YHK4}ZJQJSec~$#+z<$x7pdMLoB$70)={(dfH5LyJ6N0ySJ8W?<1ipL%k=2V{@j3MW$Tb6{nNiI0G!JV4)sw?d} z@zMQUODRnC8=NCWFlb{_EnV}Not1FQg&~FaQ`+Zi$WM)*VdHQ_ShP~aAlkU=v@O@! zd*=(Hl-6Er^0#ol;L1s5mv7&vKc{8zJ1GZA zG!NuFao^rIeM$elv{D`5+Dr?uf4oX%Js%XTjX&(os*mM*aUX5ri1o_yFRr0=hA{1v zOoy?a%jEFo+K})4e)KW(O*4X=?|A&i@LQkO*UO;J5kWqr+81_VI$xEZmYB$LEpc{U z=26p`x9!-z8)?UFO3#{C`U*RTZ|2#z@*wIFg1#ruu~c$0;<(#~pR|^cqV&$~@anR*fGhJd z$|5fbl8K(B-Vr5|L);OEh<8hSvSf1lB{QqL*Vn6^>P~wg&ob&d4sihd6v;d9W$}#| z69Y1`DD8Xa>_RtE zFiwhzrxUk$+}_cV#I302gS=uRQ>&BuK=5M4^WK@!oFhfc{lk^DoAjsCbN9#P^^i9Y zB#=?6EzmvF^Mqyy1PsoAEJv+tKF-ePw04}M@+ClPMgu4f2|45rzUJERPs%hA3iAk) zK1`-nB+SSEO;{Pu9sgd8j;_fMa_8g-fwh07XjEX8)Zdwt5^t^!yCL+qzTHT~&Lrtn ziH=k?bCj`Gp3c&xXDR@|Y|os&@D;d+4NW>kLL1U)R50UlvalLr2%ai)YEHj-q0I_q zX>DKh9Ee{>5kRo}2L|%4-nHfqfFuda)?ob1Ap$)r;O@z zW4zn`9$wEuB-P71>DPxr&t6^z4xlHg17c{Ii(~o8^>|e^>a>=ABx;%2YzNZo%zNB? zO@;P$f1lVr1N^w+c4i@kk@_7xd8|~)KYz1%tO*Jcg&lTBLUq`Ux$kj2T@ALY(BLI` z3AH-Y;q_K71Xo9v(#be6FqDfpSHxkcpd zS}m0gr<;#a6~)A=nQr0VqZsH)gTz;^;d?h#1eb5KAv&*5FGq8oy+SjlVI3fOAD(MI zeD%W;Y*Z-gJZkh~{jmA%W93Ur9^yX7RKz$NHdcjUGv)|Z7F5FaWqY15jx-`pwBDqo zG*nDqhI!l6_1AcNDvjikk;LWdbF~w$cys(K)Wy}iB>Qy3@F3>VV4L<2n#bJvb%ml2 zU^6z=2qB)-E_ncj>qUQ9B8g*m?h2_HK7s&zs5o5vMp!^OWt~RF)t?dXY_ams7gugk| z{0+G-!q8nq@dcyHtacdA)stj-HHg5Y+fHx!0n!(9+Z17w9w|EC>CICM@2m4DD)W_f z4-(yB^K{27+9-;)*ZkcM)0kNMqO3&%Z~dG4dMstYyQsu$sZ1X;THfx@;Pc!Lgrq?H zAICiVn04YEg&{ek_dha=wBBe^YiW-=4@)C9ML2BfddW1u>#0tYi94Q@)~jS9mwGcv z3$#k=anH<su4{f-Of$gSrwd4?Wx?dvGzlngI#g_ z8xIWz_>g$AJP~24FY2`nHU_$2d|&~0j$WCor2fUN6E-!pp&^oY^BaT*C_){if))jo zob$0HL&Wy@Mo(AJaJQOlFVo7b7KW>8gzl85-K+v*SEVyZmIepU>*-s@c1M$n#5$JM zppLpX-dt$@`V8p-t=>oWg6%-T11G^mLR#^Z7}am-Bv@1zE+ z?0Gxk*;Y}DDB<)DFM;*>aN?q+EUdui*946@)=eI6PdthTp3Cp679Uve>w8ar@~K&?%cs=<^v! zq|djp;Fif4_;-Ds_`sOo#HPzr+O-gk`3YWo+C~8yAh0U6*e+A(o-a&aGLDFy60SQj zplxUXz`K)WlN_%JwX8Ps*WT=mjv)wh`aIeo-AbEmtrdE z=z4~IMCw+y#c#5&3C~u7C!EB1`!J93@oY3tdM?$+9ZS80o3Ij7G|~7@eJ&Z8256$# zXcA~`NOH{Gg$3H|Ub(exvjbdA=n+o8H&uT%BZ-O^a5Rf*Z#8~4;_z|QUg7=wh#)R~zhlHeuyyG*JydoW-h z;y)+QNe8z}H$3}#mqD_j3pk$i3A<_BTczCfX_L!^jQ-qn_vvqtN!T6+0q7tcf~{oRybx4x`v_SzXL90e@{y>k-9hYutwqj(NA zSf{yDBeg>%%7>0En_OSirb9KC9M%?VTqAa5^b<-4s~-Aark&kZ(welN1;RUve@+=r zr)^6#&r2+xDtySUnOxGLkntNJvuaEaS`V1sje0*l#>EW3n7gK2!uodCNl3DY+W1F~ zDP{cid6trVj(qqJXC9vH{))2n0fYPWi&`hPiH}|HW|cz4@W{6CCat_qbq2!wM|jl1237i$8m^MVI;f zT{$1%ip;fKe|0^2rt!hjM_nnO_QzjvR9M__HIuHKsa@*YDZ&X_M5U=}<#=deh9{;} zJjSb9EX0plslstFt<>}V zo)7)U?KJ2fTS2hqRs98OD|GrjhHZi#*wpSoQ_T=`oRHhEV-o7^p~9s~FmnM=y!uhh z^JSS@oba;=shcq=<9Q(#E<;G(rA`M2zi@`KPRVA8`i0`u#n1T8@sO95g~t=dEZ|RRgHfWY<;k_rk=E8;UQd-d|)_1)DbLZ?OLb zg{*#}^j^Ev7GY>v+xLI@8*d5{_(K~6v_rBqP!U9l!m(jjQd*y%Ae%|By6jNxOHj~c zg^M|cb1KKXdV04S$-Llel*1QTY1Z18Rt}_SFR2DZ1u;ZgMIJ1U-ep@J(U~7S=4)W_ z#17}zV&qX0eQ+x^1$Fx!iXrug!evMzUtsdRCXEQ7^!^Uns2jTb$3tlgiH-GdePoR2q!>yo|1PDFbya2VoD63<~ zn$O^3$5maq+#=*X<*6l&+mv$vBYXvLIXk3*8`4bIg|#d-uUS#q zU&_5+!Ht35GcV{C@I)$`eYrK_yD*Mg^{6;{dNX0T6MY&3bHh*`Ss2Q$NHhPLkeBOI z#%wJasFaxEr^+wgFQfeu1+Npti#yM=W@THO7Qs%wNEt^ZHlzwOXI{frc2Xh3Mk8be zzkD~3C5zcg+^>w3l4kRUR7fi#XZgi`Y5p|fsm{G-XS=9LhgfRH#qk{a?zZ-VSwluy zri+S51N%Pj?U6s*pMHh-R98|l&%E{ew#=x%Gs_t}aH07Z$K>!sARw6{uFgwaeVbvd zTrXV^8ECoqUuz*V21W);w-jeg04?vb3a89>KryX0e2>SR1JQ=NC|o11g?Bsyhc6lH z#6^FtXWSObleiocEJD^A6viaTn=gJ8*|tWOZ#ve_)(tZ> z+sb{(OH9Np!j&Vu*Ci0#dX4z??P8J#;k`Cii2X^jFxX9bt%_IUfF-yq?BtUb3S!7+ ziaI10Lw`6yt+H_9Mt*CTbCkDcMZxa$1&Doxnas659se~S1jv@$Y=noc~&4od^z;o%|m}wmgK8;V%`g~Pb)pHZwK$!i$D8J~T#(I4^*yoD3GTI82UztKFGswti0{>*xL!ISbIC5oF2!~BKitWvLtE?on**Ou7x`(d)iD;<*6;*|E~ zi0eI<*e~m9y$cv-c{ILx&I1Way5NwjrucKC=pYoTTFjS;nuD69oz{Kb-q{D}$Q^;d zd@*uvX2j?7%u~%Ef}GC5VCkq!arCdQqzrCpSJ)>~?DP|HR3PECtYaLTG^*ijAsRkT z6w*`Sfkx5GPDAd2^Okhf#U{G-z!XgkzliEX89&GtK(W4ex9Yk{nv`e&E5pW*jePx7 zjf7otF;}!M;nNE7u}I7@(e%Q`+izrMZ0t3Zcu&`=_C)*C%CxGvlKrm-(mOqgM>b6{ zaObO-%21uikY%mujSXTtM_F;j*aeH{t%j;IXRCe?=&CarXyGSR>1htO-wkL6512oJ z`5*(NS`*`A!rXYz?<<*++ZRh3W22BYqK*lM+bUxV<|F;My+l1Q1_wl}zQhbQyOU09 zizEg|BEn+=?DRg+Dol40jkOL7BPg})b??UQZZNY^ZfbHXDJ$#9!_0qD!w$=$h5R(9 zo~9WAalh)D-U{9_y)pZSj1hoaebpyqqb&ECq4{kLJkH$T9V><+oAF8I1KKPr&C>4e znV6+TMw0GV;gFQl7`D$&M-G-SYfy9ZcR(Z4PS!y^)|Hl&Mc%WusXuU6_$%1YBDL6| zGK(J@v(pM|5t=R72tHK!Gg%O6hwmXP6Tjxd&YZYD-|R8_F*myYblcG51gyz;EG^9n z(DB$WY4%`s=M!t9x)*jsvNd!xD!*upv~rs)f2moMPf3joKTRe^Wem4TDXez3=1L&* zY%Z~|+v0Swl61$IO{L}aG(M)PmIk#?V(GOckS&+TRBm>5+3}hEylz^S7|@z!`v3?G z7?0^tt}XLyfZfvVCFnp(3%cHc`U%CfSM#X1h1gv=(Wsy1@Id?Nyr&X=PQ5F!h=SCG zYVVBL=C?tN=3L%-gu4?$!T=8^x=gpRuvBsv3~ef9hF-}5)G|omAlE~X&5@JB3NpM@ zXdp^?7}U4En^xjLhCsd@vId;=&;W0saw@%+bSsy@p$v9L%vtnrKKl_I*q1cJD7?U)N-I6 z0`V;6%gxg5c=zd1Zx4su8g3fc8ds?Z(vWG#H#fTiG1o>LtLm4c^W>>0YhOC4b{6xX zFVC2UZ2cqeaZDi)xJ~NyzxRbrdi%@E=qd?e!Y>y4RVVv@?M=!`M>rE^0!QsuUz~9v zX5Q81WvnHffE-fK_1or^r1M-3rv5`SA_uBY5Uw=Wi}vGIjD#s+iH|!YeX8ZdeKz)S z-S6=aVI?i;mlQUdaTX-^yZ2kxV)kMLI5nwvI1!gnNQn$RT$>Lca@>M^v~>*wFD0}r z(2cXdj_;8W&E?T}s10FQk_U2#uc2+72T$&j4a1V>p6L{f37-4&g(c)kHnfodRvC;ML>07V zwgyxc^QksSD6-a$1Jt$#V`UkP%pIb3}@Xz|1o@p30qeji7 zlf-xd?ru69MAmjC{&Zad}J#gy)=B{&pg2P+Mcw=H{r-+b!svTLz=KC^k zz?V`VEbTYD#+>UETa(kiq;y@-w>$$5=XMxok}-7s;Sk(VW(D{st1C$5hwRub6^waI z^Y6xzUjcug`JF{n7(m~*VHgxyQzrcKTsB9rM6fVI15kynQ?r|ZO!7Q)x@+)@8%&&< z=jzzPNL6`Bk|;WLG%R`KFd@t6-TRzRH2w{3?>l`5Jn02PjvH0S@fa!@R$W~$b z@`I%Etp9gf=^~UlYcdE#48fy~VPmNl{lU3NguEevxDIqYTML`mic{8z`hHuvI&{)$ zQW0=~j;rq$c!d*+fdbTVZ5_x6b&($04GzQ2oQA;cXKVQQG)Zp8l84lDUNga>o<2er zn|2@{Fuuppve4En#aCRpQ*Isnty-X^)z?h-(CPMdk~~M6f6GS^ORE~*@nh@xtMNOc zjGdOU8V6cZqVs&ekKHrA*9B>OTDR>dGzcz0fqj}qh+P7Tiq+XiS*kx<^M6MBw_O^6 zz-;QsAptjL@TtY)8PFI5y+h(<7SV_%UgUoiHZK6FR#%%QFHOSCe<}9=ORg%-?6uPZ zy&yR7WcM-#Ka{(R+RYUD`0i4j-mWAbPK?cei{$^4UHH2df&-`0_`9X4HmufYMT#fM zfOo+Sh!%9I?&dw0zAQL#^RZ>x^+X?Ctpw-c)nN-KGkosOdz7sqy{zm>`V zjq>-KEu;GlrmJnrsMnOg*fvWx@P&e89<~J)trrnF$cx!}J{;k0?9Q>2j}d;o#emM52@lgmyu)%?Xiw-gethjl0;At+X&%~=J}L(>;p?nE>SU9ub}pV{wQ zRt%>}%+s9`5^}sD-%&NlSr$~NnN9ss#$J=Z#aLQyII1-Rz+rV&r!huMF|Wdikgd}^ zcK=tBG5l_-^QTCQEsq2EI{<*OJ(0WU-3y0%&lL&~8!HFF@+Bj@_SWT36}4bhl6R%T z4-!o)71U}L|NVfMA^-auczLeiJV$nTyd7T))v$tFK63>yNWr08T@@-pyK%X*U@94t z0`1R`vHq zA~sFhkru}@;g3*40co&fNq2z_<>TU_pV;$C(_wkgsiFfaYRFsu-8f=15fPETg0^68 zjb(V((~4NX?q*CeE*ZWvL+GX`A9?gti!{*50Ce{DE-3M367KQ^vmVTkj*lOG z&Um~%dxjhkS`Mb`>giEKTKFLB_7U5Qvvdi>*bI#p78ax_NogbP=c>=rE9})7;G~Q} zO5ErBx{^f;vPZdQCj#%|gM+}OLvLS0JTxA+H^wOkNGnY-$ISRl z>1QTmTm~F@@l59H!bQU0)1T_IStoz9@EVf9(oBFCu+sTP~x@@+& zA(GZTLABu&VJ8HisZjkaOzuE~w=cSu0s&-iEbZ&H=K}bF-wy9A@C4o5=cUN8PHF*O za##{WiNUWolY_$~i0Q1?$TRcb^ecAyv{Q9x_^;(M(V63N<+T-w0&GG~PiFx%K#i(H z;d>wnMGPiG8jl6+$nDLZ0b9+_3B0+tP_`0jYlSvTzOA2q{f}F#CgO|uqgNLU!&`0C zAs`JotLA^m5I4$ocAB(fa~pb0xP#;J$faXLu8d3=fLVvD+gX>W=LOGW5wD~I{1wvA zQFC2e@)ozlY{b3gnJvz8=W{E{@&e1+?5A5VxL$r-p1&>E_|nRDQ4?(G#d^* z?W{(TW83d%D@39ynF~G&su_kHNK+@!k=81gfZ5VymhIHBwr4KJ%^}XT@=D2+7)(C| z2D}8HhOYX^JecL*5*(!0v8tKW4bN!>fm)k!sZD7eixlw^PV>?Ts7_ZI9Pz?P!*=o! zGlEdf=SqFAlj3fm?l%Ah0atQY3pZxMQknvaA$$w0Ll_;_wt-_OrlzVaj8u z1hY>n>qj1y_?$Yil?J9A(Gqvo02!~JGY*MNgj}84~%Sx zr`lfF@Z;!_1dl4TDG!i$RXh7rD<<-j@vDZReiWGg(M-WU$*3#!g){k>dG!P-l1;`k z3n_B|<8}spgHvs&w6yd9rK+hBkL1({KX<^nbQNVsa0w#L$LQ8g(ijnz_aq0p&Y{w4 zf^rx9h909&zfgi>3iekk&Y_%qFI|aD-x5q(I@+q*ywbzRdzWgn3A!=0$??@ujAuE) zNM)BI@6|(&3k70R(;NPenMqu<92!6`C*Y>>nSxrc+i*LhTK=cYUtBsKeG|l|A^Q)ULeTx z72`K7wE$r9##E29m#$*4l8?5>#>N6LhYQtqzkQR|)5Th0iB$Qi5#0WZJfu<7@s$_s zeLWV6#F66^l@ij&<=lvS>SWNrmM;rj5lLi3Rm*bz-lJzOyB(joMZUtk^9iEk7f*ez z3cGbHG5W?2z=Erm54M>-Z9CN&aOUo0OEhB0Q33@->E+9uH5oha=AjWU5GD3J%r7w2 z*95_7O?NXrTtP%_A{Ugl@8~*VPeZh2*T2n;Yg4?j;Lt9EYf`MWn6C>}Asuq3)83D7 z)1=+9F3mVkTVEb>XIvVuV-@f)LV){R6M3v(!u?b@C*mjkBFiJ#k?vy3N!|<@)+)R~ zkNg#$u%XI`4wj9+p0BOGRbEdS+S{#pd@%Y<7_ASPaKCFhpVhDc8?VO>w&%w+PK5ue z4v@S#30ZF=LM?b&hzlysE}$Du;zY2}bkIBX`E!I&K`+nVpOkeGsAvh(JTkrB5@+Z2 z)7$-~88Hb2h+ z%sqmq6P~$CB>AZw2;#Z7RjnQV{DV9H#^N=+jpV6C!%UGnw-_JH*g=;MQr4Gm-@f$; z*-x9_El`_QKb$!7&dL))TrIVP}zqOZ(AS-whGMnAEf`0oz1}+a3pV5rY8LNDz>zdd6 z%Q!Et#(tIEx8RxtkoY7OgT_!dZ(f(PKyX4h6)6vq%zVK%a9L5ho~CVeykPqz+X~&ZX z>W~8B>?paPq24L?2@#>owzuv7<-Gh2DDSzk3R{ZWKifZw1&zu;>2BAryykrTmxo6b zvDz1Bp?9?Ey^CbZFSZ1zdiXs}#oUW6V_pAo;DHjv`w%A8PS-m~eqyvQv%LJ~A5lOc z$(vO1By^;jVSv}}h-Ks2v(>lU+%yKuA|!F6i7%Yle}+p1Tdc0p zr}Stl36d57tfM3Rau15Urzo26ZFv*^<$ubNci}KV8oW~@md5-dr4m)n(M|c&vl3PH z$TF&fdx(Xa3pR&4Lb#GS{@I7SGd7>aFNw}ekZVk0R^oYE^A_f`X{r6Cb;nc3y_WSW znkS3H-0d{ga#OzeTLl;6lyFB2t_jOm)Le)$hs`+8;>&&aA`bg$eP+TTdE>^LioJL% zeRhbi$Ap&F*g;25~i;A)azrV#n&G-cjR9!g`02GXH4|6=*As#>?`O%!Et?0=(! zT6w(}$`7(LXaCWgN>%fEll){--v&zM_JC8VP8e>2?Hj%{sc&s1D`_!N*&8M~IF&k~mY(K^eu7GYFh%)tuZcF)25ciDoW#bk(6O$}OhI+2a(er)jwURIc zrDzIQ;gEbXU-Hgv0fVpJ57`au zx>xI|(kzKrGY9R?L)mjO|2l?NB_HQUGOxBIXv`AT%q|{SG2GwRjZz%P-=U2_$#*6q z4-F5O_`o5ypJ!RwnE5xYoBRw1b>SI-3DOB18sU_k$KWD`Msjj8D>DQTdGmAo2-|0F zk=3E*~m44S6EBW z86<0Q8*8JC-_Q(lek$6_Kdp(V&$%1TQO>P#4VZA^DJdg>8+H$N ziwlpZJdZ@EbJxu_uzB?Fz@U}v`&!+__UdXZ>^WrMo#jB;sP!xGTVVne;(4rQHR#s{ z{5)TPwlBr68{a{24_f3>vwKf58N8e4=>5-EBU2I@0$ONx)7nitt zI7TUR&-$6BtjsP*H|=59NL`-V%?(J?!QRuv#9&`|iWKRa2f)I|0~HjoNgI0%)Q>S4 z80iu7!{&VXECboOxp7Xht+{+4Z&rSB{Lhx$VYI$j4VO%^X?h3D8#sM3_=6YVt;h^h zIisDyPd(gUTR8wqXR#SFEs6ms#EfQfvZDz5rbyEz@q4mkW{vtp`2O`s9 z$4eOF2Z=0Q1`+BYkMJuq;h9j}S=XleJpcC4>XgIOx@0ZZo14qbjz~!?Uzmi=HMAhxSyV*%Gbp{A6>x6=r%d$mNdTKGT>?Iy%Or zcZIba5a6FP;We1vJvpg$TjK$->;-kG4QDKsh}r#9Bf?@2eq7nq*$hA6W#NSyl>vbV z)_SpO8>jOe=NxMxP~I@*q$(6{a~%QwD$p>7X8X}}Z_wrfYVQbqW}E3(dtORW9XrLOS12~F@&XW19*jaNm5A_eWQ%MJVbdzgH@|7s!#q8*4wh%~- zUf44u?)%3O?eelRL!abx9(EqgZb&(31G^xZUp(fcZ}vSsFiVkET#;l5@bD=E8P(Bk zg7bgY5O*33?~0*;LHG3Ia2(y@7CAZ!k7Q{b?`Hc;9CL^C~?f#O`eoT%?AV{)h;?ETDTJuF|7ZLc?G7 zZS3dWFJ=m-+SGck-K|vGO}H`o);|QO&saDNyh^eWX0jg|E9Tj|r-?uxOBv)VDh7Hj z4JC5-wBXVZ>VK?Vv~~N1wyToomm5$vJ4}C%zEx;+srd zUHcPJl$l(`>)KyX-j&gY(zI_m-f21Rjt@jW@Yu4$m1`!|lI>UFE~CMRwE>-YwF50U z$a~L)@vR~RN+0A>qV4}d-YU6Z(Wv6%ymB%Ny z{}9vnT3xH_K8DgT;^acN3lgRc{THKr@P<(P5h$W51jAyh8`CF~vUv29{Gp1xdHZd? zV)ri|OR>9_B0l)hlcQvgw_&05t2HYg5K7GJa>@jQJ8R7!485H+TesLa2{$Sjm7M^3 zUPS!vKVAO_ z$EU9Jy~k21d^NNd>b1lB`f94}`?>wA1L%nu*Kymo`(0gORHOAtO=Zvnm}2?v2KdF} zFW&Wg@q9*b62M#smXwq%E-WO5QeFSzVqE$&PY9UMdGh9!TL0(bnkoiY?fY}ayP(9y z+$2(@QyopmReV|c*bc98hamnU5NLWildjs&E)Y7fD^(Y*+L%z=Kj_fK8x11)-+yHG zBF5 zJ9|kkM%~-P-<8OZdiDCXf5ffi#J7R&LatYng$lubI)Ol7JW!>*!*1I-2nZHfHBAXK z)3M_~a8y-FYd?!STlk0jZY*LO4GX`=J8g_jN=+R#sY{;ccfKX@v4y_k0~Y8*@F1S- zKw@A3-hw!5D}mSXN_ZjdP}=26rCs*;_IG)ostA`-%)T?AULj!5Z!bbxQux$2>|VhCSQVqsr39=q z5%=bq1HPISzueU*5qXTB!&{``AvsonE4s+PbIzG5VBgaDixPAWk;zuf3tCku(!OE( zuK?gMMsOf5O0R9XeoXA-MShRCo)EEN|3jW}aNbhkrHn0)rhlsnqe<7ifKuF`&!p|) z))#Op-6{Fa3@)yNN)Z!7S#MZGSh(0#r@TF>5XgU=ygMT)Ir4jtLx;Nx?@Id>KQ?j7 zV(oa(o2t=l$l?8Ku*J9cn32o&45^%vaf*iLFXOn=P8J;Q&1B+%^sztXc*dn@04pJN z0?>#e$zm<>E&yAEKjYI(3k%EX;sy5Y=Dox3@;j3qAu+=|qXPJiv4HD)zw>Xex$&L= z2-JdzVMPX{-0f%yM-}~BL>H$;e2FPhK;WSA)*h@tq4*)w{?q$$OegLjPnk*!e^Iqd z#Sm&3b+o&W%5qdq!#cTI!CdeP}#jO%r+3cc~3-tAD z{GuZ+x1*_DIn&kf?V9Dq_c8NOhRC?rPR^+!{ALZu`53SoRh=Cq*>@q-A>6x)HxRK4-@x)zA8oI5ZkLe6wP>{PH5PR*%^G zDe{AP0DrNif~yTZWsXAL#D3YH*45AztLXD)3j*}yfqq0qJb8swYc7mBFG3}Kr|?PZ za*Wk}mFZ~xkUpsY4$cAa^FB$qh!{2nC1`|R1vaRz+?vL;D@2a)3%p&g8~8E`sAznb zFVzm!6lHe&_P8UbU2g%srxoyZ=$$Dl68~B!|>;8sLJtZ`=s~3rIosi&y=ZmXDv!!7XSZyLTDRg4f zTjYSg9`wj=f!IK(%;y3i^?0 zRn7FM%`S`}$z%)(0rdTZgoJI!d80kDr@=wl^OYjOuPDj)45S)NT3^eLq3J;`7snuo zQl^P#)kQEPB0M4-O{Dpu{!52Y`;tFKneY6~kLn31>wt-#e&7+UZa9s83{&au0Uz(` zc%;uu%+bh+dbp;t66?WYy^UnID?3&hYl^)$VF-?X4RegH=%G#`_tO_%tQERIz2>yp zxVpyrNeNx3^lX}l$b2<|Q>*#ax5inYk*zHgH)$V1&I*L&FoRx_x5IoDVk^H_iZq&6 z!H;^;vO-R>*_IU!`w?pt=zKWuKNjwfXYgUePp<5aZK8@VU3VN9VrV#R{!Dz?f4M62<3IFl2V+6bitkIqJ{OCZ4<6KVdE;yfxr zTbKf@;OUEHyjbG+Z7G}g*E4eTN00f_s|$t2@IJ!Mbm}N$z2xYnoC;5NHq`hrFJoIm zOJ3yFFyeFWDAVrZ;i=@r0MtQ}O&10`EfF+%g^#3BduWVtLO=O#i$9Xua-r-M`)BGEysBVTuSxqL-3; zKc^zYsm``II03vSRLi7lxoYj*PVRrn^tRno{y{dOiurA_ekwG{UqV9180JDHNmi!T z9PL2mo;On&Rjk{xp&bjn;%1f|YyX)GOv)fQ;H(tgRmzSFuJy`dI?%l*)@X5{h(6Aj ze1j-!JQZd-&nSA|!cgcC>H5_OdKcx21I+*whCiMyac-K?{hsy0j?_m~&F0h%arLDe zyNWtD`cWSBIT7a&Eb6hpi{9CKJAT6#`Vsh3Ckp@#LI%bp#RGkLY4LV_mTl86sFHpJ z({HU68tZrQ%X#oi4Gi{YFO2*>(ZBYR)}!l#)uC9Bb2>s-+Ba1d<%b5#wbxVkrFU2A zO$%LxwV(f34jc%= zA$O8Cm6Q#>@{)L~xuc7>8lD_vq>w(9HYKgu?nYyCTrc^i-%cgE<8EsfDzkX>yttSW zbJW$PujjgfCm2|5vZYd;nL)_O$;nzh5jONjO~*tY%9COjc3~}o`mSOgIx1uYBmDMr z*!YFD@ZEZ;$oqscPvg5@(H77Eej2dewl`g3Q{Z}l3$l>r&aEciH%FWK>?!(-!c2mD zZSsJZzTG}F9A1Daehq55Wsh}Gsa+Nxr>>G~N*M3J>CI21bY(*!*t&-pzYop{12U>C zCB1+DepAxcwq{a zacAfT`5-p!fv`%Y?Dk3(YoawZg#kAG7}1VT}eE|`>UT`Yz&rf zjgcc25wD44Lo#nYi_W(};DTt^KLzHbE8Nt}T3?6TH+ho@T6Y-mfn^=79&A}Dh(26# zjfCZHjuId_J}po<%wwhAW_X}<2Gt=uSKcBZ^bRUH+L|8u$Yl=2kG8*MHq^~sv^yq@ zBfOS+FQgl`RZ^Xf1}o}a@$10M!h&VG)lNKq?&TG#nhxdeu zI|ITMXf467DIA(DB4@qTtZ6iM=BUAl2Uby=3<#pc!X7)8vh2m8#}Mm6ul(pzFQO(1 z+Pw-1;bhWmt4`Fb_Ul8OCp?yu=8PNLb4lI*Ii0NZg#2I!=-$%U-B{V_EgWvhsv|14 z)+ALre0&V3k*G-eJ`4Mjo!f@SC)2}HTO>ZV@1(z1-(J=E@}(TvwJ~a^UHWlgec`=VkbU?xgWVMqj%iB59q9-0?*+dAJ5jB!fF3=E zd5CqMGTq=mg00S;Mss{yp$ro%9c1RNFRUDi7pf#s^29Nbn%yAP;j(j`1 z#(3>)ij2fOhERV4{<2rE!vBaUIuA)ZVT8BwmQectFSfn{sLifv8+Uh#mr~q|ODIL! zLa`S2Qrz8Li?_I2fwpMTpus6_#ogT{KuGeZPy4*@`_Ftc_hd3j?%YTA>|T4FJ-Y<0 z+?1E+ui3LdeH)SS_T1w@URX!O0`WaVlt&ZN{6osW+UY{q4)9z$3ykY{LX+mJOlz!i!PN&&5wy zg{IGkD5>L&OfXCKs9wvl{&3PQiW$e-U?HX-x*thJmu}zqfy1~QH?owO?Zw`M7P7(^ zK&jbREt*y=sa1Fkp3)@{f3qa|*y}lpFEs^Ca|HN(M}4wjxqKZy?)}4#3zMAl<&9 z9O4EWiL0pA{k`{>Y>8SrV~ul+XNrEX9SP^WrMF9j;4dFBjB>UElfVDoW4q6g`6XBp zowC{%iY*g#Dt})j)K-);KTi7L8O1YsEA9ygIl0GwGxldcLb0|YG9&GCv=Jzj8qa%x ze|vt;<@ih&$ePwTCg8aHPl}GQ&j>ou^3|eu4jT$q?^KeRDfa01qgzJR4Oa-WBi6th zgNCo9jZN&h&U89yUt>FrK4TfM;eTMhU{}FBUAkLxp`qk5@Vprgizob<>D%Hhu}hT0 zYbZ(+0vMD^-Dx~s8S4!t%1ep#iHX{wSr<@11oA{HdcO=BCn+HA0+Y%P&!Bbf{Y)He z$}kiaq0>65ur#Sp-Vl5wL+td5ton zG2&^Pf1^LY##9%@J0nBIy?;WHIJ3#5${LT@Bfc7&%CC(IZxvRTrjL=^LR5IiT!f?~ zl(s}NzeWm{kh7N`b7Vhxd@9OLi01aN9YJ2O(ZQybw#@JSIvEAxt+)TP$lkK`0Z;M8 z??Uepl1;Pt*ym2KU^j2YlSK@0_GFsAVB_~Xb|@6E+4@f^xrwkf%3?nU-2A4X*XBvQ z-Z9u!&%F5lgisCZAo45o74B|c_W(=c!Qotq$oF1rhC0astwlE%?Ay^lAShQZs3e$w z^2Xya=zZC|mj;S-qa})DO14of13#Lrh{mF;Z2Uhoj=wA-zAMj9jc4baIY>>KEw2+b z+(#IZKPBYE{LZ0DlXLwMx(GiS+6|_l>%^xad3x+I5)WOXQgI#JMpnvE)kyRk-_zBE z+u~@yQ4WEC@sHYNxwvWEA5r#ACSa9*pxQ+1S2H_oEAG1ZYf5ceoRL-rT*?Zq;1v+f z{>DwXZCQoe{uW~w!xNKrfVA+V!W&5AN$(Ss9M-3_C3UZ*-ut=xDHlfc;HMBzKst{M zk_izT*1;b?cIvTs#amDN_S_&45zaI%{QASIJ1o0{>+2&3z=w6^cXa)RKw{h7D1>-d zOiB#N_bFEOc)z0LZXU=_y8LGI@ozNXRf6^if7;nSAgPT1rrOY~iLCMhs_w)A-hnXI;oVZwjs@(G?&&i8-W6;Sq3bmXOv%V}&UMSa8E z#f3|3616ryKK{1Z{x3f86H8W`f813?ghWpK@ErA*4I)6^;17o0bod&rD;m&YbFFwE zQ}Oa7|19E8ootP6rdSs*PJmFhe*2O*sd~EDnDF|u{%2$=3}zGnP1A;y z$Y%qDOaN6t<2%-4uPXanlii>q^!;Ip?hK>5k0$Nj{Du^Y(s6w)S;<~0z+bA4G z3nrcqUsufu3rm5F9lx%2V~cPiq~szhiWM(oD~RreT8VJ&y627?@eF331iQMOTmdFy z_nH$+iRK(nO-N@EVd86|q$Z#Cg3G_nHa|U0w=yu)pUoupZo91e-0x@RMmH}c<%96ZguI|F? zTIgRvLms@O^plFO2v@y$<+9U^T1ie!iP{cpsslDhvY2k9J=c|W6lz7;z?@^p#DFHY z&cW=fOq#g4zA+6EHQJxtlSwg29?DCOFL-RCXdbl@*pK$6W+To&_qSu$|4 z`1+_7^dW~qddwYL_Ev?q3(!)z`XN{g=L=vQ%SV@n97|#y7Eb&aAWq|EKae&GFcuVs^*m zED0$AVOz`$#0fIqA$d2i7y?7l{3czO5QA^xh&Fke#QoOr95S&$41v;}hYdq9Ynf_R zn<0D{b{AYl`Qnk$r|iMvtZyPxhk9>EKu*W9zh+S@d~VoZxotnYcK@y#aV4kn9k=DP zR~}23oc%MJiqdl748G%9Unl3kajA$Dp?icZhu@#Ah~mezG1q}0CoS^_2R0sX7<3%T z$p2bXD#dV-u$?(Z30^^Y-}`BK+(;mv*H*s=>anuOb6ts@t%cIy1gOYsJ@p+!v(o>} z*aCeVMoIzL_H&q4>Bo+-N9lS#yjEt`>n%r*W;%&mb{>@i@5IRtQd9Y9$RbJ4tI_~- zlCQaS*cnWkTy5V|CUK=NR^m-?yL{M)^N={@T@JlEuc#))JV~o=nx{}decPUG3*vc7 zB0fqQDf5x&W)Zb@;l=aRi<|-}=#mrx#rYjH{2GmN4;m!b9zDrQI5-H;k~BDA-L+}1&&txHQ9i9hi}yjSQX1UVezKka@{_#oNB zu_2c&YDoxkbs-!J7;CA>8wGv~|7GJYILzh(xF)Bz$R=wU1)!ohYF3RhlD^hJ>-&U6 z6J;|kB9~TWz*n%WF9Rt_z~AUvN+##V502^@Rp+Miz`ck(pXaVS_4Feu1VjAipo+(Q zbk{)B%g&35X!ih%LBGD)^C##MUh=mKsoge^u3y+0#_GF!y-Qft8P@svyn#&o2)-!OYu>8(I;dg_C)F4I|%7e z*Dw;9@tzIkF(b-jCm!tlLjmVtl!JqV?;lSD1qJ#1_F}%0DsHTyBuy4?u2jbriW@t(Nn)iMyJo^WFKJ!qnAs7 zCzVb+eXJ)WKXtIuwci$loUiXwhnPO6sN2;= zw~{?L>OSQ{rruwT;!2+u4MQGt#INVMjx%Cdqk^zvX@fia9Jd50l_KVhi`*r8&2)jM z33F)RYy7AanrbA+4te{b8R?>eRf?W{A7R{~%T!y_H-&Zt5zN4ph2!|^NN*lULlbNY zwJvB^CY|T)0D!7JV@QX#UuYRPcB0VgzLuJ@@3v@2+Eq54S)8Gec_eTt`4B7Z)gOOY zcN@i?2UG-QVycmKB6n`vJvQaq<8p-S- z{rcc{bedb8<~Pax5L>9JH`zdc{gSb&2&!{J91n%NNvRQOdd8NIRwlDI5{sc z(;|jFg_DkVX^g3y=!Z^cOG0;%sdf+ny@WBPj40hiiEGk$LOIMRjEKCm7R~Rulv_JX z#}l1d!70(jr2&n+J~1gsRnOZKYoFoBgYaj!zjhgvQ@`6n2v#?#Ok|oW$&aKFAwH`3 z1W0m9a#m2$57DdesnX8P^C(*;g_DjChX(5 z&3lxC3jIctiP%zn_HhnL`FyRama%}FDrLLh*$(#xi3%N;fHsHOZ4cm8zJLUJY3J#Y z%$5Ks$9=by=kASR)Y+Rx-Kv6wY-h*7^{2UvLFst7UeU*h6wPLjT^?buk`*4-bCV9_ z`JU)TO$SIZMQeJLm3w`@>$C{KV zd4cou)LH4?4||{JW^IHS7bqETJ?){*j{dv8l^-v}vF`meHgZnAT6%{B)VM6g*jB1! zt9Kbq104FEde?}iCXphVZhzR@cDsRFJvY|GRdJ)#qJwcC+C+zd!2lHhnGh|=7=p7?lU^l@C z{d(z@63I<^_spd84d)Gyoblc~Q8<&Z8T=U@l#S|b;F@Rj<%eb*+gl8@ou_gx(o)qZ zG0r#xQz_P1vxZz6Eg!Vj&4C5$%MCwXAxqlNY*!fIZuk;(`3-UNR%EUjR7@Y;KB^e| zL?CbPFrq=f%UgB3X*1nS{ex>=vN^oTjUU&PHg*3cC|p2o*fReVX2fgeJV(&JK2s_> zMhV9d=QA{Z-fB=~ZDWJezajb1cWX60%BsI_5g{wieJaM(QM2pv2Dm)$CYCIM%A*V> z9voVg@WKfK&oMhGmrm|La`)}ucLhT-RwxYSxlBHXkWvl}*;-7DT})->ZEqE}vjA&N z+q?Aq7R|>oiA7P6u}>6(zPyl=LHj?ic!iEIQ>^ql`W;K0oRrtSTuUrKPzqD{*`YRX z)*J*;cUIo_yX$4Yjo0^p!M4L*&-Amb@WeMtM^ypWfK2_=$Z9m!#ik~2(s=mhY5*ON zUi1lN!1?Yl$wOnnY0^_I_#7cTU$-6LSNDNO*C=q4z^{aIsUk~+QB7o-0eW7_wAZ*C z3AjSWTB8GRSGC)n!{!nKXisQePhf4B9!m^?2ZA0;zN-)i2vkHG;;5Vs(+0uHgflME z@*stGxxAa~821)|`>3bx#mdfO*r@_NN5;2zs_ADiMD{1a)KmC&;C-4S@{7FF)!Q9U zwG(dAUh5GR&cIa2^z3O@naqU$74vETlb%$_Ec|{ooewSufV|ytUaNxd4GHTyk#2wR zrrfbq{t3@XgVP_jZZGpfYx6|TVIr{ARpCko**h`8^KcLh=P9$mNgiw}&%?F48RWDc zqI&>haa~|S!9*ym03=%IlYd0^kKht92VXiaQ8G))bN}-xpAi}cO10rz61hZH>duV=XhiGml2dKkLshVJi6%DPhU znuHm0x_VUJefRD;#(RH?Lg`K8(4iD=9p5UR;S6I}NBj8t z&xsi5o+~-Zd7b)`RauUnJbQy??31qWqJAZd_0d;BWHU-d=st8arz}y&!<7EzQ?h=Ar9fy}9z28&RMQ%5o9@); z*exO%cDm@eBs6s1;wa6B>l3|F_XK{<09ADGuvjo`1zJgOP7!T-Vyd7Fk4!20O!{wi z^Ugp1VSKxxJzPOhF|BKap?3|sG(6=K5f6l4h{O^OsrAcs+5YT*S9}zJM)5%QbM@xP z{c-}Yo&$XScN{@oEIDM~L_q%l~RmydQ@1ABM!H*Uz z&7M!k>gyXf`d%Nd-cpn=?k*P(QQE^#1om36Xyp)7@!ahy>)(0k7{E@?PzGcUP+R6^ zFM20D2lsk|x;XOw`MyIROIbxRiemC={Y}h==wr8uA8Eyx`b2MT3G^(+RK_|UNgd+! zLUiQZhvY2orB{Q{MbW|BSd&-QMqxn1&W-PCk?W_eyBymB2DQm1CKN1B3;L~c9(kfTI?^7sJJxRPfhTk&;0A~hYlV@XQKjEfKDvEQjvFA=T`r^#G zSy&7j4Bplsw#rKa1PRTzSkgk_u2_cn%pQOu!|FQaal4Hfr39K9JX}viyRfV!d<%AjJnfvP5aGAxwDw&6Hu+_FF3gX2c32 z&vci6vL2B9S{3h_kqq9$4!aS*PbV+>JIb*b$Zj8>a*TH&${vr%dEPsezU0IOLmiQ$ z2aO?%Ai?zq=&65N3lO+gY3SR>HB{Bnm04+eveafNeO_evPs zRUd8v0-YH%M{Z&-f|oIyFV;yZsE;;#Fwt#*iNSn1z3v5^6#9wexDogAuiH2u8HqGU z>l(D0K=06j`2{WMo^6-%wfXRGdAFvdB~{X{^Y&VZnw^w%z2e0;0@H!;$BVpmh47z> zMglRgG!X0!@SFFBQK%;TncwVGbO0)D5p2g1mfMtsI2i@ywbKaR#NkQTi`1vxk?2Ju ze%MvBSPU0=Sa(i4zS$(%;Y4O?54uPjk_VqN+(zXMADImlF*JuskzT(~02`q+;I7u@N! z3B+X+5cEORpsS+ewsStg1p0|6(CNhw=ZPb zb*cn6czU2l2^8DajHN81TtidVSa+fprQlW7y~M&KvE}jfaOsC1jt(7TK4sW3Hxb3E z$bqD!D6I*4_&U403oxUQpix#z2dM65ujQQ~TO1r;?l4#aPK zb*Ivq17eTraK=7j2fqFCq4#IUSgW@f4YlSP12;UMTC`}(ac8+!t-H7{oYYT#x*7{8 z;F6q#F;bEsvc+S=lU@J8q;*(?Gl31oGHoCn)<^|(aZfh571aQ0Qw0hSJzP%hqiY>4 zn!n$en>eYnGk*F>>iQwuXdvbDZwZg3MV$F>!iMIxO;OORT_S;4Z0AxKbG<&tTfyk zdKlbR`Z-nSd)l%ZjIKa);u!!YJOYAz@3M9pENYE}^3FjRdFSJ&s$_E_&|c$PG0#)j z3ozm8Lqpj$x~B@`ct|d8e*o;#xaKfPe#P5(`q2GS3ZUFYahk&Ep=#=F+}PZ_4qFC6 zNLv!pX0_rjd0`@XPOe^h`C+ZzxOb)+lVXUW?rpOblcRXi98 zYoz9Vb!)RFIm zheS>RuM5X&^?1bj&eBmVOXnEgFPl9Pe+ua--4k|T?0Two!`k9J&Np}@V+ z9Nh1d-1vDICb{W(&v}|8xv$>tv`6d{ix^&hQK#661ZNq>NDX#wBD5SM3ieXDBlYAD zSp!4EMw$!}PDcUQb2$XuuW3!t<;1AG9nu~AYT+POJ9w+DHNyo%90ApNxY-VK+>!<8 zz?_S6oin|~MLy{0pQ(;I%fWJLJL zWzOn%HL&9|eE8koH|%O`y(jWXqrkqd8(uuBn7y@A2l(w`k)mq3*VNQm#>W7ecdC>8 z4m>s2Q~~_dJci9t?b^>my;E&TW4sU*S360EdIN?Lwa81xHoZV+{H77~_nD*tzEqfP zAOAsv*~TbGj|$dnQ8cbTfUM3wdNfSaR$T)3_g#z$qjm-EWszlm{`5ldR>vBu^MudH;s3Mp>Vg>=5EdvmIFra8bMONOYFGh^`G{1vN; z-C5?0bM~xhYv&7!$6}C#tJ+bB6fL0b|JhkeQysKqs;7+4n z#p3msuVcPlC-U@Bt2!slm*^e~0g^0G_GV}`t%pm*mhgHBSMj${J>|#sUCeMqPwyWG#>Z>)&Eb96f z0Nb|?=Q#|BnC&hmNM8}dAMZ0>5sBO`t$l&Ge8t?~4*qVJp8P|${nyjRTNPzmf2vgH zC-=yT;T4;IeN~elte$y76LnS2fapxW@BrlAQPZ9qC-03Bk>2U!Q5!WWnCeCudd>-zLJb&NlkcAI;54qNVI{8!oB2)iL=+z zG(Nt~7~irv?nx|)6D-BO= zLUZ)<)O>yPeFQRTg$-39MIR<6N2-jRBWxd_u%kcMeIHljlz`P*Nc>yr5>wHj(B{#9 zSRV~Jxxe_C!W!T-ptfp4eUTvUn2`H-?D zLnn{gQ7+mVcS`uChKz9cZu2hQb=>*N|KjX$qERt!_iI0$)OHaawP&+)e_)-)!PiSU z6JuO(H^yt$aH6zv`U`UHhYb=eKwDha(9}1&2m6-b&d4XjbLURv^pSj5=Qt6x+ z>*>5Hjq&Sf-T&cB5Mp??55~Vm+r9U>S{!xXR~V3S>~Uh3K-{#O9E1jT^)b~fr?Y(x zcuO5M*LWuX#}WpA#Xcfg&^%PY*E#>Au710!9ag0IbEA~K9_?hmrQBo^;Tq)CaY}b? z3*{LQg>0!=ggBy*8=}cEYN3$LR#e6bk<0%+S9B4i4s(#-NjnJ4C@M z#q0O%#)!uJAWmGPr_qy_v_T6=F`tXqgC#Tk77kHDw0Hfvk!4>6{yNLQ+u?);{Au+| zdMR?~<0uJ2hJtIE89SjzbDZY?SmS@B>d&10c@-7;{osa%h~Brpl^WmD89eWt03vDH z=m-H6eH`4KCMo@1PF(qa#_fMOCldi|HM`xI_Y$b#9_=J8Gq)Ma;vDseW;`KA1h_mg zv`^9ezwdnfRHne+%&dFbMo6D6Mb?)mZL07av8$FFqQ9HZ5gw_RL8)t+61RcR3C}m2 z|K(Z!j#np|UPbCAXO4=aenUcwyF`7AM=55R|8Da@rS736ZN*K_;d=3P%+uQl?TO!< zB!Zm`D$3hn9zS&BzA#`a?jPFdE>D;Lr!xv+GBn5Zm^L}1Q6FB;|95nPv9Qr_!4(zU zmy7grV5}t3q^}Fhxh;+Ap4?FzuCE}Jxr@*Gu769HVhGrG3{&(92}5!8(Y^LEIyZ7uh}VuZQ+rJB4+1~2_X{?21+S% z|1&%Js`+uq7g>%gu88fE7Wmnxp%0TMFL>Kl$#L%9n*ZuCfu@{-EV|&+WoZUHS?*1K zow%o%TThUGEYp7s(pmL(TfJs%X7#2Y{FI(6#3>*LIz~xj==d{tTSuW*1(i<4Nf9_T^|n%Tui5UYZHRY*^+|X1E~}GD)wJ7j zF^g!TeT&1lJ(BtCq2$uUrY}wGpNk>VNcH;vG;Hl1b~Yt0mi@(uUo6Qn3kqx&{n;jIZ~p#HgO>p z+ijiblNQ8d6K#3e|=z1 zy170w-E*^8wd!1Vm1UgnN^_WXG6uWiHSjN6m%a)HH#aruff>AR+kWo6~{bS~xV-}R@AhpggwWm2r5By{g$ z`L(M}nMT&jz0D@Xw_Yo>*Jo17r)KNINyxQG?OB0|xjkL#KDYLgO*27!)$D<z4M zca~D7fph|tuCb;Wk;aUY*N`u;-bvRs1bQ*}Jx2sJ=7ymBKt$MfXQ2cGxecgUElDR1 z??OE*(xh=P@V=hr~5y{UqsqXgEjQi*RYK%yv@S8^q?Kbt%1Lk#_ zR*i$(HJmB0&CJ(VLfj#oN}61W3$pFL4$bKv04Fp05Z}IS>*WSkc2as=KZ~r#owZhMj?#7AWGGTKg;P4 zN<}Cv%<`-Km5{R)ySiaQTb?|jSw5jCv>cBiA)pL+-pTIxYzx-EhM7<$vLfN(z_zc=eZHx7Iz2Gkn^jF_M1#|EdqP?OqF zv}8nxo9>&@(I)z(wI{XSX=`2IthutIz5Jt7%UAva=Cxrgx3eeI#!TZW!@#B_Q^A#> zy_FA;IC)(StL~WjUk&EIY&7}~Jc+M~+mTjJmQ}hY$ngzFu3Avm$Ia~LOIXkPD(35% z1wfO-KME&05hj*d7GYwe46w}qqcstRkTC#73~P?J?R0tP(M}PA&p_CfV*sS3;p_h3 z#dmxc_D5vvASfbWUwvB1T2&6u2P@M^FH)kFruz9H z=;&;~Uz{R}j*@Ls5-w4(SZihWHl2&U-+h72O(fI4{BqJG++bmw={v(S?$Om~FPn;( zK3aNn#u;$M}jW%gFJSzQS_6d9J5Cb`iPCk#Rb^2(Xro9^9sg^%I-(O@x|y zM8$FJ8uxHOjX*qe4|(7k$p!6oxxK+1!5xAXu`jEHB|H2wkcHKg|It#xm&%Nl9^!mO zGQ)`_fk{~1qSvTwVN=}7*wTxaI>2Y>WnjtjQR~i?aK|g2FnbS6tLH`?{A44Sy{*{i zO|hQaU7JUG=b}zqYw1;dzl7ljTQPNe7EcieC1;hI4TK{pH`X4xh@R*FsKqZQr8P0@ zNRZd#K0|{AiBc1YuM&*^Q5GFK#8^$2N;e$BB= zHvZq29a@B!8qdBxYhN&co3Evul-hpWjC&((%)Mv9O{+b8COM=l`XP#YHpetCq_pe0 z@)T>$^?l3I3%T!a5h6Dl)sY(_L7BENHz$YQ1#lrC+Y2ot(=F~(*gD^2;k-CHs?+=l z(Z!@oQz8w0s?~RRsMCXEYHCVcH+=Mw-hS&8!qs%?ud3K zjF-N5gT-Z|5V^ia6ef+H&8>L;jHLIPtdETYebU{@$m2eZ%r49OqbT|!k>Vh!=U>QQ zG{p)@jK}Y|G`+;>xQT)WDJJCV_)+rS_qG>BEge#+F3rrO4(-PH&stAhBmXpaCs)lc z!0Ua#_Bl>1avvB;$dJ|1jE%SWVuZB zdqdPge_l>~ucjyNrQ)s_XJDzlN-|@^}I}ABr;>m*5nW{_IMmf;jGurqB zI)s}C1<3pwi@oL;MrOwF?tu?yPoljBdTP&|H7s}Aqpmz+vNrh`3Wq$SJ}m-)wdX~1 zC)E5bJH{g@uh{>`bwP=3Eern+I07B&vXX z%VXv|vLYsySuSi@=XXtDpBIw;Pih)ir_Pv^%p&VnUEZXT^W;Yh17ke^p{sM6CdT&Y zxFwYv(U5TkRyfOg=li8o%pwJ-^#2T2Xhwc1Ax@cQL)& zFN-q}wLNK)!+Ofm5v};wo++dwLC6fUlbG;91qH|PkB4Byc0i3_W0#0M2y*-CoXro% zEo1d92-jwQ@d_pAL8yg*I%?OAy7pu5yV6pQlZ#?`V8H;wXr4hGu-`v8!cRc%+>&p+ zpa+_VxD{1Z^UkyY%d@%-35R8YvR=SL5 zjxe1JMr6_iu7ruqO?=<7k#P^QEz(Ed*6U3p(nz*?P24|HzcCffq64O9)ki_7kC?al zgGUjo%_&7|)_?ClTR&nB#?bCcNVg3|P0z8$ z#(5tkGI}dTNs#xGWxiE}5x1bfxjlDs}f2mDM=F*F+kfGT05&k1W+V)7wo`F7@2S8#WNvN*xAe9drf=) z+7%sm6V7;Z|GH~pXvhLp`apu6bcwxg_D2%R-FvZJ3uilGj3lwTyYBEc(~#LEu*ffU zs`xLXB*E&B6J=P|r#B6o7TP2RagttzD`v>{HgVpO2I41t@QtY?Rcxet{$TL19VNb6 zfaL59AfTkzKZXdKcT-%qkq>_V*9DCwL2d~2BZ)0YU-jjCqzz|rimGBD(h$v5M`4iI z{dAQyIv&bKcYT)8n$sN@>KjDriOtf3;L|A(QtAaxs z&(ggXp-HL_WMP-=z5+@9Gj0O-X?(A=gU?1`O0^Spw#^g9o2<40>-?gTKovy#azVj{ zTbtU64ri+T*+Y+&E3#R>u8!=GXySiOoHuKS2L^r~x!_3si*Y0!eLl4_zRGypSXxCu z&|#L}j$j@?^8F?QoJrXst$aDQ2CsA=Jnh@ck<7c(=0LCN1L1~+lN$l9TmB!Tw&^M? zjCH$)Vp#|ZNgxjW?c2(zF{{Z)oY*8%3TcNcbs|Da-CZpN<}~rcKC)e>H{S+Q<^scR z615CM+#d`!Dl|7Y=ta_;4F5kE08=udFa|JwA#wyf{o<0$4SCvh+`CJt<44gy(Ipk8 zjFDiyPAZg_zg&WswC&%9{_-y2+?r_Xfxm5G#0^ z@SzjS3w~NvY?H2Rtz+_AySxyIjE9@4&=xbP1J4^GjPAXwVhq>fF@&)8Ggnuw1+-eZ z)&0vy{KK}#0+8=5;A@d9mNA7RT_id0n{*qx-6|Sqsi+_tPEuyw+s}mpc*&^hIRCW< z-i!$H#?_S+wrIPf7gy*`U~hHSD1BnSh4TG0$nl0Cx35JgD>Ba=gux^a#_RFYt8-=2 zME`Bt=VB00yX~vhpJ0N29v{^qN0M*ChdSh;cQ|oP$Gu2Ot7#V0maqa#UA>X2RCTLb zWhH6A`5RO-gSLkg&fAb?2Vhs|w~q_R?ARO2fd=z%tx#`~fS>JiauZWI{-$6c_w3+5 zYxK`6G0D#^{E8)vi>#4 zU()okQ#2Yd%7T#7t`ljvel5SpFQ}nqC+ADh>eiPnGTw;K|N7L#QOQUUA+km5Z5~|k z%Lxtv#J{=9AW**;Fp2}=CH@`zJ>tFhjLj=nEf{i$gg@@HCszhFv+f2#hj+?-4fF3@ zt^_J+|A*ydLSq9?b>*a<%vKqDhRb$Rs7P%+gL3_D9O-Y?PR_uBT;pGZmlxEST*y1l zL$UVV3~AQY5bGD-Rhhm1TsSL}hN`J^C0T>i5yOl|c8FKmM4gx5*?dl{m8tTFMWIEy z*{}}Smzl7&73U$LWL#7YoD*HFlc71|pI;1E@;unTaIP=&g#OnK^o1co?5|c4d)}}` zLB6MIqP{4tJnmc{hU{tl)ouznwW+7>-y&u)Dm4i9y>R>6++Qb4 z1});rc#qjYl^ShTCsmX0sfbZsf(VVL;19^-H744sZw>5z`GI6Ml^NkP!)F*##17T7^87VcZr?% zJA$i$8-w$8kZ+y_ZnfdDzKaIb<}@A$Yx`H%Z~l%QqD>o5#;u;2(Eiv)7D2a0J{S03nhxazOaLr@%o{w8hI??jBJV4{J^AW11YJSG0(o^$ z|EudK9=)?K&UmPZh{K*@(g48lEYs4|tkoi#qr#Mx@N$u&lIZtcn=yMaoO@jzOLSYG zKG*CH$$HbycJyHXZwqci*Cn=HGIizVng9U2U4^k`jv(% zV?QSH-1jn_VXNL$?fVAe_VMfs=PFkRSc%Fai27hQ1OcBAQn-Pb=|7h!KXUYPqr>vE zG=WpUb96j1;U!l1-rLG)ho-a@FunG-jv>2~G$5vTbQXC9sC@w!>)J zvYkLEcKASzOaE15LF$`nKF{pYe`((-);0Xc!Y1s7o^Rj2Z7})Xb29}ZfE2$pORfss z)IY)Q@z84-8yhL)#g9n{$iHo`t9y^TGGl_SYDRIRN{*QGLKenODZSk2|45n1OO(3A zL5nu{m@JcJs>U5{L$yZLyVnjr%^N!wmi8u%&F!z!!^i&31z-bXFU!)2B@2zBkh`Ld zH%!kGRJvBEMYqkZ)DQlu0!pqW*K2D$_p%>(h||b+>>Ttnb1ga*Y+ui;_5uueg`)UY z%sXqg4jW7KT#5l>blEJF-NvqZueiAi2cfh}PR})MMm6!`FVu1_iMGL)iQSu_Lb^B! zP>dLX4f+|5z@JJ&zpQBo?M-V6UZ|won zD&2~{gHj;T?GhKAmv$X4IVa}QF8-rS0}sbpwm&Twp-@iG<#)pSm8p}}&lVuBU7Qec zm84lwUOO36jW4y&0)dssJ z0mssA_I+=51y96u9+Hy&YXGc>^9#CjBs_-^`JwJV9L1>BX^QG2v}faKt99iE9-h(e z6lG-U*By$!6U!~&am_M!&&~Vk+L13Bl)>1)Y4{MHhUkB-)24Dqgp1c<$Lo9guxq{g z9g3Y@Wtm;Gkq0P0MI?u*iL7_cAfHWJ>S{)U&*eIMYwJc0xu|5*@3f5uRR$@PyJKa zfZAo6L(G&MMfDQkiG>{fot!-CuA*gHBv$~45JsuDq0_=bbyjVuYps%eNEDHseVmpiBabF^=Dc1$8qKH!kud@H}K zSIzIhBjn&gpZ7-9Qq1`b>x?wg}TaE9SN-yHd`}EFT6(- z+qEkU)>4s7h1_Q5<*icegI^0q`@1n;7K@~sOsu-_t{VP$e%J3X+=9aeryLaX&Az*N zO{a=cx3p{IZ5MDPnEo*xLBQ9#$}8&}38E6q?~q0Q2V#gBr(dV%@Ijmk11{`Wr*_ z6z2SAD2rYO6$)RO*Y2G>pBvr2pxPrJ5zmQ{o2bVL_u%Qs44x+Eu4L^aku%`Buy$__toWNyrb}2OVtQ zV(+8G56U^D|1nd+RM=q+CfcNQW{8a?8;u&gi04{>rjkg5h5 zg%0&{-M1Z`J9Yj_NfEk2ZwgS+4uRYn>TP=||31t#gXm9JgCFG0 zrI~b+B6fFhi+}>M6xROpGXfL|!fngunRWg;ztW!prz=u4M6L|Wl=nbVL*^kM|g z&WXy;bKXOShhy#8k6ZzmQ%kB!UV1g?!MP6Jw-R7FiUX>(Hb2klr&IwO$1xU7u#H~! z%ZXeCU3R~zNXXNrQK#qgaTN`a(WLL3RgO)&lpH&`yVcL)p}t|W&^hZvv_B&}!4&k- zDtwdJ1Re~HifPwtS#+*y zyT`y&!P#RK9uJ(7Vj%bIWk$gyp3`>PMT%h>eisqE{QMK$uE_nvd(lCeW6|@7U{*_m z%_x8qw)Y0(vq2)@QNxoMjyR&gUrV~3f@m;x*N@*H{*pro-!mQk(TY`yw4h;GbfYvN zjTA4dF!4mKG05FFDspY*$ z5~0P;ct?$&i1SXi>bZ+n71Cnx=$78+DQpUaV?RQ|%zHm( z2f*;3yd5y}_I7UxHtiN5EE9Jq!Wsr2FM`$X#60gVLbfHcMs&qg9sy{yTtI>Fc6s;B zKKIRlNiT2drt%H|4}$jI7%($Mj+t9;SN{uBgTG>>OGo!fVVXYpp9T_^m(47(0`A!B zAat{KBE!prh(k32q@((0G@}SRvk}tb<2@ned0FBQPf~@4H|5<;8{aurf_+-ymFx!b5TUV;calXJlfwvZIwZf(RqZs)P4*x zo~<;Le_%J0RUxF8tiH+K=O35N4Q<4~9k7I`4Bb_)5`Ojke{6jRG+bTxeuzX%kPs!x z1PRegqSq8ew20_k^xg-qmL53Oc1?{-bZIJhX0kk@Atj$@B6Q1 z-Nh_(@45TzbIvZ$ezwt2F{pu*!dc>{wJcd!N}#2Lq358iiRw4D($bdz)PwNm1%u7t0Q z#Xu6H&x+)Pa<=JZ-WGFf!(1kRmO{aw)KYK>r@VOrbY#@|nRw0x)qIWvBijcpxp@_4 z5twn7D>rU^PT0|_BsVOLYIT#jTg3Eu>zbkT`nvtrjJkO(A!w7yz|na~RX&H(r`5EA zpuHo_C?pn+zFv@ZrTBd6mOtax36W{y?|bW!;w=qH<%AQ+lK{tz@(8jd22x2A9a0w=eh&QG_ z=zELs)cR3kY~tkMbof*b{CQQ7a{h6w~C zLhYPCn8$Fx7B{(BA#3pS;wzQJpRkf9#Vy)nt_LDJ}Xy>Y@N8}o2ekw zBQ6{VW4WYXF;N5^Ghet3YNg%)6=~DZ>!0HAE3U>j1s|4per|J9$)W{udZe*%$OMQI3x=56=dGhQ$vf)mi=}p@_M2@i3y0xU#9wDh8Gj3nR7psFA%O$KQCqMVBo&|_lABRw+$efpNYh0i7j?Vt6rw2%-{crJ5F|parPFS zQGCtT#!DN+H(i5i#+O>F50O)awA=3HMK6<}Fb|8veUET4kR?iq%O| z*`({=n{BT#2#6IA4UItamQt3l{%$JtK~^8XtJR*aC(A9VNc%S(MF z73Lj*$?^>QKnF~QCV-y{_*E3X!~S;={SSup?<>1}P~?|>FeIzbb-{hKU_y&aE?Aau zREzd}`!TzH?oM@dWvc!+4E|?@{l2a%1UYvse<&ap`ov1wsKm~r%_&U6&lkiwTV+a z;#B}ocJw{hab$C?J`ZE@yJU0x|6bhn3Sp}HFj0qM>B3mCJ=}R{TB{Z_B$`(-;(aaB z$6DA<&kWJi=EDlVBm)b^Hay}Y8mRs)*<&}|@OKxy_D!17MqG;=A}3rU82LePPEoe` zg0GLKKahUSk+zzCs{Y?t_PHQ~hWyi-%wG`}>NC7Aw$KI)-cQnmG~)?6y2gd|3-$Y$ zVPgPNI3$+OQ7cxFbosVv&@=_Bk9YNKXZ9;xFeS3>#!gj7$c;x4TxD{8d+mJ*xM)T( zBiZ!fR{(BUJ*jpoWMWFRF@XGZC(f2>_tO)}g6Jr5p0~g#Zm|Ix%TD;s_Rn$h=h{n2 z@U{`-?O;e_-En-pRgpezd0jRngFuBu_ON1}lZsWw`md#zg2&cx@9pBY$pyh#8MlS%2 zw{6Xj3-M3Y5Tc&GkWfTsg2Xk5lq|F-yr*cn91}r(@Fbwq_!Y{mTJSC{xpf4sM@6f! zpYXW-{b*y#CWf#OLSD^rs-GJZ5L=u8Z+Ek>$R!n7vekgW3{wL#2Y_!5;es-$v8Zjk z9x4o^*jyb6jemhe4()SCPSx}(z|*Dpv2vAg&Y6u#h~>77#{yf03>epYab3OA5M@$= zK3iOHF{s;l1PVa%WcF%`%MuKs0l0zp)mPfMlN0H&+RQ491T;$Wr2yf&Y4OU-wS>+u zOyf^00w&Nue!SoGS@+600M=EMFt8-D{JlQ>jsH1!hl1~M%JV!Wqug_BB5>nSM&+3V zEkREZ!EQg_R=Ef|24WmKX0R{h(i&eLjTVTOsOj0iG5q=F(Ax-pcoKFJdPo_WFiZO= zTp%2ccYHb3c$TKRKewsG^mIHdyqAji)K@m^i)(`i7uy!XSu7Iu=~s|XYnhJ;9j|Rm zr^ovMe%3SANvL}z1!O7i<8BD+2lf=u&W#w-1#-ZgfF&p1-c?9A$KA+(gWl~$=m%^a_T>$>4QMH}NiNRL)(*NLHf783 zyhLjuNfU_$4dk@^#r%uXXjc3Wc-KX30VgB!%xkqfh}YSfm+H zbyTfEX%&GkLOz7^K-e^NozaW=`R#;`7Jobto_Ta`MFBf)`S7*F9538(0*+iEyXFxb&~TOXn*OL z)Z#@PmkF!~n1M_X63nt@?Dm;u=Eu!dPC3nyEsegtwb)pmc@mp&FSrcrPlT&YGChZg zlKA+`WRVKk(39D#yBNoMx6RCwhm4ahW33gAos}f2Y{0G&=QF5n{ZG@2`r79g;~_z6 zh`U`5jMl-Y-SG+=UX&od#3!{RDn4XL@RYx0(`L70%i~+sUozg6lzq1*ydDte@h$+{ z^Tyk#{s{p~)2`ycj^3L~Qj>SPdsLIDdH_0&kNY&3&87sQOW(*nJVbQ@w`@m=me+=- z$LWdtcjB7v;pw$_Gq!s7#6(5;dX&6gkVvsg}lLhna4ZbPg zshw5!t~Rd^2}eE`>o*wAm}bp=+ye(gFoP$H|lhvR`LOQz$s_8!~>5``Rq~H@HQyb;B;ncTURl6ACC8J6^@u=CpfQS+y8- z0$o%yV-B1e!>z&Vr7Z`)IPU-Cz2gVfJaDWR7~NJn_xeiMT&-V8Nv&OR>v`A89B8B~ zvEkpwe5P6TwN9Lyi<$Gcg(9d-H0zu@2Sb|{GC$ZqF_DS0!(GY_G+Z0V4D6DnKthI0 zoN^ST3QLj?fJG^74tP(Z6XCdqiDi;#b^yP%_RBd1+8K z{iU+|@Y8FoR_=r295*E*3t0hCbu~`-uf+w(RP~732SOd#mw9BinFk|LE0u5vBGEc`IFu@)W3pc z1&1k9jc{3izVYNmaJ&^W?6uJR?o>ZV-sL-){mw}1DYa51RWRZp&g;^wZ{K^9rr$?HQ^I?gK@ zCp|w=LXoZ{9mT8ajc&&aEtiTPq~E+~lUDk@+Pvx7WZ~8XXIDN4%fj^2u=?I3X$h>{ zlwPp+2cX~ZJ!oJ$GgI@39Cg<KMh;-5_@;Qaf>Hj@Kh6EPc**B{QEam{NJhXX&22!JylRU> zydve2OpifT4nHoAuYMLQ-ms9NGXkgHU&{bdd494eG1~^w2ylu4=Kqoo_YK{qY7lOL zvln_{Aa@JZQ1RBN@-;BC+rwL-M9rF&kK>EZ3&zCJL3=kX5L>vf}|pv!=fcd4-?&;v&dM{n(D4s7M+yB)I%EUUxN5L;>7twP|TnF$H62$z(+#N>!=3> z&i9PTI!2UuH0rlHc%@_Cr9REL{fHG5Oen#hf^SqiUi$0?Q6 zlP2@~=cNm2@P;})-kaFFJ8Jy?Y_E=%GR>KYw%tmwc}jQ9d{#pbs(W z(>iO9FkBqKQ}|bx${k1td}bHyX>9Q1!x)dXp(d^Pt!QO?Q~6Bwy-Ipm3J&@4Q2El z4U#n}S4MS3(iO-Wzhe2>96G)$Rx}!?pt*9@t=~dI!o;RV@}-0KVMj>gvGd3t182*@ z0#r&t=2oJAwHm40Jy4k=e9&IBXvypDG%3fiE1E~39&};YLL63o0T%Hc)ZjC`{exzJ zE9>+C&%Wu$H-B_{oPXj5p8#Bs=8p8Wa!^9tmkbZUl;nUlOo^;>xsK###t4sA&cTG? zA#N?Hn?S`gZ=~#BYcGg|2_|2Qxv$XqE*(Q@u5{b56&a^^TQdfFo5p9rvyLQ~4ptlT zy^GF6G(*TohARcpoh!jtPraC%!iEzS_(4s3N5tF@*JJqUUJ>Ty#T!x_{*50arWJ(V zzLL6#?!ih{IML?_2JTs@yU8kpd8zWy*98t(Zc+*DqQ3vUiGIG@fz`;il1RI};6^hQ z3+H%D%`y_^zyO8u3c7V&5PL%RapxDh2QJM!z9Rdkex+v>M16tPYJ(ll?<4fZ?n0T69sIHUmahT0dfz2n7A6=`4 zzaWh_BK057EfKEHNr(ET-J>uso(yM4Dn+F4-!uND*xFs+ zL-scf)Q?@>R!~K5)E~7QHF)0g(W2-7;Lh=Vz&_6WCSFyx(0B9nr2y5Vz0Z2GV#XzN z%V#o!bkSe$c~v`=+6K-YTr4d{Kn0ht6l#5dS zF_Dmo|630B7Y@8V$DHvw(-~iw8`;v{r8MQn@9)`;i!8o_e&F}0njch}-Y$2!YWwEi zN8_a#2MV^!EpBJjMmsb2vT~Ny2gB1bUOyUT6dZFjV&6WLlpDtyZ|~%V;ytyRYuVSt ziOKWW9za;FreHKVb$9CH&2ZAKjS;LYj7F0qp^-w%ZGEsv|9;~`lh?LQo_ZWOW$y&)7c_YhM%>2uT{ZNRel$~$4<5^ghah0ahJACrmyE1&ihj?w z)*;@kc}!5y)e)<+G4DeIF3F%+ic@n7t*nX)>BhJ{gCALv&8Q_c|dKAVo*q0 zj~bH9r)r%qOP$Z{&hIckFaR6*&sSp`E*A$3(;-V&R-4zhr$Jx8RM9qde6!Kp_fhPkJ9K z56oi7F)q==o?NPI&pxzm`^?yxH_-qL}Df0KlDZ{N@wgAm-B1 zq-3qA2K37FH>?WC#tBMf)s@COS5dodS1UamH(6y`+jcMScGymrctKm+2dUVPI-g>OrT-cN=c6Jb=a(77UgweQG5OW?b1&HlKrIMJ^L_3*} zTt4o%(XKkaVB{Zwr$Y`QuvLMy{c9{)LarIIqsH)biop=AZ!ha20qW0u9WkKmQqKtj z=)g0|p++gY>wnsb%QSG&n<2xC*gNjv{b_ZxfuMYNctbty#Tqhv8Ri*l2^bSf|hG$^DDl-P8nM-=65$t9v*Ku47KWkbcF$ z#6*-FY*0a5V(hg@(IraHK)KmryF?sto>~ev2BLSHgqiUFzW%vfmJ*Tjtp#{n1@ z)DT(3_8$}NKUuHyU*vDe>k5~-x|mOr8&od2OH{>?x|W^epMqZkDKDt1*`KuEU$*%_ z@_D_~1O}A@)pe83$zc%DEAB%l`Gu1_1V|DMnPOyNI%p?(@fyP=UL?ZyM( z2L1fTfQ(T`Q^3Q`OE-Wz!0CD5_0v-_EdBx?osWZ^ihhq>=J1Flca`eDQMK@h3jni? z?LseIK;>@spZg0k5mbF(h)MpvK!C6Q{x6jQpOf#I zt*L>5`@Y}g!me+ry#Q_GfqrC;`q<>>9Uy1@SV8_3XRuk3=G1TtKs@=mf)#td?4tV0$2|=W@BE!o)1)@5>2pSO$9HI&qplKsOL^(>tyfEt znm^){TuNZ-?FH!Umj1=*UC(H3+CM_OPD1NZ#`1C*hQ^dm&9W8`q&Ex@t-D;P%Y~gP z(xtBlrDn}`gjxIn&(Tv7?&H^Gz>Z7P_}JtavCFX8S+D>j!K@ab~L8}TniUwrc5 z53_=qI3R&Hb2+8z@9`Z-VsG+nSu10bts%E~7bG4H|$PnnK{y}sLJ|z+lLfeZL z)MaJUk0Wner+^JjVb9Z0h9=L0)Jy8rG5{XmNZ;L@tn*x@MnCiC@8=x_fN~)S(~BER8ARTZR~vT(977ZuGp?;%_)BN# z9}rq|DMd;^jv8x*eeUd~jV%zaK8B;D8p&ti!~>KMyS^K(s;A!Zc<4D=Aa5+$R?_ zernok;1YorE(}s9y=HHpo|U4rz<*YQheiNJG|IVE`Ia1u&x-X^~1k^oxT1U@<(r2{FR-nZKj+k zaFG2zc|ASdj#(Yc4Z7CIwNCO#UL^=p{+UhAHKan!A!YusZ~ieIF;*P&?&rz~bHr(1 z-&o(HOh^|hYlzZEY zN-M=bo%0&-boBJ(=`#_d$FiTheSHgt&yR-l^6`yp3=G^8{Th{LG4~Ku5H&muRPY=f z>4!7*T`}m$HrO|!mtf3vucBd~TZH)f4(`Z^Xjk~#2s7ZI{bHiG=IbjK=hD;DVUB{E zRlnAu<_zuG&$&PmDz-nnvTJV$soIv|UR?xx&pdJr}t7||ie6vkGT_xk)8*!E%{1g6tHIz&`Y83zeDa7=Uv(D5< zcDJ^^!dX*ILqn-6d$a9EAsv~7#6;UF z&oSe?N!rWro2bWKb3%0uGHdK_tJ!Co#tg3 z&syjoC+itBNn7a4&`1vmMo3k@L-P95XztWF8!QY;=A|sAt zNBI&O?_~O=#+4RY4^$Ro*b|JLgUI_;unY?xrv{bh{*cIHw~Y+VP364BvB*Kw#kNCsuwE6c$0c+r8E)Zhl6q*^DWjpR+!> zqB%d_wl+tGeHkw1*et|3`d*=OIBV&;J1r$0YTUG|A$0ui!xW>3Cg95S6In{Dg9T76 z2z(g&QvEyg{48G!YrkTv^u%VtaNV8fABH`0C!*5hbo$&WF`7>}^F#-CBA#gC41WD! zW~NhQ*r1D)rR4`m&AK&G0v}$WaE>B>OEr6tEk0UCFXr``>Rp`QCVqTdvlkonDD&JT<7L1j(SAP z6&s?ZzI|Y!FBlRp&Zo{GE+yfZ?R;(BPsQwYl7*rqhOfD~0X%H}C~zSPPS^Yz@@w^T zXyWiY7u20eZv&>6-Q8Dn26q*H+nHF{A;upDx(KO z7)&+EtR6m+)O2*>zQ9|tbU8Eph1(x%H;S3ye$5cAs}whD-1eNw!Nts*#G&6Y8^k}q z_?tP;j`8Tkl7odjQ&h##7oR1b<7LKcIvY|CRm+YjKF`jw+yW+gVuay6gNpkp_Q zpBcp*o6L(ut@&Lhb308Hjus!wdWZd5F(YutG3%}F_FqB-1#8-q`=<{t-946ljTFrQ z$v={)zxz%Ln?b;A+MLaJR+(_L6QFni0{2JG#=NWzCYSqNp)XHEbp5LlHidJd4pR9R ze8&6T!e+XGH--wJ^Zbq-yq-`xJA39ILRAIke~o5Dqcz*(P=UYpRVqPQF=F$Q{QOee zZ63xK6W*!+@}FJ0u2I9vKNI8Q$HT9&OM?D!=beuq#E8Ev)JAQ1t%iQxt?6{-?tki* zdv6eEnbc}%L4<#i*J-S==Jur@$aaC6H~l8-4#pffL<9G-Kwe=F&7U+fV~+UsxsKfw zrRTC-LzsW0TICNhdM|IqU1z;>UIxq&b{=EU)O}YI+N-d zzuif_jc0bECIhiewxaMWF>YTHl`P%VK1azV_*6!AO@WIm!@H)44yG8f`0wDnzo=OO zZqG=0qdB;I#I}}E&Zc*@Om@D++xCgT_Z26%mtNO0mqk1H)AUCrL!Ky|*AaKH0$CYZ z36dAj|1wN}J36Je&G=J$g)ja^ry@^e!2wW6o`x6;<$AjAdEVKbZoFv7>*eg+yRduY zl)z1#{>}7H-uN1+Nlia4R-ohX1j1dmOk!655NcPqcWtl5{cx@4xT0egDe)B*t zmd72KPEwBZl2w8FxBnntwNbvcQVVXju3-ml*!Z%3_#;U9b)w~FnRv;7jMPiy8=C}pgi1Xjq_WrMM#CZrqlA5QNN;_fwe|$5l;1SZ|Mk%}^ z3>Zk}i2C;L0fj-<>5NE$m9Bahkcq}}m~P2`BTHs4NPezr{7r<{doQ@uer>r1-tWC`_>Te=9gw;2U6ZO3A<_77pVs2@DEQU zq1($`&m}*Y+&Fryt$ECG>yC0nY;1Z|I47HMq9vM2emas&aOPCuXjGh#p)@GNL{T$Qhc zlvLN6^=_vzlSABOQ7Y>atnSL+TmT1R!)qm=>*6xy{y3#NYioZMp|$55&_w`&U;b-t z|I?N9+}XB)fqi#|@@qzlD&CSh8is`d4m=_&$;N}a#N>% zQi8|J{>S-gMZ+NM(cT9|WY!CrCaW?;O-ic1FAN6$=)6igf91nlaNm(PA1t?T1%g{R zWl8X_i7Sc#$C2$o|4eg^u30}c=ot5OZh85x=?uVv@PTt|&{PwRd=VHhhEvLJ1rHcr z?~ouQQRNnN7d43MOinh8zu99@7|WsIFu1zv?);f^^79n@!d5dS-2FKWB-f6;7MTPP z2dldu1C*)lD{_#7+v~DcJ0oMlba#q^%IoWCS9f-@t0s`h*xf=HRDqZ5miyUCE<&P; zP9W`dwWG^s4y1Yid7^|ASRb{(!M53n?Mi_2s5v`27A*LqdMo78t|VD9uD-Kg<}Dg4WwiZEq`k_qjzUrS#n%UmJEQ?E?DTx_{H%-SuGQAJg}0 ztv@?`Q;S9ia3*|G1~a$e@geJ(F`qdCLDH3=#mtw-2ZdFkTCXY$WmAQ%Hr$mdwP;=1Y_ga(>95T ziP6Fh_F&+hU2&W+4__3qd6TI;1 z&+oE!v^(O1C@+sQE`Yu0a^uP@;3;k1-k7S}_ejurg3Fftva^hjq7x`cv;IOF*kJ(% z3m{BaUD_WV!R(P7-7GFjzjq2VZX%j|pzFKa=2%i|-Tp6^^g1^=c|0BSVY2RGmklnowKU zUC~%=*_U6NWl}-+%ue$Sr~9^l4Y(|_sC)SOegq*JY+RS2pvz;cDHCnvx&NBh1;OSL zmf`2=Y02;5(T7Qhk9&Z-u}eya7`)MEP@7T-I}3R4)p5|WrXfLB5Zq2gw75i9Lptvwv`u-mksbnM!fll@iKb4Iw>hM$Z zcj$*WJM*9U$Qk$z$#D+|?4R~+9k9Vh#QDW0>vxRo{lNp$TY)6ETyaE2wN3Z~3^(Nb zeEf3+Z;6n&hT(=?Y1%KIf7GxQ|75EdsLYm2LBBFMi*@^_p2z0F%g6$bSU#_akNq>pYbYx3@J1)u;!LXf0PdUC)Ho zCwYu?Lx=76Pr|au$#+-WoC>6uyJ`kxymu1{)4vGp4t+obCgSu+(~w+&Ts}_`$xsTZ zy4B_TYGt5Q9VNS_0Jz7;GZoxVW!;)U@%0zGJ$~g$9McXf<;PbAz{58%r&$r_1Jw~e zjyP@VSLXE*0A|Hi_fq8>oUzQ#y4ZiFEsO~Gi0+k5>G`D5kT5Z^XrHag;Roy;Ai2k9 zr#tZ78xs%+vBZ*!3i**Y7bD}^;MnTZea^t0O`R^4$d{P-jh;dQ1{sN!7lB8*fpN$e zd#1R$KoKfFF85hxg0W6n29W0^FL0-$xv)6(=Q$a@YrtY79Q8i`g7EYjvgdORN- z;4@h*S3Jd@ENYx&L&`UE^GCrNdmaYNU!=Qp{L5F%?O7)kIjp`&s_WK)pR;%_)bJOg zr8ab;%kbsCH3-~-+Uk#>okGL5!+4C}grn%LHYUk-co3snVft|nuncZ(SpnAHnec|= zjsIB-{G{F49dmNWS%GVFd{)50S8zITwl0S{+fP4fJJT#LDf!6xOQfoxro(aV>7i$s z9}=CPCgc0QXwO-9ZOvhY{AtagDSiPxkHycL9u?VVcdV#aCmF|WZB8M(;xJN%kip(w z=Y8}E<(bytSFt=Cb|?>m9m*%BWO)(&nxjoFpwIGH4!8ft(+a0AGF*_IKeUvOJcG*> zeY9rOu4YwN7gWRQ;y7&v&koOO3n}^sx6amwH}kT+vyR_HqIUdz@{=3`fqq$Do}MoP z&hXeHqUPCI3lTXvQ~bu}=|<>DH01BOFuIL2WE z@rTgt8g!|#ZiNTxU^|9-^C4glJO$p#Z z*<+s*>&zSn^%SasTK8itcThxCGHQstqx~WCdaLgA6Gm8m^wC~e4%cLt3QyeuBCSYg zlTvcIr6}J)bN|z_Wr6%((o|{<<|tvix>mJ;_z>scr?*H?GK4gL>mQQCYWjEmDVZ z<>^7)B;Fo4c4Ufjc_wQHb*i1BHhk+5r3o&LnYc2sfl!E{+=|Y<^84dO={nVgs`u2| zHST966}b+7!Rc533J^6;l*?B>*){CA!fxNIgY|aFO&{iBM~+)0k#(W=+Jz!@4@ zpx$qZL!f0)SX=byq#D)>u6;IpcA{N9jPu)XTQS)>w)hpe2RqHTcL_vR2L`fF7Fk#L z0miGn(4=923m86TWRNF1G`t%y1DM5U+br7&2%H@XbA8#lS|l1;WZ-A_+(d50=z*;H zPiK_QF2&$yTfFuF)lj-Y;4|RiPO%sGKJ?}yc0Ni5dPcKR1YG>u6Z6Z z{?9V;mm#z}HP8)Qg48T2FMG!O)T9>axMWAHF5GuZEi%#24HWAiT=4MNwR=@&lA7Y( z>oV}Z=(Yy+M31LP4Ip4AtE3g#wS5B_{I5Jezku0}_4{<=>f>q3SZg^+H92M^=Shq5 znCFb2m(NgPOuvTKS^Ca9c%{qu>0OZQOcBqxNMF~h^Yc)U8E{QC+T7R@{;zsW_!6i| z1H5rMYYsevXgv6|=l%ne{8K#g44aqjdE>Azw*I!rWS&(;DksW|)jiiErMo|Vab-x@ zWvX6{dVj^6Z>8(Wn*`6)Baz_@%CjYxz=@|vM=h-n%aiNx@1H@-laajpEyoYbC(^#% ze59+G{w3ld@H81?zjRn|Z0%KK;3$@7>W{r05SwS*Qp9&OFBgYFPNtrnyRh{ffKDTG zvL2ZHOE=C{W%?cf2tLEk}T#@qIa4 zOY!cA@8`x{uK6Hk?V)JG6!zXRgiQjw28LexAOuTl&TW)F1Iq5|+&m1e~=1N@wF8h*P8*K7kWzscXET9YoJXr$XGeiY zoJT|V0#DikIZa8=)=ZJzx`?xtvje0qc_jHD2tOHElca)mmy=z60mN4Zk%vgA_9PNv zg5OC%n)c+3|B5Q@7IhdzA30}@$;uX<)|l26$ui|Y+Rs+7+A?ZCm%R``)WL8yK%?Q9@OPkpuS!7j?S$o?ksqV?%VDtH z8yhR!Ti(@V0ajKL$TWU>6e7y*Oa7pjfOkOS*CHeM;6Q>=4kQZ>FPaCA=}l0MVRwp7 zZZ42F@)gNWXtA?<6c2Q7OnbqVL|Pu}eKl6AlSwDMfX9#8QW~!v--_ue#lai830Bx>s%nN9xsvt7^ zWM&LkR=x27DGISp9Qf62r}b>o|Hs~Y|228_f547bYpr5ksj{qAP)4Gt>|ra23_*~g zn4uyfAbW%`g4}KysWKw6Dj3A* zuTN*)YNG{Rc@sV>n6O`cwUO44bLknO%LlW?Pr7|2#+ZyH=EKWpyPDKe1KzxsbkrUH zKreXJQ*f;`zhn50gl_;R&K}IGj_2_cc@c|P%VDuDL>jYc-c2uK3=#>0`LNVoW{;|> zE9CF5A)VUdkmVfta?lc`^yK>HaJ{%EvppBRzRoE*))tYM(0R?&q&2>x_q+vlCTGc1 zy|tWte6OFGE2(!E>iej65p&VIY`XoX@sRnc^{(ne_Yxg+PbpTAqC!o{!5C`O_RQ9d zxs~a5xE-{t*}#t-Fl`xnApASqsEDZWdd&beYpeXU)8yd$3)5=hFErH6jeyO|S&nte zK*ZuY!h;;R7V!1Qe2V;f6=td*J6;Si5Q>?s@!XY_c&bI>DkX(&AYUN!9CMAyq|k@K zS&j&n+}czgBSWsE-X<59ooO5b1fv*|XNx1=2_SjobLA;i))oYYmQ1VX&k@ zQqLa3wTP+!qm%Pg>Zo*fQjnTe=zDr>!K=r)Q3A-xkgrc$kvx8z+9CI7LtJCNjXr%} z=)OH7BWBHj^^R1{$5eMh>LxucgJ}&ckBFVv$Jl*lR7n_?%u_HBaFlgt1={K=r)*fK z<=2NtpR=f>+n|4gRytsN=7zVUa{vmXX@`-(!2heb0L zWJVDsIi&C9`5V~y$&DA}ZL2Nn^*A+_es__b?{?Lg_xC;#@E##PxO`r1icj)PQe+I3 z**4$Rpce!$K!82*s^iLYbEc-c?$5tb@0UAEE8XPhhZcy8@+H$bi-g2^i?Z0g))VV} zm)n}q-H^HOyl*#wSyTQM@u?5re&a?q@-w>Fqi{XNCZ-j@*8)GMkc3QB+in z2*}BT9e;FTte8y3BgV%AWEw-tem}BoY5|)t3uM#u&`E8cOxDVtiHcUh=itfJ?Pe_2 z>)Q^UE81)X7S}2U1Y(elPG8mGe%|T61D1@|O8SL+(6&ZsGUcsCjJdWw{-CJOiB~L8{^F>?O_Qz2091T<(cHPcJX`3@ayT zrz7?^RZUsfgnLL2(0YyBz1;V<%3+MxMEb2edW`5i2HSrFUOw2vMwN5TmK}5%gx>UP zjKWZFb{O7jr7}Eu%=`PeBUH}_Cj@ag%WUQPIEXXl8o42j<|P(*2*x@SV}^Hw;tnDL zs^0yUU;o{lp=r2SuBjwnGI8#z>}Rkwf{grmh0t!;BePJ!nV5`_hUHNJY$!*(Z-t%h zw|8)&yv9}LcKjTekdTMj}H(ieG}r6g;>=&1~hijGxNEX$)J#6L}`@S;<(3Av_7q(0On z+`VOn%eJ~inVEA)SL@j>Z(W70jH4S?;hM1qV0CBx z1U}MUhnh~*U|vg{|GRVPlL7j%;_DvAx-{=6U951g&{y|sOE(?)VCZQYy|n6t`8&W3 zQ;3`iwHB+(8+Dx?{1(u(C2Mx@dc$U$_5Q2qzFQ}Mj7-YCnA}2rh3-YSx$&xy-U8aO zyQOBkBZv3b-jR6fJel73PrrM53o(**eXy5yO?=FNoD%X0R6hy10LC#itbnoJ;t-iP4L1lG&^*@h`znO3EpWH&V zAPcF&1fFtg3B}Nm2NzqX?Y~uvfLwkfCF0l2frtEWOn-VEzA&JsJ9$AFH0bE;{;c|&5#!$+MZ%g6&1e0KPen@J%!tp;f2z9{LBj@L+rf(w_qn8hcVP7`hyCj$ zcgHe5!sI{Q0@#I_t?+5cgqiuLmxC&*^{JJ`F70wn%K!8z(Feisx^R=S>5sPlx8E@e z^ayJ9{hogqfBzo#&Z`q)x2*SnnbUvX^nFHc0_xciXV9QwX>qT*Tz`nqU_Qr5KtmNnrapwblARAs-2jd z#k0*-e81=#^Lb(S-2HSJdy?%7W0F4z`K$&ByINs6-An<`(Q+b+r5ZE(y;Gx2tusd9 zOyoF5`h&ZH-y6j3m$z@De)@8X50GJ%71dS@~m4sT!d(lk}b_;8apS+v)@VtRUd zdvAY^is{$z zy}iBDMWv-bOcj@u;L*N8uM!YL+&S-Imh8&v26uCOh4Jp)H-S1j>=(j!g}SM6{&+(C z%G0>xx-UaRC4*HoO-KShyYoJrUZaH%ogamNMPoM;99vA=gvIcyRvIm#5sV?x>CB`m zSJ&a^(B$L+Vqrl6OSs*|i$!phmzQ_N_uEIwF1FmM0h_PTwot3MX=LQ))2P^q@t0+s zG(IU99iqVBTJmOS$ovB4aTFdRZz=^YRd4504>TECSEX43PxJ6F0t_eXh?yD z+Cjt<%c-#7>TvlIi16ILKF!hx$_<0RyF5emZD?-PAKS6<0N&4~M>j8M8<%uX{_V^i zb9qOM3_QahK~%t4SyX&yIf`>_37Yq>SP06X5@NH27kjF%VQlCYb!UT6SPx*1mf)$K+;P z$1bH`D1Lax;{X%q8Rpt}N3F*GU6vZOl9M!K5~$l6Zwg}yn);`z%5g(+&4d60jrnG| zOHL{f9noZGG5<->S%b&{XGg4cHcLD4h?; z;?ZwgH=oOCwJ&}hFx$NTgIi*2c@K=u+kH^^9PLnuCzPdh{dmQd$a>`i8FQDF`VV-I zc*MP&z814Ui@zu2hZPsU|4l~TVBI2(Hh!4UyVC>d7z8}~=VK{BGzg9)M z9Xfuw#z6XksuZ45EG-I)zflv9EpT`lE(nKx$SAF{+=`cHT(1u~*LlEJg4s*xfpKl8 zg3Yt9VM;YmI!=a4Bs0!$RR6uR`&88i%&)&`t5eONWFli?ZibCXi#R8|=Nvh8?-o>b z5v<>?i4##XHb!0Hvp0GO@M;6sz4JqY=#KLCK>fgV&0<1z!-K$<<GyN)Fyqj@DcS~DJjU6w; z^TXiFTxfNy*G9^6D4E4+Tl`@jlLNyEmV%d=i2RE3&I>n>fN9a6*#kvx4cF^t5&8tP zONr)+5J)vCEeLNbnmv!0P1T!<3<{kiyeVPpouPPE9_l>y86J4uzjc-M;W4eGl2**$ zTB*OR)?euVx<|Su9nn*d9J8f2h!5B>%Elx-=>b#|j(=03t_fB>$F;76+9UN*gxI`L zNs!Ochdod*Nfn!H*?7MsvrV`ZpLzMKpSPb+d(g=j0L(mo_Tuj9)sZdho`o!W0+9H- z;@J1AJLmiI%?sh1v62X(;y)p)Ki&xe+{Cfx>Kk*E0@`m#7Mlc2;MLoV zxJP=GC(jomz3q=3J60Zo8q`^RDClP3kj3K+C9$9S0Q?L4ITG8Dz(xIlO z*v-E^`RPyKQQN<+Y{;_mje)ev)se(;N2|lR_&p1sy3eQWt4bPj`5IMySUqUtr|$c9 z)irVJ5A%MNb}C+H_?m73+z^+;Q*l)M*UFz%T9L5*ziDU1wJFS3pHX^uXtlap*BwvI zVhqz+(wieU|HN@8YrocYrRlHj*3s#Jb##@@T)RWO<@(8|aPsod*GsK)nM^BsLd8Wg zI|H(Dfx+(Z(uPCOD zsy+2Bn&=0cuxedx4t0O+E*`4w@xDJtLaqERZG)N~=}!o@q5e^uJm0V1%d2mn)?6J) z{p+e`_=n6&IGBHh2fa$7ZW$f2Q*_i=wP;7|fIQ7xrD5ei2!H4Iq%cD0%`kZtNmkziMnS~d0L_Pgyf2VjdM(ZNdN6w)YN)s@i~H=;0^1D$a#8i( zF^$(G)Q}g=5YUu!r$KdXq$jHyyw5|cR{7h>Z)-mg&;s_y^x)`E_pEhP_0dTSFWYnQ zvk77H73odYH>wZ+gM?E#n;CKt?heyPBF z;wCsoW*!Vt^`$lg_p)~ti@m)iDcBN>%kDBZ7{p4zZ@&g^0pS z)i7G??3-6j7~57FLOikYH)J6$u1b{wNWFk6ICAlx^->+1?S?fi8C43dK6=P-H|U!r$%qRnB8F@WsPXkGz+uwxS#Fud)m(5iq{3 z3jLyiaH)xWL1$KbCkok03Vx`r$iHbpUls=`BX;mlZyxnauo%Ri%yO1yI;g&iIDUg_ z(WJ*w?C-3h_>_)j)tFOcJvFPK^<*21ALVdhBND-rF4=Tyu{t z@9nh#;suV~tfuh%eL^8CZ)xtn41dDY_-sIsu5!*%!#sKoqm^wGEQt z&D`wHT;cL~$MAH9IOn~AmKJ1m|M{~HQZd!&IvoP5&dIQfWos+QH4`q$E2NDr83yme zKW%X#NanbbX$>PId@lkH|0Zy8S;Dx6_pS+7nDPq_jz`SR&G}>d4Nq56B5IPR+-jbs zdZv=q#{H7e*WaL2U`9(HHL^11OjrjqoHK=fVPQ`Yz&a>tV>ZdGN8Do~ju9^9CE{7z z{htgDLHup1cbz|=)Y#9S4A8}Ve9p`@6DV6NOw9SdIhDj92A2bDyQZv6cmWX;gDym3 zDCf!aW^RZvy@Qn>GS53@#bckZh@R$!3CG)Aw3^7s!eqn%)tO1NHo8a|e)oGY)xDu! zZ;KsJU`ZEenuDo%eO`y@sc9z0kEaaxGq95V z$LaE`!aiUlr7$+iTxF(C)x>hAZ|adjtlPcHrH{80@ZQy!M8tmai&lPjw{H+IhB_9* zmll4$jIp5%w{jgza*L?NIJZ4hRu&XjH%fVmHRcSi7cbIlYc$8373GiG$>$uvY1+SN5{@Ramcvw+5-YF5XUkKP?BdZ2mQ1p!4` zqbR|<-x>9g(A)UOdHudI(P(dm6L=MbfD@fjJ~n%7D5@u_{UI?k@!*+xUz0CTlGDqB z%Sk`T^36LoE|AbbAV}5^*(uB42?IBvJf4~u%@{wne(zH|q#X{s@OqS1;<}r^zqNA6 z$%9IEqj!&jQ_hM6u^43kLR6G!JuopEqff%d@veU?qN}Us5!SkA-#LHYd_J#zk=9_- zaOO?w@c1xDcZAd&@8pVR$SRb>%mp5Q&CRDE}D8sLFSH| z34ErrzgyX~Wl-NmZGtB|*`hDu3h%w*>z=_M)omQdRSQ0Z<;msd8zW5KvpL`8B{m;p znHQEub>4FCwl^H#?q7!MiI;r%@LWL&Pf{I^Pa~FEwq%ub&e>S2^2KdqQNjY%=cSXD zGsi0?RjgPHBaJ;Gv#l4KhlfqV$Idx!Gb!f~rXG_gr*^0-XbIzPp$JUchv#J+fByku zQv(?Zg(=`i5!0DZutgC8n8W=t=j3~EhI^h9;FJ~3NMvAuxX6Har)MRUpG|;kO z^g%&i|MT8HVjj&_GRz+~y`9NKu(7v@#?C?KKSj@ zH7u!r19@_})KEQlu6sCXL6BM&MW9E0NFT zM^=o@FZmW@A=(W3hbVCL8JTPx>ahZ=tRES_^3I+u;cm#7LD3ud{hFT8WnZZ5nmqbx zb=`YB9w)mr!Ky`=Q7SrLIBcAzV5)9zu9z@jOAIgib$gOG3;lkSb+FTfZS75&5!$vk z3?1`Hb5jL6@|Em?wq-_I47JOerPsmdlauB>YK^)G=`PGW-W!> zvD0J*v=eR`)p{#K!r=*Ntn^?lI7rz?7!ql)-4)~KZKZ4>RDr)vb#gKC1ipvo(xX_) zsUsX8FM_u=k$a#ntri%3vGf+Q3;t4_p5Rq;{9&$%i;=sHtzmT@mDwX&x+t-KNjc={ zv2hd;A5m!fn4V50SW4{a1j}msfdWdr8H1Us$jlZcIFd{~Zw34t3VfO!m&IRoPHgPi z=PDLj#r{QwvtYX}sB+4}GnM;Sv{CDLxYk(Wh`G?b^FPSN5xOlx@lj#e{T78kKl~FD z{Q;a00yY`;-2B;Jr|KWyefkW&D%;RQHxFL<5*m-(4j4E5xr1lFSU^u10QywDvFTM2 z@Bg{`AD1UL0q|>){Y2?Y1!_}QY06G{zo7q6)Ob0Pq*^wA*uE{0BV#t+_rEpu=kX@2ANBBc;1q&!HayExO6R$M|pU`}30I zze?Ixoa)^ASNq}rv?hMr4E&&pT>g%|__!7p(7>3#hGT|Pr9cKq}TAm9pOu(SsXeZ3cWyKlfni6tc^ zOIb-tNfaWL<0$1^C`?ZY5K5d1t|KKujpjEe&xV(M{-ZDf%9!}!5 zbRr&y9zf+&voaZzP@V+)*#wyyXSt zt>bIiadJ#TkN^?1fr!E^mlZV6R;^pO6KdaZmZVyk2BQApon2`7NXyamE#z`17x;*B zG4tqj#=|$w%){pXMGw!|k2KG+uDJ9l*-FCYsYhkr6UvjK2zmOZ<7A435qVz1+wQ2q z8fEzm!QsQue!J#F1#-@K*9z7%BTv(GnPMoknRMALEoN&-d?M{mTC5U zhBs@~r5fL>s8v|Uj{~tGubWPvg?f0XK8JcUu+7O7w72?%-qa(Hq{$}Wp$^?XRa_JC z6j8dR;^xic>k%RS_hphRPF1{8!iQMtWt_?>&ejKz(~w*fEI9s_fC3aU%S;t9m=X6i zIH1ApEyO<|p*547pRbk`!0886@&(gNw{JTZ(ys#?E>-I9e%#UEv#X-pIq&hxe6EbI+1LT!S)BW`ZKK=C(? z{rLWVTY;BBvT?Yu72YTFd$4#m2d<<=J$hbJT;nZWlUn=4qNE~`8mDl+3Z<+Qpl{F9 z(j2ob%ut$*e>F-=)^botH^N1utEN7_1%u>@-$j)7%aFZ$_^*oFrrd8*;>wf~P&GmL zcfqdGTV9VsQ%A70ni_>6tfyyE+nYDPSfQ_6F$CN^ww41gt dZcy}qdVni_{rcxl z{_TxL0xyrYQQCBV6S?6W1O{V-&8U%$>unQEM37xtI|~!Wf%)>LHEQS|Q6 zfQ72Nr9k`-J^=AEASg$3`OyP22UB%=4#NX#ZUm)sxh({|n%Z(+s*T?6qGpyfRMvH* zCIZ%!nQaZtj(8D-@I7TQOQK5F>TcN0cL0OL4KDt%jAI|jPirCv=~l<(wZWnE74dlT zyI{1BPkdXHSk~{M-27G?e_+7DUz(oUf9J#45%b~3ssR+R054uxIpb1499ZVuS{Umw zqJ5gF7lpR4h|)pC%0<3qK~Dw1HF3Ut|mpb_hBftIDqJkmZLhPYxc7LVxc<8%-VO9_P_?(cKG2q4c9& zl9?Yeg|_Z#TGzi4&*;wpNAJkG$XnGk^>Yi0(Dy?B9mr1zofN*Vo;-}U96YePr$?r5 z-p0pzWjOlm;l9ZOPQJ@ZsU}5T4-jJS)I9^Eu3IuYg_7$_2Xbv3J3=a}wSb@OE6u4~ zO>2~^(LMYPNNV6f#xWnK3|W#bj|UDU9Q_WpL3`zdPfA73O3FgjOeV2e#MHS#m1d3|b@axF>Cn#h3oD1FRJ^RygD18_sDvT>&#S2Z5HOf3 zNY&-IZow*9p^njG4yOii7w3Y%r(qNP6iM6o_u5VZh$tWika>nk`hBhvMqdi9jA{+# zw;RMBMj)3+r^`8M#PV_hl+ak^VDZv3ZN7EWyqSst|1WOQKas=d4IWTI^&=@fVop)b zANcA2V1rK(3%(uTrS0EXe-R#R`@s}o9pAoSnJ;0kHS6%JVCSnh=f8yP)_(Qnc#=Pw zR(lX26vMM*U$P+J+9nSeaY44Dgr*RKSNfxV;TYfa z$)H+JP5Gs2h16v0h_YesxK=+$WF0ZHh5lg?2WBHJc_tWGTg@%z6~Q{QTw`*4YxzXE zotQ-W*dQt;Z{tH1tRozT8p!=+PD#tN?a?9>C464`EC8WGuQ07aUDtoh`5uS_B|Th6 zAe)o?Lh*kX|s2B6GQJ_zrI2!Q;N6K1|H%oalBuKhK5?Mx3xtj zs5ti3_YV$UB+Mp6sH>{B=}4EZy+H}JS6$rZ=1{OrKZok+k#+DO7D|T^)7X4!wk0%U z&HmNc&?S0VS;9FylNmRi!EH7H(UpDoW(>f34IJmm={Ju|ZQ1+lVQH$oDh>p5K8FI{ zZ`v;;UOlYH-`Xiz8v|G9H+s}cF5@`h!j^XJ%In8Dh}|Q~)L@tNV~&&yuL2&! zQGqZ@>*@K$s|Ijx5{V{HeHZ`QPxuAj!UjEphX8tgB(FFlJyqVKrjIl~-QHL=)nq(y zK#`H~2t7PZXsQBHn=zp$Vv~r$u1vaB(GRi|hZ4pyh0*RR zOG7>d*Imap3??l--uujiKXENU&FLl`|OmQd&?=I1~FmdxMb|?0HNUuEq+WD)8 zcj165x@R7cI|O4LblekGH|JOKjZ3|Nwdz0b|05l79k1VOi7+@mlk?h?{bm zaW(EuSFP5mdKPAd$d!Hfq=)3FV6LOVC@wE=n5ovmm(F9 ze;4OH<@c@T?-ff^FS_h8+$=lsK=#>ZU3qlAVu46Xnp$a$sEUr-d)4C(bMNSfa5=BZ z1G1s26IFe0B?DJyP`RTaUbF^|$2C{$;d5)$ibzp=mnQX9Yk(@CH0~)6KqaNgwwE)jQfE~LXJi*dXnn*LR5MEsr33|)OcgGb;*pX?2D1I}^EuKd;t(*444+|>aBJpa2y-@}8v%Bka(hxnj^Qj1Ew8Z5o8 zf#$NaqS-`1q@I6MuUB3+=Kw}K;pTpbytN0_K-%1w_xmM7WM@LZjmO4}wv1?&Cp0MP z*S6vGX-ow+bE1utV}!eqT#``p^NQ+z7mHKu&}t?w$Fr^%*H$(`gXdQ_4%l2g!jliL z2Zzdg7QB!gpI_f+m?$^zr1zdl?rsVnaRicl|HH?sXM#)?=ZlXKUw1LGf+v_{4K|3# zu7(|q&1=}_(PmLkej>_#5!ExNG0EyFhZI2vc_GW@@vBoCuP6y>LUg?_%XvHzx74~( zH6L>92(R%TW5RXY#vP7z5vfbQIkPbTEs9TD{0$bqSt_jzcC)S9U9qsI+ICla;rmCG zSs8pX9)dERU?9u`$Fdj=tyjVf%2X3xmQyV8QB-9ZUm$9JbGahe@g*fbND$Okz5|7u zenfGLK@;HS3I1K)i$Szk#zwVr6op0IYH4xEn5dVEr6?otFxbHIsGs0Wg8Rl+93PN0 zxEBVhC!iwF1aro)I>RbJVw;;1ift=Ly*fCWsuPS6oZ#w0kr2~@aC&p$g_jh#ol3u9 zB7ftNYFWc4VEW6f?D)4g`2R9z|0ZJJhpb&0X&0?DpuP;EPri2oxU-P;0rzFxIbsRG zYqE|2_2nXPRltyz=`Vc}Qv40>f4+=NUL`M&DKBsSl81Orqz4ETtVz6Y^hMTipU*MS zTJQ1ti2wN0|4zvItme^*%Bv1(i- z?O6Gwhxi-K`uVc9Y*owIR;T#o{wF1Y)@u2WehygrD}(-LFOnQU_j`cz1HNqMXswdV z*R7UTH30wEk~Qn7AR-p4E)(%ZR`=xl>#MYG`@@z0p(}NYY_yL6pl#9m*s(dqGN*?ANZllj&5kbI(}j5R8tO4f*H=)b4^U~f0YKvM_>ihJts~5@du8hHaC*%dFS0v#aBeAbMeeNe*6=Ghz2Zek|Ry;`|U#JAP)e-pl3u+o8 z9C8)5h}RC(M1c&E#2^D*2KL2EBl_S%o8-!>{@o(M6b558RuP)e1o2wn?{^s(hQYLE z*ITwA!sK=vRhNVqgFC9whKGkIu_tqa$3ksX!VA-@QxD-EmqZP{o0|(Fl<965de_r) z6&bog>EdQKtBtDjaHEW-5Xf3*t*oq6&i>-%<;9v+G{VOB;F3~~;%Uq%Sce4uPf!md3u5srq?KtZ=E<8t`6#O&rfy;_(%);jJc)PoSNh)%#d9 z^8BEQ=sZXhQt~5o|C2Uv?2L+sLB#U$5tAm-!op7z^B`MG%F6Ro$L3BEBs|*nprrKl z4mMP+{XXzQ*R`e8fD}1*E9Ddv2rUdRsFn&tMqy-g0GkzL!?G2bD!Tz2;uHeA)D2HF z3{OGqUzZ@v3qnALhxK%7WE2g*@wbtb0pkR?|9duR0h-B8-e2Pv(PY1>2TH+^f=6Tw zts+?9XoDK7?&{_Vhg1Zo*m;c{Gr7hu&RiVNv?sv;2%IqI(=LVN$WDRXc}0cG$6E zd76L8=>3?n^j1>*%DdqCxdPF82ZzLxw&{Gh(tR7*^BTY}KRpo_;@%X`h>3|ASw2nT zJgp9$|FH>J4x;tr6BEC{OBcNk91yDe3UTQW!w~alhga-P6lGj9NJ48HJ9D>K5>_ z;Km9DA-^&a^+)YP-?0OV+wRLuZM5rWHg!waM4?qw-KluIGc$F5J&$(Y=p^&$)6Eyh zGJ>;&#DgItUrn`bWzh<4vlJ75*8 zaEHq)5GX_$_7;5q&=2ya6$|>&<*15}mJ1f#$|k)83l=&Y!6ZM$W>&l-IdU-plsF(P z0C8@kDMFCuB?ZA_;N<74BfJGx()|_nKu12a*3`6V&}8O}3hXfxi9@U4-M#INPN25i z;Oy-46_TRL$T7bb6PMCbE>Lo+xvClOOADuw(07Wk6OL1zv9beS|9a7m8%jMl8o=c9riHm@fv~RqCHU z6m6avP;HTAD zGmxE|^p&vWK#pU;!C3WU>~`~nPVFW*=H>CSmb$vSl%Ep zxE@*3WD@);@uZ{ExZjKW38;!)fv@0hAmFIE2c#w@k2)^)Cz0aAobt5?lY$M>!}fHR zqXrcM6T1*wx3;_Z9vv`oT?m(b@}TmUpWTw$iWJ84I_>Uf5L4`*nWG#hJs#?xC(Z^q zTwrsicB>=lGjW?D4kHRzDxF^5iR!HX{PhOtoK4r@Ajw*-xnURMTeF=lgGUDO|^kDY1RT5*9ARoUZ&v9AtviQ0`bwGmi3`aS~=6kHa@d2J0?aczM` zs@Qc10wf}ioi}{Z44fHNfq(tF8r=jDNesJKt*-Dre}k#}Lh#g%$3UO}-@@fdBrZdR ztHx`gBM@!rI4)`7Ngi%vh6Ms(MVCDjt#>N8fVX9tfMLan%WekdWV&T?t{g^G(Nawj(PQW1j(R!~ zcn}6#)>om&Oox9#2s5)#v$I@&DY z24w+Rv<6{e_(LZ{TwC+68UpAczE}`>A-`=O-Gp{}T(}kQj8}@ zGn4>|D!zJ^1WWu1okRyXSXvxp;;AF>BGqSC_2BTy&2t{w2%K!)aBMJ~h=A?kZ=mxO zt{hD{jlnMjyB76HVtl2-%) zZYa%42l8|Ki(!X%iRNV-7W{|#kUe{l_%xZ1Lc?$t!Lp`%sP6TWV}9G^Fh~;52XpuY zBbc6RNz>;ytB%}%ZEm3Oo!$Baedn%&xmlX?_Wq~k;9T_cdh-c#fcO-7yZGbM(&@dW z_mm_@i`)ViN$c+_yw}+Ks?>rlGz=+JiYTL4EE&_sLZ!p!Yh6mehdNfgJV0mSF1yWlUrJr-?^%SVE|0CtJbx&a-^0ey^IA~qh?T5<7r#Ny>K&~A z8nE4n&WyEno3|NG87qTnelRq9iCN7b^aTiqNhc<+xKY5Agie`E`Q;rvG5>##2(+i!vH82Q7~ zu`d?j-2=!M&D1XWuVfW}KL1@{55T^&6n?Qs(5C=2Ci|ugT6_t~N4^113)!HA`Cww}ruL`Lp|byAnD}UYwbzk*y?nSW;#pGBN_PL%iSaHF#`8uLA`R1< zkS*?rk&+qwiTNNhjpB8jIMPt`s+*G(RkH^Y=Y#iO&PC#&upoT{+8)?b>^>!UC`Qd5 zNr8u8(vOf889dfV+m+Hbc20lq^<$L^7Y(@c1%@B4-tTLBNX@c^BCRMRVQS}g7#^}m zjx;cBGq3nMui|?$HPaS|lJJq61w7_!OPQC9yTMvvz>hR|@gm-qi!Yx*LM=cl(X>## zaj!U{wY9bX_KxfRJujdXhQUZyJn)xw-LL?tEIs1~qD z77RLx6S-M>%jO=>(37b*O3Ti?XirB0WN(iP^B@cddb?8OKXR=qgYZdvk|T2Zua5WY zqk8#Q6_8$GHA)Du#%h#>U*`OEtE$V!Q2z_%7vnXi753`ePVc_QY zaWx0$e*DwU`y=2SuT=lVv6jpc-s#e#Qvs8$=lgrne9cu|M7Rq6@fB%Yf}trz!dCXj ze0-1WM8he^K(B!m6xd~bO*(ganzj5`^w_;0WHPvn(aDSVPLPDo@8s_Vo}6#pYV7Xs z=9P-+u-sVZ*EAI|1*R5mF77PcX)o#1qA9<^qtq!lpWpgQ9%iF6Yz$;`-!Ig z2O9J|s4_A*|Ij?40$aFT)j$RUkrd*9%?=B9)F&A(3@h-wL77>8+!`a4tR@>62Dupo zURdnhh|5t)grBqa=$2dyBoaya9qW8&u_3rT6`^3{F!F${rJ~^Jd6CjfvS9gObf9!# z7{I_8G%cb-`}ux0G>xmC$~W@EQ*+P+fU|EOVy>E)W>a^rZWB*#VjNeiyNYKoQ*=4lo;~tjrP4vQ(+kL z!sn*lVu64H!IF#_b1Q}30$xkpJKw@CSB);cLnqv2X(le+;ezuJQ#XJ0emP?BqvvK_i=2Z~DhDm>6}i7(y1g)yT{4)K)~V|u z$lH0KQy4nrg!fzh4Kiha=SS98T@j0dSrE0cb*1YkobR53EY(M)#^LK4%16uNfjrLl z>-emKvd(Wk1VO4Gr$NdMF_3R@aOE}htqUOjBD4}2G2+@2Ae9oPzK24?e7R60J?jMB zWMVi$KkalDpPMKNg$uztuSAd8t;V$lLOT?4DYGnSOH4UGbC;2{A8b+)6cmD}xNYUJ z+u=lX5!2kLwsrb93NY4^d~>LiU{&K}d1sA~sKkH8dexYVEZWLB4oFHwWK=>eo4fH{ zKr%krPtYk|8y#9eIl>bqN=8FM5YSiayP0HL0S`zYqVC`QKf3Y1VL6}FHRbUYR`+ZE zM~|OcAMKNB^tH7gOy0*+nDg01%V?MeyHQ`2H*cUzH38>Mngw5cE%= zFH&}ukv(;2`F|AQtWwPXFM|azvMW^nJZ#DB`t|WQGiK?tAyp~H1rDFW{7KPda zNM2T%(@p7Y)nP|m*yhBQ$+?C$=YYyIjxF@|Y@3`TTEI1y#G?=I(DD&%_w|iwGm(k7 z7i9s5GyS^j(i6ZJF#Q$Qut;N3k#uS0Q1B1u6VR(ZOgSXpPca@cyjOa_zt)8`yG4Pi z@%s;0JD?D!d<;L-UmYyw?Vwc$SK6N_5D?paziI@;QnJp2BePGq`!j`Y#v$8BIkvbyQgFoe&J?En#MP*_tFfHwrf1$@^o zzFjBC<5LDQ0Ju&Fc#|VQb|5bg_B-Eb9J&f8uoAoxuLVpB(C!ENT!sSW$CdE`ncwFu za4ZciEm;Ta{)j!L91sI53cTjXjZ-CB&X$zBaxb#_Wv_hzKRr@mJhxtr4oGhE zn*K-ZjW^Kuh70@qN!VLG3PIg7lh|AHoIco-DDirmD7d+3{RRQ=xT{vR;$OqQqkSJ8lcV})Tb0p zL`MM{k&OnS8z+Dcu(Ju*dz>d9i#F`qX227L>>b3qg?$hZfq3D4?UYT48+Tx~UazsL zBC>K8Jm-MZZiqAB+?%TO^fY;*Ig_I&u6C2Cqp70xW7~Do7b_a8+Gm{HNE*30aRnQU zRBoW4Vb7kbm(Qx6Ju;ke?E2BWD0a@rwu9M*7k3*iL-F1WB+!X_IKVAIg+i0Ni#>k>-E;T|>O z@UtXN#o1_+>D$2Pp8-k`2pXAYM?IYP&lH4(fP`6+`jHK#tgFS5Q>3~eHi*EHN4FKSmoS)U_wo%FRnhw4vV@V1P=R!f^(Dz~ zetS-Q^x08hK{~{!J|vx7e*C07c!HZTP$cL>+zVtwx0DiT6C516 zSn$fRR^`-V*7dhC4=N_d{eJu?^jj1?onQ@_YAMqZ`nL4BR-mO;J%*gGI%Kb~5#+N@ zrIZ;{SBjzOt|NJxwp>ZOrMf=djpD_Fo>+8hdfPj@xTb2SefmgU>$N0b?@f?nMHQKm zHaWps;Y_++>*iSg(+PR|k}Ab*_FCbxV3yxkB@z$)9(i_TS4OU#?u^^6vyqy_^*7_} ztEQ&giBG$$jiKL;&<`00-AXWJ_0M?jpoa9zeq)e!t>_^oGE^-Z<(71B)8V+H9oa*i zl4E)^gB*5i0g1x7&^lCDI_I3{d0I^cX3o&dH8(0A3D6C?8$6bPy)7Ns6_tp6QPD%) zw6h{56=Q1ObUasnaw5Qmb~AUxl)%w&ugMR87$i^+(4BkuO@uHR1iTxrHe?DUZg0!gMc8SG!f~DfPnPgn+Qmk8hWI6kX{p-^e#x~ z9YT?W9v~3zgL}W{`^Gu$ea8LwjypyMBMB?3J#)?Zn{&-la;GpuSDZMxwzBAOFqc{? z#+*khx;nk*tlagfOW}+l=` z4ca1j1{my9)gA0c%DTJ6!ATXq!3lAb-u-&r6B8A2{m)_j;dR>%W(F4OA-Coi(`y!6D>-K2Ngf~wfXzR zSX+IaeDfH^VVK+N4Yt|Yr;lw%5M7Pz!xMK-L}WG>y?Jl+?(9&aD_A0*Y@B zP-wVdU}pxm$#*vXXZKmUA(S&m1-|~%E*B^64{ourm;#to@dF+}I2(y6a9YtNTda=z zShSxC+W9BblQV~2XqxcHdp_4Nm#mS;l~%UnM!owfFU?hEGxlH+NpF#s{M%|M}#8>1@bxF@WBtmYWlZ(D%bn; z#cbl9v;hC(Y>2lqY96E=FMJRmAF8kj0l(()s#BajA2GCH?!rM0u~Wy5hlDT1K7z! z-LjRn0Qa4lF^W0ezMt8AYq{~^g&SnCW?k1KkoqUfo+D*5+k1PqV({y@06Q`$bVMlD zX-abM@ReS;=r^w#T!E97{VI)}*6Il+6vt2Bge^RM(ItfV_xpdsTYrD&+awb@{19_o z`fphtX8Eol_!O3z+draOXaoRijk?lH|Iv#2|9A2~O_cwi+Y6``2 zRWaT_Ttq4RlR+p2rdqm}#o_ej8VDc-f&t3?G51k5jA`CuirNrl+tLgqZlN$R+`zj< zKiIai=>j;Rg2<3Ww~nnV6?3Nz$`$9M82}uh0!+}TxeBAayIXd3OSpusrtb)HdDq=|ENgQqxr$S!8pf48UL_2mz3k(mw3ijR{0txQ`QrlF3XgZpdVuI zV_(HBl^eATo=#3q7K~elrHqJ+Zmufzl$P$KVE_Y0Q9-Xn0|4_`D8bc5ulxIfn|i9u z2m9-h4JD)v%UrAsS<$0j$38~jdomuAChkF6cKrJ<;}3>mZuA3{BoUo!E^D!(vqQR zV5pC!C?n%_x#2~;!Ec|5^>+o#v%fMMX!1O#i&a#jh7BfOVY0W>%clX;6i-zZ5a#q- zZvgQct)&A-7NvrIAgM3>c>s z5-9CpZmzCQzCd1b%3qan{o(Io_L~8Z=-=KPz0)8x3b_UdTOJoNwuWY)o{%Xjgb2tk zFcj4(Uc=!C7$9%iv>3Mdf({@R#(OG&Bg0knA`cKRw!R9CaZlUu$_u+@d(KwcV<4x# z8i>^g3Ieek{JeB+qHT+PNsep=1KC-d>Awav_eGpNCb98%HN41nLrSfB7CCP4kN_6i zi2d`egc_sKJzKxa2dL=rD2^6t>KH)J*n;Uuzx6e|@YfXtG>l2#^w-ju6FyK2kY7Oe z!TeDXU;}jmMW$VTZU+#5LqmFh_*Qh^((jdHXk*LbW_E)}^DURFz#<30FlQu%IPx{9 znu=iGN@(&vdAnkG)RHx@mgQJbGp&>WN=TS=K+e<&Aq)%*dQYQ(glA(ENCDsR{ga9< z%NLTdL3P{H!JSRN8{J18$JL>(>oV+sqH?W$&w6LUQZ>g9vmV`PD$wr(JRypG(`&1~ zJp%VD1J|8`P;m)~=NCzaF5ceG2#xo%Gq%G(6{O?P&q|z>KnWLqdV6o{JzKlsGb|Jm zbRQ)&jK->15swC}i&M?I@?c>KWc1G2@v$K%@9Wp^X8R?Oom#`o2FV`tNmSM0r;t&8 z!9*4iknp+B>nbBDpcFJPj;XfIIAQhzT8Jy@a_D1cyXBoFl>wsnB6rZ!)010f*3qB~JlBEuFUO-oSNDlIKFHJhR7_H$i?$G3MY32yXk1c{ zUnq3A^Mfx5Ix_D)uRR-w6=RbmQ!RC~F-k~4F$Z8YHZyIDD%+}95n1+`Q0Up?%@euG zg6M}+2ZeA0NxMr?B}A`5^yq0sH?p7XLpn2MH8!cG-_G9WZu+oic`vQmhnMsoT#kwB5VIn=Ki|yuuogvrGx?1 zY<2sp@VwmJCzpvv$4p6eD^PE$ooK`rZPolQ>2B;^2;Xc85NacF1Y-AbmK*XWpzz zbX*6h!PIM?xkkLroAz-L){k+OnS|4BI~X!S)0dF>kg6Y;yE^vFBn^vx_B`qkx|(Rm zhHv`!guxU_lE~v}teBB5FJaBk_3}H{{OE(iz|gMBiwSLRnpb*h7X=ASY- zCM~RHxMc@334kDQgYT(u5zPlCQH$^1LOtkY4S-5LevsX1d0K}&EfSYB;lF+gO$L8s(-xONMztw;j6TD5e1Kd5rW5V8P8z#wxG`720#>$;RQtv zQWmxirClsf_yRLI_kfox0_CMJOQncy-YE8WHwSYu5MeG5SB3q#*SYM*&*PE%~4D!JaM3zZO3$q9dE zZ>3*l9U4Hn-v*(SKA`=%-K)>r>%c(0-Y}ElmQhtsf6;KWA}Y!K32WHnMmxFhbe&7v zAp6INXpYd66@B)4{!j2&eaO%`Yg^FXmWLt%3fFJ&YmljQFyN1L;Q@Lf?jLdCG*ph1 zcHCyseVAL}1BH-T=qD18)9 zMzfs4X~DUX{S&=)z4oEg;RALWNC*a~*duPN=ErrAZt5l3_$F@jdhGggIcNm-?mIJZ zzgngMK}{H~p1fFBf};48{2&6)pxNbF+d+FF+r$S{?`B6yf0~?29Uf(nQyK-EHvE$O zeD1NkS=*$NSvUC5aHnf@!a-_E?MC6S{Et0YKIN9vk5d&fj2g|>ijvquZ#R7cyK_*Y zH#Cm;=JAlN#;Gc&A^5;HvPJK}M|0LkEE6_2Bq=~d53YA7MFa0U>o|{^#ZwNZFJQ`i zJGUIB{4P#amFB=+du&cp(VV_ul?|6Vqv%YJlaueAag!|wS01G`=|XqOi{E{w3%E%l zC6=-c+|Wn&QYI?!5t)QpCs!4(|K+tPg8#`W$vrJsZThMJ>%YA02XL6{=@0PL_W!Nb z1MK`jpg!!F1Kn$a|5K&(s)p@Nft^ZzMJ`-irzn-73tozoN(WdD6%lJK9|ORtlCUHw00QvbA#DtN%K z`707d$%~-Z?ZFSkI+Mf8r?b6E6#*zRKpli!t>6oXZdlX=MNLuFE^bhz1fCYlD*Lf3FK}L zd!JC{aqG(~L_U6J8qV8C%MB-vpVpapGJauPH1xeWG0nkJU@1f3n4H9||9}iPZ&`^6+AF?Aeyo(dqH#ry;)|d*R{IPH32t!(QRZLD6<6S?Gl4{0@9c zn#D!(YAxOsU@k&CO|ue@;R< z+%!{vf~Ukoc`UWB?;T>;a~2LenLmo{J|Zo9HM}4V&FEdr@?4avb5@p4c&-jXh% zAoZCe&}T5x+q>pSG1vi5)EI0#qprnh1zp|bL%!p`3I@#Y$-SR^SWnUHU?Oz$fdps5 zMnewV!1?IRbIu5v*}#0-th|3U(TmB_;ilak|Bc2yl;y@r)2W9dpOS;p*~O3%9CPt( zxM@QSb(Ce7AF>uZi%xGbJQs6@%;n6T7HcVq^S>6yPBN%Q#s{c%|(9^A) zcF|=OG2%g8r0-onG|VfeMUedBuJUxcDF3f!_n%X1y>V)e!geY;0`Or~F{u~Lt+PtA z&AZ{9Ste!@l9J}UNFqt+(Nj>B%JO=}YDIm$wUsYxbVUV!Tm7SjI=cl2uI|;<`Ze+R zYx-P>dqC!%ykr;DZU-o`$!BAisDX>SRK!qt&9T=#B074?Wz2ZoRixq3LUV6dw_>ES zDpAnhkP)X2NtMRQ$;wRPM0T_k4v(??Lq{D0gX?jXGt<*TJn*5&K;?U*VMH)-xAzhK zyStC-P4)f!jEH$YsdMhs6G@#+)=OYcn6Mf&=g!W89dz_&u7SwQP)=?2Ur+-BX%1BP zHmcl#D!* zLT_ZJxm>$3Fw*wx&CY&``nMXu?)VnD500nA{O<(gM*^!d^Lq)BtM zV_Vr%L$>BOr_d)nnP9-vfl#ab)i+kq(h@_HksgO%l}|DfaN#kNHfnSp-2xF0Z*6$g z+33GFhe!73DpQuwStNqApzs4*V}=iSIb+s%yAU_#d!T~($aya|R@MmROkxFg_Pb0x zKt@Wf)ew3pd4%$zZ=LC|xa*@TLwZ_TL8;PRn_Av-&`e!^2__{8I8u*jy-LP<(~&=K zMN71!njY5MnO;8N*#U}vQ-4vWIvX-*GSmhu4mV*Q=xeJOMk_U=DluU#s7ga=KPi22 ze;C8U^^@iUB*YreeWgfi$T-_4?#J~k*K1%mGpjdo{XvBAoo1mv#o~phJN_PC^XkIO z7oq~+U1b`77Tiau@(A0?4~uU_TH}2xxZY!C_0SWUo~lop=Sm^Pmt=pA7yCIO`TMS$mTv^lfMl{D7 ze4nBgoC;YebJ+U3J8R&}UKJ9TCsOIw=o2|7<8q-uIDJ+Kuc3-A$0K*Eg%N#=m~P^C zIYCb~(QyKle(7HGb6uT894NTpP+6SKa3@U9cTOp7&qOpfI6&@~9IoHxiDwt=dghO> z6j*_Eo;Lx(h3;|MJ0&v9U2X83$6)XWSqeQ-1@%BYfAtw5l?2FI=>BU>D_b1p_HOz! z55?^-?DB(bMwh{T^%-uFN&o{rI7V5mK=dw!HeF@*hnspDf54EXWES4?8pGnl9Zm70 z2RzHjZI?@Zg2B%2Z6tUEka-BEVHTh{ps$P!GhNgi5@Du`HBHiZZ@9Z9V zX&~KtYp%z7v>d>~jY7&`K9CLY<(yVI8m?i%BV{Ow%sLLbOcem-Y|TMjW!yHKU*2%@ zldZn{e}juZy%$N6(RQi{92=wicR0jo&v}Kf67pXMk^ZTl|3W_^AFhB-O8pPAe{Ys> zg%bP5iey9ogH`?j{`_y!2m)|T@umLezc)*JeuZ<^EMI5-FE}R!z&Y8hWrzRXOoinN zB<@!isr~z|D82;HnmXAV&wp>09}A57%0u@x`@e&~Y}PN5TQ~_BzrmZ#J?x(!1YgL9 zJ^k}pQlSdazSUTUpDX$7Y{&~wE2Lw7N zUYB^r@Ji-$Y=Em^qfcce+BgYtzGA-MmP_ca@evbZN?hBg)DMm_u;DMlA za(@61&Y2J-xD6v#3lnR0^cbl_rnkk?8EJ{1eob$->d#xxSXF^=ry` zB6o}f)Nl67Ns3Zw+0YN)W|OB)a+IvN=L+h7^}(*T$XEBu)os&oS#!Jren>ofDw#+i zRYwnrBL5>12E0=8SJ?Ua{62P*ljWP>s94ucYl0b$H^F7^7T8SpGCo=`LDn@5wK(H% zer{D_vv1h~wUpXfcVt19Yr|Q{W(%QuK?cP&R$vv+#|hGZex@Rh*bX4R_1C!A;&XlE z`_=BMO&I7$oo3;F?WRQJOYYh2ps%iE7Kz4T&u($)lLpvQ-V@P(VEQaWneX)YR_rp* z6+k^QbklM+lv_~D@Y-#5q<>>T9Q z{6#$bI49P;AWH_a+@PXKGd`M>6z}QhPp&A5&J?@IkAAhPyz)wQkg3Fx-F|lah8t^T zO^ppN>39bRV)a1tyn{UI-O2QHlK096!6onls1UJhGcBh>#avlKNeEF{F$7!VNfHl1X0x|97sxd5zB$iqn} znFGDWVPj60bXi(`@`&y2(WB*+!S~dLjivHdXg&JkV(A)Y8-SKDeB` zjf1?tmW`LiXPEM~ep0tWruJ+oVrfLY^-d$mBT$mq0dMMSrwLbY@ ztRX5wrcl%Ml^dKEcFTK0Uqtx*HdFs6(ktc{fcM3JYXNUJr?}_pY#%|Tpq*W(~U9{M?ZL9R=c5#-T!D87 z$T5=e)dvdK_@;Hg%DG+XbshMR?8FKXOTp=xnS=%v| z-^RY)o`ac}Z%&8fzjU)$3Asr)B@Z(RcbUl4m~D#IrR*SzlPNTbO;~~kWqiBgu1Yg&xY4;st-`P`Rz5*B}ZjBlzv9dK3}cA>J{H8sGXEs z#Il!`^ATonum>AbUf!K$)BU_!-B+aWLFZs;Y1V~=$UVp{!Rfl6NcPVO&tqutZoEYcrfHk~b1RVET=XYCG|Z)tT##H+m5 zSBXe2(Q6yKE$ZJFro*^49wub^fAnRpjuStiH{kWbDhEMg*h}8je`=;<;?cw1|3*vu z;__>&Pwm?!=(a2_9JU{gE*wd%+u`b@@s7eQ5!}>7(Zma1@cfA-0_K&NYez|gJ3Zej z^Ybfg-;{6D`fD5);-SCkWWL>J~zs&U6>rR&6LmEChl6E;vhACEmQPpN0&?a>_!&W?v zs%QS`vJ|@s{Rt_UZ$=&s!##`$4;_-UGUSwi~o=vb{}tF{l=c z;Vr0fE~?AF3eV8 z0NesBZS)gg+75QNclEQ-<8IGBK~C^liz{V)s#9IMhf??2V+b>wB(A9bk%syZ`=IS~} z->EgFfb`1&JMoETLyN(osQ6oVy&vToyz_c!T2uZf=><&V#e+)6g)#GjpU%rWnT3nK z_FB~;fAMBE9E(uZ7>G7kYLNI-x5n6Bc-6#avXXJ+eM9K9cxH*opDkF67@UG$HE?fE zagubUwdac_+;q}e?rZ_i$s5;pMCmcz&OD$(g%exRTxw(Q?Rl7*kKm_zy9|Q$H9ztgz8Dj(O z5UKo1`*OCd;eQ8fj3c;MI`wr}FGH^InM|5Lax=n@a-r-Jf^qUTvibAL1qPGGDqnE# zKRz2i57O=l^#DF)w-v5M`;i(3>}D{g>kK-`>jFoCZs-26SpWKX|g7_w@x}$s)YFu)5mtR-c^}C`FdKp(50*5)33mi}>8< zJv^jvN_T&&&YO}T=z+ew%9N-R3Sk}Dk5kt9i19;O|By;=eVQmg%@^g)!C~HMAF)S| zuJKsDVP6fL%U|Ua6tvOj(HEhQ@9*l$GvL+J(@R_!9R+NGyJAe)sznR9w$3=$^Bq_rLiZ+ zc0IL#*_W30P5#W4%q!MgK~8wH4W{eIn!E~Phw5RskT|Ey&u63gw#b#2>CDVi>jvPp z|HS6}Z@OaxgA^TC-^{%iJec^}o8F_!g_A;O-~jc4m5^}UK1*svITtX4eO-t(*UiLk zI6Pc+yP@LC3RVm7I657AfAFM1eqx=2y0G;;c(wgx|1`}Zvz5vLA1~MgiA0+5@qqeu z&W{;d>DLnymuTABi1&3(XEO*723wJ`H`WvG&faR!XC*-}F=Z%EqS-Vw+KHW2r{E8qLQIbiU~uu=1XP8~o-1|BYWIz-TDv^8pE&kKt;E|g1Ot{XfYvPV1rnc`rJ zJ5dfkqqof3IfvFnVKbIzsxc_>M5Kn(>ky|jwL}9K@z*<=9hnK_HoVb5H%x?A-GpD} z)E^$o1D0`bq=ThC5PN9f;{MrhSfW$9yKbf1Lhqm1XOh1>Kbh59}y#I*Z#*|yPr3*Db7%`YFL5V`7{=Ag`qB9w< zs~L2^RQz8S)G7s-f^%{=K?|%qaF^)>BQOD*^6X({2x!D4l8%L-lmKDVba#b!Mr#mhwQ|$=$)A{ErcSy zPfvZ_t;{y8W|hRm#MazfnN`-X-l-}R*ExYn$XYpj#(cBK3|Al(ZzoXBht7UV`nr8T z$;!2L(MCGE>7_Si5~NA}VYw9$h?zbs>(GrgK0%l6`ddUqRG@$W;9}usU^+jn%*R5X z&hPy3Y__pj`Q+)h#>V%szOysj`kdL-)lWYK6SYJ9+;7h}@CTk1Z{gzMam@z=U@7N! z6ztd=@&dnpI}?t9O`$RI`uwYoRBlrWtidk) z?vBq((yk6mYwrU<0X0p-Tl?*zph6wMSDpMb!KGVJ?mnI18QQTnuZ|LF9B75S=q#5E zKan~wD=beKk*yr|Hwtl7U0OM?GHM-x&iI@wIVk}FxR*)}L~B~z@G4*0K5jLiW{i`D z{`qZfCl*8;VXaDrvi8CbbkR#cmdccDnyq<5&wwx0In=l9#Xlx`U| zg*6C1e?4IQ#Ub!I2kO_s4cH7*C!|>Q8{hx*jM!}j*gdAz2pjt^zmzWmSawq?#mAkU zMS41g^$n*4tVDU@1S%rwt_eNjPk-pBpa1dk;*)+^%y^*xl>6`LGB0w^P*OfbcrDC4 zYMX0{Z}1UcQ&1d3C>tRhE-otVVH8Y%SlArk!r>(hmRvLVEg!x4w#_G6ucS?##m~Zx& zATv)9@SA}&4TBy3+AsT$_^s}96b#?&tXnH-wRWl<%QcVr(w>XM z0z)+#?DhV_SzpC(YN{od+gUeqvTpXQRq~{(G0u9;JIs&;k z+G4g9k)nGOI$awo7!#R?lV+9Ydd1QeeR)+{;P;LkAO%QD#qgeX_3!;;O9j>w=i?hM z{+lxg@UQ~wftA@d1qFpQIb?4LP3(OnNu?1?RcdROyg`VHU-=uv%D5408!gx`T(+ss zx>jstc%O$+)6m#QOYbE;Ts@dmzqY1vwb7)EY6>Q9>xhqfdJE3wkkgErX&!`fp(ba; z=G2XPO|B^v;O6}@gVsf#-?WNK*ui%Eh0#9tQYZ?Gxp z{AI)6;K6Q6+##NXKUU{tQ|7i6Z`K}92)rxtZDVOU(sS#0MDefHkjeYs-RVrHt%Ejf z=Gm$?4Gwa{X2!M^f8P{+uN{ z#I-=in@0K@feHcOz>X~K&fm9R0q=2Kxn~%vTTYg1b!zP>QQmdJ;wlS&ftoaHZ1S0M z2r8h-1s#P(7-3q0$tK-&KK_-224lJ}hYXq@aVP_iiXZ`aQ~|9xVZ>8LUfTwB)y-i? zf^`iww?U8XIj%E6GnJ_XLi-aS4B+a|V5m4AC7*iNhVJ^rVMIfG?-Or0ib}f$bxb~6 z1@@((O$$U!<%0#DNZG5Cr(cmY4%34+$$QVAGXEz2-LGWz-IcUurW*?Ht(4!P1AT1@ zt`2E_;5F{qO@;S_AAj`q73mr3R(u?F6EB@RrADd$UisK_|JVAW>)AfnT^8DZ6zP3h zlxq3r9sLyjgyx@RNzc~aRX#r{!+E}|J)#$?J$adWdm4nT_>37uSWzP}k$lG#e zMK)`;mqBjR37Ba{H~>JGPCCB#R}VxI0l>2mbxb^vb100=@>$d&_zh~(OtD{Uo)lYI z)!L_)-EmA}uetUHuNu0VQ&{c#=C7qGw4y)cgI#s2Us<4_)0S%ppGvmZh@Ph}1+cce z)@!$?BDm%sKC}1n=@-@R>#y_DIHUl~f-=QdNa^_t^xqg(hW2U#{O$x`Y48=pILRvs z*QEbj#LxsB9o_(<~HsJIyT?A=69;gt*UMf*oska_xnXI_5; zI~h6b^^Qt?m(HCcy;ht;LhdtbP>`2g$=UDItHKrFc*EslHj8^U@3B`#;?8426j`c= z*^8^AJ^cV+#4zE-V%m3T#*!J(n+d(+pYsYoP?F#EnyVxSyl5;BN6m)*QlXov=MpD=jyQl>iP$4@g(vipbp?*d-@Fd z48;}cEDDfK)>wy(V1Do}IFir1kskh>=j~vQidUK)q;{g>oWnxOc8tlEVE1XgsVVAeex^(g;U1I`pJtf-k%8Kv7dHK%XiI-Y6Y z!DCUoIqm=K70;X5A(c@s77ouCGP(QhYL_zf84gr1*o=8%Z2C9jW`KVw+nJcmP3#?7 z>?>i8^#{#%V~9TEwjFmMwavc>(~XVA)t%>!jiPQxHNuO}&c8_#6II{Zp}%LJ{Nn!I ztcW@#-(@^YJsg#LK*a2f@lz;Pg-?^#WqSNC*Wz69;(ku9Nv0u|V(I>$m8B1J!x}bq zbPei;)961PeK4|X+bVSq-g(=s_|-T~)+cV*e9tG$_E+jp--_EyiLyI~kz;;~jpcs+xAbpVwJKKEvkZ6xRfYuvEs!&X)wT_&AApiYp&T zzPbXgsyCndzeCrcq#pIV+M-7m7U0mMNXpr@eoC4;`gob}9(v4f`RsXnme=J4(cIQn ziWhngOq>{B_&Mt^b_)UC`JH^~6 zzwsEe@7w_ktF0FkkCkQwws`8MfkpY>C2qjk6by`v%F*L&bQPgZ6|W={als4&9rxaw z=SRdeIuXykIo=tA&8*P*9rB62sG3M_L@HjLA`yXrypK(FD!UgZnc`~z0zEorqiBhS zk=;r610o^ZeSG7>z>q5S&qA_r=|XR`zE?51ZZ3(qY57;ikg8&25Aif;&6DV`(Lq z_^i>=$}TVd-nFosVzgHcoL&jIqR}P-%8sow6#rCUZZX4qMS?YUucp zc*i}F)2)o!k^5tw%5Jq3bxUUtQ_ak0diS0V?I-lH)CD#=Sb7ZVHxBSBWaF(}inrVhcGDg6eR8nN6 zOBXK0?aqa-%mp+Vtq^V!ntp{RBot)V>o_v*65K%3EEBEh2l8^_9(O&)1l|`6d07|H z7qDlS`J_umIZkbvH%pL5pZ~#(MG1v9tb;OXG}@V1>p2ivQF6l2ieW&Mql79wh8Y}qnt{L$l`~S# z$yGkU3E;WgQ z+Z-Y<7TH)i(Z^yY!*EB$9vdA$p_?uE%>Q^vr4Yx#{O85bXkUb_oTibXk&D?)N$Z8v zR<|hn%b&w@fIr}DUCYHsYMPIFRG$1cRa4)ER_@DR1f4!bP0S$c8yWzPFscy`je^-{ zB-Q0zoIAV{9s)BEf<3ePS)so-f_4&-Dz0JUX_V0e*4t5 z`KKJ%oS$WcNkl&MyF#k~lq@ViR^?s07t=CA@F$c@-bwUjEd`%SzA>j%T_@pw- z(s^7cUS(@(Hh6JPS)Qa!dDdwTk(CUmjc0M<4&>z5^09XuyZyqk?|8SX3wMG8wbWg= zBYL&bBJTnXM3PK)eVG!5R>pw;Q> zq~j0%vUg@WnOFGLTp-L3X*PE`k4f>hUimpF(#Jg_lz-xVuY;Cc)1yca+9&m#(q4K^($& z9fnbPq|Ql6l)*xzrGD4mVsqR?IKu;331_KB@ZJ+ZxsBVNDZ4$obKq>tR4gVBz=R(B z-MJuJl}X&msVO0ojF=^ogG^dRezWf_kLoN4>vY`UZ{NzQXXDwvu&{J*`QnU0fLwbP zCVjKp@Wg4g9^7@9;<9a%Y{Q5(5-6P8P+0JlcydUOv;&)~y}YAn#ADVc9-diG+A-0QtUMxfQZ4P*r$+N1K0 zslJVhmG>7q-!~p4+BsNup6BzHe#^Ee8|J>h^;E|c{j<(QlnCc~zo~R~nc2%X&NUz+ zDXBi+6jslDNwtiJiTM%Yf_C{BeVHNRC zXAaS=!TbEBdA+!IK{Yi!u}v*t40eZ(+}J)iQWAHVCBAh4pWhqm^zBRL=ljo}9o^O( z_92Eq7y{w#&OJ;yEW#^?iKo93qLMy|=Uc0lyt{d~qqX(HkQF=M=&H(q^ywF6Rn_QH zxtvzq^Y!)jJ5ns5YMYQox@5aMMDM>Qs1|s|qx|rCUH$h(0?I2X?_mIt1 zfsKMUE02SpG)O?Gr4ag6*a4B41K8(Zh zN%M07a`s$5&?`_GONGn8gzI5oB*lfY34}L8gE1IyD47O`~7D#_Vem6^QLIvWy z*Niq_IL*uE^}IpiK62BYaPPE}f(#nRDXqvLjUFIF4D5bI|1!_0H1$0_6K9ogIqvcj zQgUIltb%&(l%nP)lNllmMMKnwZ?BcB#9C}>hwUJtmoW)Qq@gEm$|S44*=Qv#lGLS~ zEbV(T5+yfMCBnfujPDZuQoA1JX0LIXlAK%xUm)0;CW)Fn4J;SYJwcK0W|Wdlai_EG zaA9ZO6ex9Q7J0gTn9bAO2XW}tlI;r;&l`W48TQFjakPa1y{XA9` zxlfngy^(fi)Lz;YLuez1n$7(L8Isg-*ki7i+QgZ>BLv==ucYPC05s6z+msw!5AmYa znb-FpsGjuR843vKVT4Qx`b+V6;T6UkkG>Ko5_o3{6BZ!V7Tre|>3xhoA%7Yd8Fsqi zGcqN#Qiy!ISWWUsd0>s@W>Y_6Vo+QtnbjvWT1Lbm#JF9Cgv_-4OYU4PbEmdS><6u% zkDhV1H>NNI5?DK*M{v*D-aX$NAoNLDNKY3Y&4~LjG%&Orp!U?TLuXmIU$FqW*^*I0 zxx^D>YpM+m#xfdPPE)w+T-uKR(z5!C=G)YSG6oK{(RZ#3rwWEi{haa~QoI|aAs(4e zh=Phahp=D*0-0FjJ2U)~;m+QKr-FN_%R}j3alj=INiF+=Me{r139h z#4zv3dxA}VK|9m%>}K{OH2=wsjaqLZJ^ z(i?hWu76X=C*)cWjnwJCy&vE91JD9otr$9`K)E{b7@!g&$dH8k%@N>lnB?H z;6u7xnHLtL-NJ!JA(h1DX;6l48+utGC?k)_U6&qje%Z5=_2q_;2rvxSM@O-Zj;*aE zlZx#?Op5L{mWirePpegW|Ej68WH9`P`P30FQ)bC`Dh?xd1x2P}ZhE^ObUbPuFfFf1 zuln>!I3jR^q0rCK!!15jOY~hX>k)8LD26fo0N&xW`E626!WcV~YsN=N6n|sYlpqo0 zE30M;PQs)HY;Gfsb7d|0W> zFrJUM_J%RPE+5gu8MyaS*Omm{NYXRpBSG+8P1F2s@#EwBLIvReDV-r#bVX&dKc)9A8v@XdFpPY^Dp zMwYWtqYFWW7m@YGH~p%eFLxF&DW~u31XZVva2g}8J)MKids5nxy*VC?`JyR$f{+xI zvc0=8yY4js7>-D@O&0SAUWzm-ZGQiej=DIU6a746g#eXb-nX?1o~=@qwzO@H<$RUx zUUtN7C|*oN6Bas>H%Knz)|Ce(*2b{PuW`w~$fBLT{*`=|(;m?m8Gozr4Qi5AQ> zm_86=C7Gm(F?|b9Xb*hSiesd$HkLByUF&8s1y#Ncl4849-G4xxzB~2U5x4)Qm^8H} z9{IRv*xP*h?T%Z9UpOb}C&ER&>uypyo}{DgGw&$um|IfaMbtlqFtGTF34Si+s@bpn zb*p4&B-)btHnAh+4HA(AoMtohE!N3wGxYd)wT>b3E8o3VVsEm^o%M~9lj@BOJ?(En zGg3LD6Zhz8Yl3D%ZkLo>BtJ7Y4NDv+R&Q+kF;_&RSz=Z%ukF8vVoda;TOE=?abbjY zW5*bw^jazJNrv$ra-NSIB~WFx`iwL)i@&wzUAo$` z(P}?^1zv2o(ajiZPZgeKpB>os%|1z+>q+XN84R^Q(XW8!t_h3()H2>28dXt>sjIFW+8{*e7#Y_atzStFWq1EX7rvLsP6Q_24BE@~i7GybzWR z(B_;cdws4Hwha;eA)JZ-OpxHE=H6eonQ8a2Gr4C}ZzsvzctTC(E6(q3*{TpX!5riy z^o%#H`z=Nxd{%Zq)sv0S$-zt+JMo(1NZXh~mqf?xV5xi(N78 zuNo}Wkr3-e0~2F>UahxdFi`LssR4PWrEgzf3YSvn{LYnicuD!Z^G$h*7qKq!afeH9 zo$uuh?I^I@u+(L>I6t2?qjJ+)F7gQ3CM+>GZa;%ZAY7f+;w@S!d$<5AzwkAIcg@oK zps5iPrQ!%)zY~+XJL)j+_J!mv0%bQ>VtYh-ZUP1Bt~b|0aHrG-6Z+9Lgx?u2rordD zkJ%O&Y^r0v}@->_WBzI_%9jQQ0f+uX8<*(LJr zzMbu@R;N3V;7S>QV6@kS&Jbn2gU$i8()*P6-FHFmIln`gpIuxyowIfJ!j#7&$*OA) z4}QcrGmpaqXg%xl5REq?XeOuUWxZUxaZFq2+2%3rPTo~Vnuh_;#&hWVIq!E<)Dibp&VdMScaxUXauD0KN%pDVs9tz9KzG1TQ^}Cz4*f#3 zMM)l!s`F`An6QD|`*q%fi~vg4yw>KL-d+$2$Bke_PsIHE&d%E^e^oNO(q@VB)hO4} znd#5o?XY)s6b*+&vaJdkleLlsKK(=2T>BnDX-h7WO&vK_Q}+%56@ymw##DDy+HOMk zsF@06j|4?8FO@`JwQTNNXN>+RI0yfBD?D7iL0G77cMpG|bJyaDmS~z$Uh1&0>sXaE z+Zi+VoT5K(z4Go9)O<>cEcE}O=`G`$eBb|JB_t)JTSQ8_djlzv5|Qo(>24<7jdUZT z(%miHA>9pQ8$Dpa?tT8>-~D6{_F&iRI(J;xd7Q_)APo+Y2Fb*_n8q!F$J~awa%Be2 zt5uegR0P{521d={s}&TYN?)IAN02HJxM}TTzB&l^Ef%7ccy3#-pzK1)=oMZnfl1Kj zTR2>Y1G@5vG$qg8N)8@Vbj$3ZY+d6h6bK1|jEP3Pm#Q2+=E;NV3)e_tZ2sjvzKZIv z@HI~2UXM92B^ymh@Rz-!qoetp)Yc+o_wnI%h0>zyn~&vZkjWUTVC@=?nhUF;=kmZ9 z4n4_8f&kv78Pv;eUA||f^ZP6DJYEw_jI|#D&Gk=~f!nJ(dV+=zUb&gg9%W0mfOS{e zz$}63ypQGDs}1-zS-QgM$qQRl*d_6^35QJcO^pcNI%^udKl0_?0XfNbpMKHH$tDDy z;+^rCNYfpl$8^y+&>*s3=Y%Kv&sX>NXELChUp=7O3Xl0Ml~j&=A z!v(KBz-CX-)(xhidz!S53=w24wrca}><6<%9^%beMGnZ&wFg9;-|~+RsOj!DD(Ar1 zP+QdZ2>CGrDB&1kK2`wWOn>L7Ovo@%CGs$ADj#L5KiBBSXiTz{Y)nd+7#aIoQdy5% zt#E9UsaGl<>^aor?}wM3h{p0@)tYe87GE@Nor7@$-4kY-Hv2!+#$^S&a6PnW?|(D= zD8@sw4ww2?QkLn@{(fz^CJ98&Yvk0n=La5{g46@Eu}b;{f%IJywa~$DUMz-amKEnu zIJ#~1Ond9_^NTO;OydG_y@4ceZp2yC!(%N;Iv(-J!cTHU#tys=oRJYbQ%~;V7|962 z?zu=Dd^5h#5yMB<30;jP>0YJQrna>c&zI zpofnt=Vm&901?Sg1y9G{_RY+SFqD`6Aol;g!RW?)c)e?db<9i9FgA0WK(6*`buq)O z0Acu?$HWf)m&C^`^tK9xlEwGPq(dkezanEncXT9;2z&RzFiYv$#}N*l@wzI zmDYmC2_7#+zE9tZro3b5yrCPOdQo&Fhm-OP5kr~I%v@+nM1?M*?%urt&HfZ0m43+b zxn7*!LIdX`5#S*1&v&bT|FW&&5VSczOzNOKLQ1)mz0;$+)|T}|g@nLO3QexSM92YC zblu>tr45(Sip#cFV4;sBj<>Fb3rRnuKLSlWu%P;`gMo^E8haH^n9bkoq}$X2D%6fh=NCQd3&2}7$$2? zv)CLW>ZbtF8ttLbR&^k8t9*>SWuC_gs;n}YR5dyig+plF>l>~=wgf7RzQzvhFd zR`P;jAIWsL>qEb}{==dl3KU_yy=;jW-!2&H(OnF?wrZKs3!er6DfYe1iX6HJjE<+j zs}ORoGz)7wIdz#YJdRWBvP(zV07&HuS8-?;>K@;)v`Pv{hEYI=sq5C=6w{q+Zo;NJ z;xj;(?Fs%FeSJr_R0b`9OQz{=<0S9C#kzR+Ye=nI9vcUnHa;^s#f!aKClJbeE@|tk zSY&1D((_Wr((F+I1PP=x?(S$a-+48V%>Qmlo>qBLpnXWOmUhg(!Lx}8~&32XfX~-ikoGJVWhV47?u*70jS%_|PiMd^@iMdz~ z_4zse=-Jq4BDzL(z z4NRBUu;oYk9LvuqS(Rz?NxekIPk(jVREYi4g-OX@t83V>)#V{(513-MAK|>1XW+pzTn9mWK4?hRQ zC|=+~<6_CL*UB`cSJ%TX74Ei#n%ndh`qx?+9$m&1bUCX`hwUp!80mSMeetm=lX!Zju6js1@Q+|?a65&B|_Pf5Y4Eo|Qqs6w192K9$|GYq*_*|GZ^7bz2ke(iDt^J_-@e(FPG2^Mn}X{hz)Ih}R1sNq?W$T2Q`E_5b;uh-_T z7L7WFZ*q?Cmbb+vmu#*Xo5AQ3=+G@HO}VERGiFLU?2$NeV0>}jh;npF zJ3+U^CHnxzZJYJ#> z#YyANI8!eU%9WCLW^{+76tO?egXk6+jOxf3i|gGvCTAG_ic*PO3dMs%xFdgBTTdi? zleAL;in%Ue_=4gVSW|mu=6PA`Pe;H1AMk$4)YHVo)nn({QAe%Us#*Awu2|s12_Vt5hy%s2qcVHE~i@@&>?Gmt{h zK$AH0@4)aT7#pk6Pn4o$PnmIkqT*b$j%4P7AHxCMoadBY+0%V_+Pe?A@0q<%uV3*e z^`oaK_m9^Eh424p4emh^v2qpAI-EPh5oYlO)ULb?D?|pz`e9v*s1K*lY#ll6q-{cW zOf~t1G`~>zW01PZqF}n|AtksR5&mhv!-P6M$ihD^ebcbTh(VWOHan+EL)gq}BB0Ja zL{dzpc7`u56llY1NA&x^55@x#iY)=~Jd9tBd^bOP!`W`v*%>`zEC!cv5@xskp89qh zC}AI!mwxDw>QvG@dMA;-^$yd5bDcWB;FR|`yg)e! z%-KE-Pw>>Iti|<25XPlfnuS?cTn4WGi7e6k^7s-`%Jg)mMSd_?16|UXMSlf(zbGGt z%6z-BajU`Y`=Kt{l{4kr5wH?egZ*DMl__&{{)bUo&rCq3iwro|*}rniKFbP4?s{*w zzd#Pn)u64>=*cnk6$C=<>TeH)!?O>~&H(^nXwdC$fy|GnVKPSE4#cGYZAXZoBe5*Z z|5J7Ezi0mBi2|R9f(v{1=^MlELQ-T*hJ~q$zQpfJYJQZEK|5W_%|8dM(Fj%$WC?TS z6a*gN)b~81fCc`|#mHJypyd@y(_mnmCVn7f0`9R zsTJ|2J@MD$zPmiuK;gk}9`HHqb#%1X|1ECH9F8UVL$iiw*I*^`N!DtNQ|9BjX^?G8Q7)N2EV z`6?WJ{PkU0M*xUe%}}K@S^kDc<#FOdK<-7mcT|OC&wbDqNjKbdXpB2PWZ-NPxzx3@ z;d2>y`AF}LkgW~$u^m?MHO!T?UsNF0zL8)<&R=zWceZfv7YF;mO*uEooS7ppRpUf2J+GjIT-%$OhlCQjO)dC9o_pw$$+ms=G$_)LM0*J z*y+^2&~}RRCWRc0j)cFaHx+djd10?u@)&=^ZT!JDUhA+9b08$=14;TZ_YnT?wwhl7 zLxr1O`OWk#q1)|L1MX^7v2c92+RueirO$Yjf9UV%CRdf4H@p9NHtV)&x*W>6=5{#Ykw@lU zRep^@f5~$k!3=)E*AeK#b`h*LV}-pcdz;W*o4ZG$r_!e=xKmgj+!+7TBc`wHu@($z z_!d?W#Oc~QT%Znkf8?L7OaV{};A8Wll`xd8S){l(!q~6K(^kKc0(O>QwJ6-F3A0_xFH? zw`DELu@3jQ+`aGpNx3!ra4}oz-(`_`R9TOV-xT00fgH9icV->+qbT=5?8s z#ABKc`xX=ZeFVeby~EStA~3D7`jysHkGne9b77sdDdROXC((N_I_gd;u+Tk3lYWsc zF!l%lx_#J{Yrc6@eF#X(#TBCO91KV zU7rh(;SSDT9P}|0b=(Mh&f)jJ(?+Vg=_0Ds5V1VwpJ}jRt3sePRv;Yfu;$Z;*24lt zCQr`zLDM7ayWZo-6?BM7i^?|dznJ!?=d4733X>;Ud`WGe2|iPX_7(|JS6|`9@U+#m zIQ*)XWn+-W8e!;|b~Z=sVPZp%*m@D^LVI?@vT!~SlF-0q?vpF5qdy~o8n0rM4K8em zy?*-(zqckv)Ru8RocCem-+eHXi(xusLR!-SbTLZijYErrv$HF2QU2E zt*O|X9p-Ng0tJ!>Vy(-TTmi8 zgZw0rD8UXV=osa&ALPptL ztoILhmjN%#04!}QIBOjiSkEN%kExHMIS9=xPro5%FV$D0!d2))fKRRrZCE9+JLZK^U(QjwbQ&1zY zr=)Xt)0{k6q+2rt@Xcv9*~|=x>!}i|W|%9MRIvyPo3CYC>-L zh|kvhPVxPzpG8d-48*?Xi1_Li-i}KnFCF?d4G-Rf9rGoS5^x!bMHcM+A4NA$Go_B| z`dwFr^@ZIOsb=v%rwa$oL&TJ+^k_vyAAs1_@%gcz5a$osddY zPv?e1+iWFKxh1-nlWw(|yM%AQ0Sri{rvvT|P9|haq@iKl5^dL{LrF!+w}E-7X*aSh z+pdblwtOuuHGAZYF)piUKGVgG6hT@3jI^${5|}t@qeFjkwSyX-EC7g_jinIf{OlUJ zf|gvBMo?k%`CA`F4YnULcpqYTX=+B_E?Qv=lRA5$&ESDplOk$B8=HbQGsYzMiw}$jQm~b4^mD@^^dy{Jjg$Rk3l%fUh&5 zVUBd}q}3KfzWsxfHp&J%^<8Wnq$7JZh0z^v4y&j&MlhhG!&tPI4Gxh3G@YNWEyuKG z$Ve%J_6>9cWYZ3N7^d7V?nWsQ=aSI|MfIEk5iZ=%aG|6v%fD#|_x_>3h)X*{y@b}cd_DLO~R-jnyMWfR^FE9 zG6VN2lL2 zMw4a0m&gR7qSp1wqG#ZTDG))w^0qs&D6-zxLqybhdIdLdCMfsy^`i4Gvkexx+)?J4 zW6*_>!Ee!y0=*%H=8I2V44h~~j>~Gbk1PJD%&eNDpxr$0H6vXZq-WN_)?q#nOv95| z?WSKENr0u-HZ?xghJ^EUVc{Y0pgF@sum47tU>gwe8VB5ESU;b1WMF#_grCmUEOcyL z5dAB9BL~#@)I%E7d3KG+Is}BP^%BFqLCBOk^akI- zZ%vkhW&9!!s<86%ifeMDn*HW!kOH9TPKcq=!mY+%mUz|G1%U6B5ayKLHxdGclk@EA z(F4s~aayaE6Tr{1O(>~pZ+mCJ{gyBCrFdmn9je$0O3w8^zIN=RHB}j zyrMuNFoXYXu>qyNt4cREadr_tqaXE}C=9#V;3er`fzJaY$zb=zz+t84H*Tw??Q!?5 z(9XVj+(AdLXPux&i}r#RNa%Np)VvgM1`uJlyHayWAIG1W>-EfOvFpjegm?314s_0> z^B4OWIIX8qhC-;^-p(5_X|&qq@w6sI_X=QCnfRYna@V3d?SGnqgy9QFHykd* z;GpEr*P<}{q|NXNEqQ9*ljLoaDWd|O`wM*(bbFKId}gK__L88-*%>XEr=E6{uGz(g zzoCiduO+r&3!S(RYJgnuG-ZcU+xfs!dRcVGQHqy>B_rj_>8z-MArJN&(%z8NgG%!c z{%dHt?}xDij`Mr_93zb0E%EkR`(Wn<*=rLp2<_?yBZBvPwW3~=cG_m)B9Gd!5K;yP z?$}R*2R~b7mcH$8cJ9Pf<1I(WD$SVr`dltFL>t-LCxeXYV=MumybeI5eZ!RG?iMcC zeASJ#_RhqjVi-Q%b1z?HXotYp)$ojBMjH45qdoW83;l*FQIfCEeZ*P==NZF`%FrpF z_k29SKT*Uz8lyDpPuTcOoW49vYUIr4tWEZB67Q1A8`yvECS@dOmS=v+G71zFjXGRN zQ2jBYq3|fxc~kLqs97Z3Awj?RT2hhydIqgsTWP5LYmht=dRll2=IDXwK5vIWdd0s# z9oZ4>9A21?+<2MMP&j&dy!jN?Bu;77NO|^95607moQsb1McM+XOMA-1!@Oe_B?qzc zcj$B%-R%xN-1mB(i7!P?Z)^>}G~SKxGmd%cm?3+){@W4S&aIa~uiHEAmuEOpCzWo( z&^!qNai~wb~#5cZ^{T z>j^bq4timZ$mj|)dnDRmZz*VyR=$P>dDFcdJ`meg#-d3l({-vZ2|G+khuwD5ur&d% zKG8#UW}yN#E({@`^1$YJ-sy)AcMW4fG`YLpZG7Xw&sCx(ZcmXO*c5)ZwE6=yIw{QZ8MQc**ZVnJ7Tl@YY!1}l9J|z^!hIX8Zzure1)R} zQ)|CL&PU+Gt%b--4)J^Nb#Ta}`;?RgIdZLv@Bw;v2teOF+=bczk(ejNo~z;M5e#cB z+rqI1PA8LbdZh`8@iHD_OX7`y_*)xeR^-_ZhZDXN=wOCV5|=3U*H&`%}}QB;g{*imzWy`cRoUO?AOQ!@-*9^5Mq&zE{mM{FL!D3CjK z#T)+EJ8S>?18g&PSyu5ym|a`Lb`zlk!s(48Hw1h3^h4qP1LXnk){PnZ)TZOD%V88T zirhr}JT(&;ZYV|!moZ#!RX2X@WX_?@EaBJQCfx9Dn;RIv!soo5Vez4y`r}{l7hqMH z7~8X5oxM9+G)wk>o3Jzn+eW$>M0s-)uO`h{v=Xptkq!x5f(FN?q*5MTSYmRkui!X< z>Qz-2`8;~vtl#SUZCB@~md+NJ8K85So=sXR3zXBRbNLZRi=G8Wy~sR=zXDfC^I&oT zTPt6qtxJECts2_u3MXIhta(-fCT#O4vbv%+7Mu`ovwqAA<8j~MDL?wX)91LMnakVw z46mC$YM4|I>TS|AmbqUdL_1)To@}-64G6rKV+aWcav|V2)DRY*9@i_rj=Hu8aleUx zJWavcXY_XSfQGNM5#a}C)1UeucoX|;bPe_B1U2%;Rpu3pzJ!TN$98DpCzko}#*92; zZ})h0^upqK>ZO*cs;|4x=p@N*{U1WI*O>5uQs!}FEhb#lI|-WIn!J5&6-@TdOSoX5 zq@QI?T`kwsW-6gK1f<>*?X_S+ENX7_I-!ooqZ~=gVCx&2bR`a~)neTpvka`RAB{keD&yri==Ug?S34-6iGOit z%lV-=<^@pVv)H?Ms6jEz{FK0g9)Gu@Fj#*xKnzFBk%ut%^>@IkdYhHMf9a}3O#B^wL_rjExS*rSZVBDlEy=5=+Q?aakzD~2z_L4SHu+!_Uz^tjBf-?i> zPO#Hvz88ufOpx)J2I>!dh;HRGi(DyDLw`%j zWrG%+#rwgLz8$bW!8$(3esJur?&ko=wTS*z&ywRCJP|)B{ z!L&fI>N`oWD`tq*0a&7fqWfML7lI4Wm+wOx0H6Q!y(Mja^*`mWs2W;BR1r<;KQh5j z!tZQ{2lZu!vT6zDtPL{FB`|GZ^^b22nh-mmX@7>_1Cm>An5OVol4}Ue(AOC>40c5m z{*L#5-=VrK1ETi^5_PTmGm847bDYlp3x-uzcC@E#OVRGG?W`K9Dr5m67`JF2Ih^jf zy0MdU7R*FoDn*lnZ+jZVhq~EsHx86f-vpo>6bVs$s|>CCnf)60-7==GGEcTV6^uiT zh`QN@(3haYN@C0nu|Ow+nQY~1w_MpTo^0-q(v!8jxb|Tnqw8(XFVyYN_Rz|47YazL z54J;dfvY)!A^$BmJnka zmAgpGFH9;N8u?4FDKW0){G895DvyR@(&Ei~!$?UO?i-gCoU{Bg16J-efJ0%o!@c9- zD|p`esZTk@*YuV1K;0>~ln+%f3e+)8?3ismigp1W(2hbh@>lLAVxoa8UrOBhaed1< z*aw|tYmEA36Vq2ob=g}qJ@y6OC2r~&*B>Z!Hct@9eW{I0wa1-adrhN1n_|hd#XUVsnsjITT>x zZb_XGKS3%?WrxmoZNeJb4(o&eD@0DLf_UqAH6z-BbCAfHhHc4B&!4zFLiedNQ!ny* z&0z3-Po2AlXx4wcu<^@c!~gNZ-b#Oa>aI5CGDlMrG_DQQf8VU%gqn-(;Na_p<7M7w zaNgS;iuoZ|5-N8cRT}&m#jVCuknROsOLD*CLe2d}+Eb!U5^1vo)B5Xo?d(w!PPAZR zU20@Ia(h!;zYV#Jya$=PjahQ7--Uqw!$fWFXkZUvpWRMxv}}j1pnP zTEOvllQs!~IcOsCc6E~3xd9ei<2*r-pIk&NsjjeA@G#=d3mObVtmt$(knA%DLg7|& z4045dIMW{k%*_SsD63WT1G>$pv98D0!~Hpr*ss)cC49IeQRGNiMp^0=jZt?EdKSr7 zw-gtzx7yVkJ{62Octw>a$$m@xvIE}I4lu@_Ov9874JFM16^+{CSZ^XZJ6T*be= zxmHO11%-O_D6pcTa*sDJ1*&70?@&Gj2HrsA0LPhKcQCAO}X6K zDyd;`IF(74*J2QVtQxDsAN5V0fS^3u4BIHp_RdjM>_x%jp6)U^3(on_hBL(X*3*Yu z<8dEc>9p+zw7#ztKywJqgn8*IS63-$L)#NuCyN0KC3+OIxY_9&B{f$EvoF&j^wb^% zA|aCS8>rq-#3oydI|kbNkFy6dFz0%uQ8Y}zc4Yp5j{h>hU)VTM{68zhTotqiHX0hb z0cGn^qqczj6UX9os6*;m>37*XcHX(Z{NVm$_5c^L@#*{i**yu&z@`GyF|Pt=w=E2Z zy&7C3MLNb&Br+i>!Xt4;d5sK|n#Q=5fG zi13BR-QhMtXb9Q*oS*~3jDaLM39#s}Ih%3mMGYTw6=ZwX<8q(q*NS&B~GZ zisj^vm)+2Y7qCVpC3S6%th*mznl>{%L;dRL>ZU;+8 z=oEvCZtKJj9YV(x5^tNx`j;fZdC|>czo+y4*o_0!Mfpx1(dR&U-M=Kbp2=^v*Jztjh6_FCNc|K-@2ovI#h8G< zyIb;-g9A}J01Pm#C`y6v@G}shqo3Iiv`b2xb{!s&bN(zUvJGLp2jUa6|X-o;%ke-q6p_yuQfWXS>E7l``)H@yn{o=qD(d-&T}<*6h32PM7*)qpQ=R zYxT~k8A}qdzGul@cl8wT+*5^m$3N3%R->jU^C_o$#=^<$WI}SO#?a)DSHC6x+tec= z@UP_uA(1{wZ-IJd-J~CDiVWXp(tov$Wt`7ufb;7ZFilDs(aM5*Gz{7n1xm(Jodb6< z=lLkcAC(?qkRX6vI;4x1w5uBA(ZAjywEuH@Bg;tln~N6=JrzdoZQ5#V;*Id}TKqN6 z{%amf-&Cz$D*P)#_J__p$hULm`Q4W$>R`g|LjlZ4jzlSQIwtkNotW0=e>S7(SUi$> zqi%fY-wa@|$U*wULev8#;p(o_F!6Zwyh0Z&urlbiLTV zY82V*_e1a6rcl8UreJMEbFcfiiMR*Wj)>9l{Ys1s@#g@nf_Hx;@E&trh#A(6p@C}{ zk2nM1hhhIb#QH}XC>TF?2V5`Sh#9}VXvc$Es+r~Q1C@fOf>CKDGr@HyK@TE4daRsA z$C(=u-o7uW4eKmy(Awx56Y6*Sf6}?V*Ew-%HS859-w1-E*FTtq_&4pk)xI|hz1x}n zkZOiCa(8JnGxEhHu~2np^fG}CXOPK@;7*bTW#On~B$0NN*!&UGWvY(&#h$0G4B8Q9O`<`B>o^`wy3lRY?Ja$yfA*5 zV=_1>S}w>}>A0$}1ypj0zG&A0VNUWF?@j{<*Q)!=iYZCne4{`(kjD$O@Z-$o`AP#^ zqtiq&UNyg3N$Z7aHPlZZsTI|}w9n|WogGJa^C%7)^bgf*hWEoe^lIk!35=dHUlRur zj3Gh(up5gJSIDuIkr$-R1TlFauNw11F2>=bqIl1eK+Q{9JomTbltE{y3=jOygB|$1 zXWgbf&VxM>CJ*L4J;7#_XVTyJnx0!Yj2#})(rFa4MZaN>UU$$IX)g!Q{`1`2zc$b- zf5+hu`_pN!s15mZU+k~5=V|pfBRM&lL%X7eIp^)aJYoNJOG#Cbg%d~TrCfv-k5C1? zHza@5X&&mkeptM6TXHY`MD59TEkn~Iih)K)B8p;RzFarqV>rLJTkgtPkGwxSa`EzX z5^gtNxN%g?_EI6Ra+!`zha@|cIxnX&jQ#9c<_CXZcOby5j=9utve*QRbN%@kTiUSr z)-9-0>CSIzH4hajaS)^KBqFk#deUXd^k(nmC+&}l6Or(tH1>)gF5O=vgfEhjvlBE` z!+a1`9a!SUwQgjOFXQWd(_3@rpKP3mvWa!#WdUD4nw15p*!O+7+wfAha<_XE>&3oN zkjVq3)G`(=Ju~vG(Q@R|8y*9;a~71^5{l*BIslV0c|5bHF78;37DcLAt^&?ib;#ih zPC`$Qst0{+ChD+Kz(0#73m1=`)j>_++TSd54%QfdP8L|t8xX`=&Uy!WRrWvT{}ffEsI>3B$VjSm{2ek&eY`Nn!JLsqwx;Q( z@$}DD%QrcZZ$ypVB(A?$%F|avyt9~^?s7GgfBn@jZ&it`FQ+HL%i1Qs513oH3h@hDr0CEq6>^9nlR@sTCX{N){?{up60EgGEE+1t^Z-7t7$~r-Z z!qmQwC08mr;dLG=^#T_UE-Fk-X~w?MJ_9Vi^fXkci_SXfNSD{k;x0Rh3y!&IR*pd? z%0MlLBtJ&uSF6}pwN%TE>4hH08$4Ma<`^ECU~jeZsvw~Yd_|!TG$uH;`$GOhoO*g1 ztW&As2Xqp@X9Ln`=fqoLDO!DxMeGX!-)rBOHA1V!@qajg!0|fk{EuwD1A*s37mG_z z1jlu5TG#Y8qu{N82`N2ZS@GAF!%>JvDf4-Azbc_TY#Yln;>!^jx zM>0hVW}Y0oxhlb*Zo%K*bq|Z>e>-8*Yl^JCOis3Kq6ImLC^|SovIi7&zj`nopS9NE zFUtKcDG?S7`V5`8GFCNNAT+tYT1=bbt6$sH6&XlqEuhk`-w)yOj;Hl$YP0W0UaG~L zU8?H|Fb8&|W|!)wUpR4XT9*A@UUxHIxYWPV4w&0@Nc3907OBv*nhUc1n*Gh31mo4K zGs1tkfo)^@{@dr8NISjjD3*ze93JPuBW1>as!4Sv8CxI4`rry)j z=Pn~YNBq6|$3HJ2ItITMMs@t2r*Tr2vZV?kEOJQI$*XdNC6#b}Fxj{Bvt#92p*Z2W zWu>o6^5i?w_h&ytY07>M=IFODupaJo$|sKTAsCZLrY{AYrV1ZS36}-97b*PcSNQ;J z{9hhxZQX$%&VS?Z3Q@?h$}Do|H?`B|fMq`JlFD?|_otYQm63fxR%bRMvsKgBDGYi& zr%7x6z|wx&mA7BzgMU0}5_}Osz#8~d&%~*PxOM7JGNXz2M!Ppz{b8f80<6FGk-@TA z3;%Ixwz_Y^D+xYi9+b%KXDmJ@?LSHjTehXCb}H^htd7hwze_x^Og^`ifEx^bP@uOj zC8{9uQ37=C7`BMU4iVe_amh$|#~G7I;*#>1!n1jZ`>nO};|J)=<~6?Q2tO+M!htYM7YF#io00Na11t<2$<>Dooq zeL)v5b?El@9uCNW+f;Y)+j<6{)SX zQKlR#QT6(Mopn{X*Bo>+n1ix|3dqL%XTRVy)dWHCRKo}S-C2J)xrBygoS_7LE6_2kDH= zL2f);1IB~SXNCZLmA6ir@1f2}D8=$aiQ+P->88MPIZf-7f0;@88Cscww0Ii$U^T#} z!HGM)DyO~M>az8zv4uO-uU6 z8x6O=`x)JLT%$mX{iV z%?VkDSdZ@+=9|tmML!*bc#*f^SLJhu@y=`f<;W3-aq&)jZNR=?oz|z;nKk#Fvk;mF zZC0%sBNMVV5dT5PcF9ge9SOg6Gik;Z@ntj;|{p827O63w~S;@OQEw-~5yXtrAuJM2NbS6r_ z-f4Az`|}Z`!Hq*k$H&p@Z3>Gkh$u2t1u zZY#v83P9=47);GWJ-^bcM1&=NbN)+#(5FkaS%3f!eDG(Z!-Ra-9o6JGmP@~APTvQ5 zyzwy^&4M!)=TGqdpxMI@UV{3V(qq}b8l7I6vTp`bRrO_ip1p2R0NGI2xzgF83-Sf#=pZSgQ_)B-^VlxQt1zgIh%i?U5N1r}GtU#&-==?FG)Zt&it1-v;I1Hywk9DI(!*0KS;siEoe!r_GHN_WEH)G## zQ(mq;B(>T6KEsr~?5FCT>;8$#&1_}P4M8?4L#Kp^X?g8Cm1chB{*xno(rXM+fXc?x&l5b7bC1OjiCM$GlqmQkYvWeqH5T6IDmBhnLzK z1$IGCJp%9U7ot3m-w2|8ovtVr${zI;_R=hV)Ke>8DW?v8ox!>D^Iiad*`s3e(yNB+ zLw?-4{>ZyA0K}7hIOpAn7F%pL3(nYP_3G1;akJa6nJ@ALs%pPIGD<0Mey~cimghOCcg!bg8e!@I+9rBsoXhh0RE!=Z;rv+NAA zNIk6-;ioxrFd?~1b`!X~>=rSB4(?YrLqcowr|dPJ+LBTNzm7&It-h@|`7wp`OmEIv3#>VQ z9)S=OB5J2&QnSkV&#^t!r0KFn#%DW)1&=P@ElrRA?B$AKkh)R&33?h!3=E2mOe8nV zT8oyykN79S@N^H?1}+-jaSrTcm`GhH=}08c2_}cfyKSC7d2e`ZLi7QU*A!ABki548 za1!?-vecnJPX=`(@As|2n@`t~PACkdebY_nT{a%H@VTGpzz(ueuZbrMkzbHi9pI^! zCL#7?Sf>m+0d{v{2h_mc-PBan8>SZP4kw@oj1gP7T6eU3UOqR zr*F9hU#+S?nR3Ua*Yi|L{s~o3nG*k{c^EIzTu)Wsg4}u1vCd7MGAUL|sh;RFqJx4i zw}%eK0{Ib8f9J-l{i}+wO1N5hd@V%u?HQ_3PR7n8*Cr`DS&Ua`%CbWIVqaBX)kju1#gp!rpng8EWGX_; zzyYwnh)a_5k@ZKk3mEn7#Ex04=UP{>;3c^kWIGTpC@$yrLxrINl8yO? z{o2t8u;&@L>D=r(mj$@)AHeDe}UB&s}iGn~QEHE|Ji z{+lIt74S*_RLiCAZ*F#eo!Z!MS@ILtC)Zleb8D5>v(sgP=7XzUxFt+?pF??qSyN3V zdv(V6QzmT&!;S3Ln^)8B;sD{Dk|05TTl=w!MAc)82%Kb_N@cMwGbir+?EOkkhXPK{ z_EJ|@XrySD)*7$ORDPuuIJ8y1gLLLIedPPLf4+H6i-`9mE+=LCa|E9`%SpWZNvr=T z2Vx}d8#yYflD0YK3dvM(78Yb9{q?>QCN6zo5Wwd{z&nf5y&75!0$Uwptm83~>Wmj4 zQxji}Ihj5@xpbz->nhr;?=XU;?HqX+Z1Q9rjw=jSt~k0{;9R|q4S(zQHK?k8&s2Fw zgorLh;p!!gO?6jv@4Ly<5d(%k2hC?a{tKiLv1(a+cMSNb#I56bGqN=mFOKU`@SSkN zv(U43LgVS8t_V>u;sfivr9Be#^beqzBB*Y~I^ zNBivg|9e%5QUyC+dh-LjbEJIDKYHH*#LQYM(jmdhbOa?9j|-n5V_nyircGx*k{|CE z>mo+7{yaylrELW+oIMOTjb$Lby9DMtWcw_$+GRD1ms#UR{BMUJ*bX9Ct4vJ-+AR9r zz3Y(2)#HtE@$@Z0vi*YYm>UV6xsrZsyv&_1eT}CTf3ZUX!V#Q zo?(c;{nX@PVyri^@o)fMZY+0SMlf{Pf81bi?s8z(UN}JBvmyt%)*5MLMp^U*$NG%M zSYI;Q^rcN~q8z#%&JXI!V54geHw=$M$fY^&bkxz1r`7W|r~6UjuyEg;lA4x(zt`tx zqutqtXH%HoT4>oWN$bHM7PNXH;kb~)wEP)a$3gl&q3W)_;Bjpu>rxv88WVq8Vb1(t z)AX^2t9R3P?E8iZz~}U1Z%IIFQj*jc(Aw5N}YUwGX;KAeu@XLlL2i(YbmvGw5Z;fC8_;c;6%Tit3-5oFgcPWr<^r`>EJ06A7?M5oloQUu2?bb)pHzmIwS zU&U>O5G4&iB`8iI@t%{Rv*08=O6Qc z)WcE&3h3(Lbj=K_-payaGqA4B0?Ar;h;Fyk{d6j4YPTg|yVQcF;(FDyGT8q8Tlei~ z)ZaoWp=L+T?=A8%lxlf+D-3n*T>jv?QpD(J7{|!rf%SOg$p>W}{$v$B3vS7v6Cf8@ zZ;|(*E$|uPnD`mS=zdbAF7C6DPx`1*;lRnq}P&l*!*+ z29N%||NTH8%X(^Yz+XSgSb*KCYB{H*;`om9e1&AGVG>%9jm7%ORL8-*5Cu6!{Yr^n>vnEwW_KilbF3fAs0-W z5GL)zxa?VNUy0a4zb|%_H0yOt4C{_DSHGNWpFN~~y`&7AMFhS`oO@AU z;!XA##h_h5b+YEIcJcsu{@SbP1lSCdt8xzZTTMV!z*Mjbaj<^q+*=#1FkS^#Ty5Za z$8m*^j>#FR489E+Nr*k?X%5@!NR;usDM7=u6N0T;1%*@{$gC@FRFpFZqK3p8KX%4O znSZrI`YWzVlW|S?Vltvxepx3dGx^R%LD@#D>*(c-CGuHnKx68SFIc)9&iKl|FqvtW z*?Tg|w~#`WJ6wj%J}fkItQ8<&>ZFzuAD|Z-hR-mFc?ln(Ws6``_*^xISOK?-6(HFS z+j%4PZ;rYfDcg3ajHj=bjJ8oJ@j6O)rvNQ^_u_fGBTJhj*eu2}l@r?L`y~``qCgby zvSCv(!?qq?^mkrR&Mdxp?|p=>=$k4x>e8%g#OmB^-}=(Nb{ad>*P>AZO3 z!9hd0>Y;Dob9mrBj@k`{o0@{FOh^x3CglYgoqHin&K#ZgT9RV+SLA8`IP&Bjv(J*t z+|NJR*YD+PIUog!Ko&(n_c&$u6~@bnrbn_z5J)O4UdL`o#-pW%sc>&BzR&2zR>Sj# zjgb=!yMski*z`j^B~MXpf41+Yun{kPhQdg5;%jg$0WIa^!}(Kjd8)ls@4$?RKEkJ# z)+i^*25cpec;GOusjD^Fq`_D(wtIrA3wh7@J()BO%1Xzt;+bX{WXIrhm zEaKHcg$|fB`N8$nm35oQght7#l@9|)B^?S8P$m1gWD1z0-OolR&-$S*@i8$k9gDau z)u)kGfm@iP@BY%!*_cn46n)06v*k&1OaD}tu9*Kc zn)Gef3Oha%mH=%BlOF#7!~Ci-yqzd|%bv&7?NqQTDyl9f7_pHrqCEa|fAd2K_d3b% zs?K;dCW)8MBdmSxA$9@&K@4VM1lQyIK!X<^68l`hFKgE2U%%p+WXnPgs6z$wS107m za*LHg@$>z?b2DF`Piji?wl|i%4_ePfXn!68)Bx?`D)P|Z!GD@l(4;a{rLw4on+1yT z)QVM`R0~K^v*orK$xSxHr(Vl6SWX^6gdJq@g)%FTi^2}w+}2se$&}j0R#zL|ut%~2 za9F^}%)8)1AHl+eE>E2K_P%IegZAK^9waQz>^9$|)ir55YNd<>48Hxo=@HI=!Pf10 zl1}+rgM?NX)y);rLd?=l4nD}pWu0qN(ZM07>D`GBqVH{ot)esynhH%5Pgi=`_NwT& zEx!}!l2#Nr%bjFJEZw(TQ1iHBZ@5xu++~k3I8;W0e6K&vGVJ#9?_)8(7s8LZ`GeVP z^>aKX*l&gP(wdl$C%o(P)Q|4eH-6vw;0e0YY8OenANCW5iuRT0WuM6!bgwhq6Bb2V zy__(Qcz}dE8=Vg*64=TG9|J@-?7rbIfH*<+SdMamUfg#4Ba!831~T%L+rHDJ0^P82 z-=TBfr&06{2_Q1XH39^)lt(aQJeNLfgzv4$Nj+9li-1@~P0iuPS=qeFwuR@OgIg-9 zmy#Yd$dcx%6uJlVVh(n4>0bnyH;gy-`q!p{X2@&xom!NvW$g)b3>9Ai0@c^xBror9 zbVL~PAnAvlB1Ce&IYI7|@j4y_3BcAERoO|r;iw`3R4Ld9YDfHX)}SJAcV1zKW)ws90Xus8A z?n!{ny3mTz9xz7Bp4+*3G6GZ+;4elm9y~+nHurh%B0<{JgY0}nY`WAnmHW5GPs}!w zO1L2*Jx>-k68df;GZk${Lbo!R4&^bc`|FTEdsP3(#z*vKxO*lU(=MidXziF+1u6(F$Zt%zJl;3S`A3w^OK?1(u|Hu zDfj(}6|ze|E7)PP8NDzu(Ze{=@tMg&=xh=0i`zAk`vp^tG;e7Zv4oj|iv_Kv0Vx+e zd|8LaSjLroIGjJBmJ8Qy%Z|vt*AI0!akz%X2_Lvy94uBOyNBf=ACFo8nJWJ z4N>DP+Xb^Y^;&iWf8=;J^6quZ9bsXVu3rIX__b&Hl#%1kdz00UV=%;KR)JfEu-MgZ zKfKY|A2zQ7FqJzrbmbR<94VGijH%xTrarZQ(Y?rM5MJmp(3Oa`>hi4K5eql(X&X5I zW8KK^hSHXd#3*EBgCR52*iIJ+-Ko`v7mutg|D5Cqm=Nu`OM4v z-Lz`5d_^6GX$vLK`262`&U!R1>6sBs;=WwEcoEv?86l?CFAn2rdKRRYj|%kaBE*c9?^7M_$-R-HinWmQ#jVK+KB^PnPZN zKl_mL-ce0|@iyWP{>j-bSIcd$Q2ZqHl9lh%2|Av{ObBD91 zr_J)V6|5?Efb{sw?+H}j&9a9tWov>81qU5r8V-X`D{R425&Ut!pLn;6lm}$LttjO< zDq(eNUt}xT3_JB0|Kyqx@m}Nd##VMzpGT(NrzBEnbt~VOeWAOhR86z2w3C8Riz{*D zX6Sr(+HRJlM!d-ssDUh5Z2mb^x~+`#0(oY*#S|IacQr~L5#5LteVm^BIr2g~^bG!j z4E(3d7oU*bG!N|aE9BA58*iKK5-;`kTMFIS;3kV=60kf%1metK!KB&!jTKVjXtmR9 z_hH-7d}9}Xt;6z?XZ%I!gtAN2nVui`ctqa?dRw({LU_ZX*WW5?y?j!`dW5nHR@@r% zOw88S7gzQ)acbG8RiNkY)!_``JK-U1AgvUX^U1vv71e8GXc}-ky?iHC=%_tlhI^{o zR9S5kwkn9jAZO<5(wxStJALrtjl1ps>V)!a7)=Z&wa?R_>WGU-Hcu*%SRogMFYU~`eLqf*QoB4*wJ#AyI-h;7GLTPnB-{L z_=>f;ICHW>X}nO(h=aMYVWQ?D{rES$xpZA_-Y6lD2H94B7H3kpqdZfaZARodQ?I~L zBtP8fBp+mQ_j^>8+f+-kN9&$=d1axf;zm=&TS9Cjll@XMhrW(=^wRsuG=7Wh?a>~b zhM&{=)mlO=dTe(F7Y-lsZHeDeB0Rod#uTzk>XQ_7Z-8xvGBC9EPWEoCD3&B|_+Uo_ zn9yB)x(D_6sf;p{Nk`fW-q9yegFv!tloo9TnN$!X;|hE%Z)SFM$w-l)1HZW_-eWfF zk&}o@2b$8WLLYK-(*h@$xy|x1Il+gKB~rTBA{|5NEA^1|MkJ*Irl*g_nj236gsn;B zmiKqNX&Uxy4EnM;6i2e$G$&Rq4u#15)jLx(o;MY(6kIBhSLhLkHDz&+PF_^XE!wAP zeR|S$^fP?WZS)@Wu!Sue>;}0VFniWRz_6A#U9=+l90XPWV%!wOFjG|_t5nT5$ok~A zlQ%=gE1^Rwre^0Y_Mdn91Nwu7h z-2(cRu8d%vJI^eQM^VS68>JeD^#urfj_bWPH031F%#mqz6J8sX^X6UnMjwy<+Dc2v ze6VGxzyP;5OIz<7Vq`K=3-g**_F#+B4+%v#N~+aa{FrIG`9r;8(Zf`t4w~&pzFseP zBG^}8>h$1Wp_e;knpLy)c0bvAq&o^rFVw=Wa=)d>efZt5G$ko-Hhx3TNuRpoCTZr= zh$kt(p7%U084%^$I`?G!aCE&CW(7+GuMBAQ~HZewWL(uhW74<{d zINsMGe(s2`H0?RB{gI;{)D3{MAhT|B4TBtRD8uZcRi`6GDV{1 z9E2az_9eO;-Bi^amr)E5RQe31lZ7o?cKTT3%EvD{f^LTHCr#gf__X7x9=dOL8bwPoTKNwe;l(vL2gJrCJ1H&u7*L# zOjY_BpX9<@Fzl!{uTF{2c z!LFlw_$C#4I{n8u_Sk+EB^N>>NA?_9(!tkwG>w5a9sG<61oMNW3x}&o4W*uL z4BOL$ncl|^P1ZH>F?Mt{Nw<#+T4g_`@kqz$>%VC{4f$95Mw;qml?T9P$S2Gk+4O>s zdJ=dmmK&$}gsQ6?%&REqO|-?kIzHETAbsv^u~8hijq37PwR`oq_HsY}tc;$gY7^w! z{xvPIo~Sa5IJ%C0e>>~8_3>8EpUdyM`DZKrb3dcJUo>&T7R)#I3@JS(1@GKViqL0} zwoXJ1(}-LhO8DR4ImNkW;{guhd=hadU0a?)^hsB zC@OV4a0@uy)W8yC-FUQAp+dP!kbNbdnw-(;e&JYvC&(vQ)vI3VaW4NOs9Y3NNLuCwO;{9 zr73WR;e11d9^IbyaN^sbpyi5F5D_;cvF9-l_+8%W>he%dj%F4_8y=pdrNsz@_;L5l z&I!GghElGLJf(XO-~)=Nw_M)G4XV)X4C;OWJKKU%m+e$<Ays;CJTCV+mco%w<%k{JFtlkFh7AtTMeXxvajXzVsQqdSVnm+R*!W_Klk`HNMzS zUz$DGclV`U+Mbc*{n0BY0o3}$9`sXmV&=Ifk8D8QGo_~Yyc5~osmaNzIp1QjJ5hmk zD|#@G^&EnBj=H-N9P}uOXS1|nZz6ug0KZmPZI%Z$8oc|Wtyh)RNdHv|x2`&8^TvjK zdGEPw-~fw;ozFVrPNq0_s$^Y`;9e6-E0@5{IbJoAU1|Nols~Wyfrm3ZJiOJaZTv}1 z{_Wb&*h**+41X;=MQp`LYm*XE{kEKrs~`sKjAA%C^ybg5E~^{gx4?CfhR%!M2d)YNUYipP2lLZ2O``I1da!E`TqRdA}Q zARW7|4AXiqKITtNMgbePta0|XoqX zkDdDE7&u&sW}Mr@89?sgMkDMFO{%8voT{zoC^PQbNP4aWO+t1p2|W&^st&DxOT&b6 z5L{sf28M7>Lt`tIkJ&>bH?Oj6e0PMm6@32g!SPYszCi_ zm*34$=MVal4fBrsWhjofJ_y~ob!$vZ6lIrY|BCZ?PJL%*>9+>yUsAzP(#blf$MT-i zgvIA~vddd?8s}zt5}m)Zha_}{N%fxvI}>9&d8+wjrNRANh!$>Xu=D-+#xgCp@vrla zl(=T<(so;=&pcoujb4jg6CV(L#-We2!zpfP^EM4)S|D*w%{kOHX)ycaTGE1>p(P_u ztvM#4y>wwLSAYFtxE{pGyJ!&+=WOoUy?7V0yMIMr|E1;8ni+p`uP(y zXi&0;Tl!++aL9Cx@Jm)Ubtt3}rW__96;xcDzA>X0WzVLM4zJRsZ#S)qF%0{S+Ug7^ z*JjtoSm=)XYsK-^qBc1Jp_AG#0iW;C83j&%{ZR>3baCo>Qb$Js30ITg z8z|d}ck>HTl>9xozX9^sIDg^}N~9#@C~!{cSAHq5B~obIx~k(*TbLNgB}}1Lpz1Y( zrT%i4tzgX^qDNd2oepsX@vfxEP4mGqGYsY4w{D`lOx)!BH-AL)P60&e>ww5|;Z=(< zH~%Qbd;hGAE=U;Iho^jD@~`L+ZIE0e_mFiCX}Z(oC&Ui8%frsmlA}A&x4r~8CKbH& z+a~{&`Ip+C2ogFeL+pB}9|Ft)0MFbN<*sjd$>ya(4*4c$B%HZf37Yysh=(9F`BKnW!o*+X}=e^`Pv$&vlHOe}y`5pV^~;(cs){vp-B zWFXA>y6K?X=_JK}%k=-KpbUAYyu2z@8Vj0ADBz_9>XrN3Dd>V4Z5_t~H3E?@%Gu_S zEyD}c-0sC6p!5!eXe8o{r9w$Uq^nFc%S#rhH4Y6mC(ru5Ua#I%=X?FQZKX#^LTAWM;A| z*4R5P*Cm_{9yVr~uAKOk>-+54_tGI0M7{eAVaK=%FIjRkWBBv!1cIYhI;8ZQf;SD7 zw8GoB{7lG50UlyuVc$VrS=m4q!phEW5;8PBJr@fmL{g70y-QOzWz;GC5Z?K;K%E_| zZS(NbABXq*_~n-c!Lbjx12lD!xgIUtZ$djgJ*!NH(T6nY+H$oQ;sTZ*6E$XJfZxZkw!5%fQ3 z;oU%TU>NoE;1!Q8;C%9=>AgDLxYM>N7dk2Zy@|=^<627N^YUrlm!~C^J6Kt@Afh57 zEV+w6!{Oo)%8m(zB3)S71Wh$p)@k!E?p=e@kD~3lDc+J+SCa(QGV2mq%vdSiBZ`aP zcc7Get-QTkXwnVDgoTmDXUaTRJkC5!jcmi zNjJPe<<4pbj1U zTx0})4fM{Xe?jjz-I*7Fr(F(qGOZZUwt0LBud1p@0ptprVUatSG$OnmJ~sJKE^<#5 z@rv>~z(-saFYGTHNNF3Ce}75SWtE-v(itF*Qk)&^OKiRz%~PT@z=%{Xeo0j`;+BuM zDCR-yxG5G#N08`TJdB&%r52#(DZ6#9p<#IiJ9_NmXhVYm#>vosV#~1=1c?WITdo49 zve*0tPX7r%e;G<;0EI~G4MasM{e3;-}8^;wRo+#eP3xc`Dc9`NpRoX3Bu z?TG>a!jg$kfVG(aTjzrQzli=NB4@UshK2?eSs+^U2ju-uWbV(GvHq%4bu;2Uh7zIP zTpWpUC-wG5LWJ(z=||=}FqkFmKeizB<4B|-p1uMlFSc49A`B)0{s1K45gQvz2$yHf z#Z%!;?48foR@{B10#(nR9g@k_P-RgyF)b)*ELgaTi22_D!oTbEoZr>sz2BO|@rn_Z z&aVv(hbo=NSYw%(teGJbP&e0{lbb8dt)a!eQ&m+Z)L~{|;6kjZ09Nf=P*vEwtudpSGi?7d^@N0mYQV znXG&Mdm<}BVqz~4WwM3vklJhOE6P=pw=?c_Ak6A{KsNDRJOX`?QabSaZ9VVgv|EIo z+$VKQYXJqN7WVedh)WkoA_6Iq$!^5G^)}GPL?y3cO;M@SU2sIiMF9aVt+>z{K9ZZH zkmf9}z(VYqkDXna3T9H^b$BVqV(fCs?bCmp19N;70EObcuX%mVTDhcOIknwHuXkC9 z%IITmjj9Kh3Yw*ee9k?REv3(-znY6+G{y?K-PM~e$-ki#Q#$vk+$iX2FBn@Jrp`{A zEsj~rV?oq(7eF6|6>axWHiWy&V+Wx6`~liSo%XkL}O{zs*d<0X4~4J|~T zkWd=08>VIO{xJ(%sc9d7wbgV+=T$?jTlhX7{mo89t}5xfTu;psT&a*!%aC>Y;9w!6 z*I%huKXHDH`VOQLyTRaRHRNa^vo(t!M^%* zqEAYF!PaJh1d3JHZQ#DQvG(@O&qHBKRhUs(`y&CO6qJ|g}$ z&AYd6Z#Nn}JeyDbc7A@UT(l|&5leap-WWD!E9F6(tK;)CV#6&XqM{_QK$21CP)A4T z687m%L+~sA(y^>%A+f}UG^r2uLR_Ng-BGvL&D&Vs{-(ZJ!*+c{&yDpsggYnBte7z&Q{O+0TlR&M}`3=lH^B>KZf90DiI=94{ zpq*-Ge(6Az0Y-G1ofehy8fwBkp)L(&#U5EFsFa-lPa^bNEFiX%NORXmz9kUkXyJwH zXxj3mXl`In*S*UhOf`w;*2RN;AU&}>X6W%q8ngjm(vXSh%uM-ZjxPLjWB{WhuMH4z z{CiX9(k?q+gCQ*}S66Gn)P|L`72(0YF=x7tg~Y>gS;^CcBXRps3zyT`X<}EflI`Bd zKV3~9VQ)lT(785UO+4vC`@38J7`j^K%X>-veNVJk?K`_r#%InGJh@yh01XHNoqNch z&f8B_*ik8fhoAAB29ru8+~69poR?rTLgmOsy=M6PGt&$8VwM5Z9*oy9CR5i`|2PK? zmbF%sSvcH9KIc-14X!jdjCpDUTTZzoH{JqWjZS*a^HOJ+5@9u~JAn@K0xr><7RA-J zXtp?ElFFxBIWO)cO9u3@n66y?C6-S`ZwPdDr@uR@7nacf%NuN}WLRwWy5 z1aCLQ*&R+Vr(m}KR>bgGLa`6|jG<~MfcK9u8MscYyJ$Sd%E_U!dx zpVmU36(FuI<=1-z?2NDLB|s~fMS}uT<zxHD@-CLnMsiOfs{OqPU&*9(N;IIkETOlK zWzlx|Lq@N9THAb?iFEb^Eor38RxED$0Y~*m%;eCDzU;E4~pjlLJNNS<#>s2A(q=YYipE!(awVPZORh8wreqw0f!C zWWZOi))HKMM)Q~QSM~nheE*LA|D%sVjBM(|3E$H14HYRnuv~=2Z|re5yK1~}8IKy* z`VP?!eA6_ov3(W*O*sPjmp352_A==bb<-%+m5^-TT~DSv@Y9r12Ku#K)ub7tp9^A83ucbRFVo7uYSDQ?!sL;3BTFe}$jb8k&nR-t#R=}w`-A^2*^ zsyc>XU*Qz{V?9+DJgL+A`Gf$7R=}v_YbLFj9&D1-bSZISnjARwHf+28Y+H-uZ?^Hb z9zvgyKL{+(<##zy6bv7%j`skSHA3s5w@8zr8qjL_&|msUbM9d_;&iF`PUk@h;u z1q*m!di%Enot^s=wr>lVGvr<-E$&8BCt}JNT?$cUkU#oUJCs3F<_9gq@zu&^U(8k& zvII0fEYi>tLISc!4uQLyokF(_Q3~@jVHYNkJ@qu8Q*#K~`*kAm->?Do%wZ%W_9G~* zeBt)ku^#`=@cir1Cs^Hwb&Jp1~($pro**;1 z`hij^9?_yC`_Rsa7<{EIqz`{rEb@F!nRF!8`91xpgRsT458uLkT!`o=BXu#oZ-wYk|ovB(>&wV8Sc6AtuFD~Yn&DJgS@L7v#3o*Cxm4c{z z)wN4*VMTnKsHqsb`_1mzr=xzKYF;CwNszho9j3j@`>+K16}^`FqOtJL^e)qmizrl@ za(l3{>bGN7OmveJiN{MsU6Swvi>PKcviTOjpbFp6nGz=nrl(~mp zr{GTlvy9uWN5K!VH7-R93vOQ)7xY^u^b*bPRS#Kpd?dWj7+R>5O3;y!8DvE2)oOK6 zjo0QR_OXIrMefKb^|VBP_}GP7kMk?`VrrJ0$@P&*Ko8rLz6p0N+2idD8`a8{UTcd^ z4GSMkaqF8@$cGGV_p;B>`!Ho&G8z|UtzOr!Ppv9a@Q(4zmO_wJ5!sTUE!ED+llkko zSBII0N(T*vVc|(_0)XSV?$I$Kip9pFr5+2}oc(~Fk9O;5WLhMu>9jpG09LH37(Thi zHe#@Q><6Th0?*fIxdepZ8V(v2WBf!j9c)HMhHWxbRRENYr8V6S2{%>jv;tyRfqwS(_IJUBdM)f2737VFNODoihP}1VZpmqBBA`>_V`DF` zf@tq(UtWQjVMDend%Ki(mHEf4r@msdrgSftztl+BQGx%UfD+Seu!xOO6ch939G4HU(uf z_t&STq^NXS1;_-dmYVg=dU4Zyf8Ua{WW2n>L=WbJ`IBChV_87n2kh(*e|oE^srlAO zAS<-)sS&p4f3_WNw31X&nb-=Gd%4qA9iXaHj&pgrp*ZC(7wO8kkEqbh>X&fs^%f? z)+29kqE%(?ko(|=u8E1-Moc0YjE80w!dtAK-!6sY7_VYFI<~Tm8Sf<#Sgryc?)(T{ zm3r*a700QT-gUf`mGxd#&N^UQWMNcR zF6@0oc}ZFph)?dER3ZTE)%U;y(OCo+*c*Ma)i5N?L$tN#s@umFXBiKhf*T&f+h@Im zO&#~mO%AymFgZCn2mbMEFg=1cHnSe&FW2e$eZugt!N|C#>}G7i~XUO5-sdA zUf$k{ZI66TxEL68H2RjBsTq{6`-9=@^78V%R^|_k2i=8MP_Os>z1BxB9-*JQsOdC_ zi)Hm`OK}9wBK=byRCU&@6}Pk)L%5TPUQQDj*jXy951}<;pXBKL)t4a_n%6LbSucg` zy0M{KR=$nHJhf>)5UeRyw^bIzLNpz-DsSY* z2VOT$F{wyuj0645mZ)K&wmm2;r`yIg67K{jW5+DhF5Q{ znP?`iQm(m#*`>)1pU=(ndLR)SoZ8eM&G*^t?nX2HaH`G)ZoX^s8H4pTHS>jQ6q>bK z*Q0rA3ab@whiUQHy`;4bw7gw%*|qOHEpCD*&zR@oo)=E06}d3(n=_R9S-BL*T%C;O!M);nzF8RVk`B6s&$PcWeKl zu_{4v6eUE$>8<&QV;L~)_2QcE=UBSLg5wd7unQ7TMa>n3uDwx?C-~Ig1l5p9DZeA`b`SenDO9x+A2arl#5F^k5548wH=CQ^Wl^`nBBKTvgKLnXcvS1$ z6$}jcS68=$nx0GVEO=U8h%oQxe|SKTk(y1KQ>#y(W$Xdi5~vL`^uC zt0KFWt7^FNaP>fdN@p;f~P)|5*frt@CNtktMhPR?+rRgVg>s$^4R975fD3Rz~=)<)G=k!h$`-K7gW_ z3&>M6nw9x)m4{F5p>-HOp;~I06Qv>+{b@^Phc88cEKlR2D61dYJM>h3c6cU&-`B;D zxp{f`w1|wpmiS8+shGoIti0oh@f$DV<5mx~n|dt_pdQSV__hy=4Pvsj+r=)j@{ViR ztJl;D=HJKsoV((ZC5!i>SMa{Tc*ToXyjQ?2)UWyQL)WBHahqqhlv$){)7v$J$wjE{ zmIi!8;>Ty`trd5Aw5Pz_!`MRrSIo--q^=dE7P&Pf&BBkF_ z2@5S$^2*8w-ZL-#WdE?@vN>SrLfq6yFFlR9D?GBzgk@`7+v6Qf%jo(+Vkx;oToaSI z2pafo&CW6Io7oP9PVq9Z??1eC!2U%ZhedT{q7iXxm3Y zb!IwAgec*l5M||!Uo`UgSN6B`A`%JJhEb@2=bysuQhA(P%4DxzTffqV2PE0GzGcqk z6tyiCA+Oqw+S%7_3z-@VG(|w*?s`4aqTnY^@u|myX1r3@DO-vxNs%&selL*9gcdDoIi6E%`AQ3!(4n9}@B_r%UWIv6j-SWd zAA%TJKT#UVa(8E9N6X(!R%(9XJ+FXTFXM~-MYjJQy6V3Y)F0EV*n%r(eAM=?E9q`S z!Hr;F9m|;G0MgtIvMrW#Ew750+$L_fz#<*+S3^;49mgjf{SG+%duhO;)B}Yt`|mQc zb#8e_9u$vS_`(DMLZs+&>sPaGtNUGfX+TL@sA5#)==kFzORnnNH@^_l6qN#`dzpjt^D+X{84`3YB1c0 zfp(G=1OXx%(Z5vD`Nz4uCb&R6nwHPk@|d;*1p42*6QulPu84muNR1r( zfFF!!gg|vkQq#c5j+sRondJK2TK~tl$9ca|#PhdB!46&8swZZV_$La5+k1;A{z&%! zw^~)z6XywW6^kmz^iJXG>hPPok*(sYww9<#rnW18RI_l^PYDR%0Kt(%-O0r|*QvEv zd{bRn|Fd!A?=1FrC(~Y^xQ^z0-O7F3a>?8M`KNtgZPmWUoHhvkKTv9B=PT#FmCFgN z6i+WM)GbD~HAz4DV`KhB!fTmd2m8`)-n|CM^}FIZciZF{ Date: Thu, 23 May 2024 18:36:21 +0530 Subject: [PATCH 24/47] Add support for Couchbase vector store (#1901) * add couchbase vector store support * add docs + minor changes * Fix lint issues * remove stray lines * Add required validation and minor changes * Address Comments --------- Co-authored-by: Gabriel Luiz Freitas Almeida --- docs/docs/components/vector-stores.mdx | 47 ++++++++- poetry.lock | 36 ++++++- pyproject.toml | 1 + .../vectorsearch/CouchbaseSearch.py | 73 ++++++++++++++ .../components/vectorsearch/__init__.py | 2 + .../components/vectorstores/Couchbase.py | 95 +++++++++++++++++++ .../components/vectorstores/__init__.py | 2 + .../src/icons/Couchbase/Couchbase.jsx | 17 ++++ .../src/icons/Couchbase/couchbase.svg | 1 + src/frontend/src/icons/Couchbase/index.tsx | 9 ++ src/frontend/src/utils/styleUtils.ts | 2 + 11 files changed, 281 insertions(+), 4 deletions(-) create mode 100644 src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py create mode 100644 src/backend/base/langflow/components/vectorstores/Couchbase.py create mode 100644 src/frontend/src/icons/Couchbase/Couchbase.jsx create mode 100644 src/frontend/src/icons/Couchbase/couchbase.svg create mode 100644 src/frontend/src/icons/Couchbase/index.tsx diff --git a/docs/docs/components/vector-stores.mdx b/docs/docs/components/vector-stores.mdx index 66d6685a1..7e21f1021 100644 --- a/docs/docs/components/vector-stores.mdx +++ b/docs/docs/components/vector-stores.mdx @@ -26,7 +26,8 @@ The `Astra DB` initializes a vector store using Astra DB from records. It create - **Collection Indexing Policy:** Indexing policy for the collection. - Ensure you configure the necessary Astra DB token and API endpoint before starting. + Ensure you configure the necessary Astra DB token and API endpoint before + starting. --- @@ -96,6 +97,44 @@ For detailed documentation and integration guides, please refer to the [Chroma C --- +### Couchbase + +`Couchbase` builds a Couchbase vector store from records, streamlining the storage and retrieval of documents. + +**Parameters:** + +- **Embedding:** Model used by Couchbase. +- **Input:** Documents or records. +- **Couchbase Cluster Connection String:** Cluster Connection string. +- **Couchbase Cluster Username:** Cluster Username. +- **Couchbase Cluster Password:** Cluster Password. +- **Bucket Name:** Bucket identifier in Couchbase. +- **Scope Name:** Scope identifier in Couchbase. +- **Collection Name:** Collection identifier in Couchbase. +- **Index Name:** Index identifier. + +For detailed documentation and integration guides, please refer to the [Couchbase Component Documentation](https://python.langchain.com/docs/integrations/vectorstores/couchbase). + +--- + +### Couchbase Search + +`CouchbaseSearch` leverages the Couchbase component to search for documents based on similarity metric. + +**Parameters:** + +- **Input:** Search query. +- **Embedding:** Model used in the Vector Store. +- **Couchbase Cluster Connection String:** Cluster Connection string. +- **Couchbase Cluster Username:** Cluster Username. +- **Couchbase Cluster Password:** Cluster Password. +- **Bucket Name:** Bucket identifier. +- **Scope Name:** Scope identifier. +- **Collection Name:** Collection identifier in Couchbase. +- **Index Name:** Index identifier. + +--- + ### FAISS The `FAISS` component manages document ingestion into a FAISS Vector Store, optimizing document indexing and retrieval. @@ -278,7 +317,8 @@ For more details, see the [PGVector Component Documentation](https://python.lang For detailed documentation, refer to the [Redis Documentation](https://python.langchain.com/docs/integrations/vectorstores/redis). - Ensure the Redis server URL and index name are configured correctly. Provide a schema if no documents are available. + Ensure the Redis server URL and index name are configured correctly. Provide a + schema if no documents are available. --- @@ -389,7 +429,8 @@ For more information, consult the [Vectara Component Documentation](https://pyth For more details, see the [Weaviate Component Documentation](https://python.langchain.com/docs/integrations/vectorstores/weaviate). - Ensure Weaviate instance is running and accessible. Verify API key, index name, text key, and attributes are set correctly. + Ensure Weaviate instance is running and accessible. Verify API key, index + name, text key, and attributes are set correctly. --- diff --git a/poetry.lock b/poetry.lock index 70b64f432..64cddfb31 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1259,6 +1259,40 @@ files = [ test = ["PyYAML", "mock", "pytest"] yaml = ["PyYAML"] +[[package]] +name = "couchbase" +version = "4.2.1" +description = "Python Client for Couchbase" +optional = false +python-versions = ">=3.7" +files = [ + {file = "couchbase-4.2.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:7ad4c4462879f456a9067ac1788e62d852509439bac3538b9bc459a754666481"}, + {file = "couchbase-4.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:06d91891c599ba0f5052e594ac025a2ca6ab7885e528b854ac9c125df7c74146"}, + {file = "couchbase-4.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0191d4a631ead533551cb9a214704ad5f3dfff2029e21a23b57725a0b5666b25"}, + {file = "couchbase-4.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b206790d6834a18c5e457f9a70f44774f476f3acccf9f22e8c1b5283a5bd03fa"}, + {file = "couchbase-4.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c5ca571b9ce017ecbd447de12cd46e213f93e0664bec6fca0a06e1768db1a4f8"}, + {file = "couchbase-4.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:675c615cfd4b04e73e94cf03c786da5105d94527f5c3a087813dba477a1379e9"}, + {file = "couchbase-4.2.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:4cd09eedf162dc28386d9c6490e832c25068406c0f5d70a0417c0b1445394651"}, + {file = "couchbase-4.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfebb11551c6d947ce6297ab02b5006b1ac8739dda3e10d41896db0dc8672915"}, + {file = "couchbase-4.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:39e742ccfe90a0e59e6e1b0e12f0fe224a736c0207b218ef48048052f926e1c6"}, + {file = "couchbase-4.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f9ba24efddf47f30603275f5433434d8759a55233c78b3e4bc613c502ac429e9"}, + {file = "couchbase-4.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:adfca3929f07fb4385dc52f08d3a60634012f364b176f95ab023cdd1bb7fe9c0"}, + {file = "couchbase-4.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:e1c68b28c6f0475961afb9fe626ad2bac8a5643b53f719675386f060db4b6e19"}, + {file = "couchbase-4.2.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:137512462426cd495954c1815d78115d109308a4d9f8843b638285104388a359"}, + {file = "couchbase-4.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5987e5edcce7696e5f75b35be91f44fa69fb5eb95dba0957ad66f789affcdb36"}, + {file = "couchbase-4.2.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:080cb0fc333bd4a641ede4ee14ff0c7dbe95067fbb280826ea546681e0b9f9e3"}, + {file = "couchbase-4.2.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e317c2628a4a917083e8e7ce8e2662432b6a12ebac65fc00de6da2b37ab5975c"}, + {file = "couchbase-4.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:de7f8699ae344e2e96706ee0eac67e96bfdd3412fb18dcfb81d8ba5837dd3dfb"}, + {file = "couchbase-4.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:82b9deb8b1fe8e8d7dde9c232ac5f4c11ff0f067930837af0e7769706e6a9453"}, + {file = "couchbase-4.2.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:44502d069ea17a8d692b7c88d84bc0df2cf4e944cde337c8eb3175bc0b835bb9"}, + {file = "couchbase-4.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c0f131b816a7d91b755232872ba10f6d6ca5a715e595ee9534478bc97a518ae8"}, + {file = "couchbase-4.2.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e9b9deb312bbe5f9a8e63828f9de877714c4b09b7d88f7dc87b60e5ffb2a13e6"}, + {file = "couchbase-4.2.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71e8da251850d795975c3569c01d35ba1a556825dc7d9549ff9918d148255804"}, + {file = "couchbase-4.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d04492144ce520c612a2f8f265278c9f0cdf62fdd6f703e7a3210a7476b228f6"}, + {file = "couchbase-4.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:3f91b7699ea7b8253cf34c9fb6e191de9b2edfd7aa4d6f97b29c10b9a1670444"}, + {file = "couchbase-4.2.1.tar.gz", hash = "sha256:dc1c60d3f2fc179db8225aac4cc30d601d73cf2535aaf023d607e86be2d7dd78"}, +] + [[package]] name = "coverage" version = "7.5.1" @@ -10224,5 +10258,5 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "9e4b7f3e920342839dd51795994bdd6b993b6d0313fc715c900c4e0409acceef" +content-hash = "c68a14e273363466c1cea2bacec1798a6894d2bb18cf79ba443dc65c9344c57d" diff --git a/pyproject.toml b/pyproject.toml index b64cfd51f..cc7198812 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,6 +83,7 @@ langchain-google-vertexai = "^1.0.3" langchain-groq = "^0.1.3" langchain-pinecone = "^0.1.0" langchain-mistralai = "^0.1.6" +couchbase = "^4.2.1" [tool.poetry.group.dev.dependencies] diff --git a/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py b/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py new file mode 100644 index 000000000..0c8a815a4 --- /dev/null +++ b/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py @@ -0,0 +1,73 @@ +from typing import List, Optional + +from langflow.components.vectorstores.base.model import LCVectorStoreComponent +from langflow.components.vectorstores.Couchbase import CouchbaseComponent +from langflow.field_typing import Embeddings, NestedDict, Text +from langflow.schema import Record + + +class CouchbaseSearchComponent(LCVectorStoreComponent): + display_name = "Couchbase Search" + description = "Search a Couchbase Vector Store for similar documents." + documentation = "https://python.langchain.com/docs/integrations/vectorstores/couchbase" + icon = "Couchbase" + field_order = [ + "couchbase_connection_string", + "couchbase_username", + "couchbase_password", + "bucket_name", + "scope_name", + "collection_name", + "index_name", + ] + + def build_config(self): + return { + "input_value": {"display_name": "Input"}, + "embedding": {"display_name": "Embedding"}, + "couchbase_connection_string": {"display_name": "Couchbase Cluster connection string","required": True}, + "couchbase_username": {"display_name": "Couchbase username","required": True}, + "couchbase_password": { + "display_name": "Couchbase password", + "password": True, + "required": True + }, + "bucket_name": {"display_name": "Bucket Name","required": True}, + "scope_name": {"display_name": "Scope Name","required": True}, + "collection_name": {"display_name": "Collection Name","required": True}, + "index_name": {"display_name": "Index Name","required": True}, + "number_of_results": { + "display_name": "Number of Results", + "info": "Number of results to return.", + "advanced": True, + }, + } + + def build( # type: ignore[override] + self, + input_value: Text, + embedding: Embeddings, + number_of_results: int = 4, + bucket_name: str = "", + scope_name: str = "", + collection_name: str = "", + index_name: str = "", + couchbase_connection_string: str = "", + couchbase_username: str = "", + couchbase_password: str = "", + ) -> List[Record]: + vector_store = CouchbaseComponent().build( + couchbase_connection_string=couchbase_connection_string, + couchbase_username=couchbase_username, + couchbase_password=couchbase_password, + bucket_name=bucket_name, + scope_name=scope_name, + collection_name=collection_name, + embedding=embedding, + index_name=index_name, + ) + if not vector_store: + raise ValueError("Failed to create Couchbase Vector Store") + return self.search_with_vector_store( + vector_store=vector_store, input_value=input_value, search_type="similarity", k=number_of_results + ) diff --git a/src/backend/base/langflow/components/vectorsearch/__init__.py b/src/backend/base/langflow/components/vectorsearch/__init__.py index 28ea85fce..4cdf5b83c 100644 --- a/src/backend/base/langflow/components/vectorsearch/__init__.py +++ b/src/backend/base/langflow/components/vectorsearch/__init__.py @@ -9,10 +9,12 @@ from .SupabaseVectorStoreSearch import SupabaseSearchComponent from .VectaraSearch import VectaraSearchComponent from .WeaviateSearch import WeaviateSearchVectorStore from .pgvectorSearch import PGVectorSearchComponent +from .Couchbase import CouchbaseSearchComponent # type: ignore __all__ = [ "AstraDBSearchComponent", "ChromaSearchComponent", + "CouchbaseSearchComponent", "FAISSSearchComponent", "MongoDBAtlasSearchComponent", "PineconeSearchComponent", diff --git a/src/backend/base/langflow/components/vectorstores/Couchbase.py b/src/backend/base/langflow/components/vectorstores/Couchbase.py new file mode 100644 index 000000000..1816e85fb --- /dev/null +++ b/src/backend/base/langflow/components/vectorstores/Couchbase.py @@ -0,0 +1,95 @@ +from typing import List, Optional, Union + +from langchain.schema import BaseRetriever + +from langchain_community.vectorstores import CouchbaseVectorStore + +from langflow.custom import CustomComponent +from langflow.field_typing import Embeddings, VectorStore +from langflow.schema import Record + +from datetime import timedelta + +from couchbase.auth import PasswordAuthenticator # type: ignore +from couchbase.cluster import Cluster # type: ignore +from couchbase.options import ClusterOptions # type: ignore + + +class CouchbaseComponent(CustomComponent): + display_name = "Couchbase" + description = "Construct a `Couchbase Vector Search` vector store from raw documents." + documentation = "https://python.langchain.com/docs/integrations/vectorstores/couchbase" + icon = "Couchbase" + field_order = [ + "couchbase_connection_string", + "couchbase_username", + "couchbase_password", + "bucket_name", + "scope_name", + "collection_name", + "index_name", + ] + + def build_config(self): + return { + "inputs": {"display_name": "Input", "input_types": ["Document", "Record"]}, + "embedding": {"display_name": "Embedding"}, + "couchbase_connection_string": {"display_name": "Couchbase Cluster connection string","required": True}, + "couchbase_username": {"display_name": "Couchbase username","required": True}, + "couchbase_password": { + "display_name": "Couchbase password", + "password": True, + "required": True + }, + "bucket_name": {"display_name": "Bucket Name","required": True}, + "scope_name": {"display_name": "Scope Name","required": True}, + "collection_name": {"display_name": "Collection Name","required": True}, + "index_name": {"display_name": "Index Name","required": True}, + } + + def build( + self, + embedding: Embeddings, + inputs: Optional[List[Record]] = None, + bucket_name: str = "", + scope_name: str = "", + collection_name: str = "", + index_name: str = "", + couchbase_connection_string: str = "", + couchbase_username: str = "", + couchbase_password: str = "", + ) -> Union[VectorStore, BaseRetriever]: + try: + auth = PasswordAuthenticator(couchbase_username, couchbase_password) + options = ClusterOptions(auth) + cluster = Cluster(couchbase_connection_string, options) + + cluster.wait_until_ready(timedelta(seconds=5)) + except Exception as e: + raise ValueError(f"Failed to connect to Couchbase: {e}") + documents = [] + for _input in inputs or []: + if isinstance(_input, Record): + documents.append(_input.to_lc_document()) + else: + documents.append(_input) + if documents: + vector_store = CouchbaseVectorStore.from_documents( + documents=documents, + cluster=cluster, + bucket_name=bucket_name, + scope_name=scope_name, + collection_name=collection_name, + embedding=embedding, + index_name=index_name, + ) + else: + vector_store = CouchbaseVectorStore( + cluster=cluster, + bucket_name=bucket_name, + scope_name=scope_name, + collection_name=collection_name, + embedding=embedding, + index_name=index_name, + ) + return vector_store diff --git a/src/backend/base/langflow/components/vectorstores/__init__.py b/src/backend/base/langflow/components/vectorstores/__init__.py index 48e1bf9c7..d38b0a735 100644 --- a/src/backend/base/langflow/components/vectorstores/__init__.py +++ b/src/backend/base/langflow/components/vectorstores/__init__.py @@ -9,10 +9,12 @@ from .SupabaseVectorStore import SupabaseComponent from .Vectara import VectaraComponent from .Weaviate import WeaviateVectorStoreComponent from .pgvector import PGVectorComponent +from .Couchbase import CouchbaseComponent __all__ = [ "AstraDBVectorStoreComponent", "ChromaComponent", + "CouchbaseComponent", "FAISSComponent", "MongoDBAtlasComponent", "PineconeComponent", diff --git a/src/frontend/src/icons/Couchbase/Couchbase.jsx b/src/frontend/src/icons/Couchbase/Couchbase.jsx new file mode 100644 index 000000000..9259aae60 --- /dev/null +++ b/src/frontend/src/icons/Couchbase/Couchbase.jsx @@ -0,0 +1,17 @@ +const SvgCouchbaseIcon = (props) => ( + + + +); + +export default SvgCouchbaseIcon; diff --git a/src/frontend/src/icons/Couchbase/couchbase.svg b/src/frontend/src/icons/Couchbase/couchbase.svg new file mode 100644 index 000000000..6c86a8a9c --- /dev/null +++ b/src/frontend/src/icons/Couchbase/couchbase.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/icons/Couchbase/index.tsx b/src/frontend/src/icons/Couchbase/index.tsx new file mode 100644 index 000000000..85149c204 --- /dev/null +++ b/src/frontend/src/icons/Couchbase/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import SvgCouchbaseIcon from "./Couchbase"; + +export const CouchbaseIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + return ; +}); diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 1bedfa64d..c73ec5d23 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -153,6 +153,7 @@ import { AzureIcon } from "../icons/Azure"; import { BingIcon } from "../icons/Bing"; import { BotMessageSquareIcon } from "../icons/BotMessageSquare"; import { ChromaIcon } from "../icons/ChromaIcon"; +import { CouchbaseIcon } from "../icons/Couchbase"; import { CohereIcon } from "../icons/Cohere"; import { ElasticsearchIcon } from "../icons/ElasticsearchStore"; import { EvernoteIcon } from "../icons/Evernote"; @@ -324,6 +325,7 @@ export const nodeIconsLucide: iconsType = { Vectara: VectaraIcon, ArrowUpToLine: ArrowUpToLine, Chroma: ChromaIcon, + Couchbase: CouchbaseIcon, AirbyteJSONLoader: AirbyteIcon, AmazonBedrockEmbeddings: AWSIcon, Amazon: AWSIcon, From 0347709d3edc1787f10491e15bfc5bae641ca90b Mon Sep 17 00:00:00 2001 From: Eric Hare Date: Thu, 23 May 2024 06:13:15 -0700 Subject: [PATCH 25/47] Feature: Updated Chat History for Astra DB (#1895) * Updated Chat History for Astra DB * Fix linting issues (i hope) * Update AstraDBMessageWriter.py * Fixes from Nicolo's feedback --- .../memories/AstraDBMessageReader.py | 95 ++++++++++++++ .../memories/AstraDBMessageWriter.py | 117 ++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 src/backend/base/langflow/components/memories/AstraDBMessageReader.py create mode 100644 src/backend/base/langflow/components/memories/AstraDBMessageWriter.py diff --git a/src/backend/base/langflow/components/memories/AstraDBMessageReader.py b/src/backend/base/langflow/components/memories/AstraDBMessageReader.py new file mode 100644 index 000000000..9b82dd308 --- /dev/null +++ b/src/backend/base/langflow/components/memories/AstraDBMessageReader.py @@ -0,0 +1,95 @@ +from typing import Optional, cast + +from langchain_astradb.chat_message_histories import AstraDBChatMessageHistory + +from langflow.base.memory.memory import BaseMemoryComponent +from langflow.field_typing import Text +from langflow.schema.schema import Record + + +class AstraDBMessageReaderComponent(BaseMemoryComponent): + display_name = "Astra DB Message Reader" + description = "Retrieves stored chat messages from Astra DB." + + def build_config(self): + return { + "session_id": { + "display_name": "Session ID", + "info": "Session ID of the chat history.", + "input_types": ["Text"], + }, + "collection_name": { + "display_name": "Collection Name", + "info": "Collection name for Astra DB.", + "input_types": ["Text"], + }, + "token": { + "display_name": "Astra DB Application Token", + "info": "Token for the Astra DB instance.", + "password": True, + }, + "api_endpoint": { + "display_name": "Astra DB API Endpoint", + "info": "API Endpoint for the Astra DB instance.", + "password": True, + }, + "namespace": { + "display_name": "Namespace", + "info": "Namespace for the Astra DB instance.", + "input_types": ["Text"], + "advanced": True, + }, + } + + def get_messages(self, **kwargs) -> list[Record]: + """ + Retrieves messages from the AstraDBChatMessageHistory memory. + + Args: + memory (AstraDBChatMessageHistory): The AstraDBChatMessageHistory instance to retrieve messages from. + + Returns: + list[Record]: A list of Record objects representing the search results. + """ + memory: AstraDBChatMessageHistory = cast( + AstraDBChatMessageHistory, kwargs.get("memory") + ) + if not memory: + raise ValueError("AstraDBChatMessageHistory instance is required.") + + # Get messages from the memory + messages = memory.messages + results = [Record.from_lc_message(message) for message in messages] + + return list(results) + + def build( + self, + session_id: Text, + collection_name: str, + token: str, + api_endpoint: str, + namespace: Optional[str] = None, + ) -> list[Record]: + try: + from langchain_community.chat_message_histories.astradb import ( + AstraDBChatMessageHistory, + ) + except ImportError: + raise ImportError( + "Could not import langchain Astra DB integration package. " + "Please install it with `pip install langchain-astradb`." + ) + + memory = AstraDBChatMessageHistory( + session_id=session_id, + collection_name=collection_name, + token=token, + api_endpoint=api_endpoint, + namespace=namespace, + ) + + records = self.get_messages(memory=memory) + self.status = records + + return records diff --git a/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py b/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py new file mode 100644 index 000000000..33525656e --- /dev/null +++ b/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py @@ -0,0 +1,117 @@ +from typing import Optional + +from langflow.base.memory.memory import BaseMemoryComponent +from langflow.field_typing import Text +from langflow.schema.schema import Record + +from langchain_core.messages import BaseMessage +from langchain_community.chat_message_histories.astradb import AstraDBChatMessageHistory + + +class AstraDBMessageWriterComponent(BaseMemoryComponent): + display_name = "Astra DB Message Writer" + description = "Writes a message to Astra DB." + + def build_config(self): + return { + "input_value": { + "display_name": "Input Record", + "info": "Record to write to Astra DB.", + }, + "session_id": { + "display_name": "Session ID", + "info": "Session ID of the chat history.", + "input_types": ["Text"], + }, + "collection_name": { + "display_name": "Collection Name", + "info": "Collection name for Astra DB.", + "input_types": ["Text"], + }, + "token": { + "display_name": "Astra DB Application Token", + "info": "Token for the Astra DB instance.", + "password": True, + }, + "api_endpoint": { + "display_name": "Astra DB API Endpoint", + "info": "API Endpoint for the Astra DB instance.", + "password": True, + }, + "namespace": { + "display_name": "Namespace", + "info": "Namespace for the Astra DB instance.", + "input_types": ["Text"], + "advanced": True, + }, + } + + def add_message( + self, + sender: str, + sender_name: str, + text: Text, + session_id: str, + metadata: Optional[dict] = None, + **kwargs, + ): + """ + Adds a message to the AstraDBChatMessageHistory memory. + + Args: + sender (Text): The type of the message sender. Valid values are "Machine" or "User". + sender_name (Text): The name of the message sender. + text (Text): The content of the message. + session_id (Text): The session ID associated with the message. + metadata (dict | None, optional): Additional metadata for the message. Defaults to None. + **kwargs: Additional keyword arguments. + + Raises: + ValueError: If the AstraDBChatMessageHistory instance is not provided. + + """ + memory: AstraDBChatMessageHistory | None = kwargs.pop("memory", None) + if memory is None: + raise ValueError("AstraDBChatMessageHistory instance is required.") + + text_list = [BaseMessage( + content=text, + sender=sender, + sender_name=sender_name, + metadata=metadata, + session_id=session_id, + )] + + memory.add_messages(text_list) + + def build( + self, + input_value: Record, + session_id: Text, + collection_name: str, + token: str, + api_endpoint: str, + namespace: Optional[str] = None, + ) -> Record: + try: + from langchain_community.chat_message_histories.astradb import ( + AstraDBChatMessageHistory, + ) + except ImportError: + raise ImportError( + "Could not import langchain Astra DB integration package. " + "Please install it with `pip install langchain-astradb`." + ) + + memory = AstraDBChatMessageHistory( + session_id=session_id, + collection_name=collection_name, + token=token, + api_endpoint=api_endpoint, + namespace=namespace, + ) + + self.add_message(**input_value.data, memory=memory) + self.status = f"Added message to Astra DB memory for session {session_id}" + + return input_value From c7f5e4f84353c8e2476722b64d7adf9919652106 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 23 May 2024 07:55:06 -0700 Subject: [PATCH 26/47] Fix lint and tests (#1959) * refactor(chat.py): rename flow_id variable to flow_id_str for better clarity refactor(chat.py): update flow_id usage to flow_id_str in build_vertex function for consistency refactor(chat.py): change flow_id to flow_id_str in build_vertex function for consistency refactor(chat.py): replace flow_id with flow_id_str in build_vertex function for consistency refactor(chat.py): update flow_id to flow_id_str in build_vertex_stream function for consistency refactor(chat.py): change flow_id to flow_id_str in build_vertex_stream function for consistency refactor(chat.py): replace flow_id with flow_id_str in build_vertex_stream function for consistency refactor(chat.py): update flow_id to flow_id_str in build_vertex_stream function for consistency refactor(endpoints.py): replace flow_id with flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): update flow_id to flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): change flow_id to flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): replace flow_id with flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): update flow_id to flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): change flow_id to flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): replace flow_id with flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): update flow_id to flow_id_str in simplified_run_flow function for consistency refactor(endpoints.py): change flow_id to flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): replace flow_id with flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): update flow_id to flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): change flow_id to flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): replace flow_id with flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): update flow_id to flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): change flow_id to flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): replace flow_id with flow_id_str in experimental_run_flow function for consistency refactor(endpoints.py): update flow_id fix(files.py): update variable names from flow_id to flow_id_str for consistency feat(files.py): use flow_id_str instead of flow_id for file operations to ensure correct folder paths feat(files.py): improve error handling and response messages in file operations feat(flows.py): optimize query for fetching example flows feat(folders.py): refactor create_folder function for better readability and maintainability feat(folders.py): update_folder function to handle excluded_flows and concat_folder_components feat(folders.py): improve error handling and response messages in folder operations feat(folders.py): optimize query for fetching folder in download_file function feat(schemas.py): update FlowListReadWithFolderName schema field names to name and description feat(OpenAIConversationalAgent.py): add support for using pydantic SecretStr for storing API key securely feat(ChatOpenAISpecs.py): add support for using pydantic SecretStr for storing API key securely refactor(RecordsOutput.py): change base class from TextComponent to CustomComponent refactor(base.py): remove unused import and log_transaction call refactor(model.py): change components and flows fields to have default_factory=list refactor(utils.py): update SQLModel import and use Field for components and flows fields refactor(service.py): change table_map declaration to use type hints for better readability * feat(tests): add import statement for Folder model in conftest.py to support new functionality refactor(tests): update query in conftest.py to use nested query for Folder name refactor(tests): update import statement for UUID in test_endpoints.py refactor(tests): update UUID usage in test_endpoints.py for consistency and clarity refactor(tests): update UUID usage in test_endpoints.py for consistency and clarity refactor(tests): update UUID usage in test_endpoints.py for consistency and clarity refactor(tests): update UUID usage in test_endpoints.py for consistency and clarity feat(tests): add import statement for Folder model in test_initial_setup.py to support new functionality refactor(tests): update query in test_initial_setup.py to use Folder model for better readability and maintainability * new lock --- poetry.lock | 605 +++++++++--------- src/backend/base/langflow/api/v1/chat.py | 34 +- src/backend/base/langflow/api/v1/endpoints.py | 51 +- src/backend/base/langflow/api/v1/files.py | 28 +- src/backend/base/langflow/api/v1/flows.py | 11 +- src/backend/base/langflow/api/v1/folders.py | 62 +- src/backend/base/langflow/api/v1/schemas.py | 4 +- .../agents/OpenAIConversationalAgent.py | 8 +- .../components/model_specs/ChatOpenAISpecs.py | 8 +- .../components/outputs/RecordsOutput.py | 4 +- src/backend/base/langflow/graph/edge/base.py | 2 - .../services/database/models/folder/model.py | 4 +- .../services/database/models/folder/utils.py | 19 +- .../base/langflow/services/monitor/service.py | 2 +- src/backend/base/poetry.lock | 108 ++-- tests/conftest.py | 5 +- tests/test_endpoints.py | 16 +- tests/test_initial_setup.py | 9 +- 18 files changed, 498 insertions(+), 482 deletions(-) diff --git a/poetry.lock b/poetry.lock index 64cddfb31..583f1ee6c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -366,13 +366,13 @@ files = [ [[package]] name = "bce-python-sdk" -version = "0.9.10" +version = "0.9.11" description = "BCE SDK for python" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,<4,>=2.7" files = [ - {file = "bce_python_sdk-0.9.10-py3-none-any.whl", hash = "sha256:1704211afa3002a342a7dc85d82b391ae8646115b9b85d039814015b9aa6651a"}, - {file = "bce_python_sdk-0.9.10.tar.gz", hash = "sha256:f7c3c57443de6b2339cfcb634fd180f7cebe3a0964de66207dad69697b95ceb4"}, + {file = "bce_python_sdk-0.9.11-py3-none-any.whl", hash = "sha256:3afb9717f6c0c5f5fe3104a8bea4c111bf2ab3fe87ae73b05492566bc2b5d11a"}, + {file = "bce_python_sdk-0.9.11.tar.gz", hash = "sha256:d9e977f059fef6466eebdbb34ad1e27b6f76ef90338807ab959693a78a761e7d"}, ] [package.dependencies] @@ -470,17 +470,17 @@ files = [ [[package]] name = "boto3" -version = "1.34.110" +version = "1.34.111" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.110-py3-none-any.whl", hash = "sha256:2fc871b4a5090716c7a71af52c462e539529227f4d4888fd04896d5028f9cedc"}, - {file = "boto3-1.34.110.tar.gz", hash = "sha256:83ffe2273da7bdfdb480d85b0705f04e95bd110e9741f23328b7c76c03e6d53c"}, + {file = "boto3-1.34.111-py3-none-any.whl", hash = "sha256:d6a8e77db316c6e1d9a25f77c795ed1e0a8bc621f863ce26d04b2225d30f2dce"}, + {file = "boto3-1.34.111.tar.gz", hash = "sha256:8f18d212b9199dbbd9d596dd5929685b583ac938c60cceeac2e045c0c5d10323"}, ] [package.dependencies] -botocore = ">=1.34.110,<1.35.0" +botocore = ">=1.34.111,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -489,13 +489,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.110" +version = "1.34.111" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.110-py3-none-any.whl", hash = "sha256:1edf3a825ec0a5edf238b2d42ad23305de11d5a71bb27d6f9a58b7e8862df1b6"}, - {file = "botocore-1.34.110.tar.gz", hash = "sha256:b2c98c40ecf0b1facb9e61ceb7dfa28e61ae2456490554a16c8dbf99f20d6a18"}, + {file = "botocore-1.34.111-py3-none-any.whl", hash = "sha256:e10affb7f372d50da957260adf2753a3f153bf90abe6910e11f09d1e443b5515"}, + {file = "botocore-1.34.111.tar.gz", hash = "sha256:0e0fb9b605c46393d5c7c69bd516b36058334bdc8f389e680c6efcf0727f25db"}, ] [package.dependencies] @@ -1656,22 +1656,23 @@ wmi = ["wmi (>=1.5.1)"] [[package]] name = "docker" -version = "7.0.0" +version = "7.1.0" description = "A Python library for the Docker Engine API." optional = false python-versions = ">=3.8" files = [ - {file = "docker-7.0.0-py3-none-any.whl", hash = "sha256:12ba681f2777a0ad28ffbcc846a69c31b4dfd9752b47eb425a274ee269c5e14b"}, - {file = "docker-7.0.0.tar.gz", hash = "sha256:323736fb92cd9418fc5e7133bc953e11a9da04f4483f828b527db553f1e7e5a3"}, + {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, + {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, ] [package.dependencies] -packaging = ">=14.0" pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} requests = ">=2.26.0" urllib3 = ">=1.26.0" [package.extras] +dev = ["coverage (==7.2.7)", "pytest (==7.4.2)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.1.0)", "ruff (==0.1.8)"] +docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] ssh = ["paramiko (>=2.4.3)"] websockets = ["websocket-client (>=1.3.0)"] @@ -1728,58 +1729,58 @@ weaviate = ["weaviate-client (>=3.26.1,<3.27.0)", "weaviate-client (>=4.5.4,<4.6 [[package]] name = "duckdb" -version = "0.10.2" +version = "0.10.3" description = "DuckDB in-process database" optional = false python-versions = ">=3.7.0" files = [ - {file = "duckdb-0.10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3891d3ac03e12a3e5c43afa3020fe701f64060f52d25f429a1ed7b5d914368d3"}, - {file = "duckdb-0.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f63877651f1fb940e049dc53038eb763856616319acf4f892b1c3ed074f5ab0"}, - {file = "duckdb-0.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:06e3a36f04f4d98d2c0bbdd63e517cfbe114a795306e26ec855e62e076af5043"}, - {file = "duckdb-0.10.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf5f95ad5b75c8e65c6508b4df02043dd0b9d97712b9a33236ad77c388ce7861"}, - {file = "duckdb-0.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ff62bc98278c98fecbd6eecec5d698ad41ebd654110feaadbf8ac8bb59b1ecf"}, - {file = "duckdb-0.10.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cceede13fde095c23cf9a53adf7c414c7bfb21b9a7aa6a4836014fdbecbfca70"}, - {file = "duckdb-0.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:acdfff60b7efccd7f731213a9795851256249dfacf80367074b2b2e144f716dd"}, - {file = "duckdb-0.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a5d5655cf0bdaf664a6f332afe465e02b08cef715548a0983bb7aef48da06a6"}, - {file = "duckdb-0.10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a9d15842876d18763e085648656cccc7660a215d16254906db5c4471be2c7732"}, - {file = "duckdb-0.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c88cdcdc8452c910e4298223e7d9fca291534ff5aa36090aa49c9e6557550b13"}, - {file = "duckdb-0.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:364cd6f5dc8a1010d144d08c410ba9a74c521336ee5bda84fabc6616216a6d6a"}, - {file = "duckdb-0.10.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c57c11d1060296f5e9ebfb5bb7e5521e0d77912e8f9ff43c90240c3311e9de9"}, - {file = "duckdb-0.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:186d86b8dda8e1076170eb770bb2bb73ea88ca907d92885c9695d6515207b205"}, - {file = "duckdb-0.10.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f65b62f31c6bff21afc0261cfe28d238b8f34ec78f339546b12f4740c39552a"}, - {file = "duckdb-0.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a860d7466a5c93714cdd94559ce9e1db2ab91914f0941c25e5e93d4ebe36a5fa"}, - {file = "duckdb-0.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:33308190e9c7f05a3a0a2d46008a043effd4eae77011869d7c18fb37acdd9215"}, - {file = "duckdb-0.10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3a8b2f1229b4aecb79cd28ffdb99032b1497f0a805d0da1136a9b6115e1afc70"}, - {file = "duckdb-0.10.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d23a6dea61963733a0f45a0d0bbb1361fb2a47410ed5ff308b4a1f869d4eeb6f"}, - {file = "duckdb-0.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20ee0aa27e688aa52a40b434ec41a50431d0b06edeab88edc2feaca18d82c62c"}, - {file = "duckdb-0.10.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80a6d43d9044f0997a15a92e0c0ff3afd21151a1e572a92f439cc4f56b7090e1"}, - {file = "duckdb-0.10.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6934758cacd06029a5c9f54556a43bd277a86757e22bf8d0dd11ca15c1813d1c"}, - {file = "duckdb-0.10.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a11e2d68bd79044eea5486b1cddb5b915115f537e5c74eeb94c768ce30f9f4b"}, - {file = "duckdb-0.10.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0bf58385c43b8e448a2fea7e8729054934bf73ea616d1d7ef8184eda07f975e2"}, - {file = "duckdb-0.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:eae75c7014597ded6e7f6dc51e32d48362a31608acd73e9f795748ee94335a54"}, - {file = "duckdb-0.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62e89deff778a7a86f651802b947a3466425f6cce41e9d7d412d39e492932943"}, - {file = "duckdb-0.10.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f87e555fd36ec6da316b727a39fb24c53124a797dfa9b451bdea87b2f20a351f"}, - {file = "duckdb-0.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41e8b34b1a944590ebcf82f8cc59d67b084fe99479f048892d60da6c1402c386"}, - {file = "duckdb-0.10.2-cp37-cp37m-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c68c6dde2773774cf2371522a3959ea2716fc2b3a4891d4066f0e426455fe19"}, - {file = "duckdb-0.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ff6a8a0980d0f9398fa461deffa59465dac190d707468478011ea8a5fe1f2c81"}, - {file = "duckdb-0.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:728dd4ff0efda387a424754e5508d4f8c72a272c2d3ccb036a83286f60b46002"}, - {file = "duckdb-0.10.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c461d6b4619e80170044a9eb999bbf4097e330d3a4974ced0a7eaeb79c7c39f6"}, - {file = "duckdb-0.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:909351ff72eb3b50b89761251148d8a186594d8a438e12dcf5494794caff6693"}, - {file = "duckdb-0.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d9eeb8393d69abafd355b869669957eb85b89e4df677e420b9ef0693b7aa6cb4"}, - {file = "duckdb-0.10.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3102bcf5011e8f82ea3c2bde43108774fe5a283a410d292c0843610ea13e2237"}, - {file = "duckdb-0.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d64d443613e5f16caf7d67102733538c90f7715867c1a98597efd3babca068e3"}, - {file = "duckdb-0.10.2-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb31398826d1b7473344e5ee8e0f826370c9752549469ba1327042ace9041f80"}, - {file = "duckdb-0.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d09dcec467cd6127d5cc1fb0ce4efbd77e761882d9d772b0f64fc2f79a2a1cde"}, - {file = "duckdb-0.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:82fab1a24faf7c33d8a7afed08b57ee36e8821a3a68a2f1574cd238ea440bba0"}, - {file = "duckdb-0.10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38607e6e6618e8ea28c8d9b67aa9e22cfd6d6d673f2e8ab328bd6e867b697f69"}, - {file = "duckdb-0.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fb0c23bc8c09615bff38aebcf8e92e6ae74959c67b3c9e5b00edddc730bf22be"}, - {file = "duckdb-0.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:00576c11c78c83830ab483bad968e07cd9b5f730e7ffaf5aa5fadee5ac4f71e9"}, - {file = "duckdb-0.10.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077db692cdda50c4684ef87dc2a68507665804caa90e539dbe819116bda722ad"}, - {file = "duckdb-0.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca25984ad9f9a04e46e8359f852668c11569534e3bb8424b80be711303ad2314"}, - {file = "duckdb-0.10.2-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a72cc40982c7b92cf555e574618fc711033b013bf258b611ba18d7654c89d8c"}, - {file = "duckdb-0.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27b9efd6e788eb561535fdc0cbc7c74aca1ff39f748b7cfc27aa49b00e22da1"}, - {file = "duckdb-0.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:4800469489bc262dda61a7f1d40acedf67cf2454874e9d8bbf07920dc2b147e6"}, - {file = "duckdb-0.10.2.tar.gz", hash = "sha256:0f609c9d5f941f1ecde810f010dd9321cd406a552c1df20318a13fa64247f67f"}, + {file = "duckdb-0.10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd25cc8d001c09a19340739ba59d33e12a81ab285b7a6bed37169655e1cefb31"}, + {file = "duckdb-0.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f9259c637b917ca0f4c63887e8d9b35ec248f5d987c886dfc4229d66a791009"}, + {file = "duckdb-0.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b48f5f1542f1e4b184e6b4fc188f497be8b9c48127867e7d9a5f4a3e334f88b0"}, + {file = "duckdb-0.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e327f7a3951ea154bb56e3fef7da889e790bd9a67ca3c36afc1beb17d3feb6d6"}, + {file = "duckdb-0.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d8b20ed67da004b4481973f4254fd79a0e5af957d2382eac8624b5c527ec48c"}, + {file = "duckdb-0.10.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d37680b8d7be04e4709db3a66c8b3eb7ceba2a5276574903528632f2b2cc2e60"}, + {file = "duckdb-0.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d34b86d6a2a6dfe8bb757f90bfe7101a3bd9e3022bf19dbddfa4b32680d26a9"}, + {file = "duckdb-0.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:73b1cb283ca0f6576dc18183fd315b4e487a545667ffebbf50b08eb4e8cdc143"}, + {file = "duckdb-0.10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d917dde19fcec8cadcbef1f23946e85dee626ddc133e1e3f6551f15a61a03c61"}, + {file = "duckdb-0.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46757e0cf5f44b4cb820c48a34f339a9ccf83b43d525d44947273a585a4ed822"}, + {file = "duckdb-0.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:338c14d8ac53ac4aa9ec03b6f1325ecfe609ceeb72565124d489cb07f8a1e4eb"}, + {file = "duckdb-0.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:651fcb429602b79a3cf76b662a39e93e9c3e6650f7018258f4af344c816dab72"}, + {file = "duckdb-0.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3ae3c73b98b6215dab93cc9bc936b94aed55b53c34ba01dec863c5cab9f8e25"}, + {file = "duckdb-0.10.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56429b2cfe70e367fb818c2be19f59ce2f6b080c8382c4d10b4f90ba81f774e9"}, + {file = "duckdb-0.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b46c02c2e39e3676b1bb0dc7720b8aa953734de4fd1b762e6d7375fbeb1b63af"}, + {file = "duckdb-0.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:bcd460feef56575af2c2443d7394d405a164c409e9794a4d94cb5fdaa24a0ba4"}, + {file = "duckdb-0.10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e229a7c6361afbb0d0ab29b1b398c10921263c52957aefe3ace99b0426fdb91e"}, + {file = "duckdb-0.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:732b1d3b6b17bf2f32ea696b9afc9e033493c5a3b783c292ca4b0ee7cc7b0e66"}, + {file = "duckdb-0.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5380d4db11fec5021389fb85d614680dc12757ef7c5881262742250e0b58c75"}, + {file = "duckdb-0.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:468a4e0c0b13c55f84972b1110060d1b0f854ffeb5900a178a775259ec1562db"}, + {file = "duckdb-0.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa1e7ff8d18d71defa84e79f5c86aa25d3be80d7cb7bc259a322de6d7cc72da"}, + {file = "duckdb-0.10.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed1063ed97c02e9cf2e7fd1d280de2d1e243d72268330f45344c69c7ce438a01"}, + {file = "duckdb-0.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:22f2aad5bb49c007f3bfcd3e81fdedbc16a2ae41f2915fc278724ca494128b0c"}, + {file = "duckdb-0.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:8f9e2bb00a048eb70b73a494bdc868ce7549b342f7ffec88192a78e5a4e164bd"}, + {file = "duckdb-0.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6c2fc49875b4b54e882d68703083ca6f84b27536d57d623fc872e2f502b1078"}, + {file = "duckdb-0.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66c125d0c30af210f7ee599e7821c3d1a7e09208196dafbf997d4e0cfcb81ab"}, + {file = "duckdb-0.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99dd7a1d901149c7a276440d6e737b2777e17d2046f5efb0c06ad3b8cb066a6"}, + {file = "duckdb-0.10.3-cp37-cp37m-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5ec3bbdb209e6095d202202893763e26c17c88293b88ef986b619e6c8b6715bd"}, + {file = "duckdb-0.10.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:2b3dec4ef8ed355d7b7230b40950b30d0def2c387a2e8cd7efc80b9d14134ecf"}, + {file = "duckdb-0.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:04129f94fb49bba5eea22f941f0fb30337f069a04993048b59e2811f52d564bc"}, + {file = "duckdb-0.10.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d75d67024fc22c8edfd47747c8550fb3c34fb1cbcbfd567e94939ffd9c9e3ca7"}, + {file = "duckdb-0.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3796e9507c02d0ddbba2e84c994fae131da567ce3d9cbb4cbcd32fadc5fbb26"}, + {file = "duckdb-0.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:78e539d85ebd84e3e87ec44d28ad912ca4ca444fe705794e0de9be3dd5550c11"}, + {file = "duckdb-0.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a99b67ac674b4de32073e9bc604b9c2273d399325181ff50b436c6da17bf00a"}, + {file = "duckdb-0.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1209a354a763758c4017a1f6a9f9b154a83bed4458287af9f71d84664ddb86b6"}, + {file = "duckdb-0.10.3-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b735cea64aab39b67c136ab3a571dbf834067f8472ba2f8bf0341bc91bea820"}, + {file = "duckdb-0.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:816ffb9f758ed98eb02199d9321d592d7a32a6cb6aa31930f4337eb22cfc64e2"}, + {file = "duckdb-0.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:1631184b94c3dc38b13bce4045bf3ae7e1b0ecbfbb8771eb8d751d8ffe1b59b3"}, + {file = "duckdb-0.10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb98c35fc8dd65043bc08a2414dd9f59c680d7e8656295b8969f3f2061f26c52"}, + {file = "duckdb-0.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e75c9f5b6a92b2a6816605c001d30790f6d67ce627a2b848d4d6040686efdf9"}, + {file = "duckdb-0.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae786eddf1c2fd003466e13393b9348a44b6061af6fe7bcb380a64cac24e7df7"}, + {file = "duckdb-0.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9387da7b7973707b0dea2588749660dd5dd724273222680e985a2dd36787668"}, + {file = "duckdb-0.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:538f943bf9fa8a3a7c4fafa05f21a69539d2c8a68e557233cbe9d989ae232899"}, + {file = "duckdb-0.10.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6930608f35025a73eb94252964f9f19dd68cf2aaa471da3982cf6694866cfa63"}, + {file = "duckdb-0.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:03bc54a9cde5490918aad82d7d2a34290e3dfb78d5b889c6626625c0f141272a"}, + {file = "duckdb-0.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:372b6e3901d85108cafe5df03c872dfb6f0dbff66165a0cf46c47246c1957aa0"}, + {file = "duckdb-0.10.3.tar.gz", hash = "sha256:c5bd84a92bc708d3a6adffe1f554b94c6e76c795826daaaf482afc3d9c636971"}, ] [[package]] @@ -2363,74 +2364,74 @@ test = ["cffi (>=1.12.2)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idn [[package]] name = "geventhttpclient" -version = "2.2.1" +version = "2.3.1" description = "HTTP client library for gevent" optional = false python-versions = ">=3.9" files = [ - {file = "geventhttpclient-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:672c6b0239dc6651c02b54b5d3f67290af40fade700ee3ab48fc97f09c6a5dc6"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f11fda0645c406c250e01db97a3e2d2f804c7b50eb1432d1e00f37225bcc4598"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:34338eafa649a281d7f5453c3aaf88744137bbe099ad3ba157ae491cd88b96e0"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb1021556cc4329246a4493ad90ac8a55594c27c2b85093676dc937cf19d6de2"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06c6cc714ce66f66e8f892575aecdbed2355afe4b39cb89d08eb8728b8523466"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df3788352d9ee10fa7c6cdfa45260e353e96466555e2a7d2ebcc394f607e0cce"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ebe1333f4f6b879f84576ac1aeacbe32a382716f05172f9aa38313bf1bbcf45"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bcdb648301db9649d3a099d3f833919315ff34f26e47149f986b0ca2f5b0e186"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:81d6d5a6a0a93c0b7d395270d5d357bbcc4b4502ea2086e711869a65c0f9fc30"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:6af2fc621ea8c7aae6fa49c2204bd80050a0c56ea349011f3ebe2f36d8623ad4"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff7bbc4b4b913631dbc6f23d3d3cbbf1d9b020181cbfa8a806e13ebb01e13219"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-win32.whl", hash = "sha256:cfa65f0c595ad2cf9f129f7cf18de076db4f72449fa8a6cc7f7cf554e5332832"}, - {file = "geventhttpclient-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:f4e1ae7ad0bd7a00c679874652ea49a6352f91690c35ee0da45bf63114ad433b"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:438d3f8c2ba0a9a8b58d62f6ccd29bea468b41f71132f21eb9e8aff347e98c5d"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e22e108b64d20c8767b1e78ebe230d3f2af5805e80246d6aa2afd1dab4a6f19"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:164ec70971c915ea3716d4175d704c6cb0cb020a64eb6ea7f0a3277abd07f2fb"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83589b7708f40b1366616dab832fcefb3f486cf61c65dac9bf2fe3196850d34d"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d735d39b9c64fb79f01b36d47f38653f8988d441d6b7dbaedac3d4b45f0cd21"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41b56ae8a616fa237b45e1a7bc9c474441d7e69fb46a1fac4f6edc1d462454d9"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:034961b2fafcdf1f54895f37980aca5bafa8740dde39d2eacbacb4e0995b99a5"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eec11a2e3501e0170f057f4e292a5715d57e3362fefa75f804302fc4bd916b38"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7387571fa24608e40230bd60641bb811dd0565f77dd52b7b3249eecb9293d01a"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f37e0f56ade9c308ef5f5359bcb9d69f8b6d6ee177f2e1965b5f75472dfb02f9"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bbcf295b8987114437215ed5b2980811a5d135ddcdc1258add64caee679de8c"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-win32.whl", hash = "sha256:44e206dea6c5d11287f4ad96dd807d4cd85f8aad1a243f7b0d87a90dc877bdcd"}, - {file = "geventhttpclient-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:e5c55f3526bf3d9c47a6c4d789ad9cd224ed301740e15c1bdeb7bc067b38c7bf"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:86f0372314515cc49bd88a1d733db31f8d746f77790cd3e9fcb2bfadbf06bf01"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2203442640dc0f2178be7b7a2ed285deffeda31c80045162a291292f1269cf8b"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:005e4798af49bd017c19c7272f87e05bfd72ba7ff876de5a3457026587c16c33"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4188f482cc7d970b7fe71e178199c853064c17c6bfa87a4f5f482bb2a2db3d2"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f805eab5012133aabab802fc1efc7a865226f534340ce2617439c3be4f10925f"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75f2fff7785887441c4f57aa6004a5edf545952db089f060655f77dacc2f8a9f"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c20f68942bea6789abe363a08abb8453017c6eda69bc69d9b6c52f166254375c"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d9ab6892e9b95a782a3af279f07e60ee4de98f94e0a9c78955c820a1e7bb821"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:69f71152c5ff9272c1d4ee653c0ba7357e2eada4c3af68ceaa3b866c0b7410e8"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b173bc1d11ee2bef1d46f5159a23fa749f7c770b75127184aa855df976267a05"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7a771dfbaba83ba558d438e5e3ece49f04c683e3af510ad366f94502af7c5f4e"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-win32.whl", hash = "sha256:438ee39c11b83d737e6c8121467a0e72d2cabe8c5a3a8d432106a10c9c95df79"}, - {file = "geventhttpclient-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:f125e37261e9cf1841cd3d81b196e051150d7fbbf74652aad40eafab08b19969"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:37030e799993c2576c30264b58e868e7de6bbd9ff6298dace713e7ba5c545346"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ab382d7f736fa87a0f417b3b2b67b4ce8a81fceda38d1e6344725907b9d405"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f0691aaeb87f3ad8337b3d862c2f74d8910a2762076adfd32940094eb10a267"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e51627d3690a8829199ac39197d081cb13bc866c8c7fe9d9c383517b4bbbbfb"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01f4ebcd0cae416cab27092f65c6b5a8c6bc9d50e9447f6278c6261995fb6629"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9cb660559b292d7a1e3d22938d384cc3c534d356ca308f50d9c3801bfc404cb"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eec345499bbdf9acccdbd08e9180ff93334bf339cb2b0250b57b6a74a742bd4"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e013cb4fcadbb5e9ef36cbd8774bc8b70ea09f9b4d2ec84b9f3e2b5a203e1bfa"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2144d1900db9f6b5d5560ecba2bba39922829d09dbebaa794ebb0ad9e4747618"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8b30fdd201893a8ed7cfd98df23925623f0e731737e42050a5602d7ed038e55e"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ec607413b3ac1b62035c2bdf5e27d705c8d74a3ecd26851318380c66231909e2"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-win32.whl", hash = "sha256:a06342791b66e2c40b53e7d8ba0fad6b88704cc5e7dcf8d795bbe16e88f783c2"}, - {file = "geventhttpclient-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:a77fc38028c6fb8d9f712f9589c20e8da275368daf81c3efb3019cc2056b18a4"}, - {file = "geventhttpclient-2.2.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c078d03bc1edf2b484ef056312e132772cb9debd0cf0ac3f27144014b504228e"}, - {file = "geventhttpclient-2.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45daaec4ab2b77861a0a81a8735bb82f2571b5035366323ffac9f80abd2973cd"}, - {file = "geventhttpclient-2.2.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89cd7dc244e8052d0de7ae345aa009739f1ae32bbd2a0668a422321824bcd8b9"}, - {file = "geventhttpclient-2.2.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a4835f5486cdf84c64680bba49a59439a81fa9eb632e64c7e86956d074e56a7"}, - {file = "geventhttpclient-2.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8685d152abecd58d9b546012b08a35d1ff0e37761039e817347960ef576fff68"}, - {file = "geventhttpclient-2.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ff2f6b587e7834bebf8ced8be227372b11c24c5429615b9080e2d18401403329"}, - {file = "geventhttpclient-2.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4aa373c83d4724066e528d7526f46139e03299a474ff442cc50f3c802e6cc0f"}, - {file = "geventhttpclient-2.2.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd354a3f7fa6b1d6bd1c4875e8d35861cb5021fd475d5120e65462b85c546b8e"}, - {file = "geventhttpclient-2.2.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d488c914aeae9c740c0a90203ebffa195fac0bfc974a284df4677f39fc0d4d9"}, - {file = "geventhttpclient-2.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0102e761996967bb28689c068a73c009cda43fa80a54b26253198c734926d043"}, - {file = "geventhttpclient-2.2.1.tar.gz", hash = "sha256:29f7e02683e3cd4f0032fba67364ff322e8504fddd170d9de5541bcfade85a50"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da22ab7bf5af4ba3d07cffee6de448b42696e53e7ac1fe97ed289037733bf1c2"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2399e3d4e2fae8bbd91756189da6e9d84adf8f3eaace5eef0667874a705a29f8"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e33e87d0d5b9f5782c4e6d3cb7e3592fea41af52713137d04776df7646d71b"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c071db313866c3d0510feb6c0f40ec086ccf7e4a845701b6316c82c06e8b9b29"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f36f0c6ef88a27e60af8369d9c2189fe372c6f2943182a7568e0f2ad33bb69f1"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4624843c03a5337282a42247d987c2531193e57255ee307b36eeb4f243a0c21"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d614573621ba827c417786057e1e20e9f96c4f6b3878c55b1b7b54e1026693bc"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5d51330a40ac9762879d0e296c279c1beae8cfa6484bb196ac829242c416b709"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc9f2162d4e8cb86bb5322d99bfd552088a3eacd540a841298f06bb8bc1f1f03"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:06e59d3397e63c65ecc7a7561a5289f0cf2e2c2252e29632741e792f57f5d124"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4436eef515b3e0c1d4a453ae32e047290e780a623c1eddb11026ae9d5fb03d42"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-win32.whl", hash = "sha256:5d1cf7d8a4f8e15cc8fd7d88ac4cdb058d6274203a42587e594cc9f0850ac862"}, + {file = "geventhttpclient-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:4deaebc121036f7ea95430c2d0f80ab085b15280e6ab677a6360b70e57020e7f"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0ae055b9ce1704f2ce72c0847df28f4e14dbb3eea79256cda6c909d82688ea3"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f087af2ac439495b5388841d6f3c4de8d2573ca9870593d78f7b554aa5cfa7f5"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:76c367d175810facfe56281e516c9a5a4a191eff76641faaa30aa33882ed4b2f"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a58376d0d461fe0322ff2ad362553b437daee1eeb92b4c0e3b1ffef9e77defbe"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f440cc704f8a9869848a109b2c401805c17c070539b2014e7b884ecfc8591e33"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f10c62994f9052f23948c19de930b2d1f063240462c8bd7077c2b3290e61f4fa"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c45d9f3dd9627844c12e9ca347258c7be585bed54046336220e25ea6eac155"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:77c1a2c6e3854bf87cd5588b95174640c8a881716bd07fa0d131d082270a6795"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ce649d4e25c2d56023471df0bf1e8e2ab67dfe4ff12ce3e8fe7e6fae30cd672a"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:265d9f31b4ac8f688eebef0bd4c814ffb37a16f769ad0c8c8b8c24a84db8eab5"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2de436a9d61dae877e4e811fb3e2594e2a1df1b18f4280878f318aef48a562b9"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-win32.whl", hash = "sha256:83e22178b9480b0a95edf0053d4f30b717d0b696b3c262beabe6964d9c5224b1"}, + {file = "geventhttpclient-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:97b072a282233384c1302a7dee88ad8bfedc916f06b1bc1da54f84980f1406a9"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e1c90abcc2735cd8dd2d2572a13da32f6625392dc04862decb5c6476a3ddee22"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5deb41c2f51247b4e568c14964f59d7b8e537eff51900564c88af3200004e678"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c6f1a56a66a90c4beae2f009b5e9d42db9a58ced165aa35441ace04d69cb7b37"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ee6e741849c29e3129b1ec3828ac3a5e5dcb043402f852ea92c52334fb8cabf"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d0972096a63b1ddaa73fa3dab2c7a136e3ab8bf7999a2f85a5dee851fa77cdd"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00675ba682fb7d19d659c14686fa8a52a65e3f301b56c2a4ee6333b380dd9467"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea77b67c186df90473416f4403839728f70ef6cf1689cec97b4f6bbde392a8a8"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ddcc3f0fdffd9a3801e1005b73026202cffed8199863fdef9315bea9a860a032"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:c9f1ef4ec048563cc621a47ff01a4f10048ff8b676d7a4d75e5433ed8e703e56"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:a364b30bec7a0a00dbe256e2b6807e4dc866bead7ac84aaa51ca5e2c3d15c258"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:25d255383d3d6a6fbd643bb51ae1a7e4f6f7b0dbd5f3225b537d0bd0432eaf39"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-win32.whl", hash = "sha256:ad0b507e354d2f398186dcb12fe526d0594e7c9387b514fb843f7a14fdf1729a"}, + {file = "geventhttpclient-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:7924e0883bc2b177cfe27aa65af6bb9dd57f3e26905c7675a2d1f3ef69df7cca"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fe912c6456faab196b952adcd63e9353a0d5c8deb31c8d733d38f4f0ab22e359"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b599359779c2278018786c35d70664d441a7cd0d6baef2b2cd0d1685cf478ed"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:34107b506e2c40ec7784efa282469bf86888cacddced463dceeb58c201834897"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc34031905b2b31a80d88cd33d7e42b81812950e5304860ab6a65ee2803e2046"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50b54f67ba2087f4d9d2172065c5c5de0f0c7f865ac350116e5452de4be31444"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ddeb431836c2ef7fd33c505a06180dc907b474e0e8537a43ff12e12c9bf0307"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4890713433ca19b081f70b5f7ad258a0979ec3354f9538b50b3ad7d0a86f88de"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8ca7dcbe94cb563341087b00b6fbd0fdd70b2acc1b5d963f9ebbfbc1e5e2893"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05a1bbdd43ae36bcc10b3dbfa0806aefc5033a91efecfddfe56159446a46ea71"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f82c454595a88a5e510ae0985711ef398386998b6f37d90fc30e9ff1a2001280"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b032a5cdb1721921f4cd36aad620af318263b462962cfb23d648cdb93aab232"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-win32.whl", hash = "sha256:ce2c7d18bac7ffdacc4a86cd490bea6136a7d1e1170f8624f2e3bbe3b189d5b8"}, + {file = "geventhttpclient-2.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ca50dd9761971d3557b897108933b34fb4a11533d52f0f2753840c740a2861a"}, + {file = "geventhttpclient-2.3.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c31431e38df45b3c79bf3c9427c796adb8263d622bc6fa25e2f6ba916c2aad93"}, + {file = "geventhttpclient-2.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:855ab1e145575769b180b57accb0573a77cd6a7392f40a6ef7bc9a4926ebd77b"}, + {file = "geventhttpclient-2.3.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a374aad77c01539e786d0c7829bec2eba034ccd45733c1bf9811ad18d2a8ecd"}, + {file = "geventhttpclient-2.3.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c1e97460608304f400485ac099736fff3566d3d8db2038533d466f8cf5de5a"}, + {file = "geventhttpclient-2.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4f843f81ee44ba4c553a1b3f73115e0ad8f00044023c24db29f5b1df3da08465"}, + {file = "geventhttpclient-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:321b73c73d73b85cfeff36b9b5ee04174ec8406fb3dadc129558a26ccb879360"}, + {file = "geventhttpclient-2.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829d03c2a140edbe74ad1fb4f850384f585f3e06fc47cfe647d065412b93926f"}, + {file = "geventhttpclient-2.3.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:994c543f156db7bce3bae15491a0e041eeb3f1cf467e0d1db0c161a900a90bec"}, + {file = "geventhttpclient-2.3.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4beff505306aa9da5cdfe2f206b403ec7c8d06a22d6b7248365772858c4ee8c"}, + {file = "geventhttpclient-2.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fb0a9673074541ccda09a2423fa16f4528819ceb1ba19d252213f6aca7d4b44a"}, + {file = "geventhttpclient-2.3.1.tar.gz", hash = "sha256:b40ddac8517c456818942c7812f555f84702105c82783238c9fcb8dc12675185"}, ] [package.dependencies] @@ -2494,13 +2495,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-api-python-client" -version = "2.129.0" +version = "2.130.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-python-client-2.129.0.tar.gz", hash = "sha256:984cc8cc8eb4923468b1926d2b8effc5b459a4dda3c845896eb87c153b28ef84"}, - {file = "google_api_python_client-2.129.0-py2.py3-none-any.whl", hash = "sha256:d50f7e2dfdbb7fc2732f6a0cba1c54d7bb676390679526c6bb628c901e43ec86"}, + {file = "google-api-python-client-2.130.0.tar.gz", hash = "sha256:2bba3122b82a649c677b8a694b8e2bbf2a5fbf3420265caf3343bb88e2e9f0ae"}, + {file = "google_api_python_client-2.130.0-py2.py3-none-any.whl", hash = "sha256:7d45a28d738628715944a9c9d73e8696e7e03ac50b7de87f5e3035cefa94ed3a"}, ] [package.dependencies] @@ -2935,13 +2936,13 @@ test = ["objgraph", "psutil"] [[package]] name = "groq" -version = "0.6.0" +version = "0.8.0" description = "The official Python library for the groq API" optional = false python-versions = ">=3.7" files = [ - {file = "groq-0.6.0-py3-none-any.whl", hash = "sha256:99e2e5ea48df074c09bffcc349b049d3573d9cb35da872d4acbbe50a4b266414"}, - {file = "groq-0.6.0.tar.gz", hash = "sha256:a96f3a49a0d4119a1bec7f6352af0a87733a2865d464da34a4eb27bfe8068c7e"}, + {file = "groq-0.8.0-py3-none-any.whl", hash = "sha256:f5e4e892d45001241a930db451e633ca1f0007e3f749deaa5d7360062fcd61e3"}, + {file = "groq-0.8.0.tar.gz", hash = "sha256:37ceb2f706bd516d0bfcac8e89048a24b375172987a0d6bd9efb521c54f6deff"}, ] [package.dependencies] @@ -3677,72 +3678,72 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.1.0" -description = "" +version = "0.4.0" +description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" files = [ - {file = "jiter-0.1.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3aa466e89664cb94e69571df326f0c28e25e2e728f90fa4c3c235bbd35b40609"}, - {file = "jiter-0.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:46eed20f7d9642787eed4143f7b25e16cf9915bb45656980cc9b966bb1e00f59"}, - {file = "jiter-0.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51fcd4bdb23de3a26c2b64f7bd87e9e43c82f1171145ba13434a654d7c8e9aa9"}, - {file = "jiter-0.1.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:657ca4cf8d99e2e899a5ef778daed5f42eff6de6f23403a6225b6d6bafb55f38"}, - {file = "jiter-0.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5da72cf6582049d2b802e48dd647a096103994a21a7a762fe813b727565ac0ef"}, - {file = "jiter-0.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:148ae1c97be312f1e969d76fbf507818d53e2867e90cf3c7f78941a199d5b84c"}, - {file = "jiter-0.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f12ce8243d1adb4657cfd9f23ec73fbd206bd5387bea0ebb5514c41fd268a1c1"}, - {file = "jiter-0.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:067cc20889627a0afcaf6b465e942990b9f32d1ad88b0a083ece74becc3831b0"}, - {file = "jiter-0.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce5866bb5ff7dc14d036fede7e7ddb86b3b67064dc66dde15de4771e2697e539"}, - {file = "jiter-0.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f446f1f5e8466fc4dfe775f9c5d8b6c3f0b8b07dc24d4ce76d8de3468d7447a8"}, - {file = "jiter-0.1.0-cp310-none-win32.whl", hash = "sha256:47c1e12bd0789bd4f76cc4973a04d512832568a2a4925cd0b52d0ed413aa5e8d"}, - {file = "jiter-0.1.0-cp310-none-win_amd64.whl", hash = "sha256:0316fa82ee4dab455bac2ec05362f3ac19d77e3139225683289c366ce35605b9"}, - {file = "jiter-0.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f47eb274aae20ee3b565886ab315c3f16f9831c0e4fd6722dc100a2dbc0923f9"}, - {file = "jiter-0.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:80d1bf437ea70f43c0976f96cd83fa4618aceb526ba3eaccf9f736d0c3185f5c"}, - {file = "jiter-0.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215ca1178d30e7a652849b9ca145a4666e1ed0941aef0c61bbaf88a0cd084b66"}, - {file = "jiter-0.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08d7401e20fc660871a02ec05dda9dd93c95052a3c1588385230bca59d9d525b"}, - {file = "jiter-0.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cd365396e9c50b1c458bad0b21452f4c33fea222413aea78826bca98097f487"}, - {file = "jiter-0.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:050252cde3ae0b0a1eca028a30d953ce2d90e0150c1eef0e5ad75ce163d32484"}, - {file = "jiter-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfcf0996949a9435a2ebba2455934ad72d9faa1de2069c65aeaeaa8c6219820d"}, - {file = "jiter-0.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfce158151a3a7d0b8f8af549540e1d8328a9dce4ee61c2fb10b12f269d68b6d"}, - {file = "jiter-0.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c22d684e663cc99f887c3133a7714c5ecba73524438bc3c93e6bb868c55a9097"}, - {file = "jiter-0.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe94ab7e548e492dfd35118de7de613078b7e4ddc276976e8fa2f0f37029cad5"}, - {file = "jiter-0.1.0-cp311-none-win32.whl", hash = "sha256:1c41463f82b67d2efa8f269f7cd150c6c16c5902a0508277f5b1c1569e93dc1d"}, - {file = "jiter-0.1.0-cp311-none-win_amd64.whl", hash = "sha256:40d361aa7e728a186495b7b00a47f83f7153714a8b49d9d38dfc45f7b6630f99"}, - {file = "jiter-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2a1e6335a4ce98dc64d0871ba3316f06d32728beefe336a621f9877b71a237be"}, - {file = "jiter-0.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:832e1a91fea7819507b1d1215e1a82e02da423ea298231af842b35c41d8411db"}, - {file = "jiter-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7f620a558d5952218fe924c7257ce3592835a23e651a140957ba66128675c0d"}, - {file = "jiter-0.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2149878ed5c8d1909546d6bb259aaa3ca6b6f81487b03504ea618264f79f4e3b"}, - {file = "jiter-0.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88ba8abb7025fa4e806a1fa03a2be23cb8584ec737bdf62554873ba2698e44d3"}, - {file = "jiter-0.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2b29b49fe73c7da72f29d922ce85ee5a74772678ecbc2542e99bc4935c68965"}, - {file = "jiter-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53bd047ee136f38c0b56779423bae99cab1b9a65b586f1c19e94a6f65013599"}, - {file = "jiter-0.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92bd461af7766d7f091216942951b603d546f16c1818b9072f5ec7c89bb8a7d2"}, - {file = "jiter-0.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:17a45f16e7253c23c81969086707229591645b192935cb2db226e01bd3abd148"}, - {file = "jiter-0.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e6be9c021ca191c186275d5a9c70b7767cde0852454a8827c9edde995518c856"}, - {file = "jiter-0.1.0-cp312-none-win32.whl", hash = "sha256:c6445c37eca8d79bedf3bd74683ad668137b05880c7af95f0b96222d62be2db9"}, - {file = "jiter-0.1.0-cp312-none-win_amd64.whl", hash = "sha256:5cf60df741bc80439cb2d9b2923c7b712c6c82ac6848387f95d77c5723e01d0a"}, - {file = "jiter-0.1.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:977d8b322f5f661f16903d2ff8e981e210ba0e057d2d70a1f7b59b8d478e6d45"}, - {file = "jiter-0.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ceea8e8ac9af7b0f098660f3837bc3ec975716103788f36d228c543b1319c475"}, - {file = "jiter-0.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3de99e3983c0697c449f45ec740096ac559656485aea48066c982530066dd8d"}, - {file = "jiter-0.1.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb02700ad165a81b0993ad3c550f3b590f0952ff3ce10826fc62aeb064b47b6a"}, - {file = "jiter-0.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb78293d40e38ee5c4370c547af06fb63c7e810f3895ecb76ddcc5fa413e9ccf"}, - {file = "jiter-0.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:194fcbd242b35bda13196b501b116e50fa553c414e1cb0350dc1bc910bceb00d"}, - {file = "jiter-0.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0f55e5cd7b2f649d934b1397bc104200043cdf35addf4892ed66e472e6fe05"}, - {file = "jiter-0.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f6a5c6ae1587f60eb995724e34e7257291c919d163906edd030ced77af9f420b"}, - {file = "jiter-0.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f9f521361cf3633b314edb2313e7abc4fce59dfa1d918561263474fb5c7e17b8"}, - {file = "jiter-0.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c1c0e8b99b4e9fed57b7dbd5be63aa0fc36d45551dedc3c3697aa2694c9a0be3"}, - {file = "jiter-0.1.0-cp38-none-win32.whl", hash = "sha256:631d92b82f228774e9f0b79927016fafed369521b8bf059fa8c0353ba4cd76b2"}, - {file = "jiter-0.1.0-cp38-none-win_amd64.whl", hash = "sha256:c1e798a92daf8c6511907c3861c0cf500f23241c160d1c09cb0e9ba668fde667"}, - {file = "jiter-0.1.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e04740a9ea37118fe6788754eb2ef043ad83809dd677bf3c5f331cc41f8ef70d"}, - {file = "jiter-0.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2d7272eefa5b390c6e450760959e224033b925b0ab76e3279dfdad7f5ec65db0"}, - {file = "jiter-0.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae1f35e062a71deaad689fb2f51b202c1d55ac941733bdcd7587577e17b8a16"}, - {file = "jiter-0.1.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:230fc4dd9c2c3f4b6608fda3f34891cabee2537eef7c7fd0cd68792def14bcc6"}, - {file = "jiter-0.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f867893fb7b458c5cb302b33fbe769bb8c8e60594057f29e005fc8ad21b2a58"}, - {file = "jiter-0.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b80b4b64aa5dd63e79bf5addc903855a9a5b7b2493a826cc2cbf9cc9ecfcd23a"}, - {file = "jiter-0.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab154d2f877e66757202a71669142c1ba9e9b5c5d1cf81510924950d74f62a3"}, - {file = "jiter-0.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b43b3fa25b828a2fc4ed7c42f788c261df17d82fb5ced129140ef8be2577ee2"}, - {file = "jiter-0.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:eb3e9a062ddba709db2afde1ef2c72244dfbae09a27b4aa3701267e489ef7a30"}, - {file = "jiter-0.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c98bddd0dd5cfe638f1a7e4341edfae0a1c97aed879207e594b221f8c5058aa6"}, - {file = "jiter-0.1.0-cp39-none-win32.whl", hash = "sha256:9c6d24f8f1764b1c0917bc35131982bea5517cc7b12226f19c4c01215e1be208"}, - {file = "jiter-0.1.0-cp39-none-win_amd64.whl", hash = "sha256:28f3d4f3e88313ef20e51e3330c22c6ce636ca2eb167b185c298a2ea1ab67b8c"}, - {file = "jiter-0.1.0.tar.gz", hash = "sha256:d77da07222a42d2ae907dbd03bca708079e4268bb7e155006c2c6960281f7f1a"}, + {file = "jiter-0.4.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4aa6226d82a4a4505078c0bd5947bad65399635fc5cd4b226512e41753624edf"}, + {file = "jiter-0.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:947111ac906740a948e7b63799481acd3d5ef666ccb178d146e25718640b7408"}, + {file = "jiter-0.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69572ffb4e84ae289a7422b9af4ea123cae2ce0772228859b37d4b26b4bc92ea"}, + {file = "jiter-0.4.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba6046cbb5d1baa5a781b846f7e5438596a332f249a857d63f86ef5d1d9563b0"}, + {file = "jiter-0.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4f346e54602782e66d07df0d1c7389384fd93680052ed6170da2c6dc758409e"}, + {file = "jiter-0.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49110ce693f07e97d61089d894cea05a0b9894d5ccc6ac6fc583028726c8c8af"}, + {file = "jiter-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e358df6fd129f3a4e087539f086355ad0107e5da16dbc8bc857d94222eaeed5"}, + {file = "jiter-0.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7eb852ca39a48f3c049def56f0d1771b32e948e4f429a782d14ef4cc64cfd26e"}, + {file = "jiter-0.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:44dc045decb2545bffe2da04ea4c36d9438d3f3d49fc47ed423ea75c352b712e"}, + {file = "jiter-0.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:413adb15372ac63db04373240f40925788e4282c997eeafc2040530049a0a599"}, + {file = "jiter-0.4.0-cp310-none-win32.whl", hash = "sha256:0b48ea71673a97b897e4b94bbc871e62495a5a85f836c9f90712a4c70aa3ef7e"}, + {file = "jiter-0.4.0-cp310-none-win_amd64.whl", hash = "sha256:6a1c84b44afafaf0ba6223679cf17af664b889da14da31d8af3595fd977d96fa"}, + {file = "jiter-0.4.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b2cc498345fa37ca23fbc20271a553aa46e6eb00924600f49b7dc4b2aa8952ee"}, + {file = "jiter-0.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:69f7221ac09ab421abf04f89942026868297c568133998fb181bcf435760cbf3"}, + {file = "jiter-0.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef7d01c52f3e5a56ae73af36bd13797dd1a56711eb522748e5e84d15425b3f10"}, + {file = "jiter-0.4.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:39be97d5ce0c4d0dae28c23c03a0af0501a725589427e99763f99c42e18aa402"}, + {file = "jiter-0.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eac2ed1ec1e577b92b7ea2d4e6de8aec0c1164defd8af8affdc8ec0f0ec2904a"}, + {file = "jiter-0.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6258837d184c92c9cb91c983c310ad7269d41afb49d34f00ca9246e073943a03"}, + {file = "jiter-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123c2a77b066bf17a4d021e238e8351058cfa56b90ac04f2522d120dc64ea055"}, + {file = "jiter-0.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2df939f792c7a40e55f36700417db551b9f6b84d348990fa0f2c608adeb1f11b"}, + {file = "jiter-0.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cb1b09b16d40cf9ba1d11ba11e5b96ad29286a6a1c4ad5e6a2aef5e352a89f5d"}, + {file = "jiter-0.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0efb4208889ebdbf933bf08dbcbc16e64ffd34c8e2b28044ee142789a9dc3a67"}, + {file = "jiter-0.4.0-cp311-none-win32.whl", hash = "sha256:20545ac1b68e7e5b066a1e8347840c9cebdd02ace65faae2e655fc02ec5c915c"}, + {file = "jiter-0.4.0-cp311-none-win_amd64.whl", hash = "sha256:6b300f9887c8e4431cd03a974ea3e4f9958885636003c3864220a9b2d2f8462b"}, + {file = "jiter-0.4.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:923432a0563bbae404ff25bb010e348514a69bfab979f2f8119b23b625dbf6d9"}, + {file = "jiter-0.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab8bb0ec8b97cec4422dc8b37b525442d969244488c805b834609ab0ccd788e2"}, + {file = "jiter-0.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b857adb127b9c533907226791eafa79c5038c3eb5a477984994bf7c4715ba518"}, + {file = "jiter-0.4.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2609cc0d1d8d470e921ff9a604afeb4c701bbe13e00bd9834d5aa6e7ea732a9b"}, + {file = "jiter-0.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d39e99f8b7df46a119b6f84321f6ba01f16fa46abfa765d44c05c486d8e66829"}, + {file = "jiter-0.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:56de8b518ebfe76a70f856741f6de248ce396c50a87acef827b6e8388e3a502d"}, + {file = "jiter-0.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488b7e777be47f67ce1a1f8f8eb907f9bbd81af5c03784a9bab09d025c250233"}, + {file = "jiter-0.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ea35e0ecbb5dadd457855eb980dcc548c14cf5341bcd22a43814cb56f2bcc79"}, + {file = "jiter-0.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e1a9e9ee69c80b63951c93226b68d0e955953f64fe758bad2afe7ef7f9016af9"}, + {file = "jiter-0.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:78e2f3cc2a32a21d43ccc5afcf66f5d17e827ccc4e6d21c0b353bdad2c7dcc9c"}, + {file = "jiter-0.4.0-cp312-none-win32.whl", hash = "sha256:eeaa7a2b47a99f4ebbb4142bb58b95617e09f24c87570f6a57d2770687c9ddbe"}, + {file = "jiter-0.4.0-cp312-none-win_amd64.whl", hash = "sha256:8d4a78b385b93ff59a67215d26000fcb4789a388fca3730d1b60fab17fc81e3c"}, + {file = "jiter-0.4.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ebf20a3fac1089ce26963bf04140da0f803d55332ec69d59c5a87cf1a87d29c4"}, + {file = "jiter-0.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d62244ffc6a168187452277adeefb7b2c30170689c6bf543a51e98e8c17ddab7"}, + {file = "jiter-0.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40b2cde77446a41cec595739fd168be87edff2428eaf7c3438231224dd0ab7a5"}, + {file = "jiter-0.4.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e51fc0a22021ec8905b9b00a2f7d25756f2ff7a653e35a790a2067ae126b51f6"}, + {file = "jiter-0.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a56e6f980b89d7cfe5c43811dcf52d6f37b319428a4540511235dafda9ea7808"}, + {file = "jiter-0.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fec16adab8d3d3d6d74e3711a1f380836ebeab2a20e3f88cfe2ec5094d8b84"}, + {file = "jiter-0.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19e3de515801c954e8f1dc1f575282a4a86df9e782d4993ea1ed2be9a8dedaa0"}, + {file = "jiter-0.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17e0ad8abf0bb04d81810eaeaab35d2c99b5da11fcd1058e0a389607ff6503b0"}, + {file = "jiter-0.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8dc0132b728f3b3e90ff0d1874504cd49c78f3553bf3745168a7fc0b4cf674e1"}, + {file = "jiter-0.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81a883104aa96e494d3d28eaf7070780d03ecee8ccfdfaf7e4899710340c47f1"}, + {file = "jiter-0.4.0-cp38-none-win32.whl", hash = "sha256:a044c53ab1aaa4af624ac9574181b5bad8e260aea7e03104738156511433deba"}, + {file = "jiter-0.4.0-cp38-none-win_amd64.whl", hash = "sha256:d920035c869053e3d9a0b3ff94384d16a8ef5fde3dea55f97bd29916f6e27554"}, + {file = "jiter-0.4.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:091e978f4e586a2f1c69bf940d45f4e6a23455877172a0ab7d6de04a3b119299"}, + {file = "jiter-0.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79134b2d601309bcbe3304a262d7d228ad61d53c80883231c637773000a6d683"}, + {file = "jiter-0.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c471473e0b05058b5d729ff04271b6d45a575ac8bd9948563268c734b380ac7e"}, + {file = "jiter-0.4.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb84b8930da8b32b0b1fdff9817e2c4b47e8981b5647ad11c4975403416e4112"}, + {file = "jiter-0.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f2805e28941751ebfe0948596a64cde4cfb9b84bea5282affd020063e659c96"}, + {file = "jiter-0.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42ef59f9e513bf081a8b5c5578933ea9c3a63e559e6e3501a3e72edcd456ff5e"}, + {file = "jiter-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae12e3906f9e565120ab569de261b738e3a1ec50c40e30c67499e4f893e9a8c"}, + {file = "jiter-0.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:264dc1324f45a793bc89af4f653225229eb17bca9ec7107dce6c8fb4fe68d20f"}, + {file = "jiter-0.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9a1c172ec47d846e25881dfbd52438ddb690da4ea04d185e477abd3db6c32f8a"}, + {file = "jiter-0.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ccde31d0bc114aedad0dbd71b7f63ba0f0eecd7ec9ae1926a0ca01c1eb2854e7"}, + {file = "jiter-0.4.0-cp39-none-win32.whl", hash = "sha256:13139b05792fbc13a0f9a5b4c89823ea0874141decae1b8f693f12bb1d28e061"}, + {file = "jiter-0.4.0-cp39-none-win_amd64.whl", hash = "sha256:3a729b2631c6d5551a41069697415fee9659c3eadc9ab87369376ba51930cd00"}, + {file = "jiter-0.4.0.tar.gz", hash = "sha256:68203e02e0419bc3eca717c580c2d8f615aeee1150e2a1fb68d6600a7e52a37c"}, ] [[package]] @@ -3876,13 +3877,13 @@ files = [ [[package]] name = "jupyter-client" -version = "8.6.1" +version = "8.6.2" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, - {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, + {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, + {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, ] [package.dependencies] @@ -3894,7 +3895,7 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-core" @@ -4262,7 +4263,7 @@ types-requests = ">=2.31.0.2,<3.0.0.0" [[package]] name = "langflow-base" -version = "0.0.46" +version = "0.0.47" description = "A Python package with a built-in web application" optional = false python-versions = ">=3.10,<3.13" @@ -4341,13 +4342,13 @@ openai = ["openai (>=0.27.8)"] [[package]] name = "langsmith" -version = "0.1.60" +version = "0.1.62" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.60-py3-none-any.whl", hash = "sha256:3c3520ea473de0a984237b3e9d638fdf23ef3acc5aec89a42e693225e72d6120"}, - {file = "langsmith-0.1.60.tar.gz", hash = "sha256:6a145b5454437f9e0f81525f23c4dcdbb8c07b1c91553b8f697456c418d6a599"}, + {file = "langsmith-0.1.62-py3-none-any.whl", hash = "sha256:3a9f112643f64d736b8c875390c750fe6485804ea53aeae4edebce0afa4383a5"}, + {file = "langsmith-0.1.62.tar.gz", hash = "sha256:7ef894c14e6d4175fce88ec3bcd5a9c8cf9a456ea77e26e361f519ad082f34a8"}, ] [package.dependencies] @@ -4357,13 +4358,13 @@ requests = ">=2,<3" [[package]] name = "litellm" -version = "1.37.19" +version = "1.38.0" description = "Library to easily interface with LLM API providers" optional = false python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" files = [ - {file = "litellm-1.37.19-py3-none-any.whl", hash = "sha256:5a45b99d6c16a91ba66db6c69d1f406098dbca566be1c2256df5c21c3eb4e4e9"}, - {file = "litellm-1.37.19.tar.gz", hash = "sha256:9ec9260edaf16476dcff6d91a405364fb994200afa725ed46e7be7c3e54d4515"}, + {file = "litellm-1.38.0-py3-none-any.whl", hash = "sha256:bdb63f30999a664ca7361b9c9c7f0a8e3cc10678ddf252455955fd145a96eaa5"}, + {file = "litellm-1.38.0.tar.gz", hash = "sha256:1d77a8572cd9904369393fcdf24f6557e6b01ff9b04d346c2d69c04d23485716"}, ] [package.dependencies] @@ -4371,7 +4372,7 @@ aiohttp = "*" click = "*" importlib-metadata = ">=6.8.0" jinja2 = ">=3.1.2,<4.0.0" -openai = ">=1.0.0" +openai = ">=1.27.0" python-dotenv = ">=0.2.0" requests = ">=2.31.0,<3.0.0" tiktoken = ">=0.4.0" @@ -4405,19 +4406,19 @@ test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"] [[package]] name = "llama-index" -version = "0.10.37" +version = "0.10.38" description = "Interface between LLMs and your data" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index-0.10.37-py3-none-any.whl", hash = "sha256:da8871c5c8e5d038e56c0e5cb8c18a81ddc4117bf403bace95b4cec212f88fb9"}, - {file = "llama_index-0.10.37.tar.gz", hash = "sha256:d5057fd609e2423e75a4695242ab030d1647e4f07cb46faf9476ab504005f033"}, + {file = "llama_index-0.10.38-py3-none-any.whl", hash = "sha256:5d521b0ea7111679521292432960d3b9fb53c98d55414bd42d753bc6271d234d"}, + {file = "llama_index-0.10.38.tar.gz", hash = "sha256:5281cfa8b6e7f0f5f12897c00adcd790f7b51c130037f3561fd5630fca37bfb3"}, ] [package.dependencies] llama-index-agent-openai = ">=0.1.4,<0.3.0" llama-index-cli = ">=0.1.2,<0.2.0" -llama-index-core = ">=0.10.35,<0.11.0" +llama-index-core = ">=0.10.38,<0.11.0" llama-index-embeddings-openai = ">=0.1.5,<0.2.0" llama-index-indices-managed-llama-cloud = ">=0.1.2,<0.2.0" llama-index-legacy = ">=0.9.48,<0.10.0" @@ -4462,13 +4463,13 @@ llama-index-llms-openai = ">=0.1.1,<0.2.0" [[package]] name = "llama-index-core" -version = "0.10.36" +version = "0.10.38.post2" description = "Interface between LLMs and your data" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index_core-0.10.36-py3-none-any.whl", hash = "sha256:a6e8ea790e5b3656a254d9b47f8c00044dd46aae1cd43004c5d1303a7502b3e6"}, - {file = "llama_index_core-0.10.36.tar.gz", hash = "sha256:02f06bdefb5c6fd11dee1f65007a98decf3b266ad76136b7cfd3bec44efc5493"}, + {file = "llama_index_core-0.10.38.post2-py3-none-any.whl", hash = "sha256:b4b55449bac458d339e84d8d26f322b4dc9f36d3682ebb41fccf5594c295620f"}, + {file = "llama_index_core-0.10.38.post2.tar.gz", hash = "sha256:9eff6e16e9045deca9cb58bcf2a4b9ba39d0da12d7493e6aebaa5badd3b3ebb5"}, ] [package.dependencies] @@ -4496,14 +4497,6 @@ typing-extensions = ">=4.5.0" typing-inspect = ">=0.8.0" wrapt = "*" -[package.extras] -gradientai = ["gradientai (>=1.4.0)"] -html = ["beautifulsoup4 (>=4.12.2,<5.0.0)"] -langchain = ["langchain (>=0.0.303)"] -local-models = ["optimum[onnxruntime] (>=1.13.2,<2.0.0)", "sentencepiece (>=0.1.99,<0.2.0)", "transformers[torch] (>=4.33.1,<5.0.0)"] -postgres = ["asyncpg (>=0.29.0,<0.30.0)", "pgvector (>=0.2.4,<0.3.0)", "psycopg2-binary (>=2.9.9,<3.0.0)"] -query-tools = ["guidance (>=0.0.64,<0.0.65)", "jsonpath-ng (>=1.6.0,<2.0.0)", "lm-format-enforcer (>=0.4.3,<0.5.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "scikit-learn", "spacy (>=3.7.1,<4.0.0)"] - [[package]] name = "llama-index-embeddings-openai" version = "0.1.10" @@ -4699,13 +4692,13 @@ pydantic = ">=1.10" [[package]] name = "locust" -version = "2.27.0" -description = "Developer friendly load testing framework" +version = "2.28.0" +description = "Developer-friendly load testing framework" optional = false python-versions = ">=3.9" files = [ - {file = "locust-2.27.0-py3-none-any.whl", hash = "sha256:c4db5747eb9a3851216deae8147143d335db41978a9291ac32e113fa9ec8ad39"}, - {file = "locust-2.27.0.tar.gz", hash = "sha256:0c6d3d2523976dafe734012c41b2f7d9ad7120cbcea76d47d80cec5d6d139905"}, + {file = "locust-2.28.0-py3-none-any.whl", hash = "sha256:766be879db030c0118e7d9fca712f3538c4e628bdebf59468fa1c6c2fab217d3"}, + {file = "locust-2.28.0.tar.gz", hash = "sha256:260557eec866f7e34a767b6c916b5b278167562a280480aadb88f43d962fbdeb"}, ] [package.dependencies] @@ -4714,7 +4707,7 @@ flask = ">=2.0.0" Flask-Cors = ">=3.0.10" Flask-Login = ">=0.6.3" gevent = ">=22.10.2" -geventhttpclient = "2.2.1" +geventhttpclient = ">=2.3.1" msgpack = ">=1.0.0" psutil = ">=5.9.1" pywin32 = {version = "*", markers = "platform_system == \"Windows\""} @@ -4822,9 +4815,13 @@ files = [ {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, @@ -5824,13 +5821,13 @@ sympy = "*" [[package]] name = "openai" -version = "1.30.1" +version = "1.30.2" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.30.1-py3-none-any.whl", hash = "sha256:c9fb3c3545c118bbce8deb824397b9433a66d0d0ede6a96f7009c95b76de4a46"}, - {file = "openai-1.30.1.tar.gz", hash = "sha256:4f85190e577cba0b066e1950b8eb9b11d25bc7ebcc43a86b326ce1bfa564ec74"}, + {file = "openai-1.30.2-py3-none-any.whl", hash = "sha256:44316818fbff3845278e862a655c4c041e93d907b04eff64629c2835f29bd58e"}, + {file = "openai-1.30.2.tar.gz", hash = "sha256:f86780f40505de60fa389993d9b7f5564f20acfbe5efcabd5c853a12453af2b0"}, ] [package.dependencies] @@ -7234,15 +7231,18 @@ zstd = ["zstandard"] [[package]] name = "pyparsing" -version = "2.4.7" -description = "Python parsing module" +version = "3.1.2" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.6.8" files = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + [[package]] name = "pypdf" version = "4.2.0" @@ -8246,36 +8246,36 @@ tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc ( [[package]] name = "scipy" -version = "1.13.0" +version = "1.13.1" description = "Fundamental algorithms for scientific computing in Python" optional = true python-versions = ">=3.9" files = [ - {file = "scipy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d"}, - {file = "scipy-1.13.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4"}, - {file = "scipy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"}, - {file = "scipy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d"}, - {file = "scipy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c"}, - {file = "scipy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42"}, - {file = "scipy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820"}, - {file = "scipy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d"}, - {file = "scipy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86"}, - {file = "scipy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e"}, - {file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, ] [package.dependencies] @@ -8643,13 +8643,13 @@ typing = ["mypy (>=1.4)", "rich", "twisted"] [[package]] name = "supabase" -version = "2.4.5" +version = "2.4.6" description = "Supabase client for Python." optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "supabase-2.4.5-py3-none-any.whl", hash = "sha256:100441c36bf3390b040818c636c372a91645d18b6a9e0c12cea061fb00db664c"}, - {file = "supabase-2.4.5.tar.gz", hash = "sha256:8520b5a194c6d8fdbdd71b45aefc8b5a42d1a6711a2c693b6d299aeb785e8532"}, + {file = "supabase-2.4.6-py3-none-any.whl", hash = "sha256:0bfd6bb33c0e6d6891b55caaf689140f47588b01436fecc336d1d75090c70e8b"}, + {file = "supabase-2.4.6.tar.gz", hash = "sha256:442be0729f5fd9258326ba89859f60bfd8d9218283ed7fd8a62ae81e2f310474"}, ] [package.dependencies] @@ -9297,13 +9297,13 @@ types-pyOpenSSL = "*" [[package]] name = "types-requests" -version = "2.32.0.20240521" +version = "2.32.0.20240523" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.32.0.20240521.tar.gz", hash = "sha256:c5c4a0ae95aad51f1bf6dae9eed04a78f7f2575d4b171da37b622e08b93eb5d3"}, - {file = "types_requests-2.32.0.20240521-py3-none-any.whl", hash = "sha256:ab728ba43ffb073db31f21202ecb97db8753ded4a9dc49cb480d8a5350c5c421"}, + {file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"}, + {file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"}, ] [package.dependencies] @@ -9311,13 +9311,13 @@ urllib3 = ">=2" [[package]] name = "types-setuptools" -version = "69.5.0.20240519" +version = "70.0.0.20240523" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-69.5.0.20240519.tar.gz", hash = "sha256:275fb72048b0203d3fbef268298ea78a0913cd114a74872d93f8638ccc5b7c63"}, - {file = "types_setuptools-69.5.0.20240519-py3-none-any.whl", hash = "sha256:52b264eff8913b5d85848d83bd98efea935fc6129d681d370eb957783880b720"}, + {file = "types-setuptools-70.0.0.20240523.tar.gz", hash = "sha256:268c782f9d657bb0447a97bb9d50debd3a48721bb9d1d8194548d4835798beac"}, + {file = "types_setuptools-70.0.0.20240523-py3-none-any.whl", hash = "sha256:1828c1e2bc93cdb371fd0955fa51e27c3143490fe40a650db3fca22ea44233b3"}, ] [[package]] @@ -10208,46 +10208,48 @@ test = ["zope.testrunner"] [[package]] name = "zope-interface" -version = "6.4" +version = "6.4.post1" description = "Interfaces for Python" optional = false python-versions = ">=3.7" files = [ - {file = "zope.interface-6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72faa868fcfde49a29d287dce3c83180322467eecd725dd351098efe96e8d4bb"}, - {file = "zope.interface-6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:855b7233fa5d0d1f3be8c14fadf4718dee1c928e1d75f1584bea6ecec6dcc4af"}, - {file = "zope.interface-6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ee6e507a9fd4f1f0aab8e8dfc801d162e7211c27503cbfb47e1d558941a7fa"}, - {file = "zope.interface-6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:604fa920478dfc0c76cdb7c203572400a8317ffcdac288245c408b42b3d9aee9"}, - {file = "zope.interface-6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04bd4ee4766d285e83c6d8c042663a98efb934389e05ccd643fefb066c88a9d"}, - {file = "zope.interface-6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4782e173c2fde4f649c2a9a68082445bc1f2c27f41907de06bf1ba82585847f2"}, - {file = "zope.interface-6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:646cd83d24065d074f22f61fe101d20dbf4b729ca7831cc782ec986eb9156f93"}, - {file = "zope.interface-6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f61ccbc26e08031d0e72b6a0cbf9b4030f035913cb2b39f940aa42eb8e0063"}, - {file = "zope.interface-6.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:414e6dccdf4a5c96c0c98da68ba040dbf9ba7511b61b34e228f11b0ed90c439d"}, - {file = "zope.interface-6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5092f2712e1fd07579fc3101b18e9c95857c853e836847598bf992c8e672434"}, - {file = "zope.interface-6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21732994aa3ca43bbb6b36335c288023428a3c5b7322b637c7b0a03053937578"}, - {file = "zope.interface-6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe636b49c333bfc5b0913590e36a2f151167c462fb36d9f4acc66029e45c974b"}, - {file = "zope.interface-6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57f34b7997f8de7d2db08363eaccd05dad20f106e39efe95bed4fac84af2d022"}, - {file = "zope.interface-6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6494dc0314e782ce4fb0e624b4ce2458f54d074382f50a920c7700c05cbcef28"}, - {file = "zope.interface-6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cda82ab32f984985f09e4ec20a4f9665b26779a1b8e443b34a148de256f2052"}, - {file = "zope.interface-6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f78e1eac48c4f4e0168a91cabcd8d1aedb972836df5c8769071fc6173294a0a3"}, - {file = "zope.interface-6.4-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:8e246357f52952ae5fa950d19eda8572594c49e6cb1e5462508e6cec561a37de"}, - {file = "zope.interface-6.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93f28d84517dcd6c240979bd9b2f262a373832baef856fe663a24b9171d7f04d"}, - {file = "zope.interface-6.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cd56eb9a23767958c9a0654306b9a4a74def485f645b3a7378cc6ab661ef31c"}, - {file = "zope.interface-6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:502d2c9c4231d022b20225dba5c6c736236ed65e1d7e2f6f402b5aa6a7040ec9"}, - {file = "zope.interface-6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ee1e3ca6c98efe213a96dece89100a8aa52e210ac354861d8039d69bd1d6e5ff"}, - {file = "zope.interface-6.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62e6b756663deade5270f67899753437b39d970f9eecd49e19fae3b880310cf0"}, - {file = "zope.interface-6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f33af86ed460eb28dc9da1de1f3305795271a19c665161c1d973a737596b2081"}, - {file = "zope.interface-6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86e85eada0eb551950df05d72dc0e892320f14daa78bc434059e834d4b1f9300"}, - {file = "zope.interface-6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3945f4fda92c1b6fb0cb6eaaaf72599e5c2c2059654bdc42bc09c6e711c214c8"}, - {file = "zope.interface-6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbbb290751f5c4ed81e54ae73fe8557c4a85973f5ab019edbb0f746244ecea6"}, - {file = "zope.interface-6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4cc017206c1429a6d8fdd8a25c6efc15512065eec0a8d45c350df96a0911ed"}, - {file = "zope_interface-6.4.tar.gz", hash = "sha256:b11f2b67ccc990a1522fa8cd3f5d185a068459f944ab2d0e7a1b15d31bcb4af4"}, + {file = "zope.interface-6.4.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:16f73c42f10f761051157332943ee1f7cf973cc1c78a50d1960c313a211cca4a"}, + {file = "zope.interface-6.4.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ca89624d0eabc7ce4f299c6d621531cb8b0ebac3bb4f9ebf2d057477602e1b8"}, + {file = "zope.interface-6.4.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6eaa0b7df493904d24050dcdc3db6589bd94f7e49caab57971fe47a669b3ea"}, + {file = "zope.interface-6.4.post1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a45a7990d143acc37faa905d4a528f5923a5dd30f46536977d8061d10a895b09"}, + {file = "zope.interface-6.4.post1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcefd4012593ee410ebf5728ee98f61b3401f0563c5068e760aa2b7720ca68a0"}, + {file = "zope.interface-6.4.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:36234d3b8211d053c42684666c2a04eb1a35e0cec6bc3e54586bb60fb0be3b17"}, + {file = "zope.interface-6.4.post1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c18218451823ca9b5131ceaacf655fe9dd4e592ebf848cb0a65fe8428bbf604"}, + {file = "zope.interface-6.4.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:563a7192a5baf8d9b189dc598c3555e695e00fdce3eafb88b30d6d3df986fcc5"}, + {file = "zope.interface-6.4.post1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd3ab863a4e7d888728c949ba052a649664dea156bdd7140eb9269bbe6e33205"}, + {file = "zope.interface-6.4.post1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52901ff6d75a4332457610cbd2883f39b386c5bebe0745ecf78e3fe22cfdd0d9"}, + {file = "zope.interface-6.4.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:799743a342249c9b9529abd1115a3f81754800e75dea254b58efdd2984009798"}, + {file = "zope.interface-6.4.post1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:15fa208d7a802c0dd3e9d4d5336619a37efd57f2d2ce830d9f9d5843a2b7daba"}, + {file = "zope.interface-6.4.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91698257850ca5f523a5513a69775e6fb7c18129311e118996f8e9b463d11b0"}, + {file = "zope.interface-6.4.post1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45fb6fe8b5852564e63d6705a7904530a7c886056e6e9aaf938dc5e2bc637097"}, + {file = "zope.interface-6.4.post1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec57dec41c0c8b723dd70da1864d50908c689e1c9cf43f32e9b04c0992e5d93d"}, + {file = "zope.interface-6.4.post1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6c1dad571276768fd6bc92999e8d942151552662a9048e3384cac05b148985"}, + {file = "zope.interface-6.4.post1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaa1f8967c3f272de80c4bec4b1379f97cd29006323f50558bd2f780a4f637ef"}, + {file = "zope.interface-6.4.post1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8140cf2665c5a07adc285bc859fdda67cfbd7edd62480dfca2211f4798502b54"}, + {file = "zope.interface-6.4.post1-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:18f4061c3456c61557e9d7068e435f5db164b38f15f3d9bd995ff185c6db2c62"}, + {file = "zope.interface-6.4.post1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a430d2cc52aef2af0dc45866852730fbc93463cf8cdeb179e8ee04440e0955c4"}, + {file = "zope.interface-6.4.post1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:065f8ff0e034e43b8da05ffed308a9e3311720a2b13b83724f26a8dd6709964d"}, + {file = "zope.interface-6.4.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0940b3b44b6cc0375ea0da5fefee05a9abe8bb53594a3a6e4aafb9f99dc5de8d"}, + {file = "zope.interface-6.4.post1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d200aef16e577682dd54a79ff5f4f897a9807722b54bd8a9bca404679c609d"}, + {file = "zope.interface-6.4.post1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e0678885d07e865047e15be3ebe5c87903cc7f5ca5edfd0045d1c7b43f7fe9d"}, + {file = "zope.interface-6.4.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bf9fa875a9bae5318f24b0d9ab9e2c8a23bccad2979e9e4305eed8119bbe3195"}, + {file = "zope.interface-6.4.post1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68b13ac49becfaba5b77359559812daac0c5c4b3c0d43cdb293a2dec8db95c24"}, + {file = "zope.interface-6.4.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a00983c5c793b17b829020e11032dabab023c4e0ef12f134b90df802ae5adf2"}, + {file = "zope.interface-6.4.post1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ada5ac54ac7d34bb33423da40b7f3edfc54c6b9623ac9daac7f456dbf25173ba"}, + {file = "zope.interface-6.4.post1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297ee171f40f8f18665bb75f576df7d1ddce19f3e6696ef6acb930dcbfbf693f"}, + {file = "zope.interface-6.4.post1.tar.gz", hash = "sha256:e9961413091e3c9d5c3ed671757049cc6153280f39a154a0b633608efcfdec6b"}, ] [package.dependencies] setuptools = "*" [package.extras] -docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx-rtd-theme"] +docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx_rtd_theme"] test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] @@ -10258,5 +10260,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "c68a14e273363466c1cea2bacec1798a6894d2bb18cf79ba443dc65c9344c57d" - +content-hash = "9406313d19280623987bf2ee831626bc79ec0abf0ec1fe547df89bc9b1b93b0d" diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py index 6a38f4981..3e148f259 100644 --- a/src/backend/base/langflow/api/v1/chat.py +++ b/src/backend/base/langflow/api/v1/chat.py @@ -78,13 +78,13 @@ async def retrieve_vertices_order( HTTPException: If there is an error checking the build status. """ try: - flow_id = str(flow_id) + flow_id_str = str(flow_id) # First, we need to check if the flow_id is in the cache if not data: - graph = await build_and_cache_graph_from_db(flow_id=flow_id, session=session, chat_service=chat_service) + graph = await build_and_cache_graph_from_db(flow_id=flow_id_str, session=session, chat_service=chat_service) else: graph = await build_and_cache_graph_from_data( - flow_id=flow_id, graph_data=data.model_dump(), chat_service=chat_service + flow_id=flow_id_str, graph_data=data.model_dump(), chat_service=chat_service ) graph.validate_stream() if stop_component_id or start_component_id: @@ -144,26 +144,26 @@ async def build_vertex( HTTPException: If there is an error building the vertex. """ - flow_id = str(flow_id) + flow_id_str = str(flow_id) next_runnable_vertices = [] top_level_vertices = [] try: start_time = time.perf_counter() - cache = await chat_service.get_cache(flow_id) + cache = await chat_service.get_cache(flow_id_str) if not cache: # If there's no cache - logger.warning(f"No cache found for {flow_id}. Building graph starting at {vertex_id}") + logger.warning(f"No cache found for {flow_id_str}. Building graph starting at {vertex_id}") graph = await build_and_cache_graph_from_db( - flow_id=flow_id, session=next(get_session()), chat_service=chat_service + flow_id=flow_id_str, session=next(get_session()), chat_service=chat_service ) else: graph = cache.get("result") ResultDataResponse(results={}) vertex = graph.get_vertex(vertex_id) try: - lock = chat_service._cache_locks[flow_id] - set_cache_coro = partial(chat_service.set_cache, flow_id=flow_id) + lock = chat_service._cache_locks[flow_id_str] + set_cache_coro = partial(chat_service.set_cache, flow_id=flow_id_str) ( next_runnable_vertices, top_level_vertices, @@ -189,13 +189,13 @@ async def build_vertex( artifacts = {} # If there's an error building the vertex # we need to clear the cache - await chat_service.clear_cache(flow_id) + await chat_service.clear_cache(flow_id_str) # Log the vertex build if not vertex.will_stream: background_tasks.add_task( log_vertex_build, - flow_id=flow_id, + flow_id=flow_id_str, vertex_id=vertex_id, valid=valid, params=params, @@ -212,7 +212,7 @@ async def build_vertex( inactivated_vertices = list(graph.inactivated_vertices) graph.reset_inactivated_vertices() graph.reset_activated_vertices() - await chat_service.set_cache(flow_id, graph) + await chat_service.set_cache(flow_id_str, graph) # graph.stop_vertex tells us if the user asked # to stop the build of the graph at a certain vertex @@ -272,22 +272,22 @@ async def build_vertex_stream( HTTPException: If an error occurs while building the vertex. """ try: - flow_id = str(flow_id) + flow_id_str = str(flow_id) async def stream_vertex(): try: if not session_id: - cache = await chat_service.get_cache(flow_id) + cache = await chat_service.get_cache(flow_id_str) if not cache: # If there's no cache - raise ValueError(f"No cache found for {flow_id}.") + raise ValueError(f"No cache found for {flow_id_str}.") else: graph = cache.get("result") else: - session_data = await session_service.load_session(session_id, flow_id=flow_id) + session_data = await session_service.load_session(session_id, flow_id=flow_id_str) graph, artifacts = session_data if session_data else (None, None) if not graph: - raise ValueError(f"No graph found for {flow_id}.") + raise ValueError(f"No graph found for {flow_id_str}.") vertex: "InterfaceVertex" = graph.get_vertex(vertex_id) if not hasattr(vertex, "stream"): diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py index b84fff034..0b6178f29 100644 --- a/src/backend/base/langflow/api/v1/endpoints.py +++ b/src/backend/base/langflow/api/v1/endpoints.py @@ -5,7 +5,7 @@ from uuid import UUID import sqlalchemy as sa from fastapi import APIRouter, Body, Depends, HTTPException, UploadFile, status from loguru import logger -from sqlmodel import Session, col, select +from sqlmodel import Session, select from langflow.api.utils import update_frontend_node_with_template_values from langflow.api.v1.schemas import ( @@ -21,7 +21,6 @@ from langflow.api.v1.schemas import ( from langflow.graph.graph.base import Graph from langflow.graph.schema import RunOutputs from langflow.interface.custom.custom_component import CustomComponent -from langflow.interface.custom.directory_reader import DirectoryReader from langflow.interface.custom.utils import build_custom_component_template from langflow.processing.process import process_tweaks, run_graph_internal from langflow.schema.graph import Tweaks @@ -112,27 +111,27 @@ async def simplified_run_flow( session_id = input_request.session_id try: - flow_id = str(flow_id) + flow_id_str = str(flow_id) task_result: List[RunOutputs] = [] artifacts = {} if input_request.session_id: - session_data = await session_service.load_session(input_request.session_id, flow_id=flow_id) + session_data = await session_service.load_session(input_request.session_id, flow_id=flow_id_str) graph, artifacts = session_data if session_data else (None, None) if graph is None: raise ValueError(f"Session {input_request.session_id} not found") else: # Get the flow that matches the flow_id and belongs to the user # flow = session.query(Flow).filter(Flow.id == flow_id).filter(Flow.user_id == api_key_user.id).first() - flow = db.exec(select(Flow).where(Flow.id == flow_id).where(Flow.user_id == api_key_user.id)).first() + flow = db.exec(select(Flow).where(Flow.id == flow_id_str).where(Flow.user_id == api_key_user.id)).first() if flow is None: - raise ValueError(f"Flow {flow_id} not found") + raise ValueError(f"Flow {flow_id_str} not found") if flow.data is None: - raise ValueError(f"Flow {flow_id} has no data") + raise ValueError(f"Flow {flow_id_str} has no data") graph_data = flow.data graph_data = process_tweaks(graph_data, input_request.tweaks or {}, stream=stream) - graph = Graph.from_payload(graph_data, flow_id=flow_id, user_id=str(api_key_user.id)) + graph = Graph.from_payload(graph_data, flow_id=flow_id_str, user_id=str(api_key_user.id)) inputs = [ InputValueRequest(components=[], input_value=input_request.input_value, type=input_request.input_type) ] @@ -155,7 +154,7 @@ async def simplified_run_flow( ] task_result, session_id = await run_graph_internal( graph=graph, - flow_id=flow_id, + flow_id=flow_id_str, session_id=input_request.session_id, inputs=inputs, outputs=outputs, @@ -168,12 +167,12 @@ async def simplified_run_flow( except sa.exc.StatementError as exc: # StatementError('(builtins.ValueError) badly formed hexadecimal UUID string') if "badly formed hexadecimal UUID string" in str(exc): - logger.error(f"Flow ID {flow_id} is not a valid UUID") + logger.error(f"Flow ID {flow_id_str} is not a valid UUID") # This means the Flow ID is not a valid UUID which means it can't find the flow raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc except ValueError as exc: - if f"Flow {flow_id} not found" in str(exc): - logger.error(f"Flow {flow_id} not found") + if f"Flow {flow_id_str} not found" in str(exc): + logger.error(f"Flow {flow_id_str} not found") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc elif f"Session {session_id} not found" in str(exc): logger.error(f"Session {session_id} not found") @@ -237,32 +236,34 @@ async def experimental_run_flow( This endpoint facilitates complex flow executions with customized inputs, outputs, and configurations, catering to diverse application requirements. """ try: - flow_id = str(flow_id) + flow_id_str = str(flow_id) if outputs is None: outputs = [] task_result: List[RunOutputs] = [] artifacts = {} if session_id: - session_data = await session_service.load_session(session_id, flow_id=flow_id) + session_data = await session_service.load_session(session_id, flow_id=flow_id_str) graph, artifacts = session_data if session_data else (None, None) if graph is None: raise ValueError(f"Session {session_id} not found") else: # Get the flow that matches the flow_id and belongs to the user # flow = session.query(Flow).filter(Flow.id == flow_id).filter(Flow.user_id == api_key_user.id).first() - flow = session.exec(select(Flow).where(Flow.id == flow_id).where(Flow.user_id == api_key_user.id)).first() + flow = session.exec( + select(Flow).where(Flow.id == flow_id_str).where(Flow.user_id == api_key_user.id) + ).first() if flow is None: - raise ValueError(f"Flow {flow_id} not found") + raise ValueError(f"Flow {flow_id_str} not found") if flow.data is None: - raise ValueError(f"Flow {flow_id} has no data") + raise ValueError(f"Flow {flow_id_str} has no data") graph_data = flow.data graph_data = process_tweaks(graph_data, tweaks or {}) - graph = Graph.from_payload(graph_data, flow_id=flow_id) + graph = Graph.from_payload(graph_data, flow_id=flow_id_str) task_result, session_id = await run_graph_internal( graph=graph, - flow_id=flow_id, + flow_id=flow_id_str, session_id=session_id, inputs=inputs, outputs=outputs, @@ -275,12 +276,12 @@ async def experimental_run_flow( except sa.exc.StatementError as exc: # StatementError('(builtins.ValueError) badly formed hexadecimal UUID string') if "badly formed hexadecimal UUID string" in str(exc): - logger.error(f"Flow ID {flow_id} is not a valid UUID") + logger.error(f"Flow ID {flow_id_str} is not a valid UUID") # This means the Flow ID is not a valid UUID which means it can't find the flow raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc except ValueError as exc: - if f"Flow {flow_id} not found" in str(exc): - logger.error(f"Flow {flow_id} not found") + if f"Flow {flow_id_str} not found" in str(exc): + logger.error(f"Flow {flow_id_str} not found") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc elif f"Session {session_id} not found" in str(exc): logger.error(f"Session {session_id} not found") @@ -363,11 +364,11 @@ async def create_upload_file( flow_id: UUID, ): try: - flow_id = str(flow_id) - file_path = save_uploaded_file(file, folder_name=flow_id) + flow_id_str = str(flow_id) + file_path = save_uploaded_file(file, folder_name=flow_id_str) return UploadFileResponse( - flowId=flow_id, + flowId=flow_id_str, file_path=file_path, ) except Exception as exc: diff --git a/src/backend/base/langflow/api/v1/files.py b/src/backend/base/langflow/api/v1/files.py index 762d39da9..bbe97f81a 100644 --- a/src/backend/base/langflow/api/v1/files.py +++ b/src/backend/base/langflow/api/v1/files.py @@ -25,14 +25,14 @@ def get_flow_id( current_user=Depends(get_current_active_user), session=Depends(get_session), ): - flow_id = str(flow_id) + flow_id_str = str(flow_id) # AttributeError: 'SelectOfScalar' object has no attribute 'first' - flow = session.get(Flow, flow_id) + flow = session.get(Flow, flow_id_str) if not flow: raise HTTPException(status_code=404, detail="Flow not found") if flow.user_id != current_user.id: raise HTTPException(status_code=403, detail="You don't have access to this flow") - return flow_id + return flow_id_str @router.post("/upload/{flow_id}", status_code=HTTPStatus.CREATED) @@ -42,12 +42,12 @@ async def upload_file( storage_service: StorageService = Depends(get_storage_service), ): try: - flow_id = str(flow_id) + flow_id_str = str(flow_id) file_content = await file.read() file_name = file.filename or hashlib.sha256(file_content).hexdigest() - folder = flow_id + folder = flow_id_str await storage_service.save_file(flow_id=folder, file_name=file_name, data=file_content) - return UploadFileResponse(flowId=flow_id, file_path=f"{folder}/{file_name}") + return UploadFileResponse(flowId=flow_id_str, file_path=f"{folder}/{file_name}") except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @@ -55,7 +55,7 @@ async def upload_file( @router.get("/download/{flow_id}/{file_name}") async def download_file(file_name: str, flow_id: UUID, storage_service: StorageService = Depends(get_storage_service)): try: - flow_id = str(flow_id) + flow_id_str = str(flow_id) extension = file_name.split(".")[-1] if not extension: @@ -66,7 +66,7 @@ async def download_file(file_name: str, flow_id: UUID, storage_service: StorageS if not content_type: raise HTTPException(status_code=500, detail=f"Content type not found for extension {extension}") - file_content = await storage_service.get_file(flow_id=flow_id, file_name=file_name) + file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name) headers = { "Content-Disposition": f"attachment; filename={file_name} filename*=UTF-8''{file_name}", "Content-Type": "application/octet-stream", @@ -81,7 +81,7 @@ async def download_file(file_name: str, flow_id: UUID, storage_service: StorageS async def download_image(file_name: str, flow_id: UUID, storage_service: StorageService = Depends(get_storage_service)): try: extension = file_name.split(".")[-1] - flow_id = str(flow_id) + flow_id_str = str(flow_id) if not extension: raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}") @@ -93,7 +93,7 @@ async def download_image(file_name: str, flow_id: UUID, storage_service: Storage elif not content_type.startswith("image"): raise HTTPException(status_code=500, detail=f"Content type {content_type} is not an image") - file_content = await storage_service.get_file(flow_id=flow_id, file_name=file_name) + file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name) return StreamingResponse(BytesIO(file_content), media_type=content_type) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @@ -104,8 +104,8 @@ async def list_files( flow_id: UUID = Depends(get_flow_id), storage_service: StorageService = Depends(get_storage_service) ): try: - flow_id = str(flow_id) - files = await storage_service.list_files(flow_id=flow_id) + flow_id_str = str(flow_id) + files = await storage_service.list_files(flow_id=flow_id_str) return {"files": files} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @@ -116,8 +116,8 @@ async def delete_file( file_name: str, flow_id: UUID = Depends(get_flow_id), storage_service: StorageService = Depends(get_storage_service) ): try: - flow_id = str(flow_id) - await storage_service.delete_file(flow_id=flow_id, file_name=file_name) + flow_id_str = str(flow_id) + await storage_service.delete_file(flow_id=flow_id_str, file_name=file_name) return {"message": f"File {file_name} deleted successfully"} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/api/v1/flows.py b/src/backend/base/langflow/api/v1/flows.py index 2b8e4ee37..7fe7c516b 100644 --- a/src/backend/base/langflow/api/v1/flows.py +++ b/src/backend/base/langflow/api/v1/flows.py @@ -2,7 +2,6 @@ from datetime import datetime, timezone from typing import List from uuid import UUID -from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME import orjson from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from fastapi.encoders import jsonable_encoder @@ -14,6 +13,7 @@ from langflow.api.v1.schemas import FlowListCreate, FlowListIds, FlowListRead from langflow.initial_setup.setup import STARTER_FOLDER_NAME from langflow.services.auth.utils import get_current_active_user from langflow.services.database.models.flow import Flow, FlowCreate, FlowRead, FlowUpdate +from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME from langflow.services.database.models.folder.model import Folder from langflow.services.database.models.user.model import User from langflow.services.deps import get_session, get_settings_service @@ -71,12 +71,9 @@ def read_flows( flow_ids = [flow.id for flow in flows] # with the session get the flows that DO NOT have a user_id try: - example_flows = session.exec( - select(Flow).where( - Flow.user_id == None, # noqa - Flow.folder.has(Folder.name == STARTER_FOLDER_NAME), - ) - ).all() + folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first() + + example_flows = folder.flows if folder else [] for example_flow in example_flows: if example_flow.id not in flow_ids: flows.append(example_flow) # type: ignore diff --git a/src/backend/base/langflow/api/v1/folders.py b/src/backend/base/langflow/api/v1/folders.py index 9e598b1ea..96729133b 100644 --- a/src/backend/base/langflow/api/v1/folders.py +++ b/src/backend/base/langflow/api/v1/folders.py @@ -1,17 +1,17 @@ from typing import List from uuid import UUID -from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status -from langflow.api.v1.flows import create_flows -from langflow.api.v1.schemas import FlowListCreate, FlowListReadWithFolderName -from langflow.initial_setup.setup import STARTER_FOLDER_NAME -from langflow.services.database.models.flow.model import Flow, FlowCreate, FlowRead -from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME import orjson +from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status from sqlalchemy import update from sqlmodel import Session, select +from langflow.api.v1.flows import create_flows +from langflow.api.v1.schemas import FlowListCreate, FlowListReadWithFolderName +from langflow.initial_setup.setup import STARTER_FOLDER_NAME from langflow.services.auth.utils import get_current_active_user +from langflow.services.database.models.flow.model import Flow, FlowCreate, FlowRead +from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME from langflow.services.database.models.folder.model import ( Folder, FolderCreate, @@ -39,16 +39,16 @@ def create_folder( session.commit() session.refresh(new_folder) - if folder.components_list.__len__() > 0: + if folder.components_list: update_statement_components = ( - update(Flow).where(Flow.id.in_(folder.components_list)).values(folder_id=new_folder.id) + update(Flow).where(Flow.id.in_(folder.components_list)).values(folder_id=new_folder.id) # type: ignore ) - session.exec(update_statement_components) + session.exec(update_statement_components) # type: ignore session.commit() - if folder.flows_list.__len__() > 0: - update_statement_flows = update(Flow).where(Flow.id.in_(folder.flows_list)).values(folder_id=new_folder.id) - session.exec(update_statement_flows) + if folder.flows_list: + update_statement_flows = update(Flow).where(Flow.id.in_(folder.flows_list)).values(folder_id=new_folder.id) # type: ignore + session.exec(update_statement_flows) # type: ignore session.commit() return new_folder @@ -89,7 +89,6 @@ def read_folder( folder = session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first() if not folder: raise HTTPException(status_code=404, detail="Folder not found") - folder.flows = session.exec(select(Flow).where(Flow.folder_id == folder_id)).all() return folder except Exception as e: if "No result found" in str(e): @@ -128,16 +127,16 @@ def update_folder( my_collection_folder = session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME)).first() if my_collection_folder: update_statement_my_collection = ( - update(Flow).where(Flow.id.in_(excluded_flows)).values(folder_id=my_collection_folder.id) + update(Flow).where(Flow.id.in_(excluded_flows)).values(folder_id=my_collection_folder.id) # type: ignore ) - session.exec(update_statement_my_collection) + session.exec(update_statement_my_collection) # type: ignore session.commit() - if concat_folder_components.__len__() > 0: + if concat_folder_components: update_statement_components = ( - update(Flow).where(Flow.id.in_(concat_folder_components)).values(folder_id=existing_folder.id) + update(Flow).where(Flow.id.in_(concat_folder_components)).values(folder_id=existing_folder.id) # type: ignore ) - session.exec(update_statement_components) + session.exec(update_statement_components) # type: ignore session.commit() return existing_folder @@ -177,20 +176,8 @@ async def download_file( ): """Download all flows from folder.""" try: - flows = session.exec( - select(Flow).distinct().join(Folder).where(Flow.folder_id == folder_id, Folder.user_id == current_user.id) - ).all() - folder_name = ( - session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first().name - ) - folder_description = ( - session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)) - .first() - .description - ) - if not flows: - flows = [] - return FlowListReadWithFolderName(flows=flows, folder_name=folder_name, folder_description=folder_description) + folder = session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first() + return folder except Exception as e: if "No result found" in str(e): raise HTTPException(status_code=404, detail="Folder not found") @@ -208,16 +195,19 @@ async def upload_file( contents = await file.read() data = orjson.loads(contents) - if data.__len__() == 0: + if not data: raise HTTPException(status_code=400, detail="No flows found in the file") folder_results = session.exec( - select(Folder).where(Folder.name.like(f"{data['folder_name']}%"), Folder.user_id == current_user.id) + select(Folder).where( + Folder.name == data["folder_name"], + Folder.user_id == current_user.id, + ) ) existing_folder_names = [folder.name for folder in folder_results] - if existing_folder_names.__len__() > 0: - data["folder_name"] = f"{data['folder_name']} ({existing_folder_names.__len__() + 1})" + if existing_folder_names: + data["folder_name"] = f"{data['folder_name']} ({len(existing_folder_names) + 1})" folder = FolderCreate(name=data["folder_name"], description=data["folder_description"]) diff --git a/src/backend/base/langflow/api/v1/schemas.py b/src/backend/base/langflow/api/v1/schemas.py index 1d93cc0e2..2b9eff312 100644 --- a/src/backend/base/langflow/api/v1/schemas.py +++ b/src/backend/base/langflow/api/v1/schemas.py @@ -149,8 +149,8 @@ class FlowListRead(BaseModel): class FlowListReadWithFolderName(BaseModel): flows: List[FlowRead] - folder_name: str - folder_description: str + name: str + description: str class InitResponse(BaseModel): diff --git a/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py b/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py index 032704d9c..bda2579f6 100644 --- a/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py +++ b/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py @@ -12,6 +12,7 @@ from langchain_openai import ChatOpenAI from langflow.field_typing.range_spec import RangeSpec from langflow.interface.custom.custom_component import CustomComponent +from pydantic.v1 import SecretStr class ConversationalAgent(CustomComponent): @@ -57,9 +58,14 @@ class ConversationalAgent(CustomComponent): max_token_limit: int = 2000, temperature: float = 0.9, ) -> AgentExecutor: + if openai_api_key: + api_key = SecretStr(openai_api_key) + else: + api_key = None + llm = ChatOpenAI( model=model_name, - api_key=openai_api_key, + api_key=api_key, base_url=openai_api_base, max_tokens=max_token_limit, temperature=temperature, diff --git a/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py b/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py index d6560580b..75f893582 100644 --- a/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py @@ -1,6 +1,8 @@ from typing import Optional from langchain_openai import ChatOpenAI +from pydantic.v1 import SecretStr + from langflow.base.models.openai_constants import MODEL_NAMES from langflow.field_typing import BaseLanguageModel, NestedDict @@ -59,11 +61,15 @@ class ChatOpenAIComponent(CustomComponent): ) -> BaseLanguageModel: if not openai_api_base: openai_api_base = "https://api.openai.com/v1" + if openai_api_key: + api_key = SecretStr(openai_api_key) + else: + api_key = None return ChatOpenAI( max_tokens=max_tokens, model_kwargs=model_kwargs, model=model_name, base_url=openai_api_base, - api_key=openai_api_key, + api_key=api_key, temperature=temperature, ) diff --git a/src/backend/base/langflow/components/outputs/RecordsOutput.py b/src/backend/base/langflow/components/outputs/RecordsOutput.py index bdd8a85e2..25eae862e 100644 --- a/src/backend/base/langflow/components/outputs/RecordsOutput.py +++ b/src/backend/base/langflow/components/outputs/RecordsOutput.py @@ -1,8 +1,8 @@ -from langflow.base.io.text import TextComponent +from langflow.custom import CustomComponent from langflow.schema import Record -class RecordsOutput(TextComponent): +class RecordsOutput(CustomComponent): display_name = "Records Output" description = "Display Records as a Table" diff --git a/src/backend/base/langflow/graph/edge/base.py b/src/backend/base/langflow/graph/edge/base.py index dad8469c0..1fc2ef344 100644 --- a/src/backend/base/langflow/graph/edge/base.py +++ b/src/backend/base/langflow/graph/edge/base.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, Any, List, Optional from loguru import logger from pydantic import BaseModel, Field -from langflow.graph.vertex.utils import log_transaction from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.monitor.utils import log_message @@ -142,7 +141,6 @@ class ContractEdge(Edge): if not self.is_fulfilled: await self.honor(source, target) - log_transaction(self, source, target, "success") # If the target vertex is a power component we log messages if target.vertex_type == "ChatOutput" and ( isinstance(target.params.get(INPUT_FIELD_NAME), str) diff --git a/src/backend/base/langflow/services/database/models/folder/model.py b/src/backend/base/langflow/services/database/models/folder/model.py index a7a1c51d0..6ce038c63 100644 --- a/src/backend/base/langflow/services/database/models/folder/model.py +++ b/src/backend/base/langflow/services/database/models/folder/model.py @@ -51,5 +51,5 @@ class FolderUpdate(SQLModel): name: Optional[str] = None description: Optional[str] = None parent_id: Optional[UUID] = None - components: Optional[List[UUID]] = None - flows: Optional[List[UUID]] = None + components: List[UUID] = Field(default_factory=list) + flows: List[UUID] = Field(default_factory=list) diff --git a/src/backend/base/langflow/services/database/models/folder/utils.py b/src/backend/base/langflow/services/database/models/folder/utils.py index 19f70819f..446efb029 100644 --- a/src/backend/base/langflow/services/database/models/folder/utils.py +++ b/src/backend/base/langflow/services/database/models/folder/utils.py @@ -1,26 +1,33 @@ from typing import TYPE_CHECKING from uuid import UUID +from sqlmodel import Session, and_, select, update + from langflow.services.database.models.flow.model import Flow -from sqlmodel import Session, select, update from .constants import DEFAULT_FOLDER_DESCRIPTION, DEFAULT_FOLDER_NAME from .model import Folder if TYPE_CHECKING: - from langflow.services.database.models.user.model import User + pass def create_default_folder_if_it_doesnt_exist(session: Session, user_id: UUID): - if not session.exec(select(Folder).where(Folder.user_id == user_id)).first(): + folder = session.exec(select(Folder).where(Folder.user_id == user_id)).first() + if not folder: folder = Folder(name=DEFAULT_FOLDER_NAME, user_id=user_id, description=DEFAULT_FOLDER_DESCRIPTION) session.add(folder) session.commit() session.refresh(folder) session.exec( - update(Flow) - .where((Flow.folder_id == None) & (Flow.user_id == user_id)) + update(Flow) # type: ignore + .where( + and_( + Flow.folder_id == None, # type: ignore # noqa + Flow.user_id == user_id, + ) + ) .values(folder_id=folder.id) ) session.commit() - return None + return folder diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index 7bf8b6e56..9fce7dd59 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -21,7 +21,7 @@ class MonitorService(Service): self.settings_service = settings_service self.base_cache_dir = Path(user_cache_dir("langflow")) self.db_path = self.base_cache_dir / "monitor.duckdb" - self.table_map = { + self.table_map: dict[str, type[TransactionModel | MessageModel | VertexBuildModel]] = { "transactions": TransactionModel, "messages": MessageModel, "vertex_builds": VertexBuildModel, diff --git a/src/backend/base/poetry.lock b/src/backend/base/poetry.lock index 23665d65f..653359b34 100644 --- a/src/backend/base/poetry.lock +++ b/src/backend/base/poetry.lock @@ -558,58 +558,58 @@ files = [ [[package]] name = "duckdb" -version = "0.10.2" +version = "0.10.3" description = "DuckDB in-process database" optional = false python-versions = ">=3.7.0" files = [ - {file = "duckdb-0.10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3891d3ac03e12a3e5c43afa3020fe701f64060f52d25f429a1ed7b5d914368d3"}, - {file = "duckdb-0.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f63877651f1fb940e049dc53038eb763856616319acf4f892b1c3ed074f5ab0"}, - {file = "duckdb-0.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:06e3a36f04f4d98d2c0bbdd63e517cfbe114a795306e26ec855e62e076af5043"}, - {file = "duckdb-0.10.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf5f95ad5b75c8e65c6508b4df02043dd0b9d97712b9a33236ad77c388ce7861"}, - {file = "duckdb-0.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ff62bc98278c98fecbd6eecec5d698ad41ebd654110feaadbf8ac8bb59b1ecf"}, - {file = "duckdb-0.10.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cceede13fde095c23cf9a53adf7c414c7bfb21b9a7aa6a4836014fdbecbfca70"}, - {file = "duckdb-0.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:acdfff60b7efccd7f731213a9795851256249dfacf80367074b2b2e144f716dd"}, - {file = "duckdb-0.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a5d5655cf0bdaf664a6f332afe465e02b08cef715548a0983bb7aef48da06a6"}, - {file = "duckdb-0.10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a9d15842876d18763e085648656cccc7660a215d16254906db5c4471be2c7732"}, - {file = "duckdb-0.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c88cdcdc8452c910e4298223e7d9fca291534ff5aa36090aa49c9e6557550b13"}, - {file = "duckdb-0.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:364cd6f5dc8a1010d144d08c410ba9a74c521336ee5bda84fabc6616216a6d6a"}, - {file = "duckdb-0.10.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c57c11d1060296f5e9ebfb5bb7e5521e0d77912e8f9ff43c90240c3311e9de9"}, - {file = "duckdb-0.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:186d86b8dda8e1076170eb770bb2bb73ea88ca907d92885c9695d6515207b205"}, - {file = "duckdb-0.10.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f65b62f31c6bff21afc0261cfe28d238b8f34ec78f339546b12f4740c39552a"}, - {file = "duckdb-0.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a860d7466a5c93714cdd94559ce9e1db2ab91914f0941c25e5e93d4ebe36a5fa"}, - {file = "duckdb-0.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:33308190e9c7f05a3a0a2d46008a043effd4eae77011869d7c18fb37acdd9215"}, - {file = "duckdb-0.10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3a8b2f1229b4aecb79cd28ffdb99032b1497f0a805d0da1136a9b6115e1afc70"}, - {file = "duckdb-0.10.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d23a6dea61963733a0f45a0d0bbb1361fb2a47410ed5ff308b4a1f869d4eeb6f"}, - {file = "duckdb-0.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20ee0aa27e688aa52a40b434ec41a50431d0b06edeab88edc2feaca18d82c62c"}, - {file = "duckdb-0.10.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80a6d43d9044f0997a15a92e0c0ff3afd21151a1e572a92f439cc4f56b7090e1"}, - {file = "duckdb-0.10.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6934758cacd06029a5c9f54556a43bd277a86757e22bf8d0dd11ca15c1813d1c"}, - {file = "duckdb-0.10.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a11e2d68bd79044eea5486b1cddb5b915115f537e5c74eeb94c768ce30f9f4b"}, - {file = "duckdb-0.10.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0bf58385c43b8e448a2fea7e8729054934bf73ea616d1d7ef8184eda07f975e2"}, - {file = "duckdb-0.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:eae75c7014597ded6e7f6dc51e32d48362a31608acd73e9f795748ee94335a54"}, - {file = "duckdb-0.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62e89deff778a7a86f651802b947a3466425f6cce41e9d7d412d39e492932943"}, - {file = "duckdb-0.10.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f87e555fd36ec6da316b727a39fb24c53124a797dfa9b451bdea87b2f20a351f"}, - {file = "duckdb-0.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41e8b34b1a944590ebcf82f8cc59d67b084fe99479f048892d60da6c1402c386"}, - {file = "duckdb-0.10.2-cp37-cp37m-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c68c6dde2773774cf2371522a3959ea2716fc2b3a4891d4066f0e426455fe19"}, - {file = "duckdb-0.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ff6a8a0980d0f9398fa461deffa59465dac190d707468478011ea8a5fe1f2c81"}, - {file = "duckdb-0.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:728dd4ff0efda387a424754e5508d4f8c72a272c2d3ccb036a83286f60b46002"}, - {file = "duckdb-0.10.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c461d6b4619e80170044a9eb999bbf4097e330d3a4974ced0a7eaeb79c7c39f6"}, - {file = "duckdb-0.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:909351ff72eb3b50b89761251148d8a186594d8a438e12dcf5494794caff6693"}, - {file = "duckdb-0.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d9eeb8393d69abafd355b869669957eb85b89e4df677e420b9ef0693b7aa6cb4"}, - {file = "duckdb-0.10.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3102bcf5011e8f82ea3c2bde43108774fe5a283a410d292c0843610ea13e2237"}, - {file = "duckdb-0.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d64d443613e5f16caf7d67102733538c90f7715867c1a98597efd3babca068e3"}, - {file = "duckdb-0.10.2-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb31398826d1b7473344e5ee8e0f826370c9752549469ba1327042ace9041f80"}, - {file = "duckdb-0.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d09dcec467cd6127d5cc1fb0ce4efbd77e761882d9d772b0f64fc2f79a2a1cde"}, - {file = "duckdb-0.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:82fab1a24faf7c33d8a7afed08b57ee36e8821a3a68a2f1574cd238ea440bba0"}, - {file = "duckdb-0.10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38607e6e6618e8ea28c8d9b67aa9e22cfd6d6d673f2e8ab328bd6e867b697f69"}, - {file = "duckdb-0.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fb0c23bc8c09615bff38aebcf8e92e6ae74959c67b3c9e5b00edddc730bf22be"}, - {file = "duckdb-0.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:00576c11c78c83830ab483bad968e07cd9b5f730e7ffaf5aa5fadee5ac4f71e9"}, - {file = "duckdb-0.10.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077db692cdda50c4684ef87dc2a68507665804caa90e539dbe819116bda722ad"}, - {file = "duckdb-0.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca25984ad9f9a04e46e8359f852668c11569534e3bb8424b80be711303ad2314"}, - {file = "duckdb-0.10.2-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a72cc40982c7b92cf555e574618fc711033b013bf258b611ba18d7654c89d8c"}, - {file = "duckdb-0.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27b9efd6e788eb561535fdc0cbc7c74aca1ff39f748b7cfc27aa49b00e22da1"}, - {file = "duckdb-0.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:4800469489bc262dda61a7f1d40acedf67cf2454874e9d8bbf07920dc2b147e6"}, - {file = "duckdb-0.10.2.tar.gz", hash = "sha256:0f609c9d5f941f1ecde810f010dd9321cd406a552c1df20318a13fa64247f67f"}, + {file = "duckdb-0.10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd25cc8d001c09a19340739ba59d33e12a81ab285b7a6bed37169655e1cefb31"}, + {file = "duckdb-0.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f9259c637b917ca0f4c63887e8d9b35ec248f5d987c886dfc4229d66a791009"}, + {file = "duckdb-0.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b48f5f1542f1e4b184e6b4fc188f497be8b9c48127867e7d9a5f4a3e334f88b0"}, + {file = "duckdb-0.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e327f7a3951ea154bb56e3fef7da889e790bd9a67ca3c36afc1beb17d3feb6d6"}, + {file = "duckdb-0.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d8b20ed67da004b4481973f4254fd79a0e5af957d2382eac8624b5c527ec48c"}, + {file = "duckdb-0.10.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d37680b8d7be04e4709db3a66c8b3eb7ceba2a5276574903528632f2b2cc2e60"}, + {file = "duckdb-0.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d34b86d6a2a6dfe8bb757f90bfe7101a3bd9e3022bf19dbddfa4b32680d26a9"}, + {file = "duckdb-0.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:73b1cb283ca0f6576dc18183fd315b4e487a545667ffebbf50b08eb4e8cdc143"}, + {file = "duckdb-0.10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d917dde19fcec8cadcbef1f23946e85dee626ddc133e1e3f6551f15a61a03c61"}, + {file = "duckdb-0.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46757e0cf5f44b4cb820c48a34f339a9ccf83b43d525d44947273a585a4ed822"}, + {file = "duckdb-0.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:338c14d8ac53ac4aa9ec03b6f1325ecfe609ceeb72565124d489cb07f8a1e4eb"}, + {file = "duckdb-0.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:651fcb429602b79a3cf76b662a39e93e9c3e6650f7018258f4af344c816dab72"}, + {file = "duckdb-0.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3ae3c73b98b6215dab93cc9bc936b94aed55b53c34ba01dec863c5cab9f8e25"}, + {file = "duckdb-0.10.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56429b2cfe70e367fb818c2be19f59ce2f6b080c8382c4d10b4f90ba81f774e9"}, + {file = "duckdb-0.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b46c02c2e39e3676b1bb0dc7720b8aa953734de4fd1b762e6d7375fbeb1b63af"}, + {file = "duckdb-0.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:bcd460feef56575af2c2443d7394d405a164c409e9794a4d94cb5fdaa24a0ba4"}, + {file = "duckdb-0.10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e229a7c6361afbb0d0ab29b1b398c10921263c52957aefe3ace99b0426fdb91e"}, + {file = "duckdb-0.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:732b1d3b6b17bf2f32ea696b9afc9e033493c5a3b783c292ca4b0ee7cc7b0e66"}, + {file = "duckdb-0.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5380d4db11fec5021389fb85d614680dc12757ef7c5881262742250e0b58c75"}, + {file = "duckdb-0.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:468a4e0c0b13c55f84972b1110060d1b0f854ffeb5900a178a775259ec1562db"}, + {file = "duckdb-0.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa1e7ff8d18d71defa84e79f5c86aa25d3be80d7cb7bc259a322de6d7cc72da"}, + {file = "duckdb-0.10.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed1063ed97c02e9cf2e7fd1d280de2d1e243d72268330f45344c69c7ce438a01"}, + {file = "duckdb-0.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:22f2aad5bb49c007f3bfcd3e81fdedbc16a2ae41f2915fc278724ca494128b0c"}, + {file = "duckdb-0.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:8f9e2bb00a048eb70b73a494bdc868ce7549b342f7ffec88192a78e5a4e164bd"}, + {file = "duckdb-0.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6c2fc49875b4b54e882d68703083ca6f84b27536d57d623fc872e2f502b1078"}, + {file = "duckdb-0.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66c125d0c30af210f7ee599e7821c3d1a7e09208196dafbf997d4e0cfcb81ab"}, + {file = "duckdb-0.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99dd7a1d901149c7a276440d6e737b2777e17d2046f5efb0c06ad3b8cb066a6"}, + {file = "duckdb-0.10.3-cp37-cp37m-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5ec3bbdb209e6095d202202893763e26c17c88293b88ef986b619e6c8b6715bd"}, + {file = "duckdb-0.10.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:2b3dec4ef8ed355d7b7230b40950b30d0def2c387a2e8cd7efc80b9d14134ecf"}, + {file = "duckdb-0.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:04129f94fb49bba5eea22f941f0fb30337f069a04993048b59e2811f52d564bc"}, + {file = "duckdb-0.10.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d75d67024fc22c8edfd47747c8550fb3c34fb1cbcbfd567e94939ffd9c9e3ca7"}, + {file = "duckdb-0.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3796e9507c02d0ddbba2e84c994fae131da567ce3d9cbb4cbcd32fadc5fbb26"}, + {file = "duckdb-0.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:78e539d85ebd84e3e87ec44d28ad912ca4ca444fe705794e0de9be3dd5550c11"}, + {file = "duckdb-0.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a99b67ac674b4de32073e9bc604b9c2273d399325181ff50b436c6da17bf00a"}, + {file = "duckdb-0.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1209a354a763758c4017a1f6a9f9b154a83bed4458287af9f71d84664ddb86b6"}, + {file = "duckdb-0.10.3-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b735cea64aab39b67c136ab3a571dbf834067f8472ba2f8bf0341bc91bea820"}, + {file = "duckdb-0.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:816ffb9f758ed98eb02199d9321d592d7a32a6cb6aa31930f4337eb22cfc64e2"}, + {file = "duckdb-0.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:1631184b94c3dc38b13bce4045bf3ae7e1b0ecbfbb8771eb8d751d8ffe1b59b3"}, + {file = "duckdb-0.10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb98c35fc8dd65043bc08a2414dd9f59c680d7e8656295b8969f3f2061f26c52"}, + {file = "duckdb-0.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e75c9f5b6a92b2a6816605c001d30790f6d67ce627a2b848d4d6040686efdf9"}, + {file = "duckdb-0.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae786eddf1c2fd003466e13393b9348a44b6061af6fe7bcb380a64cac24e7df7"}, + {file = "duckdb-0.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9387da7b7973707b0dea2588749660dd5dd724273222680e985a2dd36787668"}, + {file = "duckdb-0.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:538f943bf9fa8a3a7c4fafa05f21a69539d2c8a68e557233cbe9d989ae232899"}, + {file = "duckdb-0.10.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6930608f35025a73eb94252964f9f19dd68cf2aaa471da3982cf6694866cfa63"}, + {file = "duckdb-0.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:03bc54a9cde5490918aad82d7d2a34290e3dfb78d5b889c6626625c0f141272a"}, + {file = "duckdb-0.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:372b6e3901d85108cafe5df03c872dfb6f0dbff66165a0cf46c47246c1957aa0"}, + {file = "duckdb-0.10.3.tar.gz", hash = "sha256:c5bd84a92bc708d3a6adffe1f554b94c6e76c795826daaaf482afc3d9c636971"}, ] [[package]] @@ -1172,13 +1172,13 @@ types-requests = ">=2.31.0.2,<3.0.0.0" [[package]] name = "langsmith" -version = "0.1.60" +version = "0.1.62" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.60-py3-none-any.whl", hash = "sha256:3c3520ea473de0a984237b3e9d638fdf23ef3acc5aec89a42e693225e72d6120"}, - {file = "langsmith-0.1.60.tar.gz", hash = "sha256:6a145b5454437f9e0f81525f23c4dcdbb8c07b1c91553b8f697456c418d6a599"}, + {file = "langsmith-0.1.62-py3-none-any.whl", hash = "sha256:3a9f112643f64d736b8c875390c750fe6485804ea53aeae4edebce0afa4383a5"}, + {file = "langsmith-0.1.62.tar.gz", hash = "sha256:7ef894c14e6d4175fce88ec3bcd5a9c8cf9a456ea77e26e361f519ad082f34a8"}, ] [package.dependencies] @@ -2586,13 +2586,13 @@ typing-extensions = ">=3.7.4.3" [[package]] name = "types-requests" -version = "2.32.0.20240521" +version = "2.32.0.20240523" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.32.0.20240521.tar.gz", hash = "sha256:c5c4a0ae95aad51f1bf6dae9eed04a78f7f2575d4b171da37b622e08b93eb5d3"}, - {file = "types_requests-2.32.0.20240521-py3-none-any.whl", hash = "sha256:ab728ba43ffb073db31f21202ecb97db8753ded4a9dc49cb480d8a5350c5c421"}, + {file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"}, + {file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"}, ] [package.dependencies] diff --git a/tests/conftest.py b/tests/conftest.py index 739f12ffb..d876aa316 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,6 +15,7 @@ from langflow.initial_setup.setup import STARTER_FOLDER_NAME from langflow.services.auth.utils import get_password_hash from langflow.services.database.models.api_key.model import ApiKey from langflow.services.database.models.flow.model import Flow, FlowCreate +from langflow.services.database.models.folder.model import Folder from langflow.services.database.models.user.model import User, UserCreate from langflow.services.database.utils import session_getter from langflow.services.deps import get_db_service @@ -388,7 +389,9 @@ def get_starter_project(active_user): # once the client is created, we can get the starter project with session_getter(get_db_service()) as session: flow = session.exec( - select(Flow).where(Flow.folder == STARTER_FOLDER_NAME).where(Flow.name == "Basic Prompting (Hello, World)") + select(Flow) + .where(Flow.folder.has(Folder.name == STARTER_FOLDER_NAME)) + .where(Flow.name == "Basic Prompting (Hello, World)") ).first() if not flow: raise ValueError("No starter project found") diff --git a/tests/test_endpoints.py b/tests/test_endpoints.py index 64a5da351..893b2b6d3 100644 --- a/tests/test_endpoints.py +++ b/tests/test_endpoints.py @@ -1,5 +1,5 @@ import time -from uuid import uuid4 +from uuid import UUID, uuid4 import pytest from fastapi import status @@ -393,8 +393,9 @@ def test_various_prompts(client, prompt, expected_input_variables): def test_get_vertices_flow_not_found(client, logged_in_headers): - response = client.post("/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers) - assert response.status_code == 500 # Or whatever status code you've set for invalid ID + uuid = uuid4() + response = client.post(f"/api/v1/build/{uuid}/vertices", headers=logged_in_headers) + assert response.status_code == 500 def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_headers): @@ -414,7 +415,8 @@ def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_head def test_build_vertex_invalid_flow_id(client, logged_in_headers): - response = client.post("/api/v1/build/nonexistent_id/vertices/vertex_id", headers=logged_in_headers) + uuid = uuid4() + response = client.post(f"/api/v1/build/{uuid}/vertices/vertex_id", headers=logged_in_headers) assert response.status_code == 500 @@ -652,7 +654,11 @@ def test_invalid_flow_id(client, created_api_key): headers = {"x-api-key": created_api_key.api_key} flow_id = "invalid-flow-id" response = client.post(f"/api/v1/run/{flow_id}", headers=headers) - assert response.status_code == status.HTTP_404_NOT_FOUND + assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY, response.text + headers = {"x-api-key": created_api_key.api_key} + flow_id = UUID(int=0) + response = client.post(f"/api/v1/run/{flow_id}", headers=headers) + assert response.status_code == status.HTTP_404_NOT_FOUND, response.text # Check if the error detail is as expected diff --git a/tests/test_initial_setup.py b/tests/test_initial_setup.py index a8f4e8548..d4f86a73f 100644 --- a/tests/test_initial_setup.py +++ b/tests/test_initial_setup.py @@ -1,16 +1,16 @@ from datetime import datetime from pathlib import Path +from sqlmodel import select + from langflow.initial_setup.setup import ( STARTER_FOLDER_NAME, create_or_update_starter_projects, get_project_data, load_starter_projects, ) -from langflow.services.database.models.flow.model import Flow +from langflow.services.database.models.folder.model import Folder from langflow.services.deps import session_scope -from sqlalchemy import func -from sqlmodel import select def test_load_starter_projects(): @@ -50,7 +50,8 @@ def test_create_or_update_starter_projects(client): num_projects = len(load_starter_projects()) # Get the number of projects in the database - num_db_projects = session.exec(select(func.count(Flow.id)).where(Flow.folder == STARTER_FOLDER_NAME)).one() + folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first() + num_db_projects = len(folder.flows) # Check that the number of projects in the database is the same as the number of projects returned by load_starter_projects assert num_db_projects == num_projects From ece3686767efb456310e2706558beba5c4efbd1c Mon Sep 17 00:00:00 2001 From: chyok Date: Thu, 23 May 2024 22:56:17 +0800 Subject: [PATCH 27/47] Remove unused local symbols (#1946) remove unused local symbols in inspection Co-authored-by: Gabriel Luiz Freitas Almeida --- src/backend/base/langflow/api/v1/chat.py | 1 - src/backend/base/langflow/api/v1/endpoints.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py index 3e148f259..23dea900b 100644 --- a/src/backend/base/langflow/api/v1/chat.py +++ b/src/backend/base/langflow/api/v1/chat.py @@ -159,7 +159,6 @@ async def build_vertex( ) else: graph = cache.get("result") - ResultDataResponse(results={}) vertex = graph.get_vertex(vertex_id) try: lock = chat_service._cache_locks[flow_id_str] diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py index 0b6178f29..e529de81c 100644 --- a/src/backend/base/langflow/api/v1/endpoints.py +++ b/src/backend/base/langflow/api/v1/endpoints.py @@ -112,7 +112,6 @@ async def simplified_run_flow( try: flow_id_str = str(flow_id) - task_result: List[RunOutputs] = [] artifacts = {} if input_request.session_id: session_data = await session_service.load_session(input_request.session_id, flow_id=flow_id_str) @@ -240,7 +239,6 @@ async def experimental_run_flow( if outputs is None: outputs = [] - task_result: List[RunOutputs] = [] artifacts = {} if session_id: session_data = await session_service.load_session(session_id, flow_id=flow_id_str) From b98f69aa980db11b2d55b4b2ee51778b1e03c897 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 23 May 2024 13:19:15 -0700 Subject: [PATCH 28/47] Add fallback to environment variables in loading test (#1961) chore: Update loading test to include fallback to environment variables --- docs/static/data/AstraDB-RAG-Flows.json | 90 +- .../Basic Prompting (Hello, world!).json | 1670 +++-- .../Langflow Blog Writter.json | 2065 +++--- .../Langflow Document QA.json | 1952 ++--- .../Langflow Memory Conversation.json | 2395 +++--- .../Langflow Prompt Chaining.json | 3339 +++++---- .../VectorStore-RAG-Flows.json | 6524 +++++++++-------- tests/test_loading.py | 3 +- 8 files changed, 9451 insertions(+), 8587 deletions(-) diff --git a/docs/static/data/AstraDB-RAG-Flows.json b/docs/static/data/AstraDB-RAG-Flows.json index 3bc1c8634..a445f5123 100644 --- a/docs/static/data/AstraDB-RAG-Flows.json +++ b/docs/static/data/AstraDB-RAG-Flows.json @@ -967,12 +967,12 @@ "advanced": false, "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, + "load_from_db": true, "title_case": false, "input_types": [ "Text" ], - "value": "" + "value": "OPENAI_API_KEY" }, "stream": { "type": "bool", @@ -1760,12 +1760,12 @@ "advanced": false, "dynamic": false, "info": "API endpoint URL for the Astra DB service.", - "load_from_db": false, + "load_from_db": true, "title_case": false, "input_types": [ "Text" ], - "value": "" + "value": "ASTRA_DB_API_ENDPOINT" }, "batch_size": { "type": "int", @@ -1846,7 +1846,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", + "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", "fileTypes": [], "file_path": "", "password": false, @@ -2065,7 +2065,7 @@ "display_name": "Setup Mode", "advanced": true, "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", + "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", "load_from_db": false, "title_case": false, "input_types": [ @@ -2087,12 +2087,12 @@ "advanced": false, "dynamic": false, "info": "Authentication token for accessing Astra DB.", - "load_from_db": false, + "load_from_db": true, "title_case": false, "input_types": [ "Text" ], - "value": "" + "value": "ASTRA_DB_APPLICATION_TOKEN" }, "_type": "CustomComponent" }, @@ -2210,12 +2210,12 @@ "advanced": false, "dynamic": false, "info": "API endpoint URL for the Astra DB service.", - "load_from_db": false, + "load_from_db": true, "title_case": false, "input_types": [ "Text" ], - "value": "" + "value": "ASTRA_DB_API_ENDPOINT" }, "batch_size": { "type": "int", @@ -2296,7 +2296,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import List, Optional\n\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Async\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> VectorStore:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", + "value": "from typing import List, Optional\n\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Async\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> VectorStore:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", "fileTypes": [], "file_path": "", "password": false, @@ -2470,7 +2470,7 @@ "display_name": "Setup Mode", "advanced": true, "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", + "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", "load_from_db": false, "title_case": false, "input_types": [ @@ -2492,12 +2492,12 @@ "advanced": false, "dynamic": false, "info": "Authentication token for accessing Astra DB.", - "load_from_db": false, + "load_from_db": true, "title_case": false, "input_types": [ "Text" ], - "value": "" + "value": "ASTRA_DB_APPLICATION_TOKEN" }, "_type": "CustomComponent" }, @@ -3091,9 +3091,9 @@ { "source": "TextOutput-BDknO", "target": "Prompt-xeI6K", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}", - "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-TextOutput-BDknO{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}-Prompt-xeI6K{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-TextOutput-BDknO{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", "data": { "targetHandle": { "fieldName": "context", @@ -3125,9 +3125,9 @@ { "source": "ChatInput-yxMKE", "target": "Prompt-xeI6K", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}", - "targetHandle": "{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-Prompt-xeI6K{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", "data": { "targetHandle": { "fieldName": "question", @@ -3160,9 +3160,9 @@ { "source": "Prompt-xeI6K", "target": "OpenAIModel-EjXlN", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-Prompt-xeI6K{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}-OpenAIModel-EjXlN{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-Prompt-xeI6K{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}-OpenAIModel-EjXlN{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", "data": { "targetHandle": { "fieldName": "input_value", @@ -3191,9 +3191,9 @@ { "source": "OpenAIModel-EjXlN", "target": "ChatOutput-Q39I8", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-OpenAIModel-EjXlN{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}-ChatOutput-Q39I8{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-OpenAIModel-EjXlN{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}-ChatOutput-Q39I8{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", "data": { "targetHandle": { "fieldName": "input_value", @@ -3222,9 +3222,9 @@ { "source": "File-t0a6a", "target": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}", - "targetHandle": "{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", - "id": "reactflow__edge-File-t0a6a{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}-RecursiveCharacterTextSplitter-tR9QM{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", + "id": "reactflow__edge-File-t0a6a{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}-RecursiveCharacterTextSplitter-tR9QM{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", "data": { "targetHandle": { "fieldName": "inputs", @@ -3251,9 +3251,9 @@ }, { "source": "OpenAIEmbeddings-ZlOk1", - "sourceHandle": "{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}", "target": "AstraDBSearch-41nRz", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", + "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", "data": { "targetHandle": { "fieldName": "embedding", @@ -3273,13 +3273,13 @@ "stroke": "#555" }, "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}-AstraDBSearch-41nRz{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}" + "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}" }, { "source": "ChatInput-yxMKE", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", "target": "AstraDBSearch-41nRz", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", "data": { "targetHandle": { "fieldName": "input_value", @@ -3304,13 +3304,13 @@ "stroke": "#555" }, "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-AstraDBSearch-41nRz{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" + "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" }, { "source": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}", "target": "AstraDB-eUCSS", - "targetHandle": "{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", + "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", "data": { "targetHandle": { "fieldName": "inputs", @@ -3330,14 +3330,14 @@ "stroke": "#555" }, "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}-AstraDB-eUCSS{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", + "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", "selected": false }, { "source": "OpenAIEmbeddings-9TPjc", - "sourceHandle": "{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}", "target": "AstraDB-eUCSS", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", + "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", "data": { "targetHandle": { "fieldName": "embedding", @@ -3357,14 +3357,14 @@ "stroke": "#555" }, "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}-AstraDB-eUCSS{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", + "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", "selected": false }, { "source": "AstraDBSearch-41nRz", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}", "target": "TextOutput-BDknO", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", "data": { "targetHandle": { "fieldName": "input_value", @@ -3387,7 +3387,7 @@ "stroke": "#555" }, "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-AstraDBSearch-41nRz{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}-TextOutput-BDknO{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" + "id": "reactflow__edge-AstraDBSearch-41nRz{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}-TextOutput-BDknO{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" } ], "viewport": { @@ -3400,4 +3400,4 @@ "name": "Vector Store RAG", "last_tested_version": "1.0.0a0", "is_component": false -} \ No newline at end of file +} diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json index b8693e13f..e7754d711 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json @@ -1,800 +1,886 @@ { - "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", - "data": { - "nodes": [ - { - "id": "Prompt-uxBqP", - "type": "genericNode", - "position": { - "x": 53.588791333410654, - "y": -107.07318910019967 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "user_input": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "user_input", - "display_name": "user_input", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "str", "Text"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["user_input"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-uxBqP", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": true, - "width": 384, - "height": 383, - "dragging": false, - "positionAbsolute": { - "x": 53.588791333410654, - "y": -107.07318910019967 - } - }, - { - "id": "OpenAIModel-k39HS", - "type": "genericNode", - "position": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": true, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", + "data": { + "nodes": [ + { + "id": "Prompt-uxBqP", + "type": "genericNode", + "position": { + "x": 53.588791333410654, + "y": -107.07318910019967 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "user_input": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "user_input", + "display_name": "user_input", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "str", + "Text" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "user_input" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-uxBqP", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": true, + "width": 384, + "height": 383, + "dragging": false, + "positionAbsolute": { + "x": 53.588791333410654, + "y": -107.07318910019967 + } }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["object", "Text", "str"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "OpenAIModel-k39HS", + "type": "genericNode", + "position": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-3.5-turbo", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": true, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "object", + "Text", + "str" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-k39HS", + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-k39HS", - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, - "dragging": false - }, - { - "id": "ChatOutput-njtka", - "type": "genericNode", - "position": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" + { + "id": "ChatOutput-njtka", + "type": "genericNode", + "position": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "Record", + "Text", + "str", + "object" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-njtka" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, + "dragging": false }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["Record", "Text", "str", "object"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null + { + "id": "ChatInput-P3fgL", + "type": "genericNode", + "position": { + "x": -495.2223093083827, + "y": -232.56998443685862 + }, + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "hi" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": [ + "object", + "Record", + "str", + "Text" + ], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-P3fgL" + }, + "selected": false, + "width": 384, + "height": 375, + "positionAbsolute": { + "x": -495.2223093083827, + "y": -232.56998443685862 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "OpenAIModel-k39HS", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}", + "target": "ChatOutput-njtka", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-njtka", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-k39HS" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-k39HS{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}-ChatOutput-njtka{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-njtka" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "dragging": false - }, - { - "id": "ChatInput-P3fgL", - "type": "genericNode", - "position": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "hi" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" + { + "source": "Prompt-uxBqP", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}", + "target": "OpenAIModel-k39HS", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-k39HS", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-uxBqP" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-uxBqP{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}-OpenAIModel-k39HS{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": ["object", "Record", "str", "Text"], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-P3fgL" - }, - "selected": false, - "width": 384, - "height": 375, - "positionAbsolute": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "OpenAIModel-k39HS", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-k39HSœ}", - "target": "ChatOutput-njtka", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-njtkaœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-njtka", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-k39HS" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-k39HS{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-k39HSœ}-ChatOutput-njtka{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-njtkaœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-uxBqP", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-uxBqPœ}", - "target": "OpenAIModel-k39HS", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-k39HSœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-k39HS", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-uxBqP" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-uxBqP{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-uxBqPœ}-OpenAIModel-k39HS{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-k39HSœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "ChatInput-P3fgL", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œRecordœ,œstrœ,œTextœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-P3fgLœ}", - "target": "Prompt-uxBqP", - "targetHandle": "{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-uxBqPœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "user_input", - "id": "Prompt-uxBqP", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Record", "str", "Text"], - "dataType": "ChatInput", - "id": "ChatInput-P3fgL" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-P3fgL{œbaseClassesœ:[œobjectœ,œRecordœ,œstrœ,œTextœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-P3fgLœ}-Prompt-uxBqP{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-uxBqPœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - } - ], - "viewport": { - "x": 260.58251815500563, - "y": 318.2261172111936, - "zoom": 0.43514115784696294 - } - }, - "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", - "name": "Basic Prompting (Hello, World)", - "last_tested_version": "1.0.0a4", - "is_component": false + { + "source": "ChatInput-P3fgL", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}", + "target": "Prompt-uxBqP", + "targetHandle": "{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "user_input", + "id": "Prompt-uxBqP", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Record", + "str", + "Text" + ], + "dataType": "ChatInput", + "id": "ChatInput-P3fgL" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-P3fgL{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}-Prompt-uxBqP{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": 260.58251815500563, + "y": 318.2261172111936, + "zoom": 0.43514115784696294 + } + }, + "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", + "name": "Basic Prompting (Hello, World)", + "last_tested_version": "1.0.0a4", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json index d2e4986ab..a2042385b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json @@ -1,987 +1,1096 @@ { - "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", - "data": { - "nodes": [ - { - "id": "Prompt-Rse03", - "type": "genericNode", - "position": { - "x": 1331.381712783371, - "y": 535.0279854229713 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "reference_1": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "reference_1", - "display_name": "reference_1", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "reference_2": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "reference_2", - "display_name": "reference_2", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "instructions": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "instructions", - "display_name": "instructions", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "Text", "str"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["reference_1", "reference_2", "instructions"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-Rse03", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 571, - "dragging": false, - "positionAbsolute": { - "x": 1331.381712783371, - "y": 535.0279854229713 - } - }, - { - "id": "URL-HYPkR", - "type": "genericNode", - "position": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, - "data": { - "type": "URL", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "urls": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "urls", - "display_name": "URL", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": [ - "https://www.promptingguide.ai/techniques/prompt_chaining" - ] - }, - "_type": "CustomComponent" - }, - "description": "Fetch content from one or more URLs.", - "icon": "layout-template", - "base_classes": ["Record"], - "display_name": "URL", - "documentation": "", - "custom_fields": { - "urls": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "URL-HYPkR" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, - "dragging": false - }, - { - "id": "ChatOutput-JPlxl", - "type": "genericNode", - "position": { - "x": 2503.8617424688505, - "y": 789.3005578928434 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["Text", "Record", "object", "str"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-JPlxl" - }, - "selected": false, - "width": 384, - "height": 383 - }, - { - "id": "OpenAIModel-gi29P", - "type": "genericNode", - "position": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "1024", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo-0125", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "0.1", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", + "data": { + "nodes": [ + { + "id": "Prompt-Rse03", + "type": "genericNode", + "position": { + "x": 1331.381712783371, + "y": 535.0279854229713 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "reference_1": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "reference_1", + "display_name": "reference_1", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "reference_2": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "reference_2", + "display_name": "reference_2", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "instructions": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "instructions", + "display_name": "instructions", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "Text", + "str" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "reference_1", + "reference_2", + "instructions" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-Rse03", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 571, + "dragging": false, + "positionAbsolute": { + "x": 1331.381712783371, + "y": 535.0279854229713 + } }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "Text", "object"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "URL-HYPkR", + "type": "genericNode", + "position": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, + "data": { + "type": "URL", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "urls": { + "type": "str", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "urls", + "display_name": "URL", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": [ + "https://www.promptingguide.ai/techniques/prompt_chaining" + ] + }, + "_type": "CustomComponent" + }, + "description": "Fetch content from one or more URLs.", + "icon": "layout-template", + "base_classes": [ + "Record" + ], + "display_name": "URL", + "documentation": "", + "custom_fields": { + "urls": null + }, + "output_types": [ + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "URL-HYPkR" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-gi29P" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, - "dragging": false - }, - { - "id": "URL-2cX90", - "type": "genericNode", - "position": { - "x": 573.961301764604, - "y": 336.41463436122086 - }, - "data": { - "type": "URL", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "urls": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "urls", - "display_name": "URL", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": ["https://www.promptingguide.ai/introduction/basics"] - }, - "_type": "CustomComponent" + { + "id": "ChatOutput-JPlxl", + "type": "genericNode", + "position": { + "x": 2503.8617424688505, + "y": 789.3005578928434 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "Text", + "Record", + "object", + "str" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-JPlxl" + }, + "selected": false, + "width": 384, + "height": 383 }, - "description": "Fetch content from one or more URLs.", - "icon": "layout-template", - "base_classes": ["Record"], - "display_name": "URL", - "documentation": "", - "custom_fields": { - "urls": null + { + "id": "OpenAIModel-gi29P", + "type": "genericNode", + "position": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "1024", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-3.5-turbo-0125", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "0.1", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-gi29P" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, + "dragging": false }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "URL-2cX90" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 573.961301764604, - "y": 336.41463436122086 - }, - "dragging": false - }, - { - "id": "TextInput-og8Or", - "type": "genericNode", - "position": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, - "data": { - "type": "TextInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[str] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics.", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as input.", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" + { + "id": "URL-2cX90", + "type": "genericNode", + "position": { + "x": 573.961301764604, + "y": 336.41463436122086 + }, + "data": { + "type": "URL", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "urls": { + "type": "str", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "urls", + "display_name": "URL", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": [ + "https://www.promptingguide.ai/introduction/basics" + ] + }, + "_type": "CustomComponent" + }, + "description": "Fetch content from one or more URLs.", + "icon": "layout-template", + "base_classes": [ + "Record" + ], + "display_name": "URL", + "documentation": "", + "custom_fields": { + "urls": null + }, + "output_types": [ + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "URL-2cX90" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 573.961301764604, + "y": 336.41463436122086 + }, + "dragging": false }, - "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": ["object", "Text", "str"], - "display_name": "Instructions", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null + { + "id": "TextInput-og8Or", + "type": "genericNode", + "position": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, + "data": { + "type": "TextInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[str] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics.", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": [ + "Record", + "Text" + ], + "dynamic": false, + "info": "Text or Record to be passed as input.", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Get text inputs from the Playground.", + "icon": "type", + "base_classes": [ + "object", + "Text", + "str" + ], + "display_name": "Instructions", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextInput-og8Or" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "URL-HYPkR", + "target": "Prompt-Rse03", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-URL-HYPkR{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "reference_2", + "id": "Prompt-Rse03", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "URL", + "id": "URL-HYPkR" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextInput-og8Or" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "URL-HYPkR", - "target": "Prompt-Rse03", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}", - "targetHandle": "{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-URL-HYPkR{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}-Prompt-Rse03{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "reference_2", - "id": "Prompt-Rse03", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "URL", - "id": "URL-HYPkR" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIModel-gi29P", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}", - "target": "ChatOutput-JPlxl", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-JPlxl", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-gi29P" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-gi29P{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}-ChatOutput-JPlxl{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "URL-2cX90", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}", - "target": "Prompt-Rse03", - "targetHandle": "{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "reference_1", - "id": "Prompt-Rse03", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "URL", - "id": "URL-2cX90" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-URL-2cX90{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}-Prompt-Rse03{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "TextInput-og8Or", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}", - "target": "Prompt-Rse03", - "targetHandle": "{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "instructions", - "id": "Prompt-Rse03", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "TextInput", - "id": "TextInput-og8Or" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-TextInput-og8Or{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}-Prompt-Rse03{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-Rse03", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}", - "target": "OpenAIModel-gi29P", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-gi29P", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "Prompt", - "id": "Prompt-Rse03" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-Rse03{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}-OpenAIModel-gi29P{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "selected": false - } - ], - "viewport": { - "x": -214.14726025721177, - "y": -35.83855793844168, - "zoom": 0.47344308394045925 - } - }, - "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", - "name": "Blog Writer", - "last_tested_version": "1.0.0a0", - "is_component": false + { + "source": "OpenAIModel-gi29P", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}", + "target": "ChatOutput-JPlxl", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-JPlxl", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-gi29P" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-gi29P{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}-ChatOutput-JPlxl{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "URL-2cX90", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}", + "target": "Prompt-Rse03", + "targetHandle": "{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "reference_1", + "id": "Prompt-Rse03", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "URL", + "id": "URL-2cX90" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-URL-2cX90{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "TextInput-og8Or", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}", + "target": "Prompt-Rse03", + "targetHandle": "{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "instructions", + "id": "Prompt-Rse03", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "TextInput", + "id": "TextInput-og8Or" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-TextInput-og8Or{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-Rse03", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}", + "target": "OpenAIModel-gi29P", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-gi29P", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "Prompt", + "id": "Prompt-Rse03" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-Rse03{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}-OpenAIModel-gi29P{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + } + ], + "viewport": { + "x": -214.14726025721177, + "y": -35.83855793844168, + "zoom": 0.47344308394045925 + } + }, + "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", + "name": "Blog Writer", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json index cde05c847..339d1eff7 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json @@ -1,933 +1,1029 @@ { - "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", - "data": { - "nodes": [ - { - "id": "Prompt-tHwPf", - "type": "genericNode", - "position": { - "x": 585.7906101139403, - "y": 117.52115876762832 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "Document": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "Document", - "display_name": "Document", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "Question": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "Question", - "display_name": "Question", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "str", "Text"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["Document", "Question"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-tHwPf", - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 479, - "positionAbsolute": { - "x": 585.7906101139403, - "y": 117.52115876762832 - }, - "dragging": false - }, - { - "id": "File-6TEsD", - "type": "genericNode", - "position": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, - "data": { - "type": "File", - "node": { - "template": { - "path": { - "type": "file", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [ - ".txt", - ".md", - ".mdx", - ".csv", - ".json", - ".yaml", - ".yml", - ".xml", - ".html", - ".htm", - ".pdf", - ".docx" - ], - "password": false, - "name": "path", - "display_name": "Path", - "advanced": false, - "dynamic": false, - "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"Files\"\n description = \"A generic file loader.\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "silent_errors": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "silent_errors", - "display_name": "Silent Errors", - "advanced": true, - "dynamic": false, - "info": "If true, errors will not raise an exception.", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "A generic file loader.", - "base_classes": ["Record"], - "display_name": "Files", - "documentation": "", - "custom_fields": { - "path": null, - "silent_errors": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "File-6TEsD" - }, - "selected": false, - "width": 384, - "height": 282, - "positionAbsolute": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, - "dragging": false - }, - { - "id": "ChatInput-MsSJ9", - "type": "genericNode", - "position": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": ["str", "Record", "Text", "object"], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-MsSJ9" - }, - "selected": true, - "width": 384, - "height": 377, - "positionAbsolute": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, - "dragging": false - }, - { - "id": "ChatOutput-F5Awj", - "type": "genericNode", - "position": { - "x": 1733.3012915204283, - "y": 168.76098809939327 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["str", "Record", "Text", "object"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-F5Awj" - }, - "selected": false, - "width": 384, - "height": 385, - "positionAbsolute": { - "x": 1733.3012915204283, - "y": 168.76098809939327 - }, - "dragging": false - }, - { - "id": "OpenAIModel-Bt067", - "type": "genericNode", - "position": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": false, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", + "data": { + "nodes": [ + { + "id": "Prompt-tHwPf", + "type": "genericNode", + "position": { + "x": 585.7906101139403, + "y": 117.52115876762832 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "Document": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "Document", + "display_name": "Document", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "Question": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "Question", + "display_name": "Question", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "str", + "Text" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "Document", + "Question" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-tHwPf", + "description": "A component for creating prompt templates using dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 479, + "positionAbsolute": { + "x": 585.7906101139403, + "y": 117.52115876762832 + }, + "dragging": false }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["object", "str", "Text"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "File-6TEsD", + "type": "genericNode", + "position": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, + "data": { + "type": "File", + "node": { + "template": { + "path": { + "type": "file", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [ + ".txt", + ".md", + ".mdx", + ".csv", + ".json", + ".yaml", + ".yml", + ".xml", + ".html", + ".htm", + ".pdf", + ".docx" + ], + "password": false, + "name": "path", + "display_name": "Path", + "advanced": false, + "dynamic": false, + "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"Files\"\n description = \"A generic file loader.\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "silent_errors": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "silent_errors", + "display_name": "Silent Errors", + "advanced": true, + "dynamic": false, + "info": "If true, errors will not raise an exception.", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "A generic file loader.", + "base_classes": [ + "Record" + ], + "display_name": "Files", + "documentation": "", + "custom_fields": { + "path": null, + "silent_errors": null + }, + "output_types": [ + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "File-6TEsD" + }, + "selected": false, + "width": 384, + "height": 282, + "positionAbsolute": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-Bt067" - }, - "selected": false, - "width": 384, - "height": 642, - "positionAbsolute": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "ChatInput-MsSJ9", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}", - "target": "Prompt-tHwPf", - "targetHandle": "{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "Question", - "id": "Prompt-tHwPf", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Record", "Text", "object"], - "dataType": "ChatInput", - "id": "ChatInput-MsSJ9" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-MsSJ9{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}-Prompt-tHwPf{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "File-6TEsD", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}", - "target": "Prompt-tHwPf", - "targetHandle": "{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "Document", - "id": "Prompt-tHwPf", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "File", - "id": "File-6TEsD" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-File-6TEsD{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}-Prompt-tHwPf{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-tHwPf", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}", - "target": "OpenAIModel-Bt067", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-Bt067", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-tHwPf" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-tHwPf{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}-OpenAIModel-Bt067{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-Bt067", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}", - "target": "ChatOutput-F5Awj", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-F5Awj", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-Bt067" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-Bt067{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}-ChatOutput-F5Awj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - } - ], - "viewport": { - "x": 352.20899206064655, - "y": 56.054900898593075, - "zoom": 0.9023391400011 - } - }, - "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", - "name": "Document QA", - "last_tested_version": "1.0.0a0", - "is_component": false + { + "id": "ChatInput-MsSJ9", + "type": "genericNode", + "position": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": [ + "str", + "Record", + "Text", + "object" + ], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-MsSJ9" + }, + "selected": true, + "width": 384, + "height": 377, + "positionAbsolute": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, + "dragging": false + }, + { + "id": "ChatOutput-F5Awj", + "type": "genericNode", + "position": { + "x": 1733.3012915204283, + "y": 168.76098809939327 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "str", + "Record", + "Text", + "object" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-F5Awj" + }, + "selected": false, + "width": 384, + "height": 385, + "positionAbsolute": { + "x": 1733.3012915204283, + "y": 168.76098809939327 + }, + "dragging": false + }, + { + "id": "OpenAIModel-Bt067", + "type": "genericNode", + "position": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-turbo-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": false, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "object", + "str", + "Text" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-Bt067" + }, + "selected": false, + "width": 384, + "height": 642, + "positionAbsolute": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "ChatInput-MsSJ9", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}", + "target": "Prompt-tHwPf", + "targetHandle": "{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "Question", + "id": "Prompt-tHwPf", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Record", + "Text", + "object" + ], + "dataType": "ChatInput", + "id": "ChatInput-MsSJ9" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-MsSJ9{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "File-6TEsD", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}", + "target": "Prompt-tHwPf", + "targetHandle": "{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "Document", + "id": "Prompt-tHwPf", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "File", + "id": "File-6TEsD" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-File-6TEsD{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-tHwPf", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}", + "target": "OpenAIModel-Bt067", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-Bt067", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-tHwPf" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-tHwPf{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}-OpenAIModel-Bt067{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-Bt067", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}", + "target": "ChatOutput-F5Awj", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-F5Awj", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-Bt067" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-Bt067{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}-ChatOutput-F5Awj{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": 352.20899206064655, + "y": 56.054900898593075, + "zoom": 0.9023391400011 + } + }, + "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", + "name": "Document QA", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json index a20f7bc19..5c62f73ad 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json @@ -1,1137 +1,1272 @@ { - "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", - "icon": "🤖", - "icon_bg_color": "#FFD700", - "data": { - "nodes": [ - { - "id": "ChatInput-t7F8v", - "type": "genericNode", - "position": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": false, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": ["Text", "object", "Record", "str"], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-t7F8v" - }, - "selected": false, - "width": 384, - "height": 469, - "positionAbsolute": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, - "dragging": false - }, - { - "id": "ChatOutput-P1jEe", - "type": "genericNode", - "position": { - "x": 3154.916355514023, - "y": 851.051882666333 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": false, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["Text", "object", "Record", "str"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-P1jEe" - }, - "selected": false, - "width": 384, - "height": 477, - "dragging": false, - "positionAbsolute": { - "x": 3154.916355514023, - "y": 851.051882666333 - } - }, - { - "id": "MemoryComponent-cdA1J", - "type": "genericNode", - "position": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - }, - "data": { - "type": "MemoryComponent", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.schema import Record\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def get_messages(self, **kwargs) -> list[Record]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "n_messages": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 5, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "n_messages", - "display_name": "Number of Messages", - "advanced": false, - "dynamic": false, - "info": "Number of messages to retrieve.", - "load_from_db": false, - "title_case": false - }, - "order": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Descending", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Ascending", "Descending"], - "name": "order", - "display_name": "Order", - "advanced": true, - "dynamic": false, - "info": "Order of the messages.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{sender_name}: {text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine and User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User", "Machine and User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "Session ID of the chat history.", - "load_from_db": false, - "title_case": false, - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Retrieves stored chat messages given a specific Session ID.", - "icon": "history", - "base_classes": ["str", "Text", "object"], - "display_name": "Chat Memory", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "session_id": null, - "n_messages": null, - "order": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": true - }, - "id": "MemoryComponent-cdA1J", - "description": "Retrieves stored chat messages given a specific Session ID.", - "display_name": "Chat Memory" - }, - "selected": false, - "width": 384, - "height": 489, - "dragging": false, - "positionAbsolute": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - } - }, - { - "id": "Prompt-ODkUx", - "type": "genericNode", - "position": { - "x": 1894.594426342426, - "y": 753.3797365481901 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "{context}\n\nUser: {user_message}\nAI: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "context": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "context", - "display_name": "context", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "user_message": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "user_message", - "display_name": "user_message", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["Text", "str", "object"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["context", "user_message"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-ODkUx", - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 477, - "dragging": false, - "positionAbsolute": { - "x": 1894.594426342426, - "y": 753.3797365481901 - } - }, - { - "id": "OpenAIModel-9RykF", - "type": "genericNode", - "position": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-1106-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "0.2", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", + "icon": "\ud83e\udd16", + "icon_bg_color": "#FFD700", + "data": { + "nodes": [ + { + "id": "ChatInput-t7F8v", + "type": "genericNode", + "position": { + "x": 1283.2700598313072, + "y": 982.5953650473145 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": false, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "MySessionID" + }, + "_type": "CustomComponent" + }, + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": [ + "Text", + "object", + "Record", + "str" + ], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-t7F8v" + }, + "selected": false, + "width": 384, + "height": 469, + "positionAbsolute": { + "x": 1283.2700598313072, + "y": 982.5953650473145 + }, + "dragging": false }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "object", "Text"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "ChatOutput-P1jEe", + "type": "genericNode", + "position": { + "x": 3154.916355514023, + "y": 851.051882666333 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": false, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "MySessionID" + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "Text", + "object", + "Record", + "str" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-P1jEe" + }, + "selected": false, + "width": 384, + "height": 477, + "dragging": false, + "positionAbsolute": { + "x": 3154.916355514023, + "y": 851.051882666333 + } }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-9RykF" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, - "dragging": false - }, - { - "id": "TextOutput-vrs6T", - "type": "genericNode", - "position": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" + { + "id": "MemoryComponent-cdA1J", + "type": "genericNode", + "position": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + }, + "data": { + "type": "MemoryComponent", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.schema import Record\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def get_messages(self, **kwargs) -> list[Record]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "n_messages": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 5, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "n_messages", + "display_name": "Number of Messages", + "advanced": false, + "dynamic": false, + "info": "Number of messages to retrieve.", + "load_from_db": false, + "title_case": false + }, + "order": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Descending", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Ascending", + "Descending" + ], + "name": "order", + "display_name": "Order", + "advanced": true, + "dynamic": false, + "info": "Order of the messages.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{sender_name}: {text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine and User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User", + "Machine and User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "Session ID of the chat history.", + "load_from_db": false, + "title_case": false, + "value": "MySessionID" + }, + "_type": "CustomComponent" + }, + "description": "Retrieves stored chat messages given a specific Session ID.", + "icon": "history", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "Chat Memory", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "session_id": null, + "n_messages": null, + "order": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": true + }, + "id": "MemoryComponent-cdA1J", + "description": "Retrieves stored chat messages given a specific Session ID.", + "display_name": "Chat Memory" + }, + "selected": false, + "width": 384, + "height": 489, + "dragging": false, + "positionAbsolute": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + } }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "object", "Text"], - "display_name": "Inspect Memory", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null + { + "id": "Prompt-ODkUx", + "type": "genericNode", + "position": { + "x": 1894.594426342426, + "y": 753.3797365481901 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "{context}\n\nUser: {user_message}\nAI: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "context": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "context", + "display_name": "context", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "user_message": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "user_message", + "display_name": "user_message", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "Text", + "str", + "object" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "context", + "user_message" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-ODkUx", + "description": "A component for creating prompt templates using dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 477, + "dragging": false, + "positionAbsolute": { + "x": 1894.594426342426, + "y": 753.3797365481901 + } }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-vrs6T" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}", - "target": "Prompt-ODkUx", - "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "context", - "type": "str", - "id": "Prompt-ODkUx", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"] - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "MemoryComponent", - "id": "MemoryComponent-cdA1J" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-Prompt-ODkUx{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "selected": false - }, - { - "source": "ChatInput-t7F8v", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}", - "target": "Prompt-ODkUx", - "targetHandle": "{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "user_message", - "type": "str", - "id": "Prompt-ODkUx", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"] - }, - "sourceHandle": { - "baseClasses": ["Text", "object", "Record", "str"], - "dataType": "ChatInput", - "id": "ChatInput-t7F8v" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-t7F8v{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}-Prompt-ODkUx{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "selected": false - }, - { - "source": "Prompt-ODkUx", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}", - "target": "OpenAIModel-9RykF", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-9RykF", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Text", "str", "object"], - "dataType": "Prompt", - "id": "Prompt-ODkUx" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-ODkUx{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}-OpenAIModel-9RykF{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-9RykF", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}", - "target": "ChatOutput-P1jEe", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-P1jEe", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "object", "Text"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-9RykF" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-9RykF{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}-ChatOutput-P1jEe{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}", - "target": "TextOutput-vrs6T", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-vrs6T", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "MemoryComponent", - "id": "MemoryComponent-cdA1J" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-foreground stroke-connection", - "id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-TextOutput-vrs6T{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" - } - ], - "viewport": { - "x": -569.862554459756, - "y": -42.08339711050985, - "zoom": 0.4868590524514978 - } - }, - "description": "This project can be used as a starting point for building a Chat experience with user specific memory. You can set a different Session ID to start a new message history.", - "name": "Memory Chatbot", - "last_tested_version": "1.0.0a0", - "is_component": false + { + "id": "OpenAIModel-9RykF", + "type": "genericNode", + "position": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-1106-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "0.2", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "str", + "object", + "Text" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-9RykF" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, + "dragging": false + }, + { + "id": "TextOutput-vrs6T", + "type": "genericNode", + "position": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": [ + "Record", + "Text" + ], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": [ + "str", + "object", + "Text" + ], + "display_name": "Inspect Memory", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-vrs6T" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", + "target": "Prompt-ODkUx", + "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "context", + "type": "str", + "id": "Prompt-ODkUx", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ] + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "MemoryComponent", + "id": "MemoryComponent-cdA1J" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + }, + { + "source": "ChatInput-t7F8v", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}", + "target": "Prompt-ODkUx", + "targetHandle": "{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "user_message", + "type": "str", + "id": "Prompt-ODkUx", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ] + }, + "sourceHandle": { + "baseClasses": [ + "Text", + "object", + "Record", + "str" + ], + "dataType": "ChatInput", + "id": "ChatInput-t7F8v" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-t7F8v{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + }, + { + "source": "Prompt-ODkUx", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}", + "target": "OpenAIModel-9RykF", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-9RykF", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Text", + "str", + "object" + ], + "dataType": "Prompt", + "id": "Prompt-ODkUx" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-ODkUx{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}-OpenAIModel-9RykF{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-9RykF", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}", + "target": "ChatOutput-P1jEe", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-P1jEe", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "object", + "Text" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-9RykF" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-9RykF{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}-ChatOutput-P1jEe{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", + "target": "TextOutput-vrs6T", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-vrs6T", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "MemoryComponent", + "id": "MemoryComponent-cdA1J" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-foreground stroke-connection", + "id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-TextOutput-vrs6T{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -569.862554459756, + "y": -42.08339711050985, + "zoom": 0.4868590524514978 + } + }, + "description": "This project can be used as a starting point for building a Chat experience with user specific memory. You can set a different Session ID to start a new message history.", + "name": "Memory Chatbot", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json index 38dda79d5..4ec2707a2 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json @@ -1,1586 +1,1769 @@ { - "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", - "data": { - "nodes": [ - { - "id": "Prompt-amqBu", - "type": "genericNode", - "position": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "document": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "document", - "display_name": "document", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "str", "Text"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["document"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-amqBu", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 385, - "positionAbsolute": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "dragging": false - }, - { - "id": "Prompt-gTNiz", - "type": "genericNode", - "position": { - "x": 3731.0813766902447, - "y": 799.631909121391 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "summary": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "summary", - "display_name": "summary", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "str", "Text"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["summary"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-gTNiz", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 385, - "dragging": false - }, - { - "id": "ChatOutput-EJkG3", - "type": "genericNode", - "position": { - "x": 3722.1747844849388, - "y": 1283.413553222214 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Summarizer", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["object", "Record", "Text", "str"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-EJkG3" - }, - "selected": false, - "width": 384, - "height": 385, - "dragging": false - }, - { - "id": "ChatOutput-DNmvg", - "type": "genericNode", - "position": { - "x": 5077.71285886074, - "y": 1232.9152769735522 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Question Generator", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["object", "Record", "Text", "str"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-DNmvg" - }, - "selected": false, - "width": 384, - "height": 385 - }, - { - "id": "TextInput-sptaH", - "type": "genericNode", - "position": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "data": { - "type": "TextInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[Text] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Revolutionary Nano-Battery Technology Unveiled In a groundbreaking announcement yesterday, researchers from the fictional Tech Innovations Institute revealed the development of a new nano-battery technology that promises to revolutionize energy storage. The new battery, dubbed the \"EnerGCell\", uses advanced nanomaterials to achieve unprecedented efficiency and storage capacities. According to lead researcher Dr. Ada Byron, the EnerGCell can store up to ten times more energy than the best lithium-ion batteries available today, while charging in just a fraction of the time. \"We're talking about charging your electric vehicle in just five minutes for a range of over 1,000 miles,\" Dr. Byron stated during the press conference. The technology behind the EnerGCell involves a complex arrangement of nanostructured electrodes that allow for rapid ion transfer and extremely high energy density. This breakthrough was achieved after a decade of research into nanomaterials and their applications in energy storage. The implications of this technology are vast, promising to accelerate the adoption of renewable energy by making it more practical and affordable to store wind and solar power. It could also lead to significant advancements in electric vehicles, mobile devices, and any other technology that relies on batteries. Despite the excitement, some experts are calling for patience, noting that the EnerGCell is still in its early stages of development and may take several years before it's commercially available. However, the potential impact of such a technology on the environment and the global economy is undeniable. Tech Innovations Institute plans to continue refining the EnerGCell and begin pilot projects with select partners in the coming year. If successful, this nano-battery technology could indeed be the breakthrough needed to usher in a new era of clean energy and technology.", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as input.", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": ["str", "Text", "object"], - "display_name": "Text Input", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextInput-sptaH" - }, - "selected": false, - "width": 384, - "height": 290, - "positionAbsolute": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "dragging": false - }, - { - "id": "TextOutput-2MS4a", - "type": "genericNode", - "position": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "Text", "object"], - "display_name": "First Prompt", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-2MS4a" - }, - "selected": false, - "width": 384, - "height": 290, - "positionAbsolute": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "dragging": false - }, - { - "id": "OpenAIModel-uYXZJ", - "type": "genericNode", - "position": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", + "data": { + "nodes": [ + { + "id": "Prompt-amqBu", + "type": "genericNode", + "position": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "document": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "document", + "display_name": "document", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "str", + "Text" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "document" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-amqBu", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 385, + "positionAbsolute": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 + }, + "dragging": false }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "Text", "object"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "Prompt-gTNiz", + "type": "genericNode", + "position": { + "x": 3731.0813766902447, + "y": 799.631909121391 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "summary": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "summary", + "display_name": "summary", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "str", + "Text" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "summary" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-gTNiz", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 385, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-uYXZJ" - }, - "selected": false, - "width": 384, - "height": 565, - "positionAbsolute": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "dragging": false - }, - { - "id": "TextOutput-MUDOR", - "type": "genericNode", - "position": { - "x": 4446.064323520379, - "y": 633.833297518702 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" + { + "id": "ChatOutput-EJkG3", + "type": "genericNode", + "position": { + "x": 3722.1747844849388, + "y": 1283.413553222214 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Summarizer", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "object", + "Record", + "Text", + "str" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-EJkG3" + }, + "selected": false, + "width": 384, + "height": 385, + "dragging": false }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "Text", "object"], - "display_name": "Second Prompt", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null + { + "id": "ChatOutput-DNmvg", + "type": "genericNode", + "position": { + "x": 5077.71285886074, + "y": 1232.9152769735522 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Question Generator", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "object", + "Record", + "Text", + "str" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-DNmvg" + }, + "selected": false, + "width": 384, + "height": 385 }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-MUDOR" - }, - "selected": false, - "width": 384, - "height": 290, - "dragging": false, - "positionAbsolute": { - "x": 4446.064323520379, - "y": 633.833297518702 + { + "id": "TextInput-sptaH", + "type": "genericNode", + "position": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, + "data": { + "type": "TextInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[Text] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Revolutionary Nano-Battery Technology Unveiled In a groundbreaking announcement yesterday, researchers from the fictional Tech Innovations Institute revealed the development of a new nano-battery technology that promises to revolutionize energy storage. The new battery, dubbed the \"EnerGCell\", uses advanced nanomaterials to achieve unprecedented efficiency and storage capacities. According to lead researcher Dr. Ada Byron, the EnerGCell can store up to ten times more energy than the best lithium-ion batteries available today, while charging in just a fraction of the time. \"We're talking about charging your electric vehicle in just five minutes for a range of over 1,000 miles,\" Dr. Byron stated during the press conference. The technology behind the EnerGCell involves a complex arrangement of nanostructured electrodes that allow for rapid ion transfer and extremely high energy density. This breakthrough was achieved after a decade of research into nanomaterials and their applications in energy storage. The implications of this technology are vast, promising to accelerate the adoption of renewable energy by making it more practical and affordable to store wind and solar power. It could also lead to significant advancements in electric vehicles, mobile devices, and any other technology that relies on batteries. Despite the excitement, some experts are calling for patience, noting that the EnerGCell is still in its early stages of development and may take several years before it's commercially available. However, the potential impact of such a technology on the environment and the global economy is undeniable. Tech Innovations Institute plans to continue refining the EnerGCell and begin pilot projects with select partners in the coming year. If successful, this nano-battery technology could indeed be the breakthrough needed to usher in a new era of clean energy and technology.", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": [ + "Record", + "Text" + ], + "dynamic": false, + "info": "Text or Record to be passed as input.", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Get text inputs from the Playground.", + "icon": "type", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "Text Input", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextInput-sptaH" + }, + "selected": false, + "width": 384, + "height": 290, + "positionAbsolute": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, + "dragging": false + }, + { + "id": "TextOutput-2MS4a", + "type": "genericNode", + "position": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": [ + "Record", + "Text" + ], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "First Prompt", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-2MS4a" + }, + "selected": false, + "width": 384, + "height": 290, + "positionAbsolute": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, + "dragging": false + }, + { + "id": "OpenAIModel-uYXZJ", + "type": "genericNode", + "position": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-turbo-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-uYXZJ" + }, + "selected": false, + "width": 384, + "height": 565, + "positionAbsolute": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "dragging": false + }, + { + "id": "TextOutput-MUDOR", + "type": "genericNode", + "position": { + "x": 4446.064323520379, + "y": 633.833297518702 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": [ + "Record", + "Text" + ], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "Second Prompt", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-MUDOR" + }, + "selected": false, + "width": 384, + "height": 290, + "dragging": false, + "positionAbsolute": { + "x": 4446.064323520379, + "y": 633.833297518702 + } + }, + { + "id": "OpenAIModel-XawYB", + "type": "genericNode", + "position": { + "x": 4500.152018344182, + "y": 1027.7382026227656 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-turbo-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "str", + "Text", + "object" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-XawYB" + }, + "selected": false, + "width": 384, + "height": 565, + "positionAbsolute": { + "x": 4500.152018344182, + "y": 1027.7382026227656 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "TextInput-sptaH", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}", + "target": "Prompt-amqBu", + "targetHandle": "{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "document", + "id": "Prompt-amqBu", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "TextInput", + "id": "TextInput-sptaH" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-TextInput-sptaH{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}-Prompt-amqBu{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-amqBu", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", + "target": "TextOutput-2MS4a", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-2MS4a", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-amqBu" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-TextOutput-2MS4a{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-amqBu", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", + "target": "OpenAIModel-uYXZJ", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-uYXZJ", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-amqBu" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-OpenAIModel-uYXZJ{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", + "target": "Prompt-gTNiz", + "targetHandle": "{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "summary", + "id": "Prompt-gTNiz", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-uYXZJ" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-Prompt-gTNiz{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", + "target": "ChatOutput-EJkG3", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-EJkG3", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-uYXZJ" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-ChatOutput-EJkG3{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-gTNiz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", + "target": "TextOutput-MUDOR", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-MUDOR", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-gTNiz" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-TextOutput-MUDOR{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-gTNiz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", + "target": "OpenAIModel-XawYB", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-XawYB", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-gTNiz" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-OpenAIModel-XawYB{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-XawYB", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}", + "target": "ChatOutput-DNmvg", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-DNmvg", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-XawYB" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-XawYB{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}-ChatOutput-DNmvg{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -383.7251879618552, + "y": 69.19813933800037, + "zoom": 0.3105753483695743 } - }, - { - "id": "OpenAIModel-XawYB", - "type": "genericNode", - "position": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "Text", "object"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-XawYB" - }, - "selected": false, - "width": 384, - "height": 565, - "positionAbsolute": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextInput-sptaH", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}", - "target": "Prompt-amqBu", - "targetHandle": "{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "document", - "id": "Prompt-amqBu", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "TextInput", - "id": "TextInput-sptaH" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-TextInput-sptaH{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}-Prompt-amqBu{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}", - "target": "TextOutput-2MS4a", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-2MS4a", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-amqBu" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-TextOutput-2MS4a{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}", - "target": "OpenAIModel-uYXZJ", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-uYXZJ", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-amqBu" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-OpenAIModel-uYXZJ{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}", - "target": "Prompt-gTNiz", - "targetHandle": "{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "summary", - "id": "Prompt-gTNiz", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-Prompt-gTNiz{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}", - "target": "ChatOutput-EJkG3", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-EJkG3", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-ChatOutput-EJkG3{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}", - "target": "TextOutput-MUDOR", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-MUDOR", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-gTNiz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-TextOutput-MUDOR{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}", - "target": "OpenAIModel-XawYB", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-XawYB", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-gTNiz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-OpenAIModel-XawYB{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-XawYB", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}", - "target": "ChatOutput-DNmvg", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-DNmvg", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-XawYB" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-XawYB{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}-ChatOutput-DNmvg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - } - ], - "viewport": { - "x": -383.7251879618552, - "y": 69.19813933800037, - "zoom": 0.3105753483695743 - } - }, - "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", - "name": "Prompt Chaining", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", + "name": "Prompt Chaining", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json b/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json index e13a206c9..74069017c 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json @@ -1,3151 +1,3407 @@ { - "id": "51e2b78a-199b-4054-9f32-e288eef6924c", - "data": { - "nodes": [ - { - "id": "ChatInput-yxMKE", - "type": "genericNode", - "position": { - "x": 1195.5276981160775, - "y": 209.421875 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "what is a line" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": ["Text", "str", "object", "Record"], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-yxMKE" - }, - "selected": false, - "width": 384, - "height": 383 - }, - { - "id": "TextOutput-BDknO", - "type": "genericNode", - "position": { - "x": 2322.600672827879, - "y": 604.9467307442569 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["object", "Text", "str"], - "display_name": "Extracted Chunks", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-BDknO" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 2322.600672827879, - "y": 604.9467307442569 - }, - "dragging": false - }, - { - "id": "OpenAIEmbeddings-ZlOk1", - "type": "genericNode", - "position": { - "x": 1183.667250865064, - "y": 687.3171828430261 - }, - "data": { - "type": "OpenAIEmbeddings", - "node": { - "template": { - "allowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "allowed_special", - "display_name": "Allowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "client": { - "type": "Any", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "client", - "display_name": "Client", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_headers": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_headers", - "display_name": "Default Headers", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_query": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_query", - "display_name": "Default Query", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "deployment": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "deployment", - "display_name": "Deployment", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "disallowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": ["all"], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "disallowed_special", - "display_name": "Disallowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "embedding_ctx_length": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 8191, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding_ctx_length", - "display_name": "Embedding Context Length", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_retries": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 6, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_retries", - "display_name": "Max Retries", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "name": "model", - "display_name": "Model", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "openai_api_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_type", - "display_name": "OpenAI API Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_version": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_version", - "display_name": "OpenAI API Version", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_organization": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_organization", - "display_name": "OpenAI Organization", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_proxy": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_proxy", - "display_name": "OpenAI Proxy", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "request_timeout": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "request_timeout", - "display_name": "Request Timeout", - "advanced": true, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "51e2b78a-199b-4054-9f32-e288eef6924c", + "data": { + "nodes": [ + { + "id": "ChatInput-yxMKE", + "type": "genericNode", + "position": { + "x": 1195.5276981160775, + "y": 209.421875 }, - "load_from_db": false, - "title_case": false - }, - "show_progress_bar": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "show_progress_bar", - "display_name": "Show Progress Bar", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "skip_empty": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "skip_empty", - "display_name": "Skip Empty", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_enable": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_enable", - "display_name": "TikToken Enable", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_model_name", - "display_name": "TikToken Model Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Generate embeddings using OpenAI models.", - "base_classes": ["Embeddings"], - "display_name": "OpenAI Embeddings", - "documentation": "", - "custom_fields": { - "openai_api_key": null, - "default_headers": null, - "default_query": null, - "allowed_special": null, - "disallowed_special": null, - "chunk_size": null, - "client": null, - "deployment": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, - "output_types": ["Embeddings"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "OpenAIEmbeddings-ZlOk1" - }, - "selected": false, - "width": 384, - "height": 383, - "dragging": false - }, - { - "id": "OpenAIModel-EjXlN", - "type": "genericNode", - "position": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "what is a line" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": [ + "Text", + "str", + "object", + "Record" + ], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-yxMKE" }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "selected": false, + "width": 384, + "height": 383 }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["object", "Text", "str"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "TextOutput-BDknO", + "type": "genericNode", + "position": { + "x": 2322.600672827879, + "y": 604.9467307442569 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": [ + "Record", + "Text" + ], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": [ + "object", + "Text", + "str" + ], + "display_name": "Extracted Chunks", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-BDknO" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 2322.600672827879, + "y": 604.9467307442569 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-EjXlN" - }, - "selected": true, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "dragging": false - }, - { - "id": "Prompt-xeI6K", - "type": "genericNode", - "position": { - "x": 2969.0261961391298, - "y": 442.1613649809069 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "context": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "context", - "display_name": "context", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "question": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "question", - "display_name": "question", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } + { + "id": "OpenAIEmbeddings-ZlOk1", + "type": "genericNode", + "position": { + "x": 1183.667250865064, + "y": 687.3171828430261 + }, + "data": { + "type": "OpenAIEmbeddings", + "node": { + "template": { + "allowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": [], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "allowed_special", + "display_name": "Allowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "chunk_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 1000, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_size", + "display_name": "Chunk Size", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "client": { + "type": "Any", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "client", + "display_name": "Client", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_headers": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_headers", + "display_name": "Default Headers", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_query": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_query", + "display_name": "Default Query", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "deployment": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "deployment", + "display_name": "Deployment", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "disallowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": [ + "all" + ], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "disallowed_special", + "display_name": "Disallowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "embedding_ctx_length": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 8191, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding_ctx_length", + "display_name": "Embedding Context Length", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_retries": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 6, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_retries", + "display_name": "Max Retries", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "name": "model", + "display_name": "Model", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "openai_api_type": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_type", + "display_name": "OpenAI API Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_version": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_version", + "display_name": "OpenAI API Version", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_organization": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_organization", + "display_name": "OpenAI Organization", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_proxy": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_proxy", + "display_name": "OpenAI Proxy", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "request_timeout": { + "type": "float", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "request_timeout", + "display_name": "Request Timeout", + "advanced": true, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "show_progress_bar": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "show_progress_bar", + "display_name": "Show Progress Bar", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "skip_empty": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "skip_empty", + "display_name": "Skip Empty", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_enable": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_enable", + "display_name": "TikToken Enable", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_model_name", + "display_name": "TikToken Model Name", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Generate embeddings using OpenAI models.", + "base_classes": [ + "Embeddings" + ], + "display_name": "OpenAI Embeddings", + "documentation": "", + "custom_fields": { + "openai_api_key": null, + "default_headers": null, + "default_query": null, + "allowed_special": null, + "disallowed_special": null, + "chunk_size": null, + "client": null, + "deployment": null, + "embedding_ctx_length": null, + "max_retries": null, + "model": null, + "model_kwargs": null, + "openai_api_base": null, + "openai_api_type": null, + "openai_api_version": null, + "openai_organization": null, + "openai_proxy": null, + "request_timeout": null, + "show_progress_bar": null, + "skip_empty": null, + "tiktoken_enable": null, + "tiktoken_model_name": null + }, + "output_types": [ + "Embeddings" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "OpenAIEmbeddings-ZlOk1" + }, + "selected": false, + "width": 384, + "height": 383, + "dragging": false }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "Text", "str"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["context", "question"] + { + "id": "OpenAIModel-EjXlN", + "type": "genericNode", + "position": { + "x": 3410.117202077183, + "y": 431.2038048137648 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-3.5-turbo", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "object", + "Text", + "str" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-EjXlN" + }, + "selected": true, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 3410.117202077183, + "y": 431.2038048137648 + }, + "dragging": false }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-xeI6K", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 477, - "positionAbsolute": { - "x": 2969.0261961391298, - "y": 442.1613649809069 - }, - "dragging": false - }, - { - "id": "ChatOutput-Q39I8", - "type": "genericNode", - "position": { - "x": 3887.2073667611485, - "y": 588.4801225794856 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" + { + "id": "Prompt-xeI6K", + "type": "genericNode", + "position": { + "x": 2969.0261961391298, + "y": 442.1613649809069 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "context": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "context", + "display_name": "context", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "question": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "question", + "display_name": "question", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "Text", + "str" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "context", + "question" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-xeI6K", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 477, + "positionAbsolute": { + "x": 2969.0261961391298, + "y": 442.1613649809069 + }, + "dragging": false }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["object", "Text", "Record", "str"], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null + { + "id": "ChatOutput-Q39I8", + "type": "genericNode", + "position": { + "x": 3887.2073667611485, + "y": 588.4801225794856 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": [ + "object", + "Text", + "Record", + "str" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-Q39I8" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 3887.2073667611485, + "y": 588.4801225794856 + }, + "dragging": false }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-Q39I8" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 3887.2073667611485, - "y": 588.4801225794856 - }, - "dragging": false - }, - { - "id": "File-t0a6a", - "type": "genericNode", - "position": { - "x": 2257.233450682836, - "y": 1747.5389618367233 - }, - "data": { - "type": "File", - "node": { - "template": { - "path": { - "type": "file", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [ - ".txt", - ".md", - ".mdx", - ".csv", - ".json", - ".yaml", - ".yml", - ".xml", - ".html", - ".htm", - ".pdf", - ".docx", - ".py", - ".sh", - ".sql", - ".js", - ".ts", - ".tsx" - ], - "file_path": "51e2b78a-199b-4054-9f32-e288eef6924c/Langflow conversation.pdf", - "password": false, - "name": "path", - "display_name": "Path", - "advanced": false, - "dynamic": false, - "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "silent_errors": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "silent_errors", - "display_name": "Silent Errors", - "advanced": true, - "dynamic": false, - "info": "If true, errors will not raise an exception.", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + { + "id": "File-t0a6a", + "type": "genericNode", + "position": { + "x": 2257.233450682836, + "y": 1747.5389618367233 + }, + "data": { + "type": "File", + "node": { + "template": { + "path": { + "type": "file", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [ + ".txt", + ".md", + ".mdx", + ".csv", + ".json", + ".yaml", + ".yml", + ".xml", + ".html", + ".htm", + ".pdf", + ".docx", + ".py", + ".sh", + ".sql", + ".js", + ".ts", + ".tsx" + ], + "file_path": "51e2b78a-199b-4054-9f32-e288eef6924c/Langflow conversation.pdf", + "password": false, + "name": "path", + "display_name": "Path", + "advanced": false, + "dynamic": false, + "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "silent_errors": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "silent_errors", + "display_name": "Silent Errors", + "advanced": true, + "dynamic": false, + "info": "If true, errors will not raise an exception.", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "A generic file loader.", + "icon": "file-text", + "base_classes": [ + "Record" + ], + "display_name": "File", + "documentation": "", + "custom_fields": { + "path": null, + "silent_errors": null + }, + "output_types": [ + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "File-t0a6a" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 2257.233450682836, + "y": 1747.5389618367233 + }, + "dragging": false }, - "description": "A generic file loader.", - "icon": "file-text", - "base_classes": ["Record"], - "display_name": "File", - "documentation": "", - "custom_fields": { - "path": null, - "silent_errors": null + { + "id": "RecursiveCharacterTextSplitter-tR9QM", + "type": "genericNode", + "position": { + "x": 2791.013514133929, + "y": 1462.9588953494142 + }, + "data": { + "type": "RecursiveCharacterTextSplitter", + "node": { + "template": { + "inputs": { + "type": "Document", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "inputs", + "display_name": "Input", + "advanced": false, + "input_types": [ + "Document", + "Record" + ], + "dynamic": false, + "info": "The texts to split.", + "load_from_db": false, + "title_case": false + }, + "chunk_overlap": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 200, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_overlap", + "display_name": "Chunk Overlap", + "advanced": false, + "dynamic": false, + "info": "The amount of overlap between chunks.", + "load_from_db": false, + "title_case": false + }, + "chunk_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 1000, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_size", + "display_name": "Chunk Size", + "advanced": false, + "dynamic": false, + "info": "The maximum length of each chunk.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "separators": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "separators", + "display_name": "Separators", + "advanced": false, + "dynamic": false, + "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": [ + "" + ] + }, + "_type": "CustomComponent" + }, + "description": "Split text into chunks of a specified length.", + "base_classes": [ + "Record" + ], + "display_name": "Recursive Character Text Splitter", + "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", + "custom_fields": { + "inputs": null, + "separators": null, + "chunk_size": null, + "chunk_overlap": null + }, + "output_types": [ + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "RecursiveCharacterTextSplitter-tR9QM" + }, + "selected": false, + "width": 384, + "height": 501, + "positionAbsolute": { + "x": 2791.013514133929, + "y": 1462.9588953494142 + }, + "dragging": false }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "File-t0a6a" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 2257.233450682836, - "y": 1747.5389618367233 - }, - "dragging": false - }, - { - "id": "RecursiveCharacterTextSplitter-tR9QM", - "type": "genericNode", - "position": { - "x": 2791.013514133929, - "y": 1462.9588953494142 - }, - "data": { - "type": "RecursiveCharacterTextSplitter", - "node": { - "template": { - "inputs": { - "type": "Document", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "inputs", - "display_name": "Input", - "advanced": false, - "input_types": ["Document", "Record"], - "dynamic": false, - "info": "The texts to split.", - "load_from_db": false, - "title_case": false - }, - "chunk_overlap": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 200, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_overlap", - "display_name": "Chunk Overlap", - "advanced": false, - "dynamic": false, - "info": "The amount of overlap between chunks.", - "load_from_db": false, - "title_case": false - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": false, - "dynamic": false, - "info": "The maximum length of each chunk.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "separators": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "separators", - "display_name": "Separators", - "advanced": false, - "dynamic": false, - "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": [""] - }, - "_type": "CustomComponent" + { + "id": "AstraDBSearch-41nRz", + "type": "genericNode", + "position": { + "x": 1723.976434815103, + "y": 277.03317407245913 + }, + "data": { + "type": "AstraDBSearch", + "node": { + "template": { + "embedding": { + "type": "Embeddings", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding", + "display_name": "Embedding", + "advanced": false, + "dynamic": false, + "info": "Embedding to use", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input Value", + "advanced": false, + "dynamic": false, + "info": "Input value to search", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "api_endpoint": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "api_endpoint", + "display_name": "API Endpoint", + "advanced": false, + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "load_from_db": true, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "ASTRA_DB_API_ENDPOINT" + }, + "batch_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "batch_size", + "display_name": "Batch Size", + "advanced": true, + "dynamic": false, + "info": "Optional number of records to process in a single batch.", + "load_from_db": false, + "title_case": false + }, + "bulk_delete_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_delete_concurrency", + "display_name": "Bulk Delete Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_batch_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_batch_concurrency", + "display_name": "Bulk Insert Batch Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_overwrite_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_overwrite_concurrency", + "display_name": "Bulk Insert Overwrite Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "collection_indexing_policy": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_indexing_policy", + "display_name": "Collection Indexing Policy", + "advanced": true, + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "load_from_db": false, + "title_case": false + }, + "collection_name": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_name", + "display_name": "Collection Name", + "advanced": false, + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "langflow" + }, + "metadata_indexing_exclude": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_exclude", + "display_name": "Metadata Indexing Exclude", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "metadata_indexing_include": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_include", + "display_name": "Metadata Indexing Include", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "metric": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metric", + "display_name": "Metric", + "advanced": true, + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "namespace": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "namespace", + "display_name": "Namespace", + "advanced": true, + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "number_of_results": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 4, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "number_of_results", + "display_name": "Number of Results", + "advanced": true, + "dynamic": false, + "info": "Number of results to return.", + "load_from_db": false, + "title_case": false + }, + "pre_delete_collection": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "pre_delete_collection", + "display_name": "Pre Delete Collection", + "advanced": true, + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "load_from_db": false, + "title_case": false + }, + "search_type": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Similarity", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Similarity", + "MMR" + ], + "name": "search_type", + "display_name": "Search Type", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "setup_mode": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Sync", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Sync", + "Async", + "Off" + ], + "name": "setup_mode", + "display_name": "Setup Mode", + "advanced": true, + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "token": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "token", + "display_name": "Token", + "advanced": false, + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "load_from_db": true, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "ASTRA_DB_APPLICATION_TOKEN" + }, + "_type": "CustomComponent" + }, + "description": "Searches an existing Astra DB Vector Store.", + "icon": "AstraDB", + "base_classes": [ + "Record" + ], + "display_name": "Astra DB Search", + "documentation": "", + "custom_fields": { + "embedding": null, + "collection_name": null, + "input_value": null, + "token": null, + "api_endpoint": null, + "search_type": null, + "number_of_results": null, + "namespace": null, + "metric": null, + "batch_size": null, + "bulk_insert_batch_concurrency": null, + "bulk_insert_overwrite_concurrency": null, + "bulk_delete_concurrency": null, + "setup_mode": null, + "pre_delete_collection": null, + "metadata_indexing_include": null, + "metadata_indexing_exclude": null, + "collection_indexing_policy": null + }, + "output_types": [ + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "token", + "api_endpoint", + "collection_name", + "input_value", + "embedding" + ], + "beta": false + }, + "id": "AstraDBSearch-41nRz" + }, + "selected": false, + "width": 384, + "height": 713, + "dragging": false, + "positionAbsolute": { + "x": 1723.976434815103, + "y": 277.03317407245913 + } }, - "description": "Split text into chunks of a specified length.", - "base_classes": ["Record"], - "display_name": "Recursive Character Text Splitter", - "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", - "custom_fields": { - "inputs": null, - "separators": null, - "chunk_size": null, - "chunk_overlap": null + { + "id": "AstraDB-eUCSS", + "type": "genericNode", + "position": { + "x": 3372.04958055989, + "y": 1611.0742035495277 + }, + "data": { + "type": "AstraDB", + "node": { + "template": { + "embedding": { + "type": "Embeddings", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding", + "display_name": "Embedding", + "advanced": false, + "dynamic": false, + "info": "Embedding to use", + "load_from_db": false, + "title_case": false + }, + "inputs": { + "type": "Record", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "inputs", + "display_name": "Inputs", + "advanced": false, + "dynamic": false, + "info": "Optional list of records to be processed and stored in the vector store.", + "load_from_db": false, + "title_case": false + }, + "api_endpoint": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "api_endpoint", + "display_name": "API Endpoint", + "advanced": false, + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "load_from_db": true, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "ASTRA_DB_API_ENDPOINT" + }, + "batch_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "batch_size", + "display_name": "Batch Size", + "advanced": true, + "dynamic": false, + "info": "Optional number of records to process in a single batch.", + "load_from_db": false, + "title_case": false + }, + "bulk_delete_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_delete_concurrency", + "display_name": "Bulk Delete Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_batch_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_batch_concurrency", + "display_name": "Bulk Insert Batch Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_overwrite_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_overwrite_concurrency", + "display_name": "Bulk Insert Overwrite Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import List, Optional, Union\n\nfrom langchain.schema import BaseRetriever\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "collection_indexing_policy": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_indexing_policy", + "display_name": "Collection Indexing Policy", + "advanced": true, + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "load_from_db": false, + "title_case": false + }, + "collection_name": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_name", + "display_name": "Collection Name", + "advanced": false, + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "langflow" + }, + "metadata_indexing_exclude": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_exclude", + "display_name": "Metadata Indexing Exclude", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "metadata_indexing_include": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_include", + "display_name": "Metadata Indexing Include", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "metric": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metric", + "display_name": "Metric", + "advanced": true, + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "namespace": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "namespace", + "display_name": "Namespace", + "advanced": true, + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "pre_delete_collection": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "pre_delete_collection", + "display_name": "Pre Delete Collection", + "advanced": true, + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "load_from_db": false, + "title_case": false + }, + "setup_mode": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Sync", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Sync", + "Async", + "Off" + ], + "name": "setup_mode", + "display_name": "Setup Mode", + "advanced": true, + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "token": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "token", + "display_name": "Token", + "advanced": false, + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "load_from_db": true, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "ASTRA_DB_APPLICATION_TOKEN" + }, + "_type": "CustomComponent" + }, + "description": "Builds or loads an Astra DB Vector Store.", + "icon": "AstraDB", + "base_classes": [ + "VectorStore" + ], + "display_name": "Astra DB", + "documentation": "", + "custom_fields": { + "embedding": null, + "token": null, + "api_endpoint": null, + "collection_name": null, + "inputs": null, + "namespace": null, + "metric": null, + "batch_size": null, + "bulk_insert_batch_concurrency": null, + "bulk_insert_overwrite_concurrency": null, + "bulk_delete_concurrency": null, + "setup_mode": null, + "pre_delete_collection": null, + "metadata_indexing_include": null, + "metadata_indexing_exclude": null, + "collection_indexing_policy": null + }, + "output_types": [ + "VectorStore" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "token", + "api_endpoint", + "collection_name", + "inputs", + "embedding" + ], + "beta": false + }, + "id": "AstraDB-eUCSS" + }, + "selected": false, + "width": 384, + "height": 573, + "positionAbsolute": { + "x": 3372.04958055989, + "y": 1611.0742035495277 + }, + "dragging": false }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "RecursiveCharacterTextSplitter-tR9QM" - }, - "selected": false, - "width": 384, - "height": 501, - "positionAbsolute": { - "x": 2791.013514133929, - "y": 1462.9588953494142 - }, - "dragging": false - }, - { - "id": "AstraDBSearch-41nRz", - "type": "genericNode", - "position": { - "x": 1723.976434815103, - "y": 277.03317407245913 - }, - "data": { - "type": "AstraDBSearch", - "node": { - "template": { - "embedding": { - "type": "Embeddings", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding", - "display_name": "Embedding", - "advanced": false, - "dynamic": false, - "info": "Embedding to use", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input Value", - "advanced": false, - "dynamic": false, - "info": "Input value to search", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "api_endpoint": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "api_endpoint", - "display_name": "API Endpoint", - "advanced": false, - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "batch_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "batch_size", - "display_name": "Batch Size", - "advanced": true, - "dynamic": false, - "info": "Optional number of records to process in a single batch.", - "load_from_db": false, - "title_case": false - }, - "bulk_delete_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_delete_concurrency", - "display_name": "Bulk Delete Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_batch_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_batch_concurrency", - "display_name": "Bulk Insert Batch Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_overwrite_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_overwrite_concurrency", - "display_name": "Bulk Insert Overwrite Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "collection_indexing_policy": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_indexing_policy", - "display_name": "Collection Indexing Policy", - "advanced": true, - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "load_from_db": false, - "title_case": false - }, - "collection_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_name", - "display_name": "Collection Name", - "advanced": false, - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "langflow" - }, - "metadata_indexing_exclude": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_exclude", - "display_name": "Metadata Indexing Exclude", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "metadata_indexing_include": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_include", - "display_name": "Metadata Indexing Include", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "metric": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metric", - "display_name": "Metric", - "advanced": true, - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "namespace": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "namespace", - "display_name": "Namespace", - "advanced": true, - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "number_of_results": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 4, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "number_of_results", - "display_name": "Number of Results", - "advanced": true, - "dynamic": false, - "info": "Number of results to return.", - "load_from_db": false, - "title_case": false - }, - "pre_delete_collection": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "pre_delete_collection", - "display_name": "Pre Delete Collection", - "advanced": true, - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "load_from_db": false, - "title_case": false - }, - "search_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Similarity", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Similarity", "MMR"], - "name": "search_type", - "display_name": "Search Type", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "setup_mode": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Sync", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Sync", "Async", "Off"], - "name": "setup_mode", - "display_name": "Setup Mode", - "advanced": true, - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "token": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "token", - "display_name": "Token", - "advanced": false, - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "_type": "CustomComponent" + { + "id": "OpenAIEmbeddings-9TPjc", + "type": "genericNode", + "position": { + "x": 2814.0402191223047, + "y": 1955.9268168273086 + }, + "data": { + "type": "OpenAIEmbeddings", + "node": { + "template": { + "allowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": [], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "allowed_special", + "display_name": "Allowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "chunk_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 1000, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_size", + "display_name": "Chunk Size", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "client": { + "type": "Any", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "client", + "display_name": "Client", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_headers": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_headers", + "display_name": "Default Headers", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_query": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_query", + "display_name": "Default Query", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "deployment": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "deployment", + "display_name": "Deployment", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "disallowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": [ + "all" + ], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "disallowed_special", + "display_name": "Disallowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "embedding_ctx_length": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 8191, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding_ctx_length", + "display_name": "Embedding Context Length", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_retries": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 6, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_retries", + "display_name": "Max Retries", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "name": "model", + "display_name": "Model", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ], + "value": "OPENAI_API_KEY" + }, + "openai_api_type": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_type", + "display_name": "OpenAI API Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_api_version": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_version", + "display_name": "OpenAI API Version", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_organization": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_organization", + "display_name": "OpenAI Organization", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "openai_proxy": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_proxy", + "display_name": "OpenAI Proxy", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "request_timeout": { + "type": "float", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "request_timeout", + "display_name": "Request Timeout", + "advanced": true, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "show_progress_bar": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "show_progress_bar", + "display_name": "Show Progress Bar", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "skip_empty": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "skip_empty", + "display_name": "Skip Empty", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_enable": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_enable", + "display_name": "TikToken Enable", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_model_name", + "display_name": "TikToken Model Name", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Generate embeddings using OpenAI models.", + "base_classes": [ + "Embeddings" + ], + "display_name": "OpenAI Embeddings", + "documentation": "", + "custom_fields": { + "openai_api_key": null, + "default_headers": null, + "default_query": null, + "allowed_special": null, + "disallowed_special": null, + "chunk_size": null, + "client": null, + "deployment": null, + "embedding_ctx_length": null, + "max_retries": null, + "model": null, + "model_kwargs": null, + "openai_api_base": null, + "openai_api_type": null, + "openai_api_version": null, + "openai_organization": null, + "openai_proxy": null, + "request_timeout": null, + "show_progress_bar": null, + "skip_empty": null, + "tiktoken_enable": null, + "tiktoken_model_name": null + }, + "output_types": [ + "Embeddings" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "OpenAIEmbeddings-9TPjc" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 2814.0402191223047, + "y": 1955.9268168273086 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "TextOutput-BDknO", + "target": "Prompt-xeI6K", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-TextOutput-BDknO{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "context", + "id": "Prompt-xeI6K", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "TextOutput", + "id": "TextOutput-BDknO" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false }, - "description": "Searches an existing Astra DB Vector Store.", - "icon": "AstraDB", - "base_classes": ["Record"], - "display_name": "Astra DB Search", - "documentation": "", - "custom_fields": { - "embedding": null, - "collection_name": null, - "input_value": null, - "token": null, - "api_endpoint": null, - "search_type": null, - "number_of_results": null, - "namespace": null, - "metric": null, - "batch_size": null, - "bulk_insert_batch_concurrency": null, - "bulk_insert_overwrite_concurrency": null, - "bulk_delete_concurrency": null, - "setup_mode": null, - "pre_delete_collection": null, - "metadata_indexing_include": null, - "metadata_indexing_exclude": null, - "collection_indexing_policy": null + { + "source": "ChatInput-yxMKE", + "target": "Prompt-xeI6K", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "question", + "id": "Prompt-xeI6K", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Text", + "str", + "object", + "Record" + ], + "dataType": "ChatInput", + "id": "ChatInput-yxMKE" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "token", - "api_endpoint", - "collection_name", - "input_value", - "embedding" - ], - "beta": false - }, - "id": "AstraDBSearch-41nRz" - }, - "selected": false, - "width": 384, - "height": 713, - "dragging": false, - "positionAbsolute": { - "x": 1723.976434815103, - "y": 277.03317407245913 + { + "source": "Prompt-xeI6K", + "target": "OpenAIModel-EjXlN", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-Prompt-xeI6K{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}-OpenAIModel-EjXlN{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-EjXlN", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "Prompt", + "id": "Prompt-xeI6K" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "OpenAIModel-EjXlN", + "target": "ChatOutput-Q39I8", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-OpenAIModel-EjXlN{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}-ChatOutput-Q39I8{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-Q39I8", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-EjXlN" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "File-t0a6a", + "target": "RecursiveCharacterTextSplitter-tR9QM", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", + "id": "reactflow__edge-File-t0a6a{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}-RecursiveCharacterTextSplitter-tR9QM{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", + "data": { + "targetHandle": { + "fieldName": "inputs", + "id": "RecursiveCharacterTextSplitter-tR9QM", + "inputTypes": [ + "Document", + "Record" + ], + "type": "Document" + }, + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "File", + "id": "File-t0a6a" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "OpenAIEmbeddings-ZlOk1", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}", + "target": "AstraDBSearch-41nRz", + "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", + "data": { + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDBSearch-41nRz", + "inputTypes": null, + "type": "Embeddings" + }, + "sourceHandle": { + "baseClasses": [ + "Embeddings" + ], + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-ZlOk1" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}" + }, + { + "source": "ChatInput-yxMKE", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", + "target": "AstraDBSearch-41nRz", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "AstraDBSearch-41nRz", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Text", + "str", + "object", + "Record" + ], + "dataType": "ChatInput", + "id": "ChatInput-yxMKE" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "RecursiveCharacterTextSplitter-tR9QM", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}", + "target": "AstraDB-eUCSS", + "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", + "data": { + "targetHandle": { + "fieldName": "inputs", + "id": "AstraDB-eUCSS", + "inputTypes": null, + "type": "Record" + }, + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "RecursiveCharacterTextSplitter", + "id": "RecursiveCharacterTextSplitter-tR9QM" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", + "selected": false + }, + { + "source": "OpenAIEmbeddings-9TPjc", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}", + "target": "AstraDB-eUCSS", + "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", + "data": { + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDB-eUCSS", + "inputTypes": null, + "type": "Embeddings" + }, + "sourceHandle": { + "baseClasses": [ + "Embeddings" + ], + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-9TPjc" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", + "selected": false + }, + { + "source": "AstraDBSearch-41nRz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}", + "target": "TextOutput-BDknO", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-BDknO", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "AstraDBSearch", + "id": "AstraDBSearch-41nRz" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-AstraDBSearch-41nRz{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}-TextOutput-BDknO{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -259.6782520315529, + "y": 90.3428735006047, + "zoom": 0.2687057134854984 } - }, - { - "id": "AstraDB-eUCSS", - "type": "genericNode", - "position": { - "x": 3372.04958055989, - "y": 1611.0742035495277 - }, - "data": { - "type": "AstraDB", - "node": { - "template": { - "embedding": { - "type": "Embeddings", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding", - "display_name": "Embedding", - "advanced": false, - "dynamic": false, - "info": "Embedding to use", - "load_from_db": false, - "title_case": false - }, - "inputs": { - "type": "Record", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "inputs", - "display_name": "Inputs", - "advanced": false, - "dynamic": false, - "info": "Optional list of records to be processed and stored in the vector store.", - "load_from_db": false, - "title_case": false - }, - "api_endpoint": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "api_endpoint", - "display_name": "API Endpoint", - "advanced": false, - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "batch_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "batch_size", - "display_name": "Batch Size", - "advanced": true, - "dynamic": false, - "info": "Optional number of records to process in a single batch.", - "load_from_db": false, - "title_case": false - }, - "bulk_delete_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_delete_concurrency", - "display_name": "Bulk Delete Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_batch_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_batch_concurrency", - "display_name": "Bulk Insert Batch Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_overwrite_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_overwrite_concurrency", - "display_name": "Bulk Insert Overwrite Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import List, Optional, Union\n\nfrom langchain.schema import BaseRetriever\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "collection_indexing_policy": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_indexing_policy", - "display_name": "Collection Indexing Policy", - "advanced": true, - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "load_from_db": false, - "title_case": false - }, - "collection_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_name", - "display_name": "Collection Name", - "advanced": false, - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "langflow" - }, - "metadata_indexing_exclude": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_exclude", - "display_name": "Metadata Indexing Exclude", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "metadata_indexing_include": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_include", - "display_name": "Metadata Indexing Include", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "metric": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metric", - "display_name": "Metric", - "advanced": true, - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "namespace": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "namespace", - "display_name": "Namespace", - "advanced": true, - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "pre_delete_collection": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "pre_delete_collection", - "display_name": "Pre Delete Collection", - "advanced": true, - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "load_from_db": false, - "title_case": false - }, - "setup_mode": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Sync", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Sync", "Async", "Off"], - "name": "setup_mode", - "display_name": "Setup Mode", - "advanced": true, - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "token": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "token", - "display_name": "Token", - "advanced": false, - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "_type": "CustomComponent" - }, - "description": "Builds or loads an Astra DB Vector Store.", - "icon": "AstraDB", - "base_classes": ["VectorStore"], - "display_name": "Astra DB", - "documentation": "", - "custom_fields": { - "embedding": null, - "token": null, - "api_endpoint": null, - "collection_name": null, - "inputs": null, - "namespace": null, - "metric": null, - "batch_size": null, - "bulk_insert_batch_concurrency": null, - "bulk_insert_overwrite_concurrency": null, - "bulk_delete_concurrency": null, - "setup_mode": null, - "pre_delete_collection": null, - "metadata_indexing_include": null, - "metadata_indexing_exclude": null, - "collection_indexing_policy": null - }, - "output_types": ["VectorStore"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "token", - "api_endpoint", - "collection_name", - "inputs", - "embedding" - ], - "beta": false - }, - "id": "AstraDB-eUCSS" - }, - "selected": false, - "width": 384, - "height": 573, - "positionAbsolute": { - "x": 3372.04958055989, - "y": 1611.0742035495277 - }, - "dragging": false - }, - { - "id": "OpenAIEmbeddings-9TPjc", - "type": "genericNode", - "position": { - "x": 2814.0402191223047, - "y": 1955.9268168273086 - }, - "data": { - "type": "OpenAIEmbeddings", - "node": { - "template": { - "allowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "allowed_special", - "display_name": "Allowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "client": { - "type": "Any", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "client", - "display_name": "Client", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_headers": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_headers", - "display_name": "Default Headers", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_query": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_query", - "display_name": "Default Query", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "deployment": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "deployment", - "display_name": "Deployment", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "disallowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": ["all"], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "disallowed_special", - "display_name": "Disallowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "embedding_ctx_length": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 8191, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding_ctx_length", - "display_name": "Embedding Context Length", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_retries": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 6, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_retries", - "display_name": "Max Retries", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "name": "model", - "display_name": "Model", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "" - }, - "openai_api_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_type", - "display_name": "OpenAI API Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_version": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_version", - "display_name": "OpenAI API Version", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_organization": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_organization", - "display_name": "OpenAI Organization", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_proxy": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_proxy", - "display_name": "OpenAI Proxy", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "request_timeout": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "request_timeout", - "display_name": "Request Timeout", - "advanced": true, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "show_progress_bar": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "show_progress_bar", - "display_name": "Show Progress Bar", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "skip_empty": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "skip_empty", - "display_name": "Skip Empty", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_enable": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_enable", - "display_name": "TikToken Enable", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_model_name", - "display_name": "TikToken Model Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Generate embeddings using OpenAI models.", - "base_classes": ["Embeddings"], - "display_name": "OpenAI Embeddings", - "documentation": "", - "custom_fields": { - "openai_api_key": null, - "default_headers": null, - "default_query": null, - "allowed_special": null, - "disallowed_special": null, - "chunk_size": null, - "client": null, - "deployment": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, - "output_types": ["Embeddings"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "OpenAIEmbeddings-9TPjc" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 2814.0402191223047, - "y": 1955.9268168273086 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextOutput-BDknO", - "target": "Prompt-xeI6K", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}", - "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-TextOutput-BDknO{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}-Prompt-xeI6K{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "context", - "id": "Prompt-xeI6K", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "TextOutput", - "id": "TextOutput-BDknO" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "ChatInput-yxMKE", - "target": "Prompt-xeI6K", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}", - "targetHandle": "{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-Prompt-xeI6K{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "question", - "id": "Prompt-xeI6K", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Text", "str", "object", "Record"], - "dataType": "ChatInput", - "id": "ChatInput-yxMKE" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "Prompt-xeI6K", - "target": "OpenAIModel-EjXlN", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-Prompt-xeI6K{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}-OpenAIModel-EjXlN{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-EjXlN", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "Prompt", - "id": "Prompt-xeI6K" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIModel-EjXlN", - "target": "ChatOutput-Q39I8", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-OpenAIModel-EjXlN{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}-ChatOutput-Q39I8{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-Q39I8", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-EjXlN" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "File-t0a6a", - "target": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}", - "targetHandle": "{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", - "id": "reactflow__edge-File-t0a6a{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}-RecursiveCharacterTextSplitter-tR9QM{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", - "data": { - "targetHandle": { - "fieldName": "inputs", - "id": "RecursiveCharacterTextSplitter-tR9QM", - "inputTypes": ["Document", "Record"], - "type": "Document" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "File", - "id": "File-t0a6a" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIEmbeddings-ZlOk1", - "sourceHandle": "{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}", - "target": "AstraDBSearch-41nRz", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", - "data": { - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDBSearch-41nRz", - "inputTypes": null, - "type": "Embeddings" - }, - "sourceHandle": { - "baseClasses": ["Embeddings"], - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-ZlOk1" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}-AstraDBSearch-41nRz{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}" - }, - { - "source": "ChatInput-yxMKE", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}", - "target": "AstraDBSearch-41nRz", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "AstraDBSearch-41nRz", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Text", "str", "object", "Record"], - "dataType": "ChatInput", - "id": "ChatInput-yxMKE" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-AstraDBSearch-41nRz{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}", - "target": "AstraDB-eUCSS", - "targetHandle": "{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", - "data": { - "targetHandle": { - "fieldName": "inputs", - "id": "AstraDB-eUCSS", - "inputTypes": null, - "type": "Record" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "RecursiveCharacterTextSplitter", - "id": "RecursiveCharacterTextSplitter-tR9QM" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}-AstraDB-eUCSS{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", - "selected": false - }, - { - "source": "OpenAIEmbeddings-9TPjc", - "sourceHandle": "{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}", - "target": "AstraDB-eUCSS", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", - "data": { - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDB-eUCSS", - "inputTypes": null, - "type": "Embeddings" - }, - "sourceHandle": { - "baseClasses": ["Embeddings"], - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-9TPjc" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}-AstraDB-eUCSS{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", - "selected": false - }, - { - "source": "AstraDBSearch-41nRz", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}", - "target": "TextOutput-BDknO", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-BDknO", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "AstraDBSearch", - "id": "AstraDBSearch-41nRz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-AstraDBSearch-41nRz{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}-TextOutput-BDknO{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" - } - ], - "viewport": { - "x": -259.6782520315529, - "y": 90.3428735006047, - "zoom": 0.2687057134854984 - } - }, - "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", - "name": "Vector Store RAG", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", + "name": "Vector Store RAG", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/tests/test_loading.py b/tests/test_loading.py index bea558f30..884a6a94a 100644 --- a/tests/test_loading.py +++ b/tests/test_loading.py @@ -1,5 +1,4 @@ import pytest - from langflow.graph import Graph from langflow.graph.schema import RunOutputs from langflow.initial_setup.setup import load_starter_projects @@ -38,6 +37,6 @@ def test_run_flow_from_json_object(): """Test loading a flow from a json file and applying tweaks""" _, projects = zip(*load_starter_projects()) project = [project for project in projects if "Basic Prompting" in project["name"]][0] - results = run_flow_from_json(project, input_value="test") + results = run_flow_from_json(project, input_value="test", fallback_to_env_vars=True) assert results is not None assert all(isinstance(result, RunOutputs) for result in results) From 9e1f056d180472ec637404affa1776591371b49f Mon Sep 17 00:00:00 2001 From: ogabrielluiz Date: Thu, 23 May 2024 17:38:39 -0300 Subject: [PATCH 29/47] chore: Update Dockerfile to remove unnecessary useradd command and fix pip installation --- build_and_push.Dockerfile | 6 +++--- build_and_push_base.Dockerfile | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build_and_push.Dockerfile b/build_and_push.Dockerfile index e27599454..3e9e18dab 100644 --- a/build_and_push.Dockerfile +++ b/build_and_push.Dockerfile @@ -78,9 +78,9 @@ RUN $POETRY_HOME/bin/poetry build # Copy virtual environment and built .tar.gz from builder base RUN useradd -m -u 1000 user +USER user # Install the package from the .tar.gz -RUN python -m pip install /app/dist/*.tar.gz --user - +RUN python -m pip install /app/dist/*.tar.gz ENTRYPOINT ["python", "-m", "langflow", "run"] -CMD ["--host", "0.0.0.0", "--port", "7860"] \ No newline at end of file +CMD ["--host", "0.0.0.0", "--port", "7860"] diff --git a/build_and_push_base.Dockerfile b/build_and_push_base.Dockerfile index cbcdbceee..bc174bf70 100644 --- a/build_and_push_base.Dockerfile +++ b/build_and_push_base.Dockerfile @@ -83,8 +83,9 @@ RUN cd src/backend/base && $POETRY_HOME/bin/poetry build --format sdist # Copy virtual environment and built .tar.gz from builder base RUN useradd -m -u 1000 user # Install the package from the .tar.gz -RUN python -m pip install /app/dist/*.tar.gz --user +USER user +RUN python -m pip install /app/dist/*.tar.gz ENTRYPOINT ["python", "-m", "langflow", "run"] -CMD ["--host", "0.0.0.0", "--port", "7860"] \ No newline at end of file +CMD ["--host", "0.0.0.0", "--port", "7860"] From 310b0f9ab1f948584735bae84f34af57f8abf9dd Mon Sep 17 00:00:00 2001 From: ogabrielluiz Date: Thu, 23 May 2024 19:01:58 -0300 Subject: [PATCH 30/47] Refactor Dockerfile to improve build process and package installation --- build_and_push_base.Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build_and_push_base.Dockerfile b/build_and_push_base.Dockerfile index bc174bf70..2c7cc2a07 100644 --- a/build_and_push_base.Dockerfile +++ b/build_and_push_base.Dockerfile @@ -78,13 +78,13 @@ RUN cd src/frontend && npm run build COPY src/backend ./src/backend RUN cp -r src/frontend/build src/backend/base/langflow/frontend RUN rm -rf src/backend/base/dist -RUN cd src/backend/base && $POETRY_HOME/bin/poetry build --format sdist +RUN cd src/backend/base && $POETRY_HOME/bin/poetry build # Copy virtual environment and built .tar.gz from builder base RUN useradd -m -u 1000 user -# Install the package from the .tar.gz USER user -RUN python -m pip install /app/dist/*.tar.gz +# Install the package from the .tar.gz +RUN python -m pip install /app/src/backend/base/dist/*.tar.gz ENTRYPOINT ["python", "-m", "langflow", "run"] From 543e8d52afbb8e64ae22255909f4453484b2bb07 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Thu, 23 May 2024 22:06:38 -0300 Subject: [PATCH 31/47] Remove Add Folder modal (#1941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed data gathering, now getting from flowpool * feat: Update get_transactions API endpoint to return TransactionModelResponse objects * refactor(schema.py): remove redundant __str__ method and improve Record class string representation by returning a JSON string of the data attributes fix record table * 🐛 (langflow/__main__.py): fix create_default_folder_if_it_doesnt_exist function call by passing user.id instead of user object ✨ (endpoints.py): add delete_multiple_flows endpoint to delete multiple flows by their IDs 📝 (flows.py): add download_file endpoint to download all flows as a file 🔧 (folders.py): add read_starter_folders endpoint to read starter folders 🔧 (login.py): fix create_default_folder_if_it_doesnt_exist function call by passing user.id instead of user object 🔧 (users.py): fix create_default_folder_if_it_doesnt_exist function call by passing user.id instead of user object ✨ (setup.py): add folder_id field to Flow model and update create_new_project function to include folder_id parameter 📝 (utils.py): import necessary modules and update function signature to use UUID instead of User object ♻️ (utils.py): refactor create_default_folder_if_it_doesnt_exist function to use user_id instead of User object and update SQL query to use UUID 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ (index.tsx): refactor useEffect to use useFolderStore instead of getFolders function 📝 (index.tsx): import useFolderStore from foldersStore ♻️ ( ✨ (services/index.tsx): update API endpoints for getting, adding, and updating folders to match backend routes 🚀 (flowsManagerStore.ts): add support for fetching starter projects and filtering them out from the list of flows ♻️ (foldersStore.tsx): refactor folder store to use Zustand for state management 📝 (types/zustand/folders/index.ts): add types for the folder store in Zustand * 📝 (App.tsx): Add import statement for useFolderStore from foldersStore to use the getFoldersApi and loadingFolders variables 📝 (App.tsx): Add useEffect hook to call getFoldersApi on component mount 📝 (ComponentsComponent/index.tsx): Add import statement for FlowType from types/flow 📝 (ComponentsComponent/index.tsx): Add import statement for useFolderStore from foldersStore to use the myCollectionFlows variable 📝 (ComponentsComponent/index.tsx): Add const flowsFromFolder to get the flows from the selected folder in useFolderStore 📝 (ComponentsComponent/index.tsx): Add useEffect hook to set the allFlows state to the flowsFromFolder on component mount 📝 (ComponentsComponent/index.tsx): Add useEffect hook to set the allFlows state to the myCollectionFlows.flows on myCollectionFlows change 📝 (ComponentsComponent/index.tsx): Add useEffect hook to filter the flows based on the searchFlowsComponents state 📝 (ComponentsComponent/index.tsx): Add useEffect hook to call getFolderById and setAllFlows on folderId change 📝 (ComponentsComponent/index.tsx): Add isLoadingFolders variable to isLoading in the conditional rendering of the loading page panel 📝 (ComponentsComponent/index.tsx): Add useEffect hook to call getFoldersApi on component mount 📝 (entities/index.tsx): Add import statement for FlowType from types/flow 📝 (sort-flows.ts): Add optional chaining to flows and f in the filter function 📝 (foldersStore.tsx): Add getMyCollectionFolder function to get the My Collection folder and set the myCollectionFlows state 📝 (foldersStore.tsx): Add setMyCollectionFlow function to set the myCollectionFlows state 📝 (foldersStore.tsx): Add myCollectionFlows state to store the My Collection folder and its flows 📝 (foldersStore.tsx): Call getMyCollectionFolder in the getFolders function to get the My Collection folder on folders load 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setFolders function to get the My Collection folder on folders update 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoading function to get the My Collection folder on loading change 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoadingById function to get the My Collection folder on loadingById change 📝 (foldersStore.tsx): Add myCollectionFlows state to store the My Collection folder and its flows 📝 (foldersStore.tsx): Call getMyCollectionFolder in the getFolders function to get the My Collection folder on folders load 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setFolders function to get the My Collection folder on folders update 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoading function to get the My Collection folder on loading change 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoadingById function to get the My Collection folder on loadingById change 📝 (foldersStore.tsx): Add myCollectionFlows state to store the My Collection folder and its flows 📝 (foldersStore.tsx): Call getMyCollectionFolder in the getFolders function to get the My Collection folder on folders load 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setFolders function to get the My Collection folder on folders update 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoading function to get the My Collection folder on loading change 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoadingById function to get the My Collection folder on loadingById change 📝 (foldersStore.tsx): Add myCollectionFlows state to store the My Collection folder and its flows 📝 (foldersStore.tsx): Call getMyCollectionFolder in the getFolders function to get the My Collection folder on folders load 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setFolders function to get the My Collection folder on folders update 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoading function to get the My Collection folder on loading change 📝 (foldersStore.tsx): Call getMyCollectionFolder in the setLoadingById function to get the My Collection folder on loadingById change 📝 (foldersStore.tsx): Add myCollectionFlows state to store the My Collection folder and its flows 📝 (foldersStore.tsx): Call getMyCollectionFolder in the getFolders function to get the My * 🐛 (flows.py): set default folder for flows without a folder_id to "My Collection" folder if it exists ✨ (componentsComponent/index.tsx): add isLoadingFolder state to track loading status of folder data 📝 (componentsComponent/index.tsx): remove console.log statement ♻️ (componentsComponent/index.tsx): refactor useEffect to setAllFlows only when folderId changes ♻️ (componentsComponent/index.tsx): refactor useEffect to log allFlows when it changes ♻️ (foldersStore.tsx): refactor getMyCollectionFolder to set myCollectionId state ♻️ (foldersStore.tsx): refactor setMyCollectionId to set myCollectionId state * Feat: create date and string logs components * ✨ (App.tsx): add autoLogin as a dependency to useEffect to trigger the effect when autoLogin changes ✨ (sideBarButtons/index.tsx): create a new component SideBarButtonsComponent to handle rendering of sidebar buttons ✨ (sideBarFolderButtons/index.tsx): create a new component SideBarFoldersButtonsComponent to handle rendering of sidebar folder buttons ♻️ (index.tsx): refactor SidebarNav component to use SideBarButtonsComponent and SideBarFoldersButtonsComponent for rendering buttons ✨ (index.tsx): add support for editing existing folders by passing folderToEdit prop to FolderForms component 📝 (index.tsx): add form validation using zod schema and zodResolver ♻️ (index.tsx): refactor form handling to use react-hook-form useForm hook and zodResolver for validation ✨ (submit-folder.tsx): create custom hook useFolderSubmit to handle form submission and API calls for adding and updating folders 📝 (entities/index.ts): add zod schema for folder form validation ♻️ (component/index.tsx): refactor imports and remove unused imports ♻️ (component/index.tsx): refactor FolderForms component to use destructuring for props and remove unused imports ♻️ (component/index.tsx): refactor useEffect to handle folderToEdit prop and set form values accordingly ♻️ (component/index.tsx): refactor FormField components to use FormItem and FormMessage components for better form structure and error handling ♻️ (component/index.tsx): refactor FormField components to use name prop instead of deprecated defaultValue prop ♻️ (component/index.tsx): refactor FormField components to use name prop instead of deprecated defaultValue prop 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component 🔧 (component/index.tsx): add missing import for FormMessage component ✨ (componentsComponent/index.tsx): remove unused isLoadingFolder variable ♻️ (componentsComponent/index.tsx): refactor useEffect to handle folderId and myCollectionId logic separately for better readability ♻️ (componentsComponent/index.tsx): refactor useEffect to setAllFlows with a delay of 500ms for smoother rendering 📝 (componentsComponent/index.tsx): remove console.log statement ✨ (modalsComponent/index.tsx): add ModalsComponent to handle different modals in ComponentsComponent ✨ (inputSearchComponent/index.tsx): add allFlows dependency to disable search input when there are no flows ✨ (delete-folder.tsx): add useDeleteFolder hook to handle folder deletion logic ✨ (dropdown-options.tsx): add useDropdownOptions hook to handle dropdown options for import from JSON 📝 (index.tsx): refactor MainPage's index.tsx to improve code readability and maintainability ✨ (index.tsx): introduce ModalsComponent to handle modals in MainPage ♻️ (foldersStore.tsx): refactor getFoldersApi function in foldersStore to allow refetching of folders ♻️ (foldersStore.tsx): refactor setFolderToEdit function in foldersStore to improve semantics ♻️ (index.ts): refactor FoldersStoreType in types/zustand/folders/index.ts to improve semantics ♻️ (tailwind.config.js): refactor tailwind.config.js to add display variant for group-hover * 🐛 (flows.py): import `col` from `sqlmodel` to fix reference error 🐛 (flows.py): change route method from DELETE to POST for deleting multiple flows 🐛 (flows.py): fix reference error in `delete_multiple_flows` function 📝 (schemas.py): add `FlowListIds` schema to handle flow ids for multiple delete ✨ (index.tsx): remove trailing commas in useState calls ♻️ (index.tsx): remove unnecessary ternary operator in className ♻️ (index.tsx): remove unnecessary arrow function in onDelete prop ♻️ (index.tsx): remove unnecessary props in DeleteConfirmationModal component ♻️ (index.tsx): remove unnecessary props in Button component ♻️ (index.tsx): remove unnecessary props in Icon component ♻️ (index.tsx): remove unnecessary props in Spinner component ♻️ (index.tsx): remove unnecessary props in IconButton component ♻️ (index.tsx): remove unnecessary props in Tooltip component ♻️ (index.tsx): remove unnecessary props in Text component ♻️ (index.tsx): remove unnecessary props in Flex component ♻️ (index.tsx): remove unnecessary props in Box component ♻️ (index.tsx): remove unnecessary props in Avatar component ♻️ (index.tsx): remove unnecessary props in Badge component ♻️ (index.tsx): remove unnecessary props in Image component ♻️ (index.tsx): remove unnecessary props in Heading component ♻️ (index.tsx): remove unnecessary props in Divider component ♻️ (index.tsx): remove unnecessary props in Spacer component ♻️ (index.tsx): remove unnecessary props in Stack component ♻️ (index.tsx): remove unnecessary props in Collapse component ♻️ (index.tsx): remove unnecessary props in Modal component ♻️ (index.tsx): remove unnecessary props in Portal component ♻️ (index.tsx): remove unnecessary props in Transition component ♻️ (index.tsx): remove unnecessary props in useFlowsManagerStore hook ♻️ (index.tsx): remove unnecessary props in useDisclosure hook ♻️ (index.tsx): remove unnecessary props in useToast hook ♻️ (index.tsx): remove unnecessary props in useColorModeValue hook ♻️ (index.tsx): remove unnecessary props in useBreakpointValue hook ♻️ (index.tsx): remove unnecessary props in useMediaQuery hook ♻️ (index.tsx): remove unnecessary props in useBoolean hook ♻️ (index.tsx): remove unnecessary props in useOutsideClick hook ♻️ (index.tsx): remove unnecessary props in useClipboard hook ♻️ (index.tsx): remove unnecessary props in useMergeRefs hook ♻️ (index.tsx): remove unnecessary props in useSafeLayoutEffect hook ♻️ (index.tsx): remove unnecessary props in useUpdateEffect hook ♻️ (index.tsx): remove unnecessary props in usePrevious hook ♻️ (index.tsx): remove unnecessary props in useTimeout hook ♻️ (index.tsx): remove unnecessary props in useDebounce hook ♻️ (index.tsx): remove unnecessary props in useThrottle hook ♻️ (index.tsx): remove unnecessary props in useWindowSize hook ♻️ (index.tsx): remove unnecessary props in useHover hook ♻️ (index.tsx): remove unnecessary props in useFocusWithin hook ♻️ (index.tsx): remove unnecessary props in useIntersect hook ♻️ (index.tsx): remove unnecessary props in useInViewport hook ♻️ (index.tsx): remove unnecessary props in useMeasure hook ♻️ (index.tsx): remove unnecessary props in useMotionValue hook ♻️ (index.tsx): remove unnecessary props in useTransform hook ♻️ (index.tsx): remove unnecessary props in useSpring hook ♻️ (index.tsx): remove unnecessary props in useDragControls hook ♻️ (index.tsx): remove unnecessary props in usePanGesture hook ♻️ (index.tsx): remove unnecessary props in useScrollControls hook ♻️ (index.tsx): remove unnecessary props in useViewportScroll hook ♻️ (index.tsx): remove unnecessary props in useAnimation hook ♻️ (index.tsx): remove unnecessary props in useCycle hook ♻️ (index.tsx): remove unnecessary props in useLottie hook ♻️ (index.tsx): remove unnecessary props in useMotionConfig hook ♻️ (index.tsx): remove unnecessary props in usePresence hook ♻ ✨ (componentsComponent/index.tsx): import multipleDeleteFlowsComponents from API controller to enable multiple deletion of flows and components ✨ (componentsComponent/index.tsx): add handleDelete function to handle individual deletion of flows and components ✨ (componentsComponent/index.tsx): add handleDeleteMultiple function to handle multiple deletion of flows and components ✨ (componentsComponent/index.tsx): add description prop to DeleteConfirmationModal to specify the type of item being deleted 📝 (modalsComponent/index.tsx): add description prop to DeleteConfirmationModal to specify the type of item being deleted * feat: Add JSON string representation to Record attributes feat: fix table view for Record * feat(frontend): add ArrayReader, NumberReader, ObjectRender components feat(frontend): add DateReader component to format date strings fix(frontend): fix component naming conventions for consistency feat(frontend): update TableAutoCellRender to use new components for rendering feat(frontend): update FlowLogsModal to use pagination and adjust modal size based on content * refactor(utils): update timestamp regex to handle optional milliseconds * refactor(api): update /monitor/messages endpoint to return MessageModel objects * refactor(api): update /monitor/messages endpoint to return List[MessageModel] * feat(modals): enable fake column editing in FlowLogsModal * update recordsOutput to expect object instead of string * refactor: update RecordsOutput to expect object instead of string * refactor: update RecordsOutputComponent to use extracted columns from rows and get multiple records * ✨ (flows.py): set default folder for newly created flows to "My Collection" if no folder is specified ♻️ (sideBarButtons/index.tsx): remove unused import and refactor code to simplify rendering of sidebar buttons ♻️ (sideBarFolderButtons/index.tsx): refactor code to simplify rendering of sidebar folder buttons and improve readability ♻️ (index.ts): refactor saveFlowToDatabase function to handle null folder_id values correctly ♻️ (NewFlowCardComponent/index.tsx): refactor code to set folder URL when creating a new flow ♻️ (undrawCards/index.tsx): refactor code to set folder URL when creating a new flow and remove unused import 📝 (newFlowModal/index.tsx): remove commented out code for IconComponent to improve code readability 📝 (newFlowModal/index.tsx): remove commented out code for examples.map to improve code readability 📝 (newFlowModal/index.tsx): change key values for UndrawCardComponent to improve uniqueness 📝 (FlowPage/index.tsx): remove unused import for useDarkStore to improve code cleanliness 📝 (FlowPage/index.tsx): remove extra whitespace to improve code readability 📝 (ComponentsComponent/index.tsx): add setFolderUrl function to set the folderUrl state in the folder store 📝 (ComponentsComponent/index.tsx): remove unnecessary whitespace to improve code readability 📝 (tabsComponent/index.tsx): add folderUrl state to navigate function to maintain folder state when changing tabs 📝 (routes.tsx): add nested route for /flow/:id/ to render FlowPage component 📝 (flowsManagerStore.ts): add folder_id property to newFlow object to store the current folder URL 📝 (foldersStore.tsx): remove unnecessary comma to fix syntax error 📝 (foldersStore.tsx): add folderUrl state and setFolderUrl function to store the current folder URL 🐛 (reactflowUtils.ts): remove unused parameter 'edges' in isValidConnection function ♻️ (reactflowUtils.ts): refactor scapeJSONParse and scapeJSONStringfy functions to remove unnecessary exclamation marks 🐛 (reactflowUtils.ts): fix bug in updateIds function where selectionIds could be undefined 🐛 (reactflowUtils.ts): fix bug in updateIds function where edge.sourceHandle could be undefined 🐛 (reactflowUtils.ts): fix bug in updateIds function where edge.targetHandle could be undefined 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in validateNode function where scapeJSONParse was called twice 🐛 (reactflowUtils.ts): fix bug in 📝 (file): update line 785 to fix a typo or improve code readability ✨ (reactflowUtils.ts): remove unnecessary comma at the end of the line ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code 📝 (reactflowUtils.ts): add missing JSDoc comments to functions ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability and remove unnecessary code ♻️ (reactflowUtils.ts): refactor code to improve readability * refactor: Update FlowLogsModal to fetch and display messages table based on active tab * update package lock * 🐛 (folders.py): import missing dependencies and update code to handle folder components and flows 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders.py): fix typo in update statement 🐛 (folders ✨ (componentsComponent/index.tsx): add support for selecting and deselecting multiple flows/components 🔧 (componentsComponent/index.tsx): update import statement for react-hook-form to include useWatch ♻️ (componentsComponent/index.tsx): refactor handleSelectAll function to only select flows from folder ♻️ (componentsComponent/index.tsx): refactor handleSelectOptionsChange function to check selectedFlowsComponentsCards length ♻️ (componentsComponent/index.tsx): refactor handleDeleteMultiple function to use selectedFlowsComponentsCards ✨ (componentsComponent/index.tsx): update selectedFlowsComponentsCards state when form values change ♻️ (componentsComponent/index.tsx): refactor getDescriptionModal to use useMemo 🐛 (inputSearchComponent/index.tsx): disable input search when loading, no flows, or no searchFlowsComponents ♻️ (flowsManagerStore.ts): add selectedFlowsComponentsCards state and setSelectedFlowsComponentsCards function 📝 (zustand/flowsManager/index.ts): update FlowsManagerStoreType to include selectedFlowsComponentsCards state and setSelectedFlowsComponentsCards function 📝 (deleteComponentFlows.spec.ts): update confirmation message for deleting a component * 🐛 (index.tsx): filter out flows without a folder_id to prevent errors when mapping over flows 🐛 (index.ts): add folder_id property to FlowType to properly handle flows with a folder_id * 📝 (sidebarComponent): remove console.log statement for items variable ♻️ (sidebarComponent): refactor sideBarButtons component to fix button width and improve styling ♻️ (sidebarComponent): refactor sideBarFolderButtons component to fix folder name truncation and improve styling ♻️ (sidebarComponent): refactor sidebarNav component to fix className prop ♻️ (mainPage): refactor HomePage component to remove unnecessary parentheses and fix indentation * 📝 (on-file-drop.tsx): import `useLocation` from `react-router-dom` to use location state in the component ♻️ (on-file-drop.tsx): refactor `useFlowsManagerStore` to `useFolderStore` to use the correct store for getting folder data ✨ (on-file-drop.tsx): add `location` and `folderId` variables to get the folder id from the location state ✨ (on-file-drop.tsx): call `getFolderById` function instead of `setAllFlows` to update the folder data after successful upload * Implemented Dict modal on Cell Editor for objects * ✨ (sideBarFolderButtons/index.tsx): add support for file drop functionality in the sidebar folder buttons component 📝 (use-on-file-drop.tsx): create a custom hook for handling file drop functionality in the sidebar component 📝 (componentsComponent/index.tsx): update import statement for the useFileDrop hook in the components component 📝 (use-delete-folder.tsx): create a custom hook for handling folder deletion in the MainPage component 📝 (use-dropdown-options.tsx): create a custom hook for generating dropdown options in the MainPage component ✨ (use-on-file-drop.tsx): add a new hook for handling file drop functionality in the MainPage component ✨ (index.tsx): update import paths for hooks in the MainPage component ♻️ (flowsManagerStore.ts): refactor the addFlow function to include a new parameter 'fromDragAndDrop' to differentiate between adding a flow from drag and drop or other methods ♻️ (foldersStore.tsx): refactor the folder store to include a new state 'folderDragging' to store the folder being dragged ♻️ (index.ts): refactor the types in the flowsManager and folders store to include the new 'fromDragAndDrop' parameter * 📝 (App.tsx): Remove unnecessary line breaks and trailing commas for better code readability ♻️ (App.tsx): Refactor code to remove unused variables and dependencies ✨ (App.tsx): Add support for fetching folders on login and error handling ♻️ (popoverObject/index.tsx): Refactor code to remove unnecessary ternary operators and improve code readability ♻️ (foldersModal/component/index.tsx): Refactor code to improve code readability and consistency ♻️ (foldersModal/index.tsx): Refactor code to improve code readability and consistency ✨ (actionsMainPage.spec.ts): add end-to-end tests for selecting and deleting all items, and searching flows and components ✨ (folders.spec.ts): add end-to-end tests for CRUD operations on folders and adding a folder by drag and drop * Refactor: Change the no data table screen to a better version * refactor: Update ObjectRender component to display truncated object and provide option to see more * style(objectRender): add hover effect to object render component for better user experience style(tailwind.config.js): add slow-wiggle animation to tailwind config for smoother animation effect * 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): update id prop value to include object id for better identification 📝 (inputComponent/index.tsx): update id prop value to include object id for better identification 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (inputComponent/index.tsx): remove unnecessary whitespace in className prop to improve code readability 📝 (sidebarComponent/components/sideBarButtons/index.tsx): remove unused item.icon prop 📝 (sidebarComponent/index.tsx): add isFolderPath variable to check if current path is a folder path 📝 (sidebarComponent/index.tsx): add isFolderPath variable to check if current path is a folder path 📝 (foldersModal/component/index.tsx): update id prop value for flow input component 📝 (foldersModal/component/index.tsx): update id prop value for component input component 📝 (end-to-end/actionsMainPage.spec.ts): update getByText assertions to include { exact: true } option for more accurate matching ✨ (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text ✨ (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove unnecessary characters in input text 📝 (chatInputOutput.spec.ts): update test case to improve readability and remove ✅ (nestedComponent.spec.ts): remove unnecessary code related to showpinecone_env checkbox ✅ (store.spec.ts): use environment variable STORE_API_KEY instead of hardcoding the API key * 📝 (inputComponent/index.tsx): update id prop value to include "popover-anchor-" prefix for better identification and accessibility ✨ (sidebarComponent/components/sideBarButtons/index.tsx): add react-router-dom Link component to wrap each sidebar button item for navigation functionality ♻️ (sidebarComponent/index.tsx): refactor isFolderPath logic to use array of path values and check if any of them is included in the current pathname for better readability and maintainability * Refactor: use shadcn alert when there is no data * Remove unnecessary quotes * Refactor: add border to no data alert * Fix: record output not using table as it should * 📝 (cardComponent/index.tsx): remove redundant "selected" from description prop in DeleteConfirmationModal component 📝 (componentsComponent/index.tsx): remove redundant "selected" from getDescriptionModal function * ✨ (logs.spec.ts): add end-to-end test for viewing and interacting with logs in the frontend 📝 (logs.spec.ts): add documentation comments to improve code readability and maintainability * 📝 (folders.py): add support for downloading all flows from a folder as a file 📝 (folders.py): add support for uploading flows from a file to a folder ✨ (index.tsx): add handleDownloadFolderFn utility function to handle downloading flows from a folder ✨ (index.tsx): add handleUploadFlowsToFolder function to handle uploading flows to a folder 📝 (services/index.ts): add downloadFlowsFromFolders function to make API call for downloading flows from a folder 📝 (services/index.ts): add uploadFlowsFromFolders function to make API call for uploading flows to a folder 📝 (handle-download-folder.ts): create handleDownloadFolderFn utility function to handle downloading flows from a folder ✨ (foldersStore.tsx): add support for uploading flows from folders 📝 (foldersStore.tsx): update types to include uploadFolder function in FoldersStoreType * 📝 (folders.py): remove unnecessary whitespace to improve code readability 📝 (folders.py): remove unnecessary whitespace to improve code readability * style: update CSS in App.css to improve scrollbar appearance feat: add TableComponent to CsvOutputComponent for better table rendering refactor: remove unused code and improve readability in CsvOutputComponent refactor: simplify logic in TableAutoCellRender component feat: add autoHeight property to columns in extractColumnsFromRows utility function * 🐛 (folders.py): fix issue where components and flows were not being assigned to the new folder 🐛 (folders.py): fix issue where components and flows were not being assigned to the new folder 🐛 (sideBarFolderButtons/index.tsx): fix issue where folder buttons were not taking up full width 🐛 (use-on-file-drop.tsx): fix issue where folder dragging was not being reset on drag leave 🐛 (use-on-file-drop.tsx): fix issue where folder dragging was not being reset on drag leave 🐛 (use-on-file-drop.tsx): fix issue where folder dragging was not being reset on drag leave 🐛 (entities/index.tsx): fix issue where AddFolderType was missing flows and components properties 🐛 (services/index.ts): fix issue where addFolder function was not correctly sending flows and components data * 📝 (model.py): remove unnecessary whitespace 📝 (index.tsx): remove unused 'pathname' prop 📝 (index.tsx): add 'handleAddFolder' prop to SideBarFoldersButtonsComponent 📝 (index.tsx): remove unused 'handleAddFolder' prop from SideBarButtonsComponent 📝 (index.tsx): remove unused import of DropdownButton in sideBarFolderButtons 📝 (index.tsx): add DropdownButton component to SideBarFoldersButtonsComponent 📝 (index.tsx): add 'handleAddFolder' prop to SideBarFoldersButtonsComponent 📝 (use-on-file-drop.tsx): remove console.log statements 📝 (index.tsx): remove console.log statements 📝 (index.tsx): remove unused import of FolderPlusIcon in mainPage 📝 (index.tsx): remove unused sidebarNavItems array in mainPage * Refactor: make select all look more like a button * feat: Add first step of drag and drop functionality to CollectionCardComponent * 📝 (langflow-pre.db): add new langflow-pre.db file to the backend/base/langflow directory ✨ (index.tsx): improve modal header description by dynamically displaying "Edit a folder" or "Add a new folder" based on the presence of folderToEdit prop * remove api key * remove api key * remove api key * Refactor: Update downloadFlowsFromFolders function to include folder name in response * add type to folder function * Refactor: Update chatComponent and sideBarFolderButtons components This commit refactors the chatComponent and sideBarFolderButtons components. In chatComponent: - Moved the declaration of the 'currentFlow' variable to ensure it is defined before being used. - Removed the unused 'hasIO' and 'hasStore' variables. - Reordered the imports for better organization. In sideBarFolderButtons: - Added imports for 'useStoreStore' and 'ShadTooltip' components. - Removed the unused 'hasStore', 'validApiKey', and 'hasApiKey' variables. - Removed the unused 'handleEditFolder' function. - Added a new button with an icon for sharing as a bundle, with a tooltip indicating the need to review the API key before sharing. These changes improve the code structure and remove unused code, enhancing the overall maintainability and user experience of the application. * copy folder modal structure to start bundle modal * new lock * refactor: Move no data alert rendering logic to a separate function * refactor: Move no data alert rendering logic to a separate function * add truncate to json objects * Refactor: store flow_id in ChatComponent's records in ChatComponent * 📝 (folders.py): add missing import for FolderBase model 🐛 (folders.py): fix issue where flows were not being fetched for a folder 🐛 (folders.py): fix issue where flows were not being deleted when a folder is deleted 🐛 (folders.py): fix issue where folder description was not being returned when downloading flows ✨ (folders.py): add support for uploading flows from a file 🐛 (schemas.py): fix issue where folder description was not included in FlowListReadWithFolderName schema ♻️ (sideBarButtons/index.tsx): refactor handleOpenNewFolderModal prop to be optional ✨ (sideBarFolderButtons/index.tsx): make handleChangeFolder, handleEditFolder, handleDeleteFolder, handleAddFolder optional to improve component reusability ♻️ (sideBarFolderButtons/index.tsx): refactor useFileDrop hook to use async/await syntax and separate file upload logic into a separate function ✨ (sideBarFolderButtons/index.tsx): add support for uploading flows from folders using the uploadFlowsFromFolders API ♻️ (sideBarFolderButtons/index.tsx): refactor handleFileDrop function to handle multiple files and use FormData to send file data to the server ♻️ (sideBarFolderButtons/index.tsx): refactor dragOver, dragEnter, dragLeave, and onDrop functions to remove unnecessary folderId parameter and set folderDragging state to a boolean value instead of an empty string 📝 (sidebarComponent/index.tsx): make handleOpenNewFolderModal, handleChangeFolder, handleEditFolder, handleDeleteFolder optional to allow flexibility in using the component 📝 (foldersModal/component/index.tsx): add allFlows variable to get all flows from the store and use it to filter components and flows on the folder being edited 📝 (foldersModal/hooks/submit-folder.tsx): import useNavigate from react-router-dom and use it to navigate to the folder page after creating or updating a folder 📝 (pages/MainPage/entities/index.tsx): add StarterProjectsType to define the type of starter projects 📝 (pages/MainPage/pages/mainPage/index.tsx): import useAlertStore from stores/alertStore and use it to set error data when trying to download an empty folder 📝 (services/index.ts): add StarterProjectsType import to support the new entity in the code 📝 (services/index.ts): add return type to updateFolder function to improve code clarity 📝 (services/index.ts): add return type to getFolderById function to improve code clarity 📝 (services/index.ts): add return type to getStarterProjects function to improve code clarity 📝 (services/index.ts): add folder_description property to the return type of downloadFlowsFromFolders function to provide additional information about the folder 📝 (services/index.ts): remove folderId parameter from uploadFlowsFromFolders function as it is not needed 📝 (utils/handle-download-folder.ts): add folder_name and folder_description properties to the data object to provide additional information about the folder being downloaded 📝 (SettingsPage/index.tsx): remove commented out code for unused settings options 📝 (stores/flowsManagerStore.ts): add missing comma in setCurrentFlowId function 📝 (stores/flowsManagerStore.ts): add return type to saveFlow function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to updateFlow function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to addFlow function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to deleteFlow function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to addFlowComponent function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to takeSnapshot function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to undo function to improve code clarity 📝 (stores/flowsManagerStore.ts): add return type to redo function to improve code clarity ♻️ (foldersStore.tsx): change folderDragging variable type from string to boolean to improve semantics and consistency ♻️ (foldersStore.tsx): remove unused folderId parameter from uploadFolder function ♻️ (foldersStore.tsx): remove unused setAllFlows function call ♻️ (folders/index.ts): change folderDragging variable type from string to boolean to match the updated type in foldersStore.tsx * 🐛 (folders.py): fix indentation and remove unnecessary whitespace ✨ (folders.py): add logic to handle duplicate folder names by appending a number to the folder name 📝 (folders.py): update comments and documentation * 🐛 (submit-folder.tsx): remove unnecessary comma after closing curly brace in error handling function 🐛 (index.tsx): remove unnecessary comma after closing parenthesis in state selectors ♻️ (index.tsx): refactor code to simplify logic for getting folder by ID and handling default case * refactor: Update add_row_to_table function to use list comprehension for values * Refactor: Update placeholder text capitalization in headerComponent and inputSearchComponent In headerComponent: - Changed "Select all" to "Select All" for better consistency and readability. In inputSearchComponent: - Changed "Search flows" to "Search Flows" and "Search components" to "Search Components" for better consistency and readability. These changes improve the user experience and maintain consistency in the application. * Modularized scroll fade and added it to folders * refactor(componentsComponent): remove unnecessary switch statement in handleSelectOptionsChange function feat(headerComponent): replace Select component with a Button component for delete action feat(headerComponent): add disableDelete prop to Button component to handle delete button state based on selected items * Made selector not disappear after hover if selected * fixed selector * 🐛 (folders.py): fix updating folder components and flows logic ✨ (folders.py): add support for moving excluded flows to "My Collection" folder * ♻️ (folders.py): remove unnecessary whitespace 🐛 (folders.py): fix indentation issue in update_folder function * refactor(headerComponent): replace Select component with Button component for delete action * refactor: Handle float conversion errors in validate_id method * Fix adding primary key * Refactor: remove trash from card and make checkbox always visible * Refactor: add padding on card title to avoid bugs * chore: Add h-full class to sideBarFolderButtons component * 📝 (api.tsx): add import statement for useUtilityStore from utilityStore to use the utility store in the API interceptor 📝 (api.tsx): add lastUrlCalled and setLastUrlCalled variables to store and retrieve the last URL called in the API interceptor 📝 (api.tsx): add logic to check for duplicate requests in the API interceptor based on the last URL called 📝 (api.tsx): add localStorage to store the last URL called in the API interceptor 📝 (api.tsx): add logic to add access token to every request in the API interceptor ♻️ (index.tsx): refactor selectedFolder?.flows to remove unnecessary parentheses in ComponentsComponent ♻️ (index.tsx): refactor state.searchFlowsComponents.toLowerCase() to remove unnecessary parentheses in ComponentsComponent ♻️ (index.tsx): refactor state.selectedFlowsComponentsCards to remove unnecessary parentheses in ComponentsComponent ♻️ (index.tsx): refactor (f.is_component ?? false) === is_component to remove unnecessary parentheses in ComponentsComponent 📝 (utilityStore.ts): add lastUrlCalled and setLastUrlCalled variables to utility store to store and retrieve the last URL called * 📝 (api.tsx): remove unused import of useUtilityStore from utilityStore ♻️ (api.tsx): remove unused variables lastUrlCalled and setLastUrlCalled from useUtilityStore 📝 (utilityStore.ts): remove unused variable lastUrlCalled and setLastUrlCalled from utilityStore * refactor: Add flow_id parameter to log_message function * fix undefined bug * refactor: Update add_row_to_table function to use list comprehension for values * refactor: Add flow_id field to FlowCreate and FlowRead models * refactor: Update FlowCreate and FlowRead models to use folder_id instead of flow_id * Refactor: make drag n drop works in the entire screen * ⬆️ (frontend/package.json): upgrade "@playwright/test" dependency from version 1.43.1 to 1.44.0 ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of XPath locator with text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Actions" and "Delete" text locators with "icon-Trash2" locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Delete" text locator with "Delete" button locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Select All" text locator with "Select All" button locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Unselect All" text locator with "Unselect All" button locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Actions" text locator with "icon-Trash2" locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Delete" text locator with "Delete" button locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "Select All" text locator with "Select All" button locator for better specificity ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end-to-end/actionsMainPage.spec.ts): replace the usage of "New Project" XPath locator with "New Project" text locator for better readability and maintainability ✨ (frontend/tests/end ✨ (floatComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (flowPage.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (flowSettings.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (folders.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (folders.spec.ts): update selector for clicking "New Folder" button to improve test reliability ✨ (folders.spec.ts): update selector for clicking "Edit Folder" button to improve test reliability ✨ (folders.spec.ts): update selector for dispatching drop event to improve test reliability ✨ (globalVariables.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (group.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (inputComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (inputListComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (intComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (keyPairListComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (langflowShortcuts.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (nestedComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (promptModalComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (python_api_generation.spec.ts): update selector for clicking "New Project" button to improve test reliability ✨ (saveComponents.spec.ts): update selector for clicking "New Project" button to improve test reliability and maintainability ✨ (store.spec.ts): update selector for clicking "New Project" button to improve test reliability and maintainability ✨ (textAreaModalComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability and maintainability ✨ (textInputOutput.spec.ts): update selector for clicking "New Project" button to improve test reliability and maintainability ✨ (toggleComponent.spec.ts): update selector for clicking "New Project" button to improve test reliability and maintainability ✨ (tweaks_test.spec.ts): update selector for clicking "New Project" button to improve test reliability and maintainability 📝 (test-results/.last-run.json): add .last-run.json file to track test run status * Refactor: make drag n drop only happen in the folder div * refactor: Fix incorrect variable assignment in memory.py * refactor: Update data retrieval in InterfaceVertex to use record data instead of model_dump * refactor: Update DateReader component to use 12-hour time format * refactor: Update activeTab state variable in FlowLogsModal component * refactor: Update FlowCreate and FlowRead models to use folder_id instead of flow_id * refactor: Update hover animation in ObjectRender component * refactor: Update icon in FlowLogsModal component * add table preview on IO * refactor: Add truncate class to StringReader component * refactor: Add TableAutoCellRender support for displaying badges * refactor: Add filter option to extractColumnsFromRows function * update card width * style(IOFieldView): update className condition to dynamically set height based on 'left' prop value * fix(IOFieldView): update height class value from "h-36" to "h-56" for better UI consistency fix(FlowLogsModal): update BaseModal.Header description based on activeTab value for dynamic content display * Update BaseModal.Header description in FlowLogsModal component * refactor: Update dict_values_to_string function to use deepcopy for dictionary copy * 📝 (sideBarFolderButtons): Remove unused variables and improve code readability 📝 (api): Remove unnecessary error handling and improve code readability 📝 (componentsComponent): Remove unused variables and improve code readability 📝 (foldersStore): Remove unnecessary error handling and improve code readability * 📝 (App.tsx): remove unnecessary call to getFoldersApi() before setting loading state to false ♻️ (App.tsx): refactor code to navigate to "/all" instead of "/flows" when window location pathname is "/" * refactor: Update FlowCreate and FlowRead models to use folder_id instead of flow_id * refactor: Update FlowCreate and FlowRead models to use folder_id instead of flow_id * refactor: Update MyCollectionComponent to use "type" prop instead of "is_component" * refactor: Update error handling in API interceptor * refactor: Update StoreGuard component to navigate to "/all" instead of "/flows" when there is no store * chore(constants.ts): add DEFAULT_FOLDER constant for improved code readability refactor(index.tsx): update title and description logic to use constants for consistency feat(foldersStore.tsx): utilize DEFAULT_FOLDER constant for folder name comparison to improve maintainability and readability * lint * reduce navbar size * chore: Update className in mainPage/index.tsx to use relative width for folder button * refactor: Remove unnecessary call to getFoldersApi() and refactor code in App.tsx * refactor: Update default column width in TableComponent * Refactor: Change folders actions buttons to another location * ✨ (cardComponent/index.tsx): refactor useState calls to remove unnecessary commas and improve code readability 📝 (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ♻️ (cardComponent/index.tsx): remove unnecessary semicolon and fix indentation ✨ (cardComponent/index.tsx): refactor onClick handler to remove unnecessary ternary operator ✨ (use-on-file-drop.tsx): refactor handleFileDrop function to use uploadFormData function for better code organization and readability * get error from folder * refactor: Handle error when updating folder in submit-folder.tsx * refactor: Update submit-folder.tsx to handle folder submission and error handling consistently * Refactor: Rename folders buttons and add search input icon * Fixed padding on select * Fix: Store tags displaying as a column * fixed checkbox color on card * Implemented draggable small folder * Refactor: Add padding to search input * fixed flow not dropping * Fixed flow and component dropping bugs * Refactor: Update ComponentsComponent to improve code readability and remove unnecessary code * Fixed deleting issue when it doesnt update on creating new folder * refactor: Update activeTab name in FlowLogsModal component * Removed onDelete of card component * update logs modal postion * Refactor: Make folders buttons the same size * Refactor: Position download folder button in a better parent * Refactor: Update folder_id when moving a flow to a different folder * Refactor: Update folder_id when moving a flow to a different folder * Refactor: Update folder_id when moving a flow to a different folder * chore: Remove unnecessary comma in API interceptor code * Refactor: Remove unused code and improve folder button behavior * Refactor: Improve code readability and remove unnecessary code in ComponentsComponent * Refactor: Update folder_id when moving a flow to a different folder * feat(sidebarComponent): add support for downloading folders with flows fix(constants): change DEFAULT_FOLDER constant value to "My Projects" for clarity refactor(emptyComponent): update text color and alignment for better readability style(headerTabsSearchComponent): remove download button from header tabs search component style(inputSearchComponent): adjust width of input search component for better UI consistency * merge on dev * fixing migration * removing db * 📝 (use-on-file-drop.tsx): add import statement for useFlowsManagerStore to use the refreshFlows function ✨ (use-on-file-drop.tsx): call refreshFlows function after uploading flows to update the flows list 📝 (foldersStore.tsx): remove unnecessary comma and fix indentation ✨ (foldersStore.tsx): call refreshFlows function after uploading flows to update the flows list * feat(modals): update folder modal title and icon * fix(cardsWrapComponent): add useEffect hook to handle visibility change when tab becomes visible to reset hover state and improve user experience * 🐛 (popover/index.tsx): fix indentation and remove unnecessary ternary operator 🐛 (popover/index.tsx): fix className prop to prevent it from being undefined 🐛 (inputComponent/index.tsx): prevent event propagation and default behavior when clicking on the button inside InputComponent * ✨ (index.tsx): add useEffect import to fix missing dependency warning and improve code readability ♻️ (index.tsx): remove unused useEffect function implementation to clean up code * ✨ (foldersStore.tsx): add call to refreshFlows() method in useFlowsManagerStore to update flows after loading folders * fix(langflow): add missing index 'ix_flow_folder_id' on 'flow' table to improve database performance * fix: add missing index 'ix_flow_folder_id' on 'flow' table * refactor(foldersModal): improve folder icon naming for better clarity and consistency * feat: add kill command to stop backend server * 📝 (App.tsx): remove unnecessary trailing commas in the useAlertStore and useGlobalVariablesStore hooks 📝 (mainPage/index.tsx): remove unused import and useEffect hook that fetches folders ♻️ (temp): delete unused temp folder * ✨ (submit-folder.tsx): update navigate path to use "all" instead of "flows" to improve consistency and clarity ✨ (mainPage/index.tsx): add call to getFoldersApi on page load to ensure folders are up to date 🐛 (chatInputOutput.spec.ts): fix selector for input-openai_api_key to use popover-anchor-input-openai_api_key 🐛 (chatInputOutput.spec.ts): fix selector for input-sender_name to use popover-anchor-input-sender_name ♻️ (chatInputOutput.spec.ts): refactor code to improve readability and remove unnecessary code ♻️ (folders.spec.ts): refactor code to improve readability and remove unnecessary code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements to match changes in the frontend code ✨ (inputComponent.spec.ts): update selectors for input elements 🐛 (tweaks_test.spec.ts): fix selectors for input fields to match updated HTML structure * 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary comma at the end of the function 🐛 (api.tsx): remove unnecessary * refactor(modals): remove commented out code in FolderForms component * 📝 (cardComponent/index.tsx): add aria-label to checkbox component for accessibility improvement ✨ (deleteComponentFlows.spec.ts): update delete flow and delete component tests to use checkbox component instead of hovering over card and clicking trash icon for better test stability and reliability ✨ (group.spec.ts): update group node test to use popover anchor input for editing group title instead of directly editing the title for better test stability and reliability ✨ (logs.spec.ts): update logs test to click on "New Project" button by text instead of using locator for better test stability and reliability * ✅ (folders.spec.ts): remove unnecessary code that was clicking on elements and pressing the Escape key ♻️ (folders.spec.ts): refactor code to improve readability and remove unused variables ✨ (folders.spec.ts): add test to verify the ability to change the flow folder * fix(folders.py): handle case where no flows are found by setting flows to an empty list instead of raising a 404 error * ♻️ (folders.py): rename the function `update_folder` to `move_to_folder` to improve clarity and consistency with the endpoint URL * 📝 (folders.py): remove unused move_to_folder endpoint 🔧 (use-on-file-drop.tsx): update import statements for API controllers and services ♻️ (use-on-file-drop.tsx): refactor uploadFromDragCard function to use updateFlowInDatabase function instead of moveFlowToFolder function ♻️ (index.ts): refactor updateFlowInDatabase function to handle null folder_id values correctly ♻️ (index.tsx): refactor HomePage component to remove unnecessary setTimeout function and reduce delay for getFoldersApi function call * refactor: remove unused handleOpenNewFolderModal function and update folder creation logic * refactor(pyproject.toml): update version to 1.0.0a35 * refactor: remove duplicate logout response in login.py * Bump langflow-base version to 0.0.46 and annotated-types version to 0.7.0 * refactor(folders.py): simplify condition checks for empty lists using truthy values perf(folders.py): optimize code by using len() function instead of __len__() method for list length calculation perf(folders.py): improve code readability by using len() function instead of __len__() method for list length calculation perf(folders.py): enhance code efficiency by using truthy values instead of comparing list length to zero * refactor: add new folder functionality to sidebar component * 📝 (sideBarFolderButtons/index.tsx): remove unused imports and fix formatting 📝 (sideBarFolderButtons/index.tsx): remove debugger statement 📝 (sideBarFolderButtons/index.tsx): fix indentation 📝 (sideBarFolderButtons/index.tsx): remove unnecessary comma 📝 (sideBarFolderButtons/index.tsx): remove unnecessary parentheses 📝 (sideBarFolderButtons/index.tsx): remove unnecessary semicolon 📝 (sideBarFolderButtons/index.tsx): remove unnecessary debugger statement 📝 (API/api.tsx): remove unnecessary comma 📝 (API/api.tsx): remove unnecessary parentheses 📝 (API/api.tsx): remove unnecessary semicolon 📝 (index.tsx): remove unnecessary comment and fix formatting 📝 (buildUtils.ts): remove unnecessary debugger statement * refactor(folders.py): update folder creation logic to handle duplicate names * 📝 (folders.py): import the `or_` function from `sqlalchemy` to use in the query for selecting folders ♻️ (folders.py): refactor the query for selecting folders to include folders with `user_id` as `None` 📝 (folders.py): remove the `read_starter_folders` endpoint as it is no longer needed 📝 (App.tsx): remove the call to `getFoldersApi` as it is no longer needed ♻️ (api.tsx): remove duplicate code for handling duplicate requests ♻️ (api.tsx): remove unnecessary code for handling duplicate requests ♻️ (api.tsx): remove unnecessary code for handling duplicate requests ♻️ (api.tsx): remove unnecessary code for handling duplicate requests ♻️ (index.ts): remove the unused `StarterProjectsType` import and the `getStarterProjects` function ✨ (flowsManagerStore.ts): Remove unused import of getStarterProjects function ♻️ (flowsManagerStore.ts): Refactor code to improve readability and remove unnecessary code duplication 📝 (flowsManagerStore.ts): Add comments to improve code documentation ♻️ (foldersStore.tsx): Refactor code to improve readability and remove unnecessary code duplication 📝 (foldersStore.tsx): Add comments to improve code documentation ♻️ (foldersStore.tsx): Refactor code to improve readability and remove unnecessary code duplication 📝 (foldersStore.tsx): Add comments to improve code documentation * 📝 (api.tsx): temporarily comment out code related to duplicate request prevention to investigate a bug 🐛 (api.tsx): fix issue with duplicate request prevention logic * 🐛 (api.tsx): fix issue with duplicate requests being made 📝 (api.tsx): add local storage to store the last URL and method called to check for duplicate requests * ✨ (index.tsx): add StrictMode component to enable additional React checks and warnings during development 📝 (index.tsx): wrap the entire app with StrictMode component to catch potential problems and deprecated features in the codebase * refactor(tableComponent): remove unused functions getRowHeight, onGridReady, onFirstDataRendered, and onGridSizeChanged to improve code readability and maintainability * Fixed naming on folders dragged from one folder to another * removed console.log * Added handling to check if data of request is the same * Feat: Edit folder name with double click * Fix: folder name not changing for a second time * 📝 (App.tsx): add useTrackLastVisitedPath hook to track the last visited path in the app ♻️ (MenuBar/index.tsx): remove unused imports and props from MenuBar component 📝 (MenuBar/index.tsx): remove removeFunction prop from MenuBar component as it is not used ♻️ (MenuBar/index.tsx): remove unused nodes variable from MenuBar component 📝 (MenuBar/index.tsx): remove unused import of Node from reactflow in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of UPLOAD_ERROR_ALERT from alerts_constants in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of SAVED_HOVER from constants in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of ExportModal from modals/exportModal in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of ShadTooltip from shadTooltipComponent in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of Button from ui/button in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of cn from utils/utils in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of IconComponent from genericIconComponent in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useFlowsManagerStore from stores/flowsManagerStore in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useFlowStore from stores/flowStore in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useDarkStore from stores/darkStore in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useAlertStore from stores/alertStore in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useTypesStore from stores/typesStore in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useGlobalVariablesStore from stores/globalVariables in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useStoreStore from stores/storeStore in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from react-router-dom in MenuBar component ♻️ (MenuBar/index.tsx): remove unused import of useNavigate from ✨ (use-on-file-drop.tsx): add support for setting folderIdDragging in useFileDrop hook to track the dragged folder ID 📝 (use-on-file-drop.tsx): remove unused import and console.log statement ✨ (constants.ts): add LOCATIONS_TO_RETURN constant to store the list of locations to return ♻️ (parameterComponent/index.tsx): remove console.log statement ✨ (use-track-last-visited-path.tsx): create useTrackLastVisitedPath hook to track the last visited path 🔧 (darkStore.ts): create darkStore to manage dark mode state and fetch GitHub stars and version ♻️ (foldersStore.tsx): refactor useFolderStore to call setAllFlows after uploading flows 🔧 (locationStore.ts): create locationStore to manage route history 🔧 (storeStore.ts): create storeStore to manage store and API key state 📝 (location/index.ts): define LocationStoreType for locationStore ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of function parameters ♻️ (utils.ts): remove unnecessary comma at the end of * feat: Add useFlowStore import to sidebarComponent * refactor(use-on-file-drop): Improve folder dragging functionality and remove unused code * refactor(use-on-file-drop): Improve folder dragging functionality and remove unused code * feat: Add AUTHORIZED_DUPLICATE_REQUESTS constant for authorized duplicate requests * refactor: Update FlowPage component to handle non-existing flows and redirect to "/all" * feat: Add AUTHORIZED_DUPLICATE_REQUESTS constant and handle duplicate requests in ApiInterceptor * refactor: Improve folder dragging functionality and remove unused code * ✅ (chatInputOutput.spec.ts): remove unnecessary code related to environment variables and modals ♻️ (chatInputOutput.spec.ts): refactor code to improve readability and remove duplicated code ✨ (chatInputOutput.spec.ts): add test for "chat_io_teste" scenario 📝 (chatInputOutput.spec.ts): update timeout value for better test performance ✨ (chatInputOutputUser.spec.ts): add end-to-end test for user interaction with chat using input/output ✨ (globalVariables.spec.ts): fix click on icon-Globe to add new variable ✨ (inputListComponent.spec.ts): fix getByTestId locator for vectorstoresAstra DB and input-list-plus-btn-edit_metadata_indexing_include-* * move doubleClick event to father div * refactor: Improve folder dragging functionality and remove unused code * Feat: Make input lose focus while editing a folder name and press enter or esc * Refactor: Esc key on edit folder name cancel the edition intead of confirm it * ⬆️ (poetry.lock): upgrade langflow-base package version from 0.0.46 to 0.0.47 ⬆️ (poetry.lock): add new wheel files for lxml package versions 5.2.2 for different platforms ⬆️ (poetry.lock): add new wheel files for lxml package versions 5.2.2 for different platforms * add alert for streamed messages on session logs * fix stream check * refactor: Update flowsManagerStore and reactflowUtils to use folderId parameter in createNewFlow function * refactor(folders.py): improve folder creation logic to handle duplicate folder names more effectively refactor(folders.py): enhance folder reading logic to handle edge cases more robustly * chore(api): remove unused import statement in utils.py chore(api): remove unused import statement in endpoints.py chore(api): remove unused import statement in folders.py refactor(vectorsearch): update field_typing import in CouchbaseSearch.py to remove unused imports and improve code readability refactor(vectorsearch): update field names and formatting in CouchbaseSearchComponent class in CouchbaseSearch.py * chore: Update pyproject.toml with youtube-transcript-api dependency * chore(pyproject.toml): update assemblyai, litellm, and chromadb versions chore(pyproject.toml): update langchain-astradb version to 0.3.0 feat(pyproject.toml): add markdown dependency at version 3.6 * feat(pyproject.toml): update dependencies versions for google-api-python-client, fake-useragent, qdrant-client, cohere, faiss-cpu, langfuse, mypy, ruff, pytest, types-requests, requests, pytest-cov, pytest-mock, pytest-xdist in the main project feat(pyproject.toml): update dependencies versions for fastapi, langchain, sqlmodel, pydantic, pydantic-settings, pypdf, emoji in the backend base project * refactor: Update imports and dependencies for langchain_core in langflow codebase * refactor: Update AzureOpenAIEmbeddings and AzureChatOpenAISpecs to use SecretStr for api_key parameter --------- Co-authored-by: Lucas Oliveira Co-authored-by: Gabriel Luiz Freitas Almeida Co-authored-by: cristhianzl Co-authored-by: igorrCarvalho Co-authored-by: ogabrielluiz --- docs/static/data/AstraDB-RAG-Flows.json | 6504 ++++++++--------- poetry.lock | 692 +- pyproject.toml | 40 +- src/backend/base/langflow/api/utils.py | 1 - src/backend/base/langflow/api/v1/callback.py | 3 +- src/backend/base/langflow/api/v1/endpoints.py | 1 - src/backend/base/langflow/api/v1/folders.py | 30 +- .../base/langflow/base/prompts/api_utils.py | 2 +- .../langflow/components/agents/JsonAgent.py | 3 +- .../agents/OpenAIConversationalAgent.py | 7 +- .../embeddings/AmazonBedrockEmbeddings.py | 3 +- .../embeddings/AzureOpenAIEmbeddings.py | 12 +- .../components/embeddings/OllamaEmbeddings.py | 3 +- .../memories/AstraDBMessageReader.py | 8 +- .../memories/AstraDBMessageWriter.py | 22 +- .../model_specs/AnthropicLLMSpecs.py | 3 +- .../model_specs/AzureChatOpenAISpecs.py | 12 +- .../components/retrievers/AmazonKendra.py | 3 +- .../components/retrievers/MetalRetriever.py | 3 +- .../retrievers/VectaraSelfQueryRetriver.py | 7 +- .../textsplitters/CharacterTextSplitter.py | 3 +- .../LanguageRecursiveTextSplitter.py | 4 +- .../RecursiveCharacterTextSplitter.py | 3 +- .../langflow/components/toolkits/Metaphor.py | 6 +- .../components/toolkits/VectorStoreInfo.py | 2 +- .../components/tools/PythonREPLTool.py | 3 +- .../vectorsearch/CouchbaseSearch.py | 22 +- .../components/vectorsearch/RedisSearch.py | 3 +- .../components/vectorsearch/WeaviateSearch.py | 3 +- .../components/vectorsearch/pgvectorSearch.py | 3 +- .../components/vectorstores/AstraDB.py | 3 +- .../components/vectorstores/Chroma.py | 6 +- .../components/vectorstores/Couchbase.py | 29 +- .../langflow/components/vectorstores/FAISS.py | 5 +- .../components/vectorstores/Pinecone.py | 5 +- .../components/vectorstores/Qdrant.py | 5 +- .../langflow/components/vectorstores/Redis.py | 5 +- .../vectorstores/SupabaseVectorStore.py | 5 +- .../components/vectorstores/Weaviate.py | 7 +- .../components/vectorstores/pgvector.py | 5 +- .../base/langflow/field_typing/constants.py | 21 +- .../Basic Prompting (Hello, world!).json | 1676 ++--- .../Langflow Blog Writter.json | 2073 +++--- .../Langflow Document QA.json | 1942 +++-- .../Langflow Memory Conversation.json | 2395 +++--- .../Langflow Prompt Chaining.json | 3317 ++++----- .../VectorStore-RAG-Flows.json | 4 +- .../base/langflow/interface/agents/custom.py | 20 +- .../langflow/interface/agents/prebuilt.py | 4 +- .../base/langflow/interface/chains/custom.py | 5 +- .../base/langflow/interface/custom_lists.py | 4 +- .../langflow/interface/importing/utils.py | 6 +- .../langflow/interface/initialize/loading.py | 11 +- .../langflow/interface/initialize/utils.py | 3 +- .../interface/initialize/vector_store.py | 2 +- .../base/langflow/interface/prompts/custom.py | 3 +- .../langflow/interface/tools/constants.py | 2 +- .../base/langflow/interface/tools/custom.py | 3 +- .../base/langflow/interface/tools/util.py | 3 +- src/backend/base/langflow/interface/utils.py | 2 +- src/backend/base/langflow/processing/base.py | 2 +- .../base/langflow/processing/process.py | 2 +- .../template/frontend_node/textsplitters.py | 3 +- src/backend/base/poetry.lock | 429 +- src/backend/base/pyproject.toml | 14 +- src/frontend/src/App.tsx | 41 +- .../utils/sort-by-name.tsx | 2 +- .../cardComponent/utils/convert-test-name.tsx | 2 +- .../components/menuBar/index.tsx | 16 +- .../src/components/headerComponent/index.tsx | 58 +- .../src/components/inputComponent/index.tsx | 6 + .../components/sideBarButtons/index.tsx | 6 +- .../components/sideBarFolderButtons/index.tsx | 312 +- .../hooks/use-on-file-drop.tsx | 29 +- .../src/components/sidebarComponent/index.tsx | 11 +- .../src/components/tableComponent/index.tsx | 49 - src/frontend/src/constants/constants.ts | 11 + src/frontend/src/controllers/API/api.tsx | 15 +- .../components/parameterComponent/index.tsx | 2 - .../src/customNodes/utils/get-field-title.tsx | 14 +- .../src/customNodes/utils/sort-fields.tsx | 72 +- .../src/hooks/use-track-last-visited-path.tsx | 14 + .../modals/apiModal/utils/get-curl-code.tsx | 16 +- .../apiModal/utils/get-python-api-code.tsx | 28 +- .../modals/apiModal/utils/get-python-code.tsx | 15 +- .../modals/apiModal/utils/get-widget-code.tsx | 16 +- .../src/modals/apiModal/utils/tabs-array.tsx | 88 +- .../src/modals/flowLogsModal/index.tsx | 29 +- src/frontend/src/modals/shareModal/index.tsx | 6 +- .../modals/shareModal/utils/get-tags-ids.tsx | 12 +- .../PageComponent/utils/get-random-name.tsx | 58 +- .../extraSidebarComponent/index.tsx | 33 +- .../utils/sensitive-sort.tsx | 43 +- src/frontend/src/pages/FlowPage/index.tsx | 12 +- .../src/pages/MainPage/entities/index.tsx | 3 +- .../src/pages/MainPage/services/index.ts | 23 +- .../stores/{darkStore.tsx => darkStore.ts} | 2 +- src/frontend/src/stores/flowsManagerStore.ts | 78 +- src/frontend/src/stores/foldersStore.tsx | 62 +- src/frontend/src/stores/locationStore.ts | 21 + .../stores/{storeStore.tsx => storeStore.ts} | 0 src/frontend/src/types/components/index.ts | 2 + .../src/types/zustand/folders/index.ts | 4 +- .../src/types/zustand/location/index.ts | 4 + src/frontend/src/utils/buildUtils.ts | 1 - src/frontend/src/utils/reactflowUtils.ts | 10 +- .../tests/end-to-end/chatInputOutput.spec.ts | 97 +- .../end-to-end/chatInputOutputUser.spec.ts | 92 + .../tests/end-to-end/globalVariables.spec.ts | 5 +- .../end-to-end/inputListComponent.spec.ts | 20 +- 110 files changed, 10155 insertions(+), 10717 deletions(-) create mode 100644 src/frontend/src/hooks/use-track-last-visited-path.tsx rename src/frontend/src/stores/{darkStore.tsx => darkStore.ts} (97%) create mode 100644 src/frontend/src/stores/locationStore.ts rename src/frontend/src/stores/{storeStore.tsx => storeStore.ts} (100%) create mode 100644 src/frontend/src/types/zustand/location/index.ts create mode 100644 src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts diff --git a/docs/static/data/AstraDB-RAG-Flows.json b/docs/static/data/AstraDB-RAG-Flows.json index a445f5123..d38364b4a 100644 --- a/docs/static/data/AstraDB-RAG-Flows.json +++ b/docs/static/data/AstraDB-RAG-Flows.json @@ -1,3403 +1,3147 @@ { - "id": "51e2b78a-199b-4054-9f32-e288eef6924c", - "data": { - "nodes": [ - { - "id": "ChatInput-yxMKE", - "type": "genericNode", - "position": { - "x": 1195.5276981160775, - "y": 209.421875 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "what is a line" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": [ - "Text", - "str", - "object", - "Record" - ], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-yxMKE" - }, - "selected": false, - "width": 384, - "height": 383 + "id": "51e2b78a-199b-4054-9f32-e288eef6924c", + "data": { + "nodes": [ + { + "id": "ChatInput-yxMKE", + "type": "genericNode", + "position": { + "x": 1195.5276981160775, + "y": 209.421875 + }, + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "what is a line" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "id": "TextOutput-BDknO", - "type": "genericNode", - "position": { - "x": 2322.600672827879, - "y": 604.9467307442569 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": [ - "Record", - "Text" - ], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": [ - "object", - "Text", - "str" - ], - "display_name": "Extracted Chunks", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-BDknO" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 2322.600672827879, - "y": 604.9467307442569 - }, - "dragging": false + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": ["Text", "str", "object", "Record"], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null }, - { - "id": "OpenAIEmbeddings-ZlOk1", - "type": "genericNode", - "position": { - "x": 1183.667250865064, - "y": 687.3171828430261 - }, - "data": { - "type": "OpenAIEmbeddings", - "node": { - "template": { - "allowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "allowed_special", - "display_name": "Allowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "client": { - "type": "Any", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "client", - "display_name": "Client", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=openai_api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_headers": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_headers", - "display_name": "Default Headers", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_query": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_query", - "display_name": "Default Query", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "deployment": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "deployment", - "display_name": "Deployment", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "disallowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [ - "all" - ], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "disallowed_special", - "display_name": "Disallowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "embedding_ctx_length": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 8191, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding_ctx_length", - "display_name": "Embedding Context Length", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_retries": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 6, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_retries", - "display_name": "Max Retries", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "name": "model", - "display_name": "Model", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "" - }, - "openai_api_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_type", - "display_name": "OpenAI API Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_version": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_version", - "display_name": "OpenAI API Version", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_organization": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_organization", - "display_name": "OpenAI Organization", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_proxy": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_proxy", - "display_name": "OpenAI Proxy", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "request_timeout": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "request_timeout", - "display_name": "Request Timeout", - "advanced": true, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "show_progress_bar": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "show_progress_bar", - "display_name": "Show Progress Bar", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "skip_empty": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "skip_empty", - "display_name": "Skip Empty", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_enable": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_enable", - "display_name": "TikToken Enable", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_model_name", - "display_name": "TikToken Model Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Generate embeddings using OpenAI models.", - "base_classes": [ - "Embeddings" - ], - "display_name": "OpenAI Embeddings", - "documentation": "", - "custom_fields": { - "openai_api_key": null, - "default_headers": null, - "default_query": null, - "allowed_special": null, - "disallowed_special": null, - "chunk_size": null, - "client": null, - "deployment": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, - "output_types": [ - "Embeddings" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "OpenAIEmbeddings-ZlOk1" - }, - "selected": false, - "width": 384, - "height": 383, - "dragging": false + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-yxMKE" + }, + "selected": false, + "width": 384, + "height": 383 + }, + { + "id": "TextOutput-BDknO", + "type": "genericNode", + "position": { + "x": 2322.600672827879, + "y": 604.9467307442569 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": ["Record", "Text"], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "id": "OpenAIModel-EjXlN", - "type": "genericNode", - "position": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": [\n \"gpt-4-turbo-preview\",\n \"gpt-3.5-turbo\",\n \"gpt-4-0125-preview\",\n \"gpt-4-1106-preview\",\n \"gpt-4-vision-preview\",\n \"gpt-3.5-turbo-0125\",\n \"gpt-3.5-turbo-1106\",\n ],\n \"value\": \"gpt-4-turbo-preview\",\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str,\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=openai_api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-4-0125-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-1106" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": true, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "object", - "Text", - "str" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-EjXlN" - }, - "selected": true, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "dragging": false + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": ["object", "Text", "str"], + "display_name": "Extracted Chunks", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null }, - { - "id": "Prompt-xeI6K", - "type": "genericNode", - "position": { - "x": 2969.0261961391298, - "y": 442.1613649809069 + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-BDknO" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 2322.600672827879, + "y": 604.9467307442569 + }, + "dragging": false + }, + { + "id": "OpenAIEmbeddings-ZlOk1", + "type": "genericNode", + "position": { + "x": 1183.667250865064, + "y": 687.3171828430261 + }, + "data": { + "type": "OpenAIEmbeddings", + "node": { + "template": { + "allowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": [], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "allowed_special", + "display_name": "Allowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "chunk_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 1000, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_size", + "display_name": "Chunk Size", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "client": { + "type": "Any", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "client", + "display_name": "Client", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=openai_api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_headers": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_headers", + "display_name": "Default Headers", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_query": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_query", + "display_name": "Default Query", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "deployment": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "deployment", + "display_name": "Deployment", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "disallowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": ["all"], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "disallowed_special", + "display_name": "Disallowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "embedding_ctx_length": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 8191, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding_ctx_length", + "display_name": "Embedding Context Length", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_retries": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 6, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_retries", + "display_name": "Max Retries", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "name": "model", + "display_name": "Model", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "" + }, + "openai_api_type": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_type", + "display_name": "OpenAI API Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_version": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_version", + "display_name": "OpenAI API Version", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_organization": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_organization", + "display_name": "OpenAI Organization", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_proxy": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_proxy", + "display_name": "OpenAI Proxy", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "request_timeout": { + "type": "float", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "request_timeout", + "display_name": "Request Timeout", + "advanced": true, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "context": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "context", - "display_name": "context", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "question": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "question", - "display_name": "question", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "object", - "Text", - "str" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "context", - "question" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-xeI6K", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 477, - "positionAbsolute": { - "x": 2969.0261961391298, - "y": 442.1613649809069 - }, - "dragging": false + "load_from_db": false, + "title_case": false + }, + "show_progress_bar": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "show_progress_bar", + "display_name": "Show Progress Bar", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "skip_empty": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "skip_empty", + "display_name": "Skip Empty", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_enable": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_enable", + "display_name": "TikToken Enable", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_model_name", + "display_name": "TikToken Model Name", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "id": "ChatOutput-Q39I8", - "type": "genericNode", - "position": { - "x": 3887.2073667611485, - "y": 588.4801225794856 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "object", - "Text", - "Record", - "str" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-Q39I8" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 3887.2073667611485, - "y": 588.4801225794856 - }, - "dragging": false + "description": "Generate embeddings using OpenAI models.", + "base_classes": ["Embeddings"], + "display_name": "OpenAI Embeddings", + "documentation": "", + "custom_fields": { + "openai_api_key": null, + "default_headers": null, + "default_query": null, + "allowed_special": null, + "disallowed_special": null, + "chunk_size": null, + "client": null, + "deployment": null, + "embedding_ctx_length": null, + "max_retries": null, + "model": null, + "model_kwargs": null, + "openai_api_base": null, + "openai_api_type": null, + "openai_api_version": null, + "openai_organization": null, + "openai_proxy": null, + "request_timeout": null, + "show_progress_bar": null, + "skip_empty": null, + "tiktoken_enable": null, + "tiktoken_model_name": null }, - { - "id": "File-t0a6a", - "type": "genericNode", - "position": { - "x": 2257.233450682836, - "y": 1747.5389618367233 + "output_types": ["Embeddings"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "OpenAIEmbeddings-ZlOk1" + }, + "selected": false, + "width": 384, + "height": 383, + "dragging": false + }, + { + "id": "OpenAIModel-EjXlN", + "type": "genericNode", + "position": { + "x": 3410.117202077183, + "y": 431.2038048137648 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": [\n \"gpt-4-turbo-preview\",\n \"gpt-3.5-turbo\",\n \"gpt-4-0125-preview\",\n \"gpt-4-1106-preview\",\n \"gpt-4-vision-preview\",\n \"gpt-3.5-turbo-0125\",\n \"gpt-3.5-turbo-1106\",\n ],\n \"value\": \"gpt-4-turbo-preview\",\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str,\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=openai_api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-3.5-turbo", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-4-0125-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-1106" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": true, + "title_case": false, + "input_types": ["Text"], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 }, - "data": { - "type": "File", - "node": { - "template": { - "path": { - "type": "file", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [ - ".txt", - ".md", - ".mdx", - ".csv", - ".json", - ".yaml", - ".yml", - ".xml", - ".html", - ".htm", - ".pdf", - ".docx" - ], - "file_path": "51e2b78a-199b-4054-9f32-e288eef6924c/Langflow conversation.pdf", - "password": false, - "name": "path", - "display_name": "Path", - "advanced": false, - "dynamic": false, - "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "silent_errors": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "silent_errors", - "display_name": "Silent Errors", - "advanced": true, - "dynamic": false, - "info": "If true, errors will not raise an exception.", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "A generic file loader.", - "icon": "file-text", - "base_classes": [ - "Record" - ], - "display_name": "File", - "documentation": "", - "custom_fields": { - "path": null, - "silent_errors": null - }, - "output_types": [ - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "File-t0a6a" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 2257.233450682836, - "y": 1747.5389618367233 - }, - "dragging": false + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" }, - { - "id": "RecursiveCharacterTextSplitter-tR9QM", - "type": "genericNode", - "position": { - "x": 2791.013514133929, - "y": 1462.9588953494142 - }, - "data": { - "type": "RecursiveCharacterTextSplitter", - "node": { - "template": { - "inputs": { - "type": "Document", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "inputs", - "display_name": "Input", - "advanced": false, - "input_types": [ - "Document", - "Record" - ], - "dynamic": false, - "info": "The texts to split.", - "load_from_db": false, - "title_case": false - }, - "chunk_overlap": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 200, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_overlap", - "display_name": "Chunk Overlap", - "advanced": false, - "dynamic": false, - "info": "The amount of overlap between chunks.", - "load_from_db": false, - "title_case": false - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": false, - "dynamic": false, - "info": "The maximum length of each chunk.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "separators": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "separators", - "display_name": "Separators", - "advanced": false, - "dynamic": false, - "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": [ - "" - ] - }, - "_type": "CustomComponent" - }, - "description": "Split text into chunks of a specified length.", - "base_classes": [ - "Record" - ], - "display_name": "Recursive Character Text Splitter", - "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", - "custom_fields": { - "inputs": null, - "separators": null, - "chunk_size": null, - "chunk_overlap": null - }, - "output_types": [ - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "RecursiveCharacterTextSplitter-tR9QM" - }, - "selected": false, - "width": 384, - "height": 501, - "positionAbsolute": { - "x": 2791.013514133929, - "y": 1462.9588953494142 - }, - "dragging": false + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["object", "Text", "str"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null }, - { - "id": "AstraDBSearch-41nRz", - "type": "genericNode", - "position": { - "x": 1723.976434815103, - "y": 277.03317407245913 - }, - "data": { - "type": "AstraDBSearch", - "node": { - "template": { - "embedding": { - "type": "Embeddings", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding", - "display_name": "Embedding", - "advanced": false, - "dynamic": false, - "info": "Embedding to use", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input Value", - "advanced": false, - "dynamic": false, - "info": "Input value to search", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "api_endpoint": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "api_endpoint", - "display_name": "API Endpoint", - "advanced": false, - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "load_from_db": true, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "ASTRA_DB_API_ENDPOINT" - }, - "batch_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "batch_size", - "display_name": "Batch Size", - "advanced": true, - "dynamic": false, - "info": "Optional number of records to process in a single batch.", - "load_from_db": false, - "title_case": false - }, - "bulk_delete_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_delete_concurrency", - "display_name": "Bulk Delete Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_batch_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_batch_concurrency", - "display_name": "Bulk Insert Batch Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_overwrite_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_overwrite_concurrency", - "display_name": "Bulk Insert Overwrite Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "collection_indexing_policy": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_indexing_policy", - "display_name": "Collection Indexing Policy", - "advanced": true, - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "load_from_db": false, - "title_case": false - }, - "collection_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_name", - "display_name": "Collection Name", - "advanced": false, - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "langflow" - }, - "metadata_indexing_exclude": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_exclude", - "display_name": "Metadata Indexing Exclude", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "metadata_indexing_include": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_include", - "display_name": "Metadata Indexing Include", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "metric": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metric", - "display_name": "Metric", - "advanced": true, - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "namespace": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "namespace", - "display_name": "Namespace", - "advanced": true, - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "number_of_results": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 4, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "number_of_results", - "display_name": "Number of Results", - "advanced": true, - "dynamic": false, - "info": "Number of results to return.", - "load_from_db": false, - "title_case": false - }, - "pre_delete_collection": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "pre_delete_collection", - "display_name": "Pre Delete Collection", - "advanced": true, - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "load_from_db": false, - "title_case": false - }, - "search_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Similarity", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Similarity", - "MMR" - ], - "name": "search_type", - "display_name": "Search Type", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "setup_mode": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Sync", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Sync", - "Async", - "Off" - ], - "name": "setup_mode", - "display_name": "Setup Mode", - "advanced": true, - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "token": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "token", - "display_name": "Token", - "advanced": false, - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "load_from_db": true, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "ASTRA_DB_APPLICATION_TOKEN" - }, - "_type": "CustomComponent" - }, - "description": "Searches an existing Astra DB Vector Store.", - "icon": "AstraDB", - "base_classes": [ - "Record" - ], - "display_name": "Astra DB Search", - "documentation": "", - "custom_fields": { - "embedding": null, - "collection_name": null, - "input_value": null, - "token": null, - "api_endpoint": null, - "search_type": null, - "number_of_results": null, - "namespace": null, - "metric": null, - "batch_size": null, - "bulk_insert_batch_concurrency": null, - "bulk_insert_overwrite_concurrency": null, - "bulk_delete_concurrency": null, - "setup_mode": null, - "pre_delete_collection": null, - "metadata_indexing_include": null, - "metadata_indexing_exclude": null, - "collection_indexing_policy": null - }, - "output_types": [ - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "token", - "api_endpoint", - "collection_name", - "input_value", - "embedding" - ], - "beta": false - }, - "id": "AstraDBSearch-41nRz" - }, - "selected": false, - "width": 384, - "height": 713, - "dragging": false, - "positionAbsolute": { - "x": 1723.976434815103, - "y": 277.03317407245913 - } + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-EjXlN" + }, + "selected": true, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 3410.117202077183, + "y": 431.2038048137648 + }, + "dragging": false + }, + { + "id": "Prompt-xeI6K", + "type": "genericNode", + "position": { + "x": 2969.0261961391298, + "y": 442.1613649809069 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "context": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "context", + "display_name": "context", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "question": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "question", + "display_name": "question", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } }, - { - "id": "AstraDB-eUCSS", - "type": "genericNode", - "position": { - "x": 3372.04958055989, - "y": 1611.0742035495277 - }, - "data": { - "type": "AstraDB", - "node": { - "template": { - "embedding": { - "type": "Embeddings", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding", - "display_name": "Embedding", - "advanced": false, - "dynamic": false, - "info": "Embedding to use", - "load_from_db": false, - "title_case": false - }, - "inputs": { - "type": "Record", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "inputs", - "display_name": "Inputs", - "advanced": false, - "dynamic": false, - "info": "Optional list of records to be processed and stored in the vector store.", - "load_from_db": false, - "title_case": false - }, - "api_endpoint": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "api_endpoint", - "display_name": "API Endpoint", - "advanced": false, - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "load_from_db": true, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "ASTRA_DB_API_ENDPOINT" - }, - "batch_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "batch_size", - "display_name": "Batch Size", - "advanced": true, - "dynamic": false, - "info": "Optional number of records to process in a single batch.", - "load_from_db": false, - "title_case": false - }, - "bulk_delete_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_delete_concurrency", - "display_name": "Bulk Delete Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_batch_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_batch_concurrency", - "display_name": "Bulk Insert Batch Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_overwrite_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_overwrite_concurrency", - "display_name": "Bulk Insert Overwrite Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import List, Optional\n\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Async\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> VectorStore:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "collection_indexing_policy": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_indexing_policy", - "display_name": "Collection Indexing Policy", - "advanced": true, - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "load_from_db": false, - "title_case": false - }, - "collection_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_name", - "display_name": "Collection Name", - "advanced": false, - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "langflow" - }, - "metadata_indexing_exclude": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_exclude", - "display_name": "Metadata Indexing Exclude", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "metadata_indexing_include": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_include", - "display_name": "Metadata Indexing Include", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "metric": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metric", - "display_name": "Metric", - "advanced": true, - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "namespace": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "namespace", - "display_name": "Namespace", - "advanced": true, - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "pre_delete_collection": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "pre_delete_collection", - "display_name": "Pre Delete Collection", - "advanced": true, - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "load_from_db": false, - "title_case": false - }, - "setup_mode": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Async", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Sync", - "Async", - "Off" - ], - "name": "setup_mode", - "display_name": "Setup Mode", - "advanced": true, - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "token": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "token", - "display_name": "Token", - "advanced": false, - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "load_from_db": true, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "ASTRA_DB_APPLICATION_TOKEN" - }, - "_type": "CustomComponent" - }, - "description": "Builds or loads an Astra DB Vector Store.", - "icon": "AstraDB", - "base_classes": [ - "VectorStore" - ], - "display_name": "Astra DB", - "documentation": "", - "custom_fields": { - "embedding": null, - "token": null, - "api_endpoint": null, - "collection_name": null, - "inputs": null, - "namespace": null, - "metric": null, - "batch_size": null, - "bulk_insert_batch_concurrency": null, - "bulk_insert_overwrite_concurrency": null, - "bulk_delete_concurrency": null, - "setup_mode": null, - "pre_delete_collection": null, - "metadata_indexing_include": null, - "metadata_indexing_exclude": null, - "collection_indexing_policy": null - }, - "output_types": [ - "VectorStore" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "token", - "api_endpoint", - "collection_name", - "inputs", - "embedding" - ], - "beta": false - }, - "id": "AstraDB-eUCSS" - }, - "selected": false, - "width": 384, - "height": 573, - "positionAbsolute": { - "x": 3372.04958055989, - "y": 1611.0742035495277 - }, - "dragging": false + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["object", "Text", "str"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["context", "question"] }, - { - "id": "OpenAIEmbeddings-9TPjc", - "type": "genericNode", - "position": { - "x": 2814.0402191223047, - "y": 1955.9268168273086 - }, - "data": { - "type": "OpenAIEmbeddings", - "node": { - "template": { - "allowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "allowed_special", - "display_name": "Allowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "client": { - "type": "Any", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "client", - "display_name": "Client", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=openai_api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_headers": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_headers", - "display_name": "Default Headers", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_query": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_query", - "display_name": "Default Query", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "deployment": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "deployment", - "display_name": "Deployment", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "disallowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [ - "all" - ], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "disallowed_special", - "display_name": "Disallowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "embedding_ctx_length": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 8191, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding_ctx_length", - "display_name": "Embedding Context Length", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_retries": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 6, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_retries", - "display_name": "Max Retries", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "name": "model", - "display_name": "Model", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "" - }, - "openai_api_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_type", - "display_name": "OpenAI API Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_version": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_version", - "display_name": "OpenAI API Version", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_organization": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_organization", - "display_name": "OpenAI Organization", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_proxy": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_proxy", - "display_name": "OpenAI Proxy", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "request_timeout": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "request_timeout", - "display_name": "Request Timeout", - "advanced": true, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "show_progress_bar": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "show_progress_bar", - "display_name": "Show Progress Bar", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "skip_empty": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "skip_empty", - "display_name": "Skip Empty", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_enable": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_enable", - "display_name": "TikToken Enable", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_model_name", - "display_name": "TikToken Model Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Generate embeddings using OpenAI models.", - "base_classes": [ - "Embeddings" - ], - "display_name": "OpenAI Embeddings", - "documentation": "", - "custom_fields": { - "openai_api_key": null, - "default_headers": null, - "default_query": null, - "allowed_special": null, - "disallowed_special": null, - "chunk_size": null, - "client": null, - "deployment": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, - "output_types": [ - "Embeddings" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "OpenAIEmbeddings-9TPjc" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 2814.0402191223047, - "y": 1955.9268168273086 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextOutput-BDknO", - "target": "Prompt-xeI6K", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "id": "reactflow__edge-TextOutput-BDknO{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "context", - "id": "Prompt-xeI6K", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Text", - "str" - ], - "dataType": "TextOutput", - "id": "TextOutput-BDknO" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-xeI6K", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 477, + "positionAbsolute": { + "x": 2969.0261961391298, + "y": 442.1613649809069 + }, + "dragging": false + }, + { + "id": "ChatOutput-Q39I8", + "type": "genericNode", + "position": { + "x": 3887.2073667611485, + "y": 588.4801225794856 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "source": "ChatInput-yxMKE", - "target": "Prompt-xeI6K", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "question", - "id": "Prompt-xeI6K", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Text", - "str", - "object", - "Record" - ], - "dataType": "ChatInput", - "id": "ChatInput-yxMKE" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["object", "Text", "Record", "str"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null }, - { - "source": "Prompt-xeI6K", - "target": "OpenAIModel-EjXlN", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "id": "reactflow__edge-Prompt-xeI6K{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}-OpenAIModel-EjXlN{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-EjXlN", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Text", - "str" - ], - "dataType": "Prompt", - "id": "Prompt-xeI6K" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-Q39I8" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 3887.2073667611485, + "y": 588.4801225794856 + }, + "dragging": false + }, + { + "id": "File-t0a6a", + "type": "genericNode", + "position": { + "x": 2257.233450682836, + "y": 1747.5389618367233 + }, + "data": { + "type": "File", + "node": { + "template": { + "path": { + "type": "file", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [ + ".txt", + ".md", + ".mdx", + ".csv", + ".json", + ".yaml", + ".yml", + ".xml", + ".html", + ".htm", + ".pdf", + ".docx" + ], + "file_path": "51e2b78a-199b-4054-9f32-e288eef6924c/Langflow conversation.pdf", + "password": false, + "name": "path", + "display_name": "Path", + "advanced": false, + "dynamic": false, + "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "silent_errors": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "silent_errors", + "display_name": "Silent Errors", + "advanced": true, + "dynamic": false, + "info": "If true, errors will not raise an exception.", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" }, - { - "source": "OpenAIModel-EjXlN", - "target": "ChatOutput-Q39I8", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "id": "reactflow__edge-OpenAIModel-EjXlN{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}-ChatOutput-Q39I8{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-Q39I8", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Text", - "str" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-EjXlN" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false + "description": "A generic file loader.", + "icon": "file-text", + "base_classes": ["Record"], + "display_name": "File", + "documentation": "", + "custom_fields": { + "path": null, + "silent_errors": null }, - { - "source": "File-t0a6a", - "target": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", - "id": "reactflow__edge-File-t0a6a{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}-RecursiveCharacterTextSplitter-tR9QM{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", - "data": { - "targetHandle": { - "fieldName": "inputs", - "id": "RecursiveCharacterTextSplitter-tR9QM", - "inputTypes": [ - "Document", - "Record" - ], - "type": "Document" - }, - "sourceHandle": { - "baseClasses": [ - "Record" - ], - "dataType": "File", - "id": "File-t0a6a" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false + "output_types": ["Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "File-t0a6a" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 2257.233450682836, + "y": 1747.5389618367233 + }, + "dragging": false + }, + { + "id": "RecursiveCharacterTextSplitter-tR9QM", + "type": "genericNode", + "position": { + "x": 2791.013514133929, + "y": 1462.9588953494142 + }, + "data": { + "type": "RecursiveCharacterTextSplitter", + "node": { + "template": { + "inputs": { + "type": "Document", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "inputs", + "display_name": "Input", + "advanced": false, + "input_types": ["Document", "Record"], + "dynamic": false, + "info": "The texts to split.", + "load_from_db": false, + "title_case": false + }, + "chunk_overlap": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 200, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_overlap", + "display_name": "Chunk Overlap", + "advanced": false, + "dynamic": false, + "info": "The amount of overlap between chunks.", + "load_from_db": false, + "title_case": false + }, + "chunk_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 1000, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_size", + "display_name": "Chunk Size", + "advanced": false, + "dynamic": false, + "info": "The maximum length of each chunk.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "separators": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "separators", + "display_name": "Separators", + "advanced": false, + "dynamic": false, + "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": [""] + }, + "_type": "CustomComponent" }, - { - "source": "OpenAIEmbeddings-ZlOk1", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}", - "target": "AstraDBSearch-41nRz", - "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", - "data": { - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDBSearch-41nRz", - "inputTypes": null, - "type": "Embeddings" - }, - "sourceHandle": { - "baseClasses": [ - "Embeddings" - ], - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-ZlOk1" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}" + "description": "Split text into chunks of a specified length.", + "base_classes": ["Record"], + "display_name": "Recursive Character Text Splitter", + "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", + "custom_fields": { + "inputs": null, + "separators": null, + "chunk_size": null, + "chunk_overlap": null }, - { - "source": "ChatInput-yxMKE", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", - "target": "AstraDBSearch-41nRz", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "AstraDBSearch-41nRz", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Text", - "str", - "object", - "Record" - ], - "dataType": "ChatInput", - "id": "ChatInput-yxMKE" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "output_types": ["Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "RecursiveCharacterTextSplitter-tR9QM" + }, + "selected": false, + "width": 384, + "height": 501, + "positionAbsolute": { + "x": 2791.013514133929, + "y": 1462.9588953494142 + }, + "dragging": false + }, + { + "id": "AstraDBSearch-41nRz", + "type": "genericNode", + "position": { + "x": 1723.976434815103, + "y": 277.03317407245913 + }, + "data": { + "type": "AstraDBSearch", + "node": { + "template": { + "embedding": { + "type": "Embeddings", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding", + "display_name": "Embedding", + "advanced": false, + "dynamic": false, + "info": "Embedding to use", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input Value", + "advanced": false, + "dynamic": false, + "info": "Input value to search", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "api_endpoint": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "api_endpoint", + "display_name": "API Endpoint", + "advanced": false, + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "load_from_db": true, + "title_case": false, + "input_types": ["Text"], + "value": "ASTRA_DB_API_ENDPOINT" + }, + "batch_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "batch_size", + "display_name": "Batch Size", + "advanced": true, + "dynamic": false, + "info": "Optional number of records to process in a single batch.", + "load_from_db": false, + "title_case": false + }, + "bulk_delete_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_delete_concurrency", + "display_name": "Bulk Delete Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_batch_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_batch_concurrency", + "display_name": "Bulk Insert Batch Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_overwrite_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_overwrite_concurrency", + "display_name": "Bulk Insert Overwrite Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "collection_indexing_policy": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_indexing_policy", + "display_name": "Collection Indexing Policy", + "advanced": true, + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "load_from_db": false, + "title_case": false + }, + "collection_name": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_name", + "display_name": "Collection Name", + "advanced": false, + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "langflow" + }, + "metadata_indexing_exclude": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_exclude", + "display_name": "Metadata Indexing Exclude", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "metadata_indexing_include": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_include", + "display_name": "Metadata Indexing Include", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "metric": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metric", + "display_name": "Metric", + "advanced": true, + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "namespace": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "namespace", + "display_name": "Namespace", + "advanced": true, + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "number_of_results": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 4, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "number_of_results", + "display_name": "Number of Results", + "advanced": true, + "dynamic": false, + "info": "Number of results to return.", + "load_from_db": false, + "title_case": false + }, + "pre_delete_collection": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "pre_delete_collection", + "display_name": "Pre Delete Collection", + "advanced": true, + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "load_from_db": false, + "title_case": false + }, + "search_type": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Similarity", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Similarity", "MMR"], + "name": "search_type", + "display_name": "Search Type", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "setup_mode": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Sync", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Sync", "Async", "Off"], + "name": "setup_mode", + "display_name": "Setup Mode", + "advanced": true, + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "token": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "token", + "display_name": "Token", + "advanced": false, + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "load_from_db": true, + "title_case": false, + "input_types": ["Text"], + "value": "ASTRA_DB_APPLICATION_TOKEN" + }, + "_type": "CustomComponent" }, - { - "source": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}", - "target": "AstraDB-eUCSS", - "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", - "data": { - "targetHandle": { - "fieldName": "inputs", - "id": "AstraDB-eUCSS", - "inputTypes": null, - "type": "Record" - }, - "sourceHandle": { - "baseClasses": [ - "Record" - ], - "dataType": "RecursiveCharacterTextSplitter", - "id": "RecursiveCharacterTextSplitter-tR9QM" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", - "selected": false + "description": "Searches an existing Astra DB Vector Store.", + "icon": "AstraDB", + "base_classes": ["Record"], + "display_name": "Astra DB Search", + "documentation": "", + "custom_fields": { + "embedding": null, + "collection_name": null, + "input_value": null, + "token": null, + "api_endpoint": null, + "search_type": null, + "number_of_results": null, + "namespace": null, + "metric": null, + "batch_size": null, + "bulk_insert_batch_concurrency": null, + "bulk_insert_overwrite_concurrency": null, + "bulk_delete_concurrency": null, + "setup_mode": null, + "pre_delete_collection": null, + "metadata_indexing_include": null, + "metadata_indexing_exclude": null, + "collection_indexing_policy": null }, - { - "source": "OpenAIEmbeddings-9TPjc", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}", - "target": "AstraDB-eUCSS", - "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", - "data": { - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDB-eUCSS", - "inputTypes": null, - "type": "Embeddings" - }, - "sourceHandle": { - "baseClasses": [ - "Embeddings" - ], - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-9TPjc" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", - "selected": false - }, - { - "source": "AstraDBSearch-41nRz", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}", - "target": "TextOutput-BDknO", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-BDknO", - "inputTypes": [ - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Record" - ], - "dataType": "AstraDBSearch", - "id": "AstraDBSearch-41nRz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-AstraDBSearch-41nRz{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}-TextOutput-BDknO{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": -259.6782520315529, - "y": 90.3428735006047, - "zoom": 0.2687057134854984 + "output_types": ["Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "token", + "api_endpoint", + "collection_name", + "input_value", + "embedding" + ], + "beta": false + }, + "id": "AstraDBSearch-41nRz" + }, + "selected": false, + "width": 384, + "height": 713, + "dragging": false, + "positionAbsolute": { + "x": 1723.976434815103, + "y": 277.03317407245913 } - }, - "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", - "name": "Vector Store RAG", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + { + "id": "AstraDB-eUCSS", + "type": "genericNode", + "position": { + "x": 3372.04958055989, + "y": 1611.0742035495277 + }, + "data": { + "type": "AstraDB", + "node": { + "template": { + "embedding": { + "type": "Embeddings", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding", + "display_name": "Embedding", + "advanced": false, + "dynamic": false, + "info": "Embedding to use", + "load_from_db": false, + "title_case": false + }, + "inputs": { + "type": "Record", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "inputs", + "display_name": "Inputs", + "advanced": false, + "dynamic": false, + "info": "Optional list of records to be processed and stored in the vector store.", + "load_from_db": false, + "title_case": false + }, + "api_endpoint": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "api_endpoint", + "display_name": "API Endpoint", + "advanced": false, + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "load_from_db": true, + "title_case": false, + "input_types": ["Text"], + "value": "ASTRA_DB_API_ENDPOINT" + }, + "batch_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "batch_size", + "display_name": "Batch Size", + "advanced": true, + "dynamic": false, + "info": "Optional number of records to process in a single batch.", + "load_from_db": false, + "title_case": false + }, + "bulk_delete_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_delete_concurrency", + "display_name": "Bulk Delete Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_batch_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_batch_concurrency", + "display_name": "Bulk Insert Batch Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "load_from_db": false, + "title_case": false + }, + "bulk_insert_overwrite_concurrency": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "bulk_insert_overwrite_concurrency", + "display_name": "Bulk Insert Overwrite Concurrency", + "advanced": true, + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import List, Optional\n\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Async\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> VectorStore:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "collection_indexing_policy": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_indexing_policy", + "display_name": "Collection Indexing Policy", + "advanced": true, + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "load_from_db": false, + "title_case": false + }, + "collection_name": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "collection_name", + "display_name": "Collection Name", + "advanced": false, + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "langflow" + }, + "metadata_indexing_exclude": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_exclude", + "display_name": "Metadata Indexing Exclude", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "metadata_indexing_include": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metadata_indexing_include", + "display_name": "Metadata Indexing Include", + "advanced": true, + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "metric": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "metric", + "display_name": "Metric", + "advanced": true, + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "namespace": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "namespace", + "display_name": "Namespace", + "advanced": true, + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "pre_delete_collection": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "pre_delete_collection", + "display_name": "Pre Delete Collection", + "advanced": true, + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "load_from_db": false, + "title_case": false + }, + "setup_mode": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Async", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Sync", "Async", "Off"], + "name": "setup_mode", + "display_name": "Setup Mode", + "advanced": true, + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "token": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "token", + "display_name": "Token", + "advanced": false, + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "load_from_db": true, + "title_case": false, + "input_types": ["Text"], + "value": "ASTRA_DB_APPLICATION_TOKEN" + }, + "_type": "CustomComponent" + }, + "description": "Builds or loads an Astra DB Vector Store.", + "icon": "AstraDB", + "base_classes": ["VectorStore"], + "display_name": "Astra DB", + "documentation": "", + "custom_fields": { + "embedding": null, + "token": null, + "api_endpoint": null, + "collection_name": null, + "inputs": null, + "namespace": null, + "metric": null, + "batch_size": null, + "bulk_insert_batch_concurrency": null, + "bulk_insert_overwrite_concurrency": null, + "bulk_delete_concurrency": null, + "setup_mode": null, + "pre_delete_collection": null, + "metadata_indexing_include": null, + "metadata_indexing_exclude": null, + "collection_indexing_policy": null + }, + "output_types": ["VectorStore"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "token", + "api_endpoint", + "collection_name", + "inputs", + "embedding" + ], + "beta": false + }, + "id": "AstraDB-eUCSS" + }, + "selected": false, + "width": 384, + "height": 573, + "positionAbsolute": { + "x": 3372.04958055989, + "y": 1611.0742035495277 + }, + "dragging": false + }, + { + "id": "OpenAIEmbeddings-9TPjc", + "type": "genericNode", + "position": { + "x": 2814.0402191223047, + "y": 1955.9268168273086 + }, + "data": { + "type": "OpenAIEmbeddings", + "node": { + "template": { + "allowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": [], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "allowed_special", + "display_name": "Allowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "chunk_size": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 1000, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "chunk_size", + "display_name": "Chunk Size", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "client": { + "type": "Any", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "client", + "display_name": "Client", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n client: Optional[Any] = None,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n client=client,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=openai_api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_headers": { + "type": "dict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_headers", + "display_name": "Default Headers", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "default_query": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "default_query", + "display_name": "Default Query", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "deployment": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "deployment", + "display_name": "Deployment", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "disallowed_special": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": ["all"], + "fileTypes": [], + "file_path": "", + "password": false, + "name": "disallowed_special", + "display_name": "Disallowed Special", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "embedding_ctx_length": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 8191, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "embedding_ctx_length", + "display_name": "Embedding Context Length", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_retries": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 6, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_retries", + "display_name": "Max Retries", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "text-embedding-ada-002", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "name": "model", + "display_name": "Model", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "" + }, + "openai_api_type": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_type", + "display_name": "OpenAI API Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_version": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_version", + "display_name": "OpenAI API Version", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_organization": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_organization", + "display_name": "OpenAI Organization", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_proxy": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_proxy", + "display_name": "OpenAI Proxy", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "request_timeout": { + "type": "float", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "request_timeout", + "display_name": "Request Timeout", + "advanced": true, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "show_progress_bar": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "show_progress_bar", + "display_name": "Show Progress Bar", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "skip_empty": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "skip_empty", + "display_name": "Skip Empty", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_enable": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_enable", + "display_name": "TikToken Enable", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "tiktoken_model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "tiktoken_model_name", + "display_name": "TikToken Model Name", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" + }, + "description": "Generate embeddings using OpenAI models.", + "base_classes": ["Embeddings"], + "display_name": "OpenAI Embeddings", + "documentation": "", + "custom_fields": { + "openai_api_key": null, + "default_headers": null, + "default_query": null, + "allowed_special": null, + "disallowed_special": null, + "chunk_size": null, + "client": null, + "deployment": null, + "embedding_ctx_length": null, + "max_retries": null, + "model": null, + "model_kwargs": null, + "openai_api_base": null, + "openai_api_type": null, + "openai_api_version": null, + "openai_organization": null, + "openai_proxy": null, + "request_timeout": null, + "show_progress_bar": null, + "skip_empty": null, + "tiktoken_enable": null, + "tiktoken_model_name": null + }, + "output_types": ["Embeddings"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "OpenAIEmbeddings-9TPjc" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 2814.0402191223047, + "y": 1955.9268168273086 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "TextOutput-BDknO", + "target": "Prompt-xeI6K", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-TextOutput-BDknO{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextOutput\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "context", + "id": "Prompt-xeI6K", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Text", "str"], + "dataType": "TextOutput", + "id": "TextOutput-BDknO" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "ChatInput-yxMKE", + "target": "Prompt-xeI6K", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-Prompt-xeI6K{\u0153fieldName\u0153:\u0153question\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "question", + "id": "Prompt-xeI6K", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Text", "str", "object", "Record"], + "dataType": "ChatInput", + "id": "ChatInput-yxMKE" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "Prompt-xeI6K", + "target": "OpenAIModel-EjXlN", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-Prompt-xeI6K{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-xeI6K\u0153}-OpenAIModel-EjXlN{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-EjXlN", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Text", "str"], + "dataType": "Prompt", + "id": "Prompt-xeI6K" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "OpenAIModel-EjXlN", + "target": "ChatOutput-Q39I8", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-OpenAIModel-EjXlN{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-EjXlN\u0153}-ChatOutput-Q39I8{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-Q39I8\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-Q39I8", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Text", "str"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-EjXlN" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "File-t0a6a", + "target": "RecursiveCharacterTextSplitter-tR9QM", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", + "id": "reactflow__edge-File-t0a6a{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-t0a6a\u0153}-RecursiveCharacterTextSplitter-tR9QM{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153Record\u0153],\u0153type\u0153:\u0153Document\u0153}", + "data": { + "targetHandle": { + "fieldName": "inputs", + "id": "RecursiveCharacterTextSplitter-tR9QM", + "inputTypes": ["Document", "Record"], + "type": "Document" + }, + "sourceHandle": { + "baseClasses": ["Record"], + "dataType": "File", + "id": "File-t0a6a" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "OpenAIEmbeddings-ZlOk1", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}", + "target": "AstraDBSearch-41nRz", + "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", + "data": { + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDBSearch-41nRz", + "inputTypes": null, + "type": "Embeddings" + }, + "sourceHandle": { + "baseClasses": ["Embeddings"], + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-ZlOk1" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-ZlOk1\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}" + }, + { + "source": "ChatInput-yxMKE", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}", + "target": "AstraDBSearch-41nRz", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "AstraDBSearch-41nRz", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Text", "str", "object", "Record"], + "dataType": "ChatInput", + "id": "ChatInput-yxMKE" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-yxMKE{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153,\u0153Record\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-yxMKE\u0153}-AstraDBSearch-41nRz{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "RecursiveCharacterTextSplitter-tR9QM", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}", + "target": "AstraDB-eUCSS", + "targetHandle": "{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", + "data": { + "targetHandle": { + "fieldName": "inputs", + "id": "AstraDB-eUCSS", + "inputTypes": null, + "type": "Record" + }, + "sourceHandle": { + "baseClasses": ["Record"], + "dataType": "RecursiveCharacterTextSplitter", + "id": "RecursiveCharacterTextSplitter-tR9QM" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153RecursiveCharacterTextSplitter\u0153,\u0153id\u0153:\u0153RecursiveCharacterTextSplitter-tR9QM\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153inputs\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Record\u0153}", + "selected": false + }, + { + "source": "OpenAIEmbeddings-9TPjc", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}", + "target": "AstraDB-eUCSS", + "targetHandle": "{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", + "data": { + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDB-eUCSS", + "inputTypes": null, + "type": "Embeddings" + }, + "sourceHandle": { + "baseClasses": ["Embeddings"], + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-9TPjc" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{\u0153baseClasses\u0153:[\u0153Embeddings\u0153],\u0153dataType\u0153:\u0153OpenAIEmbeddings\u0153,\u0153id\u0153:\u0153OpenAIEmbeddings-9TPjc\u0153}-AstraDB-eUCSS{\u0153fieldName\u0153:\u0153embedding\u0153,\u0153id\u0153:\u0153AstraDB-eUCSS\u0153,\u0153inputTypes\u0153:null,\u0153type\u0153:\u0153Embeddings\u0153}", + "selected": false + }, + { + "source": "AstraDBSearch-41nRz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}", + "target": "TextOutput-BDknO", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-BDknO", + "inputTypes": ["Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Record"], + "dataType": "AstraDBSearch", + "id": "AstraDBSearch-41nRz" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-AstraDBSearch-41nRz{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153AstraDBSearch\u0153,\u0153id\u0153:\u0153AstraDBSearch-41nRz\u0153}-TextOutput-BDknO{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-BDknO\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -259.6782520315529, + "y": 90.3428735006047, + "zoom": 0.2687057134854984 + } + }, + "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", + "name": "Vector Store RAG", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/poetry.lock b/poetry.lock index 583f1ee6c..5f1adf2a3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -242,13 +242,13 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] name = "assemblyai" -version = "0.23.1" +version = "0.26.0" description = "AssemblyAI Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "assemblyai-0.23.1-py3-none-any.whl", hash = "sha256:2887c7983fa911717cbe37a38d38fcdc8188e62687385b8b6f979546c58354f4"}, - {file = "assemblyai-0.23.1.tar.gz", hash = "sha256:4a3d4d8c4f6c956c6243f0873147ba29da4c6cf5edd6a1b52e6bdaa209526998"}, + {file = "assemblyai-0.26.0-py3-none-any.whl", hash = "sha256:46689abfe1bf9bccd595f65314aab7deec3b4859630f6882099165862d305421"}, + {file = "assemblyai-0.26.0.tar.gz", hash = "sha256:7cd7cf3231333e9ea14a130b7a72bf710c66c5d1877bbfd68ab13ff546920e33"}, ] [package.dependencies] @@ -262,20 +262,22 @@ extras = ["pyaudio (>=0.2.13)"] [[package]] name = "astrapy" -version = "0.7.7" -description = "AstraPy is a Pythonic SDK for DataStax Astra" +version = "1.2.0" +description = "AstraPy is a Pythonic SDK for DataStax Astra and its Data API" optional = false -python-versions = ">=3.8.0,<4.0.0" +python-versions = "<4.0.0,>=3.8.0" files = [ - {file = "astrapy-0.7.7-py3-none-any.whl", hash = "sha256:e5def4e3c5ceb06dfc996471250dc0c972b729c06336ea4aac006dadfc071a9a"}, - {file = "astrapy-0.7.7.tar.gz", hash = "sha256:4bf81096a0c26cce18a14a34bb5f699649fd7d90b4ec6050f3d7c0274722d769"}, + {file = "astrapy-1.2.0-py3-none-any.whl", hash = "sha256:5d65242771934c38ebe16f330e9e517968c1437846dabdbe7e48470f7b1782e8"}, + {file = "astrapy-1.2.0.tar.gz", hash = "sha256:6ce1b421d1ae21fe73373fa36048d8d56c775367886525504f01c48cbb742842"}, ] [package.dependencies] +bson = ">=0.5.10,<0.6.0" cassio = ">=0.1.4,<0.2.0" deprecation = ">=2.1.0,<2.2.0" httpx = {version = ">=0.25.2,<1", extras = ["http2"]} toml = ">=0.10.2,<0.11.0" +uuid6 = ">=2024.1.12,<2024.2.0" [[package]] name = "asttokens" @@ -470,17 +472,17 @@ files = [ [[package]] name = "boto3" -version = "1.34.111" +version = "1.34.112" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.111-py3-none-any.whl", hash = "sha256:d6a8e77db316c6e1d9a25f77c795ed1e0a8bc621f863ce26d04b2225d30f2dce"}, - {file = "boto3-1.34.111.tar.gz", hash = "sha256:8f18d212b9199dbbd9d596dd5929685b583ac938c60cceeac2e045c0c5d10323"}, + {file = "boto3-1.34.112-py3-none-any.whl", hash = "sha256:4cf28ce2c19a4e4963f1cb1f9b659a548f840f88af3e2da727b35ceb104f9223"}, + {file = "boto3-1.34.112.tar.gz", hash = "sha256:1092ac6c68acdd33051ed0d2b7cb6f5a4527c5d1535a48cda53f7012accde206"}, ] [package.dependencies] -botocore = ">=1.34.111,<1.35.0" +botocore = ">=1.34.112,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -489,13 +491,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.111" +version = "1.34.112" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.111-py3-none-any.whl", hash = "sha256:e10affb7f372d50da957260adf2753a3f153bf90abe6910e11f09d1e443b5515"}, - {file = "botocore-1.34.111.tar.gz", hash = "sha256:0e0fb9b605c46393d5c7c69bd516b36058334bdc8f389e680c6efcf0727f25db"}, + {file = "botocore-1.34.112-py3-none-any.whl", hash = "sha256:637f568a6c3322fb7e5ee55e0c5367324a15a331e87a497783ac6209253dde30"}, + {file = "botocore-1.34.112.tar.gz", hash = "sha256:053495953910bcf95d336ab1adb13efb70edc5462932eff180560737ad069319"}, ] [package.dependencies] @@ -598,6 +600,20 @@ files = [ {file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"}, ] +[[package]] +name = "bson" +version = "0.5.10" +description = "BSON codec for Python" +optional = false +python-versions = "*" +files = [ + {file = "bson-0.5.10.tar.gz", hash = "sha256:d6511b2ab051139a9123c184de1a04227262173ad593429d21e443d6462d6590"}, +] + +[package.dependencies] +python-dateutil = ">=2.4.0" +six = ">=1.9.0" + [[package]] name = "build" version = "1.2.1" @@ -989,13 +1005,13 @@ numpy = "*" [[package]] name = "chromadb" -version = "0.4.24" +version = "0.5.0" description = "Chroma." optional = false python-versions = ">=3.8" files = [ - {file = "chromadb-0.4.24-py3-none-any.whl", hash = "sha256:3a08e237a4ad28b5d176685bd22429a03717fe09d35022fb230d516108da01da"}, - {file = "chromadb-0.4.24.tar.gz", hash = "sha256:a5c80b4e4ad9b236ed2d4899a5b9e8002b489293f2881cb2cadab5b199ee1c72"}, + {file = "chromadb-0.5.0-py3-none-any.whl", hash = "sha256:8193dc65c143b61d8faf87f02c44ecfa778d471febd70de517f51c5d88a06009"}, + {file = "chromadb-0.5.0.tar.gz", hash = "sha256:7954af614a9ff7b2902ddbd0a162f33f7ec0669e2429903905c4f7876d1f766f"}, ] [package.dependencies] @@ -1016,7 +1032,6 @@ opentelemetry-sdk = ">=1.2.0" orjson = ">=3.9.12" overrides = ">=7.3.1" posthog = ">=2.4.0" -pulsar-client = ">=3.1.0" pydantic = ">=1.9" pypika = ">=0.48.9" PyYAML = ">=6.0.0" @@ -1145,13 +1160,13 @@ testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] [[package]] name = "codespell" -version = "2.2.6" +version = "2.3.0" description = "Codespell" optional = false python-versions = ">=3.8" files = [ - {file = "codespell-2.2.6-py3-none-any.whl", hash = "sha256:9ee9a3e5df0990604013ac2a9f22fa8e57669c827124a2e961fe8a1da4cacc07"}, - {file = "codespell-2.2.6.tar.gz", hash = "sha256:a8c65d8eb3faa03deabab6b3bbe798bea72e1799c7e9e955d57eca4096abcff9"}, + {file = "codespell-2.3.0-py3-none-any.whl", hash = "sha256:a9c7cef2501c9cfede2110fd6d4e5e62296920efe9abfb84648df866e47f58d1"}, + {file = "codespell-2.3.0.tar.gz", hash = "sha256:360c7d10f75e65f67bad720af7007e1060a5d395670ec11a7ed1fed9dd17471f"}, ] [package.extras] @@ -1162,13 +1177,13 @@ types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency [[package]] name = "cohere" -version = "5.5.0" +version = "5.5.3" description = "" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "cohere-5.5.0-py3-none-any.whl", hash = "sha256:7792e8898c95f2cb955b2d9f23b8602f73f3b698d59f1a1b4896c53809671da0"}, - {file = "cohere-5.5.0.tar.gz", hash = "sha256:00b492ebf8921e83cb2371f2ee36ddf301422daae3024343a87d4316f02b711b"}, + {file = "cohere-5.5.3-py3-none-any.whl", hash = "sha256:99d20129713a6dae052368b4839773a214592a76bee345b94a4846d00f702da3"}, + {file = "cohere-5.5.3.tar.gz", hash = "sha256:8c7ebe2f5bf83fee8e55a24a0acdd4b0e94de274fd0ef32b285978289a03e930"}, ] [package.dependencies] @@ -1590,17 +1605,6 @@ files = [ [package.extras] graph = ["objgraph (>=1.7.2)"] -[[package]] -name = "dirtyjson" -version = "1.0.8" -description = "JSON decoder for Python that can extract data from the muck" -optional = false -python-versions = "*" -files = [ - {file = "dirtyjson-1.0.8-py3-none-any.whl", hash = "sha256:125e27248435a58acace26d5c2c4c11a1c0de0a9c5124c5a94ba78e517d74f53"}, - {file = "dirtyjson-1.0.8.tar.gz", hash = "sha256:90ca4a18f3ff30ce849d100dcf4a003953c79d3a2348ef056f1d9c22231a25fd"}, -] - [[package]] name = "diskcache" version = "5.6.3" @@ -1839,6 +1843,21 @@ orjson = ["orjson (>=3)"] requests = ["requests (>=2.4.0,<3.0.0)"] vectorstore-mmr = ["numpy (>=1)", "simsimd (>=3)"] +[[package]] +name = "email-validator" +version = "2.1.1" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}, + {file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + [[package]] name = "emoji" version = "2.12.1" @@ -1949,23 +1968,48 @@ files = [ [[package]] name = "fastapi" -version = "0.110.3" +version = "0.111.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.110.3-py3-none-any.whl", hash = "sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32"}, - {file = "fastapi-0.110.3.tar.gz", hash = "sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626"}, + {file = "fastapi-0.111.0-py3-none-any.whl", hash = "sha256:97ecbf994be0bcbdadedf88c3150252bed7b2087075ac99735403b1b76cc8fc0"}, + {file = "fastapi-0.111.0.tar.gz", hash = "sha256:b9db9dd147c91cb8b769f7183535773d8741dd46f9dc6676cd82eab510228cd7"}, ] [package.dependencies] +email_validator = ">=2.0.0" +fastapi-cli = ">=0.0.2" +httpx = ">=0.23.0" +jinja2 = ">=2.11.2" +orjson = ">=3.2.1" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +python-multipart = ">=0.0.7" starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" +ujson = ">=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0" +uvicorn = {version = ">=0.12.0", extras = ["standard"]} [package.extras] all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "fastapi-cli" +version = "0.0.4" +description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, + {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, +] + +[package.dependencies] +typer = ">=0.12.3" + +[package.extras] +standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] + [[package]] name = "fastavro" version = "1.9.4" @@ -3977,22 +4021,20 @@ adal = ["adal (>=1.0.2)"] [[package]] name = "langchain" -version = "0.1.20" +version = "0.2.1" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.1.20-py3-none-any.whl", hash = "sha256:09991999fbd6c3421a12db3c7d1f52d55601fc41d9b2a3ef51aab2e0e9c38da9"}, - {file = "langchain-0.1.20.tar.gz", hash = "sha256:f35c95eed8c8375e02dce95a34f2fd4856a4c98269d6dc34547a23dba5beab7e"}, + {file = "langchain-0.2.1-py3-none-any.whl", hash = "sha256:3e13bf97c5717bce2c281f5117e8778823e8ccf62d949e73d3869448962b1c97"}, + {file = "langchain-0.2.1.tar.gz", hash = "sha256:5758a315e1ac92eb26dafec5ad0fafa03cafa686aba197d5bb0b1dd28cc03ebe"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -dataclasses-json = ">=0.5.7,<0.7" -langchain-community = ">=0.0.38,<0.1" -langchain-core = ">=0.1.52,<0.2.0" -langchain-text-splitters = ">=0.0.1,<0.1" +langchain-core = ">=0.2.0,<0.3.0" +langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = ">=1,<2" pydantic = ">=1,<3" @@ -4008,10 +4050,10 @@ cli = ["typer (>=0.9.0,<0.10.0)"] cohere = ["cohere (>=4,<6)"] docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<6)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<6)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.1,<0.2)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] javascript = ["esprima (>=4.0.1,<5.0.0)"] llms = ["clarifai (>=9.1.0)", "cohere (>=4,<6)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] -openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"] +openai = ["openai (<2)", "tiktoken (>=0.7,<1.0)"] qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] text-helpers = ["chardet (>=5.1.0,<6.0.0)"] @@ -4033,18 +4075,18 @@ langchain-core = ">=0.1.43,<0.3" [[package]] name = "langchain-astradb" -version = "0.1.0" +version = "0.3.2" description = "An integration package connecting Astra DB and LangChain" optional = false -python-versions = ">=3.8.1,<4.0" +python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_astradb-0.1.0-py3-none-any.whl", hash = "sha256:c6686089da343fce8c31e36c9162323e88888300b09d56b72347a19449d7361f"}, - {file = "langchain_astradb-0.1.0.tar.gz", hash = "sha256:c8a3426c9daa2beeec2dc7a718186b0b9c388082e9543e0bc07363712cc3b947"}, + {file = "langchain_astradb-0.3.2-py3-none-any.whl", hash = "sha256:15afc5c0105e863e8f57bf8686490c00be47ed05e47d3263ad1577f2031c0dd5"}, + {file = "langchain_astradb-0.3.2.tar.gz", hash = "sha256:4316f2c59402779a347a811e1b5470a0570348cb89baac17472d860b63188122"}, ] [package.dependencies] -astrapy = ">=0.7.7,<0.8.0" -langchain-core = ">=0.1.31,<0.2.0" +astrapy = ">=1,<2" +langchain-core = ">=0.1.31,<0.3" numpy = ">=1,<2" [[package]] @@ -4064,19 +4106,20 @@ langchain-core = ">=0.1.42,<0.3" [[package]] name = "langchain-community" -version = "0.0.38" +version = "0.2.1" description = "Community contributed LangChain integrations." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_community-0.0.38-py3-none-any.whl", hash = "sha256:ecb48660a70a08c90229be46b0cc5f6bc9f38f2833ee44c57dfab9bf3a2c121a"}, - {file = "langchain_community-0.0.38.tar.gz", hash = "sha256:127fc4b75bc67b62fe827c66c02e715a730fef8fe69bd2023d466bab06b5810d"}, + {file = "langchain_community-0.2.1-py3-none-any.whl", hash = "sha256:b834e2c5ded6903b839fcaf566eee90a0ffae53405a0f7748202725e701d39cd"}, + {file = "langchain_community-0.2.1.tar.gz", hash = "sha256:079942e8f15da975769ccaae19042b7bba5481c42020bbbd7d8cad73a9393261"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain-core = ">=0.1.52,<0.2.0" +langchain = ">=0.2.0,<0.3.0" +langchain-core = ">=0.2.0,<0.3.0" langsmith = ">=0.1.0,<0.2.0" numpy = ">=1,<2" PyYAML = ">=5.3" @@ -4086,17 +4129,17 @@ tenacity = ">=8.1.0,<9.0.0" [package.extras] cli = ["typer (>=0.9.0,<0.10.0)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "azure-identity (>=1.15.0,<2.0.0)", "azure-search-documents (==11.4.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.6,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "oracledb (>=2.2.0,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "azure-identity (>=1.15.0,<2.0.0)", "azure-search-documents (==11.4.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.6,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpathlib (>=0.18,<0.19)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "oracledb (>=2.2.0,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] [[package]] name = "langchain-core" -version = "0.1.52" +version = "0.2.1" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_core-0.1.52-py3-none-any.whl", hash = "sha256:62566749c92e8a1181c255c788548dc16dbc319d896cd6b9c95dc17af9b2a6db"}, - {file = "langchain_core-0.1.52.tar.gz", hash = "sha256:084c3fc452f5a6966c28ab3ec5dbc8b8d26fc3f63378073928f4e29d90b6393f"}, + {file = "langchain_core-0.2.1-py3-none-any.whl", hash = "sha256:3521e1e573988c47399fca9739270c5d34f8ecec147253ad829eb9ff288f76d5"}, + {file = "langchain_core-0.2.1.tar.gz", hash = "sha256:49383126168d934559a543ce812c485048d9e6ac9b6798fbf3d4a72b6bba5b0c"}, ] [package.dependencies] @@ -4112,36 +4155,36 @@ extended-testing = ["jinja2 (>=3,<4)"] [[package]] name = "langchain-experimental" -version = "0.0.58" +version = "0.0.59" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_experimental-0.0.58-py3-none-any.whl", hash = "sha256:106d3bc7df3dd20687378db7534c2fc21e2589201d43de42f832a1e3913dd55b"}, - {file = "langchain_experimental-0.0.58.tar.gz", hash = "sha256:8ef10ff6b39f44ef468f8f21beb3749957d2262ec64d05db2719934936ca0285"}, + {file = "langchain_experimental-0.0.59-py3-none-any.whl", hash = "sha256:d6ceb586c15ad35fc619542e86d01f0984a94985324a78a9ed8cd87615ff265d"}, + {file = "langchain_experimental-0.0.59.tar.gz", hash = "sha256:3a93f5c328f6ee1cd4f9dd8792c535df2d5638cff0d778ee25546804b5282fda"}, ] [package.dependencies] -langchain = ">=0.1.17,<0.2.0" -langchain-core = ">=0.1.52,<0.2.0" +langchain-community = ">=0.2,<0.3" +langchain-core = ">=0.2,<0.3" [package.extras] extended-testing = ["faker (>=19.3.1,<20.0.0)", "jinja2 (>=3,<4)", "pandas (>=2.0.1,<3.0.0)", "presidio-analyzer (>=2.2.352,<3.0.0)", "presidio-anonymizer (>=2.2.352,<3.0.0)", "sentence-transformers (>=2,<3)", "tabulate (>=0.9.0,<0.10.0)", "vowpal-wabbit-next (==0.6.0)"] [[package]] name = "langchain-google-genai" -version = "1.0.4" +version = "1.0.5" description = "An integration package connecting Google's genai package and LangChain" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_google_genai-1.0.4-py3-none-any.whl", hash = "sha256:e567cc401f8d629fce489ee031d258da7fa4b7da0abb8ed926d6990c650b659e"}, - {file = "langchain_google_genai-1.0.4.tar.gz", hash = "sha256:b6beccfe7504ce9f8778a8df23dc49239fd91cf076a55d61759a09fc1373ca26"}, + {file = "langchain_google_genai-1.0.5-py3-none-any.whl", hash = "sha256:06b1af072e14fe2d4f9257be4bf883ccd544896094f847c2b1ab09b123ba3b9e"}, + {file = "langchain_google_genai-1.0.5.tar.gz", hash = "sha256:5b515192755fd396a1b61b33d1b08c77fb9b53394cc25954f9d7e9a0f615de9b"}, ] [package.dependencies] google-generativeai = ">=0.5.2,<0.6.0" -langchain-core = ">=0.1.45,<0.3" +langchain-core = ">=0.2.0,<0.3" [package.extras] images = ["pillow (>=10.1.0,<11.0.0)"] @@ -4231,17 +4274,17 @@ pinecone-client = ">=3.2.2,<4.0.0" [[package]] name = "langchain-text-splitters" -version = "0.0.2" +version = "0.2.0" description = "LangChain text splitting utilities" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_text_splitters-0.0.2-py3-none-any.whl", hash = "sha256:13887f32705862c1e1454213cb7834a63aae57c26fcd80346703a1d09c46168d"}, - {file = "langchain_text_splitters-0.0.2.tar.gz", hash = "sha256:ac8927dc0ba08eba702f6961c9ed7df7cead8de19a9f7101ab2b5ea34201b3c1"}, + {file = "langchain_text_splitters-0.2.0-py3-none-any.whl", hash = "sha256:7b4c6a45f8471630a882b321e138329b6897102a5bc62f4c12be1c0b05bb9199"}, + {file = "langchain_text_splitters-0.2.0.tar.gz", hash = "sha256:b32ab4f7397f7d42c1fa3283fefc2547ba356bd63a68ee9092865e5ad83c82f9"}, ] [package.dependencies] -langchain-core = ">=0.1.28,<0.3" +langchain-core = ">=0.2.0,<0.3.0" [package.extras] extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] @@ -4278,12 +4321,12 @@ cachetools = "^5.3.1" cryptography = "^42.0.5" docstring-parser = "^0.15" duckdb = "^0.10.2" -emoji = "^2.11.0" -fastapi = "^0.110.1" +emoji = "^2.12.0" +fastapi = "^0.111.0" gunicorn = "^22.0.0" httpx = "*" jq = {version = "^1.7.0", markers = "sys_platform != \"win32\""} -langchain = "~0.1.16" +langchain = "~0.2.0" langchain-experimental = "*" langchainhub = "~0.1.15" loguru = "^0.7.1" @@ -4294,15 +4337,15 @@ pandas = "2.2.0" passlib = "^1.7.4" pillow = "^10.2.0" platformdirs = "^4.2.0" -pydantic = "^2.5.0" -pydantic-settings = "^2.1.0" -pypdf = "^4.1.0" +pydantic = "^2.7.0" +pydantic-settings = "^2.2.0" +pypdf = "^4.2.0" python-docx = "^1.1.0" python-jose = "^3.3.0" python-multipart = "^0.0.7" python-socketio = "^5.11.0" rich = "^13.7.0" -sqlmodel = "^0.0.16" +sqlmodel = "^0.0.18" typer = "^0.12.0" uvicorn = "^0.29.0" websockets = "*" @@ -4342,13 +4385,13 @@ openai = ["openai (>=0.27.8)"] [[package]] name = "langsmith" -version = "0.1.62" +version = "0.1.63" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.62-py3-none-any.whl", hash = "sha256:3a9f112643f64d736b8c875390c750fe6485804ea53aeae4edebce0afa4383a5"}, - {file = "langsmith-0.1.62.tar.gz", hash = "sha256:7ef894c14e6d4175fce88ec3bcd5a9c8cf9a456ea77e26e361f519ad082f34a8"}, + {file = "langsmith-0.1.63-py3-none-any.whl", hash = "sha256:7810afdf5e3f3b472fc581a29371fb96cd843dde2149e048d1b9610325159d1e"}, + {file = "langsmith-0.1.63.tar.gz", hash = "sha256:a609405b52f6f54df442a142cbf19ab38662d54e532f96028b4c546434d4afdf"}, ] [package.dependencies] @@ -4358,13 +4401,13 @@ requests = ">=2,<3" [[package]] name = "litellm" -version = "1.38.0" +version = "1.38.1" description = "Library to easily interface with LLM API providers" optional = false python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" files = [ - {file = "litellm-1.38.0-py3-none-any.whl", hash = "sha256:bdb63f30999a664ca7361b9c9c7f0a8e3cc10678ddf252455955fd145a96eaa5"}, - {file = "litellm-1.38.0.tar.gz", hash = "sha256:1d77a8572cd9904369393fcdf24f6557e6b01ff9b04d346c2d69c04d23485716"}, + {file = "litellm-1.38.1-py3-none-any.whl", hash = "sha256:03e0bf79fbdf0285f5b2c185f8507056dea0481cb668a63fa1641058795af0c9"}, + {file = "litellm-1.38.1.tar.gz", hash = "sha256:8eed177d5883f11c3f7bdcc78d41379efbff921460c065534cf0f7ef011b0610"}, ] [package.dependencies] @@ -4404,292 +4447,6 @@ dev = ["black (>=23.3.0)", "httpx (>=0.24.1)", "mkdocs (>=1.4.3)", "mkdocs-mater server = ["PyYAML (>=5.1)", "fastapi (>=0.100.0)", "pydantic-settings (>=2.0.1)", "sse-starlette (>=1.6.1)", "starlette-context (>=0.3.6,<0.4)", "uvicorn (>=0.22.0)"] test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"] -[[package]] -name = "llama-index" -version = "0.10.38" -description = "Interface between LLMs and your data" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index-0.10.38-py3-none-any.whl", hash = "sha256:5d521b0ea7111679521292432960d3b9fb53c98d55414bd42d753bc6271d234d"}, - {file = "llama_index-0.10.38.tar.gz", hash = "sha256:5281cfa8b6e7f0f5f12897c00adcd790f7b51c130037f3561fd5630fca37bfb3"}, -] - -[package.dependencies] -llama-index-agent-openai = ">=0.1.4,<0.3.0" -llama-index-cli = ">=0.1.2,<0.2.0" -llama-index-core = ">=0.10.38,<0.11.0" -llama-index-embeddings-openai = ">=0.1.5,<0.2.0" -llama-index-indices-managed-llama-cloud = ">=0.1.2,<0.2.0" -llama-index-legacy = ">=0.9.48,<0.10.0" -llama-index-llms-openai = ">=0.1.13,<0.2.0" -llama-index-multi-modal-llms-openai = ">=0.1.3,<0.2.0" -llama-index-program-openai = ">=0.1.3,<0.2.0" -llama-index-question-gen-openai = ">=0.1.2,<0.2.0" -llama-index-readers-file = ">=0.1.4,<0.2.0" -llama-index-readers-llama-parse = ">=0.1.2,<0.2.0" - -[[package]] -name = "llama-index-agent-openai" -version = "0.2.5" -description = "llama-index agent openai integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_agent_openai-0.2.5-py3-none-any.whl", hash = "sha256:67536bb104b24734f79324207034d948a2ca7e4cc20dd60cf05d6eeb4b12a586"}, - {file = "llama_index_agent_openai-0.2.5.tar.gz", hash = "sha256:45f4cc670d037a8a67f541d3a4d095f7f61caff6ed2c25702441eb1116d4b495"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.35,<0.11.0" -llama-index-llms-openai = ">=0.1.5,<0.2.0" -openai = ">=1.14.0" - -[[package]] -name = "llama-index-cli" -version = "0.1.12" -description = "llama-index cli" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_cli-0.1.12-py3-none-any.whl", hash = "sha256:d80d546786f02d3f16f6183b8e86b22b8b5c33a1500923659f2ccbff8d5df634"}, - {file = "llama_index_cli-0.1.12.tar.gz", hash = "sha256:3cf1f706c3c69c6b1aab07fca7faad3959db1709808efd50491b669d38b0b580"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.11.post1,<0.11.0" -llama-index-embeddings-openai = ">=0.1.1,<0.2.0" -llama-index-llms-openai = ">=0.1.1,<0.2.0" - -[[package]] -name = "llama-index-core" -version = "0.10.38.post2" -description = "Interface between LLMs and your data" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_core-0.10.38.post2-py3-none-any.whl", hash = "sha256:b4b55449bac458d339e84d8d26f322b4dc9f36d3682ebb41fccf5594c295620f"}, - {file = "llama_index_core-0.10.38.post2.tar.gz", hash = "sha256:9eff6e16e9045deca9cb58bcf2a4b9ba39d0da12d7493e6aebaa5badd3b3ebb5"}, -] - -[package.dependencies] -aiohttp = ">=3.8.6,<4.0.0" -dataclasses-json = "*" -deprecated = ">=1.2.9.3" -dirtyjson = ">=1.0.8,<2.0.0" -fsspec = ">=2023.5.0" -httpx = "*" -llamaindex-py-client = ">=0.1.18,<0.2.0" -nest-asyncio = ">=1.5.8,<2.0.0" -networkx = ">=3.0" -nltk = ">=3.8.1,<4.0.0" -numpy = "*" -openai = ">=1.1.0" -pandas = "*" -pillow = ">=9.0.0" -PyYAML = ">=6.0.1" -requests = ">=2.31.0" -SQLAlchemy = {version = ">=1.4.49", extras = ["asyncio"]} -tenacity = ">=8.2.0,<9.0.0" -tiktoken = ">=0.3.3" -tqdm = ">=4.66.1,<5.0.0" -typing-extensions = ">=4.5.0" -typing-inspect = ">=0.8.0" -wrapt = "*" - -[[package]] -name = "llama-index-embeddings-openai" -version = "0.1.10" -description = "llama-index embeddings openai integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_embeddings_openai-0.1.10-py3-none-any.whl", hash = "sha256:c3cfa83b537ded34d035fc172a945dd444c87fb58a89b02dfbf785b675f9f681"}, - {file = "llama_index_embeddings_openai-0.1.10.tar.gz", hash = "sha256:1bc1fc9b46773a12870c5d3097d3735d7ca33805f12462a8e35ae8a6e5ce1cf6"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.1,<0.11.0" - -[[package]] -name = "llama-index-indices-managed-llama-cloud" -version = "0.1.6" -description = "llama-index indices llama-cloud integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_indices_managed_llama_cloud-0.1.6-py3-none-any.whl", hash = "sha256:cba33e1a3677b2a2ae7f239119acbf6dc3818f105edc92315729842b56fbc949"}, - {file = "llama_index_indices_managed_llama_cloud-0.1.6.tar.gz", hash = "sha256:74b3b0e9ebf9d348d3054f9fc0c657031acceb9351c31116ad8d5a7ae4729f5c"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.0,<0.11.0" -llamaindex-py-client = ">=0.1.19,<0.2.0" - -[[package]] -name = "llama-index-legacy" -version = "0.9.48" -description = "Interface between LLMs and your data" -optional = false -python-versions = ">=3.8.1,<4.0" -files = [ - {file = "llama_index_legacy-0.9.48-py3-none-any.whl", hash = "sha256:714ada95beac179b4acefa4d2deff74bb7b2f22b0f699ac247d4cb67738d16d4"}, - {file = "llama_index_legacy-0.9.48.tar.gz", hash = "sha256:82ddc4691edbf49533d65582c249ba22c03fe96fbd3e92f7758dccef28e43834"}, -] - -[package.dependencies] -aiohttp = ">=3.8.6,<4.0.0" -dataclasses-json = "*" -deprecated = ">=1.2.9.3" -dirtyjson = ">=1.0.8,<2.0.0" -fsspec = ">=2023.5.0" -httpx = "*" -nest-asyncio = ">=1.5.8,<2.0.0" -networkx = ">=3.0" -nltk = ">=3.8.1,<4.0.0" -numpy = "*" -openai = ">=1.1.0" -pandas = "*" -requests = ">=2.31.0" -SQLAlchemy = {version = ">=1.4.49", extras = ["asyncio"]} -tenacity = ">=8.2.0,<9.0.0" -tiktoken = ">=0.3.3" -typing-extensions = ">=4.5.0" -typing-inspect = ">=0.8.0" - -[package.extras] -gradientai = ["gradientai (>=1.4.0)"] -html = ["beautifulsoup4 (>=4.12.2,<5.0.0)"] -langchain = ["langchain (>=0.0.303)"] -local-models = ["optimum[onnxruntime] (>=1.13.2,<2.0.0)", "sentencepiece (>=0.1.99,<0.2.0)", "transformers[torch] (>=4.33.1,<5.0.0)"] -postgres = ["asyncpg (>=0.28.0,<0.29.0)", "pgvector (>=0.1.0,<0.2.0)", "psycopg2-binary (>=2.9.9,<3.0.0)"] -query-tools = ["guidance (>=0.0.64,<0.0.65)", "jsonpath-ng (>=1.6.0,<2.0.0)", "lm-format-enforcer (>=0.4.3,<0.5.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "scikit-learn", "spacy (>=3.7.1,<4.0.0)"] - -[[package]] -name = "llama-index-llms-openai" -version = "0.1.20" -description = "llama-index llms openai integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_llms_openai-0.1.20-py3-none-any.whl", hash = "sha256:f27401acdf9f65bf4d866a100615dcbd81987b890ae5fa9c513d544ba6d711e7"}, - {file = "llama_index_llms_openai-0.1.20.tar.gz", hash = "sha256:0282e4e252893487afd72383b46da5b28ddcd3fb73bace1caefce8a36e9cf492"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.24,<0.11.0" - -[[package]] -name = "llama-index-multi-modal-llms-openai" -version = "0.1.6" -description = "llama-index multi-modal-llms openai integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_multi_modal_llms_openai-0.1.6-py3-none-any.whl", hash = "sha256:0b6950a6cf98d16ade7d3b9dd0821ecfe457ca103819ae6c3e66cfc9634ca646"}, - {file = "llama_index_multi_modal_llms_openai-0.1.6.tar.gz", hash = "sha256:10de75a877a444af35306385faad9b9f0624391e55309970564114a080a0578c"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.1,<0.11.0" -llama-index-llms-openai = ">=0.1.1,<0.2.0" - -[[package]] -name = "llama-index-program-openai" -version = "0.1.6" -description = "llama-index program openai integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_program_openai-0.1.6-py3-none-any.whl", hash = "sha256:4660b338503537c5edca1e0dab606af6ce372b4f1b597e2833c6b602447c5d8d"}, - {file = "llama_index_program_openai-0.1.6.tar.gz", hash = "sha256:c6a4980c5ea826088b28b4dee3367edb20221e6d05eb0e05019049190131d772"}, -] - -[package.dependencies] -llama-index-agent-openai = ">=0.1.1,<0.3.0" -llama-index-core = ">=0.10.1,<0.11.0" -llama-index-llms-openai = ">=0.1.1,<0.2.0" - -[[package]] -name = "llama-index-question-gen-openai" -version = "0.1.3" -description = "llama-index question_gen openai integration" -optional = false -python-versions = ">=3.8.1,<4.0" -files = [ - {file = "llama_index_question_gen_openai-0.1.3-py3-none-any.whl", hash = "sha256:1f83b49e8b2e665030d1ec8c54687d6985d9fa8426147b64e46628a9e489b302"}, - {file = "llama_index_question_gen_openai-0.1.3.tar.gz", hash = "sha256:4486198117a45457d2e036ae60b93af58052893cc7d78fa9b6f47dd47b81e2e1"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.1,<0.11.0" -llama-index-llms-openai = ">=0.1.1,<0.2.0" -llama-index-program-openai = ">=0.1.1,<0.2.0" - -[[package]] -name = "llama-index-readers-file" -version = "0.1.22" -description = "llama-index readers file integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_readers_file-0.1.22-py3-none-any.whl", hash = "sha256:a8d4a69a9ea659c14ebb22ca9a5560b9c7ec6f501e7f68f6c52f591374165376"}, - {file = "llama_index_readers_file-0.1.22.tar.gz", hash = "sha256:37de54ad0cfbdc607c195532b9a292417a4714f57773570b87027b8dc381f0e2"}, -] - -[package.dependencies] -beautifulsoup4 = ">=4.12.3,<5.0.0" -llama-index-core = ">=0.10.1,<0.11.0" -pypdf = ">=4.0.1,<5.0.0" -striprtf = ">=0.0.26,<0.0.27" - -[package.extras] -pymupdf = ["pymupdf (>=1.23.21,<2.0.0)"] - -[[package]] -name = "llama-index-readers-llama-parse" -version = "0.1.4" -description = "llama-index readers llama-parse integration" -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_index_readers_llama_parse-0.1.4-py3-none-any.whl", hash = "sha256:c4914b37d12cceee56fbd185cca80f87d60acbf8ea7a73f9719610180be1fcdd"}, - {file = "llama_index_readers_llama_parse-0.1.4.tar.gz", hash = "sha256:78608b193c818894aefeee0aa303f02b7f80f2e4caf13866c2fd3b0b1023e2c0"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.7,<0.11.0" -llama-parse = ">=0.4.0,<0.5.0" - -[[package]] -name = "llama-parse" -version = "0.4.3" -description = "Parse files into RAG-Optimized formats." -optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "llama_parse-0.4.3-py3-none-any.whl", hash = "sha256:c48c53a3080daeede293df620dddb1f381e084c31ee2dd44dce3f8615df723e8"}, - {file = "llama_parse-0.4.3.tar.gz", hash = "sha256:01836147b5238873b24a7dd41c5ab942b01b09b92d75570f30cf2861c084a0eb"}, -] - -[package.dependencies] -llama-index-core = ">=0.10.29" - -[[package]] -name = "llamaindex-py-client" -version = "0.1.19" -description = "" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "llamaindex_py_client-0.1.19-py3-none-any.whl", hash = "sha256:fd9416fd78b97209bf323bc3c7fab314499778563e7274f10853ad560563d10e"}, - {file = "llamaindex_py_client-0.1.19.tar.gz", hash = "sha256:73f74792bb8c092bae6dc626627a09ac13a099fa8d10f8fcc83e17a2b332cca7"}, -] - -[package.dependencies] -httpx = ">=0.20.0" -pydantic = ">=1.10" - [[package]] name = "locust" version = "2.28.0" @@ -4911,6 +4668,21 @@ babel = ["Babel"] lingua = ["lingua"] testing = ["pytest"] +[[package]] +name = "markdown" +version = "3.6" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, + {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, +] + +[package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -5494,31 +5266,6 @@ doc = ["myst-nb (>=1.0)", "numpydoc (>=1.7)", "pillow (>=9.4)", "pydata-sphinx-t extra = ["lxml (>=4.6)", "pydot (>=2.0)", "pygraphviz (>=1.12)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] -[[package]] -name = "nltk" -version = "3.8.1" -description = "Natural Language Toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "nltk-3.8.1-py3-none-any.whl", hash = "sha256:fd5c9109f976fa86bcadba8f91e47f5e9293bd034474752e92a520f81c93dda5"}, - {file = "nltk-3.8.1.zip", hash = "sha256:1834da3d0682cba4f2cede2f9aad6b0fafb6461ba451db0efb6f9c39798d64d3"}, -] - -[package.dependencies] -click = "*" -joblib = "*" -regex = ">=2021.8.3" -tqdm = "*" - -[package.extras] -all = ["matplotlib", "numpy", "pyparsing", "python-crfsuite", "requests", "scikit-learn", "scipy", "twython"] -corenlp = ["requests"] -machine-learning = ["numpy", "python-crfsuite", "scikit-learn", "scipy"] -plot = ["matplotlib"] -tgrep = ["pyparsing"] -twitter = ["twython"] - [[package]] name = "nodeenv" version = "1.8.0" @@ -6756,53 +6503,6 @@ files = [ {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, ] -[[package]] -name = "pulsar-client" -version = "3.5.0" -description = "Apache Pulsar Python client library" -optional = false -python-versions = "*" -files = [ - {file = "pulsar_client-3.5.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:c18552edb2f785de85280fe624bc507467152bff810fc81d7660fa2dfa861f38"}, - {file = "pulsar_client-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18d438e456c146f01be41ef146f649dedc8f7bc714d9eaef94cff2e34099812b"}, - {file = "pulsar_client-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18a26a0719841103c7a89eb1492c4a8fedf89adaa386375baecbb4fa2707e88f"}, - {file = "pulsar_client-3.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ab0e1605dc5f44a126163fd06cd0a768494ad05123f6e0de89a2c71d6e2d2319"}, - {file = "pulsar_client-3.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdef720891b97656fdce3bf5913ea7729b2156b84ba64314f432c1e72c6117fa"}, - {file = "pulsar_client-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:a42544e38773191fe550644a90e8050579476bb2dcf17ac69a4aed62a6cb70e7"}, - {file = "pulsar_client-3.5.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:fd94432ea5d398ea78f8f2e09a217ec5058d26330c137a22690478c031e116da"}, - {file = "pulsar_client-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6252ae462e07ece4071213fdd9c76eab82ca522a749f2dc678037d4cbacd40b"}, - {file = "pulsar_client-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03b4d440b2d74323784328b082872ee2f206c440b5d224d7941eb3c083ec06c6"}, - {file = "pulsar_client-3.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f60af840b8d64a2fac5a0c1ce6ae0ddffec5f42267c6ded2c5e74bad8345f2a1"}, - {file = "pulsar_client-3.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2277a447c3b7f6571cb1eb9fc5c25da3fdd43d0b2fb91cf52054adfadc7d6842"}, - {file = "pulsar_client-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:f20f3e9dd50db2a37059abccad42078b7a4754b8bc1d3ae6502e71c1ad2209f0"}, - {file = "pulsar_client-3.5.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:d61f663d85308e12f44033ba95af88730f581a7e8da44f7a5c080a3aaea4878d"}, - {file = "pulsar_client-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1ba0be25b6f747bcb28102b7d906ec1de48dc9f1a2d9eacdcc6f44ab2c9e17"}, - {file = "pulsar_client-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a181e3e60ac39df72ccb3c415d7aeac61ad0286497a6e02739a560d5af28393a"}, - {file = "pulsar_client-3.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3c72895ff7f51347e4f78b0375b2213fa70dd4790bbb78177b4002846f1fd290"}, - {file = "pulsar_client-3.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:547dba1b185a17eba915e51d0a3aca27c80747b6187e5cd7a71a3ca33921decc"}, - {file = "pulsar_client-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:443b786eed96bc86d2297a6a42e79f39d1abf217ec603e0bd303f3488c0234af"}, - {file = "pulsar_client-3.5.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:15b58f5d759dd6166db8a2d90ed05a38063b05cda76c36d190d86ef5c9249397"}, - {file = "pulsar_client-3.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af34bfe813dddf772a8a298117fa0a036ee963595d8bc8f00d969a0329ae6ed9"}, - {file = "pulsar_client-3.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a0fec1dd74e1367d3742ce16679c1807994df60f5e666f440cf39323938fad"}, - {file = "pulsar_client-3.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbcd26ef9c03f96fb9cd91baec3bbd3c4b997834eb3556670d31f41cc25b5f64"}, - {file = "pulsar_client-3.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:afea1d0b6e793fd56e56463145751ff3aa79fdcd5b26e90d0da802a1bbabe07e"}, - {file = "pulsar_client-3.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:da1ab2fb1bef64b966e9403a0a186ebc90368d99e054ce2cae5b1128478f4ef4"}, - {file = "pulsar_client-3.5.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:9ad5dcc0eb8d2a7c0fb8e1fa146a0c6d4bdaf934f1169080b2c64b2f0573e086"}, - {file = "pulsar_client-3.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5870c6805b1a57962ed908d1173e97e13470415998393925c86a43694420389"}, - {file = "pulsar_client-3.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29cb5fedb969895b78301dc00a979133e69940812b8332e4de948bb0ad3db7cb"}, - {file = "pulsar_client-3.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e53c74bfa59b20c66adea95023169060f5048dd8d843e6ef9cd3b8ee2d23e93b"}, - {file = "pulsar_client-3.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99dbadb13967f1add57010971ed36b5a77d24afcdaea01960d0e55e56cf4ba6f"}, - {file = "pulsar_client-3.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:058887661d438796f42307dcc8054c84dea88a37683dae36498b95d7e1c39b37"}, -] - -[package.dependencies] -certifi = "*" - -[package.extras] -all = ["apache-bookkeeper-client (>=4.16.1)", "fastavro (>=1.9.2)", "grpcio (>=1.60.0)", "prometheus-client", "protobuf (>=3.6.1,<=3.20.3)", "ratelimit"] -avro = ["fastavro (>=1.9.2)"] -functions = ["apache-bookkeeper-client (>=4.16.1)", "grpcio (>=1.60.0)", "prometheus-client", "protobuf (>=3.6.1,<=3.20.3)", "ratelimit"] - [[package]] name = "pure-eval" version = "0.2.2" @@ -7338,13 +7038,13 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" -version = "4.1.0" +version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, - {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, ] [package.dependencies] @@ -7352,7 +7052,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-instafail" @@ -8036,28 +7736,28 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.3.7" +version = "0.4.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, - {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, - {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, - {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, - {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, - {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, + {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"}, + {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"}, + {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"}, + {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"}, + {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"}, + {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"}, ] [[package]] @@ -8502,7 +8202,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", optional = true, markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\" or extra == \"asyncio\""} +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} typing-extensions = ">=4.6.0" [package.extras] @@ -8532,13 +8232,13 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlmodel" -version = "0.0.16" +version = "0.0.18" description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.7" files = [ - {file = "sqlmodel-0.0.16-py3-none-any.whl", hash = "sha256:b972f5d319580d6c37ecc417881f6ec4d1ad3ed3583d0ac0ed43234a28bf605a"}, - {file = "sqlmodel-0.0.16.tar.gz", hash = "sha256:966656f18a8e9a2d159eb215b07fb0cf5222acfae3362707ca611848a8a06bd1"}, + {file = "sqlmodel-0.0.18-py3-none-any.whl", hash = "sha256:d70fdf8fe595e30a918660cf4537b9c5fc2fffdbfcba851a0135de73c3ebcbb7"}, + {file = "sqlmodel-0.0.18.tar.gz", hash = "sha256:2e520efe03810ef2c268a1004cfc5ef8f8a936312232f38d6c8e62c11af2cac3"}, ] [package.dependencies] @@ -8613,17 +8313,6 @@ docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] release = ["twine"] test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] -[[package]] -name = "striprtf" -version = "0.0.26" -description = "A simple library to convert rtf to text" -optional = false -python-versions = "*" -files = [ - {file = "striprtf-0.0.26-py3-none-any.whl", hash = "sha256:8c8f9d32083cdc2e8bfb149455aa1cc5a4e0a035893bedc75db8b73becb3a1bb"}, - {file = "striprtf-0.0.26.tar.gz", hash = "sha256:fdb2bba7ac440072d1c41eab50d8d74ae88f60a8b6575c6e2c7805dc462093aa"}, -] - [[package]] name = "structlog" version = "24.1.0" @@ -9322,13 +9011,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, ] [[package]] @@ -9472,6 +9161,17 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "uuid6" +version = "2024.1.12" +description = "New time-based UUID formats which are suited for use as a database key" +optional = false +python-versions = ">=3.8" +files = [ + {file = "uuid6-2024.1.12-py3-none-any.whl", hash = "sha256:8150093c8d05a331bc0535bc5ef6cf57ac6eceb2404fd319bc10caee2e02c065"}, + {file = "uuid6-2024.1.12.tar.gz", hash = "sha256:ed0afb3a973057575f9883201baefe402787ca5e11e1d24e377190f0c43f1993"}, +] + [[package]] name = "uvicorn" version = "0.29.0" @@ -10158,6 +9858,20 @@ files = [ idna = ">=2.0" multidict = ">=4.0" +[[package]] +name = "youtube-transcript-api" +version = "0.6.2" +description = "This is an python API which allows you to get the transcripts/subtitles for a given YouTube video. It also works for automatically generated subtitles, supports translating subtitles and it does not require a headless browser, like other selenium based solutions do!" +optional = false +python-versions = "*" +files = [ + {file = "youtube_transcript_api-0.6.2-py3-none-any.whl", hash = "sha256:019dbf265c6a68a0591c513fff25ed5a116ce6525832aefdfb34d4df5567121c"}, + {file = "youtube_transcript_api-0.6.2.tar.gz", hash = "sha256:cad223d7620633cec44f657646bffc8bbc5598bd8e70b1ad2fa8277dec305eb7"}, +] + +[package.dependencies] +requests = "*" + [[package]] name = "zep-python" version = "2.0.0rc6" @@ -10260,4 +9974,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "9406313d19280623987bf2ee831626bc79ec0abf0ec1fe547df89bc9b1b93b0d" +content-hash = "33629727ceeb0aa86064658e89349c24fd786bb1bd3833f093651b70b264edb7" diff --git a/pyproject.toml b/pyproject.toml index cc7198812..6f35ebe1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,20 +29,20 @@ python = ">=3.10,<3.13" langflow-base = { path = "./src/backend/base", develop = true } beautifulsoup4 = "^4.12.2" google-search-results = "^2.4.1" -google-api-python-client = "^2.118.0" +google-api-python-client = "^2.130.0" huggingface-hub = { version = "^0.20.0", extras = ["inference"] } llama-cpp-python = { version = "~0.2.0", optional = true } networkx = "^3.1" -fake-useragent = "^1.4.0" +fake-useragent = "^1.5.0" psycopg2-binary = "^2.9.6" pyarrow = "^14.0.0" wikipedia = "^1.4.0" -qdrant-client = "^1.7.0" +qdrant-client = "^1.9.0" weaviate-client = "*" sentence-transformers = { version = "^2.3.1", optional = true } ctransformers = { version = "^0.2.10", optional = true } -cohere = "^5.1.7" -faiss-cpu = "^1.7.4" +cohere = "^5.5.3" +faiss-cpu = "^1.8.0" types-cachetools = "^5.3.0.5" pinecone-client = "^3.0.3" pymongo = "^4.6.0" @@ -56,7 +56,7 @@ redis = { version = "^5.0.1", optional = true } flower = { version = "^2.0.0", optional = true } metaphor-python = "^0.1.11" pywin32 = { version = "^306", markers = "sys_platform == 'win32'" } -langfuse = "^2.9.0" +langfuse = "^2.33.0" metal-sdk = "^2.5.0" markupsafe = "^2.1.3" # jq is not available for windows @@ -69,14 +69,12 @@ langchain-google-genai = "^1.0.1" langchain-cohere = "^0.1.0rc1" elasticsearch = "^8.12.0" pytube = "^15.0.0" -llama-index = "^0.10.13" -# unstructured = { extras = ["md"], version = "^0.12.4" } dspy-ai = "^2.4.0" -assemblyai = "^0.23.1" -litellm = "^1.34.22" -chromadb = "^0.4.24" +assemblyai = "^0.26.0" +litellm = "^1.38.0" +chromadb = "^0.5.0" langchain-anthropic = "^0.1.6" -langchain-astradb = "^0.1.0" +langchain-astradb = "^0.3.0" langchain-openai = "^0.1.1" zep-python = { version = "^2.0.0rc5", allow-prereleases = true } langchain-google-vertexai = "^1.0.3" @@ -84,26 +82,28 @@ langchain-groq = "^0.1.3" langchain-pinecone = "^0.1.0" langchain-mistralai = "^0.1.6" couchbase = "^4.2.1" +youtube-transcript-api = "^0.6.2" +markdown = "^3.6" [tool.poetry.group.dev.dependencies] types-redis = "^4.6.0.5" ipykernel = "^6.29.0" -mypy = "^1.9.0" -ruff = "^0.3.5" +mypy = "^1.10.0" +ruff = "^0.4.5" httpx = "*" -pytest = "^8.1.0" -types-requests = "^2.31.0" -requests = "^2.31.0" -pytest-cov = "^4.1.0" +pytest = "^8.2.0" +types-requests = "^2.32.0" +requests = "^2.32.0" +pytest-cov = "^5.0.0" pandas-stubs = "^2.1.4.231227" types-pillow = "^10.2.0.20240213" types-pyyaml = "^6.0.12.8" types-python-jose = "^3.3.4.8" types-passlib = "^1.7.7.13" locust = "^2.23.1" -pytest-mock = "^3.12.0" -pytest-xdist = "^3.5.0" +pytest-mock = "^3.14.0" +pytest-xdist = "^3.6.0" types-pywin32 = "^306.0.0.4" types-google-cloud-ndb = "^2.2.0.0" pytest-sugar = "^1.0.0" diff --git a/src/backend/base/langflow/api/utils.py b/src/backend/base/langflow/api/utils.py index f7e0548fe..ffb5f22c9 100644 --- a/src/backend/base/langflow/api/utils.py +++ b/src/backend/base/langflow/api/utils.py @@ -1,4 +1,3 @@ -import os import warnings from pathlib import Path from typing import TYPE_CHECKING, Optional diff --git a/src/backend/base/langflow/api/v1/callback.py b/src/backend/base/langflow/api/v1/callback.py index b326311ac..6a60ea037 100644 --- a/src/backend/base/langflow/api/v1/callback.py +++ b/src/backend/base/langflow/api/v1/callback.py @@ -1,13 +1,12 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional from uuid import UUID - -from langchain.schema import AgentAction, AgentFinish from langchain_core.callbacks.base import AsyncCallbackHandler from loguru import logger from langflow.api.v1.schemas import ChatResponse, PromptResponse from langflow.services.deps import get_chat_service, get_socket_service from langflow.utils.util import remove_ansi_escape_codes +from langchain_core.agents import AgentAction, AgentFinish if TYPE_CHECKING: from langflow.services.socket.service import SocketIOService diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py index e529de81c..e7bb761ba 100644 --- a/src/backend/base/langflow/api/v1/endpoints.py +++ b/src/backend/base/langflow/api/v1/endpoints.py @@ -19,7 +19,6 @@ from langflow.api.v1.schemas import ( UploadFileResponse, ) from langflow.graph.graph.base import Graph -from langflow.graph.schema import RunOutputs from langflow.interface.custom.custom_component import CustomComponent from langflow.interface.custom.utils import build_custom_component_template from langflow.processing.process import process_tweaks, run_graph_internal diff --git a/src/backend/base/langflow/api/v1/folders.py b/src/backend/base/langflow/api/v1/folders.py index 96729133b..3aa57842c 100644 --- a/src/backend/base/langflow/api/v1/folders.py +++ b/src/backend/base/langflow/api/v1/folders.py @@ -3,12 +3,11 @@ from uuid import UUID import orjson from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status -from sqlalchemy import update +from sqlalchemy import or_, update from sqlmodel import Session, select from langflow.api.v1.flows import create_flows from langflow.api.v1.schemas import FlowListCreate, FlowListReadWithFolderName -from langflow.initial_setup.setup import STARTER_FOLDER_NAME from langflow.services.auth.utils import get_current_active_user from langflow.services.database.models.flow.model import Flow, FlowCreate, FlowRead from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME @@ -35,6 +34,18 @@ def create_folder( try: new_folder = Folder.model_validate(folder, from_attributes=True) new_folder.user_id = current_user.id + + folder_results = session.exec( + select(Folder).where( + Folder.name.like(f"{new_folder.name}%"), # type: ignore + Folder.user_id == current_user.id, + ) + ) + existing_folder_names = [folder.name for folder in folder_results] + + if existing_folder_names: + new_folder.name = f"{new_folder.name} ({len(existing_folder_names) + 1})" + session.add(new_folder) session.commit() session.refresh(new_folder) @@ -63,16 +74,11 @@ def read_folders( current_user: User = Depends(get_current_active_user), ): try: - folders = session.exec(select(Folder).where(Folder.user_id == current_user.id)).all() - return folders - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - - -@router.get("/starter-projects", response_model=FolderReadWithFlows, status_code=200) -def read_starter_folders(*, session: Session = Depends(get_session)): - try: - folders = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first() + folders = session.exec( + select(Folder).where( + or_(Folder.user_id == current_user.id, Folder.user_id == None) # type: ignore # noqa: E711 + ) + ).all() return folders except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/base/prompts/api_utils.py b/src/backend/base/langflow/base/prompts/api_utils.py index 89a17399c..d5a6aac28 100644 --- a/src/backend/base/langflow/base/prompts/api_utils.py +++ b/src/backend/base/langflow/base/prompts/api_utils.py @@ -1,10 +1,10 @@ from fastapi import HTTPException -from langchain.prompts import PromptTemplate from loguru import logger from langflow.api.v1.base import INVALID_NAMES, check_input_variables from langflow.interface.utils import extract_input_variables_from_prompt from langflow.template.field.prompt import DefaultPromptField +from langchain_core.prompts import PromptTemplate def validate_prompt(prompt_template: str, silent_errors: bool = False) -> list[str]: diff --git a/src/backend/base/langflow/components/agents/JsonAgent.py b/src/backend/base/langflow/components/agents/JsonAgent.py index 5fa342417..51f20d71d 100644 --- a/src/backend/base/langflow/components/agents/JsonAgent.py +++ b/src/backend/base/langflow/components/agents/JsonAgent.py @@ -1,10 +1,11 @@ -from langchain.agents import AgentExecutor, create_json_agent +from langchain.agents import AgentExecutor from langchain_community.agent_toolkits.json.toolkit import JsonToolkit from langflow.field_typing import ( BaseLanguageModel, ) from langflow.interface.custom.custom_component import CustomComponent +from langchain_community.agent_toolkits import create_json_agent class JsonAgentComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py b/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py index bda2579f6..c4287569a 100644 --- a/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py +++ b/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py @@ -4,15 +4,14 @@ from langchain.agents.agent import AgentExecutor from langchain.agents.agent_toolkits.conversational_retrieval.openai_functions import _get_default_system_message from langchain.agents.openai_functions_agent.base import OpenAIFunctionsAgent from langchain.memory.token_buffer import ConversationTokenBufferMemory -from langchain.prompts import SystemMessagePromptTemplate -from langchain.prompts.chat import MessagesPlaceholder -from langchain.schema.memory import BaseMemory -from langchain.tools import Tool from langchain_openai import ChatOpenAI from langflow.field_typing.range_spec import RangeSpec from langflow.interface.custom.custom_component import CustomComponent from pydantic.v1 import SecretStr +from langchain_core.memory import BaseMemory +from langchain_core.prompts import MessagesPlaceholder, SystemMessagePromptTemplate +from langchain_core.tools import Tool class ConversationalAgent(CustomComponent): diff --git a/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py b/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py index d4330d9e4..c8cf2a96b 100644 --- a/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py @@ -1,9 +1,8 @@ from typing import Optional - -from langchain.embeddings.base import Embeddings from langchain_community.embeddings import BedrockEmbeddings from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.embeddings import Embeddings class AmazonBedrockEmeddingsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py b/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py index d8aec24cd..5e02890ff 100644 --- a/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py @@ -1,7 +1,7 @@ -from langchain.embeddings.base import Embeddings -from langchain_community.embeddings import AzureOpenAIEmbeddings - from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.embeddings import Embeddings +from langchain_openai import AzureOpenAIEmbeddings +from pydantic.v1 import SecretStr class AzureOpenAIEmbeddingsComponent(CustomComponent): @@ -52,12 +52,16 @@ class AzureOpenAIEmbeddingsComponent(CustomComponent): api_version: str, api_key: str, ) -> Embeddings: + if api_key: + azure_api_key = SecretStr(api_key) + else: + azure_api_key = None try: embeddings = AzureOpenAIEmbeddings( azure_endpoint=azure_endpoint, azure_deployment=azure_deployment, api_version=api_version, - api_key=api_key, + api_key=azure_api_key, ) except Exception as e: diff --git a/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py b/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py index 63ddc6fd4..575df2d3f 100644 --- a/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py @@ -1,9 +1,8 @@ from typing import Optional - -from langchain.embeddings.base import Embeddings from langchain_community.embeddings import OllamaEmbeddings from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.embeddings import Embeddings class OllamaEmbeddingsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/memories/AstraDBMessageReader.py b/src/backend/base/langflow/components/memories/AstraDBMessageReader.py index 9b82dd308..bbb732f16 100644 --- a/src/backend/base/langflow/components/memories/AstraDBMessageReader.py +++ b/src/backend/base/langflow/components/memories/AstraDBMessageReader.py @@ -51,9 +51,7 @@ class AstraDBMessageReaderComponent(BaseMemoryComponent): Returns: list[Record]: A list of Record objects representing the search results. """ - memory: AstraDBChatMessageHistory = cast( - AstraDBChatMessageHistory, kwargs.get("memory") - ) + memory: AstraDBChatMessageHistory = cast(AstraDBChatMessageHistory, kwargs.get("memory")) if not memory: raise ValueError("AstraDBChatMessageHistory instance is required.") @@ -72,9 +70,7 @@ class AstraDBMessageReaderComponent(BaseMemoryComponent): namespace: Optional[str] = None, ) -> list[Record]: try: - from langchain_community.chat_message_histories.astradb import ( - AstraDBChatMessageHistory, - ) + pass except ImportError: raise ImportError( "Could not import langchain Astra DB integration package. " diff --git a/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py b/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py index 33525656e..265f60cf4 100644 --- a/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py +++ b/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py @@ -5,7 +5,7 @@ from langflow.field_typing import Text from langflow.schema.schema import Record from langchain_core.messages import BaseMessage -from langchain_community.chat_message_histories.astradb import AstraDBChatMessageHistory +from langchain_astradb import AstraDBChatMessageHistory class AstraDBMessageWriterComponent(BaseMemoryComponent): @@ -74,13 +74,15 @@ class AstraDBMessageWriterComponent(BaseMemoryComponent): if memory is None: raise ValueError("AstraDBChatMessageHistory instance is required.") - text_list = [BaseMessage( - content=text, - sender=sender, - sender_name=sender_name, - metadata=metadata, - session_id=session_id, - )] + text_list = [ + BaseMessage( + content=text, + sender=sender, + sender_name=sender_name, + metadata=metadata, + session_id=session_id, + ) + ] memory.add_messages(text_list) @@ -94,9 +96,7 @@ class AstraDBMessageWriterComponent(BaseMemoryComponent): namespace: Optional[str] = None, ) -> Record: try: - from langchain_community.chat_message_histories.astradb import ( - AstraDBChatMessageHistory, - ) + pass except ImportError: raise ImportError( "Could not import langchain Astra DB integration package. " diff --git a/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py b/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py index 016eaeb2d..d83ad23a0 100644 --- a/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py +++ b/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py @@ -1,10 +1,9 @@ from typing import Optional - -from langchain.llms.base import BaseLanguageModel from langchain_anthropic import ChatAnthropic from pydantic.v1 import SecretStr from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.language_models import BaseLanguageModel class ChatAntropicSpecsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py b/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py index 6f468bbed..c0fd2b779 100644 --- a/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py @@ -1,9 +1,9 @@ from typing import Optional -from langchain.llms.base import BaseLanguageModel -from langchain_community.chat_models.azure_openai import AzureChatOpenAI - from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.language_models import BaseLanguageModel +from langchain_openai import AzureChatOpenAI +from pydantic.v1 import SecretStr class AzureChatOpenAISpecsComponent(CustomComponent): @@ -84,13 +84,17 @@ class AzureChatOpenAISpecsComponent(CustomComponent): temperature: float = 0.7, max_tokens: Optional[int] = 1000, ) -> BaseLanguageModel: + if api_key: + azure_api_key = SecretStr(api_key) + else: + azure_api_key = None try: llm = AzureChatOpenAI( model=model, azure_endpoint=azure_endpoint, azure_deployment=azure_deployment, api_version=api_version, - api_key=api_key, + api_key=azure_api_key, temperature=temperature, max_tokens=max_tokens, ) diff --git a/src/backend/base/langflow/components/retrievers/AmazonKendra.py b/src/backend/base/langflow/components/retrievers/AmazonKendra.py index 6584f6545..436f69d0f 100644 --- a/src/backend/base/langflow/components/retrievers/AmazonKendra.py +++ b/src/backend/base/langflow/components/retrievers/AmazonKendra.py @@ -1,9 +1,8 @@ from typing import Optional - -from langchain.schema import BaseRetriever from langchain_community.retrievers import AmazonKendraRetriever from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.retrievers import BaseRetriever class AmazonKendraRetrieverComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/retrievers/MetalRetriever.py b/src/backend/base/langflow/components/retrievers/MetalRetriever.py index c5c56a397..4f1e71dd1 100644 --- a/src/backend/base/langflow/components/retrievers/MetalRetriever.py +++ b/src/backend/base/langflow/components/retrievers/MetalRetriever.py @@ -1,10 +1,9 @@ from typing import Optional - -from langchain.schema import BaseRetriever from langchain_community.retrievers import MetalRetriever from metal_sdk.metal import Metal # type: ignore from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.retrievers import BaseRetriever class MetalRetrieverComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py b/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py index 759021487..0f5db6383 100644 --- a/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py +++ b/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py @@ -1,13 +1,12 @@ import json from typing import List - -from langchain.base_language import BaseLanguageModel from langchain.chains.query_constructor.base import AttributeInfo from langchain.retrievers.self_query.base import SelfQueryRetriever -from langchain.schema import BaseRetriever -from langchain.schema.vectorstore import VectorStore from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.language_models import BaseLanguageModel +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class VectaraSelfQueryRetriverComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py b/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py index 2a0f3686f..8c23720f2 100644 --- a/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py @@ -1,10 +1,9 @@ from typing import List -from langchain.text_splitter import CharacterTextSplitter - from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record from langflow.utils.util import unescape_string +from langchain_text_splitters import CharacterTextSplitter class CharacterTextSplitterComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py b/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py index 1a4ae24a1..19dc94686 100644 --- a/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py @@ -1,9 +1,8 @@ from typing import List, Optional -from langchain.text_splitter import Language - from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_text_splitters import Language, RecursiveCharacterTextSplitter class LanguageRecursiveTextSplitterComponent(CustomComponent): @@ -61,7 +60,6 @@ class LanguageRecursiveTextSplitterComponent(CustomComponent): Returns: list[str]: The chunks of text. """ - from langchain.text_splitter import RecursiveCharacterTextSplitter # Make sure chunk_size and chunk_overlap are ints if isinstance(chunk_size, str): diff --git a/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py b/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py index 1ceaa8bd6..2bcde2232 100644 --- a/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py @@ -1,11 +1,10 @@ from typing import Optional - -from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_core.documents import Document from langflow.interface.custom.custom_component import CustomComponent from langflow.schema import Record from langflow.utils.util import build_loader_repr_from_records, unescape_string +from langchain_text_splitters import RecursiveCharacterTextSplitter class RecursiveCharacterTextSplitterComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/toolkits/Metaphor.py b/src/backend/base/langflow/components/toolkits/Metaphor.py index 14962924f..ba63416fb 100644 --- a/src/backend/base/langflow/components/toolkits/Metaphor.py +++ b/src/backend/base/langflow/components/toolkits/Metaphor.py @@ -1,11 +1,9 @@ from typing import List, Union - -from langchain.agents import tool -from langchain.agents.agent_toolkits.base import BaseToolkit -from langchain.tools import Tool from metaphor_python import Metaphor # type: ignore from langflow.interface.custom.custom_component import CustomComponent +from langchain_community.agent_toolkits.base import BaseToolkit +from langchain_core.tools import Tool, tool class MetaphorToolkit(CustomComponent): diff --git a/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py b/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py index 626a14fd8..78f00dc40 100644 --- a/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py +++ b/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py @@ -1,7 +1,7 @@ from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreInfo -from langchain_community.vectorstores import VectorStore from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.vectorstores import VectorStore class VectorStoreInfoComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/tools/PythonREPLTool.py b/src/backend/base/langflow/components/tools/PythonREPLTool.py index 6cc7d8649..f2f3b4b52 100644 --- a/src/backend/base/langflow/components/tools/PythonREPLTool.py +++ b/src/backend/base/langflow/components/tools/PythonREPLTool.py @@ -1,10 +1,9 @@ import importlib - -from langchain.agents import Tool from langchain_experimental.utilities import PythonREPL from langflow.base.tools.base import build_status_from_tool from langflow.custom import CustomComponent +from langchain_core.tools import Tool class PythonREPLToolComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py b/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py index 0c8a815a4..2aa23c490 100644 --- a/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/CouchbaseSearch.py @@ -1,8 +1,8 @@ -from typing import List, Optional +from typing import List from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.Couchbase import CouchbaseComponent -from langflow.field_typing import Embeddings, NestedDict, Text +from langflow.field_typing import Embeddings, Text from langflow.schema import Record @@ -25,17 +25,13 @@ class CouchbaseSearchComponent(LCVectorStoreComponent): return { "input_value": {"display_name": "Input"}, "embedding": {"display_name": "Embedding"}, - "couchbase_connection_string": {"display_name": "Couchbase Cluster connection string","required": True}, - "couchbase_username": {"display_name": "Couchbase username","required": True}, - "couchbase_password": { - "display_name": "Couchbase password", - "password": True, - "required": True - }, - "bucket_name": {"display_name": "Bucket Name","required": True}, - "scope_name": {"display_name": "Scope Name","required": True}, - "collection_name": {"display_name": "Collection Name","required": True}, - "index_name": {"display_name": "Index Name","required": True}, + "couchbase_connection_string": {"display_name": "Couchbase Cluster connection string", "required": True}, + "couchbase_username": {"display_name": "Couchbase username", "required": True}, + "couchbase_password": {"display_name": "Couchbase password", "password": True, "required": True}, + "bucket_name": {"display_name": "Bucket Name", "required": True}, + "scope_name": {"display_name": "Scope Name", "required": True}, + "collection_name": {"display_name": "Collection Name", "required": True}, + "index_name": {"display_name": "Index Name", "required": True}, "number_of_results": { "display_name": "Number of Results", "info": "Number of results to return.", diff --git a/src/backend/base/langflow/components/vectorsearch/RedisSearch.py b/src/backend/base/langflow/components/vectorsearch/RedisSearch.py index 25e71c64b..afe653f6e 100644 --- a/src/backend/base/langflow/components/vectorsearch/RedisSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/RedisSearch.py @@ -1,11 +1,10 @@ from typing import List, Optional -from langchain.embeddings.base import Embeddings - from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.Redis import RedisComponent from langflow.field_typing import Text from langflow.schema import Record +from langchain_core.embeddings import Embeddings class RedisSearchComponent(RedisComponent, LCVectorStoreComponent): diff --git a/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py b/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py index fd5ccd1aa..b51f65a55 100644 --- a/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py @@ -1,11 +1,10 @@ from typing import List, Optional -from langchain.embeddings.base import Embeddings - from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.Weaviate import WeaviateVectorStoreComponent from langflow.field_typing import Text from langflow.schema import Record +from langchain_core.embeddings import Embeddings class WeaviateSearchVectorStore(WeaviateVectorStoreComponent, LCVectorStoreComponent): diff --git a/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py b/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py index 9b074b5f6..c6bedfede 100644 --- a/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py @@ -1,11 +1,10 @@ from typing import List -from langchain.embeddings.base import Embeddings - from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.pgvector import PGVectorComponent from langflow.field_typing import Text from langflow.schema import Record +from langchain_core.embeddings import Embeddings class PGVectorSearchComponent(PGVectorComponent, LCVectorStoreComponent): diff --git a/src/backend/base/langflow/components/vectorstores/AstraDB.py b/src/backend/base/langflow/components/vectorstores/AstraDB.py index 3425c3a4e..07ded028e 100644 --- a/src/backend/base/langflow/components/vectorstores/AstraDB.py +++ b/src/backend/base/langflow/components/vectorstores/AstraDB.py @@ -1,12 +1,11 @@ from typing import List, Optional, Union - -from langchain.schema import BaseRetriever from langchain_astradb import AstraDBVectorStore from langchain_astradb.utils.astradb import SetupMode from langflow.custom import CustomComponent from langflow.field_typing import Embeddings, VectorStore from langflow.schema import Record +from langchain_core.retrievers import BaseRetriever class AstraDBVectorStoreComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Chroma.py b/src/backend/base/langflow/components/vectorstores/Chroma.py index 8fe2f54a9..8ea943a61 100644 --- a/src/backend/base/langflow/components/vectorstores/Chroma.py +++ b/src/backend/base/langflow/components/vectorstores/Chroma.py @@ -1,13 +1,13 @@ from typing import List, Optional, Union import chromadb # type: ignore -from langchain.embeddings.base import Embeddings -from langchain.schema import BaseRetriever -from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores.chroma import Chroma from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.embeddings import Embeddings +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class ChromaComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Couchbase.py b/src/backend/base/langflow/components/vectorstores/Couchbase.py index 1816e85fb..f99ac7d40 100644 --- a/src/backend/base/langflow/components/vectorstores/Couchbase.py +++ b/src/backend/base/langflow/components/vectorstores/Couchbase.py @@ -1,8 +1,6 @@ from typing import List, Optional, Union -from langchain.schema import BaseRetriever - -from langchain_community.vectorstores import CouchbaseVectorStore +from langchain_community.vectorstores import CouchbaseVectorStore from langflow.custom import CustomComponent from langflow.field_typing import Embeddings, VectorStore @@ -10,9 +8,10 @@ from langflow.schema import Record from datetime import timedelta -from couchbase.auth import PasswordAuthenticator # type: ignore -from couchbase.cluster import Cluster # type: ignore -from couchbase.options import ClusterOptions # type: ignore +from couchbase.auth import PasswordAuthenticator # type: ignore +from couchbase.cluster import Cluster # type: ignore +from couchbase.options import ClusterOptions # type: ignore +from langchain_core.retrievers import BaseRetriever class CouchbaseComponent(CustomComponent): @@ -34,17 +33,13 @@ class CouchbaseComponent(CustomComponent): return { "inputs": {"display_name": "Input", "input_types": ["Document", "Record"]}, "embedding": {"display_name": "Embedding"}, - "couchbase_connection_string": {"display_name": "Couchbase Cluster connection string","required": True}, - "couchbase_username": {"display_name": "Couchbase username","required": True}, - "couchbase_password": { - "display_name": "Couchbase password", - "password": True, - "required": True - }, - "bucket_name": {"display_name": "Bucket Name","required": True}, - "scope_name": {"display_name": "Scope Name","required": True}, - "collection_name": {"display_name": "Collection Name","required": True}, - "index_name": {"display_name": "Index Name","required": True}, + "couchbase_connection_string": {"display_name": "Couchbase Cluster connection string", "required": True}, + "couchbase_username": {"display_name": "Couchbase username", "required": True}, + "couchbase_password": {"display_name": "Couchbase password", "password": True, "required": True}, + "bucket_name": {"display_name": "Bucket Name", "required": True}, + "scope_name": {"display_name": "Scope Name", "required": True}, + "collection_name": {"display_name": "Collection Name", "required": True}, + "index_name": {"display_name": "Index Name", "required": True}, } def build( diff --git a/src/backend/base/langflow/components/vectorstores/FAISS.py b/src/backend/base/langflow/components/vectorstores/FAISS.py index ea9ee1c4d..410ac6a87 100644 --- a/src/backend/base/langflow/components/vectorstores/FAISS.py +++ b/src/backend/base/langflow/components/vectorstores/FAISS.py @@ -1,12 +1,11 @@ from typing import List, Text, Union - -from langchain.schema import BaseRetriever -from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores.faiss import FAISS from langflow.field_typing import Embeddings from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class FAISSComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Pinecone.py b/src/backend/base/langflow/components/vectorstores/Pinecone.py index b25bb6086..31521dc10 100644 --- a/src/backend/base/langflow/components/vectorstores/Pinecone.py +++ b/src/backend/base/langflow/components/vectorstores/Pinecone.py @@ -1,7 +1,4 @@ from typing import List, Optional, Union - -from langchain.schema import BaseRetriever -from langchain_community.vectorstores import VectorStore from langchain_core.documents import Document from langchain_pinecone._utilities import DistanceStrategy from langchain_pinecone.vectorstores import PineconeVectorStore @@ -9,6 +6,8 @@ from langchain_pinecone.vectorstores import PineconeVectorStore from langflow.field_typing import Embeddings from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class PineconeComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Qdrant.py b/src/backend/base/langflow/components/vectorstores/Qdrant.py index e6b3ddbc9..200d22770 100644 --- a/src/backend/base/langflow/components/vectorstores/Qdrant.py +++ b/src/backend/base/langflow/components/vectorstores/Qdrant.py @@ -1,12 +1,11 @@ from typing import Optional, Union - -from langchain.schema import BaseRetriever -from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores.qdrant import Qdrant from langflow.field_typing import Embeddings from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class QdrantComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Redis.py b/src/backend/base/langflow/components/vectorstores/Redis.py index ea1046037..c72c11f4d 100644 --- a/src/backend/base/langflow/components/vectorstores/Redis.py +++ b/src/backend/base/langflow/components/vectorstores/Redis.py @@ -1,12 +1,11 @@ from typing import Optional, Union - -from langchain.embeddings.base import Embeddings -from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores.redis import Redis from langchain_core.retrievers import BaseRetriever from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.embeddings import Embeddings +from langchain_core.vectorstores import VectorStore class RedisComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py b/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py index df80b3699..71bf78ec8 100644 --- a/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py +++ b/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py @@ -1,13 +1,12 @@ from typing import List, Optional, Union - -from langchain.schema import BaseRetriever -from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores.supabase import SupabaseVectorStore from supabase.client import Client, create_client from langflow.field_typing import Embeddings from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class SupabaseComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Weaviate.py b/src/backend/base/langflow/components/vectorstores/Weaviate.py index 99ede77f7..108c5a5da 100644 --- a/src/backend/base/langflow/components/vectorstores/Weaviate.py +++ b/src/backend/base/langflow/components/vectorstores/Weaviate.py @@ -1,13 +1,14 @@ from typing import Optional, Union import weaviate # type: ignore -from langchain.embeddings.base import Embeddings -from langchain.schema import BaseRetriever -from langchain_community.vectorstores import VectorStore, Weaviate +from langchain_community.vectorstores import Weaviate from langchain_core.documents import Document from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.embeddings import Embeddings +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore class WeaviateVectorStoreComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/pgvector.py b/src/backend/base/langflow/components/vectorstores/pgvector.py index b061b22ac..1c46d1e51 100644 --- a/src/backend/base/langflow/components/vectorstores/pgvector.py +++ b/src/backend/base/langflow/components/vectorstores/pgvector.py @@ -1,12 +1,11 @@ from typing import Optional, Union - -from langchain.embeddings.base import Embeddings -from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores.pgvector import PGVector from langchain_core.retrievers import BaseRetriever from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record +from langchain_core.embeddings import Embeddings +from langchain_core.vectorstores import VectorStore class PGVectorComponent(CustomComponent): diff --git a/src/backend/base/langflow/field_typing/constants.py b/src/backend/base/langflow/field_typing/constants.py index 2e8fd4b3b..d73257c14 100644 --- a/src/backend/base/langflow/field_typing/constants.py +++ b/src/backend/base/langflow/field_typing/constants.py @@ -2,17 +2,18 @@ from typing import Callable, Dict, Text, Union from langchain.agents.agent import AgentExecutor from langchain.chains.base import Chain -from langchain.document_loaders.base import BaseLoader -from langchain.llms.base import BaseLLM from langchain.memory.chat_memory import BaseChatMemory -from langchain.prompts import BasePromptTemplate, ChatPromptTemplate, PromptTemplate -from langchain.schema import BaseOutputParser, BaseRetriever, Document -from langchain.schema.embeddings import Embeddings -from langchain.schema.language_model import BaseLanguageModel -from langchain.schema.memory import BaseMemory -from langchain.text_splitter import TextSplitter -from langchain.tools import Tool -from langchain_community.vectorstores import VectorStore +from langchain_core.document_loaders import BaseLoader +from langchain_core.documents import Document +from langchain_core.embeddings import Embeddings +from langchain_core.language_models import BaseLLM, BaseLanguageModel +from langchain_core.memory import BaseMemory +from langchain_core.output_parsers import BaseOutputParser +from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate, PromptTemplate +from langchain_core.retrievers import BaseRetriever +from langchain_core.tools import Tool +from langchain_core.vectorstores import VectorStore +from langchain_text_splitters import TextSplitter # Type alias for more complex dicts NestedDict = Dict[str, Union[str, Dict]] diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json index e7754d711..e001f8e41 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json @@ -1,886 +1,800 @@ { - "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", - "data": { - "nodes": [ - { - "id": "Prompt-uxBqP", - "type": "genericNode", - "position": { - "x": 53.588791333410654, - "y": -107.07318910019967 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "user_input": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "user_input", - "display_name": "user_input", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "object", - "str", - "Text" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "user_input" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-uxBqP", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": true, - "width": 384, - "height": 383, - "dragging": false, - "positionAbsolute": { - "x": 53.588791333410654, - "y": -107.07318910019967 - } + "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", + "data": { + "nodes": [ + { + "id": "Prompt-uxBqP", + "type": "genericNode", + "position": { + "x": 53.588791333410654, + "y": -107.07318910019967 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "user_input": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "user_input", + "display_name": "user_input", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } }, - { - "id": "OpenAIModel-k39HS", - "type": "genericNode", - "position": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": true, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "object", - "Text", - "str" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-k39HS", - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, - "dragging": false + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["object", "str", "Text"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["user_input"] }, - { - "id": "ChatOutput-njtka", - "type": "genericNode", - "position": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "Record", - "Text", - "str", - "object" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-njtka" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "dragging": false - }, - { - "id": "ChatInput-P3fgL", - "type": "genericNode", - "position": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "hi" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": [ - "object", - "Record", - "str", - "Text" - ], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-P3fgL" - }, - "selected": false, - "width": 384, - "height": 375, - "positionAbsolute": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "OpenAIModel-k39HS", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}", - "target": "ChatOutput-njtka", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-njtka", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Text", - "str" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-k39HS" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-k39HS{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}-ChatOutput-njtka{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-uxBqP", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}", - "target": "OpenAIModel-k39HS", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-k39HS", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "Prompt", - "id": "Prompt-uxBqP" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-uxBqP{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}-OpenAIModel-k39HS{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "ChatInput-P3fgL", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}", - "target": "Prompt-uxBqP", - "targetHandle": "{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "user_input", - "id": "Prompt-uxBqP", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Record", - "str", - "Text" - ], - "dataType": "ChatInput", - "id": "ChatInput-P3fgL" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-P3fgL{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}-Prompt-uxBqP{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": 260.58251815500563, - "y": 318.2261172111936, - "zoom": 0.43514115784696294 + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-uxBqP", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": true, + "width": 384, + "height": 383, + "dragging": false, + "positionAbsolute": { + "x": 53.588791333410654, + "y": -107.07318910019967 } - }, - "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", - "name": "Basic Prompting (Hello, World)", - "last_tested_version": "1.0.0a4", - "is_component": false + }, + { + "id": "OpenAIModel-k39HS", + "type": "genericNode", + "position": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-3.5-turbo", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": true, + "title_case": false, + "input_types": ["Text"], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["object", "Text", "str"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-k39HS", + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, + "dragging": false + }, + { + "id": "ChatOutput-njtka", + "type": "genericNode", + "position": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["Record", "Text", "str", "object"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-njtka" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, + "dragging": false + }, + { + "id": "ChatInput-P3fgL", + "type": "genericNode", + "position": { + "x": -495.2223093083827, + "y": -232.56998443685862 + }, + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "hi" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" + }, + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": ["object", "Record", "str", "Text"], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-P3fgL" + }, + "selected": false, + "width": 384, + "height": 375, + "positionAbsolute": { + "x": -495.2223093083827, + "y": -232.56998443685862 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "OpenAIModel-k39HS", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}", + "target": "ChatOutput-njtka", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-njtka", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Text", "str"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-k39HS" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-k39HS{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}-ChatOutput-njtka{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-uxBqP", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}", + "target": "OpenAIModel-k39HS", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-k39HS", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "Prompt", + "id": "Prompt-uxBqP" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-uxBqP{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}-OpenAIModel-k39HS{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "ChatInput-P3fgL", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}", + "target": "Prompt-uxBqP", + "targetHandle": "{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "user_input", + "id": "Prompt-uxBqP", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Record", "str", "Text"], + "dataType": "ChatInput", + "id": "ChatInput-P3fgL" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-P3fgL{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}-Prompt-uxBqP{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": 260.58251815500563, + "y": 318.2261172111936, + "zoom": 0.43514115784696294 + } + }, + "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", + "name": "Basic Prompting (Hello, World)", + "last_tested_version": "1.0.0a4", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json index a2042385b..e70285000 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json @@ -1,1096 +1,987 @@ { - "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", - "data": { - "nodes": [ - { - "id": "Prompt-Rse03", - "type": "genericNode", - "position": { - "x": 1331.381712783371, - "y": 535.0279854229713 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "reference_1": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "reference_1", - "display_name": "reference_1", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "reference_2": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "reference_2", - "display_name": "reference_2", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "instructions": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "instructions", - "display_name": "instructions", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "object", - "Text", - "str" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "reference_1", - "reference_2", - "instructions" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-Rse03", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 571, - "dragging": false, - "positionAbsolute": { - "x": 1331.381712783371, - "y": 535.0279854229713 - } + "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", + "data": { + "nodes": [ + { + "id": "Prompt-Rse03", + "type": "genericNode", + "position": { + "x": 1331.381712783371, + "y": 535.0279854229713 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "reference_1": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "reference_1", + "display_name": "reference_1", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "reference_2": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "reference_2", + "display_name": "reference_2", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "instructions": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "instructions", + "display_name": "instructions", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } }, - { - "id": "URL-HYPkR", - "type": "genericNode", - "position": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, - "data": { - "type": "URL", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "urls": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "urls", - "display_name": "URL", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": [ - "https://www.promptingguide.ai/techniques/prompt_chaining" - ] - }, - "_type": "CustomComponent" - }, - "description": "Fetch content from one or more URLs.", - "icon": "layout-template", - "base_classes": [ - "Record" - ], - "display_name": "URL", - "documentation": "", - "custom_fields": { - "urls": null - }, - "output_types": [ - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "URL-HYPkR" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, - "dragging": false + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["object", "Text", "str"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["reference_1", "reference_2", "instructions"] }, - { - "id": "ChatOutput-JPlxl", - "type": "genericNode", - "position": { - "x": 2503.8617424688505, - "y": 789.3005578928434 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "Text", - "Record", - "object", - "str" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-JPlxl" - }, - "selected": false, - "width": 384, - "height": 383 - }, - { - "id": "OpenAIModel-gi29P", - "type": "genericNode", - "position": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "1024", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo-0125", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "0.1", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-gi29P" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, - "dragging": false - }, - { - "id": "URL-2cX90", - "type": "genericNode", - "position": { - "x": 573.961301764604, - "y": 336.41463436122086 - }, - "data": { - "type": "URL", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "urls": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "urls", - "display_name": "URL", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": [ - "https://www.promptingguide.ai/introduction/basics" - ] - }, - "_type": "CustomComponent" - }, - "description": "Fetch content from one or more URLs.", - "icon": "layout-template", - "base_classes": [ - "Record" - ], - "display_name": "URL", - "documentation": "", - "custom_fields": { - "urls": null - }, - "output_types": [ - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "URL-2cX90" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 573.961301764604, - "y": 336.41463436122086 - }, - "dragging": false - }, - { - "id": "TextInput-og8Or", - "type": "genericNode", - "position": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, - "data": { - "type": "TextInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[str] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics.", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": [ - "Record", - "Text" - ], - "dynamic": false, - "info": "Text or Record to be passed as input.", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": [ - "object", - "Text", - "str" - ], - "display_name": "Instructions", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextInput-og8Or" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "URL-HYPkR", - "target": "Prompt-Rse03", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "id": "reactflow__edge-URL-HYPkR{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "reference_2", - "id": "Prompt-Rse03", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Record" - ], - "dataType": "URL", - "id": "URL-HYPkR" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIModel-gi29P", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}", - "target": "ChatOutput-JPlxl", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-JPlxl", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-gi29P" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-gi29P{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}-ChatOutput-JPlxl{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "URL-2cX90", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}", - "target": "Prompt-Rse03", - "targetHandle": "{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "reference_1", - "id": "Prompt-Rse03", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Record" - ], - "dataType": "URL", - "id": "URL-2cX90" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-URL-2cX90{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "TextInput-og8Or", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}", - "target": "Prompt-Rse03", - "targetHandle": "{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "instructions", - "id": "Prompt-Rse03", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Text", - "str" - ], - "dataType": "TextInput", - "id": "TextInput-og8Or" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-TextInput-og8Or{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-Rse03", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}", - "target": "OpenAIModel-gi29P", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-gi29P", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "Text", - "str" - ], - "dataType": "Prompt", - "id": "Prompt-Rse03" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-Rse03{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}-OpenAIModel-gi29P{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "selected": false - } - ], - "viewport": { - "x": -214.14726025721177, - "y": -35.83855793844168, - "zoom": 0.47344308394045925 + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-Rse03", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 571, + "dragging": false, + "positionAbsolute": { + "x": 1331.381712783371, + "y": 535.0279854229713 } - }, - "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", - "name": "Blog Writer", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + { + "id": "URL-HYPkR", + "type": "genericNode", + "position": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, + "data": { + "type": "URL", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "urls": { + "type": "str", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "urls", + "display_name": "URL", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": [ + "https://www.promptingguide.ai/techniques/prompt_chaining" + ] + }, + "_type": "CustomComponent" + }, + "description": "Fetch content from one or more URLs.", + "icon": "layout-template", + "base_classes": ["Record"], + "display_name": "URL", + "documentation": "", + "custom_fields": { + "urls": null + }, + "output_types": ["Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "URL-HYPkR" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, + "dragging": false + }, + { + "id": "ChatOutput-JPlxl", + "type": "genericNode", + "position": { + "x": 2503.8617424688505, + "y": 789.3005578928434 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" + }, + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["Text", "Record", "object", "str"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-JPlxl" + }, + "selected": false, + "width": 384, + "height": 383 + }, + { + "id": "OpenAIModel-gi29P", + "type": "genericNode", + "position": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "1024", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-3.5-turbo-0125", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "0.1", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["str", "Text", "object"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-gi29P" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, + "dragging": false + }, + { + "id": "URL-2cX90", + "type": "genericNode", + "position": { + "x": 573.961301764604, + "y": 336.41463436122086 + }, + "data": { + "type": "URL", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "urls": { + "type": "str", + "required": true, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "urls", + "display_name": "URL", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": ["https://www.promptingguide.ai/introduction/basics"] + }, + "_type": "CustomComponent" + }, + "description": "Fetch content from one or more URLs.", + "icon": "layout-template", + "base_classes": ["Record"], + "display_name": "URL", + "documentation": "", + "custom_fields": { + "urls": null + }, + "output_types": ["Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "URL-2cX90" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 573.961301764604, + "y": 336.41463436122086 + }, + "dragging": false + }, + { + "id": "TextInput-og8Or", + "type": "genericNode", + "position": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, + "data": { + "type": "TextInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[str] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics.", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": ["Record", "Text"], + "dynamic": false, + "info": "Text or Record to be passed as input.", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" + }, + "description": "Get text inputs from the Playground.", + "icon": "type", + "base_classes": ["object", "Text", "str"], + "display_name": "Instructions", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextInput-og8Or" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "URL-HYPkR", + "target": "Prompt-Rse03", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-URL-HYPkR{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "reference_2", + "id": "Prompt-Rse03", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Record"], + "dataType": "URL", + "id": "URL-HYPkR" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "selected": false + }, + { + "source": "OpenAIModel-gi29P", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}", + "target": "ChatOutput-JPlxl", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-JPlxl", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-gi29P" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-gi29P{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}-ChatOutput-JPlxl{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "URL-2cX90", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}", + "target": "Prompt-Rse03", + "targetHandle": "{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "reference_1", + "id": "Prompt-Rse03", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Record"], + "dataType": "URL", + "id": "URL-2cX90" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-URL-2cX90{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "TextInput-og8Or", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}", + "target": "Prompt-Rse03", + "targetHandle": "{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "instructions", + "id": "Prompt-Rse03", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Text", "str"], + "dataType": "TextInput", + "id": "TextInput-og8Or" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-TextInput-og8Or{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-Rse03", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}", + "target": "OpenAIModel-gi29P", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-gi29P", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "Text", "str"], + "dataType": "Prompt", + "id": "Prompt-Rse03" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-Rse03{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}-OpenAIModel-gi29P{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + } + ], + "viewport": { + "x": -214.14726025721177, + "y": -35.83855793844168, + "zoom": 0.47344308394045925 + } + }, + "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", + "name": "Blog Writer", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json index 339d1eff7..5d3ab5a1b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json @@ -1,1029 +1,933 @@ { - "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", - "data": { - "nodes": [ - { - "id": "Prompt-tHwPf", - "type": "genericNode", - "position": { - "x": 585.7906101139403, - "y": 117.52115876762832 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "Document": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "Document", - "display_name": "Document", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "Question": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "Question", - "display_name": "Question", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "object", - "str", - "Text" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "Document", - "Question" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-tHwPf", - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 479, - "positionAbsolute": { - "x": 585.7906101139403, - "y": 117.52115876762832 - }, - "dragging": false + "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", + "data": { + "nodes": [ + { + "id": "Prompt-tHwPf", + "type": "genericNode", + "position": { + "x": 585.7906101139403, + "y": 117.52115876762832 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "Document": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "Document", + "display_name": "Document", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "Question": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "Question", + "display_name": "Question", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } }, - { - "id": "File-6TEsD", - "type": "genericNode", - "position": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, - "data": { - "type": "File", - "node": { - "template": { - "path": { - "type": "file", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [ - ".txt", - ".md", - ".mdx", - ".csv", - ".json", - ".yaml", - ".yml", - ".xml", - ".html", - ".htm", - ".pdf", - ".docx" - ], - "password": false, - "name": "path", - "display_name": "Path", - "advanced": false, - "dynamic": false, - "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"Files\"\n description = \"A generic file loader.\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "silent_errors": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "silent_errors", - "display_name": "Silent Errors", - "advanced": true, - "dynamic": false, - "info": "If true, errors will not raise an exception.", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "A generic file loader.", - "base_classes": [ - "Record" - ], - "display_name": "Files", - "documentation": "", - "custom_fields": { - "path": null, - "silent_errors": null - }, - "output_types": [ - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "File-6TEsD" - }, - "selected": false, - "width": 384, - "height": 282, - "positionAbsolute": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, - "dragging": false + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["object", "str", "Text"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["Document", "Question"] }, - { - "id": "ChatInput-MsSJ9", - "type": "genericNode", - "position": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": [ - "str", - "Record", - "Text", - "object" - ], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-MsSJ9" - }, - "selected": true, - "width": 384, - "height": 377, - "positionAbsolute": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, - "dragging": false + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-tHwPf", + "description": "A component for creating prompt templates using dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 479, + "positionAbsolute": { + "x": 585.7906101139403, + "y": 117.52115876762832 + }, + "dragging": false + }, + { + "id": "File-6TEsD", + "type": "genericNode", + "position": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, + "data": { + "type": "File", + "node": { + "template": { + "path": { + "type": "file", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [ + ".txt", + ".md", + ".mdx", + ".csv", + ".json", + ".yaml", + ".yml", + ".xml", + ".html", + ".htm", + ".pdf", + ".docx" + ], + "password": false, + "name": "path", + "display_name": "Path", + "advanced": false, + "dynamic": false, + "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"Files\"\n description = \"A generic file loader.\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "silent_errors": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "silent_errors", + "display_name": "Silent Errors", + "advanced": true, + "dynamic": false, + "info": "If true, errors will not raise an exception.", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" }, - { - "id": "ChatOutput-F5Awj", - "type": "genericNode", - "position": { - "x": 1733.3012915204283, - "y": 168.76098809939327 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "str", - "Record", - "Text", - "object" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-F5Awj" - }, - "selected": false, - "width": 384, - "height": 385, - "positionAbsolute": { - "x": 1733.3012915204283, - "y": 168.76098809939327 - }, - "dragging": false + "description": "A generic file loader.", + "base_classes": ["Record"], + "display_name": "Files", + "documentation": "", + "custom_fields": { + "path": null, + "silent_errors": null }, - { - "id": "OpenAIModel-Bt067", - "type": "genericNode", - "position": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": false, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "object", - "str", - "Text" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-Bt067" - }, - "selected": false, - "width": 384, - "height": 642, - "positionAbsolute": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "ChatInput-MsSJ9", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}", - "target": "Prompt-tHwPf", - "targetHandle": "{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "Question", - "id": "Prompt-tHwPf", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Record", - "Text", - "object" - ], - "dataType": "ChatInput", - "id": "ChatInput-MsSJ9" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-MsSJ9{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "output_types": ["Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "File-6TEsD" + }, + "selected": false, + "width": 384, + "height": 282, + "positionAbsolute": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, + "dragging": false + }, + { + "id": "ChatInput-MsSJ9", + "type": "genericNode", + "position": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "source": "File-6TEsD", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}", - "target": "Prompt-tHwPf", - "targetHandle": "{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "Document", - "id": "Prompt-tHwPf", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Record" - ], - "dataType": "File", - "id": "File-6TEsD" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-File-6TEsD{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": ["str", "Record", "Text", "object"], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null }, - { - "source": "Prompt-tHwPf", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}", - "target": "OpenAIModel-Bt067", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-Bt067", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "Prompt", - "id": "Prompt-tHwPf" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-tHwPf{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}-OpenAIModel-Bt067{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-MsSJ9" + }, + "selected": true, + "width": 384, + "height": 377, + "positionAbsolute": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, + "dragging": false + }, + { + "id": "ChatOutput-F5Awj", + "type": "genericNode", + "position": { + "x": 1733.3012915204283, + "y": 168.76098809939327 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "source": "OpenAIModel-Bt067", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}", - "target": "ChatOutput-F5Awj", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-F5Awj", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-Bt067" - } + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["str", "Record", "Text", "object"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-F5Awj" + }, + "selected": false, + "width": 384, + "height": 385, + "positionAbsolute": { + "x": 1733.3012915204283, + "y": 168.76098809939327 + }, + "dragging": false + }, + { + "id": "OpenAIModel-Bt067", + "type": "genericNode", + "position": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-turbo-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": false, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-Bt067{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}-ChatOutput-F5Awj{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": 352.20899206064655, - "y": 56.054900898593075, - "zoom": 0.9023391400011 - } - }, - "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", - "name": "Document QA", - "last_tested_version": "1.0.0a0", - "is_component": false + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["object", "str", "Text"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-Bt067" + }, + "selected": false, + "width": 384, + "height": 642, + "positionAbsolute": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "ChatInput-MsSJ9", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}", + "target": "Prompt-tHwPf", + "targetHandle": "{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "Question", + "id": "Prompt-tHwPf", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Record", "Text", "object"], + "dataType": "ChatInput", + "id": "ChatInput-MsSJ9" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-MsSJ9{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "File-6TEsD", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}", + "target": "Prompt-tHwPf", + "targetHandle": "{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "Document", + "id": "Prompt-tHwPf", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Record"], + "dataType": "File", + "id": "File-6TEsD" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-File-6TEsD{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-tHwPf", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}", + "target": "OpenAIModel-Bt067", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-Bt067", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "Prompt", + "id": "Prompt-tHwPf" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-tHwPf{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}-OpenAIModel-Bt067{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-Bt067", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}", + "target": "ChatOutput-F5Awj", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-F5Awj", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-Bt067" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-Bt067{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}-ChatOutput-F5Awj{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": 352.20899206064655, + "y": 56.054900898593075, + "zoom": 0.9023391400011 + } + }, + "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", + "name": "Document QA", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json index 5c62f73ad..ef45db37d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json @@ -1,1272 +1,1137 @@ { - "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", - "icon": "\ud83e\udd16", - "icon_bg_color": "#FFD700", - "data": { - "nodes": [ - { - "id": "ChatInput-t7F8v", - "type": "genericNode", - "position": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "value": "" - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "User", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": false, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": [ - "Text", - "object", - "Record", - "str" - ], - "display_name": "Chat Input", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatInput-t7F8v" - }, - "selected": false, - "width": 384, - "height": 469, - "positionAbsolute": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, - "dragging": false + "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", + "icon": "\ud83e\udd16", + "icon_bg_color": "#FFD700", + "data": { + "nodes": [ + { + "id": "ChatInput-t7F8v", + "type": "genericNode", + "position": { + "x": 1283.2700598313072, + "y": 982.5953650473145 + }, + "data": { + "type": "ChatInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "value": "" + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": false, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "MySessionID" + }, + "_type": "CustomComponent" }, - { - "id": "ChatOutput-P1jEe", - "type": "genericNode", - "position": { - "x": 3154.916355514023, - "y": 851.051882666333 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "AI", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": false, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "Text", - "object", - "Record", - "str" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-P1jEe" - }, - "selected": false, - "width": 384, - "height": 477, - "dragging": false, - "positionAbsolute": { - "x": 3154.916355514023, - "y": 851.051882666333 - } + "description": "Get chat inputs from the Playground.", + "icon": "ChatInput", + "base_classes": ["Text", "object", "Record", "str"], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null }, - { - "id": "MemoryComponent-cdA1J", - "type": "genericNode", - "position": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - }, - "data": { - "type": "MemoryComponent", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.schema import Record\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def get_messages(self, **kwargs) -> list[Record]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "n_messages": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 5, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "n_messages", - "display_name": "Number of Messages", - "advanced": false, - "dynamic": false, - "info": "Number of messages to retrieve.", - "load_from_db": false, - "title_case": false - }, - "order": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Descending", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Ascending", - "Descending" - ], - "name": "order", - "display_name": "Order", - "advanced": true, - "dynamic": false, - "info": "Order of the messages.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{sender_name}: {text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine and User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User", - "Machine and User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "Session ID of the chat history.", - "load_from_db": false, - "title_case": false, - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Retrieves stored chat messages given a specific Session ID.", - "icon": "history", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "Chat Memory", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "session_id": null, - "n_messages": null, - "order": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": true - }, - "id": "MemoryComponent-cdA1J", - "description": "Retrieves stored chat messages given a specific Session ID.", - "display_name": "Chat Memory" - }, - "selected": false, - "width": 384, - "height": 489, - "dragging": false, - "positionAbsolute": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - } + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-t7F8v" + }, + "selected": false, + "width": 384, + "height": 469, + "positionAbsolute": { + "x": 1283.2700598313072, + "y": 982.5953650473145 + }, + "dragging": false + }, + { + "id": "ChatOutput-P1jEe", + "type": "genericNode", + "position": { + "x": 3154.916355514023, + "y": 851.051882666333 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": false, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "MySessionID" + }, + "_type": "CustomComponent" }, - { - "id": "Prompt-ODkUx", - "type": "genericNode", - "position": { - "x": 1894.594426342426, - "y": 753.3797365481901 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "{context}\n\nUser: {user_message}\nAI: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "context": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "context", - "display_name": "context", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "user_message": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "user_message", - "display_name": "user_message", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "Text", - "str", - "object" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "context", - "user_message" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-ODkUx", - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 477, - "dragging": false, - "positionAbsolute": { - "x": 1894.594426342426, - "y": 753.3797365481901 - } + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["Text", "object", "Record", "str"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null }, - { - "id": "OpenAIModel-9RykF", - "type": "genericNode", - "position": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-1106-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "0.2", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "str", - "object", - "Text" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-9RykF" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, - "dragging": false - }, - { - "id": "TextOutput-vrs6T", - "type": "genericNode", - "position": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": [ - "Record", - "Text" - ], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": [ - "str", - "object", - "Text" - ], - "display_name": "Inspect Memory", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-vrs6T" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", - "target": "Prompt-ODkUx", - "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "context", - "type": "str", - "id": "Prompt-ODkUx", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ] - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "MemoryComponent", - "id": "MemoryComponent-cdA1J" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "selected": false - }, - { - "source": "ChatInput-t7F8v", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}", - "target": "Prompt-ODkUx", - "targetHandle": "{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "user_message", - "type": "str", - "id": "Prompt-ODkUx", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ] - }, - "sourceHandle": { - "baseClasses": [ - "Text", - "object", - "Record", - "str" - ], - "dataType": "ChatInput", - "id": "ChatInput-t7F8v" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-t7F8v{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "selected": false - }, - { - "source": "Prompt-ODkUx", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}", - "target": "OpenAIModel-9RykF", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-9RykF", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "Text", - "str", - "object" - ], - "dataType": "Prompt", - "id": "Prompt-ODkUx" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-ODkUx{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}-OpenAIModel-9RykF{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "OpenAIModel-9RykF", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}", - "target": "ChatOutput-P1jEe", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-P1jEe", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "object", - "Text" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-9RykF" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-9RykF{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}-ChatOutput-P1jEe{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", - "target": "TextOutput-vrs6T", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-vrs6T", - "inputTypes": [ - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "MemoryComponent", - "id": "MemoryComponent-cdA1J" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-foreground stroke-connection", - "id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-TextOutput-vrs6T{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": -569.862554459756, - "y": -42.08339711050985, - "zoom": 0.4868590524514978 + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-P1jEe" + }, + "selected": false, + "width": 384, + "height": 477, + "dragging": false, + "positionAbsolute": { + "x": 3154.916355514023, + "y": 851.051882666333 } - }, - "description": "This project can be used as a starting point for building a Chat experience with user specific memory. You can set a different Session ID to start a new message history.", - "name": "Memory Chatbot", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + { + "id": "MemoryComponent-cdA1J", + "type": "genericNode", + "position": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + }, + "data": { + "type": "MemoryComponent", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.schema import Record\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def get_messages(self, **kwargs) -> list[Record]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "n_messages": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 5, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "n_messages", + "display_name": "Number of Messages", + "advanced": false, + "dynamic": false, + "info": "Number of messages to retrieve.", + "load_from_db": false, + "title_case": false + }, + "order": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Descending", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Ascending", "Descending"], + "name": "order", + "display_name": "Order", + "advanced": true, + "dynamic": false, + "info": "Order of the messages.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{sender_name}: {text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine and User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User", "Machine and User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "Session ID of the chat history.", + "load_from_db": false, + "title_case": false, + "value": "MySessionID" + }, + "_type": "CustomComponent" + }, + "description": "Retrieves stored chat messages given a specific Session ID.", + "icon": "history", + "base_classes": ["str", "Text", "object"], + "display_name": "Chat Memory", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "session_id": null, + "n_messages": null, + "order": null, + "record_template": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": true + }, + "id": "MemoryComponent-cdA1J", + "description": "Retrieves stored chat messages given a specific Session ID.", + "display_name": "Chat Memory" + }, + "selected": false, + "width": 384, + "height": 489, + "dragging": false, + "positionAbsolute": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + } + }, + { + "id": "Prompt-ODkUx", + "type": "genericNode", + "position": { + "x": 1894.594426342426, + "y": 753.3797365481901 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "{context}\n\nUser: {user_message}\nAI: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "context": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "context", + "display_name": "context", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + }, + "user_message": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "user_message", + "display_name": "user_message", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["Text", "str", "object"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["context", "user_message"] + }, + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-ODkUx", + "description": "A component for creating prompt templates using dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 477, + "dragging": false, + "positionAbsolute": { + "x": 1894.594426342426, + "y": 753.3797365481901 + } + }, + { + "id": "OpenAIModel-9RykF", + "type": "genericNode", + "position": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-1106-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "0.2", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["str", "object", "Text"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-9RykF" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, + "dragging": false + }, + { + "id": "TextOutput-vrs6T", + "type": "genericNode", + "position": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": ["Record", "Text"], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" + }, + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": ["str", "object", "Text"], + "display_name": "Inspect Memory", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-vrs6T" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", + "target": "Prompt-ODkUx", + "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "context", + "type": "str", + "id": "Prompt-ODkUx", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"] + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "MemoryComponent", + "id": "MemoryComponent-cdA1J" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + }, + { + "source": "ChatInput-t7F8v", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}", + "target": "Prompt-ODkUx", + "targetHandle": "{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "user_message", + "type": "str", + "id": "Prompt-ODkUx", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"] + }, + "sourceHandle": { + "baseClasses": ["Text", "object", "Record", "str"], + "dataType": "ChatInput", + "id": "ChatInput-t7F8v" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatInput-t7F8v{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + }, + { + "source": "Prompt-ODkUx", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}", + "target": "OpenAIModel-9RykF", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-9RykF", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["Text", "str", "object"], + "dataType": "Prompt", + "id": "Prompt-ODkUx" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-ODkUx{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}-OpenAIModel-9RykF{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-9RykF", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}", + "target": "ChatOutput-P1jEe", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-P1jEe", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "object", "Text"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-9RykF" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-9RykF{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}-ChatOutput-P1jEe{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", + "target": "TextOutput-vrs6T", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-vrs6T", + "inputTypes": ["Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "MemoryComponent", + "id": "MemoryComponent-cdA1J" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-foreground stroke-connection", + "id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-TextOutput-vrs6T{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -569.862554459756, + "y": -42.08339711050985, + "zoom": 0.4868590524514978 + } + }, + "description": "This project can be used as a starting point for building a Chat experience with user specific memory. You can set a different Session ID to start a new message history.", + "name": "Memory Chatbot", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json index 4ec2707a2..8563a442a 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json @@ -1,1769 +1,1586 @@ { - "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", - "data": { - "nodes": [ - { - "id": "Prompt-amqBu", - "type": "genericNode", - "position": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "document": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "document", - "display_name": "document", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "object", - "str", - "Text" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "document" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-amqBu", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 385, - "positionAbsolute": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "dragging": false + "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", + "data": { + "nodes": [ + { + "id": "Prompt-amqBu", + "type": "genericNode", + "position": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "document": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "document", + "display_name": "document", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } }, - { - "id": "Prompt-gTNiz", - "type": "genericNode", - "position": { - "x": 3731.0813766902447, - "y": 799.631909121391 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "summary": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "summary", - "display_name": "summary", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": [ - "object", - "str", - "Text" - ], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": [ - "summary" - ] - }, - "output_types": [ - "Text" - ], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-gTNiz", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 385, - "dragging": false + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["object", "str", "Text"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["document"] }, - { - "id": "ChatOutput-EJkG3", - "type": "genericNode", - "position": { - "x": 3722.1747844849388, - "y": 1283.413553222214 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Summarizer", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "object", - "Record", - "Text", - "str" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-EJkG3" - }, - "selected": false, - "width": 384, - "height": 385, - "dragging": false + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-amqBu", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 385, + "positionAbsolute": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 + }, + "dragging": false + }, + { + "id": "Prompt-gTNiz", + "type": "genericNode", + "position": { + "x": 3731.0813766902447, + "y": 799.631909121391 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "summary": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "summary", + "display_name": "summary", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } }, - { - "id": "ChatOutput-DNmvg", - "type": "genericNode", - "position": { - "x": 5077.71285886074, - "y": 1232.9152769735522 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Message", - "advanced": false, - "input_types": [ - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "In case of Message being a Record, this template will be used to convert it to text.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "return_record": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "return_record", - "display_name": "Return Record", - "advanced": true, - "dynamic": false, - "info": "Return the message as a record containing the sender, sender_name, and session_id.", - "load_from_db": false, - "title_case": false - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "Machine", - "User" - ], - "name": "sender", - "display_name": "Sender Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "sender_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Question Generator", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "session_id": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "session_id", - "display_name": "Session ID", - "advanced": true, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": [ - "object", - "Record", - "Text", - "str" - ], - "display_name": "Chat Output", - "documentation": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "input_value": null, - "session_id": null, - "return_record": null, - "record_template": null - }, - "output_types": [ - "Text", - "Record" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-DNmvg" - }, - "selected": false, - "width": 384, - "height": 385 + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": ["object", "str", "Text"], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": ["summary"] }, - { - "id": "TextInput-sptaH", - "type": "genericNode", - "position": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "data": { - "type": "TextInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[Text] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Revolutionary Nano-Battery Technology Unveiled In a groundbreaking announcement yesterday, researchers from the fictional Tech Innovations Institute revealed the development of a new nano-battery technology that promises to revolutionize energy storage. The new battery, dubbed the \"EnerGCell\", uses advanced nanomaterials to achieve unprecedented efficiency and storage capacities. According to lead researcher Dr. Ada Byron, the EnerGCell can store up to ten times more energy than the best lithium-ion batteries available today, while charging in just a fraction of the time. \"We're talking about charging your electric vehicle in just five minutes for a range of over 1,000 miles,\" Dr. Byron stated during the press conference. The technology behind the EnerGCell involves a complex arrangement of nanostructured electrodes that allow for rapid ion transfer and extremely high energy density. This breakthrough was achieved after a decade of research into nanomaterials and their applications in energy storage. The implications of this technology are vast, promising to accelerate the adoption of renewable energy by making it more practical and affordable to store wind and solar power. It could also lead to significant advancements in electric vehicles, mobile devices, and any other technology that relies on batteries. Despite the excitement, some experts are calling for patience, noting that the EnerGCell is still in its early stages of development and may take several years before it's commercially available. However, the potential impact of such a technology on the environment and the global economy is undeniable. Tech Innovations Institute plans to continue refining the EnerGCell and begin pilot projects with select partners in the coming year. If successful, this nano-battery technology could indeed be the breakthrough needed to usher in a new era of clean energy and technology.", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": [ - "Record", - "Text" - ], - "dynamic": false, - "info": "Text or Record to be passed as input.", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "Text Input", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextInput-sptaH" - }, - "selected": false, - "width": 384, - "height": 290, - "positionAbsolute": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "dragging": false + "output_types": ["Text"], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-gTNiz", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": false, + "width": 384, + "height": 385, + "dragging": false + }, + { + "id": "ChatOutput-EJkG3", + "type": "genericNode", + "position": { + "x": 3722.1747844849388, + "y": 1283.413553222214 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Summarizer", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "id": "TextOutput-2MS4a", - "type": "genericNode", - "position": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": [ - "Record", - "Text" - ], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "First Prompt", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-2MS4a" - }, - "selected": false, - "width": 384, - "height": 290, - "positionAbsolute": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "dragging": false + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["object", "Record", "Text", "str"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null }, - { - "id": "OpenAIModel-uYXZJ", - "type": "genericNode", - "position": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-uYXZJ" - }, - "selected": false, - "width": 384, - "height": 565, - "positionAbsolute": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "dragging": false + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-EJkG3" + }, + "selected": false, + "width": 384, + "height": 385, + "dragging": false + }, + { + "id": "ChatOutput-DNmvg", + "type": "genericNode", + "position": { + "x": 5077.71285886074, + "y": 1232.9152769735522 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template or \"\",\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": ["Text"], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "{text}", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "In case of Message being a Record, this template will be used to convert it to text.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": true, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": ["Machine", "User"], + "name": "sender", + "display_name": "Sender Type", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Question Generator", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "id": "TextOutput-MUDOR", - "type": "genericNode", - "position": { - "x": 4446.064323520379, - "y": 633.833297518702 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": [ - "Record", - "Text" - ], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "Second Prompt", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-MUDOR" - }, - "selected": false, - "width": 384, - "height": 290, - "dragging": false, - "positionAbsolute": { - "x": 4446.064323520379, - "y": 633.833297518702 - } + "description": "Display a chat message in the Playground.", + "icon": "ChatOutput", + "base_classes": ["object", "Record", "Text", "str"], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null }, - { - "id": "OpenAIModel-XawYB", - "type": "genericNode", - "position": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ], - "value": "" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "load_from_db": false, - "title_case": false - }, - "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "load_from_db": false, - "title_case": false, - "input_types": [ - "Text" - ] - }, - "temperature": { - "type": "float", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": [ - "str", - "Text", - "object" - ], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null - }, - "output_types": [ - "Text" - ], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-XawYB" - }, - "selected": false, - "width": 384, - "height": 565, - "positionAbsolute": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextInput-sptaH", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}", - "target": "Prompt-amqBu", - "targetHandle": "{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "document", - "id": "Prompt-amqBu", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "TextInput", - "id": "TextInput-sptaH" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-TextInput-sptaH{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}-Prompt-amqBu{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "output_types": ["Text", "Record"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-DNmvg" + }, + "selected": false, + "width": 384, + "height": 385 + }, + { + "id": "TextInput-sptaH", + "type": "genericNode", + "position": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, + "data": { + "type": "TextInput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[Text] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Revolutionary Nano-Battery Technology Unveiled In a groundbreaking announcement yesterday, researchers from the fictional Tech Innovations Institute revealed the development of a new nano-battery technology that promises to revolutionize energy storage. The new battery, dubbed the \"EnerGCell\", uses advanced nanomaterials to achieve unprecedented efficiency and storage capacities. According to lead researcher Dr. Ada Byron, the EnerGCell can store up to ten times more energy than the best lithium-ion batteries available today, while charging in just a fraction of the time. \"We're talking about charging your electric vehicle in just five minutes for a range of over 1,000 miles,\" Dr. Byron stated during the press conference. The technology behind the EnerGCell involves a complex arrangement of nanostructured electrodes that allow for rapid ion transfer and extremely high energy density. This breakthrough was achieved after a decade of research into nanomaterials and their applications in energy storage. The implications of this technology are vast, promising to accelerate the adoption of renewable energy by making it more practical and affordable to store wind and solar power. It could also lead to significant advancements in electric vehicles, mobile devices, and any other technology that relies on batteries. Despite the excitement, some experts are calling for patience, noting that the EnerGCell is still in its early stages of development and may take several years before it's commercially available. However, the potential impact of such a technology on the environment and the global economy is undeniable. Tech Innovations Institute plans to continue refining the EnerGCell and begin pilot projects with select partners in the coming year. If successful, this nano-battery technology could indeed be the breakthrough needed to usher in a new era of clean energy and technology.", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": ["Record", "Text"], + "dynamic": false, + "info": "Text or Record to be passed as input.", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", - "target": "TextOutput-2MS4a", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-2MS4a", - "inputTypes": [ - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "Prompt", - "id": "Prompt-amqBu" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-TextOutput-2MS4a{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "description": "Get text inputs from the Playground.", + "icon": "type", + "base_classes": ["str", "Text", "object"], + "display_name": "Text Input", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", - "target": "OpenAIModel-uYXZJ", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-uYXZJ", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "Prompt", - "id": "Prompt-amqBu" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-OpenAIModel-uYXZJ{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextInput-sptaH" + }, + "selected": false, + "width": 384, + "height": 290, + "positionAbsolute": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, + "dragging": false + }, + { + "id": "TextOutput-2MS4a", + "type": "genericNode", + "position": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": ["Record", "Text"], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", - "target": "Prompt-gTNiz", - "targetHandle": "{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "summary", - "id": "Prompt-gTNiz", - "inputTypes": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-Prompt-gTNiz{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": ["str", "Text", "object"], + "display_name": "First Prompt", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", - "target": "ChatOutput-EJkG3", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-EJkG3", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ" - } + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-2MS4a" + }, + "selected": false, + "width": 384, + "height": 290, + "positionAbsolute": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, + "dragging": false + }, + { + "id": "OpenAIModel-uYXZJ", + "type": "genericNode", + "position": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-turbo-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "OPENAI_API_KEY" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-ChatOutput-EJkG3{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", - "target": "TextOutput-MUDOR", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-MUDOR", - "inputTypes": [ - "Record", - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "Prompt", - "id": "Prompt-gTNiz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-TextOutput-MUDOR{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["str", "Text", "object"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", - "target": "OpenAIModel-XawYB", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-XawYB", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "object", - "str", - "Text" - ], - "dataType": "Prompt", - "id": "Prompt-gTNiz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-OpenAIModel-XawYB{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-uYXZJ" + }, + "selected": false, + "width": 384, + "height": 565, + "positionAbsolute": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "dragging": false + }, + { + "id": "TextOutput-MUDOR", + "type": "genericNode", + "position": { + "x": 4446.064323520379, + "y": 633.833297518702 + }, + "data": { + "type": "TextOutput", + "node": { + "template": { + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Value", + "advanced": false, + "input_types": ["Record", "Text"], + "dynamic": false, + "info": "Text or Record to be passed as output.", + "load_from_db": false, + "title_case": false + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "record_template": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "record_template", + "display_name": "Record Template", + "advanced": true, + "dynamic": false, + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "_type": "CustomComponent" }, - { - "source": "OpenAIModel-XawYB", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}", - "target": "ChatOutput-DNmvg", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-DNmvg", - "inputTypes": [ - "Text" - ], - "type": "str" - }, - "sourceHandle": { - "baseClasses": [ - "str", - "Text", - "object" - ], - "dataType": "OpenAIModel", - "id": "OpenAIModel-XawYB" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-XawYB{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}-ChatOutput-DNmvg{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": -383.7251879618552, - "y": 69.19813933800037, - "zoom": 0.3105753483695743 + "description": "Display a text output in the Playground.", + "icon": "type", + "base_classes": ["str", "Text", "object"], + "display_name": "Second Prompt", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-MUDOR" + }, + "selected": false, + "width": 384, + "height": 290, + "dragging": false, + "positionAbsolute": { + "x": 4446.064323520379, + "y": 633.833297518702 } - }, - "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", - "name": "Prompt Chaining", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + { + "id": "OpenAIModel-XawYB", + "type": "genericNode", + "position": { + "x": 4500.152018344182, + "y": 1027.7382026227656 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "max_tokens": { + "type": "int", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 256, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "max_tokens", + "display_name": "Max Tokens", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_kwargs": { + "type": "NestedDict", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": {}, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "model_kwargs", + "display_name": "Model Kwargs", + "advanced": true, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "model_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "gpt-4-turbo-preview", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "name": "model_name", + "display_name": "Model Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_base": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "openai_api_base", + "display_name": "OpenAI API Base", + "advanced": true, + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "openai_api_key": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": true, + "name": "openai_api_key", + "display_name": "OpenAI API Key", + "advanced": false, + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"], + "value": "" + }, + "stream": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "stream", + "display_name": "Stream", + "advanced": true, + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "load_from_db": false, + "title_case": false + }, + "system_message": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "system_message", + "display_name": "System Message", + "advanced": true, + "dynamic": false, + "info": "System message to pass to the model.", + "load_from_db": false, + "title_case": false, + "input_types": ["Text"] + }, + "temperature": { + "type": "float", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": ["str", "Text", "object"], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": ["Text"], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-XawYB" + }, + "selected": false, + "width": 384, + "height": 565, + "positionAbsolute": { + "x": 4500.152018344182, + "y": 1027.7382026227656 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "TextInput-sptaH", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}", + "target": "Prompt-amqBu", + "targetHandle": "{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "document", + "id": "Prompt-amqBu", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "TextInput", + "id": "TextInput-sptaH" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-TextInput-sptaH{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}-Prompt-amqBu{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-amqBu", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", + "target": "TextOutput-2MS4a", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-2MS4a", + "inputTypes": ["Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "Prompt", + "id": "Prompt-amqBu" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-TextOutput-2MS4a{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-amqBu", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", + "target": "OpenAIModel-uYXZJ", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-uYXZJ", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "Prompt", + "id": "Prompt-amqBu" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-OpenAIModel-uYXZJ{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", + "target": "Prompt-gTNiz", + "targetHandle": "{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "summary", + "id": "Prompt-gTNiz", + "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-uYXZJ" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-Prompt-gTNiz{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", + "target": "ChatOutput-EJkG3", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-EJkG3", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-uYXZJ" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-ChatOutput-EJkG3{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-gTNiz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", + "target": "TextOutput-MUDOR", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-MUDOR", + "inputTypes": ["Record", "Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "Prompt", + "id": "Prompt-gTNiz" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-TextOutput-MUDOR{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-gTNiz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", + "target": "OpenAIModel-XawYB", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-XawYB", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["object", "str", "Text"], + "dataType": "Prompt", + "id": "Prompt-gTNiz" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-OpenAIModel-XawYB{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-XawYB", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}", + "target": "ChatOutput-DNmvg", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-DNmvg", + "inputTypes": ["Text"], + "type": "str" + }, + "sourceHandle": { + "baseClasses": ["str", "Text", "object"], + "dataType": "OpenAIModel", + "id": "OpenAIModel-XawYB" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-OpenAIModel-XawYB{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}-ChatOutput-DNmvg{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -383.7251879618552, + "y": 69.19813933800037, + "zoom": 0.3105753483695743 + } + }, + "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", + "name": "Prompt Chaining", + "last_tested_version": "1.0.0a0", + "is_component": false } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json b/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json index 74069017c..097fdbbc2 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json @@ -1631,7 +1631,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import Optional\n\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", + "value": "from typing import Optional\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", "fileTypes": [], "file_path": "", "password": false, @@ -2300,7 +2300,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import List, Optional, Union\n\nfrom langchain.schema import BaseRetriever\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", + "value": "from typing import List, Optional, Union\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\nfrom langchain_core.retrievers import BaseRetriever\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like \u201cSync\u201d, \u201cAsync\u201d, or \u201cOff\u201d.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", "fileTypes": [], "file_path": "", "password": false, diff --git a/src/backend/base/langflow/interface/agents/custom.py b/src/backend/base/langflow/interface/agents/custom.py index 680bc9bf8..36d9bd653 100644 --- a/src/backend/base/langflow/interface/agents/custom.py +++ b/src/backend/base/langflow/interface/agents/custom.py @@ -5,7 +5,6 @@ from langchain.agents.agent_toolkits import VectorStoreInfo, VectorStoreRouterTo from langchain.agents.agent_toolkits.vectorstore.prompt import PREFIX as VECTORSTORE_PREFIX from langchain.agents.agent_toolkits.vectorstore.prompt import ROUTER_PREFIX as VECTORSTORE_ROUTER_PREFIX from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS -from langchain.base_language import BaseLanguageModel from langchain.chains.llm import LLMChain from langchain_community.utilities import SQLDatabase from langchain.tools.sql_database.prompt import QUERY_CHECKER @@ -18,6 +17,14 @@ from langchain_experimental.agents.agent_toolkits.pandas.prompt import SUFFIX_WI from langchain_experimental.tools.python.tool import PythonAstREPLTool from langflow.interface.base import CustomAgentExecutor +from langchain_community.tools import ( + InfoSQLDatabaseTool, + ListSQLDatabaseTool, + QuerySQLCheckerTool, + QuerySQLDataBaseTool, +) +from langchain_core.language_models import BaseLanguageModel +from langchain_core.prompts import PromptTemplate class JsonAgent(CustomAgentExecutor): @@ -165,17 +172,6 @@ class SQLAgent(CustomAgentExecutor): db = SQLDatabase.from_uri(database_uri) toolkit = SQLDatabaseToolkit(db=db, llm=llm) - # The right code should be this, but there is a problem with tools = toolkit.get_tools() - # related to `OPENAI_API_KEY` - # return create_sql_agent(llm=llm, toolkit=toolkit, verbose=True) - from langchain.prompts import PromptTemplate - from langchain.tools.sql_database.tool import ( - InfoSQLDatabaseTool, - ListSQLDatabaseTool, - QuerySQLCheckerTool, - QuerySQLDataBaseTool, - ) - llmchain = LLMChain( llm=llm, prompt=PromptTemplate(template=QUERY_CHECKER, input_variables=["query", "dialect"]), diff --git a/src/backend/base/langflow/interface/agents/prebuilt.py b/src/backend/base/langflow/interface/agents/prebuilt.py index ec4799a81..9e59a76e1 100644 --- a/src/backend/base/langflow/interface/agents/prebuilt.py +++ b/src/backend/base/langflow/interface/agents/prebuilt.py @@ -1,9 +1,9 @@ from langchain.chains.llm import LLMChain from langchain.agents import AgentExecutor, ZeroShotAgent from langchain.agents.agent_toolkits.json.prompt import JSON_PREFIX, JSON_SUFFIX -from langchain.agents.agent_toolkits.json.toolkit import JsonToolkit from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS -from langchain.base_language import BaseLanguageModel +from langchain_community.agent_toolkits import JsonToolkit +from langchain_core.language_models import BaseLanguageModel class MalfoyAgent(AgentExecutor): diff --git a/src/backend/base/langflow/interface/chains/custom.py b/src/backend/base/langflow/interface/chains/custom.py index 2a72f3471..af5a84c54 100644 --- a/src/backend/base/langflow/interface/chains/custom.py +++ b/src/backend/base/langflow/interface/chains/custom.py @@ -1,14 +1,13 @@ from typing import Dict, Optional, Type, Union - -from langchain.base_language import BaseLanguageModel from langchain.chains import ConversationChain from langchain.chains.question_answering import load_qa_chain from langchain.memory.buffer import ConversationBufferMemory -from langchain.schema import BaseMemory from pydantic.v1 import Field, root_validator from langflow.interface.base import CustomChain from langflow.interface.utils import extract_input_variables_from_prompt +from langchain_core.language_models import BaseLanguageModel +from langchain_core.memory import BaseMemory DEFAULT_SUFFIX = """" Current conversation: diff --git a/src/backend/base/langflow/interface/custom_lists.py b/src/backend/base/langflow/interface/custom_lists.py index 9b494e450..27429e605 100644 --- a/src/backend/base/langflow/interface/custom_lists.py +++ b/src/backend/base/langflow/interface/custom_lists.py @@ -3,11 +3,13 @@ from typing import Any from langchain import llms, memory, text_splitter from langchain_community import agent_toolkits, document_loaders, embeddings -from langchain_community.chat_models import AzureChatOpenAI, ChatAnthropic, ChatOpenAI, ChatVertexAI +from langchain_community.chat_models import ChatVertexAI from langflow.interface.agents.custom import CUSTOM_AGENTS from langflow.interface.chains.custom import CUSTOM_CHAINS from langflow.interface.importing.utils import import_class +from langchain_anthropic import ChatAnthropic +from langchain_openai import AzureChatOpenAI, ChatOpenAI # LLMs llm_type_to_cls_dict = {} diff --git a/src/backend/base/langflow/interface/importing/utils.py b/src/backend/base/langflow/interface/importing/utils.py index 1b921d87b..a4f4904ac 100644 --- a/src/backend/base/langflow/interface/importing/utils.py +++ b/src/backend/base/langflow/interface/importing/utils.py @@ -4,13 +4,13 @@ import importlib from typing import Any, Type from langchain.agents import Agent -from langchain.base_language import BaseLanguageModel from langchain.chains.base import Chain -from langchain.prompts import PromptTemplate -from langchain.tools import BaseTool from langchain_core.language_models.chat_models import BaseChatModel from langflow.interface.wrappers.base import wrapper_creator +from langchain_core.language_models import BaseLanguageModel +from langchain_core.prompts import PromptTemplate +from langchain_core.tools import BaseTool def import_module(module_path: str) -> Any: diff --git a/src/backend/base/langflow/interface/initialize/loading.py b/src/backend/base/langflow/interface/initialize/loading.py index 6001258bc..d5ebf7260 100644 --- a/src/backend/base/langflow/interface/initialize/loading.py +++ b/src/backend/base/langflow/interface/initialize/loading.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, Sequence, Type import orjson 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 langchain.chains.base import Chain -from langchain.document_loaders.base import BaseLoader -from langchain_community.vectorstores import VectorStore from langchain_core.documents import Document from loguru import logger from pydantic import ValidationError @@ -27,6 +23,11 @@ from langflow.interface.wrappers.base import wrapper_creator from langflow.schema.schema import Record from langflow.utils import validate from langflow.utils.util import unescape_string +from langchain_community.agent_toolkits.base import BaseToolkit +from langchain_core.document_loaders import BaseLoader +from langchain_core.tools import BaseTool +from langchain_core.vectorstores import VectorStore +from langchain_text_splitters import Language if TYPE_CHECKING: from langflow.custom import CustomComponent @@ -430,8 +431,6 @@ def instantiate_textsplitter( params["separators"] = [unescape_string(separator) for separator in params["separators"]] text_splitter = class_object(**params) else: - from langchain.text_splitter import Language - language = params.pop("separator_type", None) params["language"] = Language(language) params.pop("separators", None) diff --git a/src/backend/base/langflow/interface/initialize/utils.py b/src/backend/base/langflow/interface/initialize/utils.py index 0ef76836b..c09525a6c 100644 --- a/src/backend/base/langflow/interface/initialize/utils.py +++ b/src/backend/base/langflow/interface/initialize/utils.py @@ -4,9 +4,10 @@ from typing import Any, Dict, List import orjson from langchain.agents import ZeroShotAgent -from langchain.schema import BaseOutputParser, Document from langflow.services.database.models.base import orjson_dumps +from langchain_core.documents import Document +from langchain_core.output_parsers import BaseOutputParser def handle_node_type(node_type, class_object, params: Dict): diff --git a/src/backend/base/langflow/interface/initialize/vector_store.py b/src/backend/base/langflow/interface/initialize/vector_store.py index 8e596298c..8b9034e65 100644 --- a/src/backend/base/langflow/interface/initialize/vector_store.py +++ b/src/backend/base/langflow/interface/initialize/vector_store.py @@ -6,12 +6,12 @@ from langchain_community.vectorstores import ( FAISS, Chroma, MongoDBAtlasVectorSearch, - Pinecone, Qdrant, SupabaseVectorStore, Weaviate, ) from langchain_core.documents import Document +from langchain_pinecone import Pinecone def docs_in_params(params: dict) -> bool: diff --git a/src/backend/base/langflow/interface/prompts/custom.py b/src/backend/base/langflow/interface/prompts/custom.py index 202fbe409..e90ce8812 100644 --- a/src/backend/base/langflow/interface/prompts/custom.py +++ b/src/backend/base/langflow/interface/prompts/custom.py @@ -1,9 +1,8 @@ from typing import Dict, List, Optional, Type - -from langchain.prompts import PromptTemplate from pydantic.v1 import root_validator from langflow.interface.utils import extract_input_variables_from_prompt +from langchain_core.prompts import PromptTemplate # Steps to create a BaseCustomPrompt: # 1. Create a prompt template that endes with: diff --git a/src/backend/base/langflow/interface/tools/constants.py b/src/backend/base/langflow/interface/tools/constants.py index 27b42b327..39e3b7465 100644 --- a/src/backend/base/langflow/interface/tools/constants.py +++ b/src/backend/base/langflow/interface/tools/constants.py @@ -1,10 +1,10 @@ from langchain import tools -from langchain.agents import Tool from langchain.agents.load_tools import _BASE_TOOLS, _EXTRA_LLM_TOOLS, _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS from langchain_community.tools.json.tool import JsonSpec from langflow.interface.importing.utils import import_class from langflow.interface.tools.custom import PythonFunctionTool +from langchain_core.tools import Tool FILE_TOOLS = {"JsonSpec": JsonSpec} CUSTOM_TOOLS = { diff --git a/src/backend/base/langflow/interface/tools/custom.py b/src/backend/base/langflow/interface/tools/custom.py index 6ba8cac13..8afaa10da 100644 --- a/src/backend/base/langflow/interface/tools/custom.py +++ b/src/backend/base/langflow/interface/tools/custom.py @@ -1,10 +1,9 @@ from typing import Callable, Optional - -from langchain.agents.tools import Tool from pydantic.v1 import BaseModel, validator from langflow.interface.custom.utils import get_function from langflow.utils import validate +from langchain_core.tools import Tool class Function(BaseModel): diff --git a/src/backend/base/langflow/interface/tools/util.py b/src/backend/base/langflow/interface/tools/util.py index 7c8020aa9..f572efe5e 100644 --- a/src/backend/base/langflow/interface/tools/util.py +++ b/src/backend/base/langflow/interface/tools/util.py @@ -2,8 +2,7 @@ import ast import inspect import textwrap from typing import Dict, Union - -from langchain.agents.tools import Tool +from langchain_core.tools import Tool def get_func_tool_params(func, **kwargs) -> Union[Dict, None]: diff --git a/src/backend/base/langflow/interface/utils.py b/src/backend/base/langflow/interface/utils.py index d4271eabf..252d5f411 100644 --- a/src/backend/base/langflow/interface/utils.py +++ b/src/backend/base/langflow/interface/utils.py @@ -7,12 +7,12 @@ from typing import Dict import yaml from docstring_parser import parse -from langchain.base_language import BaseLanguageModel from langflow.services.chat.config import ChatConfig from langflow.services.deps import get_settings_service from langflow.utils.util import format_dict, get_base_classes, get_default_factory from loguru import logger from PIL.Image import Image +from langchain_core.language_models import BaseLanguageModel def load_file_into_dict(file_path: str) -> dict: diff --git a/src/backend/base/langflow/processing/base.py b/src/backend/base/langflow/processing/base.py index e11af0a44..35e46a3b2 100644 --- a/src/backend/base/langflow/processing/base.py +++ b/src/backend/base/langflow/processing/base.py @@ -1,11 +1,11 @@ from typing import TYPE_CHECKING, List, Union from langchain.agents.agent import AgentExecutor -from langchain.callbacks.base import BaseCallbackHandler from loguru import logger from langflow.processing.process import fix_memory_inputs, format_actions from langflow.services.deps import get_plugins_service +from langchain_core.callbacks import BaseCallbackHandler if TYPE_CHECKING: from langfuse.callback import CallbackHandler # type: ignore diff --git a/src/backend/base/langflow/processing/process.py b/src/backend/base/langflow/processing/process.py index d46274b4c..326e8ca3d 100644 --- a/src/backend/base/langflow/processing/process.py +++ b/src/backend/base/langflow/processing/process.py @@ -2,7 +2,6 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union from langchain.agents import AgentExecutor -from langchain.schema import AgentAction from loguru import logger from pydantic import BaseModel @@ -13,6 +12,7 @@ from langflow.interface.run import get_memory_key, update_memory_keys from langflow.schema.graph import InputValue, Tweaks from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.session.service import SessionService +from langchain_core.agents import AgentAction if TYPE_CHECKING: diff --git a/src/backend/base/langflow/template/frontend_node/textsplitters.py b/src/backend/base/langflow/template/frontend_node/textsplitters.py index eb302e996..8fc5620d2 100644 --- a/src/backend/base/langflow/template/frontend_node/textsplitters.py +++ b/src/backend/base/langflow/template/frontend_node/textsplitters.py @@ -1,7 +1,6 @@ -from langchain.text_splitter import Language - from langflow.template.field.base import TemplateField from langflow.template.frontend_node.base import FrontendNode +from langchain_text_splitters import Language class TextSplittersFrontendNode(FrontendNode): diff --git a/src/backend/base/poetry.lock b/src/backend/base/poetry.lock index 653359b34..b1607cf7e 100644 --- a/src/backend/base/poetry.lock +++ b/src/backend/base/poetry.lock @@ -545,6 +545,26 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] +[[package]] +name = "dnspython" +version = "2.6.1" +description = "DNS toolkit" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, +] + +[package.extras] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] + [[package]] name = "docstring-parser" version = "0.15" @@ -630,6 +650,21 @@ six = ">=1.9.0" gmpy = ["gmpy"] gmpy2 = ["gmpy2"] +[[package]] +name = "email-validator" +version = "2.1.1" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}, + {file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + [[package]] name = "emoji" version = "2.12.1" @@ -663,23 +698,48 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.110.3" +version = "0.111.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.110.3-py3-none-any.whl", hash = "sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32"}, - {file = "fastapi-0.110.3.tar.gz", hash = "sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626"}, + {file = "fastapi-0.111.0-py3-none-any.whl", hash = "sha256:97ecbf994be0bcbdadedf88c3150252bed7b2087075ac99735403b1b76cc8fc0"}, + {file = "fastapi-0.111.0.tar.gz", hash = "sha256:b9db9dd147c91cb8b769f7183535773d8741dd46f9dc6676cd82eab510228cd7"}, ] [package.dependencies] +email_validator = ">=2.0.0" +fastapi-cli = ">=0.0.2" +httpx = ">=0.23.0" +jinja2 = ">=2.11.2" +orjson = ">=3.2.1" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +python-multipart = ">=0.0.7" starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" +ujson = ">=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0" +uvicorn = {version = ">=0.12.0", extras = ["standard"]} [package.extras] all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "fastapi-cli" +version = "0.0.4" +description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, + {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, +] + +[package.dependencies] +typer = ">=0.12.3" + +[package.extras] +standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] + [[package]] name = "frozenlist" version = "1.4.1" @@ -890,6 +950,54 @@ http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] trio = ["trio (>=0.22.0,<0.26.0)"] +[[package]] +name = "httptools" +version = "0.6.1" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, + {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, + {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, + {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, + {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, + {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, + {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, +] + +[package.extras] +test = ["Cython (>=0.29.24,<0.30.0)"] + [[package]] name = "httpx" version = "0.27.0" @@ -925,6 +1033,23 @@ files = [ {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + [[package]] name = "jq" version = "1.7.0" @@ -1034,22 +1159,20 @@ files = [ [[package]] name = "langchain" -version = "0.1.20" +version = "0.2.1" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.1.20-py3-none-any.whl", hash = "sha256:09991999fbd6c3421a12db3c7d1f52d55601fc41d9b2a3ef51aab2e0e9c38da9"}, - {file = "langchain-0.1.20.tar.gz", hash = "sha256:f35c95eed8c8375e02dce95a34f2fd4856a4c98269d6dc34547a23dba5beab7e"}, + {file = "langchain-0.2.1-py3-none-any.whl", hash = "sha256:3e13bf97c5717bce2c281f5117e8778823e8ccf62d949e73d3869448962b1c97"}, + {file = "langchain-0.2.1.tar.gz", hash = "sha256:5758a315e1ac92eb26dafec5ad0fafa03cafa686aba197d5bb0b1dd28cc03ebe"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -dataclasses-json = ">=0.5.7,<0.7" -langchain-community = ">=0.0.38,<0.1" -langchain-core = ">=0.1.52,<0.2.0" -langchain-text-splitters = ">=0.0.1,<0.1" +langchain-core = ">=0.2.0,<0.3.0" +langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = ">=1,<2" pydantic = ">=1,<3" @@ -1065,28 +1188,29 @@ cli = ["typer (>=0.9.0,<0.10.0)"] cohere = ["cohere (>=4,<6)"] docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<6)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<6)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.1,<0.2)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] javascript = ["esprima (>=4.0.1,<5.0.0)"] llms = ["clarifai (>=9.1.0)", "cohere (>=4,<6)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] -openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"] +openai = ["openai (<2)", "tiktoken (>=0.7,<1.0)"] qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] text-helpers = ["chardet (>=5.1.0,<6.0.0)"] [[package]] name = "langchain-community" -version = "0.0.38" +version = "0.2.1" description = "Community contributed LangChain integrations." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_community-0.0.38-py3-none-any.whl", hash = "sha256:ecb48660a70a08c90229be46b0cc5f6bc9f38f2833ee44c57dfab9bf3a2c121a"}, - {file = "langchain_community-0.0.38.tar.gz", hash = "sha256:127fc4b75bc67b62fe827c66c02e715a730fef8fe69bd2023d466bab06b5810d"}, + {file = "langchain_community-0.2.1-py3-none-any.whl", hash = "sha256:b834e2c5ded6903b839fcaf566eee90a0ffae53405a0f7748202725e701d39cd"}, + {file = "langchain_community-0.2.1.tar.gz", hash = "sha256:079942e8f15da975769ccaae19042b7bba5481c42020bbbd7d8cad73a9393261"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain-core = ">=0.1.52,<0.2.0" +langchain = ">=0.2.0,<0.3.0" +langchain-core = ">=0.2.0,<0.3.0" langsmith = ">=0.1.0,<0.2.0" numpy = ">=1,<2" PyYAML = ">=5.3" @@ -1096,17 +1220,17 @@ tenacity = ">=8.1.0,<9.0.0" [package.extras] cli = ["typer (>=0.9.0,<0.10.0)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "azure-identity (>=1.15.0,<2.0.0)", "azure-search-documents (==11.4.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.6,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "oracledb (>=2.2.0,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "azure-identity (>=1.15.0,<2.0.0)", "azure-search-documents (==11.4.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.6,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpathlib (>=0.18,<0.19)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "oracledb (>=2.2.0,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] [[package]] name = "langchain-core" -version = "0.1.52" +version = "0.2.1" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_core-0.1.52-py3-none-any.whl", hash = "sha256:62566749c92e8a1181c255c788548dc16dbc319d896cd6b9c95dc17af9b2a6db"}, - {file = "langchain_core-0.1.52.tar.gz", hash = "sha256:084c3fc452f5a6966c28ab3ec5dbc8b8d26fc3f63378073928f4e29d90b6393f"}, + {file = "langchain_core-0.2.1-py3-none-any.whl", hash = "sha256:3521e1e573988c47399fca9739270c5d34f8ecec147253ad829eb9ff288f76d5"}, + {file = "langchain_core-0.2.1.tar.gz", hash = "sha256:49383126168d934559a543ce812c485048d9e6ac9b6798fbf3d4a72b6bba5b0c"}, ] [package.dependencies] @@ -1122,35 +1246,35 @@ extended-testing = ["jinja2 (>=3,<4)"] [[package]] name = "langchain-experimental" -version = "0.0.58" +version = "0.0.59" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_experimental-0.0.58-py3-none-any.whl", hash = "sha256:106d3bc7df3dd20687378db7534c2fc21e2589201d43de42f832a1e3913dd55b"}, - {file = "langchain_experimental-0.0.58.tar.gz", hash = "sha256:8ef10ff6b39f44ef468f8f21beb3749957d2262ec64d05db2719934936ca0285"}, + {file = "langchain_experimental-0.0.59-py3-none-any.whl", hash = "sha256:d6ceb586c15ad35fc619542e86d01f0984a94985324a78a9ed8cd87615ff265d"}, + {file = "langchain_experimental-0.0.59.tar.gz", hash = "sha256:3a93f5c328f6ee1cd4f9dd8792c535df2d5638cff0d778ee25546804b5282fda"}, ] [package.dependencies] -langchain = ">=0.1.17,<0.2.0" -langchain-core = ">=0.1.52,<0.2.0" +langchain-community = ">=0.2,<0.3" +langchain-core = ">=0.2,<0.3" [package.extras] extended-testing = ["faker (>=19.3.1,<20.0.0)", "jinja2 (>=3,<4)", "pandas (>=2.0.1,<3.0.0)", "presidio-analyzer (>=2.2.352,<3.0.0)", "presidio-anonymizer (>=2.2.352,<3.0.0)", "sentence-transformers (>=2,<3)", "tabulate (>=0.9.0,<0.10.0)", "vowpal-wabbit-next (==0.6.0)"] [[package]] name = "langchain-text-splitters" -version = "0.0.2" +version = "0.2.0" description = "LangChain text splitting utilities" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_text_splitters-0.0.2-py3-none-any.whl", hash = "sha256:13887f32705862c1e1454213cb7834a63aae57c26fcd80346703a1d09c46168d"}, - {file = "langchain_text_splitters-0.0.2.tar.gz", hash = "sha256:ac8927dc0ba08eba702f6961c9ed7df7cead8de19a9f7101ab2b5ea34201b3c1"}, + {file = "langchain_text_splitters-0.2.0-py3-none-any.whl", hash = "sha256:7b4c6a45f8471630a882b321e138329b6897102a5bc62f4c12be1c0b05bb9199"}, + {file = "langchain_text_splitters-0.2.0.tar.gz", hash = "sha256:b32ab4f7397f7d42c1fa3283fefc2547ba356bd63a68ee9092865e5ad83c82f9"}, ] [package.dependencies] -langchain-core = ">=0.1.28,<0.3" +langchain-core = ">=0.2.0,<0.3.0" [package.extras] extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] @@ -1172,13 +1296,13 @@ types-requests = ">=2.31.0.2,<3.0.0.0" [[package]] name = "langsmith" -version = "0.1.62" +version = "0.1.63" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.62-py3-none-any.whl", hash = "sha256:3a9f112643f64d736b8c875390c750fe6485804ea53aeae4edebce0afa4383a5"}, - {file = "langsmith-0.1.62.tar.gz", hash = "sha256:7ef894c14e6d4175fce88ec3bcd5a9c8cf9a456ea77e26e361f519ad082f34a8"}, + {file = "langsmith-0.1.63-py3-none-any.whl", hash = "sha256:7810afdf5e3f3b472fc581a29371fb96cd843dde2149e048d1b9610325159d1e"}, + {file = "langsmith-0.1.63.tar.gz", hash = "sha256:a609405b52f6f54df442a142cbf19ab38662d54e532f96028b4c546434d4afdf"}, ] [package.dependencies] @@ -2522,13 +2646,13 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlmodel" -version = "0.0.16" +version = "0.0.18" description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.7" files = [ - {file = "sqlmodel-0.0.16-py3-none-any.whl", hash = "sha256:b972f5d319580d6c37ecc417881f6ec4d1ad3ed3583d0ac0ed43234a28bf605a"}, - {file = "sqlmodel-0.0.16.tar.gz", hash = "sha256:966656f18a8e9a2d159eb215b07fb0cf5222acfae3362707ca611848a8a06bd1"}, + {file = "sqlmodel-0.0.18-py3-none-any.whl", hash = "sha256:d70fdf8fe595e30a918660cf4537b9c5fc2fffdbfcba851a0135de73c3ebcbb7"}, + {file = "sqlmodel-0.0.18.tar.gz", hash = "sha256:2e520efe03810ef2c268a1004cfc5ef8f8a936312232f38d6c8e62c11af2cac3"}, ] [package.dependencies] @@ -2600,13 +2724,13 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, ] [[package]] @@ -2635,6 +2759,93 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] +[[package]] +name = "ujson" +version = "5.10.0" +description = "Ultra fast JSON encoder and decoder for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, + {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"}, + {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"}, + {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"}, + {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"}, + {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"}, + {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"}, + {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"}, + {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"}, + {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"}, + {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"}, + {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"}, + {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"}, + {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"}, + {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"}, +] + [[package]] name = "urllib3" version = "2.2.1" @@ -2665,12 +2876,150 @@ files = [ [package.dependencies] click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +[[package]] +name = "uvloop" +version = "0.19.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, + {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, +] + +[package.extras] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + +[[package]] +name = "watchfiles" +version = "0.21.0" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchfiles-0.21.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa"}, + {file = "watchfiles-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c"}, + {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9"}, + {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9"}, + {file = "watchfiles-0.21.0-cp310-none-win32.whl", hash = "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293"}, + {file = "watchfiles-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235"}, + {file = "watchfiles-0.21.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7"}, + {file = "watchfiles-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7"}, + {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0"}, + {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365"}, + {file = "watchfiles-0.21.0-cp311-none-win32.whl", hash = "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400"}, + {file = "watchfiles-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe"}, + {file = "watchfiles-0.21.0-cp311-none-win_arm64.whl", hash = "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078"}, + {file = "watchfiles-0.21.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a"}, + {file = "watchfiles-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c"}, + {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235"}, + {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7"}, + {file = "watchfiles-0.21.0-cp312-none-win32.whl", hash = "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3"}, + {file = "watchfiles-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094"}, + {file = "watchfiles-0.21.0-cp312-none-win_arm64.whl", hash = "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6"}, + {file = "watchfiles-0.21.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99"}, + {file = "watchfiles-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562"}, + {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19"}, + {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0"}, + {file = "watchfiles-0.21.0-cp38-none-win32.whl", hash = "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214"}, + {file = "watchfiles-0.21.0-cp38-none-win_amd64.whl", hash = "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca"}, + {file = "watchfiles-0.21.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e"}, + {file = "watchfiles-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28"}, + {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6"}, + {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49"}, + {file = "watchfiles-0.21.0-cp39-none-win32.whl", hash = "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94"}, + {file = "watchfiles-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097"}, + {file = "watchfiles-0.21.0.tar.gz", hash = "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + [[package]] name = "websockets" version = "12.0" @@ -2891,4 +3240,4 @@ local = [] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "200c17e119f7ba7fdb64de320bdf464c65daf06f62bcc41258b32247a99e3dc1" +content-hash = "33e71f349d108a5bc98b0f8cd0f5c14736202f3db30b0ea1acf588163ef5fbe3" diff --git a/src/backend/base/pyproject.toml b/src/backend/base/pyproject.toml index b59196fa2..a3978a804 100644 --- a/src/backend/base/pyproject.toml +++ b/src/backend/base/pyproject.toml @@ -26,18 +26,18 @@ langflow-base = "langflow.__main__:main" [tool.poetry.dependencies] python = ">=3.10,<3.13" -fastapi = "^0.110.1" +fastapi = "^0.111.0" httpx = "*" uvicorn = "^0.29.0" gunicorn = "^22.0.0" -langchain = "~0.1.16" +langchain = "~0.2.0" langchainhub = "~0.1.15" -sqlmodel = "^0.0.16" +sqlmodel = "^0.0.18" loguru = "^0.7.1" rich = "^13.7.0" langchain-experimental = "*" -pydantic = "^2.5.0" -pydantic-settings = "^2.1.0" +pydantic = "^2.7.0" +pydantic-settings = "^2.2.0" websockets = "*" typer = "^0.12.0" cachetools = "^5.3.1" @@ -56,9 +56,9 @@ duckdb = "^0.10.2" python-socketio = "^5.11.0" python-docx = "^1.1.0" jq = { version = "^1.7.0", markers = "sys_platform != 'win32'" } -pypdf = "^4.1.0" +pypdf = "^4.2.0" nest-asyncio = "^1.6.0" -emoji = "^2.11.0" +emoji = "^2.12.0" cryptography = "^42.0.5" asyncer = "^0.0.5" diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index db35073e8..922ec9994 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -15,6 +15,7 @@ import { } from "./constants/constants"; import { AuthContext } from "./contexts/authContext"; import { autoLogin, getGlobalVariables, getHealth } from "./controllers/API"; +import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path"; import Router from "./routes"; import useAlertStore from "./stores/alertStore"; import { useDarkStore } from "./stores/darkStore"; @@ -24,6 +25,8 @@ import { useGlobalVariablesStore } from "./stores/globalVariablesStore/globalVar import { useStoreStore } from "./stores/storeStore"; import { useTypesStore } from "./stores/typesStore"; export default function App() { + useTrackLastVisitedPath(); + const removeFromTempNotificationList = useAlertStore( (state) => state.removeFromTempNotificationList, ); @@ -104,7 +107,6 @@ export default function App() { const fetchAllData = async () => { setTimeout(async () => { await Promise.all([refreshStars(), refreshVersion(), fetchData()]); - getFoldersApi(); }, 1000); }; @@ -112,6 +114,7 @@ export default function App() { return new Promise(async (resolve, reject) => { if (isAuthenticated) { try { + await getFoldersApi(); await getTypes(); await refreshFlows(); const res = await getGlobalVariables(); @@ -208,7 +211,7 @@ export default function App() {
{tempNotificationList.map((alert) => (
- {alert.type === "error" && ( + {alert.type === "error" ? ( - )} -
- ))} -
-
- {tempNotificationList.map((alert) => ( -
- {alert.type === "notice" ? ( - ) : ( - alert.type === "success" && ( - @@ -244,6 +233,20 @@ export default function App() {
))}
+
+ {tempNotificationList.map((alert) => ( +
+ {alert.type === "success" && ( + + )} +
+ ))} +
); diff --git a/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx b/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx index 96a1b6b68..f3dc06453 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx @@ -1,3 +1,3 @@ export default function sortByName(stringList: string[]): string[] { return stringList.sort((a, b) => a.localeCompare(b)); -} \ No newline at end of file +} diff --git a/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx b/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx index ac8800540..068b7b585 100644 --- a/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx +++ b/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx @@ -1,3 +1,3 @@ export function convertTestName(name: string): string { - return name.replace(/ /g, "-").toLowerCase(); + return name.replace(/ /g, "-").toLowerCase(); } diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index b5a115e1e..41f7b6d5b 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -8,7 +8,6 @@ import { } from "../../../ui/dropdown-menu"; import { useNavigate } from "react-router-dom"; -import { Node } from "reactflow"; import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants"; import { SAVED_HOVER } from "../../../../constants/constants"; import ExportModal from "../../../../modals/exportModal"; @@ -22,11 +21,7 @@ import IconComponent from "../../../genericIconComponent"; import ShadTooltip from "../../../shadTooltipComponent"; import { Button } from "../../../ui/button"; -export const MenuBar = ({ - removeFunction, -}: { - removeFunction: (nodes: Node[]) => void; -}): JSX.Element => { +export const MenuBar = ({}: {}): JSX.Element => { const addFlow = useFlowsManagerStore((state) => state.addFlow); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const setErrorData = useAlertStore((state) => state.setErrorData); @@ -36,7 +31,6 @@ export const MenuBar = ({ const saveLoading = useFlowsManagerStore((state) => state.saveLoading); const [openSettings, setOpenSettings] = useState(false); const [openLogs, setOpenLogs] = useState(false); - const nodes = useFlowStore((state) => state.nodes); const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); const navigate = useNavigate(); const isBuilding = useFlowStore((state) => state.isBuilding); @@ -72,14 +66,6 @@ export const MenuBar = ({ return currentFlow ? (
-
diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 2467fdcfe..4f6c02bd8 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -3,14 +3,17 @@ import { FaDiscord, FaGithub } from "react-icons/fa"; import { RiTwitterXFill } from "react-icons/ri"; import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; import AlertDropdown from "../../alerts/alertDropDown"; -import { USER_PROJECTS_HEADER } from "../../constants/constants"; +import { + LOCATIONS_TO_RETURN, + USER_PROJECTS_HEADER, +} from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; -import { Node } from "reactflow"; import useAlertStore from "../../stores/alertStore"; import { useDarkStore } from "../../stores/darkStore"; import useFlowStore from "../../stores/flowStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; +import { useLocationStore } from "../../stores/locationStore"; import { useStoreStore } from "../../stores/storeStore"; import { gradients } from "../../utils/styleUtils"; import IconComponent from "../genericIconComponent"; @@ -29,6 +32,7 @@ import MenuBar from "./components/menuBar"; export default function Header(): JSX.Element { const notificationCenter = useAlertStore((state) => state.notificationCenter); const location = useLocation(); + const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext); const navigate = useNavigate(); const removeFlow = useFlowsManagerStore((store) => store.removeFlow); @@ -40,20 +44,56 @@ export default function Header(): JSX.Element { const setDark = useDarkStore((state) => state.setDark); const stars = useDarkStore((state) => state.stars); - async function checkForChanges(nodes: Node[]): Promise { + const routeHistory = useLocationStore((state) => state.routeHistory); + + async function checkForChanges(): Promise { if (nodes.length === 0) { await removeFlow(id!); } } + const redirectToLastLocation = () => { + const lastFlowVisitedIndex = routeHistory + .reverse() + .findIndex( + (path) => path.includes("/flow/") && path !== location.pathname, + ); + + const lastFlowVisited = routeHistory[lastFlowVisitedIndex]; + lastFlowVisited && !location.pathname.includes("/flow") + ? navigate(lastFlowVisited) + : navigate("/all"); + }; + + const visitedFlowPathBefore = () => { + const lastThreeVisitedPaths = routeHistory.slice(-3); + return lastThreeVisitedPaths.some((path) => path.includes("/flow/")); + }; + + const showArrowReturnIcon = + LOCATIONS_TO_RETURN.some((path) => location.pathname.includes(path)) && + visitedFlowPathBefore(); + return (
- checkForChanges(nodes)}> + ⛓️ - + {showArrowReturnIcon && ( + + )} + +
+
diff --git a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx index ee83a34e6..8a1dc4a29 100644 --- a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx +++ b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx @@ -1,16 +1,18 @@ +import { useEffect, useRef, useState } from "react"; import { useLocation } from "react-router-dom"; import { FolderType } from "../../../../pages/MainPage/entities"; +import { addFolder, updateFolder } from "../../../../pages/MainPage/services"; +import { handleDownloadFolderFn } from "../../../../pages/MainPage/utils/handle-download-folder"; +import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; import { useFolderStore } from "../../../../stores/foldersStore"; +import { handleKeyDown } from "../../../../utils/reactflowUtils"; import { cn } from "../../../../utils/utils"; -import DropdownButton from "../../../dropdownButtonComponent"; import IconComponent, { ForwardedIconComponent, } from "../../../genericIconComponent"; import { Button, buttonVariants } from "../../../ui/button"; +import { Input } from "../../../ui/input"; import useFileDrop from "../../hooks/use-on-file-drop"; -import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; -import { handleDownloadFolderFn } from "../../../../pages/MainPage/utils/handle-download-folder"; -import useAlertStore from "../../../../stores/alertStore"; type SideBarFoldersButtonsComponentProps = { folders: FolderType[]; @@ -18,22 +20,27 @@ type SideBarFoldersButtonsComponentProps = { handleChangeFolder?: (id: string) => void; handleEditFolder?: (item: FolderType) => void; handleDeleteFolder?: (item: FolderType) => void; - handleAddFolder?: () => void; }; const SideBarFoldersButtonsComponent = ({ - folders, pathname, - handleAddFolder, handleChangeFolder, handleEditFolder, handleDeleteFolder, }: SideBarFoldersButtonsComponentProps) => { + const refInput = useRef(null); + const setFolders = useFolderStore((state) => state.setFolders); + const folders = useFolderStore((state) => state.folders); + const [foldersNames, setFoldersNames] = useState({}); + const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); + const [editFolders, setEditFolderName] = useState( + folders.map((obj) => ({ name: obj.name, edit: false })), + ); const uploadFolder = useFolderStore((state) => state.uploadFolder); const currentFolder = pathname.split("/"); const urlWithoutPath = pathname.split("/").length < 4; const myCollectionId = useFolderStore((state) => state.myCollectionId); - const allFlows = useFlowsManagerStore((state) => state.allFlows); - const setErrorData = useAlertStore((state) => state.setErrorData); + const getFoldersApi = useFolderStore((state) => state.getFoldersApi); + const folderIdDragging = useFolderStore((state) => state.folderIdDragging); const checkPathName = (itemId: string) => { if (urlWithoutPath && itemId === myCollectionId) { @@ -62,20 +69,44 @@ const SideBarFoldersButtonsComponent = ({ handleDownloadFolderFn(id); }; + function addNewFolder() { + addFolder({ name: "New Folder", parent_id: null, description: "" }).then( + (res) => { + getFoldersApi(true); + }, + ); + } + + function handleEditFolderName(e, name): void { + const { + target: { value }, + } = e; + setFoldersNames((old) => ({ + ...old, + [name]: value, + })); + } + + useEffect(() => { + folders.map((obj) => ({ name: obj.name, edit: false })); + }, [folders]); + + console.log(folderId, folderIdDragging); + return ( <>
- + + {folders.map((item, index) => { + const editFolderName = editFolders?.filter( + (folder) => folder.name === item.name, + )[0]; + return ( +
dragOver(e, item.id!)} + onDragEnter={(e) => dragEnter(e, item.id!)} + onDragLeave={dragLeave} + onDrop={(e) => onDrop(e, item.id!)} + key={item.id} + data-testid={`sidebar-nav-${item.name}`} + className={cn( + buttonVariants({ variant: "ghost" }), + checkPathName(item.id!) + ? "border border-border bg-muted hover:bg-muted" + : "border hover:bg-transparent lg:border-transparent lg:hover:border-border", + "group flex w-full shrink-0 cursor-pointer gap-2 opacity-100 lg:min-w-full", + folderIdDragging === item.id! ? "bg-border" : "", )} - {index > 0 && ( + onClick={() => handleChangeFolder!(item.id!)} + > +
{ + if (item.name === "My Projects") { + return; + } + + if (!foldersNames[item.name]) { + setFoldersNames({ [item.name]: item.name }); + } + + if ( + editFolders.find((obj) => obj.name === item.name)?.name + ) { + const newEditFolders = editFolders.map((obj) => { + if (obj.name === item.name) { + return { name: item.name, edit: true }; + } + return { name: obj.name, edit: false }; + }); + setEditFolderName(newEditFolders); + takeSnapshot(); + event.stopPropagation(); + event.preventDefault(); + return; + } + + setEditFolderName((old) => [ + ...old, + { name: item.name, edit: true }, + ]); + setFoldersNames((oldFolder) => ({ + ...oldFolder, + [item.name]: item.name, + })); + takeSnapshot(); + event.stopPropagation(); + event.preventDefault(); + }} + className="flex w-full items-center gap-2" + > + + {editFolderName?.edit ? ( +
+ { + handleEditFolderName(e, item.name); + }} + ref={refInput} + onKeyDown={(e) => { + if (e.key === "Escape") { + const newEditFolders = editFolders.map((obj) => { + if (obj.name === item.name) { + return { name: item.name, edit: false }; + } + return { name: obj.name, edit: false }; + }); + setEditFolderName(newEditFolders); + setFoldersNames({}); + setEditFolderName( + folders.map((obj) => ({ + name: obj.name, + edit: false, + })), + ); + } + if (e.key === "Enter") { + refInput.current?.blur(); + } + handleKeyDown(e, e.key, ""); + }} + autoFocus={true} + onBlur={async () => { + const newEditFolders = editFolders.map((obj) => { + if (obj.name === item.name) { + return { name: item.name, edit: false }; + } + return { name: obj.name, edit: false }; + }); + setEditFolderName(newEditFolders); + if (foldersNames[item.name].trim() !== "") { + setFoldersNames((old) => ({ + ...old, + [item.name]: foldersNames[item.name], + })); + const body = { + ...item, + name: foldersNames[item.name], + flows: item.flows?.length > 0 ? item.flows : [], + components: + item.components?.length > 0 + ? item.components + : [], + }; + const updatedFolder = await updateFolder( + body, + item.id!, + ); + const updateFolders = folders.filter( + (f) => f.name !== item.name, + ); + setFolders([...updateFolders, updatedFolder]); + setFoldersNames({}); + setEditFolderName( + folders.map((obj) => ({ + name: obj.name, + edit: false, + })), + ); + } else { + setFoldersNames((old) => ({ + ...old, + [item.name]: item.name, + })); + } + }} + value={foldersNames[item.name]} + id={`input-folder-${item.name}`} + /> +
+ ) : ( + + {item.name} + + )} +
+ {index > 0 && ( + + )} + {/* {index > 0 && ( + + )} */} - )} - +
-
- ))} + ); + })}
diff --git a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx index ce0ad3614..141dcb110 100644 --- a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx +++ b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx @@ -7,13 +7,16 @@ import { uploadFlowsFromFolders } from "../../../pages/MainPage/services"; import useAlertStore from "../../../stores/alertStore"; import useFlowsManagerStore from "../../../stores/flowsManagerStore"; import { useFolderStore } from "../../../stores/foldersStore"; -import { FlowType } from "../../../types/flow"; +import { addVersionToDuplicates } from "../../../utils/reactflowUtils"; const useFileDrop = (folderId, folderChangeCallback) => { const setFolderDragging = useFolderStore((state) => state.setFolderDragging); + const setFolderIdDragging = useFolderStore( + (state) => state.setFolderIdDragging, + ); + const setErrorData = useAlertStore((state) => state.setErrorData); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); - const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows); const flows = useFlowsManagerStore((state) => state.flows); const triggerFolderChange = (folderId) => { @@ -42,12 +45,14 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, + folderId: string, ) => { e.preventDefault(); if (e.dataTransfer.types.some((types) => types === "Files")) { setFolderDragging(true); } + setFolderIdDragging(folderId); }; const dragEnter = ( @@ -55,10 +60,12 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, + folderId: string, ) => { if (e.dataTransfer.types.some((types) => types === "Files")) { setFolderDragging(true); } + setFolderIdDragging(folderId); e.preventDefault(); }; @@ -71,6 +78,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { e.preventDefault(); if (e.target === e.currentTarget) { setFolderDragging(false); + setFolderIdDragging(""); } }; @@ -92,7 +100,6 @@ const useFileDrop = (folderId, folderChangeCallback) => { e.preventDefault(); handleFileDrop(e); - setFolderDragging(false); }; const uploadFromDragCard = (flowId, folderId) => { @@ -101,11 +108,15 @@ const useFileDrop = (folderId, folderChangeCallback) => { if (!selectedFlow) { throw new Error("Flow not found"); } + const updatedFlow = { ...selectedFlow, folder_id: folderId }; + + const newName = addVersionToDuplicates(updatedFlow, flows); + + updatedFlow.name = newName; + + setFolderDragging(false); + setFolderIdDragging(""); - const updatedFlow: FlowType = { - ...selectedFlow, - folder_id: folderId, - }; updateFlowInDatabase(updatedFlow).then(() => { getFoldersApi(true); triggerFolderChange(folderId); @@ -115,11 +126,11 @@ const useFileDrop = (folderId, folderChangeCallback) => { const uploadFormData = (data) => { const formData = new FormData(); formData.append("file", data); - + setFolderDragging(false); + setFolderIdDragging(""); uploadFlowsFromFolders(formData).then(() => { getFoldersApi(true); triggerFolderChange(folderId); - refreshFlows(); }); }; diff --git a/src/frontend/src/components/sidebarComponent/index.tsx b/src/frontend/src/components/sidebarComponent/index.tsx index 63fec9661..396373705 100644 --- a/src/frontend/src/components/sidebarComponent/index.tsx +++ b/src/frontend/src/components/sidebarComponent/index.tsx @@ -5,6 +5,9 @@ import { cn } from "../../utils/utils"; import HorizontalScrollFadeComponent from "../horizontalScrollFadeComponent"; import SideBarButtonsComponent from "./components/sideBarButtons"; import SideBarFoldersButtonsComponent from "./components/sideBarFolderButtons"; +import { addFolder } from "../../pages/MainPage/services"; +import { useNavigate } from "react-router-dom"; +import useFlowStore from "../../stores/flowStore"; type SidebarNavProps = { items: { @@ -22,7 +25,6 @@ type SidebarNavProps = { export default function SidebarNav({ className, items, - handleOpenNewFolderModal, handleChangeFolder, handleEditFolder, handleDeleteFolder, @@ -39,11 +41,7 @@ export default function SidebarNav({ return (