Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
Lucas Oliveira
201dd54019 Added nudges restore and edit to settings 2025-09-11 15:05:54 -03:00
Lucas Oliveira
6052e7c55d Adjusted nudges var name, added nudges flow link to settings 2025-09-11 15:05:49 -03:00
9 changed files with 169 additions and 55 deletions

View file

@ -8,7 +8,7 @@ LANGFLOW_SECRET_KEY=
# flow ids for chat and ingestion flows
LANGFLOW_CHAT_FLOW_ID=1098eea1-6649-4e1d-aed1-b77249fb8dd0
LANGFLOW_INGEST_FLOW_ID=5488df7c-b93f-4f87-a446-b67028bc0813
NUDGES_FLOW_ID=ebc01d31-1976-46ce-a385-b0240327226c
LANGFLOW_NUDGES_FLOW_ID=ebc01d31-1976-46ce-a385-b0240327226c
# Set a strong admin password for OpenSearch; a bcrypt hash is generated at
# container startup from this value. Do not commit real secrets.

View file

@ -56,7 +56,7 @@ services:
- LANGFLOW_CHAT_FLOW_ID=${LANGFLOW_CHAT_FLOW_ID}
- LANGFLOW_INGEST_FLOW_ID=${LANGFLOW_INGEST_FLOW_ID}
- DISABLE_INGEST_WITH_LANGFLOW=${DISABLE_INGEST_WITH_LANGFLOW:-false}
- NUDGES_FLOW_ID=${NUDGES_FLOW_ID}
- LANGFLOW_NUDGES_FLOW_ID=${LANGFLOW_NUDGES_FLOW_ID}
- OPENSEARCH_PORT=9200
- OPENSEARCH_USERNAME=admin
- OPENSEARCH_PASSWORD=${OPENSEARCH_PASSWORD}

View file

@ -55,7 +55,7 @@ services:
- LANGFLOW_CHAT_FLOW_ID=${LANGFLOW_CHAT_FLOW_ID}
- LANGFLOW_INGEST_FLOW_ID=${LANGFLOW_INGEST_FLOW_ID}
- DISABLE_INGEST_WITH_LANGFLOW=${DISABLE_INGEST_WITH_LANGFLOW:-false}
- NUDGES_FLOW_ID=${NUDGES_FLOW_ID}
- LANGFLOW_NUDGES_FLOW_ID=${LANGFLOW_NUDGES_FLOW_ID}
- OPENSEARCH_PORT=9200
- OPENSEARCH_USERNAME=admin
- OPENSEARCH_PASSWORD=${OPENSEARCH_PASSWORD}

View file

