This commit is contained in:
Cristhian Zanforlin Lousa 2023-06-15 19:38:16 -03:00
commit 1b0c173f39
7 changed files with 86 additions and 12 deletions

View file

@ -27,12 +27,19 @@ def get_number_of_workers(workers=None):
return workers
def update_settings(config: str, dev: bool = False, database_url: Optional[str] = None):
def update_settings(
config: str,
dev: bool = False,
database_url: Optional[str] = None,
remove_api_keys: bool = False,
):
"""Update the settings from a config file."""
if config:
settings.update_from_yaml(config, dev=dev)
if database_url:
settings.update_database_url(database_url)
settings.update_settings(database_url=database_url)
if remove_api_keys:
settings.update_settings(remove_api_keys=remove_api_keys)
def serve_on_jcloud():
@ -107,6 +114,9 @@ def serve(
open_browser: bool = typer.Option(
True, help="Open the browser after starting the server."
),
remove_api_keys: bool = typer.Option(
False, help="Remove API keys from the projects saved in the database."
),
):
"""
Run the Langflow server.
@ -132,7 +142,9 @@ def serve(
load_dotenv(env_file)
configure(log_level=log_level, log_file=log_file)
update_settings(config, dev=dev, database_url=database_url)
update_settings(
config, dev=dev, database_url=database_url, remove_api_keys=remove_api_keys
)
app = create_app()
# get the directory of the current file
if not path:

View file

@ -0,0 +1,24 @@
API_WORDS = ["api", "key", "token"]
def has_api_terms(word: str):
return "api" in word and (
"key" in word or ("token" in word and "tokens" not in word)
)
def remove_api_keys(flow: dict):
"""Remove api keys from flow data."""
if flow.get("data") and flow["data"].get("nodes"):
for node in flow["data"]["nodes"]:
node_data = node.get("data").get("node")
template = node_data.get("template")
for value in template.values():
if (
isinstance(value, dict)
and has_api_terms(value["name"])
and value.get("password")
):
value["value"] = None
return flow

View file

@ -1,5 +1,7 @@
from typing import List
from uuid import UUID
from langflow.settings import settings
from langflow.api.utils import remove_api_keys
from langflow.api.v1.schemas import FlowListCreate, FlowListRead
from langflow.database.models.flow import (
Flow,
@ -54,10 +56,13 @@ def update_flow(
*, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate
):
"""Update a flow."""
db_flow = session.get(Flow, flow_id)
if not db_flow:
raise HTTPException(status_code=404, detail="Flow not found")
flow_data = flow.dict(exclude_unset=True)
if not settings.remove_api_keys:
flow_data = remove_api_keys(flow_data)
for key, value in flow_data.items():
setattr(db_flow, key, value)
session.add(db_flow)

View file

@ -1,5 +1,5 @@
import os
from typing import List, Optional
from typing import List
import yaml
from pydantic import BaseSettings, root_validator
@ -21,6 +21,7 @@ class Settings(BaseSettings):
utilities: List[str] = []
dev: bool = False
database_url: str = "sqlite:///./langflow.db"
remove_api_keys: bool = False
class Config:
validate_assignment = True
@ -48,9 +49,10 @@ class Settings(BaseSettings):
self.utilities = new_settings.utilities or []
self.dev = dev
def update_database_url(self, database_url: Optional[str] = None):
if database_url:
self.database_url = database_url
def update_settings(self, **kwargs):
for key, value in kwargs.items():
if hasattr(self, key):
setattr(self, key, value)
def save_settings_to_yaml(settings: Settings, file_path: str):

View file

@ -46,7 +46,10 @@ class LLMFrontendNode(FrontendNode):
if field.name in SHOW_FIELDS:
field.show = True
if "api" in field.name and ("key" in field.name or "token" in field.name):
if "api" in field.name and (
"key" in field.name
or ("token" in field.name and "tokens" not in field.name)
):
field.password = True
field.show = True
# Required should be False to support

View file

@ -68,6 +68,8 @@ BASE_API_URL = "${window.location.protocol}//${
window.location.host
}/ap1/v1/predict"
FLOW_ID = "${flowId}"
# You can tweak the flow by adding a tweaks dictionary
# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}}
TWEAKS = ${JSON.stringify(tweaks, null, 2)}
def run_flow(message: str, flow_id: str, tweaks: dict = None) -> dict:

View file

@ -1,4 +1,4 @@
import _ from "lodash";
import _, { set } from "lodash";
import { useContext, useRef, useState, useEffect, useCallback } from "react";
import ReactFlow, {
OnSelectionChangeParams,
@ -15,6 +15,7 @@ import ReactFlow, {
updateEdge,
Background,
Controls,
NodeChange,
} from "reactflow";
import GenericNode from "../../../../CustomNodes/GenericNode";
import Chat from "../../../../components/chatComponent";
@ -43,7 +44,9 @@ export default function Page({ flow }: { flow: FlowType }) {
lastCopiedSelection,
setLastCopiedSelection,
tabsState,
saveFlow
saveFlow,
setTabsState,
tabId
} = useContext(TabsContext);
const { types, reactFlowInstance, setReactFlowInstance, templates } =
useContext(typesContext);
@ -145,8 +148,31 @@ export default function Page({ flow }: { flow: FlowType }) {
let newX = _.cloneDeep(x);
return newX;
});
setTabsState((prev) => {
return {
...prev,
[tabId]: {
isPending: true,
},
};
});
},
[onEdgesChange, setNodes]
[onEdgesChange, setNodes,setTabsState,tabId]
);
const onNodesChangeMod = useCallback(
(s: NodeChange[]) => {
onNodesChange(s);
setTabsState((prev) => {
return {
...prev,
[tabId]: {
isPending: true,
},
};
});
},
[onNodesChange,setTabsState,tabId]
);
const onConnect = useCallback(
@ -345,7 +371,7 @@ export default function Page({ flow }: { flow: FlowType }) {
onPaneMouseLeave={() => {
setDisableCopyPaste(true);
}}
onNodesChange={onNodesChange}
onNodesChange={onNodesChangeMod}
onEdgesChange={onEdgesChangeMod}
onConnect={onConnect}
disableKeyboardA11y={true}