From c7cdf3f9e9e46c404f16554abd6f9b99044f0401 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Thu, 28 Mar 2024 18:42:16 -0300 Subject: [PATCH] Fix nodeToolbarComponent rendering issue and add chat_io end-to-end test --- .../components/nodeToolbarComponent/index.tsx | 2 +- .../tests/end-to-end/assets/ChatTest.json | 403 ++++++++++++++++++ src/frontend/tests/end-to-end/chat_io.spec.ts | 46 ++ 3 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 src/frontend/tests/end-to-end/assets/ChatTest.json create mode 100644 src/frontend/tests/end-to-end/chat_io.spec.ts diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 17b4b2225..155b61392 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -499,7 +499,7 @@ export default function NodeToolbarComponent({ /> )} - {!hasStore && ( + {!hasStore || !hasApiKey || !validApiKey && (
Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": false, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "User", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Used to get user input from the chat.", + "icon": "ChatInput", + "base_classes": [ + "Text", + "object", + "str", + "Record" + ], + "display_name": "Chat Input", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatInput-7hPDT" + }, + "selected": false, + "width": 384, + "height": 569, + "positionAbsolute": { + "x": 687, + "y": 41.9375 + }, + "dragging": false + }, + { + "id": "ChatOutput-4sm9Z", + "type": "genericNode", + "position": { + "x": 4.939451516507972, + "y": 103.3695231904992 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Used to send a message to the chat.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "input_value": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Message", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "return_record": { + "type": "bool", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "return_record", + "display_name": "Return Record", + "advanced": false, + "dynamic": false, + "info": "Return the message as a record containing the sender, sender_name, and session_id.", + "load_from_db": false, + "title_case": false + }, + "sender": { + "type": "str", + "required": false, + "placeholder": "", + "list": true, + "show": true, + "multiline": false, + "value": "Machine", + "fileTypes": [], + "file_path": "", + "password": false, + "options": [ + "Machine", + "User" + ], + "name": "sender", + "display_name": "Sender Type", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "sender_name": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "AI", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "sender_name", + "display_name": "Sender Name", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "session_id": { + "type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "session_id", + "display_name": "Session ID", + "advanced": true, + "dynamic": false, + "info": "If provided, the message will be stored in the memory.", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "_type": "CustomComponent" + }, + "description": "Used to send a message to the chat.", + "icon": "ChatOutput", + "base_classes": [ + "Text", + "object", + "str", + "Record" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-4sm9Z" + }, + "selected": true, + "width": 384, + "height": 569, + "positionAbsolute": { + "x": 4.939451516507972, + "y": 103.3695231904992 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "ChatOutput-4sm9Z", + "sourceHandle": "{œbaseClassesœ:[œTextœ,œobjectœ,œstrœ,œRecordœ],œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-4sm9Zœ}", + "target": "ChatInput-7hPDT", + "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatInput-7hPDTœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "data": { + "targetHandle": { + "fieldName": "input_value", + "id": "ChatInput-7hPDT", + "inputTypes": [ + "Text" + ], + "type": "str" + }, + "sourceHandle": { + "baseClasses": [ + "Text", + "object", + "str", + "Record" + ], + "dataType": "ChatOutput", + "id": "ChatOutput-4sm9Z" + } + }, + "style": { + "stroke": "#555" + }, + "className": "stroke-gray-900 stroke-connection", + "id": "reactflow__edge-ChatOutput-4sm9Z{œbaseClassesœ:[œTextœ,œobjectœ,œstrœ,œRecordœ],œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-4sm9Zœ}-ChatInput-7hPDT{œfieldNameœ:œinput_valueœ,œidœ:œChatInput-7hPDTœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" + } + ], + "viewport": { + "x": 316.78239920440234, + "y": 182.84104875768622, + "zoom": 0.6070974421975234 + } + }, + "description": "flow to test ChatInput and output", + "name": "ChatITest", + "last_tested_version": "1.0.0a0", + "is_component": false +} \ No newline at end of file diff --git a/src/frontend/tests/end-to-end/chat_io.spec.ts b/src/frontend/tests/end-to-end/chat_io.spec.ts new file mode 100644 index 000000000..58a7901e3 --- /dev/null +++ b/src/frontend/tests/end-to-end/chat_io.spec.ts @@ -0,0 +1,46 @@ +import { test } from "@playwright/test"; +import { readFileSync } from "fs"; +test.beforeEach(async ({ page }) => { + // await page.waitForTimeout(20000); + // test.setTimeout(120000); +}); +test("chat_io_teste", async ({ page }) => { + await page.goto("/"); + await page.locator("span").filter({ hasText: "My Collection" }).isVisible(); + // Read your file into a buffer. + const jsonContent = readFileSync( + "tests/end-to-end/assets/ChatTest.json", + "utf-8" + ); + + // Create the DataTransfer and File + const dataTransfer = await page.evaluateHandle((data) => { + const dt = new DataTransfer(); + // Convert the buffer to a hex array + const file = new File([data], "ChatTest.json", { + type: "application/json", + }); + dt.items.add(file); + return dt; + }, jsonContent); + + await page.locator('//*[@id="new-project-btn"]').click(); + await page.waitForTimeout(2000); + + await page.getByTestId("blank-flow").click(); + await page.waitForTimeout(2000); + + // Now dispatch + await page.dispatchEvent( + '//*[@id="react-flow-id"]/div[1]/div[1]/div', + "drop", + { + dataTransfer, + } + ); + await page.getByLabel('fit view').click(); + await page.getByText('Run', { exact: true }).click(); + await page.getByPlaceholder('Send a message...').click(); + await page.getByPlaceholder('Send a message...').fill('teste'); + await page.getByRole('button').nth(1).click(); +});