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_search import TavilySearchToolComponent
from .wikidata_api import WikidataAPIComponent
from .wikipedia import WikipediaComponent
from .wikipedia_api import WikipediaAPIComponent
from .wolfram_alpha_api import WolframAlphaAPIComponent
from .yahoo import YfinanceComponent
@ -62,6 +63,7 @@ __all__ = [
"TavilySearchToolComponent",
"WikidataAPIComponent",
"WikipediaAPIComponent",
"WikipediaComponent",
"WolframAlphaAPIComponent",
"YfinanceComponent",
"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 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.io import Output
from langflow.schema import Data
from langflow.schema.message import Message
class WikipediaAPIComponent(Component):
display_name = "Wikipedia API"
class WikipediaAPIComponent(LCToolComponent):
display_name = "Wikipedia API [Deprecated]"
description = "Call Wikipedia API."
name = "WikipediaAPI"
icon = "Wikipedia"
legacy = True
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),
@ -27,25 +29,16 @@ class WikipediaAPIComponent(Component):
),
]
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]:
def run_model(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_tool(self) -> Tool:
wrapper = self._build_wrapper()
return cast("Tool", WikipediaQueryRun(api_wrapper=wrapper))
def _build_wrapper(self) -> WikipediaAPIWrapper:
return WikipediaAPIWrapper(

View file

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