@ -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 {
@ -66,6 +66,34 @@ interface Connection {
last_sync?: string;
}
// Helper function to get connector icon (moved outside component to avoid re-renders)
const getConnectorIcon = (iconName: string) => {
const iconMap: { [key: string]: React.ReactElement } = {
"google-drive": (
<div className="w-8 h-8 bg-blue-600 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
G
</div>
),
sharepoint: (
<div className="w-8 h-8 bg-blue-700 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
SP
</div>
),
onedrive: (
<div className="w-8 h-8 bg-blue-400 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
OD
</div>
),
};
return (
iconMap[iconName] || (
<div className="w-8 h-8 bg-gray-500 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
?
</div>
)
);
};
function KnowledgeSourcesPage() {
const { isAuthenticated, isNoAuthMode } = useAuth();
const { addTask, tasks } = useTask();
@ -89,11 +117,16 @@ function KnowledgeSourcesPage() {
const [ingestFlowId, setIngestFlowId] = useState<string>(
"5488df7c-b93f-4f87-a446-b67028bc0813",
);
const [nudgesFlowId, setNudgesFlowId] = useState<string>(
"ebc01d31-1976-46ce-a385-b0240327226c",
);
const [langflowEditUrl, setLangflowEditUrl] = useState<string>("");
const [langflowIngestEditUrl, setLangflowIngestEditUrl] = useState<string>("");
const [langflowIngestEditUrl, setLangflowIngestEditUrl] =
useState<string>("");
const [langflowNudgesEditUrl, setLangflowNudgesEditUrl] =
useState<string>("");
const [publicLangflowUrl, setPublicLangflowUrl] = useState<string>("");
// Fetch settings from backend
const fetchSettings = useCallback(async () => {
try {
@ -106,12 +139,18 @@ function KnowledgeSourcesPage() {
if (settings.ingest_flow_id) {
setIngestFlowId(settings.ingest_flow_id);
}
if (settings.langflow_nudges_flow_id) {
setNudgesFlowId(settings.langflow_nudges_flow_id);
}
if (settings.langflow_edit_url) {
setLangflowEditUrl(settings.langflow_edit_url);
}
if (settings.langflow_ingest_edit_url) {
setLangflowIngestEditUrl(settings.langflow_ingest_edit_url);
}
if (settings.langflow_nudges_edit_url) {
setLangflowNudgesEditUrl(settings.langflow_nudges_edit_url);
}
if (settings.langflow_public_url) {
setPublicLangflowUrl(settings.langflow_public_url);
}
@ -121,34 +160,6 @@ function KnowledgeSourcesPage() {
}
}, []);
// Helper function to get connector icon
const getConnectorIcon = (iconName: string) => {
const iconMap: { [key: string]: React.ReactElement } = {
"google-drive": (
<div className="w-8 h-8 bg-blue-600 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
G
</div>
),
sharepoint: (
<div className="w-8 h-8 bg-blue-700 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
SP
</div>
),
onedrive: (
<div className="w-8 h-8 bg-blue-400 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
OD
</div>
),
};
return (
iconMap[iconName] || (
<div className="w-8 h-8 bg-gray-500 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
?
</div>
)
);
};
// Connector functions
const checkConnectorStatuses = useCallback(async () => {
try {
@ -393,11 +404,25 @@ function KnowledgeSourcesPage() {
}
}, [tasks, prevTasks]);
const handleEditInLangflow = (flowType: "chat" | "ingest", closeDialog: () => void) => {
const handleEditInLangflow = (
flowType: "chat" | "ingest" | "nudges",
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;
let targetFlowId: string;
let editUrl: string;
if (flowType === "ingest") {
targetFlowId = ingestFlowId;
editUrl = langflowIngestEditUrl;
} else if (flowType === "nudges") {
targetFlowId = nudgesFlowId;
editUrl = langflowNudgesEditUrl;
} else {
targetFlowId = chatFlowId;
editUrl = langflowEditUrl;
}
const derivedFromWindow =
typeof window !== "undefined"
? `${window.location.protocol}//${window.location.hostname}:7860`
@ -408,9 +433,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
};
@ -443,6 +468,20 @@ function KnowledgeSourcesPage() {
});
};
const handleRestoreNudgesFlow = (closeDialog: () => void) => {
fetch(`/api/reset-flow/nudges`, {
method: "POST",
})
.then((response) => response.json())
.then(() => {
closeDialog(); // Close after successful completion
})
.catch((error) => {
console.error("Error restoring nudges flow:", error);
closeDialog(); // Close even on error (could show error toast instead)
});
};
return (
<div className="space-y-8">
{/* Knowledge Ingest Section */}
@ -473,7 +512,9 @@ function KnowledgeSourcesPage() {
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Edit in Langflow"
>
<title>Edit in Langflow</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
@ -493,7 +534,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)
}
/>
</div>
</div>
@ -569,7 +612,9 @@ function KnowledgeSourcesPage() {
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Edit in Langflow"
>
<title>Edit in Langflow</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
@ -589,7 +634,68 @@ 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)
}
/>
</div>
</div>
</CardHeader>
</Card>
{/* Nudges Section */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-lg">Nudges</CardTitle>
<CardDescription>
Manage prompt suggestions that appear in the chat interface
</CardDescription>
</div>
<div className="flex gap-2">
<ConfirmationDialog
trigger={<Button variant="secondary">Restore flow</Button>}
title="Restore default Nudges flow"
description="This restores defaults and discards all custom settings and overrides. This can't be undone."
confirmText="Restore"
variant="destructive"
onConfirm={handleRestoreNudgesFlow}
/>
<ConfirmationDialog
trigger={
<Button>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Edit in Langflow"
>
<title>Edit in Langflow</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
></path>
<path
fill="currentColor"
d="M19.5355 11.5862H22.8301C23.4762 11.5862 24 12.1128 24 12.7624V14.716C24 15.3656 23.4762 15.8922 22.8301 15.8922H19.957C19.6467 15.8922 19.3491 16.0161 19.1297 16.2367L14.1997 21.1934C13.9803 21.414 13.6827 21.5379 13.3725 21.5379H11.0026C10.3682 21.5379 9.84945 21.0296 9.83309 20.392L9.78189 18.3974C9.76492 17.7361 10.2935 17.1908 10.9514 17.1908H12.9918C13.302 17.1908 13.5996 17.0669 13.819 16.8463L18.7082 11.9307C18.9276 11.7101 19.2252 11.5862 19.5355 11.5862Z"
></path>
<path
fill="currentColor"
d="M19.5355 2.9796L22.8301 2.9796C23.4762 2.9796 24 3.50622 24 4.15583V6.1094C24 6.75901 23.4762 7.28563 22.8301 7.28563H19.957C19.6467 7.28563 19.3491 7.40955 19.1297 7.63014L14.1997 12.5868C13.9803 12.8074 13.6827 12.9313 13.3725 12.9313H10.493C10.1913 12.9313 9.90126 13.0485 9.68346 13.2583L4.14867 18.5917C3.93087 18.8016 3.64085 18.9187 3.33917 18.9187H1.32174C0.675616 18.9187 0.151832 18.3921 0.151832 17.7425V15.7343C0.151832 15.0846 0.675616 14.558 1.32174 14.558H3.32468C3.63496 14.558 3.93253 14.4341 4.15193 14.2135L9.40827 8.92878C9.62767 8.70819 9.92524 8.58427 10.2355 8.58427H12.9918C13.302 8.58427 13.5996 8.46034 13.819 8.23976L18.7082 3.32411C18.9276 3.10353 19.2252 2.9796 19.5355 2.9796Z"
></path>
</svg>
Edit in Langflow
</Button>
}
title="Edit Nudges flow in Langflow"
description="You're entering Langflow. You can edit the Nudges flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience."
confirmText="Proceed"
onConfirm={(closeDialog) =>
handleEditInLangflow("nudges", closeDialog)
}
/>
</div>
</div>

View file

@ -5,6 +5,7 @@ from config.settings import (
LANGFLOW_CHAT_FLOW_ID,
LANGFLOW_INGEST_FLOW_ID,
LANGFLOW_PUBLIC_URL,
LANGFLOW_NUDGES_FLOW_ID,
clients,
)
@ -20,6 +21,7 @@ async def get_settings(request, session_manager):
"langflow_url": LANGFLOW_URL,
"flow_id": LANGFLOW_CHAT_FLOW_ID,
"ingest_flow_id": LANGFLOW_INGEST_FLOW_ID,
"langflow_nudges_flow_id": LANGFLOW_NUDGES_FLOW_ID,
"langflow_public_url": LANGFLOW_PUBLIC_URL,
}
@ -34,6 +36,11 @@ async def get_settings(request, session_manager):
f"{LANGFLOW_PUBLIC_URL.rstrip('/')}/flow/{LANGFLOW_INGEST_FLOW_ID}"
)
if LANGFLOW_PUBLIC_URL and LANGFLOW_NUDGES_FLOW_ID:
settings["langflow_nudges_edit_url"] = (
f"{LANGFLOW_PUBLIC_URL.rstrip('/')}/flow/{LANGFLOW_NUDGES_FLOW_ID}"
)
# Fetch ingestion flow configuration to get actual component defaults
if LANGFLOW_INGEST_FLOW_ID:
try:

View file

@ -30,7 +30,7 @@ _legacy_flow_id = os.getenv("FLOW_ID")
LANGFLOW_CHAT_FLOW_ID = os.getenv("LANGFLOW_CHAT_FLOW_ID") or _legacy_flow_id
LANGFLOW_INGEST_FLOW_ID = os.getenv("LANGFLOW_INGEST_FLOW_ID")
NUDGES_FLOW_ID = os.getenv("NUDGES_FLOW_ID")
LANGFLOW_NUDGES_FLOW_ID = os.getenv("LANGFLOW_NUDGES_FLOW_ID")
if _legacy_flow_id and not os.getenv("LANGFLOW_CHAT_FLOW_ID"):
logger.warning("FLOW_ID is deprecated. Please use LANGFLOW_CHAT_FLOW_ID instead")

View file

@ -1,4 +1,4 @@
from config.settings import NUDGES_FLOW_ID, clients, LANGFLOW_URL
from config.settings import LANGFLOW_NUDGES_FLOW_ID, clients, LANGFLOW_URL
from agent import (
async_chat,
async_langflow,
@ -170,9 +170,9 @@ class ChatService:
):
"""Handle Langflow chat requests"""
if not LANGFLOW_URL or not NUDGES_FLOW_ID:
if not LANGFLOW_URL or not LANGFLOW_NUDGES_FLOW_ID:
raise ValueError(
"LANGFLOW_URL and NUDGES_FLOW_ID environment variables are required"
"LANGFLOW_URL and LANGFLOW_NUDGES_FLOW_ID environment variables are required"
)
# Prepare extra headers for JWT authentication
@ -207,7 +207,7 @@ class ChatService:
response_text, response_id = await async_langflow_chat(
langflow_client,
NUDGES_FLOW_ID,
LANGFLOW_NUDGES_FLOW_ID,
prompt,
user_id,
extra_headers=extra_headers,

View file

@ -1,4 +1,4 @@
from config.settings import NUDGES_FLOW_ID, LANGFLOW_URL, LANGFLOW_CHAT_FLOW_ID, LANGFLOW_INGEST_FLOW_ID, clients
from config.settings import LANGFLOW_NUDGES_FLOW_ID, LANGFLOW_URL, LANGFLOW_CHAT_FLOW_ID, LANGFLOW_INGEST_FLOW_ID, clients
import json
import os
from utils.logging_config import get_logger
@ -23,7 +23,7 @@ class FlowsService:
# Determine flow file and ID based on type
if flow_type == "nudges":
flow_file = "flows/openrag_nudges.json"
flow_id = NUDGES_FLOW_ID
flow_id = LANGFLOW_NUDGES_FLOW_ID
elif flow_type == "retrieval":
flow_file = "flows/openrag_agent.json"
flow_id = LANGFLOW_CHAT_FLOW_ID

View file

@ -33,6 +33,7 @@ class EnvConfig:
langflow_superuser_password: str = ""
langflow_chat_flow_id: str = "1098eea1-6649-4e1d-aed1-b77249fb8dd0"
langflow_ingest_flow_id: str = "5488df7c-b93f-4f87-a446-b67028bc0813"
langflow_nudges_flow_id: str = "ebc01d31-1976-46ce-a385-b0240327226c"
# OAuth settings
google_oauth_client_id: str = ""
@ -105,7 +106,7 @@ class EnvManager:
"LANGFLOW_SUPERUSER_PASSWORD": "langflow_superuser_password",
"LANGFLOW_CHAT_FLOW_ID": "langflow_chat_flow_id",
"LANGFLOW_INGEST_FLOW_ID": "langflow_ingest_flow_id",
"NUDGES_FLOW_ID": "nudges_flow_id",
"LANGFLOW_NUDGES_FLOW_ID": "langflow_nudges_flow_id",
"GOOGLE_OAUTH_CLIENT_ID": "google_oauth_client_id",
"GOOGLE_OAUTH_CLIENT_SECRET": "google_oauth_client_secret",
"MICROSOFT_GRAPH_OAUTH_CLIENT_ID": "microsoft_graph_oauth_client_id",
@ -246,7 +247,7 @@ class EnvManager:
f.write(
f"LANGFLOW_INGEST_FLOW_ID={self.config.langflow_ingest_flow_id}\n"
)
f.write(f"NUDGES_FLOW_ID={self.config.nudges_flow_id}\n")
f.write(f"LANGFLOW_NUDGES_FLOW_ID={self.config.langflow_nudges_flow_id}\n")
f.write(f"OPENSEARCH_PASSWORD={self.config.opensearch_password}\n")
f.write(f"OPENAI_API_KEY={self.config.openai_api_key}\n")
f.write(