langchain-serpex-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ """SERPEX integration for LangChain.
2
+
3
+ This module provides tools for searching the web using the SERPEX API,
4
+ which supports multiple search engines including Google, Bing, DuckDuckGo,
5
+ Baidu, and Yandex.
6
+ """
7
+
8
+ from langchain_serpex_python.tools import SerpexSearchResults
9
+
10
+ __all__ = ["SerpexSearchResults"]
@@ -0,0 +1 @@
1
+ # Marker file for PEP 561
@@ -0,0 +1,285 @@
1
+ """SERPEX Search Tool for LangChain."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from typing import Any
7
+
8
+ import httpx
9
+ from langchain_core.callbacks import CallbackManagerForToolRun
10
+ from langchain_core.tools import BaseTool
11
+ from pydantic import Field, SecretStr, model_validator
12
+
13
+
14
+ class SerpexSearchResults(BaseTool):
15
+ """Tool for searching the web using the SERPEX API.
16
+
17
+ SERPEX provides multi-engine search results from Google, Bing, DuckDuckGo,
18
+ Brave, Yahoo, and Yandex search engines in JSON format.
19
+
20
+ Setup:
21
+ Install `langchain-serpex` and set environment variable `SERPEX_API_KEY`.
22
+
23
+ ```bash
24
+ pip install -U langchain-serpex
25
+ export SERPEX_API_KEY="your-serpex-api-key"
26
+ ```
27
+
28
+ Instantiation:
29
+ ```python
30
+ from langchain_serpex import SerpexSearchResults
31
+
32
+ # With explicit API key
33
+ tool = SerpexSearchResults(
34
+ api_key="your-serpex-api-key",
35
+ engine="auto", # or google, bing, duckduckgo, brave, yahoo, yandex
36
+ time_range="day" # optional: all, day, week, month, year
37
+ )
38
+
39
+ # Or using environment variable
40
+ tool = SerpexSearchResults()
41
+ ```
42
+
43
+ Invocation:
44
+ ```python
45
+ # Basic search
46
+ results = tool.invoke("latest AI developments")
47
+ print(results)
48
+
49
+ # With specific parameters
50
+ results = tool.invoke({
51
+ "query": "Python programming",
52
+ "engine": "google",
53
+ "time_range": "week"
54
+ })
55
+ ```
56
+
57
+ Example with Agent:
58
+ ```python
59
+ from langchain_serpex import SerpexSearchResults
60
+ from langchain_openai import ChatOpenAI
61
+ from langchain.agents import initialize_agent, AgentType
62
+
63
+ search = SerpexSearchResults(api_key="your-key")
64
+ llm = ChatOpenAI(temperature=0)
65
+
66
+ agent = initialize_agent(
67
+ tools=[search],
68
+ llm=llm,
69
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION
70
+ )
71
+
72
+ result = agent.run("What's the latest news about AI?")
73
+ ```
74
+ """
75
+
76
+ name: str = "serpex_search"
77
+ description: str = (
78
+ "A powerful multi-engine web search tool. "
79
+ "Useful for answering questions about current events, "
80
+ "finding information from the web, and getting real-time data. "
81
+ "Input should be a search query string. "
82
+ "Supports automatic routing with retry logic and multiple search engines "
83
+ "(Google, Bing, DuckDuckGo, Brave, Yahoo, Yandex)."
84
+ )
85
+
86
+ api_key: SecretStr = Field(default_factory=lambda: SecretStr(""))
87
+ engine: str = Field(
88
+ default="auto",
89
+ description=(
90
+ "Search engine: auto, google, bing, duckduckgo, brave, yahoo, yandex"
91
+ ),
92
+ )
93
+ category: str = Field(
94
+ default="web",
95
+ description="Search category (currently only 'web' supported)",
96
+ )
97
+ time_range: str | None = Field(
98
+ default=None,
99
+ description=(
100
+ "Time range: all, day, week, month, year (not supported by Brave)"
101
+ ),
102
+ )
103
+
104
+ base_url: str = Field(default="https://api.serpex.dev")
105
+
106
+ @model_validator(mode="before")
107
+ @classmethod
108
+ def validate_environment(cls, values: dict[str, Any]) -> dict[str, Any]:
109
+ """Validate that API key exists in environment."""
110
+ api_key = values.get("api_key")
111
+ if not api_key or (
112
+ isinstance(api_key, SecretStr) and not api_key.get_secret_value()
113
+ ):
114
+ api_key_from_env = os.getenv("SERPEX_API_KEY", "")
115
+ if api_key_from_env:
116
+ values["api_key"] = SecretStr(api_key_from_env)
117
+ elif isinstance(api_key, str):
118
+ values["api_key"] = SecretStr(api_key)
119
+
120
+ return values
121
+
122
+ def _build_params(self, query: str, **kwargs: Any) -> dict[str, Any]:
123
+ """Build parameters for the API request."""
124
+ params: dict[str, Any] = {
125
+ "q": query,
126
+ "engine": kwargs.get("engine", self.engine),
127
+ "category": kwargs.get("category", self.category),
128
+ }
129
+
130
+ # Add time_range if specified
131
+ time_range = kwargs.get("time_range") or self.time_range
132
+ if time_range is not None:
133
+ params["time_range"] = time_range
134
+
135
+ return params
136
+
137
+ def _format_results(self, data: dict[str, Any]) -> str:
138
+ """Format the search results into a readable string."""
139
+ results_parts: list[str] = []
140
+
141
+ # Instant answers (from knowledge panels/answer boxes)
142
+ if (
143
+ "answers" in data
144
+ and isinstance(data["answers"], list)
145
+ and len(data["answers"]) > 0
146
+ ):
147
+ answer = data["answers"][0]
148
+ if "answer" in answer and answer["answer"]:
149
+ results_parts.append(f"Answer: {answer['answer']}")
150
+ elif "snippet" in answer and answer["snippet"]:
151
+ results_parts.append(f"Featured Snippet: {answer['snippet']}")
152
+
153
+ # Infoboxes (knowledge panels)
154
+ if (
155
+ "infoboxes" in data
156
+ and isinstance(data["infoboxes"], list)
157
+ and len(data["infoboxes"]) > 0
158
+ ):
159
+ infobox = data["infoboxes"][0]
160
+ if "description" in infobox and infobox["description"]:
161
+ results_parts.append(f"Knowledge Panel: {infobox['description']}")
162
+
163
+ # Organic search results
164
+ if (
165
+ "results" in data
166
+ and isinstance(data["results"], list)
167
+ and len(data["results"]) > 0
168
+ ):
169
+ num_results = data.get("metadata", {}).get(
170
+ "number_of_results", len(data["results"])
171
+ )
172
+ results_parts.append(f"\nFound {num_results} results:\n")
173
+
174
+ for i, result in enumerate(data["results"][:10], 1):
175
+ title = result.get("title", "")
176
+ url = result.get("url", "")
177
+ snippet = result.get("snippet", "")
178
+ published_date = result.get("published_date")
179
+
180
+ result_text = f"[{i}] {title}"
181
+ if url:
182
+ result_text += f"\nURL: {url}"
183
+ if snippet:
184
+ result_text += f"\n{snippet}"
185
+ if published_date:
186
+ result_text += f"\nPublished: {published_date}"
187
+
188
+ results_parts.append(result_text)
189
+
190
+ # Search suggestions
191
+ if (
192
+ not results_parts
193
+ and "suggestions" in data
194
+ and isinstance(data["suggestions"], list)
195
+ and len(data["suggestions"]) > 0
196
+ ):
197
+ results_parts.append("No direct results found. Related searches:")
198
+ results_parts.extend(data["suggestions"])
199
+
200
+ # Query corrections
201
+ if (
202
+ not results_parts
203
+ and "corrections" in data
204
+ and isinstance(data["corrections"], list)
205
+ and len(data["corrections"]) > 0
206
+ ):
207
+ results_parts.append(f"Did you mean: {', '.join(data['corrections'])}?")
208
+
209
+ if not results_parts:
210
+ return "No search results found."
211
+
212
+ return "\n\n".join(results_parts)
213
+
214
+ def _run(
215
+ self,
216
+ query: str,
217
+ run_manager: CallbackManagerForToolRun | None = None,
218
+ **kwargs: Any,
219
+ ) -> str:
220
+ """Execute the search."""
221
+ params = self._build_params(query, **kwargs)
222
+
223
+ headers = {
224
+ "Authorization": f"Bearer {self.api_key.get_secret_value()}",
225
+ "Content-Type": "application/json",
226
+ }
227
+
228
+ url = f"{self.base_url}/api/search"
229
+
230
+ try:
231
+ with httpx.Client() as client:
232
+ response = client.get(url, params=params, headers=headers, timeout=30.0)
233
+ response.raise_for_status()
234
+ data = response.json()
235
+
236
+ if "error" in data:
237
+ return f"SERPEX API error: {data['error']}"
238
+
239
+ return self._format_results(data)
240
+
241
+ except httpx.HTTPStatusError as e:
242
+ return f"HTTP error occurred: {e.response.status_code} - {e.response.text}"
243
+ except httpx.RequestError as e:
244
+ return f"Request error occurred: {str(e)}"
245
+ except Exception as e:
246
+ return f"Error searching with SERPEX: {str(e)}"
247
+
248
+ async def _arun(
249
+ self,
250
+ query: str,
251
+ run_manager: CallbackManagerForToolRun | None = None,
252
+ **kwargs: Any,
253
+ ) -> str:
254
+ """Execute the search asynchronously."""
255
+ params = self._build_params(query, **kwargs)
256
+
257
+ headers = {
258
+ "Authorization": f"Bearer {self.api_key.get_secret_value()}",
259
+ "Content-Type": "application/json",
260
+ }
261
+
262
+ url = f"{self.base_url}/api/search"
263
+
264
+ try:
265
+ async with httpx.AsyncClient() as client:
266
+ response = await client.get(
267
+ url, params=params, headers=headers, timeout=30.0
268
+ )
269
+ response.raise_for_status()
270
+ data = response.json()
271
+
272
+ if "error" in data:
273
+ return f"SERPEX API error: {data['error']}"
274
+
275
+ return self._format_results(data)
276
+
277
+ except httpx.HTTPStatusError as e:
278
+ return f"HTTP error occurred: {e.response.status_code} - {e.response.text}"
279
+ except httpx.RequestError as e:
280
+ return f"Request error occurred: {str(e)}"
281
+ except Exception as e:
282
+ return f"Error searching with SERPEX: {str(e)}"
283
+
284
+
285
+ __all__ = ["SerpexSearchResults"]
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-serpex-python
3
+ Version: 0.1.0
4
+ Summary: An integration package connecting SERPEX and LangChain (Python)
5
+ Project-URL: Homepage, https://docs.langchain.com/oss/python/integrations/providers/serpex
6
+ Project-URL: Documentation, https://serpex.dev/docs
7
+ Project-URL: Source, https://github.com/divyeshradadiya/langchain-serpex
8
+ Project-URL: Repository, https://github.com/divyeshradadiya/langchain-serpex
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Requires-Python: <4.0.0,>=3.10.0
12
+ Requires-Dist: httpx>=0.27.0
13
+ Requires-Dist: langchain-core<2.0.0,>=1.0.0
14
+ Description-Content-Type: text/markdown
15
+
16
+ # langchain-serpex-python
17
+
18
+ [![PyPI - Version](https://img.shields.io/pypi/v/langchain-serpex-python?label=%20)](https://pypi.org/project/langchain-serpex-python/#history)
19
+ [![PyPI - License](https://img.shields.io/pypi/l/langchain-serpex-python)](https://opensource.org/licenses/MIT)
20
+ [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchainai.svg?style=social&label=Follow%20%40LangChainAI)](https://twitter.com/langchainai)
21
+
22
+ This package contains the LangChain integration with SERPEX (Python).
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install langchain-serpex-python
28
+ ```
29
+
30
+ ## What is SERPEX?
31
+
32
+ SERPEX is a powerful multi-engine search API that provides access to search results from Google, Bing, DuckDuckGo, Baidu, Yandex, and other search engines in JSON format. It's designed for developers building AI applications, SEO tools, market research platforms, and data aggregation services.
33
+
34
+ ## Features
35
+
36
+ - **Multi-Engine Support**: Search across Google, Bing, DuckDuckGo, Baidu, and Yandex
37
+ - **Rich Results**: Get organic results, answer boxes, knowledge graphs, news, images, videos, and shopping results
38
+ - **Localization**: Support for location-based and language-specific searches
39
+ - **Real-time Data**: Access to current search results
40
+ - **Easy Integration**: Simple API with comprehensive documentation
41
+
42
+ ## Quick Start
43
+
44
+ ### Get Your API Key
45
+
46
+ Sign up at [SERPEX](https://serpex.dev) to get your API key.
47
+
48
+ ### Basic Usage
49
+
50
+ ```python
51
+ from langchain_serpex_python import SerpexSearchResults
52
+
53
+ # Initialize the tool
54
+ tool = SerpexSearchResults(
55
+ api_key="your-serpex-api-key",
56
+ engine="google",
57
+ num_results=10
58
+ )
59
+
60
+ # Perform a search
61
+ results = tool.invoke("latest AI developments")
62
+ print(results)
63
+ ```
64
+
65
+ ### With Agents
66
+
67
+ ```python
68
+ from langchain_serpex_python import SerpexSearchResults
69
+ from langchain_openai import ChatOpenAI
70
+ from langchain.agents import initialize_agent, AgentType
71
+
72
+ # Initialize the search tool
73
+ search_tool = SerpexSearchResults(
74
+ api_key="your-serpex-api-key",
75
+ engine="google",
76
+ num_results=5
77
+ )
78
+
79
+ # Initialize the LLM
80
+ llm = ChatOpenAI(temperature=0)
81
+
82
+ # Create an agent with the search tool
83
+ agent = initialize_agent(
84
+ tools=[search_tool],
85
+ llm=llm,
86
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
87
+ verbose=True
88
+ )
89
+
90
+ # Run the agent
91
+ result = agent.run("What are the latest developments in quantum computing?")
92
+ print(result)
93
+ ```
94
+
95
+ ### Advanced Configuration
96
+
97
+ ```python
98
+ from langchain_serpex_python import SerpexSearchResults
99
+
100
+ # Configure with advanced parameters
101
+ tool = SerpexSearchResults(
102
+ api_key="your-serpex-api-key",
103
+ engine="google",
104
+ num_results=20,
105
+ gl="us", # Country code
106
+ hl="en", # Language code
107
+ location="New York", # Specific location
108
+ time_period="m", # Results from past month
109
+ safe_search="moderate"
110
+ )
111
+
112
+ # Search for location-specific results
113
+ results = tool.invoke("best restaurants")
114
+ print(results)
115
+ ```
116
+
117
+ ### Different Search Engines
118
+
119
+ ```python
120
+ from langchain_serpex_python import SerpexSearchResults
121
+
122
+ # Google Search
123
+ google_tool = SerpexSearchResults(api_key="your-key", engine="google")
124
+ google_results = google_tool.invoke("Python programming")
125
+
126
+ # Bing Search
127
+ bing_tool = SerpexSearchResults(api_key="your-key", engine="bing")
128
+ bing_results = bing_tool.invoke("Python programming")
129
+
130
+ # DuckDuckGo Search
131
+ ddg_tool = SerpexSearchResults(api_key="your-key", engine="duckduckgo")
132
+ ddg_results = ddg_tool.invoke("Python programming")
133
+ ```
134
+
135
+ ## Configuration
136
+
137
+ ### Environment Variables
138
+
139
+ You can set your SERPEX API key as an environment variable:
140
+
141
+ ```bash
142
+ export SERPEX_API_KEY="your-serpex-api-key"
143
+ ```
144
+
145
+ Then use the tool without passing the API key:
146
+
147
+ ```python
148
+ from langchain_serpex_python import SerpexSearchResults
149
+
150
+ tool = SerpexSearchResults() # Will use SERPEX_API_KEY from environment
151
+ ```
152
+
153
+ ### Parameters
154
+
155
+ - `api_key` (str): Your SERPEX API key (required)
156
+ - `engine` (str): Search engine to use - "google", "bing", "duckduckgo", "baidu", "yandex" (default: "google")
157
+ - `num_results` (int): Number of results to return, 1-100 (default: 10)
158
+ - `gl` (str): Country code for localized results (e.g., "us", "uk", "ca")
159
+ - `hl` (str): Language code (e.g., "en", "es", "fr")
160
+ - `location` (str): Specific location for localized results
161
+ - `time_period` (str): Time filter - "d" (day), "w" (week), "m" (month), "y" (year)
162
+ - `safe_search` (str): Safe search filter - "off", "moderate", "strict"
163
+
164
+ ## Documentation
165
+
166
+ For more detailed documentation, visit:
167
+ - [LangChain Documentation](https://python.langchain.com)
168
+ - [SERPEX API Documentation](https://serpex.dev/docs)
169
+
170
+ ## Support
171
+
172
+ For issues and questions:
173
+ - GitHub Issues: [langchain-serpex issues](https://github.com/langchain-ai/langchain/issues)
174
+ - SERPEX Support: [support@serpex.dev](mailto:support@serpex.dev)
175
+
176
+ ## License
177
+
178
+ This package is licensed under the MIT License.
179
+
180
+ ## CI / Publishing
181
+
182
+ A GitHub Actions workflow is provided to publish the package to PyPI when a tag like `v*` is pushed or when a release is published.
183
+
184
+ Required repository secret:
185
+ - `PYPI_API_TOKEN` — a PyPI API token with permission to upload the package. Set this in the repository's Settings → Secrets → Actions.
186
+
187
+ To publish a new release, create a tag `vMAJOR.MINOR.PATCH` and push it or create a release in GitHub; the workflow will build sdist and wheel and upload them to PyPI.
@@ -0,0 +1,7 @@
1
+ langchain_serpex_python/__init__.py,sha256=owZSYVufiNrS44tCs9XlDkJdh3ZcW1cibAOxDbFqk0A,305
2
+ langchain_serpex_python/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
3
+ langchain_serpex_python/tools.py,sha256=H45fTP0XvPBk_kkgGAcLDYclRQ96Z1V_oI36jc_knGU,9488
4
+ langchain_serpex_python-0.1.0.dist-info/METADATA,sha256=v_2LDkohScvgs7xrsAUi-sIcgLMsZbMVFvfitgsbzXA,5906
5
+ langchain_serpex_python-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ langchain_serpex_python-0.1.0.dist-info/licenses/LICENSE,sha256=oB3P_cEpG0BD8qgdJJqfPkXJA28jCMnN_u_hg3E3HoA,1066
7
+ langchain_serpex_python-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 LangChain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.