chore: import upstream snapshot with attribution
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.testing.sample_components.accumulate import Accumulate
|
||||
from haystack.testing.sample_components.add_value import AddFixedValue
|
||||
from haystack.testing.sample_components.concatenate import Concatenate
|
||||
from haystack.testing.sample_components.double import Double
|
||||
from haystack.testing.sample_components.fstring import FString
|
||||
from haystack.testing.sample_components.future_annotations import HelloUsingFutureAnnotations
|
||||
from haystack.testing.sample_components.greet import Greet
|
||||
from haystack.testing.sample_components.hello import Hello
|
||||
from haystack.testing.sample_components.joiner import StringJoiner, StringListJoiner
|
||||
from haystack.testing.sample_components.parity import Parity
|
||||
from haystack.testing.sample_components.remainder import Remainder
|
||||
from haystack.testing.sample_components.repeat import Repeat
|
||||
from haystack.testing.sample_components.subtract import Subtract
|
||||
from haystack.testing.sample_components.sum import Sum
|
||||
from haystack.testing.sample_components.text_splitter import TextSplitter
|
||||
from haystack.testing.sample_components.threshold import Threshold
|
||||
|
||||
__all__ = [
|
||||
"Concatenate",
|
||||
"Subtract",
|
||||
"Parity",
|
||||
"Remainder",
|
||||
"Accumulate",
|
||||
"Threshold",
|
||||
"AddFixedValue",
|
||||
"Repeat",
|
||||
"Sum",
|
||||
"Greet",
|
||||
"Double",
|
||||
"StringJoiner",
|
||||
"Hello",
|
||||
"HelloUsingFutureAnnotations",
|
||||
"TextSplitter",
|
||||
"StringListJoiner",
|
||||
"FString",
|
||||
]
|
||||
@@ -0,0 +1,70 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
from haystack.core.component import component
|
||||
from haystack.core.errors import ComponentDeserializationError
|
||||
from haystack.core.serialization import default_to_dict
|
||||
from haystack.utils.callable_serialization import deserialize_callable, serialize_callable
|
||||
|
||||
|
||||
def _default_function(first: int, second: int) -> int:
|
||||
return first + second
|
||||
|
||||
|
||||
@component
|
||||
class Accumulate:
|
||||
"""
|
||||
Accumulates the value flowing through the connection into an internal attribute.
|
||||
|
||||
The sum function can be customized. Example of how to deal with serialization when some of the parameters
|
||||
are not directly serializable.
|
||||
"""
|
||||
|
||||
def __init__(self, function: Callable | None = None) -> None:
|
||||
"""
|
||||
Class constructor
|
||||
|
||||
:param function:
|
||||
the function to use to accumulate the values.
|
||||
The function must take exactly two values.
|
||||
If it's a callable, it's used as it is.
|
||||
If it's a string, the component will look for it in sys.modules and
|
||||
import it at need. This is also a parameter.
|
||||
"""
|
||||
self.state = 0
|
||||
self.function: Callable = _default_function if function is None else function
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""Converts the component to a dictionary"""
|
||||
return default_to_dict(self, function=serialize_callable(self.function))
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> "Accumulate":
|
||||
"""Loads the component from a dictionary"""
|
||||
if "type" not in data:
|
||||
raise ComponentDeserializationError("Missing 'type' in component serialization data")
|
||||
if data["type"] != f"{cls.__module__}.{cls.__name__}":
|
||||
raise ComponentDeserializationError(f"Class '{data['type']}' can't be deserialized as '{cls.__name__}'")
|
||||
|
||||
init_params = data.get("init_parameters", {})
|
||||
|
||||
# Resolve the function through `deserialize_callable` so it passes the deserialization
|
||||
# allowlist instead of importing arbitrary handles directly.
|
||||
function = init_params.get("function")
|
||||
accumulator_function = deserialize_callable(function) if function else None
|
||||
|
||||
return cls(function=accumulator_function)
|
||||
|
||||
@component.output_types(value=int)
|
||||
def run(self, value: int):
|
||||
"""
|
||||
Accumulates the value flowing through the connection into an internal attribute.
|
||||
|
||||
The sum function can be customized.
|
||||
"""
|
||||
self.state = self.function(self.state, value)
|
||||
return {"value": self.state}
|
||||
@@ -0,0 +1,24 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class AddFixedValue:
|
||||
"""
|
||||
Adds two values together.
|
||||
"""
|
||||
|
||||
def __init__(self, add: int = 1) -> None:
|
||||
self.add = add
|
||||
|
||||
@component.output_types(result=int)
|
||||
def run(self, value: int, add: int | None = None):
|
||||
"""
|
||||
Adds two values together.
|
||||
"""
|
||||
if add is None:
|
||||
add = self.add
|
||||
return {"result": value + add}
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Concatenate:
|
||||
"""
|
||||
Concatenates two values
|
||||
"""
|
||||
|
||||
@component.output_types(value=list[str])
|
||||
def run(self, first: list[str] | str, second: list[str] | str):
|
||||
"""
|
||||
Concatenates two values
|
||||
"""
|
||||
if isinstance(first, str) and isinstance(second, str):
|
||||
res = [first, second]
|
||||
elif isinstance(first, list) and isinstance(second, list):
|
||||
res = first + second
|
||||
elif isinstance(first, list) and isinstance(second, str):
|
||||
res = first + [second]
|
||||
elif isinstance(first, str) and isinstance(second, list):
|
||||
res = [first] + second
|
||||
else:
|
||||
res = None
|
||||
return {"value": res}
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Double:
|
||||
"""
|
||||
Doubles the input value.
|
||||
"""
|
||||
|
||||
@component.output_types(value=int)
|
||||
def run(self, value: int):
|
||||
"""
|
||||
Doubles the input value.
|
||||
"""
|
||||
return {"value": value * 2}
|
||||
@@ -0,0 +1,32 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from typing import Any
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class FString:
|
||||
"""
|
||||
Takes a template string and a list of variables in input and returns the formatted string in output.
|
||||
"""
|
||||
|
||||
def __init__(self, template: str, variables: list[str] | None = None) -> None:
|
||||
self.template = template
|
||||
self.variables = variables or []
|
||||
if "template" in self.variables:
|
||||
raise ValueError("The variable name 'template' is reserved and cannot be used.")
|
||||
component.set_input_types(self, **dict.fromkeys(self.variables, Any))
|
||||
|
||||
@component.output_types(string=str)
|
||||
def run(self, template: str | None = None, **kwargs):
|
||||
"""
|
||||
Takes a template string and a list of variables in input and returns the formatted string in output.
|
||||
|
||||
If the template is not given, the component will use the one given at initialization.
|
||||
"""
|
||||
if not template:
|
||||
template = self.template
|
||||
return {"string": template.format(**kwargs)}
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from haystack import component
|
||||
|
||||
|
||||
@component
|
||||
class HelloUsingFutureAnnotations:
|
||||
@component.output_types(output=str)
|
||||
def run(self, word: str) -> dict[str, str]:
|
||||
"""Takes a string in input and returns "Hello, <string>!"in output."""
|
||||
return {"output": f"Hello, {word}!"}
|
||||
@@ -0,0 +1,48 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging
|
||||
|
||||
import haystack.logging as haystack_logging
|
||||
from haystack.core.component import component
|
||||
|
||||
logger = haystack_logging.getLogger(__name__)
|
||||
|
||||
|
||||
@component
|
||||
class Greet:
|
||||
"""
|
||||
Logs a greeting message without affecting the value passing on the connection.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, message: str = "\nGreeting component says: Hi! The value is {value}\n", log_level: str = "INFO"
|
||||
) -> None:
|
||||
"""
|
||||
Class constructor
|
||||
|
||||
:param message: the message to log. Can use `{value}` to embed the value.
|
||||
:param log_level: the level to log at.
|
||||
"""
|
||||
if log_level and not getattr(logging, log_level):
|
||||
raise ValueError(f"This log level does not exist: {log_level}")
|
||||
self.message = message
|
||||
self.log_level = log_level
|
||||
|
||||
@component.output_types(value=int)
|
||||
def run(self, value: int, message: str | None = None, log_level: str | None = None):
|
||||
"""
|
||||
Logs a greeting message without affecting the value passing on the connection.
|
||||
"""
|
||||
if not message:
|
||||
message = self.message
|
||||
if not log_level:
|
||||
log_level = self.log_level
|
||||
|
||||
level = getattr(logging, log_level, None)
|
||||
if not level:
|
||||
raise ValueError(f"This log level does not exist: {log_level}")
|
||||
|
||||
logger.log(level=level, msg=message.format(value=value))
|
||||
return {"value": value}
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Hello:
|
||||
@component.output_types(output=str)
|
||||
def run(self, word: str):
|
||||
"""Takes a string in input and returns "Hello, <string>!"in output."""
|
||||
return {"output": f"Hello, {word}!"}
|
||||
@@ -0,0 +1,35 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from haystack.core.component import component
|
||||
from haystack.core.component.types import Variadic
|
||||
|
||||
|
||||
@component
|
||||
class StringJoiner:
|
||||
@component.output_types(output=str)
|
||||
def run(self, input_str: Variadic[str]):
|
||||
"""
|
||||
Take strings from multiple input nodes and join them into a single one returned in output.
|
||||
|
||||
Since `input_str` is Variadic, we know we'll receive a list[str].
|
||||
"""
|
||||
return {"output": " ".join(input_str)}
|
||||
|
||||
|
||||
@component
|
||||
class StringListJoiner:
|
||||
@component.output_types(output=str)
|
||||
def run(self, inputs: Variadic[list[str]]):
|
||||
"""
|
||||
Take list of strings from multiple input nodes and join them into a single one returned in output.
|
||||
|
||||
Since `input_str` is Variadic, we know we'll receive a list[list[str]].
|
||||
"""
|
||||
retval: list[str] = []
|
||||
for list_of_strings in inputs:
|
||||
retval += list_of_strings
|
||||
|
||||
return {"output": retval}
|
||||
@@ -0,0 +1,22 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Parity:
|
||||
"""
|
||||
Redirects the value, unchanged, along the 'even' connection if even, or along the 'odd' one if odd.
|
||||
"""
|
||||
|
||||
@component.output_types(even=int, odd=int)
|
||||
def run(self, value: int):
|
||||
"""
|
||||
:param value: The value to check for parity
|
||||
"""
|
||||
remainder = value % 2
|
||||
if remainder:
|
||||
return {"odd": value}
|
||||
return {"even": value}
|
||||
@@ -0,0 +1,21 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Remainder:
|
||||
def __init__(self, divisor: int = 3) -> None:
|
||||
if divisor == 0:
|
||||
raise ValueError("Can't divide by zero")
|
||||
self.divisor = divisor
|
||||
component.set_output_types(self, **{f"remainder_is_{val}": int for val in range(divisor)})
|
||||
|
||||
def run(self, value: int):
|
||||
"""
|
||||
:param value: the value to check the remainder of.
|
||||
"""
|
||||
remainder = value % self.divisor
|
||||
return {f"remainder_is_{remainder}": value}
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Repeat:
|
||||
def __init__(self, outputs: list[str]) -> None:
|
||||
self._outputs = outputs
|
||||
component.set_output_types(self, **dict.fromkeys(outputs, int))
|
||||
|
||||
def run(self, value: int):
|
||||
"""
|
||||
:param value: the value to repeat.
|
||||
"""
|
||||
return dict.fromkeys(self._outputs, value)
|
||||
@@ -0,0 +1,22 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Subtract:
|
||||
"""
|
||||
Compute the difference between two values.
|
||||
"""
|
||||
|
||||
@component.output_types(difference=int)
|
||||
def run(self, first_value: int, second_value: int):
|
||||
"""
|
||||
Run the component.
|
||||
|
||||
:param first_value: name of the connection carrying the value to subtract from.
|
||||
:param second_value: name of the connection carrying the value to subtract.
|
||||
"""
|
||||
return {"difference": first_value - second_value}
|
||||
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
from haystack.core.component.types import Variadic
|
||||
|
||||
|
||||
@component
|
||||
class Sum:
|
||||
@component.output_types(total=int)
|
||||
def run(self, values: Variadic[int]):
|
||||
"""
|
||||
:param value: the values to sum.
|
||||
"""
|
||||
return {"total": sum(values)}
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class TextSplitter:
|
||||
@component.output_types(output=list[str])
|
||||
def run(self, sentence: str):
|
||||
"""Takes a sentence in input and returns its words in output."""
|
||||
return {"output": sentence.split()}
|
||||
@@ -0,0 +1,34 @@
|
||||
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from haystack.core.component import component
|
||||
|
||||
|
||||
@component
|
||||
class Threshold:
|
||||
"""
|
||||
Redirects the value, along a different connection whether the value is above or below the given threshold.
|
||||
|
||||
:param threshold: the number to compare the input value against. This is also a parameter.
|
||||
"""
|
||||
|
||||
def __init__(self, threshold: int = 10) -> None:
|
||||
"""
|
||||
:param threshold: the number to compare the input value against.
|
||||
"""
|
||||
self.threshold = threshold
|
||||
|
||||
@component.output_types(above=int, below=int)
|
||||
def run(self, value: int, threshold: int | None = None):
|
||||
"""
|
||||
Redirects the value, along a different connection whether the value is above or below the given threshold.
|
||||
|
||||
:param threshold: the number to compare the input value against. This is also a parameter.
|
||||
"""
|
||||
if threshold is None:
|
||||
threshold = self.threshold
|
||||
|
||||
if value < threshold:
|
||||
return {"below": value}
|
||||
return {"above": value}
|
||||
Reference in New Issue
Block a user