feat: add Parse JSON component (#3167)

* feat: add Parse JSON component

* feat: Update ParseJSONDataComponent to handle JSON decoding errors

* fix tests

* [autofix.ci] apply automated fixes

* add string check in _parse_data

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Nicolò Boschi 2024-09-03 18:36:30 +02:00 • committed by GitHub
commit 1c7ef6ee60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 162 additions and 16 deletions

View file

@ -1,14 +1,11 @@
import os
from typing import List
from astrapy.db import AstraDB
import pytest
from langflow.components.embeddings import OpenAIEmbeddingsComponent
from langflow.custom import Component
from langflow.inputs import StrInput
from langflow.template import Output
from tests.api_keys import get_astradb_application_token, get_astradb_api_endpoint, get_openai_api_key
from tests.integration.components.mock_components import TextToData
from tests.integration.utils import ComponentInputHandle
from langchain_core.documents import Document
@ -70,14 +67,6 @@ async def test_base(astradb_client: AstraDB):
assert astradb_client.collection(BASIC_COLLECTION)
class TextToData(Component):
inputs = [StrInput(name="text_data", is_list=True)]
outputs = [Output(name="data", display_name="Data", method="create_data")]
def create_data(self) -> List[Data]:
return [Data(text=t) for t in self.text_data]
@pytest.mark.api_key_required
@pytest.mark.asyncio
async def test_astra_embeds_and_search():
@ -93,7 +82,7 @@ async def test_astra_embeds_and_search():
"number_of_results": 1,
"search_input": "test1",
"ingest_data": ComponentInputHandle(
clazz=TextToData, inputs={"text_data": ["test1", "test2"]}, output_name="data"
clazz=TextToData, inputs={"text_data": ["test1", "test2"]}, output_name="from_text"
),
"embedding": ComponentInputHandle(
clazz=OpenAIEmbeddingsComponent,

View file

@ -0,0 +1,57 @@
import pytest
from langflow.components.helpers.ParseJSONData import ParseJSONDataComponent
from langflow.components.inputs import ChatInput
from langflow.schema import Data
from tests.integration.components.mock_components import TextToData
from tests.integration.utils import run_single_component, ComponentInputHandle
@pytest.mark.asyncio
async def test_from_data():
outputs = await run_single_component(
ParseJSONDataComponent,
inputs={
"input_value": ComponentInputHandle(
clazz=TextToData, inputs={"text_data": ['{"key":"value1"}'], "is_json": True}, output_name="from_text"
),
"query": ".[0].key",
},
)
assert outputs["filtered_data"] == [Data(text="value1")]
outputs = await run_single_component(
ParseJSONDataComponent,
inputs={
"input_value": ComponentInputHandle(
clazz=TextToData,
inputs={"text_data": ['{"key":[{"field1": 1, "field2": 2}]}'], "is_json": True},
output_name="from_text",
),
"query": ".[0].key.[0].field2",
},
)
assert outputs["filtered_data"] == [Data(text="2")]
@pytest.mark.asyncio
async def test_from_message():
outputs = await run_single_component(
ParseJSONDataComponent,
inputs={
"input_value": ComponentInputHandle(clazz=ChatInput, inputs={}, output_name="message"),
"query": ".[0].key",
},
run_input="{'key':'value1'}",
)
assert outputs["filtered_data"] == [Data(text="value1")]
outputs = await run_single_component(
ParseJSONDataComponent,
inputs={
"input_value": ComponentInputHandle(clazz=ChatInput, inputs={}, output_name="message"),
"query": ".[0].key.[0].field2",
},
run_input='{"key":[{"field1": 1, "field2": 2}]}',
)
assert outputs["filtered_data"] == [Data(text="2")]

View file

@ -0,0 +1,25 @@
import json
from typing import List
from langflow.custom import Component
from langflow.inputs import StrInput, BoolInput
from langflow.schema import Data
from langflow.template import Output
class TextToData(Component):
inputs = [
StrInput(name="text_data", is_list=True),
BoolInput(name="is_json", info="Parse text_data as json and fill the data object."),
]
outputs = [
Output(name="from_text", display_name="From text", method="create_data"),
]
def _to_data(self, text: str) -> Data:
if self.is_json:
return Data(data=json.loads(text))
return Data(text=text)
def create_data(self) -> List[Data]:
return [self._to_data(t) for t in self.text_data]