feat: adds Wikipedia Component and deprecates the wikipedia API tool component (#5871)

* update

* Update test_wikipedia_api.py

* [autofix.ci] apply automated fixes

* Update src/backend/base/langflow/components/tools/wikipedia.py

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* Update test_wikipedia_api.py

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Edwin Jose 2025-01-22 13:29:53 -05:00 • committed by GitHub
commit dcd68c5f4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 141 additions and 75 deletions

View file

@ -25,6 +25,7 @@ from .serp_api import SerpAPIComponent
from .tavily import TavilySearchComponent from .tavily import TavilySearchComponent
from .tavily_search import TavilySearchToolComponent from .tavily_search import TavilySearchToolComponent
from .wikidata_api import WikidataAPIComponent from .wikidata_api import WikidataAPIComponent
from .wikipedia import WikipediaComponent
from .wikipedia_api import WikipediaAPIComponent from .wikipedia_api import WikipediaAPIComponent
from .wolfram_alpha_api import WolframAlphaAPIComponent from .wolfram_alpha_api import WolframAlphaAPIComponent
from .yahoo import YfinanceComponent from .yahoo import YfinanceComponent
@ -62,6 +63,7 @@ __all__ = [
"TavilySearchToolComponent", "TavilySearchToolComponent",
"WikidataAPIComponent", "WikidataAPIComponent",
"WikipediaAPIComponent", "WikipediaAPIComponent",
"WikipediaComponent",
"WolframAlphaAPIComponent", "WolframAlphaAPIComponent",
"YfinanceComponent", "YfinanceComponent",
"YfinanceToolComponent", "YfinanceToolComponent",

View file

@ -0,0 +1,55 @@
from langchain_community.utilities.wikipedia import WikipediaAPIWrapper
from langflow.custom import Component
from langflow.inputs import BoolInput, IntInput, MessageTextInput, MultilineInput
from langflow.io import Output
from langflow.schema import Data
from langflow.schema.message import Message
class WikipediaComponent(Component):
display_name = "Wikipedia"
description = "Call Wikipedia API."
icon = "Wikipedia"
inputs = [
MultilineInput(
name="input_value",
display_name="Input",
tool_mode=True,
),
MessageTextInput(name="lang", display_name="Language", value="en"),
IntInput(name="k", display_name="Number of results", value=4, required=True),
BoolInput(name="load_all_available_meta", display_name="Load all available meta", value=False, advanced=True),
IntInput(
name="doc_content_chars_max", display_name="Document content characters max", value=4000, advanced=True
),
]
outputs = [
Output(display_name="Data", name="data", method="fetch_content"),
Output(display_name="Text", name="text", method="fetch_content_text"),
]
def fetch_content(self) -> list[Data]:
wrapper = self._build_wrapper()
docs = wrapper.load(self.input_value)
data = [Data.from_document(doc) for doc in docs]
self.status = data
return data
def fetch_content_text(self) -> Message:
data = self.fetch_content()
result_string = ""
for item in data:
result_string += item.text + "\n"
self.status = result_string
return Message(text=result_string)
def _build_wrapper(self) -> WikipediaAPIWrapper:
return WikipediaAPIWrapper(
top_k_results=self.k,
lang=self.lang,
load_all_available_meta=self.load_all_available_meta,
doc_content_chars_max=self.doc_content_chars_max,
)

View file

@ -1,23 +1,25 @@
from typing import cast
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities.wikipedia import WikipediaAPIWrapper from langchain_community.utilities.wikipedia import WikipediaAPIWrapper
from langflow.custom import Component from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs import BoolInput, IntInput, MessageTextInput, MultilineInput from langflow.inputs import BoolInput, IntInput, MessageTextInput, MultilineInput
from langflow.io import Output
from langflow.schema import Data from langflow.schema import Data
from langflow.schema.message import Message
class WikipediaAPIComponent(Component): class WikipediaAPIComponent(LCToolComponent):
display_name = "Wikipedia API" display_name = "Wikipedia API [Deprecated]"
description = "Call Wikipedia API." description = "Call Wikipedia API."
name = "WikipediaAPI" name = "WikipediaAPI"
icon = "Wikipedia" icon = "Wikipedia"
legacy = True
inputs = [ inputs = [
MultilineInput( MultilineInput(
name="input_value", name="input_value",
display_name="Input", display_name="Input",
tool_mode=True,
), ),
MessageTextInput(name="lang", display_name="Language", value="en"), MessageTextInput(name="lang", display_name="Language", value="en"),
IntInput(name="k", display_name="Number of results", value=4, required=True), IntInput(name="k", display_name="Number of results", value=4, required=True),
@ -27,25 +29,16 @@ class WikipediaAPIComponent(Component):
), ),
] ]
outputs = [ def run_model(self) -> list[Data]:
Output(display_name="Data", name="data", method="fetch_content"),
Output(display_name="Text", name="text", method="fetch_content_text"),
]
def fetch_content(self) -> list[Data]:
wrapper = self._build_wrapper() wrapper = self._build_wrapper()
docs = wrapper.load(self.input_value) docs = wrapper.load(self.input_value)
data = [Data.from_document(doc) for doc in docs] data = [Data.from_document(doc) for doc in docs]
self.status = data self.status = data
return data return data
def fetch_content_text(self) -> Message: def build_tool(self) -> Tool:
data = self.fetch_content() wrapper = self._build_wrapper()
result_string = "" return cast("Tool", WikipediaQueryRun(api_wrapper=wrapper))
for item in data:
result_string += item.text + "\n"
self.status = result_string
return Message(text=result_string)
def _build_wrapper(self) -> WikipediaAPIWrapper: def _build_wrapper(self) -> WikipediaAPIWrapper:
return WikipediaAPIWrapper( return WikipediaAPIWrapper(

View file

@ -1,85 +1,101 @@
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
from langflow.components.tools import WikipediaAPIComponent from langflow.components.tools import WikipediaComponent
from langflow.custom import Component from langflow.custom import Component
from langflow.custom.utils import build_custom_component_template from langflow.custom.utils import build_custom_component_template
from langflow.schema import Data from langflow.schema import Data
from langflow.schema.message import Message from langflow.schema.message import Message
# Import the base test class
def test_wikipedia_initialization(): from tests.base import ComponentTestBaseWithoutClient
component = WikipediaAPIComponent()
assert component.display_name == "Wikipedia API"
assert component.description == "Call Wikipedia API."
assert component.icon == "Wikipedia"
def test_wikipedia_template(): class TestWikipediaComponent(ComponentTestBaseWithoutClient):
wikipedia = WikipediaAPIComponent() @pytest.fixture
component = Component(_code=wikipedia._code) def component_class(self):
frontend_node, _ = build_custom_component_template(component) """Fixture to create a WikipediaComponent instance."""
return WikipediaComponent
# Verify basic structure @pytest.fixture
assert isinstance(frontend_node, dict) def default_kwargs(self):
"""Return the default kwargs for the component."""
return {
"input_value": "test query",
"lang": "en",
"k": 3,
}
# Verify inputs @pytest.fixture
assert "template" in frontend_node def file_names_mapping(self):
input_names = [input_["name"] for input_ in frontend_node["template"].values() if isinstance(input_, dict)] """Return an empty list since this component doesn't have version-specific files."""
return []
expected_inputs = ["input_value", "lang", "k", "load_all_available_meta", "doc_content_chars_max"] def test_wikipedia_initialization(self, component_class):
component = component_class()
assert component.display_name == "Wikipedia"
assert component.description == "Call Wikipedia API."
assert component.icon == "Wikipedia"
for input_name in expected_inputs: def test_wikipedia_template(self, component_class):
assert input_name in input_names component = component_class()
frontend_node, _ = build_custom_component_template(Component(_code=component._code))
# Verify basic structure
assert isinstance(frontend_node, dict)
@pytest.fixture # Verify inputs
def mock_wikipedia_wrapper(mocker): assert "template" in frontend_node
return mocker.patch("langchain_community.utilities.wikipedia.WikipediaAPIWrapper") input_names = [input_["name"] for input_ in frontend_node["template"].values() if isinstance(input_, dict)]
expected_inputs = ["input_value", "lang", "k", "load_all_available_meta", "doc_content_chars_max"]
def test_fetch_content(mock_wikipedia_wrapper): for input_name in expected_inputs:
component = WikipediaAPIComponent() assert input_name in input_names
component.input_value = "test query"
component.k = 3
component.lang = "en"
# Mock the WikipediaAPIWrapper and its load method @pytest.fixture
mock_instance = MagicMock() def mock_wikipedia_wrapper(self, mocker):
mock_wikipedia_wrapper.return_value = mock_instance return mocker.patch("langchain_community.utilities.wikipedia.WikipediaAPIWrapper")
mock_doc = MagicMock()
mock_doc.page_content = "Test content"
mock_doc.metadata = {"source": "wikipedia", "title": "Test Page"}
mock_instance.load.return_value = [mock_doc]
# Mock the _build_wrapper method to return our mock instance def test_fetch_content(self, component_class, mock_wikipedia_wrapper):
component._build_wrapper = MagicMock(return_value=mock_instance) component = component_class()
component.input_value = "test query"
component.k = 3
component.lang = "en"
result = component.fetch_content() # Mock the WikipediaAPIWrapper and its load method
mock_instance = MagicMock()
mock_wikipedia_wrapper.return_value = mock_instance
mock_doc = MagicMock()
mock_doc.page_content = "Test content"
mock_doc.metadata = {"source": "wikipedia", "title": "Test Page"}
mock_instance.load.return_value = [mock_doc]
# Verify wrapper was built with correct params # Mock the _build_wrapper method to return our mock instance
component._build_wrapper.assert_called_once() component._build_wrapper = MagicMock(return_value=mock_instance)
mock_instance.load.assert_called_once_with("test query")
assert isinstance(result, list)
assert len(result) == 1
assert result[0].text == "Test content"
result = component.fetch_content()
def test_fetch_content_text(): # Verify wrapper was built with correct params
component = WikipediaAPIComponent() component._build_wrapper.assert_called_once()
component.fetch_content = MagicMock(return_value=[Data(text="First result"), Data(text="Second result")]) mock_instance.load.assert_called_once_with("test query")
assert isinstance(result, list)
assert len(result) == 1
assert result[0].text == "Test content"
result = component.fetch_content_text() def test_fetch_content_text(self, component_class):
component = component_class()
component.fetch_content = MagicMock(return_value=[Data(text="First result"), Data(text="Second result")])
assert isinstance(result, Message) result = component.fetch_content_text()
assert result.text == "First result\nSecond result\n"
assert isinstance(result, Message)
assert result.text == "First result\nSecond result\n"
def test_wikipedia_error_handling(): def test_wikipedia_error_handling(self, component_class):
component = WikipediaAPIComponent() component = component_class()
# Mock _build_wrapper to raise exception
component._build_wrapper = MagicMock(side_effect=Exception("API Error"))
# Mock _build_wrapper to raise exception with pytest.raises(Exception, match="API Error"):
component._build_wrapper = MagicMock(side_effect=Exception("API Error")) component.fetch_content()
with pytest.raises(Exception, match="API Error"):
component.fetch_content()