Comments (5)
To fix the KeyError
when uploading a file to a folder due to the recent commit that made each flow have a default folder name, you need to ensure that the folder_name
and folder_description
keys are present in the uploaded data. Additionally, you can use the utility function create_default_folder_if_it_doesnt_exist
to handle the creation of a default folder if it doesn't exist.
Here is the relevant part of the code that handles the upload:
@router.post("/upload/", response_model=List[FlowRead], status_code=201)
async def upload_file(
*,
session: Session = Depends(get_session),
file: UploadFile = File(...),
current_user: User = Depends(get_current_active_user),
):
"""Upload flows from a file."""
contents = await file.read()
data = orjson.loads(contents)
if not data:
raise HTTPException(status_code=400, detail="No flows found in the file")
if "folder_name" not in data or "folder_description" not in data:
raise HTTPException(status_code=400, detail="Missing folder_name or folder_description in the data")
folder_results = session.exec(
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:
data["folder_name"] = f"{data['folder_name']} ({len(existing_folder_names) + 1})"
folder = FolderCreate(name=data["folder_name"], description=data["folder_description"])
new_folder = Folder.model_validate(folder, from_attributes=True)
new_folder.id = None
new_folder.user_id = current_user.id
session.add(new_folder)
session.commit()
session.refresh(new_folder)
del data["folder_name"]
del data["folder_description"]
if "flows" in data:
flow_list = FlowListCreate(flows=[FlowCreate(**flow) for flow in data["flows"]])
else:
raise HTTPException(status_code=400, detail="No flows found in the data")
# Now we set the user_id for all flows
for flow in flow_list.flows:
flow.user_id = current_user.id
flow.folder_id = new_folder.id
return create_flows(session=session, flow_list=flow_list, current_user=current_user)
Additionally, you can use the create_default_folder_if_it_doesnt_exist
function to ensure a default folder is created if it doesn't exist:
def create_default_folder_if_it_doesnt_exist(session: Session, user_id: UUID):
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) # type: ignore
.where(
and_(
Flow.folder_id == None, # type: ignore # noqa
Flow.user_id == user_id,
)
)
.values(folder_id=folder.id)
)
session.commit()
return folder
This ensures that the necessary keys are present and prevents the KeyError
, while also handling the creation of a default folder if needed [1][2].
Additionally, you can refer to the uploadFlowsFromFolders
function in the frontend service to ensure the correct API endpoint and data format are used when uploading flows:
export async function uploadFlowsFromFolders(
flows: FormData
): Promise<FlowType[]> {
try {
const response = await api.post(`${BASE_URL_API}folders/upload/`, flows);
if (response?.status !== 201) {
throw new Error(`HTTP error! status: ${response?.status}`);
}
return response.data;
} catch (error) {
console.error(error);
throw error;
}
}
This function handles the API call to upload flows to the server, ensuring that the data is correctly formatted and the appropriate endpoint is used [3].
Furthermore, the useFolderStore
in the frontend ensures that folders are managed correctly, including handling the default folder and starter projects:
import { create } from "zustand";
import { DEFAULT_FOLDER, STARTER_FOLDER_NAME } from "../constants/constants";
import {
getFolderById,
getFolders,
uploadFlowsFromFolders,
} from "../pages/MainPage/services";
import { FoldersStoreType } from "../types/zustand/folders";
import useFlowsManagerStore from "./flowsManagerStore";
export const useFolderStore = create<FoldersStoreType>((set, get) => ({
folders: [],
getFoldersApi: (refetch = false) => {
return new Promise<void>((resolve, reject) => {
if (get()?.folders.length === 0 || refetch === true) {
get().setLoading(true);
getFolders().then(
(res) => {
const foldersWithoutStarterProjects = res.filter(
(folder) => folder.name !== STARTER_FOLDER_NAME,
);
const starterProjects = res.find(
(folder) => folder.name === STARTER_FOLDER_NAME,
);
set({ starterProjectId: starterProjects!.id ?? "" });
set({ folders: foldersWithoutStarterProjects });
const myCollectionId = res?.find(
(f) => f.name === DEFAULT_FOLDER,
)?.id;
set({ myCollectionId });
if (refetch === true) {
useFlowsManagerStore.getState().refreshFlows();
useFlowsManagerStore.getState().setAllFlows;
}
get().setLoading(false);
resolve();
},
() => {
set({ folders: [] });
get().setLoading(false);
reject();
},
);
}
});
},
setFolders: (folders) => set(() => ({ folders: folders })),
loading: false,
setLoading: (loading) => set(() => ({ loading: loading })),
getFolderById: (id) => {
get().setLoadingById(true);
if (id) {
getFolderById(id).then(
(res) => {
const setAllFlows = useFlowsManagerStore.getState().setAllFlows;
setAllFlows(res.flows);
set({ selectedFolder: res });
get().setLoadingById(false);
},
() => {
get().setLoadingById(false);
},
);
}
},
selectedFolder: null,
loadingById: false,
setLoadingById: (loading) => set(() => ({ loadingById: loading })),
getMyCollectionFolder: () => {
const folders = get().folders;
const myCollectionId = folders?.find((f) => f.name === DEFAULT_FOLDER)?.id;
if (myCollectionId) {
getFolderById(myCollectionId).then((res) => {
set({ myCollectionFlows: res });
});
}
},
setMyCollectionFlow: (folder) => set(() => ({ myCollectionFlows: folder })),
myCollectionFlows: null,
setMyCollectionId: () => {
const folders = get().folders;
const myCollectionId = folders?.find((f) => f.name === DEFAULT_FOLDER)?.id;
if (myCollectionId) {
set({ myCollectionId });
}
},
myCollectionId: "",
folderToEdit: null,
setFolderToEdit: (folder) => set(() => ({ folderToEdit: folder })),
folderUrl: "",
setFolderUrl: (url) => set(() => ({ folderUrl: url })),
folderDragging: false,
setFolderDragging: (folder) => set(() => ({ folderDragging: folder })),
folderIdDragging: "",
setFolderIdDragging: (id) => set(() => ({ folderIdDragging: id })),
uploadFolder: () => {
return new Promise<void>(() => {
const input = document.createElement("input");
input.type = "file";
input.onchange = (event: Event) => {
if (
(event.target as HTMLInputElement).files![0].type ===
"application/json"
) {
const file = (event.target as HTMLInputElement).files![0];
const formData = new FormData();
formData.append("file", file);
uploadFlowsFromFolders(formData).then(() => {
get().getFoldersApi(true);
});
}
};
input.click();
});
},
starterProjectId: "",
setStarterProjectId: (id) => set(() => ({ starterProjectId: id })),
}));
This ensures that the frontend correctly handles folder management, including the creation and uploading of flows to the appropriate folders [4].
Details
About Dosu
This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.
Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.
To continue the conversation, mention @dosu.
from langflow.
To address your concerns and provide a solution for directly uploading a Flow, you can implement a direct "upload flow" option that allows for the Name and Description of the Flow to be updated accordingly.
Backend: Add an Endpoint for Uploading a Single Flow
You can add a new endpoint to handle the upload of a single flow. This endpoint will ensure that the Name and Description are included in the uploaded data:
@router.post("/upload_flow/", response_model=FlowRead, status_code=201)
async def upload_single_flow(
*,
session: Session = Depends(get_session),
file: UploadFile = File(...),
current_user: User = Depends(get_current_active_user),
):
"""Upload a single flow from a file."""
contents = await file.read()
data = orjson.loads(contents)
if not data:
raise HTTPException(status_code=400, detail="No flow found in the file")
if "name" not in data or "description" not in data:
raise HTTPException(status_code=400, detail="Missing name or description in the data")
flow = FlowCreate(name=data["name"], description=data["description"], user_id=current_user.id)
new_flow = Flow.model_validate(flow, from_attributes=True)
new_flow.id = None
session.add(new_flow)
session.commit()
session.refresh(new_flow)
return new_flow
Frontend: Add a Function to Handle the Upload of a Single Flow
Next, you can add a function in the frontend to handle the API call for uploading a single flow:
export async function uploadSingleFlow(flow: FormData): Promise<FlowType> {
try {
const response = await api.post(`${BASE_URL_API}upload_flow/`, flow);
if (response?.status !== 201) {
throw new Error(`HTTP error! status: ${response?.status}`);
}
return response.data;
} catch (error) {
console.error(error);
throw error;
}
}
Frontend: Add a Button and Handler for Uploading a Single Flow
Finally, you can add a button and handler in your frontend to allow users to upload a single flow directly:
import React from 'react';
import { uploadSingleFlow } from '../services';
const UploadFlowButton = () => {
const handleUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file && file.type === "application/json") {
const formData = new FormData();
formData.append("file", file);
try {
const uploadedFlow = await uploadSingleFlow(formData);
console.log("Uploaded Flow:", uploadedFlow);
} catch (error) {
console.error("Error uploading flow:", error);
}
}
};
return (
<input type="file" accept="application/json" onChange={handleUpload} />
);
};
export default UploadFlowButton;
This setup allows you to upload a single flow directly, ensuring that the Name and Description are updated as specified in the uploaded JSON file. This should streamline the process and avoid the need to create a blank project first.
To continue talking to Dosu, mention @dosu.
from langflow.
I see. The upload button on the main page is specifically for uploading folders, not flows.
Perhaps just a quick json validation check is enough to avoid confusion here
from langflow.
Is there a way to upload a Flow directly? I've been creating a blank project, then importing, but that doesn't update the Name or Description of the Flow. Can we have a direct "upload flow" option?
from langflow.
@jordanrfrazier to import a specific flow you need to create a new blank one, from the dropdown click "Import" and pass it the JSON file.
The "upload" button in the main page is for folders (I've sent this improvement #2125)
from langflow.
Related Issues (20)
- Faiss search error HOT 2
- The outout of the Chat Input is not been recognized as text by OpenAI model HOT 4
- Error Building Component Error building Component Astra DB: {"errors":[{"message":"Request invalid: field 'command.name' value \"english-test\" not valid. Problem: must match \"[a-zA-Z][a-zA-Z0-9_]*\".","errorCode":"COMMAND_FIELD_INVALID"}]} HOT 1
- ValidationError: 2 validation errors for HumanMessage at v1.0.0a59 HOT 4
- Encountering error in building ASTRA DB Search node in the canvas. Error Building Component Error building Component Astra DB Search: Invalid inputs provided. HOT 4
- API Request ERROR HOT 3
- [Feature Request]: Allow local cassandra connections
- idea
- [Request] Please add openrouter as LLM Model
- Nested chats HOT 1
- Module langflow.inputs not found HOT 1
- CommandError: Multiple head revisions are present for given argument 'head'; please specify a specific target revision, '<branchname>@head' to narrow to a specific head, or 'heads' for all heads HOT 3
- Questions about Run Flow HOT 3
- An error was thrown while using the groq component HOT 3
- Question: Hugging Face API HOT 1
- Issue with Chat Input component HOT 7
- Question: Inquiry on Session Management and Parameter Passing in Langflow API HOT 3
- Langflow Store Suspension HOT 1
- Documentation to use Flow as Tool HOT 3
- Method not Allowed on API HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from langflow.