Merge branch 'db' of personal:logspace-ai/langflow into db

This commit is contained in:
anovazzi1 2023-06-16 15:54:30 -03:00
commit 8fd94f0298
11 changed files with 76 additions and 101 deletions

2
poetry.lock generated
View file

@ -6416,4 +6416,4 @@ deploy = ["langchain-serve"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.9,<3.12" python-versions = ">=3.9,<3.12"
content-hash = "e3a7355edeae80f8330e6e71fd5acbc446fd287397cf7d8d027ab6b450569f28" content-hash = "4ed469589797b717f4b878f219dfe7c83d21d45d6947617693b6d2feb55cee3a"

View file

@ -61,6 +61,7 @@ faiss-cpu = "^1.7.4"
anthropic = "^0.2.9" anthropic = "^0.2.9"
orjson = "^3.9.0" orjson = "^3.9.0"
multiprocess = "^0.70.14" multiprocess = "^0.70.14"
cachetools = "^5.3.1"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]

View file

@ -12,10 +12,11 @@ from langflow.api.v1.schemas import BuiltResponse, InitResponse
from langflow.chat.manager import ChatManager from langflow.chat.manager import ChatManager
from langflow.graph.graph.base import Graph from langflow.graph.graph.base import Graph
from langflow.utils.logger import logger from langflow.utils.logger import logger
from cachetools import LRUCache
router = APIRouter(tags=["Chat"]) router = APIRouter(tags=["Chat"])
chat_manager = ChatManager() chat_manager = ChatManager()
flow_data_store = {} flow_data_store = LRUCache(maxsize=10)
@router.websocket("/chat/{client_id}") @router.websocket("/chat/{client_id}")
@ -38,7 +39,8 @@ async def init_build(graph_data: dict):
try: try:
flow_id = graph_data.get("id") flow_id = graph_data.get("id")
if flow_id is None:
raise ValueError("No ID provided")
flow_data_store[flow_id] = graph_data flow_data_store[flow_id] = graph_data
return InitResponse(flowId=flow_id) return InitResponse(flowId=flow_id)

View file

