Merge branch 'db' of github.com:logspace-ai/langflow into db

This commit is contained in:
Lucas Oliveira 2023-06-15 15:24:45 -03:00
commit 6275f904bc
9 changed files with 84 additions and 73 deletions

View file

@ -109,7 +109,7 @@ async def stream_build(flow_id: str):
chat_manager.set_cache(flow_id, graph.build())
except Exception as exc:
logger.error("Error while building the flow: %s", exc)
yield f"data: {json.dumps({'error': str(exc)})}\n\n"
yield f"error: {json.dumps({'error': str(exc)})}\n\n"
finally:
yield f"data: {final_response}\n\n"

View file

@ -49,7 +49,7 @@ def read_flow(*, session: Session = Depends(get_session), flow_id: UUID):
raise HTTPException(status_code=404, detail="Flow not found")
@router.patch("/{flow_id}", response_model=FlowReadWithStyle, status_code=200)
@router.patch("/{flow_id}", response_model=FlowRead, status_code=200)
def update_flow(
*, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate
):

View file

@ -1,14 +1,11 @@
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
import Tooltip from "../../../../components/TooltipComponent";
import {
classNames,
groupByFamily,
isValidConnection,
toFirstUpperCase,
} from "../../../../utils";
import { useContext, useEffect, useRef, useState } from "react";
import InputComponent from "../../../../components/inputComponent";
import ToggleComponent from "../../../../components/toggleComponent";
import InputListComponent from "../../../../components/inputListComponent";
import TextAreaComponent from "../../../../components/textAreaComponent";
import { typesContext } from "../../../../contexts/typesContext";
@ -43,6 +40,7 @@ export default function ParameterComponent({
const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0);
const { closePopUp } = useContext(PopUpContext);
const { setTabsState, tabId } = useContext(TabsContext);
useEffect(() => {
if (ref.current && ref.current.offsetTop && ref.current.clientHeight) {
@ -66,6 +64,19 @@ export default function ParameterComponent({
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
const [myData, setMyData] = useState(useContext(typesContext).data);
const handleOnNewValue = (newValue: any) => {
data.node.template[name].value = newValue;
// Set state to pending
setTabsState((prev) => {
return {
...prev,
[tabId]: {
isPending: true,
},
};
});
};
useEffect(() => {
const groupedObj = groupByFamily(myData, tooltipTitle);
@ -165,17 +176,13 @@ export default function ParameterComponent({
? [""]
: data.node.template[name].value
}
onChange={(t: string[]) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
) : data.node.template[name].multiline ? (
<TextAreaComponent
disabled={disabled}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
) : (
<InputComponent
@ -183,9 +190,7 @@ export default function ParameterComponent({
disableCopyPaste={true}
password={data.node.template[name].password ?? false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
)}
</div>
@ -195,7 +200,7 @@ export default function ParameterComponent({
disabled={disabled}
enabled={enabled}
setEnabled={(t) => {
data.node.template[name].value = t;
handleOnNewValue(t);
setEnabled(t);
}}
size="large"
@ -207,9 +212,7 @@ export default function ParameterComponent({
disabled={disabled}
disableCopyPaste={true}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
</div>
) : left === true &&
@ -218,9 +221,7 @@ export default function ParameterComponent({
<div className="w-full">
<Dropdown
options={data.node.template[name].options}
onSelect={(newValue) =>
(data.node.template[name].value = newValue)
}
onSelect={handleOnNewValue}
value={data.node.template[name].value ?? "Choose an option"}
></Dropdown>
</div>
@ -228,17 +229,13 @@ export default function ParameterComponent({
<CodeAreaComponent
disabled={disabled}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
) : left === true && type === "file" ? (
<InputFileComponent
disabled={disabled}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
fileTypes={data.node.template[name].fileTypes}
suffixes={data.node.template[name].suffixes}
onFileChange={(t: string) => {
@ -251,18 +248,14 @@ export default function ParameterComponent({
disabled={disabled}
disableCopyPaste={true}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
</div>
) : left === true && type === "prompt" ? (
<PromptAreaComponent
disabled={disabled}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
}}
onChange={handleOnNewValue}
/>
) : (
<></>

View file

@ -7,7 +7,7 @@ import {
useContext,
} from "react";
import { FlowType, NodeType } from "../types/flow";
import { TabsContextType } from "../types/tabs";
import { TabsContextType, TabsState } from "../types/tabs";
import { updateIds, updateTemplate } from "../utils";
import { alertContext } from "./alertContext";
import { typesContext } from "./typesContext";
@ -43,7 +43,8 @@ const TabsContextInitialValue: TabsContextType = {
setDisableCopyPaste: (state: boolean) => {},
lastCopiedSelection: null,
setLastCopiedSelection: (selection: any) => {},
tabsState: {},
setTabsState: (state: TabsState) => {},
getNodeId: (nodeType: string) => "",
paste: (
selection: { nodes: any; edges: any },
@ -64,6 +65,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
const [id, setId] = useState(uid());
const { templates, reactFlowInstance } = useContext(typesContext);
const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
const [tabsState, setTabsState] = useState<TabsState>({});
const newNodeId = useRef(uid());
function incrementNodeId() {
@ -534,6 +536,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
description: flowData.description,
name: flow?.name ?? "New Flow",
data: flowData.data,
id: "",
});
const addFlowToLocalState = (newFlow) => {
@ -582,6 +585,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
uploadFlows,
uploadFlow,
getNodeId,
tabsState,
setTabsState,
paste,
}}
>

View file

@ -111,7 +111,9 @@ export async function saveFlowToDatabase(newFlow: {
* @returns {Promise<any>} The updated flow data.
* @throws Will throw an error if the update fails.
*/
export async function updateFlowInDatabase(updatedFlow: FlowType) {
export async function updateFlowInDatabase(
updatedFlow: FlowType
): Promise<FlowType> {
try {
const response = await axios.patch(`/api/v1/flows/${updatedFlow.id}`, {
name: updatedFlow.name,

View file

@ -1,9 +1,9 @@
import { Dialog, Transition } from "@headlessui/react";
import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline";
import { Fragment, useContext, useEffect, useRef, useState } from "react";
import { FlowType, NodeType } from "../../types/flow";
import { FlowType } from "../../types/flow";
import { alertContext } from "../../contexts/alertContext";
import { toNormalCase, validateNodes } from "../../utils";
import { validateNodes } from "../../utils";
import { typesContext } from "../../contexts/typesContext";
import ChatMessage from "./chatMessage";
import { FaEraser } from "react-icons/fa";
@ -174,16 +174,6 @@ export default function ChatModal({
updateLastMessage({ str: data.message });
}
}
function getWebSocketUrl(chatId, isDevelopment = false) {
const isSecureProtocol = window.location.protocol === "https:";
const webSocketProtocol = isSecureProtocol ? "wss" : "ws";
const host = isDevelopment ? "localhost:7860" : window.location.host;
const chatEndpoint = `/api/v1/chat/${chatId}`;
return `${
isDevelopment ? "ws" : webSocketProtocol
}://${host}${chatEndpoint}`;
}
function connectWS() {
try {

View file

@ -1,4 +1,3 @@
import { ArrowDownTrayIcon } from "@heroicons/react/24/outline";
import { useContext, useRef, useState } from "react";
import { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext";
@ -14,16 +13,16 @@ import {
} from "../../components/ui/dialog";
import { Button } from "../../components/ui/button";
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants";
import { updateFlowInDatabase } from "../../controllers/API";
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
import { Settings2 } from "lucide-react";
import { updateFlowInDatabase } from "../../controllers/API";
export default function FlowSettingsModal() {
const [open, setOpen] = useState(true);
const { closePopUp } = useContext(PopUpContext);
const { setErrorData, setSuccessData } = useContext(alertContext);
const ref = useRef();
const { flows, tabId, updateFlow } = useContext(TabsContext);
const { flows, tabId, updateFlow, setTabsState } = useContext(TabsContext);
const maxLength = 50;
function setModalOpen(x: boolean) {
setOpen(x);
@ -34,22 +33,26 @@ export default function FlowSettingsModal() {
}
}
function handleSaveFlow(flow) {
if (name !== "") {
let newFlow = flows.find((f) => f.id === tabId);
if (newFlow) {
newFlow.name = name;
newFlow.description = description;
updateFlow(newFlow);
}
}
async function handleSaveFlow(flow) {
try {
updateFlowInDatabase(flow);
const updatedFlow = await updateFlowInDatabase(flow);
if (updatedFlow) {
updateFlow(updatedFlow);
setTabsState((prev) => {
return {
...prev,
[tabId]: {
isPending: false,
},
};
});
}
// updateFlowStyleInDataBase(flow);
} catch (err) {
setErrorData(err);
}
}
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
const [description, setDescription] = useState(
flows.find((f) => f.id === tabId).description

View file

@ -13,24 +13,23 @@ import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import ShadTooltip from "../../../../components/ShadTooltipComponent";
import { Code2, FileDown, FileUp, Save } from "lucide-react";
import { PopUpContext } from "../../../../contexts/popUpContext";
import ImportModal from "../../../../modals/importModal";
import ExportModal from "../../../../modals/exportModal";
import ApiModal from "../../../../modals/ApiModal";
import { TabsContext } from "../../../../contexts/tabsContext";
import { alertContext } from "../../../../contexts/alertContext";
import { updateFlowInDatabase } from "../../../../controllers/API";
import { INPUT_STYLE } from "../../../../constants";
import { Input } from "../../../../components/ui/input";
import { Separator } from "../../../../components/ui/separator";
export default function ExtraSidebar() {
const { data } = useContext(typesContext);
const { openPopUp } = useContext(PopUpContext);
const { flows, tabId, uploadFlow } = useContext(TabsContext);
const { flows, tabId, uploadFlow, updateFlow, tabsState, setTabsState } =
useContext(TabsContext);
const { setSuccessData, setErrorData } = useContext(alertContext);
const [dataFilter, setFilterData] = useState(data);
const [search, setSearch] = useState("");
const isPending = tabsState[tabId]?.isPending;
function onDragStart(
event: React.DragEvent<any>,
data: { type: string; node?: APIClassType }
@ -62,9 +61,21 @@ export default function ExtraSidebar() {
});
}
function handleSaveFlow(flow) {
async function handleSaveFlow(flow) {
try {
updateFlowInDatabase(flow);
const updatedFlow = await updateFlowInDatabase(flow);
if (updatedFlow) {
updateFlow(updatedFlow);
setTabsState((prev) => {
console.log(prev);
return {
...prev,
[tabId]: {
isPending: false,
},
};
});
}
// updateFlowStyleInDataBase(flow);
} catch (err) {
setErrorData(err);
@ -118,8 +129,13 @@ export default function ExtraSidebar() {
handleSaveFlow(flows.find((f) => f.id === tabId));
setSuccessData({ title: "Changes saved successfully" });
}}
disabled={!isPending}
>
<Save className="w-5 h-5 dark:text-gray-300"></Save>
<Save
className={
"w-5 h-5" + (isPending ? " text-muted-foreground" : " ")
}
></Save>
</button>
</ShadTooltip>
</div>

View file

@ -1,3 +1,4 @@
import { Dispatch, SetStateAction } from "react";
import { FlowType } from "../flow";
export type TabsContextType = {
@ -18,6 +19,8 @@ export type TabsContextType = {
disableCopyPaste: boolean;
setDisableCopyPaste: (value: boolean) => void;
getNodeId: (nodeType: string) => string;
tabsState: TabsState;
setTabsState: Dispatch<SetStateAction<TabsState>>;
paste: (
selection: { nodes: any; edges: any },
position: { x: number; y: number; paneX?: number; paneY?: number }
@ -26,9 +29,8 @@ export type TabsContextType = {
setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void;
};
export type LangFlowState = {
tabIndex: number;
flows: FlowType[];
id: string;
nodeId: number;
export type TabsState = {
[key: string]: {
isPending: boolean;
};
};