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 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.""" """Update the settings from a config file."""
if config: if config:
settings.update_from_yaml(config, dev=dev) settings.update_from_yaml(config, dev=dev)
if database_url: 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(): def serve_on_jcloud():
@ -107,6 +114,9 @@ def serve(
open_browser: bool = typer.Option( open_browser: bool = typer.Option(
True, help="Open the browser after starting the server." 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. Run the Langflow server.
@ -132,7 +142,9 @@ def serve(
load_dotenv(env_file) load_dotenv(env_file)
configure(log_level=log_level, log_file=log_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() app = create_app()
# get the directory of the current file # get the directory of the current file
if not path: 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 typing import List
from uuid import UUID 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.api.v1.schemas import FlowListCreate, FlowListRead
from langflow.database.models.flow import ( from langflow.database.models.flow import (
Flow, Flow,
@ -54,10 +56,13 @@ def update_flow(
*, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate *, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate
): ):
"""Update a flow.""" """Update a flow."""
db_flow = session.get(Flow, flow_id) db_flow = session.get(Flow, flow_id)
if not db_flow: if not db_flow:
raise HTTPException(status_code=404, detail="Flow not found") raise HTTPException(status_code=404, detail="Flow not found")
flow_data = flow.dict(exclude_unset=True) 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(): for key, value in flow_data.items():
setattr(db_flow, key, value) setattr(db_flow, key, value)
session.add(db_flow) session.add(db_flow)

View file

@ -1,5 +1,5 @@
import os import os
from typing import List, Optional from typing import List
import yaml import yaml
from pydantic import BaseSettings, root_validator from pydantic import BaseSettings, root_validator
@ -21,6 +21,7 @@ class Settings(BaseSettings):
utilities: List[str] = [] utilities: List[str] = []
dev: bool = False dev: bool = False
database_url: str = "sqlite:///./langflow.db" database_url: str = "sqlite:///./langflow.db"
remove_api_keys: bool = False
class Config: class Config:
validate_assignment = True validate_assignment = True
@ -48,9 +49,10 @@ class Settings(BaseSettings):
self.utilities = new_settings.utilities or [] self.utilities = new_settings.utilities or []
self.dev = dev self.dev = dev
def update_database_url(self, database_url: Optional[str] = None): def update_settings(self, **kwargs):
if database_url: for key, value in kwargs.items():
self.database_url = database_url if hasattr(self, key):
setattr(self, key, value)
def save_settings_to_yaml(settings: Settings, file_path: str): 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: if field.name in SHOW_FIELDS:
field.show = True 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.password = True
field.show = True field.show = True
# Required should be False to support # Required should be False to support

View file

@ -68,6 +68,8 @@ BASE_API_URL = "${window.location.protocol}//${
window.location.host window.location.host
}/ap1/v1/predict" }/ap1/v1/predict"
FLOW_ID = "${flowId}" 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)} TWEAKS = ${JSON.stringify(tweaks, null, 2)}
def run_flow(message: str, flow_id: str, tweaks: dict = None) -> dict: 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 { useContext, useRef, useState, useEffect, useCallback } from "react";
import ReactFlow, { import ReactFlow, {
OnSelectionChangeParams, OnSelectionChangeParams,
@ -15,6 +15,7 @@ import ReactFlow, {
updateEdge, updateEdge,
Background, Background,
Controls, Controls,
NodeChange,
} from "reactflow"; } from "reactflow";
import GenericNode from "../../../../CustomNodes/GenericNode"; import GenericNode from "../../../../CustomNodes/GenericNode";
import Chat from "../../../../components/chatComponent"; import Chat from "../../../../components/chatComponent";
@ -43,7 +44,9 @@ export default function Page({ flow }: { flow: FlowType }) {
lastCopiedSelection, lastCopiedSelection,
setLastCopiedSelection, setLastCopiedSelection,
tabsState, tabsState,
saveFlow saveFlow,
setTabsState,
tabId
} = useContext(TabsContext); } = useContext(TabsContext);
const { types, reactFlowInstance, setReactFlowInstance, templates } = const { types, reactFlowInstance, setReactFlowInstance, templates } =
useContext(typesContext); useContext(typesContext);
@ -145,8 +148,31 @@ export default function Page({ flow }: { flow: FlowType }) {
let newX = _.cloneDeep(x); let newX = _.cloneDeep(x);
return newX; 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( const onConnect = useCallback(
@ -345,7 +371,7 @@ export default function Page({ flow }: { flow: FlowType }) {
onPaneMouseLeave={() => { onPaneMouseLeave={() => {
setDisableCopyPaste(true); setDisableCopyPaste(true);
}} }}
onNodesChange={onNodesChange} onNodesChange={onNodesChangeMod}
onEdgesChange={onEdgesChangeMod} onEdgesChange={onEdgesChangeMod}
onConnect={onConnect} onConnect={onConnect}
disableKeyboardA11y={true} disableKeyboardA11y={true}