@ -3,7 +3,6 @@ from langflow.processing.process import process_graph_cached, process_tweaks
from langflow.utils.logger import logger from langflow.utils.logger import logger
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import HTTPBearer
from langflow.api.v1.schemas import ( from langflow.api.v1.schemas import (
PredictRequest, PredictRequest,
@ -17,20 +16,6 @@ from sqlmodel import Session
# build router # build router
router = APIRouter(tags=["Base"]) router = APIRouter(tags=["Base"])
security = HTTPBearer()
def get_flow_from_token(
bearer: HTTPBearer = Depends(security), session: Session = Depends(get_session)
) -> str:
# Extract the token, which is the flow_id in this case
flow_id = bearer.credentials
# Check if the flow_id exists in the database
flow = session.get(Flow, flow_id)
if flow is None:
raise HTTPException(status_code=401, detail="Invalid token")
return flow
@router.get("/all") @router.get("/all")
def get_all(): def get_all():
@ -51,6 +36,9 @@ async def predict_flow(
flow = session.get(Flow, flow_id) flow = session.get(Flow, flow_id)
if flow is None: if flow is None:
raise ValueError(f"Flow {flow_id} not found") raise ValueError(f"Flow {flow_id} not found")
if flow.data is None:
raise ValueError(f"Flow {flow_id} has no data")
graph_data = flow.data graph_data = flow.data
if predict_request.tweaks: if predict_request.tweaks:
graph_data = process_tweaks(graph_data, predict_request.tweaks) graph_data = process_tweaks(graph_data, predict_request.tweaks)

View file

@ -252,7 +252,11 @@ class VectorStoreRouterAgent(CustomAgentExecutor):
): ):
"""Construct a vector store router agent from an LLM and tools.""" """Construct a vector store router agent from an LLM and tools."""
tools = vectorstoreroutertoolkit.get_tools() tools = (
vectorstoreroutertoolkit
if isinstance(vectorstoreroutertoolkit, list)
else vectorstoreroutertoolkit.get_tools()
)
prompt = ZeroShotAgent.create_prompt(tools, prefix=VECTORSTORE_ROUTER_PREFIX) prompt = ZeroShotAgent.create_prompt(tools, prefix=VECTORSTORE_ROUTER_PREFIX)
llm_chain = LLMChain( llm_chain = LLMChain(
llm=llm, llm=llm,

View file

@ -1,3 +1,5 @@
import os
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
@ -20,7 +22,11 @@ def create_app(static_path: str = "static"):
@app.exception_handler(404) @app.exception_handler(404)
async def custom_404_handler(request, __): async def custom_404_handler(request, __):
return FileResponse(f"{static_path}/index.html") path = f"{static_path}/index.html"
if not os.path.isfile(path):
raise RuntimeError(f"File at path {path} does not exist.")
return FileResponse(path)
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,

View file

@ -172,7 +172,7 @@ def load_flow_from_json(path: str, build=True):
return graph return graph
def process_tweaks(graph_data: dict, tweaks: dict): def process_tweaks(graph_data: Dict, tweaks: Dict):
"""This function is used to tweak the graph data using the node id and the tweaks dict""" """This function is used to tweak the graph data using the node id and the tweaks dict"""
# the tweaks dict is a dict of dicts # the tweaks dict is a dict of dicts
# the key is the node id and the value is a dict of the tweaks # the key is the node id and the value is a dict of the tweaks

View file

@ -120,7 +120,7 @@ def test_initialize_agent(client: TestClient):
json_response = response.json() json_response = response.json()
agents = json_response["agents"] agents = json_response["agents"]
initialize_agent = agents["initialize_agent"] initialize_agent = agents["AgentInitializer"]
assert initialize_agent["base_classes"] == ["AgentExecutor", "function"] assert initialize_agent["base_classes"] == ["AgentExecutor", "function"]
template = initialize_agent["template"] template = initialize_agent["template"]
@ -136,6 +136,7 @@ def test_initialize_agent(client: TestClient):
"react-docstore", "react-docstore",
"self-ask-with-search", "self-ask-with-search",
"conversational-react-description", "conversational-react-description",
"openai-functions",
], ],
"name": "agent", "name": "agent",
"type": "str", "type": "str",

View file

@ -18,14 +18,15 @@ def test_conversation_chain(client: TestClient):
chains = json_response["chains"] chains = json_response["chains"]
chain = chains["ConversationChain"] chain = chains["ConversationChain"]
# Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects # Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects
assert set(chain["base_classes"]) == { assert set(chain["base_classes"]) == {
"function",
"LLMChain",
"ConversationChain", "ConversationChain",
"LLMChain",
"Chain", "Chain",
"Serializable",
"function",
} }
template = chain["template"] template = chain["template"]
assert template["memory"] == { assert template["memory"] == {
"required": False, "required": False,
@ -101,7 +102,13 @@ def test_llm_chain(client: TestClient):
chain = chains["LLMChain"] chain = chains["LLMChain"]
# Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects # Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects
assert set(chain["base_classes"]) == {"function", "LLMChain", "Chain"} assert set(chain["base_classes"]) == {
"Serializable",
"function",
"LLMChain",
"Chain"
}
template = chain["template"] template = chain["template"]
assert template["memory"] == { assert template["memory"] == {
"required": False, "required": False,
@ -159,31 +166,14 @@ def test_llm_checker_chain(client: TestClient):
chain = chains["LLMCheckerChain"] chain = chains["LLMCheckerChain"]
# Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects # Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects
assert set(chain["base_classes"]) == {"function", "LLMCheckerChain", "Chain"} assert set(chain["base_classes"]) == {
"Serializable",
"function",
"LLMCheckerChain",
"Chain"
}
template = chain["template"] template = chain["template"]
assert template["memory"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": False,
"password": False,
"name": "memory",
"type": "BaseMemory",
"list": False,
"advanced": False,
}
assert template["verbose"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": False,
"value": False,
"password": False,
"name": "verbose",
"type": "bool",
"list": False,
"advanced": True,
}
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
"placeholder": "", "placeholder": "",
@ -195,35 +185,11 @@ def test_llm_checker_chain(client: TestClient):
"list": False, "list": False,
"advanced": False, "advanced": False,
} }
assert template["input_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "query",
"password": False,
"name": "input_key",
"type": "str",
"list": False,
"advanced": True,
}
assert template["output_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "result",
"password": False,
"name": "output_key",
"type": "str",
"list": False,
"advanced": True,
}
assert template["_type"] == "LLMCheckerChain" assert template["_type"] == "LLMCheckerChain"
# Test the description object # Test the description object
assert ( assert (
chain["description"] == "Chain for question-answering with self-verification." chain["description"] == ""
) )
@ -234,9 +200,14 @@ def test_llm_math_chain(client: TestClient):
chains = json_response["chains"] chains = json_response["chains"]
chain = chains["LLMMathChain"] chain = chains["LLMMathChain"]
# Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects # Test the base classes, template, memory, verbose, llm, input_key, output_key, and _type objects
assert set(chain["base_classes"]) == {"function", "LLMMathChain", "Chain"} assert set(chain["base_classes"]) == {
"function",
"Serializable",
"LLMMathChain",
"Chain"
}
template = chain["template"] template = chain["template"]
assert template["memory"] == { assert template["memory"] == {
"required": False, "required": False,
@ -450,4 +421,4 @@ def test_time_travel_guide_chain(client: TestClient):
"advanced": False, "advanced": False,
} }
assert chain["description"] == "Time travel guide chain to be used in the flow." assert chain["description"] == "Time travel guide chain."

View file

@ -1,21 +1,21 @@
from uuid import UUID, uuid4
from langflow.api.v1.schemas import FlowListCreate
from langflow.database.models.flow import FlowCreate, FlowUpdate
import json import json
import pytest
import threading
from uuid import UUID, uuid4
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from langflow.database.models.flow import Flow
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from fastapi.encoders import jsonable_encoder
from langflow.api.v1.schemas import FlowListCreate
from langflow.database.models.flow import Flow, FlowCreate, FlowUpdate
from langflow.database.models.flow_style import ( from langflow.database.models.flow_style import (
FlowStyleCreate, FlowStyleCreate,
FlowStyleRead, FlowStyleRead,
FlowStyleUpdate, FlowStyleUpdate,
) )
from fastapi.encoders import jsonable_encoder
import pytest
import threading
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
@ -37,13 +37,13 @@ def test_create_flow(client: TestClient, json_flow: str):
data = flow["data"] data = flow["data"]
flow = FlowCreate(name="Test Flow", description="description", data=data) flow = FlowCreate(name="Test Flow", description="description", data=data)
response = client.post("api/v1/flows/", json=flow.dict()) response = client.post("api/v1/flows/", json=flow.dict())
assert response.status_code == 200 assert response.status_code == 201
assert response.json()["name"] == flow.name assert response.json()["name"] == flow.name
assert response.json()["data"] == flow.data assert response.json()["data"] == flow.data
# flow is optional so we can create a flow without a flow # flow is optional so we can create a flow without a flow
flow = FlowCreate(name="Test Flow") flow = FlowCreate(name="Test Flow")
response = client.post("api/v1/flows/", json=flow.dict(exclude_unset=True)) response = client.post("api/v1/flows/", json=flow.dict(exclude_unset=True))
assert response.status_code == 200 assert response.status_code == 201
assert response.json()["name"] == flow.name assert response.json()["name"] == flow.name
assert response.json()["data"] == flow.data assert response.json()["data"] == flow.data
@ -53,7 +53,7 @@ def test_read_flows(client: TestClient, json_flow: str):
data = flow_data["data"] data = flow_data["data"]
flow = FlowCreate(name="Test Flow", description="description", data=data) flow = FlowCreate(name="Test Flow", description="description", data=data)
response = client.post("api/v1/flows/", json=flow.dict()) response = client.post("api/v1/flows/", json=flow.dict())
assert response.status_code == 200 assert response.status_code == 201
assert response.json()["name"] == flow.name assert response.json()["name"] == flow.name
assert response.json()["data"] == flow.data assert response.json()["data"] == flow.data
@ -68,7 +68,7 @@ def test_read_flows(client: TestClient, json_flow: str):
flow = FlowCreate(name="Test Flow", description="description", data=data) flow = FlowCreate(name="Test Flow", description="description", data=data)
response = client.post("api/v1/flows/", json=flow.dict()) response = client.post("api/v1/flows/", json=flow.dict())
assert response.status_code == 200 assert response.status_code == 201
assert response.json()["name"] == flow.name assert response.json()["name"] == flow.name
assert response.json()["data"] == flow.data assert response.json()["data"] == flow.data
@ -157,7 +157,7 @@ def test_create_flows(client: TestClient, session: Session, json_flow: str):
# Make request to endpoint # Make request to endpoint
response = client.post("api/v1/flows/batch/", json=flow_list.dict()) response = client.post("api/v1/flows/batch/", json=flow_list.dict())
# Check response status code # Check response status code
assert response.status_code == 200 assert response.status_code == 201
# Check response data # Check response data
response_data = response.json() response_data = response.json()
assert len(response_data) == 2 assert len(response_data) == 2
@ -185,7 +185,7 @@ def test_upload_file(client: TestClient, session: Session, json_flow: str):
files={"file": ("examples.json", file_contents, "application/json")}, files={"file": ("examples.json", file_contents, "application/json")},
) )
# Check response status code # Check response status code
assert response.status_code == 200 assert response.status_code == 201
# Check response data # Check response data
response_data = response.json() response_data = response.json()
assert len(response_data) == 2 assert len(response_data) == 2
@ -233,10 +233,10 @@ def test_create_flow_with_invalid_data(client: TestClient):
def test_get_nonexistent_flow(client: TestClient): def test_get_nonexistent_flow(client: TestClient):
# uuid4 generates a random UUID
uuid = uuid4() uuid = uuid4()
response = client.get(f"api/v1/flows/{uuid}") with pytest.raises(RuntimeError) as excinfo:
assert response.status_code == 404 client.get(f"api/v1/flows/{uuid}")
assert str(excinfo.value) == "File at path static/index.html does not exist."
def test_update_flow_idempotency(client: TestClient, json_flow: str): def test_update_flow_idempotency(client: TestClient, json_flow: str):
@ -260,14 +260,16 @@ def test_update_nonexistent_flow(client: TestClient, json_flow: str):
description="description", description="description",
data=data, data=data,
) )
response = client.patch(f"api/v1/flows/{uuid}", json=updated_flow.dict()) with pytest.raises(RuntimeError) as excinfo:
assert response.status_code == 404 client.patch(f"api/v1/flows/{uuid}", json=updated_flow.dict())
assert str(excinfo.value) == "File at path static/index.html does not exist."
def test_delete_nonexistent_flow(client: TestClient): def test_delete_nonexistent_flow(client: TestClient):
uuid = uuid4() uuid = uuid4()
response = client.delete(f"api/v1/flows/{uuid}") with pytest.raises(RuntimeError) as excinfo:
assert response.status_code == 404 client.delete(f"api/v1/flows/{uuid}")
assert str(excinfo.value) == "File at path static/index.html does not exist."
def test_read_empty_flows(client: TestClient): def test_read_empty_flows(client: TestClient):

View file

@ -9,7 +9,7 @@ def test_init_build(client):
response = client.post( response = client.post(
"api/v1/build/init", json={"id": "test", "data": {"key": "value"}} "api/v1/build/init", json={"id": "test", "data": {"key": "value"}}
) )
assert response.status_code == 200 assert response.status_code == 201
assert response.json() == {"flowId": "test"} assert response.json() == {"flowId": "test"}