serphouse-ai-sdk 0.1.0__tar.gz
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.
- serphouse_ai_sdk-0.1.0/PKG-INFO +251 -0
- serphouse_ai_sdk-0.1.0/README.md +215 -0
- serphouse_ai_sdk-0.1.0/pyproject.toml +57 -0
- serphouse_ai_sdk-0.1.0/serphouse/__init__.py +1 -0
- serphouse_ai_sdk-0.1.0/serphouse/client.py +100 -0
- serphouse_ai_sdk-0.1.0/serphouse/langchain.py +66 -0
- serphouse_ai_sdk-0.1.0/serphouse/llamaindex.py +66 -0
- serphouse_ai_sdk-0.1.0/serphouse/schema.py +100 -0
- serphouse_ai_sdk-0.1.0/serphouse_ai_sdk.egg-info/PKG-INFO +251 -0
- serphouse_ai_sdk-0.1.0/serphouse_ai_sdk.egg-info/SOURCES.txt +16 -0
- serphouse_ai_sdk-0.1.0/serphouse_ai_sdk.egg-info/dependency_links.txt +1 -0
- serphouse_ai_sdk-0.1.0/serphouse_ai_sdk.egg-info/requires.txt +18 -0
- serphouse_ai_sdk-0.1.0/serphouse_ai_sdk.egg-info/top_level.txt +1 -0
- serphouse_ai_sdk-0.1.0/setup.cfg +4 -0
- serphouse_ai_sdk-0.1.0/tests/test_client.py +66 -0
- serphouse_ai_sdk-0.1.0/tests/test_langchain.py +83 -0
- serphouse_ai_sdk-0.1.0/tests/test_llamaindex.py +75 -0
- serphouse_ai_sdk-0.1.0/tests/test_schema.py +115 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: serphouse-ai-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SERPHouse AI SDK — search API tools for LangChain and LlamaIndex
|
|
5
|
+
Author-email: SERPHouse <support@serphouse.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://serphouse.com
|
|
8
|
+
Project-URL: Source, https://github.com/SERPHouse/ai-sdk-python
|
|
9
|
+
Project-URL: Documentation, https://serphouse.com/docs
|
|
10
|
+
Keywords: serphouse,search,ai,langchain,llamaindex,seo
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: requests>=2.28.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Provides-Extra: langchain
|
|
25
|
+
Requires-Dist: langchain>=0.3.0; extra == "langchain"
|
|
26
|
+
Provides-Extra: llamaindex
|
|
27
|
+
Requires-Dist: llama-index>=0.12.0; extra == "llamaindex"
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: serphouse-ai-sdk[langchain,llamaindex]; extra == "all"
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == "test"
|
|
33
|
+
Requires-Dist: langchain-openai>=0.2; extra == "test"
|
|
34
|
+
Requires-Dist: llama-index-llms-openai>=0.3; extra == "test"
|
|
35
|
+
Requires-Dist: python-dotenv>=1.0; extra == "test"
|
|
36
|
+
|
|
37
|
+
<div align="center">
|
|
38
|
+
|
|
39
|
+
<img src="./assets/serphouse-logo.png" alt="SERPHouse logo" width="80" />
|
|
40
|
+
|
|
41
|
+
# SERPHouse AI SDK
|
|
42
|
+
|
|
43
|
+
**Python SDK for the SERPHouse search API — with first-class integrations for LangChain and LlamaIndex.**
|
|
44
|
+
|
|
45
|
+
Drop live Google, Bing, and Yahoo search data into your AI agents. No boilerplate, no custom API clients — just import, configure, and let your agent search the web.
|
|
46
|
+
|
|
47
|
+
<br />
|
|
48
|
+
|
|
49
|
+
[](https://pypi.org/project/serphouse-ai-sdk/)
|
|
50
|
+
[](https://www.python.org/)
|
|
51
|
+
[](https://langchain.com/)
|
|
52
|
+
[](https://llamaindex.ai/)
|
|
53
|
+
[](LICENSE)
|
|
54
|
+
[](https://serphouse.com)
|
|
55
|
+
[](https://github.com/SERPHouse)
|
|
56
|
+
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Table of Contents
|
|
62
|
+
|
|
63
|
+
- [Why SERPHouse AI SDK](#why-serphouse-ai-sdk)
|
|
64
|
+
- [Installation](#installation)
|
|
65
|
+
- [Quick Start](#quick-start)
|
|
66
|
+
- [LangChain](#langchain)
|
|
67
|
+
- [LlamaIndex](#llamaindex)
|
|
68
|
+
- [API Key](#api-key)
|
|
69
|
+
- [Tools Reference](#tools-reference)
|
|
70
|
+
- [Advanced Usage](#advanced-usage)
|
|
71
|
+
- [Custom API key per tool](#custom-api-key-per-tool)
|
|
72
|
+
- [SERPHouseClient](#serphouseclient)
|
|
73
|
+
- [Development](#development)
|
|
74
|
+
- [Contributing](#contributing)
|
|
75
|
+
- [License](#license)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Why SERPHouse AI SDK
|
|
80
|
+
|
|
81
|
+
| | |
|
|
82
|
+
|---|---|
|
|
83
|
+
| **Zero boilerplate** | Two lines to add web search, news, or video results to any LangChain or LlamaIndex agent |
|
|
84
|
+
| **Framework-native** | Functions return standard `StructuredTool` / `FunctionTool` objects — no wrappers, no adapters |
|
|
85
|
+
| **Live SERP data** | Every call hits the SERPHouse API in real time. No cached or stale results. |
|
|
86
|
+
| **Production-ready** | Built on `requests` and `pydantic` with typed schemas, configurable timeouts, and clear error handling |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Installation
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install serphouse-ai-sdk
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
With framework extras:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install serphouse-ai-sdk[langchain]
|
|
100
|
+
pip install serphouse-ai-sdk[llamaindex]
|
|
101
|
+
pip install serphouse-ai-sdk[all] # both frameworks
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Quick Start
|
|
107
|
+
|
|
108
|
+
Set the `SERPHOUSE_API_KEY` environment variable (or [pass it per tool](#custom-api-key-per-tool)).
|
|
109
|
+
|
|
110
|
+
### LangChain
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from langchain.agents import create_agent
|
|
114
|
+
from langchain_openai import ChatOpenAI
|
|
115
|
+
from serphouse.langchain import search, news, short_video
|
|
116
|
+
|
|
117
|
+
agent = create_agent(
|
|
118
|
+
model=ChatOpenAI(model="gpt-4"),
|
|
119
|
+
tools=[search(), news(), short_video()],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
response = agent.invoke({
|
|
123
|
+
"messages": [{"role": "user", "content": "Latest AI news from OpenAI"}]
|
|
124
|
+
})
|
|
125
|
+
print(response["messages"][-1].content)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### LlamaIndex
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from llama_index.core.agent.workflow import FunctionAgent
|
|
132
|
+
from llama_index.llms.openai import OpenAI
|
|
133
|
+
from serphouse.llamaindex import search, news, short_video
|
|
134
|
+
|
|
135
|
+
agent = FunctionAgent(
|
|
136
|
+
llm=OpenAI(model="gpt-4"),
|
|
137
|
+
tools=[search(), news(), short_video()],
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
response = agent.run("Latest AI news from OpenAI")
|
|
141
|
+
print(response)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## API Key
|
|
147
|
+
|
|
148
|
+
Get your key at [serphouse.com](https://serphouse.com) and choose one of:
|
|
149
|
+
|
|
150
|
+
| Method | Example |
|
|
151
|
+
|--------|---------|
|
|
152
|
+
| **Environment variable** (recommended) | `export SERPHOUSE_API_KEY=your_key_here` |
|
|
153
|
+
| **Per-tool options dict** | `search({"api_key": "your_key_here"})` |
|
|
154
|
+
| **SERPHouseClient** | `SERPHouseClient(api_key="your_key_here")` |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Tools Reference
|
|
159
|
+
|
|
160
|
+
| Tool | Framework | Endpoint | Description |
|
|
161
|
+
|------|-----------|----------|-------------|
|
|
162
|
+
| `search()` | LangChain, LlamaIndex | `/web-search-lite` | General web search |
|
|
163
|
+
| `news()` | LangChain, LlamaIndex | `/google-news` | Google News search |
|
|
164
|
+
| `short_video()` | LangChain, LlamaIndex | `/google-short-videos-api` | Google Short Videos (Shorts) |
|
|
165
|
+
|
|
166
|
+
All tools accept the following parameters:
|
|
167
|
+
|
|
168
|
+
| Parameter | Type | Default | Description |
|
|
169
|
+
|-----------|------|---------|-------------|
|
|
170
|
+
| `q` | `str` | — | Search query (required) |
|
|
171
|
+
| `domain` | `str` | `google.com` | Search domain |
|
|
172
|
+
| `lang` | `str` | `en` | Search language code |
|
|
173
|
+
| `loc` | `str` | `New York,New York,United States` | Location (`City,State,Country`) |
|
|
174
|
+
| `device` | `str` | `desktop` | `desktop` or `mobile` |
|
|
175
|
+
| `page` | `int` | — | Page number |
|
|
176
|
+
| `date_range` | `str` | `y` | `h` (hour), `d` (24h), `w` (week), `m` (month), `y` (year), or `YYYY-MM-DD,YYYY-MM-DD` |
|
|
177
|
+
| `gl` | `str` | `US` | Country code (ISO 3166-1 alpha-2, search only) |
|
|
178
|
+
| `video_quality` | `str` | `high` | Video quality (short_video only) |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Advanced Usage
|
|
183
|
+
|
|
184
|
+
### Custom API key per tool
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from serphouse.langchain import search
|
|
188
|
+
|
|
189
|
+
tool = search({"api_key": "your-key"})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### SERPHouseClient
|
|
193
|
+
|
|
194
|
+
Use the raw client directly for custom integrations:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
from serphouse import SERPHouseClient
|
|
198
|
+
|
|
199
|
+
client = SERPHouseClient(api_key="your-key")
|
|
200
|
+
result = client.post("/web-search-lite", {"q": "python sdk"})
|
|
201
|
+
print(result)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Development
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Clone and enter the repo
|
|
210
|
+
git clone https://github.com/serphouse/ai-sdk.git
|
|
211
|
+
cd ai-sdk
|
|
212
|
+
|
|
213
|
+
# Create a virtual environment
|
|
214
|
+
python3 -m venv venv
|
|
215
|
+
source venv/bin/activate
|
|
216
|
+
|
|
217
|
+
# Install in editable mode with all dev dependencies
|
|
218
|
+
pip install -e ".[test]"
|
|
219
|
+
|
|
220
|
+
# Run tests
|
|
221
|
+
pytest tests -v
|
|
222
|
+
|
|
223
|
+
# Run only unit tests (skip OpenAI integration tests)
|
|
224
|
+
pytest tests -v -k "not Integration"
|
|
225
|
+
|
|
226
|
+
# Run integration tests (requires OPENAI_API_KEY)
|
|
227
|
+
OPENAI_API_KEY=sk-... pytest tests -v -k "Integration"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions are welcome. Please keep changes focused and match existing code style.
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
git checkout -b feature/your-feature
|
|
238
|
+
pip install -e ".[test]"
|
|
239
|
+
# make changes
|
|
240
|
+
pytest tests -v
|
|
241
|
+
git commit -m "Add your feature"
|
|
242
|
+
git push origin feature/your-feature
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Then open a Pull Request. Update this README if you change setup or configuration.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
[MIT License](LICENSE) — Copyright SERPHouse.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="./assets/serphouse-logo.png" alt="SERPHouse logo" width="80" />
|
|
4
|
+
|
|
5
|
+
# SERPHouse AI SDK
|
|
6
|
+
|
|
7
|
+
**Python SDK for the SERPHouse search API — with first-class integrations for LangChain and LlamaIndex.**
|
|
8
|
+
|
|
9
|
+
Drop live Google, Bing, and Yahoo search data into your AI agents. No boilerplate, no custom API clients — just import, configure, and let your agent search the web.
|
|
10
|
+
|
|
11
|
+
<br />
|
|
12
|
+
|
|
13
|
+
[](https://pypi.org/project/serphouse-ai-sdk/)
|
|
14
|
+
[](https://www.python.org/)
|
|
15
|
+
[](https://langchain.com/)
|
|
16
|
+
[](https://llamaindex.ai/)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://serphouse.com)
|
|
19
|
+
[](https://github.com/SERPHouse)
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Table of Contents
|
|
26
|
+
|
|
27
|
+
- [Why SERPHouse AI SDK](#why-serphouse-ai-sdk)
|
|
28
|
+
- [Installation](#installation)
|
|
29
|
+
- [Quick Start](#quick-start)
|
|
30
|
+
- [LangChain](#langchain)
|
|
31
|
+
- [LlamaIndex](#llamaindex)
|
|
32
|
+
- [API Key](#api-key)
|
|
33
|
+
- [Tools Reference](#tools-reference)
|
|
34
|
+
- [Advanced Usage](#advanced-usage)
|
|
35
|
+
- [Custom API key per tool](#custom-api-key-per-tool)
|
|
36
|
+
- [SERPHouseClient](#serphouseclient)
|
|
37
|
+
- [Development](#development)
|
|
38
|
+
- [Contributing](#contributing)
|
|
39
|
+
- [License](#license)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Why SERPHouse AI SDK
|
|
44
|
+
|
|
45
|
+
| | |
|
|
46
|
+
|---|---|
|
|
47
|
+
| **Zero boilerplate** | Two lines to add web search, news, or video results to any LangChain or LlamaIndex agent |
|
|
48
|
+
| **Framework-native** | Functions return standard `StructuredTool` / `FunctionTool` objects — no wrappers, no adapters |
|
|
49
|
+
| **Live SERP data** | Every call hits the SERPHouse API in real time. No cached or stale results. |
|
|
50
|
+
| **Production-ready** | Built on `requests` and `pydantic` with typed schemas, configurable timeouts, and clear error handling |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install serphouse-ai-sdk
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
With framework extras:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install serphouse-ai-sdk[langchain]
|
|
64
|
+
pip install serphouse-ai-sdk[llamaindex]
|
|
65
|
+
pip install serphouse-ai-sdk[all] # both frameworks
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
Set the `SERPHOUSE_API_KEY` environment variable (or [pass it per tool](#custom-api-key-per-tool)).
|
|
73
|
+
|
|
74
|
+
### LangChain
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from langchain.agents import create_agent
|
|
78
|
+
from langchain_openai import ChatOpenAI
|
|
79
|
+
from serphouse.langchain import search, news, short_video
|
|
80
|
+
|
|
81
|
+
agent = create_agent(
|
|
82
|
+
model=ChatOpenAI(model="gpt-4"),
|
|
83
|
+
tools=[search(), news(), short_video()],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
response = agent.invoke({
|
|
87
|
+
"messages": [{"role": "user", "content": "Latest AI news from OpenAI"}]
|
|
88
|
+
})
|
|
89
|
+
print(response["messages"][-1].content)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### LlamaIndex
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from llama_index.core.agent.workflow import FunctionAgent
|
|
96
|
+
from llama_index.llms.openai import OpenAI
|
|
97
|
+
from serphouse.llamaindex import search, news, short_video
|
|
98
|
+
|
|
99
|
+
agent = FunctionAgent(
|
|
100
|
+
llm=OpenAI(model="gpt-4"),
|
|
101
|
+
tools=[search(), news(), short_video()],
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
response = agent.run("Latest AI news from OpenAI")
|
|
105
|
+
print(response)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## API Key
|
|
111
|
+
|
|
112
|
+
Get your key at [serphouse.com](https://serphouse.com) and choose one of:
|
|
113
|
+
|
|
114
|
+
| Method | Example |
|
|
115
|
+
|--------|---------|
|
|
116
|
+
| **Environment variable** (recommended) | `export SERPHOUSE_API_KEY=your_key_here` |
|
|
117
|
+
| **Per-tool options dict** | `search({"api_key": "your_key_here"})` |
|
|
118
|
+
| **SERPHouseClient** | `SERPHouseClient(api_key="your_key_here")` |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Tools Reference
|
|
123
|
+
|
|
124
|
+
| Tool | Framework | Endpoint | Description |
|
|
125
|
+
|------|-----------|----------|-------------|
|
|
126
|
+
| `search()` | LangChain, LlamaIndex | `/web-search-lite` | General web search |
|
|
127
|
+
| `news()` | LangChain, LlamaIndex | `/google-news` | Google News search |
|
|
128
|
+
| `short_video()` | LangChain, LlamaIndex | `/google-short-videos-api` | Google Short Videos (Shorts) |
|
|
129
|
+
|
|
130
|
+
All tools accept the following parameters:
|
|
131
|
+
|
|
132
|
+
| Parameter | Type | Default | Description |
|
|
133
|
+
|-----------|------|---------|-------------|
|
|
134
|
+
| `q` | `str` | — | Search query (required) |
|
|
135
|
+
| `domain` | `str` | `google.com` | Search domain |
|
|
136
|
+
| `lang` | `str` | `en` | Search language code |
|
|
137
|
+
| `loc` | `str` | `New York,New York,United States` | Location (`City,State,Country`) |
|
|
138
|
+
| `device` | `str` | `desktop` | `desktop` or `mobile` |
|
|
139
|
+
| `page` | `int` | — | Page number |
|
|
140
|
+
| `date_range` | `str` | `y` | `h` (hour), `d` (24h), `w` (week), `m` (month), `y` (year), or `YYYY-MM-DD,YYYY-MM-DD` |
|
|
141
|
+
| `gl` | `str` | `US` | Country code (ISO 3166-1 alpha-2, search only) |
|
|
142
|
+
| `video_quality` | `str` | `high` | Video quality (short_video only) |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Advanced Usage
|
|
147
|
+
|
|
148
|
+
### Custom API key per tool
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from serphouse.langchain import search
|
|
152
|
+
|
|
153
|
+
tool = search({"api_key": "your-key"})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### SERPHouseClient
|
|
157
|
+
|
|
158
|
+
Use the raw client directly for custom integrations:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from serphouse import SERPHouseClient
|
|
162
|
+
|
|
163
|
+
client = SERPHouseClient(api_key="your-key")
|
|
164
|
+
result = client.post("/web-search-lite", {"q": "python sdk"})
|
|
165
|
+
print(result)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Clone and enter the repo
|
|
174
|
+
git clone https://github.com/serphouse/ai-sdk.git
|
|
175
|
+
cd ai-sdk
|
|
176
|
+
|
|
177
|
+
# Create a virtual environment
|
|
178
|
+
python3 -m venv venv
|
|
179
|
+
source venv/bin/activate
|
|
180
|
+
|
|
181
|
+
# Install in editable mode with all dev dependencies
|
|
182
|
+
pip install -e ".[test]"
|
|
183
|
+
|
|
184
|
+
# Run tests
|
|
185
|
+
pytest tests -v
|
|
186
|
+
|
|
187
|
+
# Run only unit tests (skip OpenAI integration tests)
|
|
188
|
+
pytest tests -v -k "not Integration"
|
|
189
|
+
|
|
190
|
+
# Run integration tests (requires OPENAI_API_KEY)
|
|
191
|
+
OPENAI_API_KEY=sk-... pytest tests -v -k "Integration"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Contributing
|
|
197
|
+
|
|
198
|
+
Contributions are welcome. Please keep changes focused and match existing code style.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
git checkout -b feature/your-feature
|
|
202
|
+
pip install -e ".[test]"
|
|
203
|
+
# make changes
|
|
204
|
+
pytest tests -v
|
|
205
|
+
git commit -m "Add your feature"
|
|
206
|
+
git push origin feature/your-feature
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Then open a Pull Request. Update this README if you change setup or configuration.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
[MIT License](LICENSE) — Copyright SERPHouse.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "serphouse-ai-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "SERPHouse AI SDK — search API tools for LangChain and LlamaIndex"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "SERPHouse", email = "support@serphouse.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["serphouse", "search", "ai", "langchain", "llamaindex", "seo"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Internet :: WWW/HTTP :: Indexing/Search",
|
|
20
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
dependencies = [
|
|
29
|
+
"requests>=2.28.0",
|
|
30
|
+
"pydantic>=2.0.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
langchain = [
|
|
35
|
+
"langchain>=0.3.0",
|
|
36
|
+
]
|
|
37
|
+
llamaindex = [
|
|
38
|
+
"llama-index>=0.12.0",
|
|
39
|
+
]
|
|
40
|
+
all = [
|
|
41
|
+
"serphouse-ai-sdk[langchain,llamaindex]",
|
|
42
|
+
]
|
|
43
|
+
test = [
|
|
44
|
+
"pytest>=8.0",
|
|
45
|
+
"pytest-asyncio>=0.24",
|
|
46
|
+
"langchain-openai>=0.2",
|
|
47
|
+
"llama-index-llms-openai>=0.3",
|
|
48
|
+
"python-dotenv>=1.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://serphouse.com"
|
|
53
|
+
Source = "https://github.com/SERPHouse/ai-sdk-python"
|
|
54
|
+
Documentation = "https://serphouse.com/docs"
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
include = ["serphouse*"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .client import SERPHouseClient, ApiError
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
BASE_URL = "https://api.serphouse.com"
|
|
9
|
+
DEFAULT_API_KEY_ENV = "SERPHOUSE_API_KEY"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ApiError(Exception):
|
|
13
|
+
def __init__(self, status: int, body: Any):
|
|
14
|
+
self.status = status
|
|
15
|
+
self.body = body
|
|
16
|
+
|
|
17
|
+
if isinstance(body, str):
|
|
18
|
+
message = body
|
|
19
|
+
elif isinstance(body, dict):
|
|
20
|
+
message = str(
|
|
21
|
+
body.get("message")
|
|
22
|
+
or body.get("error")
|
|
23
|
+
or f"HTTP {status}"
|
|
24
|
+
)
|
|
25
|
+
else:
|
|
26
|
+
message = f"HTTP {status}"
|
|
27
|
+
|
|
28
|
+
super().__init__(message)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SERPHouseClient:
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
api_key: str | None = None,
|
|
35
|
+
base_url: str = BASE_URL,
|
|
36
|
+
timeout: int = 30,
|
|
37
|
+
):
|
|
38
|
+
self.api_key = api_key or os.getenv(DEFAULT_API_KEY_ENV)
|
|
39
|
+
|
|
40
|
+
if not self.api_key:
|
|
41
|
+
raise ValueError(
|
|
42
|
+
f"Missing API key. Set {DEFAULT_API_KEY_ENV} or pass api_key."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
self.base_url = base_url.rstrip("/")
|
|
46
|
+
self.timeout = timeout
|
|
47
|
+
self.session = requests.Session()
|
|
48
|
+
self.session.headers.update(
|
|
49
|
+
{
|
|
50
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def _request(
|
|
56
|
+
self,
|
|
57
|
+
method: str,
|
|
58
|
+
path: str,
|
|
59
|
+
body: dict[str, Any] | None = None,
|
|
60
|
+
) -> Any:
|
|
61
|
+
url = (
|
|
62
|
+
path
|
|
63
|
+
if path.startswith(("http://", "https://"))
|
|
64
|
+
else f"{self.base_url}{path if path.startswith('/') else '/' + path}"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
response = self.session.request(
|
|
68
|
+
method=method,
|
|
69
|
+
url=url,
|
|
70
|
+
json=body,
|
|
71
|
+
timeout=self.timeout,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
content_type = response.headers.get("Content-Type", "")
|
|
75
|
+
|
|
76
|
+
if "application/json" in content_type:
|
|
77
|
+
data = response.json()
|
|
78
|
+
else:
|
|
79
|
+
data = response.text
|
|
80
|
+
|
|
81
|
+
if not response.ok:
|
|
82
|
+
raise ApiError(response.status_code, data)
|
|
83
|
+
|
|
84
|
+
return data
|
|
85
|
+
|
|
86
|
+
def get(self, path: str) -> Any:
|
|
87
|
+
return self._request("GET", path)
|
|
88
|
+
|
|
89
|
+
def post(
|
|
90
|
+
self,
|
|
91
|
+
path: str,
|
|
92
|
+
data: dict[str, Any],
|
|
93
|
+
) -> Any:
|
|
94
|
+
return self._request(
|
|
95
|
+
"POST",
|
|
96
|
+
path,
|
|
97
|
+
{
|
|
98
|
+
"data": data,
|
|
99
|
+
},
|
|
100
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from langchain_core.tools import StructuredTool
|
|
2
|
+
|
|
3
|
+
from .client import SERPHouseClient
|
|
4
|
+
from .schema import NewsSchema, SearchSchema, ShortVideoSchema
|
|
5
|
+
|
|
6
|
+
ToolOptions = dict[str, str] | None
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def search(options: ToolOptions = None) -> StructuredTool:
|
|
10
|
+
"""
|
|
11
|
+
Search the web using SERPHouse.
|
|
12
|
+
"""
|
|
13
|
+
client = SERPHouseClient(api_key=options.get("api_key") if options else None)
|
|
14
|
+
|
|
15
|
+
def execute(**kwargs):
|
|
16
|
+
return client.post(
|
|
17
|
+
"/web-search-lite",
|
|
18
|
+
{k: v for k, v in kwargs.items() if v is not None},
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
return StructuredTool.from_function(
|
|
22
|
+
func=execute,
|
|
23
|
+
name="search",
|
|
24
|
+
description="Search the web for information.",
|
|
25
|
+
args_schema=SearchSchema,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def news(options: ToolOptions = None) -> StructuredTool:
|
|
30
|
+
"""
|
|
31
|
+
Search news using SERPHouse.
|
|
32
|
+
"""
|
|
33
|
+
client = SERPHouseClient(api_key=options.get("api_key") if options else None)
|
|
34
|
+
|
|
35
|
+
def execute(**kwargs):
|
|
36
|
+
return client.post(
|
|
37
|
+
"/google-news",
|
|
38
|
+
{k: v for k, v in kwargs.items() if v is not None},
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return StructuredTool.from_function(
|
|
42
|
+
func=execute,
|
|
43
|
+
name="news",
|
|
44
|
+
description="Search for news on the web.",
|
|
45
|
+
args_schema=NewsSchema,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def short_video(options: ToolOptions = None) -> StructuredTool:
|
|
50
|
+
"""
|
|
51
|
+
Search short videos using SERPHouse.
|
|
52
|
+
"""
|
|
53
|
+
client = SERPHouseClient(api_key=options.get("api_key") if options else None)
|
|
54
|
+
|
|
55
|
+
def execute(**kwargs):
|
|
56
|
+
return client.post(
|
|
57
|
+
"/google-short-videos-api",
|
|
58
|
+
{k: v for k, v in kwargs.items() if v is not None},
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return StructuredTool.from_function(
|
|
62
|
+
func=execute,
|
|
63
|
+
name="short_video",
|
|
64
|
+
description="Search for short videos on the web.",
|
|
65
|
+
args_schema=ShortVideoSchema,
|
|
66
|
+
)
|