From dfb09f3b07e4b6ff831550f20e34683e24e23348 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 9 Sep 2025 17:07:35 -0300 Subject: [PATCH] Implement flow validation settings and enhance ingestion configuration UI This commit adds state management for flow validation and ingestion settings in the KnowledgeSourcesPage component. It introduces new state variables to handle flow validation data and ingestion settings, including chunk size, chunk overlap, separator, and embedding model. The fetchSettings function is updated to prevent multiple calls and to set ingestion settings based on available UI settings from the backend. Additionally, the UI is enhanced to display and modify these settings dynamically, improving user experience and configurability. --- frontend/src/app/settings/page.tsx | 239 +++++++++++++++++++++++++++-- 1 file changed, 225 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/settings/page.tsx b/frontend/src/app/settings/page.tsx index e7250394..f2d1f0a1 100644 --- a/frontend/src/app/settings/page.tsx +++ b/frontend/src/app/settings/page.tsx @@ -52,11 +52,11 @@ interface Connector { } interface SyncResult { - processed?: number; - added?: number; - errors?: number; - skipped?: number; - total?: number; + processed?: number; + added?: number; + errors?: number; + skipped?: number; + total?: number; } interface Connection { @@ -90,12 +90,24 @@ function KnowledgeSourcesPage() { "5488df7c-b93f-4f87-a446-b67028bc0813", ); const [langflowEditUrl, setLangflowEditUrl] = useState(""); - const [langflowIngestEditUrl, setLangflowIngestEditUrl] = useState(""); + const [langflowIngestEditUrl, setLangflowIngestEditUrl] = + useState(""); const [publicLangflowUrl, setPublicLangflowUrl] = useState(""); + // Flow validation and ingestion settings state + const [flowValidation, setFlowValidation] = useState(null); + const [settingsLoaded, setSettingsLoaded] = useState(false); + const [ingestionSettings, setIngestionSettings] = useState({ + chunkSize: 1000, + chunkOverlap: 200, + separator: "\\n", + embeddingModel: "text-embedding-3-small", + }); // Fetch settings from backend const fetchSettings = useCallback(async () => { + if (settingsLoaded) return; // Prevent multiple calls + try { const response = await fetch("/api/settings"); if (response.ok) { @@ -115,11 +127,56 @@ function KnowledgeSourcesPage() { if (settings.langflow_public_url) { setPublicLangflowUrl(settings.langflow_public_url); } + + // Handle flow validation data + if (settings.flow_validation) { + setFlowValidation(settings.flow_validation); + + // Update ingestion settings with flow defaults + const availableSettings = + settings.flow_validation.available_ui_settings || {}; + + const newSettings = { ...ingestionSettings }; + + if ( + availableSettings.chunkSize?.available && + availableSettings.chunkSize.param_info?.value + ) { + newSettings.chunkSize = + availableSettings.chunkSize.param_info.value; + } + if ( + availableSettings.chunkOverlap?.available && + availableSettings.chunkOverlap.param_info?.value + ) { + newSettings.chunkOverlap = + availableSettings.chunkOverlap.param_info.value; + } + if ( + availableSettings.separator?.available && + availableSettings.separator.param_info?.value + ) { + newSettings.separator = + availableSettings.separator.param_info.value; + } + if ( + availableSettings.embeddingModel?.available && + availableSettings.embeddingModel.param_info?.value + ) { + newSettings.embeddingModel = + availableSettings.embeddingModel.param_info.value; + } + + setIngestionSettings(newSettings); + } + + setSettingsLoaded(true); } } catch (error) { console.error("Failed to fetch settings:", error); + setSettingsLoaded(true); } - }, []); + }, [settingsLoaded]); // Helper function to get connector icon const getConnectorIcon = (iconName: string) => { @@ -393,11 +450,15 @@ function KnowledgeSourcesPage() { } }, [tasks, prevTasks]); - const handleEditInLangflow = (flowType: "chat" | "ingest", closeDialog: () => void) => { + const handleEditInLangflow = ( + flowType: "chat" | "ingest", + closeDialog: () => void, + ) => { // Select the appropriate flow ID and edit URL based on flow type const targetFlowId = flowType === "ingest" ? ingestFlowId : chatFlowId; - const editUrl = flowType === "ingest" ? langflowIngestEditUrl : langflowEditUrl; - + const editUrl = + flowType === "ingest" ? langflowIngestEditUrl : langflowEditUrl; + const derivedFromWindow = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:7860` @@ -408,9 +469,9 @@ function KnowledgeSourcesPage() { "http://localhost:7860" ).replace(/\/$/, ""); const computed = targetFlowId ? `${base}/flow/${targetFlowId}` : base; - + const url = editUrl || computed; - + window.open(url, "_blank"); closeDialog(); // Close immediately after opening Langflow }; @@ -421,6 +482,10 @@ function KnowledgeSourcesPage() { }) .then((response) => response.json()) .then(() => { + // Reload settings after successful restore + setSettingsLoaded(false); + setFlowValidation(null); + fetchSettings(); closeDialog(); // Close after successful completion }) .catch((error) => { @@ -435,6 +500,10 @@ function KnowledgeSourcesPage() { }) .then((response) => response.json()) .then(() => { + // Reload settings after successful restore + setSettingsLoaded(false); + setFlowValidation(null); + fetchSettings(); closeDialog(); // Close after successful completion }) .catch((error) => { @@ -493,7 +562,9 @@ function KnowledgeSourcesPage() { title="Edit Ingest flow in Langflow" description="You're entering Langflow. You can edit the Ingest flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience." confirmText="Proceed" - onConfirm={(closeDialog) => handleEditInLangflow("ingest", closeDialog)} + onConfirm={(closeDialog) => + handleEditInLangflow("ingest", closeDialog) + } /> @@ -539,6 +610,144 @@ function KnowledgeSourcesPage() { */} + {flowValidation && + Object.keys(flowValidation.available_ui_settings || {}).some( + (key) => flowValidation.available_ui_settings[key]?.available, + ) && ( + +
+ {flowValidation.available_ui_settings?.chunkSize?.available && ( +
+ +
+ {flowValidation.available_ui_settings.chunkSize.param_info + ?.info || "Maximum length of each text chunk"} +
+ + setIngestionSettings((prev) => ({ + ...prev, + chunkSize: parseInt(e.target.value) || 1000, + })) + } + className="max-w-32" + min="100" + max="8000" + /> +
+ )} + + {flowValidation.available_ui_settings?.chunkOverlap + ?.available && ( +
+ +
+ {flowValidation.available_ui_settings.chunkOverlap + .param_info?.info || + "Number of characters to overlap between chunks"} +
+ + setIngestionSettings((prev) => ({ + ...prev, + chunkOverlap: parseInt(e.target.value) || 200, + })) + } + className="max-w-32" + min="0" + max="1000" + /> +
+ )} + + {flowValidation.available_ui_settings?.separator?.available && ( +
+ +
+ {flowValidation.available_ui_settings.separator.param_info + ?.info || "Character(s) to split text on"} +
+ + setIngestionSettings((prev) => ({ + ...prev, + separator: e.target.value, + })) + } + className="max-w-48" + placeholder="\\n" + /> +
+ )} + + {flowValidation.available_ui_settings?.embeddingModel + ?.available && ( +
+ +
+ {flowValidation.available_ui_settings.embeddingModel + .param_info?.info || "OpenAI embedding model to use"} +
+ +
+ )} +
+
+ )} {/* Agent Behavior Section */} @@ -589,7 +798,9 @@ function KnowledgeSourcesPage() { title="Edit Agent flow in Langflow" description="You're entering Langflow. You can edit the Agent flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience." confirmText="Proceed" - onConfirm={(closeDialog) => handleEditInLangflow("chat", closeDialog)} + onConfirm={(closeDialog) => + handleEditInLangflow("chat", closeDialog) + } />